Ejemplo n.º 1
0
def get_timing_lombscargle(n, ofac, hfac):

    x, y, dy = generate_random_signal(n)

    Nf = int(floor(0.5 * len(x) * ofac * hfac))
    df = 1. / (ofac * (max(x) - min(x)))
    f0 = df

    model = LombScargleFast(silence_warnings=True)
    model.fit(x, y, dy)
    t0 = time()
    model.score_frequency_grid(f0, df, Nf)
    dt = time() - t0

    return dt
Ejemplo n.º 2
0
def FlarePer(time, minper=0.1, maxper=30.0, nper=20000):
    '''
    Look for periodicity in the flare occurrence times. Could be due to:
    a) mis-identified periodic things (e.g. heartbeat stars)
    b) crazy binary star flaring things
    c) flares on a rotating star
    d) bugs in code
    e) aliens

    '''

    # use energy = 1 for flare times.
    # This will create something like the window function
    energy = np.ones_like(time)

    # Use Jake Vanderplas faster version!
    pgram = LombScargleFast(fit_offset=False)
    pgram.optimizer.set(period_range=(minper, maxper))

    pgram = pgram.fit(time, energy - np.nanmedian(energy))

    df = (1. / minper - 1. / maxper) / nper
    f0 = 1. / maxper
    pwr = pgram.score_frequency_grid(f0, df, nper)

    freq = f0 + df * np.arange(nper)
    per = 1. / freq

    pk = per[np.argmax(pwr)]  # peak period
    pp = np.max(pwr)  # peak period power

    return pk, pp
Ejemplo n.º 3
0
    def Periodogram(self, madVar=True):
        """ This function computes the power spectrum from the timeseries ONLY.
        """

        dtav = np.mean(np.diff(self.time_fix))  # mean value of time differences (s)
        dtmed = np.median(np.diff(self.time_fix))  # median value of time differences (s)
        if dtmed == 0:  dtmed = dtav

        # compute periodogram from regular frequency values
        fmin = 0  # minimum frequency
        N = len(self.time_fix)  # n-points
        df = 1./(dtmed*N)  # bin width (1/Tobs) (in Hz)
        model = LombScargleFast().fit(self.time_fix, self.flux_fix, np.ones(N))
        power = model.score_frequency_grid(fmin, df, N/2)  # signal-to-noise ratio, (1) eqn 9
        freqs = fmin + df * np.arange(N/2)  # the periodogram was computed over these freqs (Hz)

        # the variance of the flux
        if madVar:  var = mad_std(self.flux_fix)**2
        else:       var = np.std(self.flux_fix)**2

        # convert to PSD, see (1) eqn 1, 8, 9 & (2)
        power /= np.sum(power)  # make the power sum to unity (dimensionless)
        power *= var  # Parseval's theorem. time-series units: ppm. variance units: ppm^2
        power /= df * 1e6  # convert from ppm^2 to ppm^2 muHz^-1

        if len(freqs) < len(power):  power = power[0:len(freqs)]
        if len(freqs) > len(power):  freqs = freqs[0:len(power)]

        self.freq = freqs * 1e6    # muHz
        self.power = power         # ppm^2 muHz^-1
        self.bin_width = df * 1e6  # muHz
