我怎样才能使这个正弦波与我当前的数据相匹配?

Bar*_*nat 4 python numpy matplotlib curve-fitting data-fitting

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

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

直接绘制测量结果(不适合)

在此输入图像描述

适合水平和垂直移动(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")
Run Code Online (Sandbox Code Playgroud)

Sam*_*son 5

我会使用 FFT 来对参数进行初步猜测,因为这种事情是高度非线性的,curve_fit否则不太可能走得太远。使用 FFT 的原因是为了初步了解所涉及的频率,仅此而已。如果您还没有看过, 3Blue1Brown 有一个关于 FFT 的精彩视频

我使用网络绘图数字化仪从绘图中获取数据,然后将其导入 Python 并确保它看起来不错:

import pandas as pd
import matplotlib.pyplot as plt

df = pd.read_csv('sinfit2.csv')
print(df.head())
Run Code Online (Sandbox Code Playgroud)

给我:

       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
Run Code Online (Sandbox Code Playgroud)

我首先使用 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], '.')
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

我乘以 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])
Run Code Online (Sandbox Code Playgroud)

我再次对 进行硬编码* 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)
)
Run Code Online (Sandbox Code Playgroud)

给我:

验证图

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