def make_psd(segment, navg=1):

    times = segment[:, 0]
    dt = times[1:] - times[:-1]
    dt = np.min(dt)

    counts = segment[:, 1] * dt

    tseg = times[-1] - times[0]
    nlc = len(times)
    nseg = int(nlc / navg)

    if navg == 1:
        ps = powerspectrum.PowerSpectrum(times, counts=counts, norm="rms")
        ps.freq = np.array(ps.freq)
        ps.ps = np.array(ps.ps) * ps.freq
        return ps.freq, ps.ps
    else:
        ps_all = []
        for n in xrange(navg):
            t_small = times[n * nseg:(n + 1) * nseg]
            c_small = counts[n * nseg:(n + 1) * nseg]
            ps = powerspectrum.PowerSpectrum(t_small,
                                             counts=c_small,
                                             norm="rms")
            ps.freq = np.array(ps.freq)
            ps.ps = np.array(ps.ps) * ps.freq
            ps_all.append(ps.ps)

        ps_all = np.average(np.array(ps_all), axis=0)

    return ps.freq, ps_all
def psd_features(seg, pcb):
    """
    Computer PSD-based features.
    seg: data slice of type [times, count rates, count rate error]^T
    pcb: frequency bands to use for power colours
    """

    times = seg[:, 0]
    dt = times[1:] - times[:-1]
    dt = np.min(dt)

    counts = seg[:, 1] * dt

    ps = powerspectrum.PowerSpectrum(times, counts=counts, norm="rms")
    ps.freq = np.array(ps.freq)
    ps.ps = np.array(ps.ps) * ps.freq

    bkg = np.mean(ps.ps[-100:])

    freq = np.array(ps.freq[1:])
    ps = ps.ps[1:]

    binfreq, binps, nsamples = logbin_periodogram(freq, ps)

    bkg = np.mean(binps[-30:])

    binps -= bkg

    fmax_ind = np.where(binfreq * binps == np.max(binfreq * binps))
    maxfreq = binfreq[fmax_ind[0]]

    ## find power in spectral bands for power-colours
    pa_min_freq = freq.searchsorted(pcb["pa_min"])
    pa_max_freq = freq.searchsorted(pcb["pa_max"])

    pb_min_freq = freq.searchsorted(pcb["pb_min"])
    pb_max_freq = freq.searchsorted(pcb["pb_max"])

    pc_min_freq = freq.searchsorted(pcb["pc_min"])
    pc_max_freq = freq.searchsorted(pcb["pc_max"])

    pd_min_freq = freq.searchsorted(pcb["pd_min"])
    pd_max_freq = freq.searchsorted(pcb["pd_max"])

    psd_a = np.sum(ps[pa_min_freq:pa_max_freq])
    psd_b = np.sum(ps[pb_min_freq:pb_max_freq])
    psd_c = np.sum(ps[pc_min_freq:pc_max_freq])
    psd_d = np.sum(ps[pd_min_freq:pd_max_freq])
    pc1 = np.sum(ps[pc_min_freq:pc_max_freq]) / np.sum(
        ps[pa_min_freq:pa_max_freq])
    pc2 = np.sum(ps[pb_min_freq:pb_max_freq]) / np.sum(
        ps[pd_min_freq:pd_max_freq])

    return maxfreq, psd_a, psd_b, psd_c, psd_d, pc1, pc2
def total_psd(seg, bins):
    times = seg[:, 0]
    dt = times[1:] - times[:-1]
    dt = np.min(dt)
    counts = seg[:, 1] * dt

    ps = powerspectrum.PowerSpectrum(times, counts=counts, norm="rms")
    binfreq, binps, binsamples = ps.rebin_log()
    bkg = np.mean(ps.ps[-100:])
    binps -= bkg

    return np.array(binfreq), np.array(binps)
