在 Python 中拟合正弦数据

Fitting sinusoidal data in Python

我正在尝试拟合实验数据

具有以下形式的函数:

A * np.sin(w*t + p) * np.exp(-g*t) + c

然而,拟合曲线(下图中的直线)并不准确:

如果我省略了指数衰减部分,它就起作用了,我得到了一个不衰减的正弦函数:

我使用的函数来自this thread:

def fit_sin(tt, yy):
    '''Fit sin to the input time sequence, and return fitting parameters "amp", "omega", "phase", "offset", "freq", "period" and "fitfunc"'''
    tt = np.array(tt)
    yy = np.array(yy)
    ff = np.fft.fftfreq(len(tt), (tt[1]-tt[0]))   # assume uniform spacing
    Fyy = abs(np.fft.fft(yy))
    guess_freq = abs(ff[np.argmax(Fyy[1:])+1])   # excluding the zero frequency "peak", which is related to offset
    guess_amp = np.std(yy) * 2.**0.5
    guess_offset = np.mean(yy)
    guess_phase = 0.
    guess_damping = 0.5
    guess = np.array([guess_amp, 2.*np.pi*guess_freq, guess_phase, guess_offset, guess_damping])

    def sinfunc(t, A, w, p, g, c):  return A * np.sin(w*t + p) * np.exp(-g*t) + c
    popt, pcov = scipy.optimize.curve_fit(sinfunc, tt, yy, p0=guess)
    A, w, p, g, c = popt
    f = w/(2.*np.pi)
    fitfunc = lambda t: A * np.sin(w*t + p) * np.exp(-g*t) + c
    return {"amp": A, "omega": w, "phase": p, "offset": c, "damping": g, "freq": f, "period": 1./f, "fitfunc": fitfunc, "maxcov": np.max(pcov), "rawres": (guess,popt,pcov)}

res = fit_sin(x, y)
x_fit = np.linspace(np.min(x), np.max(x), len(x))

plt.plot(x, y, label='Data', linewidth=line_width)
plt.plot(x_fit, res["fitfunc"](x_fit), label='Fit Curve', linewidth=line_width)
plt.show()

我不确定我是否错误地实现了代码,或者该函数是否无法正确描述我的数据。感谢您的帮助!

您可以从这里加载 txt 文件:

GitHub

并像这样操作数据以将其与 post:

进行比较
file = 'A2320_Data.txt'
column = 17

data = np.loadtxt(file, float)

start = 270
end = 36000

time_scale = 3600

x = []
y = []
for i in range(len(data)):
    if start < data[i][0] < end:
        x.append(data[i][0]/time_scale)
        y.append(data[i][column])

x = np.array(x)
y = np.array(y)

plt.plot(x, y, label='Pyro Oscillations', linewidth=line_width)

您的拟合曲线将如下所示


import numpy as np
import matplotlib.pyplot as plt
import scipy.optimize
def sinfunc(t, A, w, p, g, c):  return A * np.sin(w*t + p) * np.exp(-g*t) + c

tt = np.linspace(0, 10, 1000)
yy = sinfunc(tt, -1, 10, 2, 0.3, 2)
plt.plot(tt, yy)

g水平拉伸包络,c垂直移动中心,w确定振荡频率,A垂直拉伸包络

因此它无法准确地为您拥有的数据建模。

此外,您将无法可靠地拟合 w,要确定振荡频率,最好尝试 FFT

当然,您可以通过添加更多参数来调整函数以使其看起来像您的数据,例如

import numpy as np
import matplotlib.pyplot as plt
import scipy.optimize
def sinfunc(t, A, w, p, g, c1, c2, c3):  return A * np.sin(w*t + p) * (np.exp(-g*t) - c1) + c2 * np.exp(-g*t) + c3

tt = np.linspace(0, 10, 1000)
yy = sinfunc(tt, -1, 20, 2, 0.5, 1, 1.5, 1)
plt.plot(tt, yy)

但是你仍然需要对频率给出一个很好的猜测。