我怎样才能用我当前的数据拟合这个正弦波?

How can I fit this sinusoidal wave with my current data?

我收集了一些数据来分析加速度随时间的变化。但是当我编写下面的代码以很好地拟合正弦波时,结果就是这样。这是因为我没有足够的数据还是我在这里做错了什么?

在这里你可以看到我的图表:

直接绘制的测量值(不适合)

适合水平和垂直移位(curve_fit)

linspace增加了数据

手动操作振幅

编辑:我通过使用 linspace 函数增加了数据大小并绘制了它,但我不确定为什么振幅不匹配,是因为要分析的数据很少吗? (我可以手动控制振幅,但我不明白为什么不能)

我用于拟合的代码

def model(x, a, b):

    return a * np.sin(b * x)

param, parav_cov = cf(model, time, z_values)

array_x = np.linspace(800, 1400, 1000)

fig = plt.figure(figsize = (9, 4))

plt.scatter(time, z_values, color = "#3333cc", label = "Data")

plt.plot(array_x, model(array_x, param[0], param[1], param[2], param[3]), label = "Sin Fit")

我会使用 FFT 来初步猜测参数,因为这种事情是高度非线性的,否则 curve_fit 不太可能走得太远。使用 FFT 的原因是为了初步了解所涉及的频率,仅此而已。 3Blue1Brown 有一个很棒的 video on FFTs 如果你不觉得它

我使用 web plot digitizer 从绘图中获取数据,然后进入 Python 并确保它看起来正常:

import pandas as pd
import matplotlib.pyplot as plt

df = pd.read_csv('sinfit2.csv')
print(df.head())

给我:

       x     y
0  809.3   0.3
1  820.0   0.3
2  830.3  19.6
3  839.9  19.6
4  849.6   0.4

我首先用 NumPy 做了一个基本的 FFT(SciPy 有更完整的 fftpack,但这里不需要):

import numpy as np
from numpy.fft import fft

d = fft(df.y)

plt.plot(np.abs(d)[:len(d)//2], '.')

np.abs(d) 是因为你得到一个包含相位和振幅的复数,而 [:len(d)//2] 是因为(对于实值输入)输出关于中点对称,即 d[5] == d[-5].

这表示最大的分量是 18,我试着手工绘制它,看起来还不错:

x = np.linspace(0, np.pi * 2, len(df))

plt.plot(df.x, df.y, '.-', lw=1)
plt.plot(df.x, np.sin(x * 18) * 10 + 10)

我乘以 10 并加 10 是因为正弦的范围是 (-1, +1),我们需要将它取到 (0, 20)。

接下来我将这些传递给 curve_fit 使用简化模型来帮助它:

from scipy.optimize import curve_fit

def model(x, a, b):
    return np.sin(x * a + b) * 10 + 10

(a, b), cov = curve_fit(model, x, df.y, [18, 0])

我再次对 * 10 + 10 进行硬编码以获得与您的数据匹配的范围,这给了我 a=17.8b=2.97

最后我绘制了以更高频率采样的函数以确保一切正常:

plt.plot(df.x, df.y)
plt.plot(
    np.linspace(810, 1400, 501),
    model(np.linspace(0, np.pi*2, 501), a, b)
)

给我:

看起来还不错。请注意,您可能想要更改这些参数以使其适合您的原始 X,并注意我的 df.x 从 810 开始,所以我可能错过了第一点。