Esempio n. 1
0
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
Esempio n. 2
0
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
Esempio n. 3
0
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]
Esempio n. 4
0
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
    ]
Esempio n. 5
0
    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
Esempio n. 6
0
    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
Esempio n. 7
0
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
Esempio n. 8
0
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]
Esempio n. 9
0
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
    ]
Esempio n. 10
0
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]
Esempio n. 11
0
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]
Esempio n. 12
0
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
Esempio n. 13
0
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]
Esempio n. 14
0
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()
Esempio n. 15
0
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]
Esempio n. 16
0
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]
Esempio n. 17
0
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
Esempio n. 18
0
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
Esempio n. 19
0
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
Esempio n. 20
0
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
Esempio n. 22
0
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
Esempio n. 23
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
Esempio n. 24
0
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')
Esempio n. 25
0
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()
Esempio n. 26
0
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
Esempio n. 27
0
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
Esempio n. 28
0
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
Esempio n. 29
0
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
Esempio n. 30
0
    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