def psd_pca(seg, n_components=12):
    """
    Extract a PCA representation of the light curves
    """

    freq_all, ps_all, maxfreq_all = [], [], []
    for s in seg:
        times = s[:, 0]
        dt = times[1:] - times[:-1]
        dt = np.min(dt)

        counts = s[:, 1] * dt

        ps = powerspectrum.PowerSpectrum(times, counts=counts, norm="rms")
        ps.freq = np.array(ps.freq)
        ps.ps = np.array(ps.ps) * ps.freq

        freq = np.array(ps.freq[1:])
        ps = ps.ps[1:]

        binfreq, binps, nsamples = logbin_periodogram(freq, ps)

        bkg = np.mean(binps[-50:])

        binps -= bkg

        fmax_ind = np.where(binfreq * binps == np.max(binfreq * binps))
        maxfreq = binfreq[fmax_ind[0]]
        freq_all.append(binfreq)
        ps_all.append(binps)
        maxfreq_all.append(maxfreq)

    freq_all = np.array(freq_all)
    ps_all = np.array(ps_all)
    maxfreq_all = np.hstack(maxfreq_all)

    ps_scaled = StandardScaler().fit_transform(ps_all)
    pc = PCA(n_components=n_components)
    ps_pca = pc.fit(ps_scaled).transform(ps_scaled)

    return ps_pca
Beispiel #5
0
    def simulate_periodogram(self, nsim=5000):
        """
        Simulate periodograms from posterior samples of the
        broadband noise model.

        This method uses the results of an MCMC run to
        pick samples from the posterior and use the function
        stored in self.lpost.func to create a power spectral form.

        In order to transform this into a model periodogram,
        it picks for each frequency from an exponential distribution
        with a shape parameter corresponding to the model power
        at that frequency.

        Parameters
        ----------

        nsim : int, optional, default 5000
            The number of periodograms to simulate. This number
            must be smaller than the number of samples generated
            during the MCMC run.

        Returns
        -------
        fps : array-like
            An array of shape (nsim, nfrequencies) with all
            simulated periodograms.

        """

        ## the function to use is stored in lpost:
        func = self.lpost.func

        ### number of simulations is either given by the user,
        ### or defined by the number of MCMCs run!
        nsim = min(nsim,len(self.mcall[0]))

        ### shuffle MCMC parameters
        theta = np.transpose(self.mcall)
        #print "theta: " + str(len(theta))
        np.random.shuffle(theta)

        fps = []
        percount = 1.0

        for x in range(nsim):

            ### extract parameter set
            ain = theta[x]
            ### compute model 'true' spectrum
            mpower = func(self.x, *ain)

            ### define distribution
            if self.m == 1:
                #print("m = 1")
                noise = np.random.exponential(size=len(self.x))
            else:
                #print("m = " + str(self.m))
                noise = np.random.chisquare(2*self.m, size=len(self.x))/(2.0*self.m)

            ### add random fluctuations
            mpower = mpower*noise

            ### save generated power spectrum in a PowerSpectrum object
            mps = powerspectrum.PowerSpectrum()
            mps.freq = self.x
            mps.ps = mpower
            mps.df = self.x[1] - self.x[0]
            mps.n = 2.0*len(self.x)
            mps.nphots = mpower[0]
            mps.m = self.m

            fps.append(mps)

        return np.array(fps)
