As this question confirmed, Python doesn't currently have a sum of sines function like MATLAB.
I am looking to curve fit a 4th-order sinusoid in Python. Here is the MATLAB solution:
ft = fittype('sin4');
opts = fitoptions('Method', 'NonlinearLeastSquares');
[fitresult, gof] = fit(xData, yData, ft, opts);
% values for [a1, b1, ..., c4] are calculated
% fitted result
x=1:length(yData);
y=a1*sin(b1*x+c1) + a2*sin(b2*x+c2) + a3*sin(b3*x+c3) + a4*sin(b4*x+c4);
I can create a 1st-order sinusoidal fit with this solution (adapted):
def fit_sin(tt, yy):
'''Fit sinewave to input time sequence'''
tt = numpy.array(tt)
yy = numpy.array(yy)
ff = numpy.fft.fftfreq(len(tt), (tt[1]-tt[0]))
Fyy = abs(numpy.fft.fft(yy))
guess_freq = abs(ff[numpy.argmax(Fyy[1:])+1])
guess_amp = numpy.std(yy) * 2.**0.5
guess_offset = numpy.mean(yy)
guess = numpy.array([guess_amp, 2.*numpy.pi*guess_freq, 0., guess_offset])
def sinfunc(t, A, w, p, c): return A * numpy.sin(w*t + p) + c
popt, pcov = scipy.optimize.curve_fit(sinfunc, tt, yy, p0=guess)
A, w, p, c = popt
f = w/(2.*numpy.pi)
fitfunc = lambda t: A * numpy.sin(w*t + p) + c
return {"amp": A, "omega": w, "phase": p, "offset": c, "freq": f, "period": 1./f, "fitfunc": fitfunc, "maxcov": numpy.max(pcov), "rawres": (guess,popt,pcov)}
x = np.arange(0, len(yData))
res = fit_sin(x, yData)
y = res['fitfunc'](x)
So far I have tried iterating by entering the 1st-order output parameters (amp, omega, and phase)
as input parameters p0 = (a1, b1, and c1)
to a 2nd-order version of fit_sin()
, and working my way up to a 4th-order.
However, this is very inefficient and the results did not match the MATLAB solution. Suggestions for how to proceed would be appreciated.