Ejemplo n.º 4
0
    def fast_find_spectrum(self, f_samps, mag_low, mag_high, raw=False):
        """
        Finds the Lomb-Scargle periodogram of the concentration time series,
        frequency units are in hz. This method uses the Gatspy package, which
        has a fast fft based periodogram calculator.

        f_samps -- int; number of frequency samples to be used in the fitting,
                        they are spaced logarithmically

        mag_low -- float;
        mag_high -- float; the sampled frequency range is
                    [10^mag_low, 10^mag_high]

        raw -- Boolean; if true, self.c_raw is used, otherwise self.c is used

        NB the frequency grid is linear (logarithmic in self.find_spectrum())
        in this method, so many more points should be used.
        """

        assert mag_low < mag_high

        if raw:
            abs_time = self.t_raw
            gas_conc = self.c_raw
        else:
            abs_time = self.t
            gas_conc = self.c

        rel_time = np.array([])
        #the date/datetime objects should be in increasing order, but it should
        #work all the same
        t0 = EPOCH
        for t in abs_time:
            delta_t = t - t0
            rel_time = np.append(rel_time, delta_t.total_seconds())

        fmin = 10**mag_low
        fmax = 10**mag_high

        df = (fmax - fmin) / f_samps

        #NB uses same x and t in the above section
        model = LombScargleFast().fit(rel_time, gas_conc)
        rel_power = model.score_frequency_grid(fmin, df, f_samps)
        freqs = fmin + df * np.arange(f_samps)

        abs_amplitude = gas_conc.std() * np.sqrt(2 * rel_power)

        self.rel_spectrum = np.array([freqs, rel_power])
        self.spectrum = np.array([freqs, abs_amplitude])
        return None
Ejemplo n.º 5
0
 def fAnalysis(self, rr_samples):
     """
     Frequency analysis to calc self.lf, self.hf, returns the LF/HF-ratio and
     also calculates the spectrum as pairs of (self.f_hr_axis,self.f_hr).
     The input arrary is in sample points where R peaks have been detected.
     """
     # discrete timestamps
     self.hr_discrete = self._intervals(rr_samples) / 1000
     # hr positions in time
     self.t_hr_discrete = [i / self.fs for i in rr_samples[1:]]
     # now let's create function which approximates the hr(t) relationship
     self.hr_func = interp1d(self.t_hr_discrete, self.hr_discrete)
     # we take 1024 samples for a linear time array for hr(t)
     nsamp = 1000
     # linear time array for the heartrate
     self.t_hr_linear = np.linspace(
         self.t_hr_discrete[1],
         self.t_hr_discrete[len(self.t_hr_discrete) - 2],
         num=nsamp)
     # duration in secs of the heartrate array minus the ends b/c of the approx
     duration = self.t_hr_discrete[len(self.t_hr_discrete) -
                                   2] - self.t_hr_discrete[1]
     # heartrate linearly approximated between discrete samples
     self.hr_linear = self.hr_func(self.t_hr_linear)
     model = LombScargleFast().fit(self.t_hr_discrete, self.hr_discrete,
                                   1E-2)
     fmax = 1
     fmin = 0.01
     df = (fmax - fmin) / nsamp
     self.f_hr = model.score_frequency_grid(fmin, df, nsamp)
     self.f_hr_axis = fmin + df * np.arange(nsamp)
     # lf
     self.lf = 0
     # hf
     self.hf = 0
     for i in range(0, int(nsamp / 2)):
         if (self.f_hr_axis[i] >= 0.04) and (self.f_hr_axis[i] <= 0.15):
             self.lf = self.lf + self.f_hr[i]
         if (self.f_hr_axis[i] >= 0.15) and (self.f_hr_axis[i] <= 0.4):
             self.hf = self.hf + self.f_hr[i]
     # hf
     return self.lf / self.hf
