亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Scipy Optimize CurveFit 計算錯誤的值

Scipy Optimize CurveFit 計算錯誤的值

慕工程0101907 2022-10-06 16:25:29
我很想知道兩種正弦波類型之間的相移。為此,我試圖用 scipy.cuve_fit 來擬合每一波。我一直在關注這個帖子。但是,我獲得了負幅度,并且相移有時看起來像轉發的 pi 弧度。我正在使用的代碼是下面的代碼:def fit_sin_LD(t_LD, y_LD):'''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_LD), (t_LD[1]-t_LD[0]))   # assume uniform spacingFyy = abs(np.fft.fft(y_LD))guess_freq = abs(ff[np.argmax(Fyy[1:])+1])   # excluding the zero frequency "peak", which is related to offsetguess_amp = np.std(y_LD) * 2.**0.5guess_offset = np.mean(y_LD)guess = np.array([guess_amp, 2.*np.pi*guess_freq, 0., guess_offset])def sinfunc_LD(t_LD, A, w, p, c):    return A * np.sin(w*t_LD + p) + c#boundary=([0,-np.inf,-np.pi, 1.5],[0.8, +np.inf, np.pi, 2.5])popt, pcov = scipy.optimize.curve_fit(sinfunc_LD, t_LD, y_LD, p0=guess, maxfev=3000) # with maxfev= number I can increase the number of iterationsA, w, p, c = poptf          = w/(2.*np.pi)fitfunc_LD = lambda t_LD: A*np.sin(w*t_LD + p) + cfitted_LD  = fitfunc_LD(t_LD)dic_LD = {"amp_LD": A, "omega_LD": w, "phase_LD": p, "offset_LD": c, "freq_LD": f, "period_LD": 1./f, "fitfunc_LD": fitted_LD, "maxcov_LD": np.max(pcov), "rawres_LD": (guess, popt, pcov)}return dic_LDdef fit_sin_APD(t_APD, y_APD):''' 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 spacingFyy = abs(np.fft.fft(y_APD))guess_freq = abs(ff[np.argmax(Fyy[1:])+1])   # excluding the zero frequency "peak", which is related to offsetguess_amp = np.std(y_APD) * 2.**0.5guess_offset = np.mean(y_APD)guess = np.array([guess_amp, 2.*np.pi*guess_freq, 0., guess_offset])我不明白為什么curve_fit會返回負幅度(就物理學而言沒有意義)。我也嘗試將邊界條件設置為 **kwargs* :bounds=([0.0, -np.inf,-np.pi, 0.0],[+np.inf, +np.inf,-np.pi, +np.inf])但它會產生更奇怪的結果。我添加了一張顯示這種差異的圖片:有誰如何通過相位和幅度來克服這個問題?
查看完整描述

1 回答

?
喵喔喔

TA貢獻1735條經驗 獲得超5個贊

這里有幾個我不明白的問題:

  1. 無需在“擬合函數”中定義擬合函數

  2. 如果唯一的區別是字典的命名,則無需定義兩次。(雖然我不明白為什么首先必須以不同的方式命名)

  3. 一個可以直接擬合頻率而不是歐米茄

  4. 預先計算擬合值時,直接使用給定的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

即在第一次嘗試中,盡管對幅度進行了很好的猜測,但結果為負。這可能是由于大相位。由于該猜測為零,因此算法更容易先切換幅度的符號,然后再調整相位。如上所述,這很容易糾正,甚至不需要錯誤傳播。

http://img1.sycdn.imooc.com//633e960f0001f7b006120452.jpg

查看完整回答
反對 回復 2022-10-06
  • 1 回答
  • 0 關注
  • 163 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號