1 回答

TA貢獻1735條經驗 獲得超5個贊
這里有幾個我不明白的問題:
無需在“擬合函數”中定義擬合函數
如果唯一的區別是字典的命名,則無需定義兩次。(雖然我不明白為什么首先必須以不同的方式命名)
一個可以直接擬合頻率而不是歐米茄
預先計算擬合值時,直接使用給定的fitfunction
總的來說,我不明白為什么第二次擬合會失敗并且在這里使用一些通用數據,但事實并非如此??紤]到物理學中幅度可能很復雜的事實,我對負面結果沒有問題。不過,我理解 OP 中的要點。當然,擬合算法不了解物理學,從數學上講,幅度為負是沒有問題的。這只是給出了 pi 的額外相移。因此,在處理所需的相移時,可以很容易地強制施加正幅度。我在這里介紹了這個作為可能的關鍵字參數。此外,我將其簡化為一個適合函數,并可能將輸出字典鍵“重命名”為關鍵字參數。
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
def sinfunc( t, A, f, p, c ):
return A * np.sin( 2.0 * np.pi * f * t + p) + c
def fit_sin(t_APD, y_APD, addName="", posamp=False):
''' Fit sin to the input time sequence, and return fitting parameters "amp", "omega", "phase", "offset", "freq", "period" and "fitfunc" '''
ff = np.fft.fftfreq( len( t_APD ), t_APD[1] - t_APD[0] ) # assume uniform spacing
Fyy = abs( np.fft.fft( y_APD ) )
guess_freq = abs( ff[np.argmax( Fyy[1:] ) + 1] ) # excluding the zero frequency "peak", which is related to offset
guess_amp = np.std( y_APD ) * 2.**0.5
guess_offset = np.mean( y_APD )
guess = np.array( [ guess_amp, guess_freq, 0., guess_offset ] )
popt, pcov = curve_fit(sinfunc, t_APD, y_APD, p0=guess, maxfev=500) # with maxfev= number I can increase the number of iterations
if popt[0] < 0 and posamp:
popt[0] = -popt[0]
popt[2] += np.pi
popt[2] = popt[2] % ( 2 * np.pi )
A, f, p, c = popt
fitted_APD = sinfunc( t_APD, *popt )
dic_APD = {
"amp{}".format(addName): A,
"omega{}".format(addName): 2.0 * np.pi * f,
"phase{}".format(addName): p,
"offset{}".format(addName): c,
"freq{}".format(addName): f,
"period{}".format(addName): 1.0 / f,
"fitfunc{}".format(addName): fitted_APD,
"maxcov{}".format(addName): np.max( pcov ),
"rawres{}".format(addName): ( guess, popt, pcov ) }
return dic_APD
tl = np.linspace(0,1e-6, 150 )
sl1 = np.fromiter( (sinfunc(t, .18, 4998735, 3.6, 2.0 ) + .01 *( 1 - 2 * np.random.random() ) for t in tl ), np.float )
sl2 = np.fromiter( (sinfunc(t, .06, 4998735, 2.1, 0.4 ) + .01 *( 1 - 2 * np.random.random() ) for t in tl ), np.float )
ld = fit_sin(tl, sl1, addName="_ld" )
print ld["amp_ld"]
ld = fit_sin(tl, sl1, addName="_ld", posamp=True )
print ld["amp_ld"]
apd = fit_sin(tl, sl2 )
fig = plt.figure("1")
ax = fig.add_subplot( 1, 1, 1 )
ax.plot( tl, sl1, color="r" )
ax.plot( tl, ld["fitfunc_ld"], color="k", ls="--" )
ax.plot( tl, sl2, color="#50FF80" )
ax.plot( tl, apd["fitfunc"], color="k", ls="--" )
ax.grid()
plt.show()
這給了我:
-0.180108427200549
0.180108427200549
即在第一次嘗試中,盡管對幅度進行了很好的猜測,但結果為負。這可能是由于大相位。由于該猜測為零,因此算法更容易先切換幅度的符號,然后再調整相位。如上所述,這很容易糾正,甚至不需要錯誤傳播。
添加回答
舉報