简体   繁体   中英

I am trying to fit periodic data to a template with scipy curve_fit but it doesn't find the period

I am trying to write a script that takes in photometry data of a potentially variable star and tries to fit a theoretical template to it to determine several characteristics about it such as period and amplitude.

The data comes with a date/time (in mjd, essentially the number of days since January 1, 4713 BC) and a brightness in magnitudes.

The template is an array of phase and y values, the phase going from t=0 to t=.998 (in increments of.002) as y goes from 0 to 1 and back to 0 over the period.

My model function will stretch and shift the template to have same peak-to-peak amplitude and same range as the data's y values. I shift the given t value then divide by the period to get time in terms of phase. I use %1 to remove everything but the fractional values, since I don't care which period the data comes from, just where in the period it lies. (ex 347.65 -> 0.65)

class tmpfitter:
    def __init__ (self, templets)
        self.n=0
        self.tmps=templets

    def model(self, t, period, t0, amplitude, yoffset):
        # modify the template using peak-to-peak amplitude, yoffset
        # shift times so phases line up, fold input times t by period
        xtemp = self.tmps[self.n,:,0]
        ytemp = self.tmps[self.n,:,1]*amplitude + yoffset
        ph = (t - t0) / period % 1 #Folds data into single period
        # interpolate the modified template at the phase we want
        return interp1d(xtemp,ytemp)(ph)


def tmpfit(templets,data,pinit):
    datfit = []
    npars = []
    fitter = tmpfitter(templets)
    # Iterate through all templates, finding a best fit for each, find best fit of best fits at end.
    for i in range(len(templets)):
        fitter.n = i
        pars, cov = curve_fit(fitter.model, data[:,0], data[:,1], sigma=data[:,2], p0=pinit, maxfev=10000)
        datfit.append(median(abs(fitter.model(data[:,0],pars[0],pars[1],pars[2],pars[3])-data[:,1])))
        npars.append(pars)
    n = np.argmin(datfit)
    return n, npars[n]

This correctly finds values for t0, amplitude and yoffset, but it is incapable of finding a period. If I give the correct period in the initial guess (p0) then this successfully fits the templates to the data. But if the period is off it will not change the period from the initial guess.

I suspect this is because of how I fold the data and chop off the whole number part, but am not knowledgeable enough about the curve_fit function to find a fix. I also tried using scipy's least_squares function (I know curve_fit is a wrapper for it) but couldn't get it to work either.

what would be a better way to do this fit?

This function will "fold" your time series for some period. You can then fit the resulting folded time curve to a sinusoid (or whatever model), and see what period gives the best results.

If you don't want to just randomly try different periods, you can take a fourier transform of the data and look for the period that gives the highest power. Though, that linked function I think requires evenly spaced data...

Here is a good description of how time series are handled when it comes to Cepheid variables.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM