Я старался соответствовать амплитуде, частоте и фазе кривой синуса, учитывая некоторые генерируемые двумерные данные игрушек. (Код в конце)Ошибка нелинейной подгонки к синусоидальной кривой
Чтобы получить оценки для трех параметров, я сначала выполняю БПФ. Я использую значения из БПФ в качестве исходных догадок для фактической частоты и фазы, а затем для них (строки за строкой). Я написал свой код таким образом, что я ввожу, в каком бункере БПФ мне нужна частота, поэтому я могу проверить, работает ли фитинг. Но есть странное поведение. Если мой входной бит равен 3.1 (не встроенный бит, поэтому БПФ не даст мне правильную частоту), то пригонка отлично работает. Но если входной бит равен 3 (поэтому FFT выводит точную частоту), то моя подгонка не удалась, и я пытаюсь понять, почему.
Вот вывод, когда я дам входных бункеров (в направлении X и Y), как 3,0 и 2,1 соответственно:
(Участок справа есть данные - подходят)
Вот выход, когда я даю входные лотки как 3.0 и 2.0:
Вопрос: Почему не линейная подгонка терпит неудачу, когда я ввести точную частоту кривого?
Код:
#! /usr/bin/python
# For the purposes of this code, it's easier to think of the X-Y axes as transposed,
# so the X axis is vertical and the Y axis is horizontal
import numpy as np
import matplotlib.pyplot as plt
import scipy.optimize as optimize
import itertools
import sys
PI = np.pi
# Function which accepts paramters to define a sin curve
# Used for the non linear fit
def sineFit(t, a, f, p):
return a * np.sin(2.0 * PI * f*t + p)
xSize = 18
ySize = 60
npt = xSize * ySize
# Get frequency bin from user input
xFreq = float(sys.argv[1])
yFreq = float(sys.argv[2])
xPeriod = xSize/xFreq
yPeriod = ySize/yFreq
# arrays should be defined here
# Generate the 2D sine curve
for jj in range (0, xSize):
for ii in range(0, ySize):
sineGen[jj, ii] = np.cos(2.0*PI*(ii/xPeriod + jj/yPeriod))
# Compute 2dim FFT as well as freq bins along each axis
fftData = np.fft.fft2(sineGen)
fftMean = np.mean(fftData)
fftRMS = np.std(fftData)
xFreqArr = np.fft.fftfreq(fftData.shape[1]) # Frequency bins along x
yFreqArr = np.fft.fftfreq(fftData.shape[0]) # Frequency bins along y
# Find peak of FFT, and position of peak
maxVal = np.amax(np.abs(fftData))
maxPos = np.where(np.abs(fftData) == maxVal)
# Iterate through peaks in the FFT
# For this example, number of loops will always be only one
prevPhase = -1000
for col, row in itertools.izip(maxPos[0], maxPos[1]):
# Initial guesses for fit parameters from FFT
init_phase = np.angle(fftData[col,row])
init_amp = 2.0 * maxVal/npt
init_freqY = yFreqArr[col]
init_freqX = xFreqArr[row]
cntr = 0
if prevPhase == -1000:
prevPhase = init_phase
guess = [init_amp, init_freqX, prevPhase]
# Fit each row of the 2D sine curve independently
for rr in sineGen:
(amp, freq, phs), pcov = optimize.curve_fit(sineFit, xDat, rr, guess)
# xDat is an linspace array, containing a list of numbers from 0 to xSize-1
# Subtract fit from original data and plot
fitData = sineFit(xDat, amp, freq, phs)
sub1 = rr - fitData
# Plot
fig1 = plt.figure()
ax1 = fig1.add_subplot(121)
p1, = ax1.plot(rr, 'g')
p2, = ax1.plot(fitData, 'b')
plt.legend([p1,p2], ["data", "fit"])
ax2 = fig1.add_subplot(122)
p3, = ax2.plot(sub1)
plt.legend([p3], ['residual1'])
fig1.tight_layout()
plt.show()
cntr += 1
prevPhase = phs # Update guess for phase of sine curve
невыполнима для меня чтобы прочитать так много кода (без комментариев!) и найти ошибку ... Я предлагаю разложить вашу программу на кусочки, которая строит все эти массивы, другая, которая пригодится, другая, которая делает графики. Затем протестируйте их отдельно, узнайте, где ошибка, и повторно опубликуйте это, чтобы мы могли посмотреть на него и сыграть с небольшим фрагментом кода. – Jblasco
Вы разместили код, но это не минимальный пример _working_. Даже с комментариями, почему не определяется 'xDat' или' sineGen'? – Hooked
@Hooked - Извините ... в попытке сделать мой код меньше, я просто поставил комментарии вместо определений. Я его отредактирую! – Kitchi