2017-02-10 116 views
2

我试图适应的正弦波曲线这个数据分布,但由于某些原因,适合的才是不正确的:Python的 - 曲线拟合产生不正确配合

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





#======================= 
#====== Analysis ======= 
#======================= 

# sine curve fit 
def fit_Sin(t, A, b, C): 
    return A* np.sin(t*b) + C 

## The Data extraciton 
t,y,y1 = np.loadtxt("new10_CoCore_5to20_BL.txt", unpack=True) 

xdata = t 
popt, pcov = curve_fit(fit_Sin, t, y) 
print "A = %s , b = %s, C = %s" % (popt[0], popt[1], popt[2]) 



#======================= 
#====== Plotting ======= 
#======================= 

fig1 = plt.figure() 
ax1 = fig1.add_subplot(111) 

ax1.plot(t, y, ".") 
ax1.plot(t, fit_Sin(t, *popt)) 


plt.show() 

enter image description here

在此配合使数据极度低估。任何想法,为什么这是?

这里是这里提供的数据:https://www.dropbox.com/sh/72jnpkkk0jf3sjg/AAAb17JSPbqhQOWnI68xK7sMa?dl=0

知道为什么这是生产呢?

回答

3

如果您的频率猜测关闭,正弦波非常难以适应。这是因为在数据中有足够数量的周期时,猜测将与半数数据不同步,并且与半数数据同相,即使频率出现小错误。此时,直线比不同频率的正弦波更适合。这就是傅立叶变换工作的方式。

我能想到的三种方式来估计频率以及足以让一个非线性最小二乘算法接管:

  1. 眼球吧。减去GUI或甚至命令行中两个峰值的x值。如果您的数据噪音非常低,则可以轻松自动执行此过程。
  2. 使用离散傅里叶变换。如果你的数据是一个分量的正弦波,那么第一个非恒定峰值会给你频率。我发现这需要一些额外的调整,因为采样频率通常不是正弦波频率的倍数。围绕峰值的三个点(包括峰值的三个点)的抛物线拟合可以帮助解决这种情况。
  3. 找到您的数据跨越垂直偏移的位置。这与#1类似,但对于相对无噪音的数据更容易自动化。波长是一对交点之间距离的两倍。

使用#1,我可以清楚地看到您的波长为50.因此b的初始猜测应该是2*np.pi/50。此外,不要忘记添加一个相移参数,以使配合水平滑动:A*sin(b*t + d) + C

您需要通过p0参数初步猜出curve_fit。一个好的眼球估计是p0=(0.55, np.pi/25, 0.0, -np.pi/25*12.5)。数据中的相移似乎是右边的四分之一,因此是12.5。

我目前正在编写一个算法来拟合带有单个频率分量的噪声正弦波,我将提交给SciPy。完成后会更新。

+0

我已经有一些成功的使用遗传算法来提供初始参数估计,但我的经验是,你的#1建议似乎最佳。请注意,此处“C”的初始参数估计值只是数据的平均值。 –

+0

@JamesPhillips。对于足够棘手的数据(我已经看过例子),最好首先估计幅度,然后取峰值之间的一半距离。但说实话,除了频率,相移是唯一偶尔需要2次或3次迭代'curve_fit'才能确定的参数。 –

+0

我的计划是做一个愚蠢的KDE来获得比FFT更可靠的频率 –