Ejemplo n.º 6
0
def FitSin(time,
           flux,
           error,
           maxnum=5,
           nper=20000,
           minper=0.1,
           maxper=30.0,
           plim=0.25,
           per2=False,
           returnmodel=True,
           debug=False):
    '''
    Use Lomb Scargle to find a periodic signal. If it is significant then fit
    a sine curve and subtract. Repeat this procedure until no more periodic
    signals are found, or until maximum number of iterations has been reached.

    Note: this is where major issues were found in the light curve fitting as
    of Davenport (2016), where the iterative fitting was not adequately
    subtracting "pointy" features, such as RR Lyr or EBs. Upgrades to the
    fitting step are needed! Or, don't use iterative sine fitting...

    Idea for future: if L-S returns a significant P, use a median fit of the
    phase-folded data at that P instead of a sine fit...

    Parameters
    ----------
    time : 1-d numpy array
    flux : 1-d numpy array
    error : 1-d numpy array
    maxnum : int, optional
        maximum number of iterations to try finding periods at
        (default=5)
    nper : int, optional
        number of periods to search over with Lomb Scargle
        (defeault=20000)
    minper : float, optional
        minimum period (in units of time array, nominally days) to search
        for periods over (default=0.1)
    maxper : float, optional
        maximum period (in units of time array, nominally days) to search
        for periods over (default=30.0)
    plim : float, optional
        Lomb-Scargle power threshold needed to define a "significant" period
        (default=0.25)
    per2 : bool, optional
        if True, use the 2-sine model fit at each period. if False, use normal
        1-sine model (default=False)
    returnmodel : bool, optional
        if True, return the combined sine model. If False, return the
        data - model (default=True)
    debug : bool, optional
        used to print out troubleshooting things (default=False)

    Returns
    -------
    If returnmodel=True, output = combined sine model (default=True)
    If returnmodel=False, output = (data - model)
    '''

    flux_out = np.array(flux, copy=True)
    sin_out = np.zeros_like(flux)  # return the sin function!

    # total baseline of time window
    dt = np.nanmax(time) - np.nanmin(time)

    medflux = np.nanmedian(flux)
    # ti = time[dl[i]:dr[i]]

    for k in range(0, maxnum):
        # Use Jake Vanderplas faster version!
        pgram = LombScargleFast(fit_offset=False)
        pgram.optimizer.set(period_range=(minper, maxper))
        pgram = pgram.fit(time, flux_out - medflux, error)

        df = (1. / minper - 1. / maxper) / nper
        f0 = 1. / maxper
        pwr = pgram.score_frequency_grid(f0, df, nper)

        freq = f0 + df * np.arange(nper)
        per = 1. / freq

        pok = np.where((per < dt) & (per > minper))
        pk = per[pok][np.argmax(pwr[pok])]
        pp = np.max(pwr)

        if debug is True:
            print('trial (k): ' + str(k) + '.  peak period (pk):' + str(pk) +
                  '.  peak power (pp):' + str(pp))

        # if a period w/ enough power is detected
        if (pp > plim):
            # fit sin curve to window and subtract
            if per2 is True:
                p0 = [
                    pk, 3.0 * np.nanstd(flux_out - medflux), 0.0, pk / 2.,
                    1.5 * np.nanstd(flux_out - medflux), 0.1, 0.0
                ]
                try:
                    pfit, pcov = curve_fit(_sinfunc2,
                                           time,
                                           flux_out - medflux,
                                           p0=p0)
                    if debug is True:
                        print('>>', pfit)
                except RuntimeError:
                    pfit = [pk, 0., 0., 0., 0., 0., 0.]
                    if debug is True:
                        print('Curve_Fit2 no good')

                flux_out = flux_out - _sinfunc2(time, *pfit)
                sin_out = sin_out + _sinfunc2(time, *pfit)

            else:
                p0 = [pk, 3.0 * np.nanstd(flux_out - medflux), 0.0, 0.0]
                try:
                    pfit, pcov = curve_fit(_sinfunc,
                                           time,
                                           flux_out - medflux,
                                           p0=p0)
                except RuntimeError:
                    pfit = [pk, 0., 0., 0.]
                    if debug is True:
                        print('Curve_Fit no good')

                flux_out = flux_out - _sinfunc(time, *pfit)
                sin_out = sin_out + _sinfunc(time, *pfit)

        # add the median flux for this window BACK in
        sin_out = sin_out + medflux

    # if debug is True:
    #     plt.figure()
    #     plt.plot(time, flux)
    #     plt.plot(time, flux_out, c='red')
    #     plt.show()

    if returnmodel is True:
        return sin_out
    else:
        return flux_out
