You can use curve_fit with a number of trigonometric functions, usually very reliable and precision-tuned, that you need, just increasing the number of terms ... here is an example:
from scipy import sin, cos, linspace def f(x, a0,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12, c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12): return a0 + s1*sin(1*x) + c1*cos(1*x) \ + s2*sin(2*x) + c2*cos(2*x) \ + s3*sin(3*x) + c3*cos(3*x) \ + s4*sin(4*x) + c4*cos(4*x) \ + s5*sin(5*x) + c5*cos(5*x) \ + s6*sin(6*x) + c6*cos(6*x) \ + s7*sin(7*x) + c7*cos(7*x) \ + s8*sin(8*x) + c8*cos(8*x) \ + s9*sin(9*x) + c9*cos(9*x) \ + s10*sin(9*x) + c10*cos(9*x) \ + s11*sin(9*x) + c11*cos(9*x) \ + s12*sin(9*x) + c12*cos(9*x) from scipy.optimize import curve_fit pi/2. / (x.max() - x.min()) x_norm *= norm_factor popt, pcov = curve_fit(f, x_norm, y) x_fit = linspace(x_norm.min(), x_norm.max(), 1000) y_fit = f(x_fit, *popt) plt.plot( x_fit/x_norm, y_fit )
source share