def calPower(code, df): tt = df.index.values dfD = df[df[code].notna().values] t = dfD.index.values x = (t.astype('datetime64[D]') - np.datetime64('1979-01-01')).astype( np.float) y = dfD[code].values nt = len(tt) freq = np.fft.fftfreq(nt)[1:] ind = np.where((1 / freq >= 0) & (1 / freq < 1000))[0] freq = freq[ind] ls = LombScargle(x, y) power = ls.power(freq) p = ls.false_alarm_probability(power) return freq, power, 1 - p
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 get_LS(time, flux, error, freq): x = time y = flux dy = error FP = 1.0 LS = LombScargle(x, y, normalization='standard') # LS = LombScargle(x, y, normalization='psd') power = LS.power(freq) FP = LS.false_alarm_probability(power.max(), minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') FP_99 = LS.false_alarm_level(0.0027, minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') FP_95 = LS.false_alarm_level(0.05, minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') FP_68 = LS.false_alarm_level(0.32, minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') # if FP<0.01:print(dataname) plt.figure(1, (9, 6)) plt.title('Lomb-Scargle Periodogram') plt.plot(freq, power) plt.semilogx() # print(1. / freq[np.where(power == np.max(power))]) # print(np.where(power == np.max(power))) out_period = 1. / freq[np.where(power == np.max(power))] plt.plot([freq[0], freq[-1]], [FP_99, FP_99], '--') plt.plot([freq[0], freq[-1]], [FP_95, FP_95], '--') plt.plot([freq[0], freq[-1]], [FP_68, FP_68], '--') plt.text(freq[0], FP_99, '99%') plt.text(freq[0], FP_95, '95%') plt.text(freq[0], FP_68, '68%') plt.xlabel('Frequency (1/day)', font1) plt.ylabel('Normalized LSP', font1) plt.tick_params(labelsize=16) plt.show() return [FP, out_period]
def get_LS(time, flux, freq): ## Lomb-Scagrle周期图算法,参考VanderPlas J. T., 2018, ApJS, 236, 16 ## x = time y = flux plt.figure(1, (9, 6)) # LS = LombScargle(x, y, dy = 1, normalization = 'standard', fit_mean = True, # center_data = True).power(freq, method = 'cython') LS = LombScargle(x, y, normalization='standard') power = LS.power(freq) FP = LS.false_alarm_probability(power.max(), minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') FP_99 = LS.false_alarm_level(0.0027, minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') FP_90 = LS.false_alarm_level(0.05, minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') FP_68 = LS.false_alarm_level(0.32, minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') plt.plot([freq[0], freq[-1]], [FP_99, FP_99], '--') plt.plot([freq[0], freq[-1]], [FP_90, FP_90], '--') plt.plot([freq[0], freq[-1]], [FP_68, FP_68], '--') plt.title('FP={0}'.format(FP), font1) plt.semilogx() plt.xlabel('frequency (Hz)') plt.ylabel('Normalized Lomb-Scargle power') plt.plot(freq, power) print(1. / freq[np.where(power == np.max(power))]) plt.xlabel('frequency', font1) plt.ylabel('normalized LSP', font1) plt.tick_params(labelsize=16) plt.show() res = 1e5 * power res = np.round(res, 2) return [ FP, 1. / freq[np.where(power == np.max(power))], np.max(power), res ]
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 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 get_LS(time, flux,freq): path='/Users/baotong/xmm/0201290301/txt/' x = time y = flux # dy=np.sqrt(y) # plt.scatter(x,y) # plt.show() # LS = LombScargle(x, y, dy = 1, normalization = 'standard', fit_mean = True, # center_data = True).power(freq, method = 'cython') LS = LombScargle(x, y,normalization = 'standard') # LS = LombScargle(x, y, dy, normalization='psd') power = LS.power(freq) # print('freq_num={0}'.format(len(freq))) FP=LS.false_alarm_probability(power.max(),minimum_frequency = freq[0], maximum_frequency = freq[-1],method='baluev') FP_99 = LS.false_alarm_level(0.0027, minimum_frequency = freq[0], maximum_frequency = freq[-1],method='baluev') FP_90 = LS.false_alarm_level(0.05, minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') FP_68 = LS.false_alarm_level(0.32, minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') plt.title('FP={0}'.format(FP)) plt.semilogx() # plt.xlim(1000.,1500.) plt.plot(1/freq, power) print(1./freq[np.where(power==np.max(power))]) # plt.plot([freq[0], freq[-1]], [FP_99, FP_99], '--') # plt.plot([freq[0], freq[-1]], [FP_90, FP_90], '--') # plt.plot([freq[0], freq[-1]], [FP_68, FP_68], '--') # plt.plot([1/(20.3*60),1/(20.3*60)],[0,0.08],'--',color='green') # plt.plot([1 / (22.5 * 60), 1 / (22.5 * 60)], [0, 0.08], '--', color='yellow') # plt.plot([1 / (18.6 * 60), 1 / (18.6 * 60)], [0, 0.08], '--', color='blue') plt.plot([20.3*60,20.3*60],[0,0.08],'--',color='green') plt.plot([22.5 * 60, 22.5 * 60], [0, 0.08], '--', color='yellow') plt.plot([18.6 * 60, 18.6 * 60], [0, 0.08], '--', color='blue') plt.show() res=1e5*power res=np.round(res,2) # res=res[::smooth] # np.savetxt(path+'LS_simres_{0}.txt'.format(trial+1),res,fmt='%10.5f') return [FP, 1. / freq[np.where(power == np.max(power))],np.max(power),res]
def get_LS(time, flux, freq): x = time y = flux # LS = LombScargle(x, y, dy = 1, normalization = 'standard', fit_mean = True, # center_data = True).power(freq, method = 'cython') LS = LombScargle(x, y, normalization='standard') FP = 0 power = LS.power(freq) FP = LS.false_alarm_probability(power.max(), minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') FP_99 = LS.false_alarm_level(0.0027, minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') FP_90 = LS.false_alarm_level(0.05, minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') FP_68 = LS.false_alarm_level(0.32, minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') plt.figure(1, (9, 6)) plt.plot([freq[0], freq[-1]], [FP_99, FP_99], '--') plt.plot([freq[0], freq[-1]], [FP_90, FP_90], '--') plt.plot([freq[0], freq[-1]], [FP_68, FP_68], '--') # plt.plot([1 /950.7, 1 / 950.7], [0, np.max(power)], '--', linewidth=1) plt.title('FP={0}'.format(FP)) plt.semilogx() # plt.xlim(1000.,1500.) plt.plot(freq, power) print(1. / freq[np.where(power == np.max(power))]) plt.show() res = 1e5 * power res = np.round(res, 2) return [ FP, 1. / freq[np.where(power == np.max(power))], np.max(power), res ]
def get_LS(time, flux, freq): x = time y = flux LS = LombScargle(x, y, normalization='standard') # LS = LombScargle(x, y, normalization='psd') power = LS.power(freq) max_NormLSP = np.max(power) FP = LS.false_alarm_probability(power.max(), minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') FP_99 = LS.false_alarm_level(0.0027, minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') FP_95 = LS.false_alarm_level(0.05, minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') FP_68 = LS.false_alarm_level(0.32, minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') # if FP<0.01:print(dataname) # plt.title('Epoch {2}: XID={0},FAP={1}'.format(dataname,np.round(FP,4),k),font1) # plt.semilogx() plt.plot(freq, power) plt.semilogx() out_period = 1. / freq[np.where(power == np.max(power))][0] plt.plot([freq[0], freq[-1]], [FP_99, FP_99], '--') plt.plot([freq[0], freq[-1]], [FP_95, FP_95], '--') plt.plot([freq[0], freq[-1]], [FP_68, FP_68], '--') plt.text(freq[0], FP_99, '1-FAP 99%', font1) plt.text(freq[0], FP_95, '95%', font1) plt.text(freq[0], FP_68, '68%', font1) plt.xlabel('Frequency (Hz)', font1) plt.ylabel('Normalized LS Periodogram', font1) plt.tick_params(labelsize=16) # plt.show() # plt.savefig('/Users/baotong/Desktop/CDFS/fig_LS_ep{0}_ovsamp_5_baluev/{1}.eps'.format(k,dataname)) plt.close() return [FP, out_period, max_NormLSP]
def get_LS(time, flux,freq,dataname,k): x = time y = flux # dy=np.sqrt(y) # plt.scatter(x,y) # plt.show() FP=1.0 LS = LombScargle(x, y,dy=None,normalization = 'standard') # print(len(freq)) # LS = LombScargle(x, y, normalization='psd') power = LS.power(freq) # print(power.max()) FP=LS.false_alarm_probability(power.max(),minimum_frequency = freq[0],maximum_frequency = freq[-1],method='baluev') FP_99 = LS.false_alarm_level(0.01,minimum_frequency = freq[0], maximum_frequency = freq[-1],method='baluev') FP_95 = LS.false_alarm_level(0.05, minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') FP_68 = LS.false_alarm_level(0.32,minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') # if FP<0.01:print(dataname) plt.title('Epoch {2}: XID={0},FAP={1}'.format(dataname,np.round(FP,4),k),font1) # plt.semilogx() plt.plot(freq, power) # plt.plot([1/2492.73,1/2492.73],[0,np.max(power)],'--',linewidth=1) plt.semilogx() print(1. / freq[np.where(power == np.max(power))]) # print(np.where(power == np.max(power))) # if FP<0.01:print(1./freq[np.where(power==np.max(power))]);print(np.where(power==np.max(power))) out_period=1./freq[np.where(power==np.max(power))] plt.plot([freq[0], freq[-1]], [FP_99, FP_99], '--') plt.plot([freq[0], freq[-1]], [FP_95, FP_95], '--') plt.plot([freq[0], freq[-1]], [FP_68, FP_68], '--') plt.text(freq[0], FP_99, 'FAP 99%',font1) plt.text(freq[0], FP_95, '95%',font1) plt.text(freq[0], FP_68, '68%',font1) plt.xlabel('Frequency (Hz)',font1) plt.ylabel('Normalized LS Periodogram',font1) plt.tick_params(labelsize=16) plt.show() # plt.savefig('/Users/baotong/Desktop/CDFS/fig_LS_ep{0}_ovsamp_5_baluev/{1}.eps'.format(k,dataname)) # plt.savefig('/Users/baotong/Desktop/CDFS/fig_LS_ep{0}_samp_1_baluev/{1}.eps'.format(k,dataname)) # plt.close() return [FP,out_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 get_LS(time, flux, freq): x = time y = flux LS = LombScargle(x, y, normalization='standard') # LS = LombScargle(x, y, dy, normalization='psd') power = LS.power(freq) FP = LS.false_alarm_probability(power.max(), minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') FP_99 = LS.false_alarm_level(0.0027, minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') FP_90 = LS.false_alarm_level(0.05, minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') FP_68 = LS.false_alarm_level(0.32, minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') # if FP<0.01:print(dataname) # plt.title('{0},FP={1}'.format(dataname,FP)) # plt.semilogx() # plt.title('XID 19') plt.plot(freq, power) plt.semilogx() print(1. / freq[np.where(power == np.max(power))]) print(np.where(power == np.max(power))) # if FP<0.01:print(1./freq[np.where(power==np.max(power))]);print(np.where(power==np.max(power))) out_period = 1. / freq[np.where(power == np.max(power))] plt.plot([freq[0], freq[-1]], [FP_99, FP_99], '--') plt.plot([freq[0], freq[-1]], [FP_90, FP_90], '--') plt.plot([freq[0], freq[-1]], [FP_68, FP_68], '--') plt.show() # plt.savefig('/Users/baotong/Desktop/CDFS/fig_LS_ep{0}_ovsamp_5_baluev/{1}.eps'.format(k,dataname)) # plt.close() return [FP, out_period]
def get_LS(time, flux, freq): x = time y = flux LS = LombScargle(x, y, normalization='standard') # LS = LombScargle(x, y, dy, normalization='psd') power = LS.power(freq) FP = LS.false_alarm_probability(power.max(), samples_per_peak=5, nyquist_factor=5, minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') FP_99 = LS.false_alarm_level(0.01, samples_per_peak=10, nyquist_factor=5, minimum_frequency=freq[0], maximum_frequency=freq[-1], method='naive') FP_90 = LS.false_alarm_level(0.1, samples_per_peak=10, nyquist_factor=5, minimum_frequency=freq[0], maximum_frequency=freq[-1], method='naive') FP_68 = LS.false_alarm_level(0.32, samples_per_peak=10, nyquist_factor=5, minimum_frequency=freq[0], maximum_frequency=freq[-1], method='naive') plt.plot(freq, power) print(1. / freq[np.where(power == np.max(power))]) plt.plot([freq[0], freq[-1]], [FP_99, FP_99], '--') plt.plot([freq[0], freq[-1]], [FP_90, FP_90], '--') plt.plot([freq[0], freq[-1]], [FP_68, FP_68], '--') plt.show()
def get_LS(time, flux, freq, dataname): x = time y = flux # dy=np.sqrt(y) # plt.scatter(x,y) # plt.show() # LS = LombScargle(x, y, dy = 1, normalization = 'standard', fit_mean = True, # center_data = True).power(freq, method = 'cython') LS = LombScargle(x, y, normalization='standard') # LS = LombScargle(x, y, normalization='psd') power = LS.power(freq) power_freq = np.max(power[np.where((1 / freq - 2493.76) < 20)]) FP = LS.false_alarm_probability(power_freq, minimum_frequency=freq[0], maximum_frequency=freq[-1], method='baluev') # FP_99 = LS.false_alarm_level(0.0027,minimum_frequency = freq[0], maximum_frequency = freq[-1],method='baluev') # FP_90 = LS.false_alarm_level(0.05, minimum_frequency=freq[0], # maximum_frequency=freq[-1], method='baluev') # FP_68 = LS.false_alarm_level(0.32,minimum_frequency=freq[0], # maximum_frequency=freq[-1], method='baluev') # # if FP<0.01:print(dataname) plt.title('{0},FP={1}'.format(dataname, FP)) # plt.semilogx() plt.plot(freq, power) # plt.plot([1/2492,1/2492.],[0,np.max(power)],'--',linewidth=1) plt.semilogx() print(1. / freq[np.where(power == np.max(power))]) # if FP<0.01:print(1./freq[np.where(power==np.max(power))]);print(np.where(power==np.max(power))) out_period = 1. / freq[np.where(power == np.max(power))] # if np.abs(out_period-950.7317)>30:FP=1 # plt.savefig('/Users/baotong/Desktop/CDFS/fig_LS_ep{0}_ovsamp_5_baluev/{1}.eps'.format(k,dataname)) plt.close() return [FP, out_period]
def get_LS(time, flux,freq,trial=1): path='/Users/baotong/Desktop/CDFS/txt_all_obs_0.5_8_ep3/simulation/19_LS_sim_noQPO/' x = time y = flux # dy=np.sqrt(y) # plt.scatter(x,y) # plt.show() # LS = LombScargle(x, y, dy = 1, normalization = 'standard', fit_mean = True, # center_data = True).power(freq, method = 'cython') LS = LombScargle(x, y,normalization = 'standard') # LS = LombScargle(x, y, dy, normalization='psd') power = LS.power(freq) # print('freq_num={0}'.format(len(freq))) FP=LS.false_alarm_probability(power.max(),minimum_frequency = freq[0], maximum_frequency = freq[-1],method='baluev') # FP_99 = LS.false_alarm_level(0.0027, minimum_frequency = freq[0], maximum_frequency = freq[-1],method='baluev') # FP_90 = LS.false_alarm_level(0.05, minimum_frequency=freq[0], # maximum_frequency=freq[-1], method='baluev') # FP_68 = LS.false_alarm_level(0.32, minimum_frequency=freq[0], # maximum_frequency=freq[-1], method='baluev') # if FP<0.01:print(dataname) # plt.title('FP={0}'.format(FP)) # plt.semilogx() # plt.plot(freq, power) # print(1./freq[np.where(power==np.max(power))]) # plt.plot([freq[0], freq[-1]], [FP_99, FP_99], '--' # plt.plot([freq[0], freq[-1]], [FP_90, FP_90], '--') # plt.plot([freq[0], freq[-1]], [FP_68, FP_68], '--') # plt.show() res=1e2*power res=np.round(res,2) # res=res[::smooth] # np.savetxt(path+'LS_simres_{0}.txt'.format(trial+1),res,fmt='%10.5f') return [FP,1. / freq[np.where(power == np.max(power))],np.max(power),res]
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 _run_locor(TIME, FLUX, dtr_dict, lsp_dict): """ NOTE: lsp_dict is created here if None is passed. """ from notch_and_locor.core import rcomb # Format "data" into recarray format needed for notch. N_points = len(TIME) data = np.recarray((N_points, ), dtype=[('t', float), ('fraw', float), ('fcor', float), ('s', float), ('qual', int), ('divisions', float)]) data.t = TIME data.fcor = FLUX data.fraw[:] = 0 data.s[:] = 0 data.qual[:] = 0 # Get rotation period, if not available. In most cases, it should be # passed in via lsp_dict. if not isinstance(lsp_dict, dict): print( "Did not get period from lsp_dict: finding via Lomb Scargle. " "WARNING: it's better to feed via lsp_dict for cacheing speeds. ") ls = LombScargle(TIME, FLUX, FLUX * 1e-3) period_min, period_max = 0.1, 10 freq, power = ls.autopower(minimum_frequency=1 / period_max, maximum_frequency=1 / period_min) ls_fap = ls.false_alarm_probability(power.max()) best_freq = freq[np.argmax(power)] ls_period = 1 / best_freq theta = ls.model_parameters(best_freq) ls_amplitude = theta[1] # NOTE: this just forces LOCOR to run irrespective of the exact # ls_period, ls_amplitude, ls_fap, or color. In other words, it # doesn't deal with the question of whether the star is young. You # should do that elsewhere, and probably only be running LOCOR for # stars with Prot <~ a few days. lsp_dict['ls_period'] = ls_period lsp_dict['ls_amplitude'] = np.abs(ls_amplitude) lsp_dict['ls_fap'] = ls_fap wsize = lsp_dict['ls_period'] # # minimum rotation period to bunch rotations together to run LOCoR. # 2 days works robustly for K2 long cadence data. TESS we shall see. # alias_num = 2.0 # Run LOCOR (Locally Optimized Combination of Rotations) fittimes, depth, detrend, polyshape, badflag = (rcomb(data, wsize, aliasnum=alias_num)) assert len(fittimes) == len(TIME) # store everything in a common format recarray N_points = len(detrend) locor = np.recarray((N_points, ), dtype=[('t', float), ('detrend', float), ('badflag', int)]) locor.detrend = detrend.copy() locor.badflag = badflag.copy() locor.polyshape = polyshape.copy() locor.t = data.t # # Convert to my naming scheme. # flat_flux = locor.detrend trend_flux = locor.polyshape return flat_flux, trend_flux, locor
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 flatten_with_gp(lc, break_tolerance, min_period, return_trend=False): """ Detrend the flux from an alderaan LiteCurve using a celerite RotationTerm GP kernel The mean function of each uninterrupted segment of flux is modeled as an exponential Fmean = F0*(1+A*exp(-t/tau)) Parameters ---------- lc : alderaan.LiteCurve must have .time, .flux and .mask attributes break_tolerance : int number of cadences considered a large gap in time min_period : float lower bound on primary period for RotationTerm kernel return_trend : bool (default=False) if True, return the trend inferred from the GP fit Returns ------- lc : alderaan.LiteCurve LiteCurve with trend removed from lc.flux gp_trend : ndarray trend inferred from GP fit (only returned if return_trend == True) """ # find gaps/breaks/jumps in the data gaps = identify_gaps(lc, break_tolerance=break_tolerance) gaps[-1] -= 1 # initialize data arrays and lists of segments gp_time = np.array(lc.time, dtype="float64") gp_flux = np.array(lc.flux, dtype="float64") gp_mask = np.sum(lc.mask, 0) == 0 gp_quarter = np.array(lc.quarter, dtype="int") time_segs = [] flux_segs = [] mask_segs = [] seg_quarter = [] for i in range(len(gaps) - 1): time_segs.append(gp_time[gaps[i]:gaps[i + 1]]) flux_segs.append(gp_flux[gaps[i]:gaps[i + 1]]) mask_segs.append(gp_mask[gaps[i]:gaps[i + 1]]) seg_quarter.append(gp_quarter[gaps[i]]) mean_flux = [] approx_var = [] for i in range(len(gaps) - 1): m = mask_segs[i] mean_flux.append(np.mean(flux_segs[i][m])) approx_var.append(np.var(flux_segs[i] - sig.medfilt(flux_segs[i], 13))) # group segments by quarter quarters = np.unique(seg_quarter) nseg = len(time_segs) ngroup = len(quarters) seg_groups = [0] for j, q in enumerate(quarters): seg_groups.append(np.sum(np.array(seg_quarter) <= q)) seg_groups = np.array(seg_groups) # identify oscillation period to initialize GP ls_estimate = LombScargle(gp_time, gp_flux) xf, yf = ls_estimate.autopower(minimum_frequency=1 / 91.0, maximum_frequency=4.0) peak_freq = xf[np.argmax(yf)] peak_per = 1 / peak_freq peak_fap = ls_estimate.false_alarm_probability(yf.max()) if peak_fap < 1e-4: min_period = 0.5 * peak_per # set up lists to hold trend info trend_maps = [None] * ngroup # optimize the GP for each group of segments for j in range(ngroup): sg0 = seg_groups[j] sg1 = seg_groups[j + 1] nuse = sg1 - sg0 with pm.Model() as trend_model: log_amp = pm.Normal("log_amp", mu=np.log(np.std(gp_flux)), sd=5) log_per_off = pm.Normal("log_per_off", mu=np.log(peak_per - min_period), sd=5) log_Q0_off = pm.Normal("log_Q0_off", mu=0, sd=10) log_deltaQ = pm.Normal("log_deltaQ", mu=2, sd=10) mix = pm.Uniform("mix", lower=0, upper=1) P = pm.Deterministic("P", min_period + T.exp(log_per_off)) Q0 = pm.Deterministic("Q0", 1 / T.sqrt(2) + T.exp(log_Q0_off)) kernel = exo.gp.terms.RotationTerm(log_amp=log_amp, period=P, Q0=Q0, log_deltaQ=log_deltaQ, mix=mix) # exponential trend logtau = pm.Normal("logtau", mu=np.log(3) * np.ones(nuse), sd=5 * np.ones(nuse), shape=nuse) exp_amp = pm.Normal('exp_amp', mu=np.zeros(nuse), sd=np.std(gp_flux) * np.ones(nuse), shape=nuse) # nuissance parameters per segment flux0 = pm.Normal('flux0', mu=np.array(mean_flux[sg0:sg1]), sd=np.std(gp_flux) * np.ones(nuse), shape=nuse) logvar = pm.Normal('logvar', mu=np.log(approx_var[sg0:sg1]), sd=10 * np.ones(nuse), shape=nuse) # now set up the GP ramp = [None] * nuse gp = [None] * nuse obs = [None] * nuse for i in range(nuse): t = time_segs[sg0 + i] f = flux_segs[sg0 + i] m = mask_segs[sg0 + i] ramp[i] = pm.Deterministic( "ramp_{0}".format(i), 1 + exp_amp[i] * T.exp(-(t[m] - t[0]) / T.exp(logtau[i]))) gp[i] = exo.gp.GP(kernel, t[m], T.exp(logvar[i]) * T.ones(len(t[m]))) obs[i] = pm.Potential( 'obs_{0}'.format(i), gp[i].log_likelihood(f[m] - flux0[i] * ramp[i])) with trend_model: trend_maps[j] = exo.optimize(start=trend_model.test_point, vars=[flux0, logvar]) trend_maps[j] = exo.optimize( start=trend_maps[j], vars=[log_amp, mix, log_per_off, log_Q0_off, log_deltaQ]) trend_maps[j] = exo.optimize(start=trend_maps[j], vars=[logtau, exp_amp]) trend_maps[j] = exo.optimize(start=trend_maps[j]) # now compute the trend from the MAP parameter estimates # using gp.predict() inside the initial model was crashing jupyter # seriously, don't try to do it...it's not worth the memory issues # set up mean and variance vectors gp_mean = np.ones_like(gp_flux) gp_var = np.ones_like(gp_flux) for i in range(nseg): j = np.argmin(seg_groups <= i) - 1 g0 = gaps[i] g1 = gaps[i + 1] F0_ = trend_maps[j]["flux0"][i - seg_groups[j]] A_ = trend_maps[j]["exp_amp"][i - seg_groups[j]] tau_ = np.exp(trend_maps[j]["logtau"][i - seg_groups[j]]) t_ = gp_time[g0:g1] - gp_time[g0] gp_mean[g0:g1] = F0_ * (1 + A_ * np.exp(-t_ / tau_)) gp_var[g0:g1] = np.ones(g1 - g0) * np.exp( trend_maps[j]["logvar"][i - seg_groups[j]]) # increase variance for cadences in transit (yes, this is hacky, but it works) gp_var[~gp_mask] *= 1e12 # now evaluate the GP to get the final trend gp_trend = np.zeros_like(gp_flux) for j in range(ngroup): start = gaps[seg_groups[j]] end = gaps[seg_groups[j + 1]] m = gp_mask[start:end] with pm.Model() as trend_model: log_amp = trend_maps[j]["log_amp"] P = trend_maps[j]["P"] Q0 = trend_maps[j]["Q0"] log_deltaQ = trend_maps[j]["log_deltaQ"] mix = trend_maps[j]["mix"] kernel = exo.gp.terms.RotationTerm(log_amp=log_amp, period=P, Q0=Q0, log_deltaQ=log_deltaQ, mix=mix) gp = exo.gp.GP(kernel, gp_time[start:end], gp_var[start:end]) gp.log_likelihood(gp_flux[start:end] - gp_mean[start:end]) gp_trend[start:end] = gp.predict().eval() + gp_mean[start:end] # now remove the trend lc.flux = lc.flux / gp_trend # return results if return_trend: return lc, gp_trend else: return lc
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 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
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
x = (t.astype('datetime64[D]') - np.datetime64('1979-01-01')).astype(np.float) y = df['00955'].values y = y-np.nanmean(y) nt = len(xx) # nt = 1000 # freq = 1/np.linspace(2, nt, nt) # freq = np.arange(1, nt)/nt freq = np.fft.fftfreq(nt)[1:] ls = LombScargle(x, y) power = ls.power(freq) xx = (dfObs.index.values.astype('datetime64[D]') - np.datetime64('1979-01-01')).astype(np.float) p = ls.false_alarm_probability(power) # ym = np.zeros([len(freq), len(x)]) # yp = np.zeros([len(freq), len(x)]) # for k, f in enumerate(freq): # ym[k, :] = ls.model(x, f) # yp[k, :] = ym[k, :]*ls.power(f) folder = r'C:\Users\geofk\work\waterQuality\tempData\LS' ym = np.load(os.path.join(folder, siteNo)+'.npy') yp = np.load(os.path.join(folder, siteNo+'-full')+'.npy') ind = np.where(p < 0.2)[0] pd = np.unique(np.abs((1/freq[ind]).astype(int))) fig, axes = plt.subplots(2, 1, figsize=(10, 4)) axes[0].plot(t, y, '-*b', label='obs')
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 estimate_period_old(time, y, y_err, periodogram_kwargs=None, astropy_kwargs=None, wotan_kwargs=None, options=None): ''' Parameters ---------- time : TYPE DESCRIPTION. y : TYPE DESCRIPTION. y_err : TYPE DESCRIPTION. periodogram_kwargs : TYPE, optional DESCRIPTION. The default is None. astropy_kwargs : TYPE, optional DESCRIPTION. The default is None. wotan_kwargs : TYPE, optional DESCRIPTION. The default is None. options : None or dictionary, optional The default is None, which will evaluate to: options = {} options['show_plot'] = True #show a plot in the terminal? options['save_plot'] = True #save a plot? options['fname_plot'] = 'periodogram' #filenmae of the plot options['outdir'] = '.' #output directory for the plot If a dictionary is given, it may contain and overwrite all these keys. Returns ------- 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 'return_plot' not in options: options['return_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(time, np.ma.masked_invalid(y), low=astropy_kwargs['sigma'], high=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 = 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 * y_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'] or options['return_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) # 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[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, 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[1] plot_phase_folded_lightcurve(time, ff, period=1. / best_frequency, epoch=0, ax=ax) ax.set(ylim=[np.nanmin(ff), np.nanmax(ff)], ylabel='Data (clipped; phased)') ax = axes[2] plot_phase_folded_lightcurve(time, ff, 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(ff[ind_notnan], index=time[ind_notnan]), ax=ax, lags=np.linspace(start=1, stop=2000, num=100, dtype=int)) ax.set(xlabel='Lag', ylabel='Autocorrelation', title='') 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) if options['return_plot'] is True: return 1. / best_frequency, FAP, axes else: return 1. / best_frequency, FAP
def LS_estimator(x, y, fsamp=None, fap=0.1, return_levels=False, max_peaks=2): """ Generates a Lomb-Scargle periodogram and identifies significant frequencies from a data series Assumes that data are nearly evenly sampled Optimized for finding marginal periodic TTV signals in OMC data; may not perform well for other applications Parameters ---------- x : array-like 1D array of x data values; should be monotonically increasing y : array-like 1D array of corresponding y data values, len(x) fsamp: float nominal sampling frequency; if not provided it will be calculated from the data fap : float false alarm probability threshold to consider a frequency significant (default=0.1) Returns ------- xf : ndarray 1D array of frequencies yf : ndarray 1D array of corresponding response freqs : list signficant frequencies faps : list corresponding false alarm probabilities """ # get sampling frequency if fsamp is None: fsamp = 1 / np.min(x[1:] - x[:-1]) # Hann window to reduce ringing hann = sig.windows.hann(len(x)) hann /= np.sum(hann) # identify any egregious outliers out = np.abs(y - np.median(y)) / astropy.stats.mad_std(y) > 5.0 xt = x[~out] yt = y[~out] freqs = [] faps = [] loop = True while loop: lombscargle = LombScargle(xt, yt * hann[~out]) xf, yf = lombscargle.autopower(minimum_frequency=2.0/(xt.max()-xt.min()), \ maximum_frequency=0.25*fsamp, \ samples_per_peak=10) peak_freq = xf[np.argmax(yf)] peak_fap = lombscargle.false_alarm_probability(yf.max(), method='bootstrap') # output first iteration of LS periodogram if len(freqs) == 0: xf_out = xf.copy() yf_out = yf.copy() levels = lombscargle.false_alarm_level([0.1, 0.01, 0.001]) if peak_fap < fap: yt -= lombscargle.model(xt, peak_freq) * len(xt) freqs.append(peak_freq) faps.append(peak_fap) else: loop = False if len(freqs) >= max_peaks: loop = False if return_levels: return xf_out, yf_out, freqs, faps, levels else: return xf_out, yf_out, freqs, faps
def clean_rotationsignal_tess_singlesector_light_curve(time, mag, magisflux=False, dtr_dict=None, lsp_dict=None, maskorbitedge=True, lsp_options={ 'period_min': 0.1, 'period_max': 20 }, verbose=True): """ The goal of this function is to remove a stellar rotation signal from a single TESS light curve (ideally one without severe insturmental systematics) while preserving transits. "Cleaning" by default is taken to mean the sequence of mask_orbit_edge -> slide_clip -> detrend -> slide_clip. "Detrend" can mean any of the Wotan flatteners, Notch, or LOCOR. "slide_clip" means apply windowed sigma-clipping removal. Args: time, mag (np.ndarray): time and magnitude (or flux) vectors magisflux (bool): True if the "mag" vector is a flux already dtr_dict (optional dict): dictionary containing arguments passed to Wotan, Notch, or LOCOR. Relevant keys should include: 'dtr_method' (str): one of: ['best', 'notch', 'locor', 'pspline', 'biweight', 'none'] 'break_tolerance' (float): number of days past which a segment of light curve is considered a "new segment". 'window_length' (float): length of sliding window in days lsp_dict (optional dict): dictionary containing Lomb Scargle periodogram information, which is used in the "best" method for choosing between LOCOR or Notch detrending. If this is not passed, it'll be constructed here after the mask_orbit_edge -> slide_clip steps. lsp_options: contains keys period_min and period_max, used for the internal Lomb Scargle periodogram search. maskorbitedge (bool): whether to apply the initial "mask_orbit_edge" step. Probably would only want to be false if you had already done it elsewhere. Returns: search_time, search_flux, dtr_stages_dict (np.ndarrays and dict): light curve ready for TLS or BLS style periodograms; and a dictionary of the different processing stages (see comments for details of `dtr_stages_dict` contents). """ dtr_method = _get_detrending_method(dtr_dict) # # convert mag to flux and median-normalize # if magisflux: flux = mag else: f_x0 = 1e4 m_x0 = 10 flux = f_x0 * 10**(-0.4 * (mag - m_x0)) flux /= np.nanmedian(flux) # # ignore the times near the edges of orbits for TLS. # if maskorbitedge: _time, _flux = moe.mask_orbit_start_and_end( time, flux, raise_expectation_error=False, verbose=verbose) else: _time, _flux = time, flux # # sliding sigma clip asymmetric [20,3]*MAD, about median. use a 3-day # window, to give ~100 to 150 data points. mostly to avoid big flares. # clip_window = 3 clipped_flux = slide_clip(_time, _flux, window_length=clip_window, low=20, high=3, method='mad', center='median') sel0 = ~np.isnan(clipped_flux) # # for "best" or LOCOR detrending, you need to know the stellar rotation # period. so, if it hasn't already been run, run the LS periodogram here. # in `lsp_dict`, cache the LS peak period, amplitude, and FAP. # if (not isinstance(lsp_dict, dict)) and (dtr_method in ['locor', 'best']): period_min = lsp_options['period_min'] period_max = lsp_options['period_max'] ls = LombScargle(_time[sel0], clipped_flux[sel0], clipped_flux[sel0] * 1e-3) freq, power = ls.autopower(minimum_frequency=1 / period_max, maximum_frequency=1 / period_min) ls_fap = ls.false_alarm_probability(power.max()) best_freq = freq[np.argmax(power)] ls_period = 1 / best_freq theta = ls.model_parameters(best_freq) ls_amplitude = theta[1] lsp_dict = {} lsp_dict['ls_period'] = ls_period lsp_dict['ls_amplitude'] = np.abs(ls_amplitude) lsp_dict['ls_fap'] = ls_fap if not isinstance(dtr_dict, dict): dtr_dict = {} dtr_dict['method'] = dtr_method # # apply the detrending call based on the method given # dtr_method_used = dtr_method if dtr_method in ['pspline', 'biweight', 'none']: if 'break_tolerance' not in dtr_dict: dtr_dict['break_tolerance'] = None if 'window_length' not in dtr_dict: dtr_dict['window_length'] = None flat_flux, trend_flux = detrend_flux( _time[sel0], clipped_flux[sel0], break_tolerance=dtr_dict['break_tolerance'], method=dtr_dict['method'], cval=None, window_length=dtr_dict['window_length'], edge_cutoff=None) elif dtr_method == 'notch': flat_flux, trend_flux, notch = _run_notch(_time[sel0], clipped_flux[sel0], dtr_dict, verbose=verbose) elif dtr_method == 'locor': flat_flux, trend_flux, notch = _run_locor(_time[sel0], clipped_flux[sel0], dtr_dict, lsp_dict) elif dtr_method == 'best': # for stars with Prot < 1 day, use LOCOR. for stars with Prot > 1 day, # use Notch. (or pspline?). PERIOD_CUTOFF = 1.0 if lsp_dict['ls_period'] > PERIOD_CUTOFF: flat_flux, trend_flux, notch = _run_notch(_time[sel0], clipped_flux[sel0], dtr_dict, verbose=verbose) dtr_method_used += '-notch' elif (lsp_dict['ls_period'] < PERIOD_CUTOFF and lsp_dict['ls_period'] > 0): flat_flux, trend_flux, notch = _run_locor(_time[sel0], clipped_flux[sel0], dtr_dict, lsp_dict) dtr_method_used += '-locor' else: raise NotImplementedError(f"Got LS period {lsp_dict['ls_period']}") # # re-apply sliding sigma clip asymmetric [20,3]*MAD, about median, after # detrending. # clip_window = 3 clipped_flat_flux = slide_clip(_time[sel0], flat_flux, window_length=clip_window, low=20, high=3, method='mad', center='median') sel1 = ~np.isnan(clipped_flat_flux) search_flux = clipped_flat_flux[sel1] search_time = _time[sel0][sel1] dtr_stages_dict = { # non-nan indices from clipped_flux 'sel0': sel0, # non-nan indices from clipped_flat_flux 'sel1': sel1, # after initial window sigma_clip on flux, what is left? 'clipped_flux': clipped_flux, # after detrending, what is left? 'flat_flux': flat_flux, # after window sigma_clip on flat_flux, what is left? 'clipped_flat_flux': clipped_flat_flux, # what does the detrending algorithm give as the "trend"? 'trend_flux': trend_flux, 'trend_time': _time[sel0], # what method was used? if "best", gives "best-notch" or "best-locor" 'dtr_method_used': dtr_method_used, # times and fluxes used 'search_time': search_time, 'search_flux': search_flux } if isinstance(lsp_dict, dict): # in most cases, cache the LS period, amplitude, and FAP dtr_stages_dict['lsp_dict'] = lsp_dict return search_time, search_flux, dtr_stages_dict
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 add_increment_signals(self, period, start_amp=0.001, end_amp=2000, fap_threshold=0.001): """ Add sine signals to the time series object with a range of amplitudes. :param fap_threshold: :param period: :param start_amp: :param end_amp: :return: """ time = self.t - self.t[0] start = start_amp end = end_amp amp = (start_amp + end_amp) / 2 fap = 1 upperLimits = [] frequency = 1 / period # IF DEBUGGING, UNCOMMENT THE COMMENTED LINES OF CODE # counter = 0 while fap_threshold > fap or fap > fap_threshold + fap_threshold / 2: # counter = counter + 1 # print("Counter: ", counter, "Period: ", period, "Current amplitude being tested: ", amp, "FAP: ", fap) ls = LombScargle(self.t, add_signal(self.y, time, amp, period), self.err) fap = ls.false_alarm_probability(ls.power(frequency)) if fap_threshold > fap: # If FAP is too small, DECREASE the amplitude if round(start, 6) == end_amp or round(end, 6) == start_amp: upperLimits.append(period) upperLimits.append(amp) upperLimits.append(fap) break else: end = amp amp = abs(start + end) / 2 elif fap_threshold + fap_threshold / 2 < fap: # If FAP is too large, INCREASE the amplitude if round(start, 6) == end_amp or round(end, 6) == start_amp: upperLimits.append(period) upperLimits.append(amp) upperLimits.append(fap) break else: start = amp amp = abs(start + end) / 2 else: upperLimits.append(period) upperLimits.append(amp) upperLimits.append(fap) break return upperLimits