在 Python 中拟合正弦数据

发布于 2025-01-15 13:02:01 字数 2665 浏览 4 评论 0原文

我正在尝试拟合实验数据

在此处输入图像描述

具有以下形式的函数:

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

但是,拟合的曲线(下图中的线)不准确:

sstatic.net/XYS2H.png" rel="nofollow noreferrer">在此处输入图像描述

如果我省略指数衰减部分,它会起作用我得到了一个不会衰退的窦功能:

在此处输入图像描述

我使用的函数来自 此线程

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

并像这样操作数据进行比较它与帖子:

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)

I am trying to fit experimental data

enter image description here

with a function of the form:

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

However, the fitted curve (the line in the following image) is not accurate:

enter image description here

If I leave out the exponential decay part, it works and I get a sinus function that is not decaying:

enter image description here

The function that I use is from 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()

I am not sure if I implemented the code incorrectly or if the function is not able to describe my data correctly. I appreciate your help!

You can load the txt file from here:

GitHub

and manipulate the data like this to compare it with the 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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

坐在坟头思考人生 2025-01-22 13:02:01

您的拟合曲线将如下所示


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)

在此处输入图像描述

但您仍然需要对频率进行很好的猜测。

Your fitted curve will look like this


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)

enter image description here

g stretches the envelope horizontally, c moves the center vertically, w determines the oscillation frequency, A stretches the envelope vertically.

So it can't accurately model the data you have.

Also, you will not be able to reliably fit w, to determine the oscilation frequency it is better to try an FFT.

Of course you could adjust the function to look like your data by adding a few more parameters, e.g.

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)

enter image description here

But you will still have to give a good guess for the frequency.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文