Ejemplo n.º 7
0
def FitSin(time,
           flux,
           error,
           maxnum=5,
           nper=20000,
           minper=0.1,
           maxper=30.0,
           plim=0.25,
           returnmodel=True,
           debug=False,
           per2=False):
    '''
    Use Lomb Scargle to find periods, fit sins, remove, repeat.

    Parameters
    ----------
    time:
    flux:
    error:
    maxnum:
    nper: int, optional
        number of periods to search over with Lomb Scargle
    minper:
    maxper:
    plim:
    debug:

    Returns
    -------
    '''
    # periods = np.linspace(minper, maxper, nper)

    flux_out = np.array(flux, copy=True)
    sin_out = np.zeros_like(flux)  # return the sin function!

    # total baseline of time window
    dt = np.nanmax(time) - np.nanmin(time)

    medflux = np.nanmedian(flux)
    # ti = time[dl[i]:dr[i]]

    for k in range(0, maxnum):
        # Use Jake Vanderplas faster version!
        pgram = LombScargleFast(fit_offset=False)
        pgram.optimizer.set(period_range=(minper, maxper))
        pgram = pgram.fit(time, flux_out - medflux, error)

        df = (1. / minper - 1. / maxper) / nper
        f0 = 1. / maxper
        pwr = pgram.score_frequency_grid(f0, df, nper)

        freq = f0 + df * np.arange(nper)
        per = 1. / freq

        pok = np.where((per < dt) & (per > minper))
        pk = per[pok][np.argmax(pwr[pok])]
        pp = np.max(pwr)

        if debug is True:
            print('trial (k): ' + str(k) + '.  peak period (pk):' + str(pk) +
                  '.  peak power (pp):' + str(pp))

        # if a period w/ enough power is detected
        if (pp > plim):
            # fit sin curve to window and subtract
            if per2 is True:
                p0 = [
                    pk, 3.0 * np.nanstd(flux_out - medflux), 0.0, pk / 2.,
                    1.5 * np.nanstd(flux_out - medflux), 0.1, 0.0
                ]
                try:
                    pfit, pcov = curve_fit(_sinfunc2,
                                           time,
                                           flux_out - medflux,
                                           p0=p0)
                    if debug is True:
                        print('>>', pfit)
                except RuntimeError:
                    pfit = [pk, 0., 0., 0., 0., 0., 0.]
                    if debug is True:
                        print('Curve_Fit2 no good')

                flux_out = flux_out - _sinfunc2(time, *pfit)
                sin_out = sin_out + _sinfunc2(time, *pfit)

            else:
                p0 = [pk, 3.0 * np.nanstd(flux_out - medflux), 0.0, 0.0]
                try:
                    pfit, pcov = curve_fit(_sinfunc,
                                           time,
                                           flux_out - medflux,
                                           p0=p0)
                except RuntimeError:
                    pfit = [pk, 0., 0., 0.]
                    if debug is True:
                        print('Curve_Fit no good')

                flux_out = flux_out - _sinfunc(time, *pfit)
                sin_out = sin_out + _sinfunc(time, *pfit)

        # add the median flux for this window BACK in
        sin_out = sin_out + medflux

    # if debug is True:
    #     plt.figure()
    #     plt.plot(time, flux)
    #     plt.plot(time, flux_out, c='red')
    #     plt.show()

    if returnmodel is True:
        return sin_out
    else:
        return flux_out
