def plot(self, periodogram=False): ncols = 2 if periodogram else 1 fig, axs = plt.subplots(3 + 1, ncols,) #sharex=False, sharey=False, # constrained_layout=True) axs = axs.ravel() if periodogram: indices_plots = np.arange(0, 8, 2) else: indices_plots = np.arange(0, 4) kw = dict(fmt='o', ms=3) axs[indices_plots[0]].errorbar(self.time, self.fullRV - self.fullRV.mean(), self.fullRVerror, color='k', **kw) axs[indices_plots[1]].errorbar(self.time, self.blueRV - self.blueRV.mean(), self._blueRVerror, color='b', **kw) axs[indices_plots[2]].errorbar(self.time, self.midRV - self.midRV.mean(), self._midRVerror, color='g', **kw) axs[indices_plots[3]].errorbar(self.time, self.redRV - self.redRV.mean(), self._redRVerror, color='r', **kw) if periodogram: from astropy.timeseries import LombScargle model = LombScargle(self.time, self.fullRV, self.fullRVerror) f, p = model.autopower() axs[1].semilogx(1 / f, p, color='k') axs[1].hlines(model.false_alarm_level([0.1, 0.01]), *axs[1].get_xlim(), alpha=0.2, ls='--') model = LombScargle(self.time, self.blueRV, self._blueRVerror) f, p = model.autopower() axs[3].semilogx(1 / f, p, color='b') axs[3].hlines(model.false_alarm_level([0.1, 0.01]), *axs[3].get_xlim(), alpha=0.2, ls='--') model = LombScargle(self.time, self.midRV, self._midRVerror) f, p = model.autopower() axs[5].semilogx(1 / f, p, color='g') axs[5].hlines(model.false_alarm_level([0.1, 0.01]), *axs[5].get_xlim(), alpha=0.2, ls='--') model = LombScargle(self.time, self.redRV, self._redRVerror) f, p = model.autopower() axs[7].semilogx(1 / f, p, color='r') axs[7].hlines(model.false_alarm_level([0.1, 0.01]), *axs[7].get_xlim(), alpha=0.2, ls='--') return fig, axs
def set_power_period(self, nt=5, min_p=1, max_p=100, n_f=10000, auto=True, method='LS_astropy'): self.pmin = min_p self.pmax = max_p self.method = method if self.method == 'LS_astropy': if auto: ls = LombScargle(self.df.t.values, self.df.m.values, self.df.dflux.values, nterms=nt) self.frequency, self.power = ls.autopower(minimum_frequency=1. / self.pmax, maximum_frequency=1. / self.pmin) else: self.frequency = np.linspace(1. / self.pmax, 1. / self.pmin, n_f) self.power = LombScargle(self.df.t.values, self.df.m.values, self.df.dflux.values).power(self.frequency) elif self.method == 'BLS_astropy': model = BoxLeastSquares(self.df.t.values, self.df.m.values, dy=self.df.dflux.values) if auto: periodogram = model.autopower(0.2) self.frequency = 1. / periodogram.period self.power = periodogram.power else: periods = np.linspace(self.pmin, self.pmax, 10) periodogram = model.power(periods, 0.2) self.frequency = 1. / periodogram.period self.power = periodogram.power else: print('Method should be chosen between these options:') print('LS_astropy, BLS_astropy') sys.exit() # setting_period period = (1. / self.frequency[np.argmax(self.power)]) print("p f p-f", period, np.fix(period), period-np.fix(period)) if period - np.fix(period) < 0.009: self.period = (1. / self.frequency[(np.asarray(self.power).argsort()[-2])]) else: self.period = period
def period_mining(self, user_df: pd.DataFrame): """设置用户初始时间为0将时间转化为时间序列(0,1,2,...)(小时), 得到单个用户全部活动的周期""" def get_time_intervals(t, base_t): """返回 t减去base_t的小时数""" diff = pd.to_datetime(t) - pd.to_datetime(base_t) return diff.days * 24 + diff.seconds / 3600 x = np.array(user_df['localtime'].apply(lambda t: get_time_intervals(t, user_df['localtime'].min()))) y = user_df['placeID'].to_numpy() # 遍历全部的placeID对某个单独的placeID进行周期提取 for place_id in np.unique(y): y_copy = y.copy() # 将其他place_id设为 -1 y_copy[y_copy != place_id] = -1 # 控制最大频率(频率范围),因为知道周期不会小于1小时,则频率必定落在(0, 1)中 ls = LombScargle(x, y_copy) frequency, power = ls.autopower(minimum_frequency=0.0001, maximum_frequency=1) try: period = 1 / frequency[np.where(power > power.max() * 0.5)] # period = 1 / frequency[np.where(power == power.max())] self.periods[str(place_id)] = round(period.max()[0], 2) except (ValueError, IndexError): # 没有周期性的时候将周期设置为-1表示没有周期性 self.periods[str(place_id)] = -1 return self.periods
def periodogram(self): dt = [self.t[i + 1] - self.t[i - 1] for i in range(1, len(self.t) - 1)] fmax = 1.0 / np.median(dt) fmin = 2.0 / (max(self.t)) ls = LombScargle(self.t, self.flux, self.flux_err) #Oversampling a factor of 10 to achieve frequency resolution freq, power = ls.autopower(minimum_frequency=fmin, maximum_frequency=fmax, samples_per_peak=10) # Find the dominant peak best_f = freq[np.argmax(power)] period = 1.0 / best_f #period from the LS periodogram fap_p = ls.false_alarm_probability(power.max()) fap_001 = ls.false_alarm_level(0.01) if (period > 30.0): # Long periods are often spurious, search for a shorter minimum one # Calculates treshold using a running median every 2000 points mean_freq = avg_array(freq, 2000) mean_power = avg_array(power, 2000) treshold = np.interp(freq, mean_freq, mean_power) # Finds the period looking for the local maximum max_loc = np.argmax(power / treshold) best_f = freq[max_loc] period = 1.0 / best_f fap_p = ls.false_alarm_probability(power[max_loc]) fap_001 = ls.false_alarm_level(0.01) self.freq = np.array(freq) self.power = np.array(power) self.period = period self.fap_p = fap_p self.fap_001 = fap_001
def lombscargle(time, relFlux): LS = LombScargle(time, relFlux) frequency, power = LS.autopower(minimum_frequency=1 / 27, maximum_frequency=1 / .1) bestPeriod = 1 / frequency[np.argmax(power)] maxPower = np.max(power) period = 1 / frequency return period, power, bestPeriod, maxPower
def find_periodicity_peak(t, f, plims=None, plot=False): """Calculates the Lomb-Scargle periodogram of a timeseries. Default threshold for the false-alarm probability is now set to 10**-30 (k2sc is 1e-50). Perhaps a more specific metric should be used (i.e amplitude of wave vs white noise). Args: t f plims (tuple): upper and lower bound for periods to calculate the periodogram on. Default: [0.5, 15] Returns: max_period (float): value of the most valid peak threshhold_flag (bool): True if passes the threshold pfa (float): probability of false alarm P(peak max | gaussian noise) lsp (pd.DataFrame): 'frequency', 'period', 'power' """ threshold_fa = 1e-30 plims = plims if plims is not None else (0.5, 15) ls = LombScargle(t, f) freqs, power = ls.autopower(minimum_frequency=1 / max(plims), maximum_frequency=1 / min(plims)) periods = 1.0 / freqs lsp = pd.DataFrame({'frequency': freqs, 'period': periods, 'power': power}) max_period = periods[np.argmax(power)] pfa = ls.false_alarm_probability(power.max()) threshhold_flag = True if pfa < threshold_fa else False if plot: fig, ax = plt.subplots(3) ax[0].plot(t, f, 'k.') ax[0].set_xlabel('t') ax[0].set_ylabel('f') ax[1].plot(lc_utils.fold_on_first(t, max_period), f, 'k.') ax[1].set_xlabel('t') ax[1].set_ylabel('f') ax[2].plot(periods, power, 'k-') ax[2].set_xlabel('period') ax[2].set_ylabel('power') fig.show() return max_period, threshhold_flag, pfa, lsp
def computeperiod(npjdmag): JDtime = npjdmag[:, 0] targetflux = npjdmag[:, 1] ls = LombScargle(JDtime, targetflux, normalization='model') frequency, power = ls.autopower(minimum_frequency=0.025, maximum_frequency=20) index = np.argmax(power) maxpower = np.max(power) period = 1 / frequency[index] wrongP = ls.false_alarm_probability(power.max()) return period, wrongP, maxpower
def lomb_scargle_estimator( x, y, yerr=None, min_period=None, max_period=None, filter_period=None, max_peaks=2, **kwargs, ): """Estimate period of a time series using the periodogram Args: x (ndarray[N]): The times of the observations y (ndarray[N]): The observations at times ``x`` yerr (Optional[ndarray[N]]): The uncertainties on ``y`` min_period (Optional[float]): The minimum period to consider max_period (Optional[float]): The maximum period to consider filter_period (Optional[float]): If given, use a high-pass filter to down-weight period longer than this max_peaks (Optional[int]): The maximum number of peaks to return (default: 2) Returns: A dictionary with the computed ``periodogram`` and the parameters for up to ``max_peaks`` peaks in the periodogram. """ if min_period is not None: kwargs["maximum_frequency"] = 1.0 / min_period if max_period is not None: kwargs["minimum_frequency"] = 1.0 / max_period # Estimate the power spectrum model = LombScargle(x, y, yerr) freq, power = model.autopower(method="fast", normalization="psd", **kwargs) power /= len(x) power_est = np.array(power) # Filter long periods if filter_period is not None: freq0 = 1.0 / filter_period filt = 1.0 / np.sqrt(1 + (freq0 / freq)**(2 * 3)) power *= filt # Find and fit peaks peaks = find_peaks(freq, power, max_peaks=max_peaks) return dict(periodogram=(freq, power_est), peaks=peaks, ls=model)
def period_finder(self, nt=5, min_p=1, max_p=100, n_f=10000, auto=True, method='LS_astropy'): self.pmin = min_p self.pmax = max_p self.method = method if self.method == 'LS_astropy': if auto: ls = LombScargle(self.df.t.values, self.df.m.values, self.df.e.values, nterms=nt) self.frequency, self.power = ls.autopower( minimum_frequency=1. / self.pmax, maximum_frequency=1. / self.pmin) else: self.frequency = np.linspace(1. / self.pmax, 1. / self.pmin, n_f) self.power = LombScargle(self.df.t.values, self.df.m.values, self.df.e.values).power( self.frequency) elif self.method == 'BLS_astropy': model = BoxLeastSquares(self.df.t.values * u.day, self.df.m.values, dy=self.df.e.values) if auto: periodogram = model.autopower(0.2) self.frequency = 1. / periodogram.period self.power = periodogram.power else: periods = np.linspace(self.pmin, self.pmax, 10) periodogram = model.power(periods, 0.2) self.frequency = 1. / periodogram.period self.power = periodogram.power else: print('Method should be chosen between these options:') print('LS_astropy, BLS_astropy') sys.exit() self.set_period() self.plot_ls()
def get_GLS(t, rv, rv_error): """ compute the Generalized Lomb-Scargle periodogram. Notes ----- The irregularly-sampled data enables frequencies much higher than the average Nyquist frequency. """ ls = LombScargle(t, rv, rv_error, fit_mean=True) frequency, power = ls.autopower( ) # minimum_frequency=f_min, maximum_frequency = f_max) ### automated f limits from baseline and Nyquist factor i_peak = np.argmax(power) peakFrequency = frequency[i_peak] peakPower = power[i_peak] FAP = ls.false_alarm_probability(peakPower, method='bootstrap') return peakFrequency, peakPower, FAP, ls
def period_mining(user_df: pd.DataFrame): """设置用户初始时间为0将时间转化为时间序列(0,1,2,...)(小时), 得到单个用户全部活动的周期""" def get_time_intervals(t, base_t): """返回 t减去base_t的小时数""" diff = pd.to_datetime(t) - pd.to_datetime(base_t) return round(diff.days * 24 + diff.seconds / 3600) checkin_time = np.array(user_df['localtime'].apply( lambda t: get_time_intervals(t, user_df['localtime'].min()))) checkin_id = user_df['placeID'].to_numpy() periods = {} # 遍历全部的placeID对某个单独的placeID进行周期提取 for cur_id in np.unique(checkin_id): # print("打卡地点:", cur_id) # 选择出当前id的打卡时间列表 cur_checkin_time = checkin_time[checkin_id == cur_id] # 以最大打卡时间范围为x轴,最小为y轴, 间隔1建立横轴 x = np.arange(cur_checkin_time.min(), cur_checkin_time.max()) y = [] # 在打卡时间内的设置为cur_id值,其余的设置为0,建立y轴 for i in range(cur_checkin_time.min(), cur_checkin_time.max()): y.append(cur_id if i in list(cur_checkin_time) else 0) y = np.array(y) ls = LombScargle(x, y) # 控制最大频率(频率范围),因为知道周期不会小于3/24小时,则频率必定落在(0, 1)中, 最大频率设置为8个月至少访问5次,8/5 * 30 * 24 frequency = None try: frequency, power = ls.autopower(minimum_frequency=1 / ((8 / 5) * 30 * 24), maximum_frequency=3 / 24) # 如果没有符合条件的说明没有周期性 if frequency.size: # 选取满足条件的周期中最大的,并保留两位小数 periods[str(cur_id)] = [ round(1 / frequency[np.where(power == power.max())][0]), round(ls.false_alarm_probability(power.max()), 3) ] else: # 没有周期性的时候将周期设置为-1表示没有周期性 periods[str(cur_id)] = [-1, 1] except Exception as e: print(e, frequency) periods[str(cur_id)] = [-1, 1] continue return periods
def gls(self, col_x='Julian Date', col_y='Radial Velocity (m/s)', err_col='Error (m/s)'): """ Computes a generalized lomb-scargle periodogram on the object time series, as described by Zechmeister et al. (2009). The default format for col1 and col2 is the HiRES publicly available radial velocity data (Butler, Vogt, Laughlin et al. 2017). :param col_x: a string, the name of the column containing the x-values (time stamps). :param col_y: a string, the name of the column containing the y-values (radial velocities). :param err_col: a string, the name of the columm containing the radial velocity errors. :return: the period, power, and false alarm probability for each signal detected with the periodogram. Moreover, the lsdf pandas DataFrame is updated with the contents of the period, power, and FAP arrays. """ # Compute Generalized Lomb-Scargle periodogram (Zechmeister et al. 2009) ls = LombScargle(self.df[col_x], self.df[col_y], self.df[err_col], fit_mean=True) frequency, power = ls.autopower(method="slow") # Compute false alarm probability for each signal. fap = [] print("Starting Bootstrap FAP extrapolation process...") for pow_ in power: # append(ls.false_alarm_probability(pow_, method='bootstrap')) fap.append(ls.false_alarm_probability(pow_)) print("Finished Bootstrap FAP extrapolation process.") fap = np.array(fap) period_ = 1 / frequency df = pd.DataFrame({'Period': period_, 'Power': power, 'FAP': fap}) self.lsdf = df print( "Saving the Period, Power, and FAP dataset to a csv at the directory " + self.dir + "...") self.lsdf.to_csv(self.dir + '_LombScarglePeriodogramResults.csv') print("Done!") self.lsdf = self.lsdf.reset_index(drop=True) return period_, power, fap
def window(t, n=5): """Computes the periodogram of the window function. Parameters ---------- t: array-like Timestamps of the sampling comb window. n: float, optional Samples per peak (default is 5). Returns ------- f: ndarray Frequency array. a: ndarray Power array. """ ls = LombScargle(t, 1, fit_mean=False, center_data=False) f, a = ls.autopower(minimum_frequency=0, samples_per_peak=n) return f, a
def find_best_period(t, y, FAP=False, return_model=False): baseline = max(t) - min(t) ls = LombScargle(t, y) frequency, power = ls.autopower(minimum_frequency=1 / baseline, maximum_frequency=1 / 2) periods = 1 / frequency best_power = power.max() best_period = periods[list(power).index(best_power)] if (FAP): FAP = ls.false_alarm_probability(best_power) if (return_model): return (best_period, FAP, ls) else: return (best_period, FAP) else: if (return_model): return (best_period, ls) else: return best_period
def periodogram(times, data): # Create Lomb-Scargle Periodogram model ls = LombScargle(times, data) baseline = max(times) - min(times) frequency, power = ls.autopower(minimum_frequency=1/baseline, maximum_frequency=1/(1/10)) periods = 1 / frequency # Find the best period within a reasonable range best_power = 0 best_period = 1 for i, p in enumerate(power): if (periods[i] > 4 and periods[i] < 70): if (p > best_power): best_power = p best_period = periods[i] FAP = ls.false_alarm_probability(best_power) return ls, periods, power, best_period, FAP
def periodogram(ax, t, sig): alpha = 0.001 baseline = max(t) - min(t) ls = LombScargle(t, sig) frequency, power = ls.autopower(minimum_frequency=1 / baseline, maximum_frequency=1 / 2) periods = 1 / frequency ax.plot(periods, power, 'k-') ax.set(xlim=(min(periods), max(periods)), ylim=min(power), xlabel='Period (JD)', ylabel='Lomb-Scargle Power', xscale='log') # Add line to periodogram representing FAP = alpha n = 100 x_values = [1.3**i for i in range(n)] + [1.11] y_values_alpha = [ls.false_alarm_level(alpha) for i in range(n + 1)] ax.plot(x_values, y_values_alpha, 'b_') ax.legend(["{0} FAP".format(alpha)], loc="upper right", frameon=False, handlelength=0) best_period = find_best_period(t, sig) # Plot aliases, harmonics and sampling periods on the periodogram as vertical lines. f_sampling = [1 / 1, 1 / 29.5, 1 / 365] aliases, harmonics = find_aliases(1 / best_period, [-1, 1], f_sampling) for alias in aliases: ax.axvline(alias, c="grey", lw=0.8) for harmonic in harmonics: ax.axvline(harmonic, c="blue", lw=0.8) for f in f_sampling: ax.axvline(1 / f, c="green", lw=0.8)
def plot_periodograms(activityFile, plot_dir, results): """ Produce periodograms of RV and activity indices @author: Melissa Hobson adapted by Martin Schlecker Parameters ------------ activityFile : string file containing the reduced time series plot_dir : string directory for the created plots results : results object a results object returned by juliet.fit() Returns -------- fig : matplotlib figure figure containing the plot ax : matplotlib axis axis object with the plot """ font = {'size': 15} mpl.rc('font', **font) bbox_props = { 'boxstyle': "round", 'fc': "w", 'edgecolor': "w", # 'ec':0.5, 'alpha': 0.9 } # ============================================================================= # Read data in # FEROS data feros_dat = np.genfromtxt(activityFile, names=True) feros_dat = pd.DataFrame(feros_dat).replace(-999, np.nan) transit_per = np.median(results.posteriors['posterior_samples']['P_p1']) # ============================================================================= # Periodograms - FEROS f_min = 1 / (feros_dat['BJD_OUT'].max() - feros_dat['BJD_OUT'].min()) f_max = None #RV # variables bjd_feros = feros_dat['BJD_OUT'] RV_feros = feros_dat['RV'] RV_E_feros = feros_dat['RV_E'] # create periodogram rv_ls = LombScargle(bjd_feros, RV_feros, RV_E_feros) rv_frequency, rv_power = rv_ls.autopower(minimum_frequency=f_min, maximum_frequency=f_max) # Get FAP levels probabilities = [0.01, 0.005, 0.001] labels = ['1.00% FAP', '0.50% FAP', '0.01% FAP'] ltype = ['solid', 'dashed', 'dotted'] rv_faps = rv_ls.false_alarm_level(probabilities, method='bootstrap') # H alpha # variables ha_feros = feros_dat['HALPHA'] ha_e_feros = feros_dat['HALPHA_E'] # create periodogram ha_ls = LombScargle(bjd_feros, ha_feros, ha_e_feros) ha_frequency, ha_power = ha_ls.autopower(minimum_frequency=f_min, maximum_frequency=f_max) # Get FAP levels ha_faps = ha_ls.false_alarm_level(probabilities, method='bootstrap') # log Rhk # variables rhk_feros = feros_dat['LOG_RHK'].dropna() rhk_e_feros = feros_dat['LOGRHK_E'].dropna() bjd_rhk = bjd_feros.iloc[rhk_feros.index] # create periodogram rhk_ls = LombScargle(bjd_rhk, rhk_feros, rhk_e_feros) rhk_frequency, rhk_power = rhk_ls.autopower(minimum_frequency=f_min, maximum_frequency=f_max) # Get FAP levels rhk_faps = rhk_ls.false_alarm_level(probabilities, method='bootstrap') # Na II # variables na_feros = feros_dat['NA_II'] na_e_feros = feros_dat['NA_II_E'] # create periodogram na_ls = LombScargle(bjd_feros, na_feros, na_e_feros) na_frequency, na_power = na_ls.autopower(minimum_frequency=f_min, maximum_frequency=f_max) # Get FAP levels na_faps = na_ls.false_alarm_level(probabilities, method='bootstrap') # He I # variables he_feros = feros_dat['HE_I'] he_e_feros = feros_dat['HE_I_E'] # create periodogram he_ls = LombScargle(bjd_feros, he_feros, he_e_feros) he_frequency, he_power = he_ls.autopower(minimum_frequency=f_min, maximum_frequency=f_max) # Get FAP levels he_faps = he_ls.false_alarm_level(probabilities, method='bootstrap') # ============================================================================= # Plot the data # figsize = plotstyle.set_size(subplot=[5,1]) # (11, 21) figsize = (8, 10) fig, axs = plt.subplots(5, 1, figsize=figsize, sharex=True, sharey=True, gridspec_kw={ 'wspace': 0, 'hspace': 0.08 }) # # RV timeseries # axs[0].errorbar(bjd_feros, RV_feros, yerr=RV_E_feros, fmt='o') # axs[0].set_xlabel('BJD') # axs[0].set_ylabel('RV [km/s]') # RV periodogram annotOffsets = [-.12, 0, .12] axs[0].plot(rv_frequency, rv_power) for ind in range(len(rv_faps)): axs[0].axhline(rv_faps[ind], xmax=0.81, label=labels[ind], lw=1.5, linestyle=ltype[ind], c='black') axs[0].annotate(labels[ind], xy=[.815, rv_faps[ind]], va='center', xytext=[.86, rv_faps[1] + annotOffsets[ind]], size=10, xycoords=('axes fraction', 'data'), arrowprops=dict(arrowstyle="-")) axs[0].axvline(1 / transit_per, lw=1.5, linestyle='dashed', color='C1') # axs[0].set_xscale('log') # axs[0].set_xlabel('Frequency [1/d]') axs[0].set_ylabel('power') axs[0].annotate('P = {:.2f} d'.format(transit_per), [1 / transit_per, 1.05], color='C1', ha='center', xycoords=('data', 'axes fraction')) axs[0].annotate('RV', xy=(0, 1.01), xytext=(.02, .84), size=15, bbox=bbox_props, ha='left', va='center', xycoords='axes fraction', textcoords='axes fraction') # # Halpha timeseries # plt.subplot(4, 3, 2) # plt.errorbar(bjd_feros, ha_feros, yerr=ha_e_feros, fmt='o') # plt.set_xlabel('BJD') # plt.set_ylabel('H ALPHA') # Halpha periodogram axs[1].plot(ha_frequency, ha_power) for ind in range(len(ha_faps)): axs[1].axhline(ha_faps[ind], label=labels[ind], lw=1.5, linestyle=ltype[ind], c='black') axs[1].axvline(1 / transit_per, lw=1.5, linestyle='dashed', color='C1') # axs[1].set_xscale('log') # axs[1].set_xlabel('Period [d]') axs[1].set_ylabel('power') axs[1].annotate(r'H$_\alpha$', xy=(0, 1.01), xytext=(.02, .84), size=15, bbox=bbox_props, ha='left', va='center', xycoords='axes fraction', textcoords='axes fraction') # # log RHK timeseries # plt.subplot(4, 3, 3) # plt.errorbar(bjd_feros, rhk_feros, yerr=rhk_e_feros, fmt='o') # plt.set_xlabel('BJD'HKk) # plt.set_ylabel('LOG RHK') # log Rhk periodogram axs[2].plot(rhk_frequency, rhk_power) for ind in range(len(rhk_faps)): axs[2].axhline(rhk_faps[ind], label=labels[ind], lw=1.5, linestyle=ltype[ind], c='black') axs[2].axvline(1 / transit_per, lw=1.5, linestyle='dashed', color='C1') # axs[2].set_xscale('log') # axs[2].set_xlabel('Period [d]') axs[2].set_ylabel('power') axs[2].annotate(r'log($R^\prime_{HK}$)', xy=(0, 1.01), xytext=(.02, .84), size=15, bbox=bbox_props, ha='left', va='center', xycoords='axes fraction', textcoords='axes fraction') # # Na II timeseries # plt.subplot(4, 3, 8) # plt.errorbar(bjd_feros, na_feros, yerr=na_e_feros, fmt='o') # plt.set_xlabel('BJD') # plt.set_ylabel('NA II') # Na II periodogram axs[3].plot(na_frequency, na_power) for ind in range(len(na_faps)): axs[3].axhline(na_faps[ind], label=labels[ind], lw=1.5, linestyle=ltype[ind], c='black') axs[3].axvline(1 / transit_per, lw=1.5, linestyle='dashed', color='C1') # axs[3].set_xscale('log') # axs[3].set_xlabel('Period [d]') axs[3].set_ylabel('power') axs[3].annotate(r'Na II', xy=(0, 1.01), xytext=(.02, .84), size=15, bbox=bbox_props, ha='left', va='center', xycoords='axes fraction', textcoords='axes fraction') # # HeI timeseries # plt.subplot(4, 3, 9) # plt.errorbar(bjd_feros, he_feros, yerr=he_e_feros, fmt='o') # plt.set_xlabel('BJD') # plt.set_ylabel('HE I') # HeI periodogram axs[4].plot(he_frequency, he_power) for ind in range(len(he_faps)): axs[4].axhline(he_faps[ind], label=labels[ind], lw=1.5, linestyle=ltype[ind], c='black') axs[4].axvline(1 / transit_per, lw=1.5, linestyle='dashed', color='C1') # axs[4].set_xscale('log') # axs[4].set_xlabel('Period [d]') axs[4].set_xlabel('Frequency [1/d]') axs[4].set_ylabel('power') axs[4].annotate(r'He I', xy=(0, 1.01), xytext=(.02, .84), size=15, bbox=bbox_props, ha='left', va='center', xycoords='axes fraction', textcoords='axes fraction') # some eye candy [ax.set_xlim([0.005, 0.3]) for ax in axs] # [ax.set_ylim([0,.9]) for ax in axs] [ax.tick_params(direction='in', top=True, right=True) for ax in axs] # fig.subplots_adjust(hspace = .03, wspace=0.4) plt.show() fig.savefig(plot_dir + 'periodograms.pdf') return fig, ax # import pickle # out_folder = 'out/27_tess+chat+feros+GP' # priors, params = get_priors(GP=True) # times_lc, fluxes, fluxes_error, gp_times_lc = read_photometry(datafolder, # plotPhot=False, outlierIndices=outlierIndices) # times_rv, rvs, rvs_error = read_rv(datafolder) # # dataset = juliet.load( # priors=priors, t_lc=times_lc, y_lc=fluxes, yerr_lc=fluxes_error, # t_rv=times_rv, y_rv=rvs, yerr_rv=rvs_error, # GP_regressors_lc=gp_times_lc, # out_folder=out_folder, verbose=True) # results = pickle.load(open(out_folder + '/results.pkl', 'rb')) # plot_periodograms(activityFile, plot_dir, results) # sys.exit(0)
def estimate_period(time, y, y_err, clip=True, plot=True, **kwargs): """ Run a Lomb-Scargle Periodogram to find periodic signals. It's recommended to use the allesfitter.time_series functions sigma_clip and slide_clip beforehand. Parameters ---------- time : array of float e.g. time array (usually in days) y : array of float e.g. flux or RV array (usually as normalized flux or RV in km/s) yerr : array of float e.g. flux or RV error array (usually as normalized flux or RV in km/s) clip : bool, optional Automatically clip the input data with sigma_clip(low=4, high=4) and slide_clip(window_length=1, low=4, high=4). The default is True. plot : bool, optional To plot or not, that is the question. The default is False. **kwargs : collection of keyword arguments Any keyword arguments will be passed onto the astropy periodogram class. Returns ------- best_period : float The best period found. FAP : float The false alarm probability for the best period. fig : matplotlib.figure object, optional The summary figure. Only returned if plot is True. """ #========================================================================== #::: clean the inputs #========================================================================== time, y, y_err = clean(time, y, y_err) plot_bool = plot if clip: y = sigma_clip(time, y, low=4, high=4) y = slide_clip(time, y, window_length=1, low=4, high=4) time, y, y_err = clean(time, y, y_err) #========================================================================== #::: handle inputs #========================================================================== cadence = np.nanmedian(np.diff(time)) if kwargs is None: kwargs = {} if 'minperiod' not in kwargs: kwargs['minperiod'] = 10. * cadence if 'maxperiod' not in kwargs: kwargs['maxperiod'] = time[-1] - time[0] minfreq = 1. / kwargs['maxperiod'] maxfreq = 1. / kwargs['minperiod'] #========================================================================== #::: now do the periodogram #========================================================================== ls = LombScargle( time, y ) #Analyze our dates and s-index data using the AstroPy Lomb Scargle module frequency, power = ls.autopower( minimum_frequency=minfreq, maximum_frequency=maxfreq) #Determine the LS periodogram best_power = np.nanmax(power) best_frequency = frequency[np.argmax(power)] best_period = 1. / best_frequency FAP = ls.false_alarm_probability( best_power) #Calculate the FAP for the highest peak in the power array #========================================================================== #::: plot #========================================================================== def plot(): peak_loc = round(float(1. / best_frequency), 2) FAP_probabilities = [0.5, 0.1, 0.01] #Enter FAP values you want to determine FAP_levels = ls.false_alarm_level( FAP_probabilities) #Get corresponding LS Power values fig, axes = plt.subplots(4, 1, figsize=[10, 15], tight_layout=True) #::: plot the periodogram ax = axes[0] ax.semilogx(1. / frequency, power, color='b') ax.plot(peak_loc, best_power, marker='d', markersize=12, color='r') ax.text(peak_loc * 1.2, best_power * 0.95, 'Peak Period: ' + str(peak_loc) + ' days') ax.text(peak_loc * 1.2, best_power * 0.85, 'FAP: ' + str(FAP)) ax.hlines(FAP_levels, kwargs['minperiod'], kwargs['maxperiod'], color='grey', lw=1) ax.text(kwargs['maxperiod'], FAP_levels[0], '0.5% FAP ', ha='right') ax.text(kwargs['maxperiod'], FAP_levels[1], '0.1% FAP ', ha='right') ax.text(kwargs['maxperiod'], FAP_levels[2], '0.01% FAP ', ha='right') ax.set(xlabel='Period (days)', ylabel='L-S power') ax.tick_params(axis='both', which='major') #::: plot the phase-folded data ax = axes[1] plot_phase_folded_lightcurve(time, y, period=1. / best_frequency, epoch=0, ax=ax) ax.set(ylim=[np.nanmin(y), np.nanmax(y)], ylabel='Data (clipped; phased)') #::: plot the phase-folded data, zoomed ax = axes[2] plot_phase_folded_lightcurve(time, y, period=1. / best_frequency, epoch=0, ax=ax) ax.set(ylabel='Data (clipped; phased; y-zoom)') #::: plot the autocorrelation of the data ax = axes[3] plot_acf(pd.Series(y, index=time), ax=ax, lags=np.linspace(start=1, stop=2 * best_period / cadence, num=100, dtype=int)) ax.set(xlabel='Lag', ylabel='Autocorrelation', title='') return fig #========================================================================== #::: return #========================================================================== if plot_bool: fig = plot() return best_period, FAP, fig else: return best_period, FAP
def lombscargle(t, x, dx=None, f0=None, fmax=None, n=5, fap_method=None, fap_level=None, psd=False): """Computes the generalized Lomb-Scargle periodogram of a discrete signal. Parameters ---------- t: array-like Time array. x: array-like Signal array. dx: array-like, optional Measurement uncertainties for each sample. f0: float, optional Minimum frequency. If not given, it will be determined from the time baseline. fmax: float, optional Maximum frequency. If not given, defaults to the pseudo-Nyquist limit. n: float, optional Samples per peak (default is 5). fap_method: {None, 'baluev', 'bootstrap'} The approximation method to use for the highest peak FAP and false alarm levels. The default is None, in which case the FAP is not calculated. fap_level: array-like, optional List of false alarm probabilities for which you want to calculate approximate levels. Can also be passed as a single scalar value. psd: bool, optional Whether to leave periodogram non-normalized (Fourier Spectral Density). Returns ------- ls: astropy.timeseries.LombScargle object The full object for the given data. f: ndarray Frequency array. a: ndarray Power array. fap: float If `fap_method` is given, the False Alarm Probability of highest peak. fal: float If `fap_level` is given, the power level for the given probabilities. """ if psd: ls = LombScargle(t, x, dy=dx, normalization='psd') else: ls = LombScargle(t, x, dy=dx) if fmax is None: ts = float(np.median(np.diff(t))) fs = 1 / ts fmax = fs / 2 f, a = ls.autopower(samples_per_peak=n, minimum_frequency=f0, maximum_frequency=fmax) if fap_method is not None: if fap_method not in ['baluev', 'bootstrap']: raise ValueError(f"Unknown FAP method {fap_method}.") fap = ls.false_alarm_probability(a.max(), method=fap_method, minimum_frequency=f0, maximum_frequency=fmax, samples_per_peak=n) if fap_level is not None: fal = ls.false_alarm_level(fap_level, method=fap_method, minimum_frequency=f0, maximum_frequency=fmax, samples_per_peak=n) return ls, f, a, fap, fal return ls, f, a, fap return ls, f, a
def genLS(self, show_plot='y', compute_fap='n', use_detrend='n', minP=None, maxP=None, LSquarters=None): print("calling _mp_visuals.py/genLS().") ### this function generates a Lomb-Scargle Periodogram! LSperiods = [] LSmaxpower_periods = [] LSpowers = [] LSfaps = [] nquarters = len(self.quarters) if type(LSquarters) == type(None): LSquarters = self.quarters for qidx in np.arange(0, nquarters, 1): this_quarter = self.quarters[qidx] if this_quarter not in LSquarters: ### use this in case you've only specified select quarters. continue print("processing LS for ", this_quarter) if nquarters != 1: if use_detrend == 'n': qtimes, qfluxes, qerrors = self.times[qidx], self.fluxes[ qidx], self.errors[qidx] elif use_detrend == 'y': qtimes, qfluxes, qerrors = self.times[ qidx], self.fluxes_detrend[qidx], self.errors_detrend[qidx] else: if use_detrend == 'n': qtimes, qfluxes, qerrors = self.times, self.fluxes, self.errors elif use_use_detrend == 'y': qtimes, qfluxes, qerrors = self.times, self.fluxes_detrend, self.errors_detrend if maxP == None: maxperiod = 0.5 * (np.nanmax(qtimes) - np.nanmin(qtimes)) else: maxperiod = maxP if minP == None: minperiod = 0.5 else: minperiod = minP minfreq, maxfreq = 1 / maxperiod, 1 / minperiod qls = LombScargle(qtimes, qfluxes, qerrors) qfreq, qpower = qls.autopower(minimum_frequency=minfreq, maximum_frequency=maxfreq) qperiods = 1 / qfreq if compute_fap == 'y': qfap = qls.false_alarm_probability(qpower.max(), method='bootstrap') probabilities = [0.1, 0.05, 0.01] quarter_FALs = qls.false_alarm_level(probabilities) if show_plot == 'y': random_color = np.random.rand(3) plt.plot(qperiods[::-1], qpower[::-1], c=random_color) if compute_fap == 'y': plt.plot(qperiods[::-1], np.linspace(quarter_FALs[1], quarter_FALs[1], len(qperiods[::-1])), c=random_color) LSperiods.append(qperiods) max_power_period = qperiods[np.nanargmax(qpower)] LSmaxpower_periods.append(max_power_period) LSpowers.append(qpower) if compute_fap == 'y': LSfaps.append(qfap) if show_plot == 'y': plt.xscale('log') plt.xlabel('Period [days]') plt.ylabel('Power') plt.title(self.target) plt.show() LSperiods, LSpowers, LSfaps = np.array(LSperiods), np.array( LSpowers), np.array(LSfaps) print('LS max power periods = ', LSmaxpower_periods) LSperiod_median = np.nanmedian(LSmaxpower_periods) LSperiod_std = np.nanstd(LSmaxpower_periods) print('median(LS max power periods) = ', LSperiod_median) print('std(LS max power periods) = ', LSperiod_std) self.LSperiods = LSperiods self.LSpowers = LSpowers self.LSfaps = LSfaps self.LSmaxperiods = LSmaxpower_periods
def lombscargle_periodogram(time, flux, error, dt=0, min_period=0.1, max_period=4, peak_points=10, height=0, peak_ind=0, plot=True, xlim=(0, 1)): ''' this function determines the peak period of a given light curve, allows one to choose which peak to select, then plots the periodogram and the folded light curve Parameters ---------- time : array of float contains time data for the light curve flux : array of float contains flux data for the light curve error : array of float contains error data for the light curve dt : float time shift [default = 0] min_period : float minimum period to investigate [default = 0.1 days] max_period : float maximum period to investigate [default = 4 days] peak_points : int number of points around peaks [default = 10] height : float minimum height to consider peaks [default = 0] peak_ind : ind choose a peak number, maximum is default [peak_ind = 0] plot : bool plot a periodogram and the folded lightcurve with best fit sinusoid xlim : tuple x-limits of the folded plot [default = (0, 1)] Returns ------- Pb : tuple contains the best fit parameters for the sine wave (amplitude, period, phase) residuals : array of float contains the residuals between the best fit model and the data ''' time_fixed = time - dt # create the periodogram model = LombScargle(time_fixed, flux, error) frequencies, power = model.autopower(minimum_frequency=(1. / max_period), maximum_frequency=(1 / min_period), samples_per_peak=peak_points) # convert to periods periods = 1 / frequencies # identify and extract peaks inds, peaks = find_peaks(power, height=height) peaks = peaks['peak_heights'] sort_peaks = np.argsort(peaks) inds = inds[sort_peaks] peaks = peaks[sort_peaks] # select peak period = periods[inds[-1 - peak_ind]] # fit the sinusoid flux_fit = model.model(time_fixed, 1 / period) residuals = flux - flux_fit t0, t1, t2 = model.model_parameters(1 / period) # convert theta parameters to amplitude and phase amplitude = np.hypot(t1, t2) * np.sign(flux_fit[0]) phase = -np.arctan(t1 / t2) + np.pi / 2 Pb = (amplitude, period, phase) # plot the periodogram and folded light curve if plot == True: # periodogram fig = plt.figure(figsize=(16, 8)) plt.title('Lomb-Scargle Periodogram of Stellar Variations') plt.xlabel('Period [days]') plt.ylabel('Power [-]') plt.plot(periods, power, 'b-') plt.gca().axvline(x=period, color='k', ls=':') plt.show() # folded light curve plot_folded(time_fixed, flux, error, Pb, flux_fit, dt, xlim) print('%.6f sin(2 pi time / %.4f + %.4f)' % Pb) return Pb, residuals
def estimate_period(time, flux, flux_err, periodogram_kwargs=None, astropy_kwargs=None, wotan_kwargs=None, options=None): #========================================================================== #::: handle inputs #========================================================================== cadence = np.nanmedian(np.diff(time)) if periodogram_kwargs is None: periodogram_kwargs = {} if 'minperiod' not in periodogram_kwargs: periodogram_kwargs['minperiod'] = 10. * cadence if 'maxperiod' not in periodogram_kwargs: periodogram_kwargs['maxperiod'] = time[-1] - time[0] if astropy_kwargs is None: astropy_kwargs = {} if 'sigma' not in astropy_kwargs: astropy_kwargs['sigma'] = 5 if wotan_kwargs is None: wotan_kwargs = {} if 'slide_clip' not in wotan_kwargs: wotan_kwargs['slide_clip'] = {} if 'window_length' not in wotan_kwargs['slide_clip']: wotan_kwargs['slide_clip']['window_length'] = 1. if 'low' not in wotan_kwargs['slide_clip']: wotan_kwargs['slide_clip']['low'] = 5 if 'high' not in wotan_kwargs['slide_clip']: wotan_kwargs['slide_clip']['high'] = 5 if options is None: options = {} if 'show_plot' not in options: options['show_plot'] = False if 'save_plot' not in options: options['save_plot'] = False if 'fname_plot' not in options: options['fname_plot'] = 'periodogram' if 'outdir' not in options: options['outdir'] = '.' minfreq = 1. / periodogram_kwargs['maxperiod'] maxfreq = 1. / periodogram_kwargs['minperiod'] #========================================================================== #::: first, a global 5 sigma clip #========================================================================== ff = sigma_clip( np.ma.masked_invalid(flux), sigma=astropy_kwargs['sigma']) #astropy wants masked arrays ff = np.array( ff.filled(np.nan) ) #use NaN instead of masked arrays, because masked arrays drive me crazy #========================================================================== #::: fast slide clip (1 day, 5 sigma) [replaces Wotan's slow slide clip] #========================================================================== try: ff = fast_slide_clip(time, ff, **wotan_kwargs['slide_clip']) except: print('Fast slide clip failed and was skipped.') #========================================================================== #::: now do the periodogram #========================================================================== ind_notnan = np.where(~np.isnan(time * ff * flux_err)) ls = LombScargle( time[ind_notnan], ff[ind_notnan] ) #Analyze our dates and s-index data using the AstroPy Lomb Scargle module frequency, power = ls.autopower( minimum_frequency=minfreq, maximum_frequency=maxfreq) #Determine the LS periodogram best_power = np.nanmax(power) best_frequency = frequency[np.argmax(power)] FAP = ls.false_alarm_probability( best_power) #Calculate the FAP for the highest peak in the power array #========================================================================== #::: plots #========================================================================== if options['show_plot'] or options['save_plot']: peak_loc = round(float(1. / best_frequency), 2) FAP_probabilities = [0.5, 0.1, 0.01] #Enter FAP values you want to determine FAP_levels = ls.false_alarm_level( FAP_probabilities) #Get corresponding LS Power values fig, axes = plt.subplots(5, 1, figsize=[10, 15], tight_layout=True) axes = np.atleast_1d(axes) ax = axes[0] ind_clipped = np.where(np.isnan(ff))[0] ax.plot(time[ind_clipped], flux[ind_clipped], 'r.', rasterized=True) ax.plot(time, ff, 'b.', rasterized=True) ax.set(xlabel='Time (BJD)', ylabel='Flux') ax = axes[1] ax.plot(time, ff, 'b.', rasterized=True) ax.set(xlabel='Time (BJD)', ylabel='Flux (clipped)') ax = axes[2] ax.semilogx(1. / frequency, power, color='b') ax.plot(peak_loc, best_power, marker='d', markersize=12, color='r') ax.text(peak_loc * 1.2, best_power * 0.95, 'Peak Period: ' + str(peak_loc) + ' days') ax.text(peak_loc * 1.2, best_power * 0.85, 'FAP: ' + str(FAP)) ax.hlines(FAP_levels, periodogram_kwargs['minperiod'], periodogram_kwargs['maxperiod'], color='grey', lw=1) ax.text(periodogram_kwargs['maxperiod'], FAP_levels[0], '0.5% FAP ', ha='right') ax.text(periodogram_kwargs['maxperiod'], FAP_levels[1], '0.1% FAP ', ha='right') ax.text(periodogram_kwargs['maxperiod'], FAP_levels[2], '0.01% FAP ', ha='right') ax.set(xlabel='Period (days)', ylabel='L-S power') ax.tick_params(axis='both', which='major') # ax.text(peak_loc*1.2,best_power*0.75,'std_old:'+str(std_old*1e3)[0:4]+' --> '+'std_new:'+str(std_new*1e3)[0:4]) ax = axes[3] plot_phase_folded_lightcurve(time, ff, period=1. / best_frequency, epoch=0, ax=ax) ax.set(ylim=[np.nanmin(ff), np.nanmax(ff)], ylabel='Flux (clipped)', xticklabels=[]) ax = axes[4] plot_phase_folded_lightcurve(time, ff, period=1. / best_frequency, epoch=0, ax=ax) ax.set(ylabel='Flux (clipped; y-zoom)') if options['save_plot']: if not os.path.exists(options['outdir']): os.makedirs(options['outdir']) fig.savefig(os.path.join(options['outdir'], options['fname_plot'] + '.pdf'), bbox_inches='tight') if options['show_plot']: plt.show(fig) else: plt.close(fig) return 1. / best_frequency, FAP
from astropy.modeling import models, fitting from astropy.time import Time from datetime import date from astropy.timeseries import LombScargle import matplotlib.gridspec as gridspec data = Table.read('gj1132_lya_lc.ecsv') times, flux, error = np.array(data['MJD']), np.array(data['FLUX']), np.array(data['ERROR']) fitter = fitting.LevMarLSQFitter() plt.figure(figsize=(16, 6)) gs = gridspec.GridSpec(1,7) ls = LombScargle(times, flux, dy=np.array(error), normalization='model') frequency, power = ls.autopower(maximum_frequency = 1/100, minimum_frequency=1/1500, samples_per_peak=10) plt.subplot(gs[0:3]) plt.plot(1/frequency, power) period = 1/frequency[np.argmax(power)] print(period) plt.xlabel('Period (d)') plt.ylabel('LS Power') #plt.annotate('P\_max = {0:10.1f} d'.format(period), (0.6, 0.9), xycoords ='axes fraction' ) #plt.axhline(ls.false_alarm_level(0.01)) plt.xlim(101, 1399) plt.subplot(gs[3:]) plt.errorbar(times, flux, yerr=error, ls='none', marker='o')
def main(): names = [ "d-abc_f.by", "d-abc_f.by.001", "d-abc_f.by.002", "d-ab_f.by", "d-ac_f.by", "d-ab_f.by", "c-ab_f.by", "d-bc_f.by", "c-a_f.by", "d-b_f.by", "d-a_f.by" ] names_index = 0 while (names_index < 15): filename = names[names_index] try: file = open(filename) break except: names_index += 1 continue season_lengths = [] last_day = 0 curr_season_length = 0 for line in file.readlines(): words = line.split() day = float(words[0]) if (day - last_day > 1000): #first line last_day = day curr_season_length += 1 continue if (day - last_day > 50): #fix season_lengths.append(curr_season_length) curr_season_length = 0 last_day = day curr_season_length += 1 season_lengths.append(curr_season_length) file.close() newfile = open("seasons.by", "w") file = open(filename) print("Season\tn\tBest Period\tFAP\tp < 0.05 ?") print("-" * 50) t = [] mag = [] for season_number, season_length in enumerate(season_lengths): times = [] fluxes = [] for n in range(season_length): words = file.readline().split() times.append(float(words[0])) fluxes.append(float(words[1])) times, fluxes = residuals(times, fluxes, 2) # fluxes = bandpass.band_pass_filter(times, fluxes, 1/100, 1/4) for n in range(season_length): newfile.write(str(times[n]) + " " + str(fluxes[n]) + "\n") newfile.write("\n") # group seasons groups_of = 6 t += list(times) mag += list(fluxes) if ((season_number + 1) % groups_of == 0 or season_number + 1 == len(season_lengths)): pass else: continue first_season = season_number - groups_of + 2 if (season_number + 1 == len(season_lengths)): first_season = season_number - (season_number % groups_of) + 1 dmag = 1 #arbitrary, doesn't affect anything baseline = max(t) - min(t) ls = LombScargle(t, mag) frequency, power = ls.autopower(minimum_frequency=1 / baseline, maximum_frequency=1 / 2) periods = 1 / frequency best_power = power.max() best_period = periods[list(power).index(best_power)] alpha = 0.05 print("{0}-{4}\t{1}\t{2:.3f}\t\t{3:.4f}\t".format( first_season, len(t), best_period, ls.false_alarm_probability(best_power), season_number + 1), end="") if (best_power > ls.false_alarm_level(alpha)): print("True") else: print("False") t = [] mag = [] newfile.close() file.close() data = ascii.read("seasons.by") # fig = plt.plot(data["col1"], data["col2"], 'k.') # plt.xlabel("Day", fontsize=10) # plt.ylabel("Res. Flux", fontsize=10) # plt.title("Residuals of Relative Flux", fontsize=15) # plt.savefig("residuals.png") # make periodogram t = data["col1"] mag = data["col2"] dmag = 1 #arbitrary, doesn't affect anything baseline = max(t) - min(t) cwd = os.getcwd() starname = cwd.split('/')[-1] ls = LombScargle(t, mag) frequency, power = ls.autopower(minimum_frequency=1 / baseline, maximum_frequency=1 / 2) periods = 1 / frequency best_power = power.max() best_period = periods[list(power).index(best_power)] probabilities = [0.1, 0.05, 0.01] fa_levels = ls.false_alarm_level(probabilities) print("1-{0}\t{1}\t{2:.3f}\t\t{3:.4f}\t".format( len(season_lengths), len(t), best_period, ls.false_alarm_probability(best_power)), end="") alpha = 0.01 if (best_power > ls.false_alarm_level(alpha)): print("True") else: print("False") # file = open("/Users/Ilya/Desktop/SURF/best_periods_using_fap.txt", "a") # if (best_power > ls.false_alarm_level(alpha)): # file.write("{0} {1}\n".format(starname, best_period)) # else: # file.write("{0}\n".format(starname)) # file.close() # make phased data # if (best_power > ls.false_alarm_level(alpha)): # data = ascii.read(filename) # phased_t = [] # for element in t: # phased_t.append(element % best_period) # y_fit = ls.model(phased_t, 1/best_period) # fig, ax = plt.subplots() # ax.plot(phased_t, mag, 'k.') # ax.plot(phased_t, y_fit, 'b.') # plt.savefig("phased.png") # plt.show() length = 100 x_values = [1.3**n for n in range(length)] + [1.11] y_values_10 = [fa_levels[0] for n in range(length + 1)] y_values_05 = [fa_levels[1] for n in range(length + 1)] y_values_01 = [fa_levels[2] for n in range(length + 1)] fig, ax = plt.subplots() ax.plot(periods, power, 'k-') ax.plot(x_values, y_values_01, 'b*', markersize=4) ax.plot(x_values, y_values_05, 'b.', markersize=4) ax.plot(x_values, y_values_10, 'b_') ax.set( xlim=(2, baseline * 5), ylim=min(power), xlabel='period (days)', ylabel='Lomb-Scargle Power', xscale='log', title='{0}'.format(starname), ) ax.legend([ "Best Period: {0:.3f} days".format(best_period), "0.01 FAP", "0.05 FAP", "0.10 FAP" ], loc="center right", frameon=False, handlelength=0) plt.show()
def main(): names = [ "d-abc_f.by", "d-abc_f.by.001", "d-abc_f.by.002", "d-ab_f.by", "d-ac_f.by", "d-ab_f.by", "c-ab_f.by", "d-bc_f.by", "c-a_f.by", "d-b_f.by", "d-a_f.by" ] names_index = 0 while (names_index < 15): filename = names[names_index] try: file = open(filename) break except: names_index += 1 continue season_lengths = [] last_day = 0 curr_season_length = 0 for line in file.readlines(): words = line.split() day = float(words[0]) if (day - last_day > 1000): #first line last_day = day curr_season_length += 1 continue if (day - last_day > 50): #fix season_lengths.append(curr_season_length) curr_season_length = 0 last_day = day curr_season_length += 1 season_lengths.append(curr_season_length) file.close() newfile = open("seasons.by", "w") file = open(filename) for season_length in season_lengths: times = [] fluxes = [] for n in range(season_length): words = file.readline().split() times.append(float(words[0])) fluxes.append(float(words[1])) times, fluxes = residuals(times, fluxes, 2) for n in range(season_length): newfile.write(str(times[n]) + " " + str(fluxes[n]) + "\n") newfile.write("\n") newfile.close() file.close() # make residual plot data = ascii.read("seasons.by") fig = plt.plot(data["col1"], data["col2"], 'k.') plt.xlabel("Day", fontsize=10) plt.ylabel("Res. Flux", fontsize=10) plt.title("Residuals of Relative Flux", fontsize=15) plt.savefig("residuals.png") # make periodogram t = data["col1"] mag = data["col2"] dmag = 1 #arbitrary, doesn't affect anything baseline = max(t) - min(t) cwd = os.getcwd() starname = cwd.split('/')[-1] ls = LombScargle(t, mag) frequency, power = ls.autopower(minimum_frequency=1 / baseline, maximum_frequency=1 / 2) periods = 1 / frequency best_power = power.max() best_period = periods[list(power).index(best_power)] probabilities = [0.1, 0.05, 0.01] fa_levels = ls.false_alarm_level(probabilities) alpha = 0.01 file = open("/Users/Ilya/Desktop/SURF/best_periods_using_fap.txt", "a") if (best_power > ls.false_alarm_level(alpha)): file.write("{0} {1}\n".format(starname, best_period)) else: file.write("{0}\n".format(starname)) file.close() # make phased data if (best_power > ls.false_alarm_level(alpha)): data = ascii.read(filename) phased_t = [] for element in t: phased_t.append(element % best_period) y_fit = ls.model(phased_t, 1 / best_period) fig, ax = plt.subplots() ax.plot(phased_t, mag, 'k.') ax.plot(phased_t, y_fit, 'b.') plt.savefig("phased.png") plt.show() length = 100 x_values = [1.3**n for n in range(length)] + [1.11] y_values_10 = [fa_levels[0] for n in range(length + 1)] y_values_05 = [fa_levels[1] for n in range(length + 1)] y_values_01 = [fa_levels[2] for n in range(length + 1)] fig, ax = plt.subplots() ax.plot(periods, power, 'k-') ax.plot(x_values, y_values_01, 'b*', markersize=4) ax.plot(x_values, y_values_05, 'b.', markersize=4) ax.plot(x_values, y_values_10, 'b_') ax.set( xlim=(2, baseline * 5), ylim=min(power), xlabel='period (days)', ylabel='Lomb-Scargle Power', xscale='log', title='{0}'.format(starname), ) ax.legend([ "Best Period: {0:.3f} days".format(best_period), "0.01 FAP", "0.05 FAP", "0.10 FAP" ], loc="center right", frameon=False, handlelength=0) plt.savefig("adjusted_periodogram.png")
def plot_graph(data, out_filepath, to_display=False, save_to_disk=True): ''' Plot grapth and return its data Params data - input data in list of lists with pair value and time out_filepath - out file name path for create to_display - if set to true then graph will be shown on the display save_to_disk - if set to true then graph will be saved on the disk Return List of lists of graph values in form [freq, period, pgram_value, time_value] ''' output_data = list() x = list() y = list() # Get first time value as constant time value for all window time_value = data[0][1] for val_pair in data: if val_pair[0] != None: x.append(val_pair[1]) y.append(val_pair[0]) # Calculate Lomb-Scargle periodogram Astropy astropy_pgram = LombScargle(x, y, normalization='psd') astropy_freq, astropy_power = astropy_pgram.autopower() astropy_false_alarm_probability = astropy_pgram.false_alarm_probability(astropy_power.max(), method='baluev') # Create figure with 2 subplots fig = plt.figure() source_ax = fig.add_subplot(211) astropy_pgram_ax = fig.add_subplot(212) #Now make a plot of the input data: source_ax.plot(x, y, 'b+') # astropy periodogram astropy_pgram_ax.plot(astropy_freq, astropy_power,'g') astropy_pgram_ax.text(0.95, 0.95, "FAP(first_peak) = {:.4f}%".format(astropy_false_alarm_probability), verticalalignment='top', horizontalalignment='right', transform=astropy_pgram_ax.transAxes, color='green', fontsize=15) if to_display: plt.show() if save_to_disk: plt.savefig(out_filepath) # Generate output for idx, freq in enumerate(astropy_freq): period = 1 / freq output_data.append([freq, period, astropy_power[idx], time_value]) plt.cla() plt.clf() plt.close(fig) return output_data
def pixel_by_pixel(self, colrange=None, rowrange=None, cmap='viridis', data_type="corrected", mask=None, xlim=None, ylim=None, color_by_pixel=False, color_by_aperture=True, freq_range=[1 / 20., 1 / 0.1], FAP=None, aperture=None, ap_color='r', ap_linewidth=2): """ Creates a pixel-by-pixel light curve using the corrected flux. Contribution from Oliver Hall. Parameters ---------- colrange : np.array, optional A list of start column and end column you're interested in zooming in on. rowrange : np.array, optional A list of start row and end row you're interested in zooming in on. cmap : str, optional Name of a matplotlib colormap. Default is 'viridis'. data_type : str, optional The type of flux used. Either: 'raw', 'corrected', 'amplitude', or 'periodogram'. If not, default set to 'corrected'. mask : np.array, optional Specifies the cadences used in the light curve. If not, default set to good quality cadences. xlim : np.array, optional Specifies the xlim on the subplots. If not, default is set to the entire light curve. ylim : np.array, optional Specifies the ylim on the subplots, If not, default is set to the entire light curve flux range. color_by_pixel : bool, optional Colors the light curve given the color of the pixel. If not, default is set to False. freq_range : list, optional List of minimum and maximum frequency to search in Lomb Scargle periodogram. Only used if data_type = 'periodogram'. If None, default = [1/20., 1/0.1]. FAP: np.array, optional. False Alarm Probability levels to include in periodogram. Ensure that the values are < 1. For example: FAP = np.array([0.1, 0.01]), will plot the 10% and 1% FAP levels. """ if self.obj.lite: print( 'This is an eleanor-lite object. No pixel_by_pixel visualization can be created.' ) print( 'Please create a regular eleanor.TargetData object (lite=False) to use this tool.' ) return if colrange is None: colrange = [0, self.dimensions[1]] if rowrange is None: rowrange = [0, self.dimensions[0]] nrows = int(np.round(colrange[1] - colrange[0])) ncols = int(np.round(rowrange[1] - rowrange[0])) if (colrange[1] > self.dimensions[1]) or (rowrange[1] > self.dimensions[0]): raise ValueError( "Asking for more pixels than available in the TPF.") figure = plt.figure(figsize=(20, 8)) outer = gridspec.GridSpec(1, 2, width_ratios=[1, 4]) inner = gridspec.GridSpecFromSubplotSpec(ncols, nrows, hspace=0.1, wspace=0.1, subplot_spec=outer[1]) i, j = rowrange[0], colrange[0] if mask is None: q = self.obj.quality == 0 else: q = mask == 0 ## PLOTS TARGET PIXEL FILE ## ax = plt.subplot(outer[0]) if aperture is None: aperture = self.obj.aperture plotflux = np.nanmedian(self.flux[:, rowrange[0]:rowrange[1], colrange[0]:colrange[1]], axis=0) c = ax.imshow(plotflux, origin='lower', vmax=np.percentile(plotflux, 95), cmap=cmap) divider = make_axes_locatable(ax) cax = divider.append_axes('right', size='5%', pad=0.15) plt.colorbar(c, cax=cax, orientation='vertical') f = lambda x, y: aperture[int(y), int(x)] g = np.vectorize(f) x = np.linspace(colrange[0], colrange[1], nrows * 100) y = np.linspace(rowrange[0], rowrange[1], ncols * 100) X, Y = np.meshgrid(x[:-1], y[:-1]) Z = g(X[:-1], Y[:-1]) ax.contour(Z, [0.05], colors=ap_color, linewidths=[ap_linewidth], extent=[0 - 0.5, nrows - 0.5, 0 - 0.5, ncols - 0.5]) ## PLOTS PIXEL LIGHT CURVES ## for ind in range(int(nrows * ncols)): if ind == 0: ax = plt.Subplot(figure, inner[ind]) origax = ax else: ax = plt.Subplot(figure, inner[ind], sharex=origax) flux = self.flux[:, i, j] time = self.obj.time corr_flux = self.obj.corrected_flux(flux=flux) if data_type.lower() == 'corrected': y = corr_flux[q] / np.nanmedian(corr_flux[q]) x = time[q] elif data_type.lower() == 'amplitude': lc = lk.LightCurve(time=time, flux=corr_flux) pg = lc.normalize().to_periodogram() x = pg.frequency.value y = pg.power.value elif data_type.lower() == 'raw': y = flux[q] / np.nanmedian(flux[q]) x = time[q] elif data_type.lower() == 'periodogram': LS = LombScargle(time, corr_flux) freq, power = LS.autopower(minimum_frequency=freq_range[0], maximum_frequency=freq_range[1], method='fast') y = power x = 1 / freq if (FAP is not None): if np.all(FAP < 1 ): # Ensure that the probabilities are all < 1 if type(FAP) == list: FAP = np.array(FAP) FAPlevel = LS.false_alarm_level(FAP, method='baluev') if color_by_pixel is False: color = 'k' else: rgb = c.cmap(c.norm(self.flux[100, i, j])) color = matplotlib.colors.rgb2hex(rgb) ax.plot(x, y, c=color) if (data_type.lower() == 'periodogram') & (FAP is not None): if np.all(FAP < 1): _ = [ ax.axhline(f, color='k', ls='--', alpha=0.3) for f in FAPlevel ] if color_by_aperture and aperture[i, j] > 0: for iax in ['top', 'bottom', 'left', 'right']: ax.spines[iax].set_color(ap_color) ax.spines[iax].set_linewidth(ap_linewidth) j += 1 if j == colrange[1]: i += 1 j = colrange[0] if ylim is None: ax.set_ylim(np.percentile(y, 1), np.percentile(y, 99)) else: ax.set_ylim(ylim[0], ylim[1]) if xlim is None: ax.set_xlim(np.min(x) - 0.1, np.max(x) + 0.1) else: ax.set_xlim(xlim[0], xlim[1]) if data_type.lower() == 'amplitude': ax.set_yscale('log') ax.set_xscale('log') ax.set_ylim(y.min(), y.max()) ax.set_xlim(np.min(x), np.max(x)) ax.set_xticks([]) ax.set_yticks([]) figure.add_subplot(ax) return figure
def make_WWZ_plot(wwz, wwa, omegas, taus, t, y, lombscargle=True, **kwargs): """ Makes a pretty plot with the WWZ info Parameters ---------- wwz : array-like `(len(omegas),len(taus))` Weighted Wavelet Z-transform array wwa : array-like `(len(omegas),len(taus))` Weighted Wavelet Amplitude array omegas : array-like 1-D array of angular frequencies taus : array-like 1-D array of time-shifts t : array-like 1-D array of time observations y : array-like 1-D array of flux or magnitude observations lombscargle : bool Whether or not to plot the Lomb-Scargle periodogram to compare with the WWZ spectrum. Default True. **kwargs Passed to `matplotlib.pyplot.figure()` Returns ------- fig : `matplotlib.pyplot.Figure` Figure object ax : list List of `matplotlib.pyplot.Axes` objects """ if lombscargle: ls = LombScargle(t, y) freq, power = ls.autopower( minimum_frequency=np.min(omegas) / 2 / np.pi, maximum_frequency=np.max(omegas) / 2 / np.pi) fig = plt.figure(constrained_layout=True, **kwargs) gs = GridSpec(5, 4, figure=fig) lcax = fig.add_subplot(gs[0, :3]) wwzax = fig.add_subplot(gs[1:3, :3]) wwaax = fig.add_subplot(gs[3:, :3]) zsumax = fig.add_subplot(gs[1:3, 3]) asumax = fig.add_subplot(gs[3:, 3]) lcax.scatter(t, y, s=1, c='k') lcax.set(ylabel='Normalized Flux', xlim=(np.min(t), np.max(t))) wwzax.contourf(taus, omegas / 2.0 / np.pi, wwz, levels=100, cmap='cividis') wwzax.fill_between(2 * np.pi / omegas + np.min(t), 0, omegas / 2 / np.pi, alpha=0.5, facecolor='white') #fill the whole axis below this wwzax.fill_between( [np.min(t), np.min(2 * np.pi / omegas + np.min(t))], 0, wwzax.get_ylim()[-1], alpha=0.5, facecolor='white') wwzax.fill_between(np.max(t) - 2 * np.pi / omegas, 0, omegas / 2 / np.pi, alpha=0.5, facecolor='white') #fill the whole axis above this wwzax.fill_between([np.max(np.max(t) - 2 * np.pi / omegas), np.max(t)], 0, wwzax.get_ylim()[-1], alpha=0.5, facecolor='white') wwzax.set(ylabel=r'Frequency [d$^{-1}$]', ylim=(np.min(omegas) / 2 / np.pi, np.max(omegas / 2 / np.pi)), xlim=(np.min(t), np.max(t))) wwaax.contourf(taus, omegas / 2.0 / np.pi, wwa, levels=100, cmap='cividis') wwaax.fill_between(2 * np.pi / omegas + np.min(t), 0, omegas / 2 / np.pi, alpha=0.5, facecolor='white') wwaax.fill_between( [np.min(t), np.min(2 * np.pi / omegas + np.min(t))], 0, wwzax.get_ylim()[-1], alpha=0.5, facecolor='white') wwaax.fill_between(np.max(t) - 2 * np.pi / omegas, 0, omegas / 2 / np.pi, alpha=0.5, facecolor='white') wwaax.fill_between([np.max(np.max(t) - 2 * np.pi / omegas), np.max(t)], 0, wwzax.get_ylim()[-1], alpha=0.5, facecolor='white') wwaax.set(xlabel='Time [d]', ylabel=r'Frequency [d$^{-1}$]', ylim=(np.min(omegas) / 2 / np.pi, np.max(omegas / 2 / np.pi)), xlim=(np.min(t), np.max(t))) zsumax.plot(np.mean(wwz, axis=1), omegas / 2.0 / np.pi) if lombscargle: scale = np.max(np.mean(wwz, axis=1)) / np.max(power) zsumax.plot(power * scale, freq, c='k') zsumax.set(yticks=[], xlabel=r'$\langle WWZ \rangle$', ylim=(np.min(omegas) / 2 / np.pi, np.max(omegas / 2 / np.pi)), xlim=(0, zsumax.get_xlim()[-1])) asumax.plot(np.mean(wwa, axis=1), omegas / 2.0 / np.pi) asumax.set(yticks=[], xlabel=r'$\langle WWA \rangle$', ylim=(np.min(omegas) / 2 / np.pi, np.max(omegas / 2 / np.pi)), xlim=(0, asumax.get_xlim()[-1])) if lombscargle: scale = np.max(np.mean(wwa, axis=1)) / np.max(power) asumax.plot(power * scale, freq, c='k') return fig, [lcax, wwzax, wwaax, zsumax, asumax]
def LSP(x, y, dy, fVal=[0, 1, 5, 1], norm='standard', figout=None, label=None, freq_set=None): ''' 周期分析 https://docs.astropy.org/en/stable/timeseries/lombscargle.html#periodogram-algorithms 参数: x,y,dy: arrays 时间,星等,误差 figout: str 图片保存名称 fVal: list minimum_frequency,maximum_frequency,samples_per_peak(default 5),nterms(default 1) return: frequency, power, residuals, x_range, y_fit, theta if nterms=1: theta=[off_set,amplitude,phi,best_frequency] y=off_set+amplitude*np.sin(2*np.pi*best_frequency*x+phi) ''' import numpy as np import matplotlib.pyplot as plt from astropy.timeseries import LombScargle if not isinstance(x, np.ndarray): x = np.array(x) y = np.array(y) dy = np.array(dy) fVal[0] = 10**-5 if fVal[0] == 0 else fVal[0] ls = LombScargle(x, y, dy, nterms=fVal[-1], normalization=norm) frequency, power = ls.autopower(minimum_frequency=fVal[0], maximum_frequency=fVal[1], samples_per_peak=fVal[2]) fig, ax = plt.subplots(3) fig.set_size_inches(20, 27) #ax[0].invert_yaxis();ax[2].invert_yaxis(); ax[0].grid() ax[1].grid() ax[2].grid() ax[0].errorbar(x, y, dy, fmt='bo-', label=label) ax[1].set_xlim((frequency[0], frequency[-1])) ax[1].plot(frequency, power, 'b-') ax11 = ax[1].twiny() ax11.set_xlim(ax[1].get_xlim()) x_side = np.linspace(0.001 + frequency[0], frequency[-1], 10) x_side_var = np.round(24 * 60 / x_side, 2) plt.xticks(x_side, x_side_var, rotation=0) best_frequency = frequency[np.argmax(power)] peak_power = power.max() ax[1].plot(best_frequency, peak_power, 'ro') ax[1].legend([ 'spectrum distribution', 'peak frequency ' + str(round(best_frequency, 4)) + 'c/d is period ' + str(round(24 / best_frequency, 4)) + 'h' ], loc='upper right', fontsize=15, frameon=False) if fVal[-1] == 1: for cutoff in ls.false_alarm_level([0.1, 0.05, 0.01]): ax[1].axhline(cutoff, color='black', linestyle='dotted') if freq_set != None: best_frequency = freq_set phase = (x * best_frequency) % 1 y_fit = ls.model(x, best_frequency) residuals = y - y_fit y_fit = y_fit[np.argsort(phase)] ax[2].plot(np.sort(phase), y_fit, 'r-', linewidth=5) ax[2].errorbar(phase, y, dy, fmt='b.', alpha=1) ax[2].legend( ['best fitted curve is ' + str(best_frequency), 'folded data'], loc='upper right', fontsize=15, frameon=False) x_range = np.linspace(x.min(), x.max(), 100) y_fit = ls.model(x_range, best_frequency) ax[0].plot(x_range, y_fit, 'r-', label='fitting curve', linewidth=5) ax[0].legend(loc='upper right', fontsize=15, frameon=False) if figout: plt.savefig(figout, dpi=100) plt.show() if fVal[-1] == 1: print('the false alarm probability for %0.2f (%0.2f min) is %0.2e' % (best_frequency, 24 * 60 / best_frequency, ls.false_alarm_probability(peak_power, method='davies'))) theta = ls.model_parameters(best_frequency) theta[0] = ls.offset() + theta[0] if len(theta) == 3: K = (theta[1]**2 + theta[2]**2)**0.5 phi = np.arcsin(theta[2] / K) theta = [theta[0], K, phi, best_frequency] return frequency, power, residuals, x_range, y_fit, theta
def prewhiten(time, flux, err, verbose=True, red_noise=True, max_freq=np.inf): """ Runs through a prewhitening procedure to reproduce the variability as sin functions. Now encorporates an optional way of fitting for red noise in the periodograms! Parameters ---------- time : array-like times flux : array-like fluxes err : array-like corresponding errors. verbose : bool If set, will print out every 10th stage of prewhitening, as well as some other diagnostics red_noise : bool If set, will fit for a red noise background model before finding the highest peak max_freq : numeric Determines the number of frequencies to fit for if given. Default `np.inf` Returns ------- good_fs : `~numpy.ndarray` Nx2 array with first dimension frequencies, and the second errors good_amps :`~numpy.ndarray` Nx2 array with first dimension amplitudes, and the second errors good_amps :`~numpy.ndarray` Nx2 array with first dimension amplitudes, and the second errors good_snrs :`~numpy.ndarray` 1D array with signal to noise, calculated directly from the periodogram good_amps :`~numpy.ndarray` 1D array with the heights of the extracted peaks. """ pseudo_NF = 0.5 / (np.mean(np.diff(time))) rayleigh = 1.0 / (np.max(time) - np.min(time)) #Step 1: subtract off the mean, save original arrays for later flux -= np.mean(flux) time -= np.mean(time) original_flux = flux.copy() original_err = err.copy() original_time = time.copy() found_fs = [] err_fs = [] found_amps = [] err_amps = [] found_phases = [] err_phases = [] found_peaks = [] found_snrs = [] #Step 2: Calculate the Lomb Scargle periodogram ls = LombScargle(time, flux, normalization='psd') frequency, power = ls.autopower(minimum_frequency=1.0 / 30.0, maximum_frequency=pseudo_NF) power /= len(time) #putting into the right units #Step 2.5: Normaling by the red noise! if red_noise: try: popt, pcov, resid = fit_red_noise(frequency, power) except RuntimeError: popt, pcov, resid = fit_red_noise(frequency[frequency < 50], power[frequency < 50]) power = resid #Step 3: Find frequency of max residual power, and the SNR of that peak f_0 = frequency[np.argmax(power)] noise_region = (np.abs(frequency - f_0) / rayleigh < 7) & (np.abs(frequency - f_0) / rayleigh > 2) found_peaks.append(power.max()) found_snrs.append(power.max() / np.std(power[noise_region])) #Step 4: Fit the sin. Initial guess is that frequency, the max flux point, and no phase # Then save the fit params p0 = [f_0, np.max(flux), 0] bounds = ([f_0 - rayleigh, 0, -np.inf], [f_0 + rayleigh, np.inf, np.inf]) popt, pcov = curve_fit(parametrized_sin, time, flux, bounds=bounds, p0=p0) found_fs.append(popt[0]) found_amps.append(popt[1]) phase = popt[2] while phase >= np.pi: phase -= 2.0 * np.pi while phase <= -np.pi: phase += 2.0 * np.pi found_phases.append(phase) #Calculate the errors err_fs.append( np.sqrt(6.0 / len(time)) * rayleigh * np.std(flux) / (np.pi * popt[1])) err_amps.append(np.sqrt(2.0 / len(time)) * np.std(flux)) err_phases.append(np.sqrt(2.0 / len(time)) * np.std(flux) / popt[1]) #Calculate the BIC up to a constant: -2 log L + m log (N) log_like_ish = np.sum( np.power(((original_flux - np.sum([ parametrized_sin(time, f, amp, phase) for f, amp, phase in zip(found_fs, found_amps, found_phases) ], axis=0)) / original_err), 2.0)) bic = log_like_ish + 3.0 * len(found_fs) * np.log(len(time)) #bic with no fit is: old_bic = np.sum(np.power((original_flux / original_err), 2.0)) bic_dif = bic - old_bic #subtract off the fit flux -= parametrized_sin(time, *popt) #now loop until BIC hits a minimum j = 0 while (bic_dif <= 0) and (len(found_fs) <= max_freq): #Reset old_bic old_bic = bic #Lomb Scargle ls = LombScargle(time, flux, normalization='psd') frequency, power = ls.autopower(minimum_frequency=1.0 / 30.0, maximum_frequency=pseudo_NF) power /= len(time) #putting into the right units #fit if red_noise: try: popt, pcov, resid = fit_red_noise(frequency, power) except RuntimeError: popt, pcov, resid = fit_red_noise(frequency[frequency < 50], power[frequency < 50]) power = resid #Highest peak f_0 = frequency[np.argmax(power)] noise_region = (np.abs(frequency - f_0) / rayleigh < 7) & (np.abs(frequency - f_0) / rayleigh > 2) found_peaks.append(power.max()) found_snrs.append(power.max() / np.std(power[noise_region])) #Fit p0 = [f_0, np.max(flux), 0] bounds = ([f_0 - rayleigh, 0, -np.inf], [f_0 + rayleigh, np.inf, np.inf]) popt, pcov = curve_fit(parametrized_sin, time, flux, bounds=bounds, p0=p0) found_fs.append(popt[0]) found_amps.append(popt[1]) phase = popt[2] while phase >= np.pi: phase -= 2.0 * np.pi while phase <= -np.pi: phase += 2.0 * np.pi found_phases.append(phase) #Calculate the errors err_fs.append( np.sqrt(6.0 / len(time)) * rayleigh * np.std(flux) / (np.pi * popt[1])) err_amps.append(np.sqrt(2.0 / len(time)) * np.std(flux)) err_phases.append(np.sqrt(2.0 / len(time)) * np.std(flux) / popt[1]) #Calculate BIC log_like_ish = np.sum( np.power(((original_flux - np.sum([ parametrized_sin(time, f, amp, phase) for f, amp, phase in zip(found_fs, found_amps, found_phases) ], axis=0)) / original_err), 2.0)) bic = log_like_ish + 3.0 * len(found_fs) * np.log(len(time)) bic_dif = bic - old_bic #subtract off the fit flux -= parametrized_sin(time, *popt) j += 1 if (j % 10 == 0) and verbose: print(j) if verbose: print('Found {} frequencies'.format(len(found_fs) - 1)) #if we didn't find any GOOD frequencies, get rid of that ish if len(found_fs) - 1 == 0: return np.array([]), np.array([]), np.array([]), np.array( []), np.array([]) #pop the last from each array, as it made the fit worse, then turn into numpy arrays found_fs = np.array(found_fs[:-1]) found_amps = np.array(found_amps[:-1]) found_phases = np.array(found_phases[:-1]) found_snrs = np.array(found_snrs[:-1]) found_peaks = np.array(found_peaks[:-1]) err_fs = np.array(err_fs[:-1]) err_amps = np.array(err_amps[:-1]) err_phases = np.array(err_phases[:-1]) #Now loop through frequencies. If any of the less-strong peaks are within 1.5/T, #get rid of it. good_fs = np.array([[found_fs[0], err_fs[0]]]) good_amps = np.array([[found_amps[0], err_amps[0]]]) good_phases = np.array([[found_phases[0], err_phases[0]]]) good_snrs = np.array([found_snrs[0]]) good_peaks = np.array([found_peaks[0]]) for f, ef, a, ea, p, ep, s, pk in zip(found_fs[1:], err_fs[1:], found_amps[1:], err_amps[1:], found_phases[1:], err_phases[1:], found_snrs[1:], found_peaks[1:]): if ~np.any(np.abs(good_fs[:, 0] - f) <= 1.5 * rayleigh): good_fs = np.append(good_fs, [[f, ef]], axis=0) good_amps = np.append(good_amps, [[a, ea]], axis=0) good_phases = np.append(good_phases, [[p, ep]], axis=0) good_snrs = np.append(good_snrs, [s], axis=0) good_peaks = np.append(good_peaks, [pk], axis=0) if verbose: print('{} unique frequencies'.format(len(good_fs))) return good_fs, good_amps, good_phases, good_snrs, good_peaks