def get_circadian_movement(fus_df): """Calculates the circadian movement based on GPS location for participants Basing implementation off of https://github.com/sosata/CS120DataAnalysis/blob/master/features/estimate_circadian_movement.m """ # frequency range of 24 +- 0.5 hrs at a minute granularity freq = np.linspace(86400 - 30 * 60, 86400 + 30 * 60, 60) # scipy implementation requires angular frequency freq = 2 * np.pi / freq try: # make sure to precenter each time series energy_lat = sum( lombscargle(fus_df['timestamp'], fus_df['latitude'], freq, precenter=True, normalize=True)) energy_long = sum( lombscargle(fus_df['timestamp'], fus_df['longitude'], freq, precenter=True, normalize=True)) except ZeroDivisionError: return np.nan tot_energy = energy_lat + energy_long if tot_energy > 0: return np.log(energy_lat + energy_long) else: return np.nan
def test_normalize(self): # Test normalize option of Lomb-Scarge. # Input parameters ampl = 2. w = 1. phi = 0.5 * np.pi nin = 100 nout = 1000 p = 0.7 # Fraction of points to select # Randomly select a fraction of an array with timesteps np.random.seed(2353425) r = np.random.rand(nin) t = np.linspace(0.01*np.pi, 10.*np.pi, nin)[r >= p] # Plot a sine wave for the selected times x = ampl * np.sin(w*t + phi) # Define the array of frequencies for which to compute the periodogram f = np.linspace(0.01, 10., nout) # Calculate Lomb-Scargle periodogram pgram = lombscargle(t, x, f) pgram2 = lombscargle(t, x, f, normalize=True) # check if normalization works as expected assert_allclose(pgram * 2 / np.dot(x, x), pgram2) assert_approx_equal(np.max(pgram2), 1.0, significant=2)
def test_precenter(self): # Test if precenter gives the same result as manually precentering. # Input parameters ampl = 2. w = 1. phi = 0.5 * np.pi nin = 100 nout = 1000 p = 0.7 # Fraction of points to select offset = 0.15 # Offset to be subtracted in pre-centering # Randomly select a fraction of an array with timesteps np.random.seed(2353425) r = np.random.rand(nin) t = np.linspace(0.01*np.pi, 10.*np.pi, nin)[r >= p] # Plot a sine wave for the selected times x = ampl * np.sin(w*t + phi) + offset # Define the array of frequencies for which to compute the periodogram f = np.linspace(0.01, 10., nout) # Calculate Lomb-Scargle periodogram pgram = lombscargle(t, x, f, precenter=True) pgram2 = lombscargle(t, x - x.mean(), f, precenter=False) # check if centering worked assert_allclose(pgram, pgram2)
def __generate_ft__(self, n=0, s=500, lock=False, nymult=1, num=1, full=True, se=0, frange=[None]): time, flux, meta = self.get_lc(n=n, full=full, se=se) if not len(time) <= 1: avg_sample_rate = (max(time) - min(time)) / len(time) if avg_sample_rate != 0: ny = 1 / (2 * avg_sample_rate) res = 1 / (max(time) - min(time)) else: ny = 1 / 24 res = 0.01 if lock: us = s else: us = int(10 * ny / (res)) flux = self.normalize(flux) start_freq = 0.1 * res end_freq = nymult * ny total_range = end_freq - start_freq if frange[0] == None: fts = np.zeros((num, 2, us)) for i in range(num): sub_start = ((i / num) * total_range) + start_freq sub_end = (((i + 1) / num) * total_range) + start_freq f = np.linspace(sub_start, sub_end, us) pgram = lombscargle(np.array(time), np.array(flux), f, normalize=True) fts[i][0] = f fts[i][1] = pgram else: fts = np.zeros((1, 2, us)) f = np.linspace(frange[0], frange[1], us) pgram = lombscargle(np.array(time), np.array(flux), f, normalize=True) fts[0][0] = f fts[0][1] = pgram return fts[:, 0, :], fts[:, 1, :], meta else: f = np.linspace(0, 1 / 24, s) fts = np.zeros((num, 2, s)) for i in range(num): fts[i][0] = f fts[i][1] = np.zeros(s) return fts[:, 0, :], fts[:, 1, :], meta
def findPeaks(times, rv, fap, oversample): ntrials = 200 min_int = float("inf") for i in range(len(times) - 1): min_int = min(min_int, times[i + 1] - times[i]) # Identify frequencies at which to evaluate the periodogram n0 = len(times) T = max(times) - min(times) k = np.linspace(1.0 / oversample, T / 1.5, T / 1.5 * oversample) omegas = 2 * np.pi * k / T # For each trial, randomly permute the data and generate a periodogram maxes = [] for i in range(ntrials): noise = np.random.permutation(rv) psd = lombscargle(np.array(times), noise, omegas) maxes.append(max(psd)) z = range(int(max(maxes) * 100 + 1)) # Calculate CDF for each z value cdf = [] for i in z: cdf.append(len([x for x in maxes if x > i / 100.0]) / float(ntrials)) #plot the CDF: P(max_peak > Z) #plt.plot(np.array(z)/100.0, cdf) #plt.show() # Find the threshold frequency associated the given FAP for i in range(len(cdf)): if cdf[i] > fap: idx = i thres = z[idx + 1] / 100.0 psd = lombscargle(np.array(times), np.array(rv), omegas) plt.plot(1 / omegas * 2 * np.pi, psd) plt.axhline(thres, color='r') plt.xlabel('Period (days)') plt.ylabel('Power') plt.show() # find the periods for which the data has significant peaks peaks = [ 1 / omegas[x] * 2 * np.pi for x in range(len(psd)) if psd[x] > thres ] print len(peaks) return peaks
def findPeaks(times, rv, fap, oversample): ntrials = 200 min_int = float("inf") for i in range(len(times)-1): min_int = min(min_int, times[i+1] - times[i]) # Identify frequencies at which to evaluate the periodogram n0 = len(times) T = max(times)-min(times) k = np.linspace(1.0/oversample, T / 1.5, T/1.5 *oversample) omegas = 2 * np.pi * k / T # For each trial, randomly permute the data and generate a periodogram maxes = [] for i in range(ntrials): noise = np.random.permutation(rv) psd = lombscargle(np.array(times), noise, omegas) maxes.append(max(psd)) z = range(int(max(maxes)*100 + 1)) # Calculate CDF for each z value cdf = [] for i in z: cdf.append(len([x for x in maxes if x > i/100.0])/float(ntrials)) #plot the CDF: P(max_peak > Z) #plt.plot(np.array(z)/100.0, cdf) #plt.show() # Find the threshold frequency associated the given FAP for i in range(len(cdf)): if cdf[i] > fap: idx = i thres = z[idx+1]/100.0 psd = lombscargle(np.array(times), np.array(rv), omegas) plt.plot(1/omegas * 2 * np.pi, psd) plt.axhline(thres, color='r') plt.xlabel('Period (days)') plt.ylabel('Power') plt.show() # find the periods for which the data has significant peaks peaks = [1/omegas[x] * 2 * np.pi for x in range(len(psd)) if psd[x] > thres] print len(peaks) return peaks
def periodogram(x, y, period_low=1, period_high=35, res=200): """ calculate the periodogram at the specified frequencies, return periods, pgram """ periods = np.linspace(period_low, period_high, res) # periods = np.logspace(np.log10(period_low), np.log10(period_high), # res) freqs = 2*np.pi/periods try: pgram = signal.lombscargle(x, y, freqs) # Scipy bug, will be fixed in 1.5.0 except ZeroDivisionError: pgram = signal.lombscargle(x+1, y, freqs) return periods, pgram
def funcPoint(iP, axes): kA = 0 siteNo = siteNoLst[iP] startDate = pd.datetime(1979, 1, 1) endDate = pd.datetime(2019, 12, 31) ctR = pd.date_range(startDate, endDate) dfData = pd.DataFrame({'date': ctR}).set_index('date') dfC = usgs.readSample(siteNo, codeLst=codeLst, startDate=startDate) dfQ = usgs.readStreamflow(siteNo, startDate=startDate) dfQ = dfQ.rename(columns={'00060_00003': '00060'}) dfData = dfData.join(dfQ) dfData = dfData.join(dfC) # plot normalized time series ax = axes[kA] kA = kA + 1 t = dfData.index.values dfDataN = (dfData - dfData.mean()) / dfData.std() varLst = dfData.columns.tolist() data = [dfDataN[var].values for var in varLst] legLst = ['streamflow' ] + [usgs.codePdf.loc[code]['shortName'] for code in codeLst] axplot.plotTS(ax, t, data, styLst='-***', cLst='krgb', legLst=legLst) # plot C-Q nc = len(codeLst) for k in range(nc): code = codeLst[k] q = dfData['00060'] c = dfData[code] [q, c], ind = utils.rmNan([q, c]) ax = axes[kA] kA = kA + 1 ax.plot(np.log(q), np.log(c), 'r*') # plot fractual for k in range(nc): code = codeLst[k] dfV = dfData[dfData[code].notna()] nt = len(dfData) x = dfV.index.values.astype('datetime64[D]') y = dfV[code].values freq = 2 * np.pi / np.linspace(2, nt, nt) power = signal.lombscargle(x, y, freq) ax = axes[kA] kA = kA + 1 ax.plot(np.log(freq / 2 * np.pi), np.log(power), '-*') fyr = 2 * np.pi / 365 pyr = signal.lombscargle(x, y, [fyr]) ax.plot(np.log(fyr / 2 * np.pi), np.log(pyr), 'r*')
def periodogram(sampler, resid, pmin=3): logpost = sampler.lnprobfn.f if logpost.nkep == 0 and logpost.Pfixed is None: plt.figure() plt.errorbar(logpost.t, resid, logpost.dy, fmt='.') else: pers = np.array([logpost.get_periods(p) for p in sampler.flatchain]) pers = np.mean(pers, axis=0) for p in pers: plt.figure() plt.title('P = {}'.format(p)) plt.errorbar(logpost.t % p, resid, logpost.dy, fmt='.') T = logpost.t[-1] - logpost.t[0] dt = np.min(np.diff(logpost.t)) df = 1.0 / T fmax = 1.0 / (2 * dt) fs = np.arange(df, fmax, df) rpsd = ss.lombscargle(logpost.t, resid, 2 * np.pi * fs) psd = ss.lombscargle(logpost.t, logpost.y, 2 * np.pi * fs) N = len(logpost.t) plt.figure() plt.title('Raw') plt.plot(1.0 / fs, np.sqrt(4 * psd / N) * 1000, '-k') plt.xscale('log') plt.xlabel(r'$P$ (day)') plt.ylabel(r'$A$ ($\mathrm{m}/\mathrm{s}$)') plt.figure() plt.title('Cleaned') plt.plot(1.0 / fs, np.sqrt(4 * rpsd / N) * 1000, '-b') plt.xscale('log') plt.xlabel(r'$P$ (day)') plt.ylabel(r'$A$ ($\mathrm{m}/\mathrm{s}$)') pers = 1.0 / fs sel = pers > pmin ibest = np.argmax(rpsd[sel]) pbest = pers[sel][ibest] print 'Maximum amplitude period is ', pbest, ' at ', 1000 * np.sqrt( rpsd[sel][ibest] * 4 / len(resid)) return fs, rpsd
def lomb_scargle_ampspec(t, x): tstep = np.mean(np.ediff1d(t)) freqs = np.fft.fftfreq(x.size, tstep) idxx = np.argsort(freqs) freqs2 = freqs[idxx] freqs2 = freqs2[freqs2>0] try: pgram = sp.lombscargle(t, x, freqs2*2*np.pi) except: #slightly perturb frequencies to prevent crashes #in case of perfectly evenly spaced data #print("Warning: perturbed frequencies a bit to avoid bug in scipy") #freqs2=freqs2*(1+0.00001*np.random.random(freqs2.size)) pgram = sp.lombscargle(t, x, freqs2*2*np.pi) return freqs2, np.sqrt(pgram/(t.size/4))
def periodogram(sampler, resid, pmin=3): logpost = sampler.lnprobfn.f if logpost.nkep == 0 and logpost.Pfixed is None: plt.figure() plt.errorbar(logpost.t, resid, logpost.dy, fmt='.') else: pers = np.array([logpost.get_periods(p) for p in sampler.flatchain]) pers = np.mean(pers, axis=0) for p in pers: plt.figure() plt.title('P = {}'.format(p)) plt.errorbar(logpost.t % p, resid, logpost.dy, fmt='.') T = logpost.t[-1] - logpost.t[0] dt = np.min(np.diff(logpost.t)) df = 1.0/T fmax = 1.0/(2*dt) fs = np.arange(df, fmax, df) rpsd = ss.lombscargle(logpost.t, resid, 2*np.pi*fs) psd = ss.lombscargle(logpost.t, logpost.y, 2*np.pi*fs) N = len(logpost.t) plt.figure() plt.title('Raw') plt.plot(1.0/fs, np.sqrt(4*psd/N)*1000, '-k') plt.xscale('log') plt.xlabel(r'$P$ (day)') plt.ylabel(r'$A$ ($\mathrm{m}/\mathrm{s}$)') plt.figure() plt.title('Cleaned') plt.plot(1.0/fs, np.sqrt(4*rpsd/N)*1000, '-b') plt.xscale('log') plt.xlabel(r'$P$ (day)') plt.ylabel(r'$A$ ($\mathrm{m}/\mathrm{s}$)') pers = 1.0/fs sel = pers > pmin ibest = np.argmax(rpsd[sel]) pbest = pers[sel][ibest] print 'Maximum amplitude period is ', pbest, ' at ', 1000*np.sqrt(rpsd[sel][ibest]*4/len(resid)) return fs, rpsd
def find_period(times, mags, minperiod=2., maxperiod=35., nbins=1000): """ Find the period of a lightcurve. The parameters used here imply magnitudes but there is no reason this would not work if fluxes are passed. :param times: A list of times for the given observations :param mags: A list of magnitudes for the object at the given times :param minperiod: Minimum period to search :param maxperiod: Maximum period to search :param nbins: Number of frequency bins to use in the search :returns: Period in the same units as used in times. This is simply the max value in the Lomb-Scargle periodogram """ # Recenter the magnitude measurements about zero dmags = mags - np.median(mags) # Create frequency bins f = np.linspace(1./maxperiod, 1./minperiod, nbins) # Calculate periodogram pgram = lombscargle(times, dmags, f) idx = np.argmax(pgram) # Return period of the bin with the max value in the periodogram return 1./f[idx]
def lomb(time, counts, frequencies): """Compute the lombscargle periodigram Necessary wrapper around the set lomscargle algorithm https://github.com/scipy/scipy/issues/2643 Parameters ---------- time : np.ndarray array of data times counts : np.ndarray array of counts frequencies : np.ndarray What frequencies Returns ------- freqs : np.ndarray calculated freqencies """ time = time.byteswap().newbyteorder().astype('float64') counts = counts.byteswap().newbyteorder().astype('float64') freqs = lombscargle(time, counts, frequencies) return freqs
def test_lombscargle( self, lombscargle_gen, num_in_samps, num_out_samps, precenter, normalize, use_numba, ): cpu_x, cpu_y, cpu_f, gpu_x, gpu_y, gpu_f = lombscargle_gen( num_in_samps, num_out_samps) cpu_lombscargle = signal.lombscargle(cpu_x, cpu_y, cpu_f, precenter, normalize) gpu_lombscargle = cp.asnumpy( cusignal.lombscargle( gpu_x, gpu_y, gpu_f, precenter, normalize, use_numba=use_numba, )) assert array_equal(cpu_lombscargle, gpu_lombscargle)
def freq_hrv_ls(self, t, y): """Returns HRV (heart rate variability) in frequency domain using Lomb-Scargle periodogram. Note - it may contain noise. :param t: (array) input time stamps of phase values :param y: (array) input phase values :return: periodogram value amplitudes with corresponding frequencies """ indexes_peaks = indexes(y, min_dist=self.samp_rate / 2) if len(indexes_peaks) < 2: return np.array([0]), np.array([0]) peaklist = indexes_peaks RR_list = np.diff(t[indexes_peaks]) * 1000 RR_x = peaklist[1:] RR_y = RR_list f = np.linspace(0.01, 0.5, 100) try: pgram = signal.lombscargle(RR_x, RR_y, f, normalize=True) except ValueError: return np.array([0]), np.array([0]) return pgram, f
def periodogram_rvs(self,freqs=np.linspace(0.01,10,100)): from scipy.signal import lombscargle self.pgram = lombscargle(self.time_data,self.rvs_data,freqs,normalize=True) plt.ylabel('Power') plt.xlabel('Period') plt.plot(1/freqs,self.pgram) plt.show()
def parameter_initialiser(x, y, p): t_min = np.amin(x) t_range = np.amax(x) - t_min if t_range == 0.0: t_range = 1.0 # Estimate frequency. Starting with a Lomb-Scargle periodogram (which # supports irregularly-spaced samples), we pick the strongest frequency # component which leads to a pi time larger than t_min. # # TODO: Could use better heuristics for frequency range based on minimum # distance between points -> aliasing. freq = np.pi / t_range freqs = np.linspace(0.1 * freq, 10 * freq, 2 * len(x)) pgram = lombscargle(x, y, freqs, precenter=True) freq_order = np.argsort(-pgram) for f in freqs[freq_order]: t = 2 * np.pi / f if t / 2 > t_min: p["t_period"] = t break p["t_dead"] = 0.0 p["y_lower"] = np.clip(2 * np.mean(y) - 1, 0, 1) # TODO: Estimate decay time constant using RMS amplitude from global mean # in first and last chunk. p["tau_decay"] = 1
def Lomb_Scargle(data, precision, min_period, max_period, period_jobs=1): """ Returns the period of *data* according to the `Lomb-Scargle periodogram <https://en.wikipedia.org/wiki/Least-squares_spectral_analysis#The_Lomb.E2.80.93Scargle_periodogram>`_. **Parameters** data : array-like, shape = [n_samples, 2] or [n_samples, 3] Array containing columns *time*, *mag*, and (optional) *error*. precision : number Distance between contiguous frequencies in search-space. min_period : number Minimum period in search-space. max_period : number Maximum period in search-space. period_jobs : int, optional Number of simultaneous processes to use while searching. Only one process will ever be used, but argument is included to conform to *periodogram* standards of :func:`find_period` (default 1). **Returns** period : number The period of *data*. """ time, mags, *err = data.T scaled_mags = (mags - mags.mean()) / mags.std() minf, maxf = 2 * np.pi / max_period, 2 * np.pi / min_period freqs = np.arange(minf, maxf, precision) pgram = lombscargle(time, scaled_mags, freqs) return 2 * np.pi / freqs[np.argmax(pgram)]
def test_lombscargle(num_in_samps, num_out_samps, precenter, normalize, use_numba): A = 2.0 w = 1.0 phi = 0.5 * np.pi frac_points = 0.9 # Fraction of points to select r = np.random.rand(num_in_samps) x = np.linspace(0.01, 10 * np.pi, num_in_samps) x = x[r >= frac_points] y = A * np.cos(w * x + phi) f = np.linspace(0.01, 10, num_out_samps) cpu_lombscargle = signal.lombscargle(x, y, f, precenter, normalize) d_x = cp.asarray(x) d_y = cp.asarray(y) d_f = cp.asarray(f) gpu_lombscargle = cp.asnumpy( cusignal.lombscargle( d_x, d_y, d_f, precenter, normalize, use_numba=use_numba, )) assert array_equal(cpu_lombscargle, gpu_lombscargle)
def test_lombscargle_atan_vs_atan2(self): # https://github.com/scipy/scipy/issues/3787 # This raised a ZeroDivisionError. t = np.linspace(0, 10, 1000, endpoint=False) x = np.sin(4 * t) f = np.linspace(0, 50, 500, endpoint=False) + 0.1 q = lombscargle(t, x, f * 2 * np.pi)
def find_period_LS(times, mags, minperiod=2., maxperiod=35., nbinmax=10**5, verbose=False): """ Find the period of a lightcurve using scipy's lombscargle method. The parameters used here imply magnitudes but there is no reason this would not work if fluxes are passed. :param times: A list of times for the given observations :param mags: A list of magnitudes for the object at the given times :param minperiod: Minimum period to search :param maxperiod: Maximum period to search :param nbinmax: Maximum number of frequency bins to use in the search :returns: Period in the same units as used in times. This is simply the max value in the Lomb-Scargle periodogram """ if minperiod < 0: minperiod = 0.01 nbins = int((times.max() - times.min())/minperiod * 1000) if nbins > nbinmax: if verbose: print 'lowered nbins' nbins = nbinmax # Recenter the magnitude measurements about zero dmags = mags - np.median(mags) # Create frequency bins f = np.linspace(1./maxperiod, 1./minperiod, nbins) # Calculate periodogram pgram = lombscargle(times, dmags, f) idx = np.argmax(pgram) # Return period of the bin with the max value in the periodogram return 1./f[idx]
def test_frequency(self): """Test if frequency location of peak corresponds to frequency of generated input signal. """ # Input parameters ampl = 2. w = 1. phi = 0.5 * np.pi nin = 100 nout = 1000 p = 0.7 # Fraction of points to select # Randomly select a fraction of an array with timesteps np.random.seed(2353425) r = np.random.rand(nin) t = np.linspace(0.01 * np.pi, 10. * np.pi, nin)[r >= p] # Plot a sine wave for the selected times x = ampl * np.sin(w * t + phi) # Define the array of frequencies for which to compute the periodogram f = np.linspace(0.01, 10., nout) # Calculate Lomb-Scargle periodogram P = lombscargle(t, x, f) # Check if difference between found frequency maximum and input # frequency is less than accuracy delta = f[1] - f[0] assert_(w - f[np.argmax(P)] < (delta / 2.))
def test_amplitude(self): """Test if height of peak in normalized Lomb-Scargle periodogram corresponds to amplitude of the generated input signal. """ # Input parameters ampl = 2. w = 1. phi = 0.5 * np.pi nin = 100 nout = 1000 p = 0.7 # Fraction of points to select # Randomly select a fraction of an array with timesteps np.random.seed(2353425) r = np.random.rand(nin) t = np.linspace(0.01 * np.pi, 10. * np.pi, nin)[r >= p] # Plot a sine wave for the selected times x = ampl * np.sin(w * t + phi) # Define the array of frequencies for which to compute the periodogram f = np.linspace(0.01, 10., nout) # Calculate Lomb-Scargle periodogram pgram = lombscargle(t, x, f) # Normalize pgram = np.sqrt(4 * pgram / t.shape[0]) # Check if difference between found frequency maximum and input # frequency is less than accuracy assert_approx_equal(np.max(pgram), ampl, significant=2)
def periodogram(time, flux, f): # computed periodogram is unnormalized # takes the value (A**2) * N/4 # for a harmonic signal with amplitude A for sufficiently large N pgram = lombscargle(time, flux, f) plt.subplot(2, 1, 1) plt.plot(time, flux, '.') plt.xlabel('Time (MJD)') plt.ylabel('Flux') normval = t.shape[0] plt.subplot(2, 1, 2) power = np.sqrt(4*(pgram/normval)) # plot normalized periodogram plt.plot(f, power) plt.xlabel('Ang. Frequency (MJD)') plt.ylabel('Power') plt.show() big_frequency = f[np.argmax(pgram)] # dominant ang. frequency big_power = power[np.argmax(pgram)] # dominant power print "dominant ang. frequency =", big_frequency print "domninant power =", big_power
def get_pgram(times, mags, periods): freqs = 2*np.pi / periods scaled_mags = (mags - np.mean(mags)) / np.std(mags) pgram = lombscargle(times, scaled_mags, freqs) return pgram
def plotlb(outputfile,index,columnfile,name='',plot=True,getarg=False,periods=np.linspace(0.2, 1.4, 4000)): datagoodmjd= createdatadicclean(outputfile,index,columnfile,name=name,timeformat='mjd') t, mag, dmag = datagoodmjd['time'], datagoodmjd['VEGAMAG'],datagoodmjd['errorsmag'] # Choose a period grid periods = periods #periods = np.linspace(0.2, 1.4, 4000) ang_freqs = 2 * np.pi / periods # compute the (unnormalized) periodogram # note pre-centering of y values! power = lombscargle(t.flatten(), mag - mag.mean(), ang_freqs,normalize=False,precenter=True) # normalize the power N = len(t.flatten()) #power *= 2 / (N * mag.std() ** 2) if plot == True: # plot the results fig, ax = plt.subplots() ax.plot(periods, power) ax.set(ylim=(0, 0.8), xlabel='period (days)', ylabel='Lomb-Scargle Power'); if getarg == True: return periods, power,t,mag,dmag
def test_frequency(self): """Test if frequency location of peak corresponds to frequency of generated input signal. """ # Input parameters ampl = 2. w = 1. phi = 0.5 * np.pi nin = 100 nout = 1000 p = 0.7 # Fraction of points to select # Randomly select a fraction of an array with timesteps np.random.seed(2353425) r = np.random.rand(nin) t = np.linspace(0.01*np.pi, 10.*np.pi, nin)[r >= p] # Plot a sine wave for the selected times x = ampl * np.sin(w*t + phi) # Define the array of frequencies for which to compute the periodogram f = np.linspace(0.01, 10., nout) # Calculate Lomb-Scargle periodogram P = lombscargle(t, x, f) # Check if difference between found frequency maximum and input # frequency is less than accuracy delta = f[1] - f[0] assert_(w - f[np.argmax(P)] < (delta/2.))
def get_best_n(self): periods = 10**np.linspace(-3,4,1000) omega = 2*np.pi/periods res=sig.lombscargle(self.t-self.t[0],self.vr,omega) max_pers = np.argsort(res) return omega[max_pers[-1]]
def lomb(data_df: pd.DataFrame, min_period: float, max_period: float): """ Lomb–Scargle periodogram implementation :param data: list :param high_frequency: float :param low_frequency: float :return lomb-scargle pgram and frequency values """ time_stamps = data_df.Dt.values samples = data_df.altdiff_dem.values window = signal.tukey(len(samples)) samples *= window # nout = 10000 # number of frequency-space points at which to calculate the signal strength (output) periods = np.linspace(min_period, max_period, len(data_df) * 100) freqs = 1.0 / periods frequency_range = 2 * np.pi * freqs # frequency_range = np.linspace(low_frequency, high_frequency, len(data_df)) result = signal.lombscargle(time_stamps, samples, frequency_range, precenter=True, normalize=True) return result, frequency_range
def get_best_n(self): periods = 10**np.linspace(-3, 4, 1000) omega = 2 * np.pi / periods res = sig.lombscargle(self.t - self.t[0], self.vr, omega) max_pers = np.argsort(res) return omega[max_pers[-1]]
def calculate_frequency_features(data_RR, frequency_options): """ Calculate frequency-based features for given chunk of pulse. Args data_RR (np.array of np.int64): data in format (time [ms], interval [ms]) frequency_options (dict): see get_default_pulse_features_params() Returns features (dict): namesa and calculated features for given pulse chunk """ times = data_RR[:, 0].copy().astype(float) intervals = data_RR[:, 1].copy().astype(float) features = [] f = np.linspace(0.001, 0.4, 100) pgram = sg.lombscargle(times/1000, intervals/1000, f) bounds_names = ['ULF', 'VLF', 'LF', 'HF'] frequency_bounds = frequency_options['frequency bounds'] power = np.mean(pgram) * (frequency_bounds[-1] - frequency_bounds[0]) for i in xrange(len(frequency_bounds) - 1): idx = (f > frequency_bounds[i]) * (f <= frequency_bounds[i+1]) features.append([bounds_names[i], np.mean(pgram[idx]) * (frequency_bounds[i+1] - frequency_bounds[i])]) features.append([bounds_names[i] + 'rel', np.sum(pgram[idx]) / power]) features.append([bounds_names[i] + 'peak', f[idx][np.argmax(pgram[idx])]]) if i > 1: features.append([bounds_names[i] + 'normalized', np.sum(pgram[idx]) / (power - features[3][1])]) #features[3][1] is VLF and is already calculated features.append(['LF/HF', pgram[2] / pgram[3]]) return features
def find_period_LS(times, mags, minperiod=2., maxperiod=35., nbinmax=10**5, verbose=False): """Find the period of a lightcurve using scipy's lombscargle method. The parameters used here imply magnitudes but there is no reason this would not work if fluxes are passed. :param times: A list of times for the given observations :param mags: A list of magnitudes for the object at the given times :param minperiod: Minimum period to search :param maxperiod: Maximum period to search :param nbinmax: Maximum number of frequency bins to use in the search :returns: Period in the same units as used in times. This is simply the max value in the Lomb-Scargle periodogram """ if minperiod < 0: minperiod = 0.01 nbins = int((times.max() - times.min())/minperiod * 1000) if nbins > nbinmax: if verbose: print('lowered nbins') nbins = nbinmax # Recenter the magnitude measurements about zero dmags = mags - np.median(mags) # Create frequency bins f = np.linspace(1./maxperiod, 1./minperiod, nbins) # Calculate periodogram pgram = lombscargle(times, dmags, f) idx = np.argmax(pgram) # Return period of the bin with the max value in the periodogram return 1./f[idx]
def test_amplitude(self): """Test if height of peak in normalized Lomb-Scargle periodogram corresponds to amplitude of the generated input signal. """ # Input parameters ampl = 2. w = 1. phi = 0.5 * np.pi nin = 100 nout = 1000 p = 0.7 # Fraction of points to select # Randomly select a fraction of an array with timesteps np.random.seed(2353425) r = np.random.rand(nin) t = np.linspace(0.01*np.pi, 10.*np.pi, nin)[r >= p] # Plot a sine wave for the selected times x = ampl * np.sin(w*t + phi) # Define the array of frequencies for which to compute the periodogram f = np.linspace(0.01, 10., nout) # Calculate Lomb-Scargle periodogram pgram = lombscargle(t, x, f) # Normalize pgram = np.sqrt(4 * pgram / t.shape[0]) # Check if difference between found frequency maximum and input # frequency is less than accuracy assert_approx_equal(np.max(pgram), ampl, significant=2)
def Lomb_Scargle(data, precision, min_period, max_period, period_jobs=1): """ Returns the period of *data* according to the `Lomb-Scargle periodogram <https://en.wikipedia.org/wiki/Least-squares_spectral_analysis#The_Lomb.E2.80.93Scargle_periodogram>`_. **Parameters** data : array-like, shape = [n_samples, 2] or [n_samples, 3] Array containing columns *time*, *mag*, and (optional) *error*. precision : number Distance between contiguous frequencies in search-space. min_period : number Minimum period in search-space. max_period : number Maximum period in search-space. period_jobs : int, optional Number of simultaneous processes to use while searching. Only one process will ever be used, but argument is included to conform to *periodogram* standards of :func:`find_period` (default 1). **Returns** period : number The period of *data*. """ time, mags, *err = data.T scaled_mags = (mags-mags.mean())/mags.std() minf, maxf = 2*np.pi/max_period, 2*np.pi/min_period freqs = np.arange(minf, maxf, precision) pgram = lombscargle(time, scaled_mags, freqs) return 2*np.pi/freqs[np.argmax(pgram)]
def narrow_periodgram(time, amplitude, center_frequency, frequency_width, num=1000): f_min = center_frequency - frequency_width / 2 f_max = center_frequency + frequency_width / 2 frequencies = np.linspace(f_min, f_max, num=num) pgram = signal.lombscargle(time, amplitude, 2 * np.pi * frequencies) return (frequencies, pgram)
def RRI_2_LFHF_ls(dataset): time = dataset["elapsed_time"] t = np.array(time) rri = dataset["rri"] ibi = np.array(rri) phi = 4.0 * np.pi f = np.linspace(0.001, phi, 1000) Pgram = lombscargle(t, ibi, f, normalize=True) vlf = 0.04 lf = 0.15 hf = 0.4 Fs = 250 lf_freq_band = (f >= vlf) & (f <= lf) hf_freq_band = (f >= lf) & (f <= hf) dy = 1.0 / Fs LF = np.trapz(y=abs(Pgram[lf_freq_band]), x=None, dx=dy) HF = np.trapz(y=abs(Pgram[hf_freq_band]), x=None, dx=dy) LF_HF = float(LF) / HF return LF_HF
def test_lombscargle_atan_vs_atan2(self): # https://github.com/scipy/scipy/issues/3787 # This raised a ZeroDivisionError. t = np.linspace(0, 10, 1000, endpoint=False) x = np.sin(4*t) f = np.linspace(0, 50, 500, endpoint=False) + 0.1 q = lombscargle(t, x, f*2*np.pi)
def parameter_initialiser(x, y, p): # Sort data by time (x-axis) mask = np.argsort(x) x = x[mask] y = y[mask] min_step = np.min(x[1:] - x[:-1]) duration = x[-1] - x[0] # Nyquist limit does not apply to irregularly spaced data # We'll use it as a starting point anyway... f_max = 0.5 / min_step # relaxed Fourier limit f_min = 0.25 / duration omega_list = 2 * np.pi * np.linspace(f_min, f_max, int(f_max / f_min)) # the periodogram should give the correct width up-to a factor of 2 pgram = lombscargle(x, y, omega_list, precenter=True) p["width"] = omega_list[np.argmax(pgram)] / np.pi p['y0'] = np.mean(y) y_diff = y - p['y0'] peak_ind = np.argmax(np.abs(y_diff)) p['x0'] = x[peak_ind] p['a'] = y[peak_ind] - p['y0'] return p
def getPeriodograms_SLOW(self, rejectSet, times, window, normalize, ang_freqs): pgrams = [] t = np.array(times) # times hammingWindow = np.array(window) n = len(t) print "n: " + str(n) for ch in rejectSet: y = np.array(ch) # samples y = y * hammingWindow # apply hamming window y = y - np.mean( y ) # demeaned samples ******** IS THIS NECESSARY?? Answer: yes to avoid low frequency noise pgram = signal.lombscargle(t, y, ang_freqs) if normalize: pgram = np.sqrt(4 * (pgram / n)) print "len(pgram): " + str(len(pgram)) pgrams.append(pgram) return pgrams
def lombscarglescipy(self, period): f = np.linspace(0.1, 1000, 10000) pgram = signal.lombscargle(self.d, self.m, f) periods = 2 * np.pi / f normval = self.d.shape[0] power = np.sqrt(4 * (pgram / normval)) x = periods y = power fig, axes = plt.subplots(1, 2, figsize=(8, 8)) ax1, ax2 = axes.flatten() ax1.plot(x, y, color="red", linewidth=2) ax1.set_xlabel("period (days)") ax1.set_ylabel("Lomb-Scargle.scipy Power") ax1.set_xlim(0, 10) ax1.legend() phase = 1.0 * self.d / (period) phase = phase % 1 * 1 ax2.plot(phase, self.m, 'ro') ax2.set_xlabel("phase") ax2.set_ylabel("Mag") #ax2.set_ylim(0,1) ax2.set_xlim(0, 1) ax2.legend() # plt.savefig('/home/yf/ptftry/pic/Lomb-Scargle.png') plt.show()
def Gen_FT(time, flux, NyFreq, s, power_spec=False, periodigram=False): """ Description: Generate a Fourier Transform (Lomb Scargle Periodigram techniacally) given a time and value set. Can also generate a power spectrum. Args: time - Time string to pass in (numeric 1D iteratable) flux - value string to pass in (numeric 1D iteratable) NyFreq - Nyquist frequency of the time string (float) s - number of samples in frequency array (int) power_spec - generate a power spectrum of not (bool) returns: dicionay: 'Freq' - Frequency array in Hz (float) 'Amp' - Amplitude array for FT (float) Raises: HARD FAIL - Raised on exessive NaN values in Time Array """ # return Gen_flsp(time, flux, NyFreq, s) # return Gen_fft(time, flux, NyFreq) timeSansNAN = [] for checksum in time: if math.isnan(checksum) is False: timeSansNAN.append(checksum) # Power Spectrum if len(timeSansNAN) > 0: res = 1 / (max(timeSansNAN) - min(timeSansNAN)) else: warn('NON FATAL ERROR (time Not Build Correctly) |' 'ATTEMPTING RECOVERING WITH DEFAULT SETTINGS') try: res = 1.0 / 30.0 warn('RECOVERY [OKAY]') except: warn('RECOVERY [FAILED] | HARD FAIL') return -1 # samples = int(NyFreq/res) * 10 samples = s f = np.linspace(res / 10, NyFreq, samples) xuse = np.asarray(time) yuse = np.asarray(flux) if not periodigram: try: pgram = lombscargle(xuse, yuse, f * 2 * np.pi) except ZeroDivisionError: warn('Zero division encountered in GEN_FT') pgram = np.linspace(0, 1, samples) normval = xuse.shape[0] if power_spec is False: pgramgraph = np.sqrt(4 * (pgram / normval)) else: pgramgraph = pgram fgo = f return {'Freq': fgo.tolist(), 'Amp': pgramgraph.tolist()} else: frequency, chi2 = periodigram()
def lombscargle_scipy(t, y, frequency, normalization='normalized', center_data=True): """Lomb-Scargle Periodogram This is a wrapper of ``scipy.signal.lombscargle`` for computation of the Lomb-Scargle periodogram. This is a relatively fast version of the naive O[N^2] algorithm, but cannot handle heteroskedastic errors. Parameters ---------- t, y: array_like times, values, and errors of the data points. These should be broadcastable to the same shape. frequency : array_like frequencies (not angular frequencies) at which to calculate periodogram normalization : string (optional, default='normalized') Normalization to use for the periodogram TODO: figure out what options to use center_data : bool (optional, default=True) if True, pre-center the data by subtracting the weighted mean of the input data. Returns ------- power : array_like Lomb-Scargle power associated with each frequency. Units of the result depend on the normalization. References ---------- .. [1] M. Zechmeister and M. Kurster, A&A 496, 577-584 (2009) .. [2] W. Press et al, Numerical Recipies in C (2002) .. [3] Scargle, J.D. 1982, ApJ 263:835-853 """ if not HAS_SCIPY: raise ValueError("scipy must be installed to use lombscargle_scipy") t, y = np.broadcast_arrays(t, y) frequency = np.asarray(frequency) assert t.ndim == 1 assert frequency.ndim == 1 if center_data: y = y - y.mean() # Note: scipy input accepts angular frequencies p = signal.lombscargle(t, y, 2 * np.pi * frequency) if normalization == 'unnormalized': pass elif normalization == 'normalized': p *= 2 / (t.size * np.mean(y**2)) else: raise ValueError("normalization='{0}' " "not recognized".format(normalization)) return p
def get_ls(times, dat): '''Given time and data arrays, return a Lomb-Scargle periodogram: a tuple (freq, Fdat) of a frequency array and an intensity array.''' freqs = np.fft.fftfreq(int(times[-1] - times[0])) # interval, not size Fdat = spsignal.lombscargle(times, dat, 2*np.pi*freqs) # 1/s -> rad/s return (freqs, Fdat)
def get_outputs(self, output_refs: List[int]): try: pgram = si.lombscargle(np.roll(self.buffer[0], self.index), np.roll(self.buffer[1], self.index), self.w) except ZeroDivisionError: return [0 for _ in output_refs] outputs = np.sqrt(4 * (pgram / self.normval)) return [outputs[output_ref] for output_ref in output_refs]
def window(b): time, depth = np.genfromtxt("data/l45b{0}_cadence.txt".format(b)).T ps = np.linspace(0.1, 100, 1000) fs = 1.0 / ps ys = np.ones_like(time) normval = time.shape[0] pgram = sps.lombscargle(time, ys, 2 * np.pi * fs) return ps, pgram, normval, time, depth
def lombscargle_scipy(t, y, frequency, normalization='normalized', center_data=True): """Lomb-Scargle Periodogram This is a wrapper of ``scipy.signal.lombscargle`` for computation of the Lomb-Scargle periodogram. This is a relatively fast version of the naive O[N^2] algorithm, but cannot handle heteroskedastic errors. Parameters ---------- t, y: array_like times, values, and errors of the data points. These should be broadcastable to the same shape. frequency : array_like frequencies (not angular frequencies) at which to calculate periodogram normalization : string (optional, default='normalized') Normalization to use for the periodogram TODO: figure out what options to use center_data : bool (optional, default=True) if True, pre-center the data by subtracting the weighted mean of the input data. Returns ------- power : array_like Lomb-Scargle power associated with each frequency. Units of the result depend on the normalization. References ---------- .. [1] M. Zechmeister and M. Kurster, A&A 496, 577-584 (2009) .. [2] W. Press et al, Numerical Recipies in C (2002) .. [3] Scargle, J.D. 1982, ApJ 263:835-853 """ if not HAS_SCIPY: raise ValueError("scipy must be installed to use lombscargle_scipy") t, y = np.broadcast_arrays(t, y) frequency = np.asarray(frequency) assert t.ndim == 1 assert frequency.ndim == 1 if center_data: y = y - y.mean() # Note: scipy input accepts angular frequencies p = signal.lombscargle(t, y, 2 * np.pi * frequency) if normalization == 'unnormalized': pass elif normalization == 'normalized': p *= 2 / (t.size * np.mean(y ** 2)) else: raise ValueError("normalization='{0}' " "not recognized".format(normalization)) return p
def compute_power_series(data, min_period, max_period, n=250): periods = np.linspace(min_period, max_period, n) assert (periods > 0).all(), "Periods must be greater than 0" freqs = 2. * np.pi / periods med_flux = np.median(data.flux) power = signal.lombscargle(data.mjd.astype(float), (data.flux - med_flux).astype(float), freqs) return PowerSeries(periods, power)
def periodogram(x, rv, f, max_period): ''' Computes a Lomb-Scargle Periodogram of the input RV data. This was adapted from Jake Vanderplas' article "Fast Lomb-Scargle Periodograms in Python." Parameters ---------- x : list The times at which the data points were gathered. rv : list The values of the measurand at the corresponding time, x. f : float The number of samples to take over the interval. max_period : float The maximum of the interval of periods to check. Returns ------- periods : array_like[len(f)] Equally spaced array of possible period values. powers : array_like[len(f)] The calculated Power values over the range of periods, these form the normalized Lomb-Scargle Periodogram. delta_x : float The smallest separation between two values in x. ''' from scipy.signal import lombscargle # Sort the time data chronologically. x = np.sort(np.array(x)) rv = np.array(rv) # Start delta_x very large delta_x = np.inf # Iteratively lower delta_x for i in range(0, len(x)-2): if x[i+1]-x[i] < delta_x and x[i+1]-x[i] != 0: delta_x = x[i+1]-x[i] # Compute the periodogram periods = np.linspace(delta_x, max_period, num = f) ang_freqs = 2 * pi / periods powers = lombscargle(x, rv - rv.mean(), ang_freqs) powers *= 2 / (len(x) * rv.std() ** 2) return periods, powers, delta_x
def pgram_peaks(freq, flux, f, num): from scipy.signal import lombscargle normval = freq.shape[0] pgram = lombscargle(freq, flux, f)/normval pgram = np.sqrt(4*(pgram/normval)) # find local maxima not at the edge of the periodogram maxmask = np.r_[False, pgram[1:] > pgram[:-1]] &\ np.r_[pgram[:-1] > pgram[1:], False] sortarg = np.argsort(pgram[maxmask]) peak_freqs = f[maxmask][sortarg[-num:]] peak_flux = pgram[maxmask][sortarg[-num:]] return pgram, peak_freqs, peak_flux
def psd(data,timestamp,winLen=2000,graph=False,overlap=1,nout=20,maxFreq=20): psd=[] data=np.array(data) timestamp=np.array(timestamp) norm=[] f=0 for i in data: norm.append(np.sqrt(i[0]**2+i[1]**2+i[2]**2)) norm=np.array(norm) #Create windows of 2seconds of data previous=0 for i in range(len(timestamp)-overlap): if i>0: if timestamp[i]-timestamp[previous]>winLen and len(norm[previous:i])>10: dataWindow=norm[previous:i] timeWindow=timestamp[previous:i] timeWindow=(timeWindow-timeWindow[0])/1000 f = np.linspace(0.01, maxFreq, nout) tempOut=sp2.lombscargle(timeWindow,dataWindow,f) tempOut=np.sqrt(4*tempOut/len(dataWindow)) previous=previous+overlap psd.append(tempOut) if graph: plt.subplot(2, 1, 1) plt.plot(timeWindow,dataWindow, 'b') plt.subplot(2, 1, 2) plt.plot(f, tempOut) plt.show() return psd,f,norm #First calculate the power spectrum density on the norm #then calculate statistics over the resulting #have in mind that I should use different frequencies #for the power spectrum density estimation #Also, remember that the PSD is calculated over a window #of data ideally here I also produce the labels #for the data points as well #Once all this is done I guess the remaining part is just the Crossvalidation print(norm) pass
def apply_filter(self, array): if len(array.shape)!=1: return False # make frequency axis df = 1/abs(array.coords[0][-1] - array.coords[0][0]) # time is stored in ps -> 1/ps = THz my = max(abs(array.data)) data_f = np.linspace(df/array.shape[0], df*(array.shape[0]-1)*np.pi, array.shape[0]) # Lomb-Scargle doesn't allow f=0 #data_f = data_f[:len(data_f)/2-1] # return frequencies up to 1/dt/2 to be consistent with FFT (not compulsory) # calculate spectrum data_s = abs(lombscargle(array.coords[0], array.data/my, data_f))*my**2 array.coords[0] = data_f/(2*np.pi) array.data = data_s return True
def _fk_ls_filter_eliminate_phase_sp(ArrayData, y_dist=False, radius=None, maxk=False): """ Only use with the function fk_filter! Function to test the fk workflow with synthetic data param data: data of the array type data: numpy.ndarray param snes: slownessvalue of the desired extracted phase type snes: int """ # Define freq Array freq = np.zeros((len(ArrayData), len(ArrayData[0]) / 2 + 1)) + 1j for i in range(len(ArrayData)): freq_new = np.fft.rfftn(ArrayData[i]) freq[i] = freq_new # Define k Array freqT = freq.conj().transpose() knum = np.zeros( ( len(freqT), len(freqT[0]) /2 +1 )) #calc best range N = len(freqT[0]) dN = ( max(freqT[0]) - min(freqT[0]) / N ) f_temp = np.fft.rfftfreq(len(freqT[0]), dN) * 2.* np.pi #1. try: #period_range = np.linspace(min_wavelength, max_bound, len(freqT[0])) #2. try: #period_range = np.linspace(f_temp[1], max(f_temp), N) #3. try: period_range = f_temp #period_range = period_range.astype('float') period_range[0] = 1. #after this change the first outputparameter of the periodogram to a #correlation between the signal and a e^0 function ;) period_range = period_range.astype('float') for j in range(len(freqT)): k_new = signal.lombscargle(y_dist, abs(freqT[j]), period_range) k_new = ls2ifft_prep(k_new, abs(freqT[j])) knum[j] = k_new #change dtype to integer, for further processing period_range = period_range.astype('int') fkspectra = knum dsfft = line_set_zero(fkspectra, 0, radius) return fkspectra.conj().transpose(), period_range
def periodicity(df, col): x = df[col] t = (df.position_update_timestamp - df.position_update_timestamp.min())/pd.Timedelta('1s') # We sample at 1 hz best, so we can't measure any components above 0.5 hz # We can in principle see very low frequency all the way down to dc # but we can't tell the difference between dc and an 8h frequency # If we chunk down to 30m or 1h, 1e-4 is a better lower bound f = np.logspace(-4, np.log10(0.5), 10000)# in hertz try: return f, signal.lombscargle(t.values, x.values.astype(float), f) except ZeroDivisionError: return [], []
def get_period(curva): from scipy.signal import lombscargle x = np.array(curva.index) - min(curva.index) mag_mean, mag_std = np.mean(curva['mag']), np.std(curva['mag']) y = (np.array(curva['mag']) - mag_mean)/mag_std T_tot = np.amax(x) - np.amin(x) f_N = 0.5*(1/get_avg_timestep(curva)) f = np.arange(4/T_tot, 10, 0.1/T_tot) f = f*2*np.pi P = lombscargle(x, y, f) f_max = f[P.argmax()]/(2*np.pi) return 1/f_max
def period(mag, index): from scipy.signal import lombscargle x = np.array(index) - min(index) mag_mean, mag_std = np.mean(mag), np.std(mag) y = (np.array(mag) - mag_mean)/mag_std T_tot = np.amax(x) - np.amin(x) f_N = 0.5*(1/get_avg_timestep(index)) f = np.arange(4/T_tot, 10, 0.1/T_tot) f = f*2*np.pi P = lombscargle(np.ravel(x), np.ravel(y), np.ravel(f)) f_max = f[P.argmax()]/(2*np.pi) return 1/f_max
def periodogram(self,pmin=0.5,pmax=60,npts=2000, recalc=False): pers = np.logspace(np.log10(pmin),np.log10(pmax),npts) if np.array_equal(pers,self._pers) and not recalc: pgram = self._pgram else: freqs = (2*np.pi)/(pers) t = self.t[~self.mask] f = self.f[~self.mask] pgram = lombscargle(t.astype('float64'), f.astype('float64'), freqs.astype('float64')) self._pgram = pgram self._pers = pers return pers,pgram
def get_period(time, flux): scaled_flux = (flux - flux.mean()) / flux.std() freqs = np.linspace(0, 100, len(time))[1:] power = lombscargle(time, scaled_flux, freqs) # Normalize # power = np.sqrt(4.0 * power / time.shape[0]) # Calculate false alarm probability # fap = get_fap(freqs, time, power) # Get period period = 1. / (freqs / 2.0 / np.pi) print(period, power) return period, power#, fap