Ejemplo n.º 8
0
    def power_spectrum(self, verbose=False, noise=0.0, \
                       length=-1):
        ''' This function computes the power spectrum from the timeseries.
        
        The function checks to see if the timeseries has been read in, and if not it calls the read_timeseries function.
        
        The porperties of the power spectrum can be altered for a given timeseries via the noise, and length parameters.
        
        The frequency and power are stored in the object atributes self.freq and self,power.
        
        Parameters
        ----------------
        verbose: Bool(False)
            Provide verbose output if set to True.
            
        noise: Float
            If noise is not zero then additional noise is added to the timeseries where the value of noise is the standard deviation of the additional noise.

        length: Int
            If length is not -1 then a subset of the timeseries is selected when n points will equal length.  The subset of data is taken from the start of the time series.  TODO this can be updated if neccessary.

        Returns
        ----------------
        
        NA
        
        Examples
        ----------------
        
        To read in a data set and create the power spectrum one need only run:
            
        >>> import K2data
        >>> star = K2data.Dataset(2001122017, '/home/davies/Data/ktwo_2001122017_llc.pow')
        >>> star.power_spectrum()
        
        '''
        if len(self.time) < 1:
            self.read_timeseries(verbose=True)
        if noise > 0.0:
            self.flux_fix[:length] += np.random.randn(len(self.time_fix[:length])) * noise
        dtav = np.mean(np.diff(self.time_fix[:length]))
        dtmed = np.median(np.diff(self.time_fix[:length]))
        if dtmed == 0:
            dtmed = dtav
        fmin = 0
        N = len(self.time_fix[:length]) #n-points
        df = 1.0 / dtmed / N #bw
        model = LombScargleFast().fit(self.time_fix[:length], \
                                    self.flux_fix[:length], \
                                      np.ones(N))
        power = model.score_frequency_grid(fmin, df, N/2)
        freqs = fmin + df * np.arange(N/2)
        var = np.std(self.flux_fix[:length])**2
        power /= np.sum(power)
        power *= var
        power /= df * 1e6
        if len(freqs) < len(power):
            power = power[0:len(freqs)]
        if len(freqs) > len(power):
            freqs = freqs[0:len(power)]
        self.freq = freqs * 1e6
        self.power = power
        if verbose:
            print("Frequency resolution : {}".format(self.freq[1]))
            print("Nyquist : ~".format(self.freq.max()))
Ejemplo n.º 9
0
plt.figure(0)
plt.plot(t, x)

#the frequency domain, component frequencies are clear (in hz)
plt.figure(1)
plt.plot(ang_f / ang, x_tilde_norm)

end0 = datetime.datetime.now()
print("SciPy took:", end0 - start0)
###############################################################################
from gatspy.periodic import LombScargleFast

start1 = datetime.datetime.now()

N = 1000
fmin = 0.001
fmax = 10

df = (fmax - fmin) / N

#NB uses same x and t in the above section
model = LombScargleFast().fit(t, x)
power = model.score_frequency_grid(fmin, df, N)
freqs = fmin + df * np.arange(N)

# plot the results
plt.figure()
plt.plot(freqs, ((x.std()) * np.sqrt(2 * power)), ls='', marker='+')

end1 = datetime.datetime.now()
print("Gatspy took:", end1 - start1)
		t=np.ma.array(t,mask=to_mask)
		signal=np.ma.array(signal,mask=to_mask)
	#We choose the frequency range we want to check. An angular frequency is required
	#for the L-S diagram.	
	fmin=0.01*f_real
	fmax=10.*f_real
	Nf= N
	df = (fmax - fmin) / Nf		
	f = 2.0*np.pi*np.linspace(fmin, fmax, Nf)
	
	#We take the L-S of the signal.	
	if hole_index == 0:
		pgram = LombScargleFast().fit(t, signal,sdev)
	elif hole_index == 1:
		pgram = LombScargleFast().fit(t[~t.mask], signal[~signal.mask],sdev)
	power = pgram.score_frequency_grid(fmin,df,Nf)
	
	#We plot the signal and the L-S
	fig, ax = plt.subplots(2, 1)
	ax[0].plot(t,signal, 'o', ms = 1.5)  
	ax[0].set_xlim([0.,T_tot])                         
	ax[0].set_xlabel('Time')
	ax[0].set_ylabel('Flux')
	ax[0].grid()
	
	#We want the frequency in Hz.
	ax[1].plot(f/2.0/np.pi/f_real, power, 'o')
	ax[1].set_xlim([fmin/2.0/np.pi/f_real,6])
	ax[1].set_xlabel('Freq (1/orbital period)')
	ax[1].set_ylabel('L-S power')
	ax[1].grid()