Beispiel #6
0
    def mlest(self,
              func,
              ain,
              obs=True,
              noise=None,
              nmax=1,
              residuals=None,
              smooth=0,
              m=1,
              map=True):

        if smooth == 0:
            power = self.y
        elif smooth == 3:
            power = self.smooth3
        elif smooth == 5:
            power = self.smooth5
        elif smooth == 11:
            power = self.smooth11
        else:
            raise Exception(
                'No valid option for kwarg "smooth". Options are 0,3,5 and 11!'
            )

        if not residuals is None:
            power = residuals

        lenpower = float(len(power))

        ### renormalize normalization so it's in the right range
        varobs = np.sum(power)
        varmod = np.sum(func(self.x, *ain))
        renorm = varobs / varmod

        if len(ain) > 1:
            ain[1] = ain[1] + np.log(renorm)

        ### If last parameter is noise level, renormalize noise level
        ### to something useful:
        if not noise is None:
            #print("Renormalizing noise level ...")
            ### take the last 50 elements of the power spectrum
            noisepower = power[-51:-1]
            meannoise = np.log(np.mean(noisepower))
            ain[noise] = meannoise

        ### set function to be minimized: posterior density for periodograms:

        pstemp = powerspectrum.PowerSpectrum()
        pstemp.freq = self.x
        pstemp.ps = power
        pstemp.df = self.ps.df

        if m == 1:
            lposterior = posterior.PerPosterior(pstemp, func)
        elif m > 1:
            lposterior = posterior.StackPerPosterior(pstemp, func, m)

        else:
            raise Exception("Number of power spectra is not a valid number!")

        if not map:
            lpost = lposterior.loglikelihood
        else:
            lpost = lposterior

        fitparams = self._fitting(lpost, ain, neg=True, obs=obs)

        fitparams["model"] = str(func).split()[1]
        fitparams["mfit"] = func(self.x, *fitparams['popt'])

        ### calculate model power spectrum from optimal parameters
        #fitparams['mfit'] = func(self.x, *fitparams['popt'])
        ### figure-of-merit (SSE)
        fitparams['merit'] = np.sum(
            ((power - fitparams['mfit']) / fitparams['mfit'])**2.0)

        ### find highest outlier
        plrat = 2.0 * (self.y / fitparams['mfit'])
        #print(plrat)
        fitparams['sobs'] = np.sum(plrat)

        if nmax == 1:
            ### plmaxpow is the maximum of 2*data/model
            plmaxpow = max(plrat[1:])
            #print('plmaxpow: ' + str(plmaxpow))
            plmaxind = np.where(plrat == plmaxpow)[0]
            #print('plmaxind: ' + str(plmaxind))
            if len(plmaxind) > 1:
                plmaxind = plmaxind[0]
            elif len(plmaxind) == 0:
                plmaxind = -2
            plmaxfreq = self.x[plmaxind]

        else:

            plratsort = copy.copy(plrat)
            plratsort.sort()
            plmaxpow = plratsort[-nmax:]

            plmaxind, plmaxfreq = [], []
            for p in plmaxpow:
                try:
                    plmaxind_temp = np.where(plrat == p)[0]
                    if len(plmaxind_temp) > 1:
                        plmaxind_temp = plmaxind_temp[0]
                    elif len(plmaxind_temp) == 0:
                        plmaxind_temp = -2
                    plmaxind.append(plmaxind_temp)
                    plmaxfreq.append(self.x[plmaxind_temp])

                except TypeError:
                    plmaxind.append(None)
                    plmaxfreq.append(None)

        fitparams['maxpow'] = plmaxpow
        fitparams['maxind'] = plmaxind
        fitparams['maxfreq'] = plmaxfreq

        s3rat = 2.0 * (fitparams['smooth3'] / fitparams['mfit'])
        fitparams['s3max'] = max(s3rat[1:])
        try:
            s3maxind = np.where(s3rat == fitparams['s3max'])[0]
            if len(s3maxind) > 1:
                s3maxind = s3maxind[0]
            fitparams['s3maxfreq'] = self.x[s3maxind]
        except TypeError:
            fitparams["s3maxfreq"] = None
        s5rat = 2.0 * (fitparams['smooth5'] / fitparams['mfit'])
        fitparams['s5max'] = max(s5rat[1:])
        try:
            s5maxind = np.where(s5rat == fitparams['s5max'])[0]
            if len(s5maxind) > 1:
                s5maxind = s5maxind[0]
            fitparams['s5maxfreq'] = self.x[s5maxind]
        except TypeError:
            fitparams['s5maxfreq'] = None

        s11rat = 2.0 * (fitparams['smooth11'] / fitparams['mfit'])
        fitparams['s11max'] = max(s11rat[1:])
        try:
            s11maxind = np.where(s11rat == fitparams['s11max'])[0]
            if len(s11maxind) > 1:
                s11maxind = s11maxind[0]
            fitparams['s11maxfreq'] = self.x[s11maxind]
        except TypeError:
            fitparams['s11maxfreq'] = None

        ### compute binned periodograms and find highest outlier in those:
        df = (self.x[1] - self.x[0])
        ### first, compute the maximum binning that would even make sense
        bmax = int(self.x[-1] / (2.0 * (self.x[1] - self.x[0])))
        #print('bmax: ' + str(bmax))
        bins = [1, 3, 5, 7, 10, 15, 20, 30, 50, 70, 100, 200, 300, 500]

        bindict = {}

        for b in bins:
            if b < bmax:
                if b == 1:
                    binps = self.ps
                else:
                    binps = self.ps.rebinps(b * df)
                binpsname = "bin" + str(b)
                bindict[binpsname] = binps
                binpl = func(binps.freq, *fitparams["popt"])
                binratio = 2.0 * np.array(binps.ps) / binpl
                maxind = np.where(binratio[1:] == max(binratio[1:]))[0]
                if len(maxind) > 1:
                    maxind = maxind[0]
                elif len(maxind) == 0:
                    maxind = -2
                binmaxpow = "bmax" + str(b)
                bindict[binmaxpow] = max(binratio[1:])
                binmaxfreq = "bmaxfreq" + str(b)
                bindict[binmaxfreq] = binps.freq[maxind + 1]
                bindict['binpl' + str(b)] = binpl

        fitparams["bindict"] = bindict

        ## do a KS test comparing residuals to the exponential distribution
        plks = scipy.stats.kstest(plrat / 2.0, 'expon', N=len(plrat))
        fitparams['ksp'] = plks[1]

        if obs == True:
            print("The figure-of-merit function for this model is: " +
                  str(fitparams['merit']) + " and the fit for " +
                  str(fitparams['dof']) + " dof is " +
                  str(fitparams['merit'] / fitparams['dof']) + ".")

            print("Fitting statistics: ")
            print(" -- number of frequencies: " + str(len(self.x)))
            print(" -- Deviance [-2 log L] D = " + str(fitparams['deviance']))
            print(" -- Highest data/model outlier 2I/S = " +
                  str(fitparams['maxpow']))
            print("    at frequency f_max = " + str(fitparams['maxfreq']))

            print(
                " -- Highest smoothed data/model outlier for smoothing factor [3] 2I/S = "
                + str(fitparams['s3max']))
            print("    at frequency f_max = " + str(fitparams['s3maxfreq']))
            print(
                " -- Highest smoothed data/model outlier for smoothing factor [5] 2I/S = "
                + str(fitparams['s5max']))
            print("    at frequency f_max = " + str(fitparams['s5maxfreq']))
            print(
                " -- Highest smoothed data/model outlier for smoothing factor [11] 2I/S = "
                + str(fitparams['s11max']))
            print("    at frequency f_max = " + str(fitparams['s11maxfreq']))

            print(" -- Summed Residuals S = " + str(fitparams['sobs']))
            print(" -- Expected S ~ " + str(fitparams['sexp']) + " +- " +
                  str(fitparams['ssd']))
            print(" -- KS test p-value (use with caution!) p = " +
                  str(fitparams['ksp']))
            print(" -- merit function (SSE) M = " + str(fitparams['merit']))

        return fitparams
