My nonlinear data are approximated using a least square fit with the formula Asin(wt+phase)exp(-decay*t)
while keeping omega(w)
as a constant. I have tried several approaches without success.
Below is my code
import numpy as np
from numpy import loadtxt
import lmfit
np.random.seed(2)
x = np.linspace(0, 10, 101)
decay = 4.5
shift = 0
amp = 0.0015
y = amp * np.sin(x*5+shift) * np.exp(-x*decay)
yn = y + np.random.normal(size=y.size, scale=0.450)
def resid(params, x, ydata):
decay = params['decay'].value
shift = params['shift'].value
amp = params['amp'].value
y_model = amp * np.sin(x*5+shift) * np.exp(-x*decay)
return y_model - ydata
params = lmfit.Parameters()
params.add('shift', 0.0, min=-np.pi, max=np.pi)
params.add('amp', 0.0015, min=0, max=0.02)
params.add('decay', 4.0, min=0, max=10.0)
fit = lmfit.minimize(resid, params, args=(x, yn), method='differential_evolution')
print("\n\n# Fit using differential_evolution:")
lmfit.report_fit(fit)
plt.plot(x, y, 'ko', lw=2)
plt.plot(x, yn+fit.residual, 'b--', lw=2)
plt.legend(['data', 'leastsq', 'diffev'], loc='upper left')
plt.show()
Comments pointed out that the decay you have is very severe. But also, the noise you add to
yn
is enormous compared to your decaying sine wave. You and others may have missed this because you do not plot theyn
array that you fit, rather you ploty
, without the added noisedata
.If you do plot the data you actually use in the fit:
you will see this:
You also label the very poort best-fit you get as
leastsq
though you actually useddifferential_evolution
.If you lower the noise and the decay in your test data, and really fit with
leastsq
, you might have something like this:which will give a report of
and a plot of
I think the conclusion is that your residual function and setting up the problem are OK, but your very noisy test data set is not represented by that decaying sine-wave very well.