Ejemplo n.º 11
0
    def FFT_data(self, oversample=False):
        """------------------------------------------------------------------"""
        """perform FFT on timeseries, two options available: gatspy / astropy"""
        """------------------------------------------------------------------"""
        self.setTime()
        print("Pre-mask times length: %s" % len(self.times))
        self.mask_data()  #mask out useless data
        print("Post-mask times length: %s" % len(self.times))
        N = len(self.times)

        if self.FFT_option == 'gatspy':
            print('... using gatspy')
            #gatspy LS
            from gatspy.periodic import LombScargleFast
            #ls = LombScargleFast().fit(self.times, self.df)#, self.error)
            #periods, self.power = ls.periodogram_auto(nyquist_factor=2)
            #self.frequencies = (1/periods)*(1e6) #frequencies in microHz

            fmin = 0
            dtmed = np.median(np.diff(self.times))
            df = 1. / (dtmed * N)
            ls = LombScargleFast().fit(self.times, self.df, np.ones(N))
            power = ls.score_frequency_grid(fmin, df, N / 2)
            freqs = fmin + df * np.arange(N / 2)
            var = np.std(self.df)**2
            power /= np.sum(power)  # convert so sums to unity
            power *= var  # Parseval's: time-series units [G], variance units [G^2]
            power /= df * 1e6  # convert to G^2/muHz
            self.power = power
            self.frequencies = freqs * 1e6

            ts_energy = np.sum(np.abs(np.power(self.df, 2))) / N
            fd_energy = np.sum(np.abs(np.power(self.power, 2)))
            print('TS: %s' % ts_energy)
            print('FD: %s' % fd_energy)

            #df = pd.DataFrame({'periods':periods, 'power':power})
            #df.to_csv('/mnt/storage/003. Data/004. HiSPARC Data/FFT.csv')

        elif self.FFT_option == 'astropy':
            print('... using astropy')
            #astropy LS
            from astropy.stats import LombScargle
            from scipy.integrate import simps
            """ts_energy = simps(np.power(self.df,2), self.times)
            print(ts_energy)"""
            dtmed = np.median(np.diff(self.times))
            df = 1. / (dtmed * N)
            fmin = 0
            if oversample != False:
                frequencies = fmin + (
                    df / oversample) * np.arange(oversample * N / 2 + 1)
            else:
                frequencies = fmin + df * np.arange(N / 2 + 1)
            power = LombScargle(self.times, self.df).power(frequencies)
            power[0] = 0.0
            #frequencies, power = LombScargle(self.times, self.df).autopower(nyquist_factor=1)
            var = np.std(self.df)**2

            ts_energy = np.sum(np.abs(np.power(self.df, 2))) / N

            power /= np.sum(power)  # convert so sums to unity
            power *= var  # Parseval's: time-series units [G], variance units [G^2]

            fd_energy = np.sum(np.abs(np.power(power, 1)))

            power /= df * 1e6  # convert to G^2/muHz
            self.power = power
            self.frequencies = frequencies * 1e6  #frequencies in microHz

            #ts_energy = np.sum(np.abs(np.power(self.df,2)))/N
            #fd_energy = np.sum(np.abs(np.power(self.power,2)))
            print('TS: %s' % ts_energy)
            print('TS_var: %s' % var)
            print('FD: %s' % fd_energy)

        return self.frequencies, self.power, self.times
plt.ylabel('NUV Flux \n'
           r'(x10$^{-15}$ erg s$^{-1}$ cm$^{-2}$ ${\rm\AA}^{-1}$)')
plt.title('Flags = 0')

minper = 10  # my windowing
maxper = 200000
nper = 1000
pgram = LombScargleFast(fit_offset=False)
pgram.optimizer.set(period_range=(minper, maxper))

pgram = pgram.fit(time_big - min(time_big), flux_big - np.nanmedian(flux_big))

df = (1. / minper - 1. / maxper) / nper
f0 = 1. / maxper

pwr = pgram.score_frequency_grid(f0, df, nper)

freq = f0 + df * np.arange(nper)
per = 1. / freq

##
plt.figure()
plt.plot(per, pwr, lw=0.75)
plt.xlabel('Period (seconds)')
plt.ylabel('L-S Power')
plt.xscale('log')
plt.xlim(10, 500)
plt.savefig('periodogram.pdf', dpi=150, bbox_inches='tight', pad_inches=0.25)

t_unix = Time(exp_data['NUV']['t0'] + 315964800, format='unix')
mjd_time_med = t_unix.mjd