Beispiel #7
0
    def __init__(self,
                 bstart,
                 blength,
                 energies=None,
                 photons=None,
                 events=None,
                 filename=None,
                 instrument="gbm",
                 fnyquist=4096.0,
                 norm='leahy',
                 fluence=None,
                 epeak=None,
                 ttrig=None,
                 addfrac=0.2):

        ### which instrument was used to record this data
        ### note: this makes a difference in terms of file formats
        ### and general data structure
        self.instrument = instrument

        if ":" in str(bstart):
            self.bst = self.convert_time(bstart)
        else:
            self.bst = bstart

        self.blen = blength + 2. * addfrac * blength

        start = self.bst - addfrac * blength
        length = (1. + 2. * addfrac) * self.blen
        end = start + length

        ### assume burst length is in seconds
        self.fluence = fluence
        self.epeak = epeak
        self.ttrig = ttrig

        ### data is in form of Photon objects such that time/energy filtering
        ### becomes easy
        if photons is None and filename:
            self.read_data(filename)

        elif not photons is None:
            self.photons = photons

        else:
            raise Exception(
                "Data missing! You must specify either a photon "
                "object or a file name from which to read the data!")

        if not events is None:
            self.energies = events
        startind = photons.searchsorted(start)
        endind = photons.searchsorted(end)
        self.photons = self.photons[startind:endind]
        self.energies = self.energies[startind:endind]

        ### filter for energy selection, if this is specified
        #if energies:
        #    gt.Data.filterenergy(self, energies[0], energies[1])
        if energies:
            self.photons = np.array([
                s for s, e in zip(self.photons, self.energies)
                if energies[0] <= e <= energies[1]
            ])
            self.energies = np.array([
                e for s, e in zip(self.photons, self.energies)
                if energies[0] <= e <= energies[1]
            ])

        #### filter for burst times
        #gt.Data.filterburst([self.bst-0.1*self.blen, self.bend+0.1*self.blen])

        ### make a light curve
        self.time = self.photons
        #print("length time: " + str(len(self.time)))
        #print("tseg: " + str(self.time[-1] - self.time[0]))

        #self.time = np.array([s.time for s in self.photons])
        self.lc = lightcurve.Lightcurve(self.time,
                                        timestep=0.5 / fnyquist,
                                        tseg=self.blen,
                                        tstart=self.bst)

        #print("length lc: " + str(len(self.lc.time)))

        ### make a periodogram
        self.ps = powerspectrum.PowerSpectrum(self.lc, norm=norm)

        return