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()
您可以使用scipy中的least-square optimization函数将任意函数拟合到另一个函数。在拟合sin函数的情况下,要拟合的3个参数是偏移量(“a”)、振幅(“b”)和相位(“c”)。
只要对参数提供合理的第一次猜测,优化就应该收敛得很好。幸运的是,对于正弦函数,其中两个参数的第一次估计是很容易的:偏移量可以通过取数据的平均值和通过RMS(3*标准差/sqrt(2))得到的振幅来估计。
注:作为以后的编辑,还添加了频率拟合。这不是很好的工作(可能导致极不适合)。因此,根据您的判断,我的建议是不要使用频率拟合,除非频率误差小于百分之几。
这将导致以下代码:
编辑:我假设你知道正弦波的周期数。如果你不喜欢,那就更难适应了。您可以尝试通过手动绘图猜测周期数,并尝试将其优化为您的第6个参数。
对我们来说更友好的是curvefit函数。这里有一个例子:
这里有一个无参数拟合函数
fit_sin()
,不需要手动猜测频率:初始频率的猜测是由频域中的峰值频率通过FFT给出的。假设只有一个主频(而不是零频峰值),拟合结果几乎是完美的。
即使在高噪音的情况下,效果也很好:
相关问题 更多 >
编程相关推荐