The signal I want to fit is a superposition of multiple sine-functions (and noise) and I want to fit for all frequencies simultaneously. Here an example data file, generated with two frequencies of 240d^-1 and 261.8181d^-1: https://owncloud.gwdg.de/index.php/s/JZQTJ3VMYZH8qNB and plot of the time series (excerpt)
So far I can fit one sine-function after the other, while keeping the frequency fixed to a value. I get the frequency from e.g. a periodogram and in the end I am interested in amplitude and phase of the fit.
import numpy as np
from scipy import optimize
import bottleneck as bn
def f_sinus0(x,a,b,c,d):
return a*np.sin(b*x+c)+d
def fit_single(t, flux, flux_err, freq_model, c0 = 0.):
# initial guess for the parameter
d0 = bn.nanmean(flux)
a0 = 3*np.std(flux)/np.sqrt(2.)
# fit function with fixed frequency "freq_model"
popt, pcov = optimize.curve_fit(lambda x, a, c, d:
f_sinus0(x, a, freq_model*2*np.pi, c, d),
t, flux, sigma = flux_err, p0 = (a0,c0,d0),
bounds=([a0-0.5*abs(a0),-np.inf,d0-0.25*abs(d0)],
[a0+0.5*abs(a0),np.inf,d0+0.25*abs(d0)]),
absolute_sigma=True)
perr = np.sqrt(np.diag(pcov))
return popt, perr
filename = 'data-test.csv'
data = np.loadtxt(filename)
time = data[0]
flux = data[1]
flux_err = data[2]
freq_model = 260 #d^-1
popt, perr = fit_single(time, flux, flux_err, freq_model, c0 = 0.)
Now I want to fit both frequencies simultaneously. I defined a function that returns a sum of fitting-functions, depending on the length of the input-parameter-list like this
def f_multiple_sin(x, *params):
y = np.zeros_like(x)
for i in range(0, len(params), 4): #4=amplitude, freq, phase, offset
amplitude = params[i]
freq = params[i+1]
phase = params[i+2]
offset = params[i+3]
y = y + amplitude*np.sin(np.multiply(freq, x)+phase)+offset
return y
Performing the fit
def fit_multiple(t, flux, flux_err, guess):
popt, pcov = optimize.curve_fit(
f_multiple_sin, t, flux, sigma=flux_err, p0=guess,
bounds=(guess-np.multiply(guess,0.1),guess+np.multiply(guess,0.1)),
absolute_sigma=True
)
perr = np.sqrt(np.diag(pcov))
return popt, perr
guess = [4.50148944e-03, 2.40000040e+02, 3.01766641e-03, 8.99996136e-01, 3.14546648e-03, 2.61818207e+02, 2.94282247e-03, 5.56770657e-06]
popt, perr = fit_multiple(time, flux, flux_err, guess)
using the results from the individual fits as initial parameters guess = [amplitude1, frequency1, phase1, offset1, amplitude2,...]
But how can I fit multiple sine-functions, each with a fixed frequency? The lambda
approach seems not so straight forward to me in this case.