import numpy as np
from scipy.optimize import leastsq
import pylab as plt
N = 1000 # number of data points
t = np.linspace(0, 4*np.pi, N)
f = 1.15247 # Optional!! Advised not to use
data = 3.0*np.sin(f*t+0.001) + 0.5 + np.random.randn(N) # create artificial data with noise
guess_mean = np.mean(data)
guess_std = 3*np.std(data)/(2**0.5)/(2**0.5)
guess_phase = 0
guess_freq = 1
guess_amp = 1
# we'll use this to plot our first estimate. This might already be good enough for you
data_first_guess = guess_std*np.sin(t+guess_phase) + guess_mean
# Define the function to optimize, in this case, we want to minimize the difference
# between the actual data and our "guessed" parameters
optimize_func = lambda x: x[0]*np.sin(x[1]*t+x[2]) + x[3] - data
est_amp, est_freq, est_phase, est_mean = leastsq(optimize_func, [guess_amp, guess_freq, guess_phase, guess_mean])[0]
# recreate the fitted curve using the optimized parameters
data_fit = est_amp*np.sin(est_freq*t+est_phase) + est_mean
# recreate the fitted curve using the optimized parameters
fine_t = np.arange(0,max(t),0.1)
data_fit=est_amp*np.sin(est_freq*fine_t+est_phase)+est_mean
plt.plot(t, data, '.')
plt.plot(t, data_first_guess, label='first guess')
plt.plot(fine_t, data_fit, label='after fitting')
plt.legend()
plt.show()
import numpy as np
from scipy.optimize import curve_fit
import pylab as plt
N = 1000 # number of data points
t = np.linspace(0, 4*np.pi, N)
data = 3.0*np.sin(t+0.001) + 0.5 + np.random.randn(N) # create artificial data with noise
guess_freq = 1
guess_amplitude = 3*np.std(data)/(2**0.5)
guess_phase = 0
guess_offset = np.mean(data)
p0=[guess_freq, guess_amplitude,
guess_phase, guess_offset]
# create the function we want to fit
def my_sin(x, freq, amplitude, phase, offset):
return np.sin(x * freq + phase) * amplitude + offset
# now do the fit
fit = curve_fit(my_sin, t, data, p0=p0)
# we'll use this to plot our first estimate. This might already be good enough for you
data_first_guess = my_sin(t, *p0)
# recreate the fitted curve using the optimized parameters
data_fit = my_sin(t, *fit[0])
plt.plot(data, '.')
plt.plot(data_fit, label='after fitting')
plt.plot(data_first_guess, label='first guess')
plt.legend()
plt.show()
import numpy as np
import pylab as plt
# fake data
N = 1000 # number of data points
t = np.linspace(0, 4*np.pi, N)
f = 1.05
data = 3.0*np.sin(f*t+0.001) + np.random.randn(N) # create artificial data with noise
# FFT...
mfft=np.fft.fft(data)
imax=np.argmax(np.absolute(mfft))
mask=np.zeros_like(mfft)
mask[[imax]]=1
mfft*=mask
fdata=np.fft.ifft(mfft)
plt.plot(t, data, '.')
plt.plot(t, fdata,'.', label='FFT')
plt.legend()
plt.show()
from sklearn.linear_model import LinearRegression
reg = LinearRegression()
x= # your x values list
y = # your y values list
X = np.column_stack((np.sin(x), np.cos(x)))
reg.fit(X, y)
可以通过以下方式访问拟合参数:
a = reg.intercept_
b = reg.coef_[0]
c = reg.coef_[1]
6条答案
按热度按时间6vl6ewon1#
下面是一个不需要手动猜测频率的无参数拟合函数
fit_sin()
:初始频率猜测由使用FFT的频域中的峰值频率给出。假设只有一个主频率(除了零频率峰值),拟合结果几乎是完美的。
即使在高噪声情况下,效果也很好:
振幅=1.00660540618,角频率=2.03370472482,相位=0.360276844224,偏移=3.95747467506,最大值Cov.=0.0122923578658
62o28rlo2#
你可以在scipy中使用least-square optimization函数来拟合任意函数。在拟合sin函数的情况下,要拟合的3个参数是偏移(“a”)、幅度(“b”)和相位(“c”)。
只要你提供了一个合理的参数的第一个猜测,优化应该收敛得很好。幸运的是,对于正弦函数,首先估计其中的2个是很容易的:可以通过RMS(3* 标准偏差/sqrt(2))取数据和幅度的平均值来估计偏移。
注:作为后期编辑,还添加了频率拟合。这并不能很好地工作(可能导致极差的配合)。因此,使用在您的自由裁量权,我的建议是不要使用频率拟合,除非频率误差小于百分之几。
这将导致以下代码:
编辑:我假设你知道正弦波的周期数。如果你不这样做,它是有点棘手的适合。您可以尝试通过手动绘图来猜测周期数,并尝试将其优化为第6个参数。
lg40wkob3#
对我们来说更友好的是函数curvefit。这里有一个例子:
xesrikrc4#
目前的方法来拟合正弦曲线到一个给定的数据集需要一个参数的第一次猜测,其次是一个迭代的过程。这是一个非线性回归问题。
一种不同的方法在于通过方便的积分方程将非线性回归转换为线性回归。然后,不需要初始猜测,也不需要迭代过程:直接获得拟合。
对于函数
y = a + r*sin(w*x+phi)
或y=a+b*sin(w*x)+c*cos(w*x)
,请参见Scribd上发表的论文"Régression sinusoidale"
的第35 - 36页在函数
y = a + p*x + r*sin(w*x+phi)
的情况下:第49 - 51页的“混合线性和正弦回归”一章。对于更复杂的函数,一般过程在第54 - 61页的
"Generalized sinusoidal regression"
一章中进行了说明,随后是第62 - 63页的数值示例y = r*sin(w*x+phi)+(b/x)+c*ln(x)
insrf1ej5#
上面所有的答案都是基于曲线拟合,并且大多数使用迭代方法-它们都工作得很好,但我想使用FFT添加一种不同的方法。在这里,我们变换数据,将除峰值频率之外的所有频率设置为零,然后进行逆变换。请注意,您可能希望在执行FFT之前删除数据平均值(和去趋势),然后您可以在FFT之后将其添加回来。
ej83mcc06#
如果您已经知道频率,则可以进行线性拟合,这在计算上比非线性拟合方法更有效。正如@JJacquelin所指出的,不需要最初的猜测。
明确地说,您需要将
y=a+b*sin(x)+c*sin(x)
拟合到数据中。请注意,这等效于A*sin(x+phi)
,通过trig恒等式。然而,这是以拟合参数线性的方式表达的(尽管不是x,y)。因此,我们可以在Python中使用线性拟合。假设
x1 = sin(x)
和x2 = cos(x)
是输入,对y = a + b* x1 + c* x2
使用线性拟合函数做那个用途
可以通过以下方式访问拟合参数: