简单的scipy curve_fit测试未返回预期结果

时间:2018-09-21 17:41:11

标签: scipy curve-fitting frequency-analysis

我试图基于仅几个周期的测量来估计大约50Hz的输入信号的幅度,频率和相位。频率必须精确到0.01 Hz。由于信号本身将是一个非常清晰的正弦波,因此我正在尝试使用SciPy的curve_fit进行参数拟合。我以前从未使用过它,所以我写了一个快速测试功能。

我首先生成一个虚拟余弦波周期的样本

from math import *
import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt

fs = 1000 # Sampling rate (Hz)
T = .1 # Length of collection (s)
windowlength = int(fs*T) # Number of samples
f0 = 10 # Fundamental frequency of our wave (Hz)

wave = [0]*windowlength
for x in range(windowlength):
    wave[x] = cos(2*pi*f0*x/fs)

t = np.linspace(0,T,int(fs*T)) # This will be our x-axis for plotting

然后,我尝试将这些样本拟合为一个函数,并改编scipy提供的官方示例中的代码:https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.curve_fit.html

# Define function to fit
def sinefit(x, A, ph, f):
    return A * np.sin(2*pi*f * x + ph)

# Call curve_fit
popt,cov = curve_fit(sinefit, t, wave, p0=[1,np.pi/2,10])

# Plot the result
plt.plot(t, wave, 'b-', label='data')
plt.plot(t, sinefit(t, *popt), 'r-', label='fit')

print("[Amplitude,phase,frequency]")
print(popt)

这给了我popt = [1.,1.57079633,9.9]和情节

plot output

我的问题是:为什么我的频率不正常?我用余弦波的确切参数初始化了curve_fit函数,因此LM算法的第一次迭代难道不应该意识到残差为零并且已经得出正确答案了吗?振幅和相位似乎都是这种情况,但是频率太低了0.1Hz。

我希望这是一个愚蠢的编码错误,因为原始波形和拟合在图中清楚地排列了起来。我还确认了在整个样本中它们之间的差异为零。如果它们确实异相.1 Hz,则在我的100ms窗口中将有3.6度的相移。

任何想法都将不胜感激!

1 个答案:

答案 0 :(得分:1)

问题是您的数组t不正确。 t中的最后一个值为0.1,但是采样周期为1 / fs = 0.001,t中的最后一个值应为0.099。也就是说,这100个样本的时间为[0,0.001,0.002,...,0.098,0.099]。

您可以使用任一方法正确创建t

t = np.linspace(0, T, int(fs*T), endpoint=False)

t = np.arange(windowlength)/fs  # Use float(fs) if you are using Python 2