Esempio n. 1
0
    def calc_min_smearing(self, verbose=False):
        """Calculate minimum (optimal) smearing.
            
            Inputs:
                verbose: Print information to screen (Default = False)
        """
        half_dDMmin = 0.5 * ALLOW_DMSTEPS[0]
        self.min_chan_smear = psr_utils.dm_smear(self.loDM + half_dDMmin, self.obs.chanwidth, self.obs.fctr)
        self.min_bw_smear = psr_utils.dm_smear(half_dDMmin, self.obs.BW, self.obs.fctr)
        self.min_total_smear = np.sqrt(2 * self.obs.dt ** 2.0 + self.min_chan_smear ** 2.0 + self.min_bw_smear ** 2.0)
        self.best_resolution = max([self.req_resolution, self.min_chan_smear, self.min_bw_smear, self.obs.dt])
        self.resolution = self.best_resolution

        if verbose:
            print
            print "Minimum total smearing     : %.3g s" % self.min_total_smear
            print "--------------------------------------------"
            print "Minimum channel smearing   : %.3g s" % self.min_chan_smear
            print "Minimum smearing across BW : %.3g s" % self.min_bw_smear
            print "Minimum sample time        : %.3g s" % self.obs.dt
            print
            print "Setting the new 'best' resolution to : %.3g s" % self.best_resolution

        # See if the data is too high time resolution for our needs
        if (FF * self.min_chan_smear > self.obs.dt) or (self.resolution > self.obs.dt):
            if self.resolution > FF * self.min_chan_smear:
                if verbose:
                    print "   Note: resolution > dt (i.e. data is higher resolution than needed)"
                self.resolution = self.resolution
            else:
                if verbose:
                    print "   Note: min chan smearing > dt (i.e. data is higher resolution than needed)"
                self.resolution = FF * self.min_chan_smear
Esempio n. 2
0
    def _compute_rating(self, cand):
        """Return a rating for the candidate. The rating value is the
            ratio of the width of the narrowest gaussian component 
            to the DM smearing.
        
            Input:
                cand: A Candidate object to rate.

            Output:
                value: The rating value.
        """
        pfd = cand.get_from_cache('pfd')
        mgauss = cand.get_from_cache('multigaussfit')
        ncomp = len(mgauss.components)
        if not ncomp:
            raise utils.RatingError("Bad number of components for single " \
                                    "gaussian fit (%d)" % ncomp)
        
        # Get the period
        period = pfd.bary_p1 or pfd.topo_p1
        if period is None:
            raise utils.RatingError("Bad period in PFD file (%f)" % period)
        f_ctr = (pfd.hifreq + pfd.lofreq)/2.0
        dm_smear = psr_utils.dm_smear(pfd.bestdm, pfd.chan_wid, f_ctr)
        width_phs = np.sqrt(dm_smear**2 + pfd.dt**2)/period

        minfwhm = min([comp.fwhm for comp in mgauss.components])
        return width_phs/minfwhm
Esempio n. 3
0
    def _compute_rating(self, cand):
        """Return a rating for the candidate. The rating value is the
            ratio of the width of the narrowest gaussian component 
            to the DM smearing.
        
            Input:
                cand: A Candidate object to rate.

            Output:
                value: The rating value.
        """
        pfd = cand.pfd
        mgauss = cand.multigaussfit
        ncomp = len(mgauss.components)
        if not ncomp:
            raise utils.RatingError("Bad number of components for single " \
                                    "gaussian fit (%d)" % ncomp)

        # Get the period
        period = pfd.bary_p1 or pfd.topo_p1
        if period is None:
            raise utils.RatingError("Bad period in PFD file (%f)" % period)
        f_ctr = (pfd.hifreq + pfd.lofreq) / 2.0
        dm_smear = psr_utils.dm_smear(pfd.bestdm, pfd.chan_wid, f_ctr)
        width_phs = np.sqrt(dm_smear**2 + pfd.dt**2) / period

        minfwhm = min([comp.fwhm for comp in mgauss.components])
        return width_phs / minfwhm
Esempio n. 4
0
def subband_smear(DM, subDM, subBW, fctr):
    """
    subband_smear(DM, subDM, subBW, fctr):
        Return the smearing in ms caused by subbanding at DM='DM' given
        subbands of bandwidth 'subBW' (MHz) at DM='subDM'.  All values
        are computed at the frequency fctr in MHz.
    """
    return 1000.0 * pu.dm_smear(num.fabs(DM-subDM), subBW, fctr)
Esempio n. 5
0
    def fit_powers(self, freqlim=None, use_errors=True, **kwargs):
        # Use iminuit to fit power-law + DC to powers
        import iminuit
        if freqlim is None:
            freqlim = np.inf
            if self.inf.DM > 0:
                tdm = psr_utils.dm_smear(self.inf.DM, self.inf.BW,
                                         self.inf.lofreq + 0.5 * self.inf.BW)
                freqlim = 1.0 / tdm
                print "Dispersion smearing time: %.2f ms" % (1000.0 * tdm)
            freqlim = min(10.0, freqlim)
            print "Only fitting using frequencies up to %.2f Hz" % freqlim
        iuse = (self.freqs < freqlim)
        iuse[0] = 0  # Always ignore zeroth element

        if use_errors:
            # Compute power errors
            self.estimate_power_errors()

        # Define function to minimize
        def to_minimize(amp, index, dc):
            model = power_law(self.freqs[iuse], amp, index, dc)
            diff = model - self.powers[iuse]
            #plt.figure()
            #plt.plot(self.freqs[1:], self.powers[1:], 'r-', alpha=0.5)
            #plt.plot(self.freqs[iuse], self.powers[iuse], 'k-', alpha=0.5)
            #plt.plot(self.freqs[iuse], model, 'k--', lw=2)
            #plt.xscale('log')
            #plt.yscale('log')
            #plt.xlabel("Freq (Hz)")
            #plt.ylabel("Raw Power")
            #plt.show()
            if use_errors:
                diff /= self.errs[iuse]
            return np.sum(diff**2)

        white = self.estimate_white_power_level(1000)
        kwargs.setdefault('amp', 1e14)
        kwargs.setdefault('error_amp', 1e12)
        kwargs.setdefault('limit_amp', (0, 1e20))
        kwargs.setdefault('index', -1.5)
        kwargs.setdefault('error_index', .1)
        kwargs.setdefault('limit_index', (-10.0, 0.0))
        kwargs.setdefault('dc', white)
        kwargs.setdefault('error_dc', white * 0.1)
        #kwargs.setdefault('limit_dc', (white*0.01, np.max(self.powers[1:])))
        kwargs.setdefault('fix_dc', True)
        m = iminuit.Minuit(to_minimize,
                           frontend=iminuit.ConsoleFrontend,
                           print_level=0,
                           **kwargs)
        # Minimize
        m.migrad()
        return m.values
Esempio n. 6
0
    def calc_min_smearing(self, verbose=False):
        """Calculate minimum (optimal) smearing.
            
            Inputs:
                verbose: Print information to screen (Default = False)
        """
        half_dDMmin = 0.5 * ALLOW_DMSTEPS[0]
        self.min_chan_smear = psr_utils.dm_smear(self.loDM+half_dDMmin, \
                                            self.obs.chanwidth, self.obs.fctr)
        self.min_bw_smear = psr_utils.dm_smear(half_dDMmin, self.obs.BW,
                                               self.obs.fctr)
        self.min_total_smear = np.sqrt(2*self.obs.dt**2.0 + \
                                  self.min_chan_smear**2.0 + \
                                  self.min_bw_smear**2.0)
        self.best_resolution = max([self.req_resolution, self.min_chan_smear, \
                                    self.min_bw_smear, self.obs.dt])
        self.resolution = self.best_resolution

        if verbose:
            print
            print "Minimum total smearing     : %.3g s" % self.min_total_smear
            print "--------------------------------------------"
            print "Minimum channel smearing   : %.3g s" % self.min_chan_smear
            print "Minimum smearing across BW : %.3g s" % self.min_bw_smear
            print "Minimum sample time        : %.3g s" % self.obs.dt
            print
            print "Setting the new 'best' resolution to : %.3g s" % self.best_resolution

        # See if the data is too high time resolution for our needs
        if (FF*self.min_chan_smear > self.obs.dt) or \
                (self.resolution > self.obs.dt):
            if self.resolution > FF * self.min_chan_smear:
                if verbose:
                    print "   Note: resolution > dt (i.e. data is higher resolution than needed)"
                self.resolution = self.resolution
            else:
                if verbose:
                    print "   Note: min chan smearing > dt (i.e. data is higher resolution than needed)"
                self.resolution = FF * self.min_chan_smear
Esempio n. 7
0
    def _compute_rating(self, cand):
        """Return a rating for the candidate. The rating value encodes 
            how close the candidate's period and DM are to that of a
            known pulsar.

            Input:
                cand: A Candidate object to rate.

            Output:
                value: The rating value.
        """
        info = cand.get_from_cache('info')
        candp = info['bary_period']
        canddm = info['dm']
        ra = info['raj_deg']
        dec = info['decj_deg']
        pfd = cand.get_from_cache('pfd')

        diff_ra = np.abs(self.known_ras - ra)
        diff_dec = np.abs(self.known_decs - dec)

        ii_nearby = (diff_ra < 0.2) & (diff_dec < 0.2)
        knownps = self.known_periods[ii_nearby]
        knowndms = self.known_dms[ii_nearby]

        dp_smear_phase = np.inf * np.ones(knownps.size)
        ddms = np.abs(canddm - knowndms)
        bw = pfd.hifreq - pfd.lofreq
        fctr = 0.5 * (pfd.hifreq + pfd.lofreq)
        ddm_smear_phase = psr_utils.dm_smear(ddms, bw, fctr) / knownps

        if knownps.size:
            for b in range(1, M):
                dp_smear_sec = np.abs(candp * b - knownps) * pfd.T
                dp_smear_phase = np.min(np.vstack(
                    (dp_smear_sec / knownps, dp_smear_phase)),
                                        axis=0)
            for rat in self.ratios:
                dp_smear_sec = np.abs(candp * b - knownps) * pfd.T
                dp_smear_phase = np.min(np.vstack(
                    (dp_smear_sec / knownps, dp_smear_phase)),
                                        axis=0)
            smear_phase = np.min(
                np.sqrt(dp_smear_phase**2 + ddm_smear_phase**2))
            #if smear_phase > 1:
            #    print pfd.pfd_filename, smear_phase
            smear_phase = np.clip(smear_phase, 0, 10)
        else:
            # No nearby known pulsars
            smear_phase = 10
        return smear_phase
Esempio n. 8
0
def filter_on_effective_time_resolution(candidates, metadata, n_bins):
    '''
    Reject pulsar candidates with fewer than n_bins bins across their profile.
    '''
    out_cand_list = []
    channel_bandwidth = metadata.channel_bandwidth
    central_frequency = ((metadata.n_channels/2) - 0.5) * channel_bandwidth +\
        metadata.low_channel_central_freq
    for c in candidates:
        intra_channel_smearing = psr_utils.dm_smear(c.DM, channel_bandwidth,
            central_frequency)
        if c.p / intra_channel_smearing > n_bins:
            out_cand_list.append(c)
    print 'Filtering on effective time resolution:' 
    print '  Removed %d out %d candidates.' % (
        len(candidates) - len(out_cand_list), len(candidates))
    return out_cand_list 
Esempio n. 9
0
    def _compute_rating(self, cand):
        """Return a rating for the candidate. The rating value encodes 
            how close the candidate's period and DM are to that of a
            known pulsar.

            Input:
                cand: A Candidate object to rate.

            Output:
                value: The rating value.
        """
        info = cand.get_from_cache('info')
        candp = info['bary_period']
        canddm = info['dm']
        ra = info['raj_deg']
        dec = info['decj_deg']
        pfd = cand.get_from_cache('pfd')

        diff_ra = np.abs(self.known_ras - ra)
        diff_dec = np.abs(self.known_decs - dec)

        ii_nearby = (diff_ra < 0.2) & (diff_dec < 0.2)
        knownps = self.known_periods[ii_nearby]
        knowndms = self.known_dms[ii_nearby]

        dp_smear_phase = np.inf*np.ones(knownps.size)
        ddms = np.abs(canddm-knowndms)
        bw = pfd.hifreq-pfd.lofreq
        fctr = 0.5*(pfd.hifreq+pfd.lofreq)
        ddm_smear_phase = psr_utils.dm_smear(ddms, bw, fctr)/knownps

        if knownps.size:
            for b in range(1, M):
                dp_smear_sec = np.abs(candp*b-knownps)*pfd.T
                dp_smear_phase = np.min(np.vstack((dp_smear_sec/knownps, dp_smear_phase)), axis=0)
            for rat in self.ratios:
                dp_smear_sec = np.abs(candp*b-knownps)*pfd.T
                dp_smear_phase = np.min(np.vstack((dp_smear_sec/knownps, dp_smear_phase)), axis=0)
            smear_phase = np.min(np.sqrt(dp_smear_phase**2+ddm_smear_phase**2))
            #if smear_phase > 1:
            #    print pfd.pfd_filename, smear_phase
            smear_phase = np.clip(smear_phase, 0, 10)
        else:
            # No nearby known pulsars
            smear_phase = 10
        return smear_phase
Esempio n. 10
0
    def __init__(self, ddplan, downsamp, loDM, dDM, numDMs=0, numsub=0, smearfact=2.0):
        """DDstep object constructor.

            Inputs:
                ddplan: DDplan object this DDstep is part of.
                downsamp: Downsampling factor.
                loDM: Low DM edge of this DDstep (pc cm-3)
                dDM: DM step size to use (pc cm-3)
                numDMs: Number of DMs. If numDMs=0 compute numDMs
                        based on DM range and spacing.
                        (Default: 0)
                numsub: Number of subbands to use. (Default: no subbanding).
                smearfact: Allowable smearing in a single channel, relative
                        to other smearing contributions (Default: 2.0)
        """
        self.ddplan = ddplan
        self.downsamp = downsamp
        self.loDM = loDM
        self.dDM = dDM
        self.numsub = numsub
        self.BW_smearing = psr_utils.dm_smear(dDM * 0.5, self.ddplan.obs.BW, self.ddplan.obs.fctr)
        self.numprepsub = 0
        if numsub:
            # Calculate the maximum subband smearing we can handle
            DMs_per_prepsub = 2
            while True:
                next_dsubDM = (DMs_per_prepsub + 2) * dDM
                next_ss = psr_utils.dm_smear(next_dsubDM * 0.5, self.ddplan.obs.BW / numsub, self.ddplan.obs.fctr)
                # The 0.8 is a small fudge factor to make sure that the subband
                # smearing is always the smallest contribution
                if next_ss > 0.8 * min(self.BW_smearing, self.ddplan.obs.dt * self.downsamp):
                    self.dsubDM = DMs_per_prepsub * dDM
                    self.DMs_per_prepsub = DMs_per_prepsub
                    self.sub_smearing = psr_utils.dm_smear(
                        self.dsubDM * 0.5, self.ddplan.obs.BW / self.numsub, self.ddplan.obs.fctr
                    )
                    break
                DMs_per_prepsub += 2
        else:
            self.dsubDM = dDM
            self.sub_smearing = 0.0

        # Calculate the nominal DM to move to the next step
        cross_DM = self.DM_for_smearfact(smearfact)
        if cross_DM > self.ddplan.hiDM:
            cross_DM = self.ddplan.hiDM
        if numDMs == 0:
            self.numDMs = int(np.ceil((cross_DM - self.loDM) / self.dDM))
            if numsub:
                self.numprepsub = int(np.ceil(self.numDMs * self.dDM / self.dsubDM))
                self.numDMs = self.numprepsub * DMs_per_prepsub
        else:
            self.numDMs = numDMs
        self.hiDM = loDM + self.numDMs * dDM
        self.DMs = np.arange(self.numDMs, dtype="d") * self.dDM + self.loDM

        # Calculate a few more smearing values
        self.chan_smear = psr_utils.dm_smear(self.DMs, self.ddplan.obs.chanwidth, self.ddplan.obs.fctr)
        self.tot_smear = np.sqrt(
            (self.ddplan.obs.dt) ** 2.0
            + (self.ddplan.obs.dt * self.downsamp) ** 2.0
            + self.BW_smearing ** 2.0
            + self.sub_smearing ** 2.0
            + self.chan_smear ** 2.0
        )
Esempio n. 11
0
                counterpart = j
                break
#      print f1,fwant
        if counterpart == False:
            print "Didn't find counterpart frequency for %f" % f0
            sub.set_weight(i, 0.0)
            continue
#    else:
#      print counterpart,f1
#    print f0, f1
#    sys.exit()
#    print f0,f1

        p = sub.get_folding_period()

        smear = (psr_utils.dm_smear(dm, chbw, f0) +
                 psr_utils.dm_smear(dm, chbw, f1)) / p

        delay = (psr_utils.delay_from_DM(dm, f0) -
                 psr_utils.delay_from_DM(dm, f1)) / p

        delay -= int(delay)
        if delay < -0.5: delay += 1.0
        if delay > 0.5: delay -= 1.0

        #print i, smear, delay

        for pol in range(2):
            if pol == 0:
                correction = pol0correction / 2.0
            else:
Esempio n. 12
0
    def plot(self, fn=None):
        """Generate a plot for this dedispersion plan.

            Inputs:
                fn: Filename to save plot as. If None, show plot interactively.
                    (Default: Show plot interactively.)
        """
        fig = plt.figure(figsize=(11, 8.5))
        ax = plt.axes()
        stepDMs = []
        # Plot each dedispersion step
        for ii, (step, wf) in enumerate(zip(self.DDsteps, self.work_fracts)):
            stepDMs.append(step.DMs)
            DMspan = np.ptp(step.DMs)
            loDM = step.DMs.min() + DMspan * 0.02
            hiDM = step.DMs.max() - DMspan * 0.02
            midDM = step.DMs.min() + DMspan * 0.5
            # Sample time
            plt.plot(step.DMs, np.zeros(step.numDMs)+step.ddplan.obs.dt*step.downsamp, \
                        '#33CC33', label=((ii and "_nolegend_") or "Sample Time (ms)"))
            # DM stepsize smearing
            plt.plot(step.DMs, np.zeros(step.numDMs)+step.BW_smearing, 'r', \
                        label=((ii and "_nolegend_") or "DM Stepsize Smearing"))
            if self.numsub:
                plt.plot(step.DMs, np.zeros(step.numDMs)+step.sub_smearing, '#993399', \
                        label=((ii and "_nolegend_") or "Subband Stepsize Smearing (# passes)"))
            plt.plot(step.DMs, step.tot_smear, 'k', \
                        label=((ii and "_nolegend_") or "Total Smearing"))

            # plot text
            plt.text(midDM, 1.1*np.median(step.tot_smear), \
                        "%d (%.1f%%)" % (step.numDMs, 100.0*wf), \
                        rotation='vertical', size='small', \
                        ha='center', va='bottom')
            plt.text(loDM, 0.85*step.ddplan.obs.dt*step.downsamp, \
                        "%g" % (1000*step.ddplan.obs.dt*step.downsamp), \
                        size='small', color='#33CC33', ha='left')
            plt.text(hiDM, 0.85*step.BW_smearing, \
                        "%g" % step.dDM, size='small', color='r', ha='right')
            if self.numsub:
                plt.text(midDM, 0.85*step.sub_smearing, \
                            "%g (%d)" % (step.dsubDM, step.numprepsub), \
                            size='small', color='#993399', ha='center')
        allDMs = np.concatenate(stepDMs)

        chan_smear = psr_utils.dm_smear(allDMs, self.obs.chanwidth,
                                        self.obs.fctr)
        bw_smear = psr_utils.dm_smear(ALLOW_DMSTEPS[0], self.obs.BW,
                                      self.obs.fctr)
        tot_smear = np.sqrt(2*self.obs.dt**2.0 + \
                                  chan_smear**2.0 + \
                                  bw_smear**2.0)
        plt.plot(allDMs, tot_smear, '#FF9933', label="Optimal Smearing")
        plt.plot(allDMs, chan_smear, 'b', label="Channel Smearing")
        # Add text above plot
        settings = r"$f_{ctr}$ = %g MHz" % self.obs.fctr
        if self.obs.dt < 1e-4:
            settings += r",  dt = %g $\mu$s" % (self.obs.dt * 1e6)
        else:
            settings += r",  dt = %g ms" % (self.obs.dt * 1000)
        settings += r",  BW = %g MHz" % self.obs.BW
        settings += r",  N$_{chan}$ = %d" % self.obs.numchan

        if self.numsub:
            settings += r",  N$_{sub}$ = %d" % self.numsub
        if self.obs.numsamp:
            settings += r",  N$_{samp}$ = %d" % self.obs.numsamp
        plt.figtext(0.05, 0.005, settings, \
                            ha='left', size='small')

        plt.yscale('log')
        plt.xlabel(r"Dispersion Measure (pc cm$^{-3}$)")
        plt.ylabel(r"Smearing (s)")
        plt.xlim(allDMs.min(), allDMs.max())
        plt.ylim(0.3 * tot_smear.min(), 2.5 * tot_smear.max())
        leg = plt.legend(loc='lower right')
        plt.setp(leg.texts, size='small')
        plt.setp(leg.legendHandles, linewidth=2)
        if fn is not None:
            # Save figure to file
            plt.savefig(fn, orientation='landscape', papertype='letter')
        else:
            # Show figure interactively
            def keypress(event):
                if event.key in ['q', 'Q']:
                    plt.close()

            fig.canvas.mpl_connect('key_press_event', keypress)
            plt.show()
Esempio n. 13
0
    def plot(self, fn=None):
        """Generate a plot for this dedispersion plan.

            Inputs:
                fn: Filename to save plot as. If None, show plot interactively.
                    (Default: Show plot interactively.)
        """
        fig = plt.figure(figsize=(11, 8.5))
        ax = plt.axes()
        stepDMs = []
        # Plot each dedispersion step
        for ii, (step, wf) in enumerate(zip(self.DDsteps, self.work_fracts)):
            stepDMs.append(step.DMs)
            DMspan = np.ptp(step.DMs)
            loDM = step.DMs.min() + DMspan * 0.02
            hiDM = step.DMs.max() - DMspan * 0.02
            midDM = step.DMs.min() + DMspan * 0.5
            # Sample time
            plt.plot(
                step.DMs,
                np.zeros(step.numDMs) + step.ddplan.obs.dt * step.downsamp,
                "#33CC33",
                label=((ii and "_nolegend_") or "Sample Time (ms)"),
            )
            # DM stepsize smearing
            plt.plot(
                step.DMs,
                np.zeros(step.numDMs) + step.BW_smearing,
                "r",
                label=((ii and "_nolegend_") or "DM Stepsize Smearing"),
            )
            if self.numsub:
                plt.plot(
                    step.DMs,
                    np.zeros(step.numDMs) + step.sub_smearing,
                    "#993399",
                    label=((ii and "_nolegend_") or "Subband Stepsize Smearing (# passes)"),
                )
            plt.plot(step.DMs, step.tot_smear, "k", label=((ii and "_nolegend_") or "Total Smearing"))

            # plot text
            plt.text(
                midDM,
                1.1 * np.median(step.tot_smear),
                "%d (%.1f%%)" % (step.numDMs, 100.0 * wf),
                rotation="vertical",
                size="small",
                ha="center",
                va="bottom",
            )
            plt.text(
                loDM,
                0.85 * step.ddplan.obs.dt * step.downsamp,
                "%g" % (1000 * step.ddplan.obs.dt * step.downsamp),
                size="small",
                color="#33CC33",
                ha="left",
            )
            plt.text(hiDM, 0.85 * step.BW_smearing, "%g" % step.dDM, size="small", color="r", ha="right")
            if self.numsub:
                plt.text(
                    midDM,
                    0.85 * step.sub_smearing,
                    "%g (%d)" % (step.dsubDM, step.numprepsub),
                    size="small",
                    color="#993399",
                    ha="center",
                )
        allDMs = np.concatenate(stepDMs)

        chan_smear = psr_utils.dm_smear(allDMs, self.obs.chanwidth, self.obs.fctr)
        bw_smear = psr_utils.dm_smear(ALLOW_DMSTEPS[0], self.obs.BW, self.obs.fctr)
        tot_smear = np.sqrt(2 * self.obs.dt ** 2.0 + chan_smear ** 2.0 + bw_smear ** 2.0)
        plt.plot(allDMs, tot_smear, "#FF9933", label="Optimal Smearing")
        plt.plot(allDMs, chan_smear, "b", label="Channel Smearing")
        # Add text above plot
        settings = r"$f_{ctr}$ = %g MHz" % self.obs.fctr
        if self.obs.dt < 1e-4:
            settings += r",  dt = %g $\mu$s" % (self.obs.dt * 1e6)
        else:
            settings += r",  dt = %g ms" % (self.obs.dt * 1000)
        settings += r",  BW = %g MHz" % self.obs.BW
        settings += r",  N$_{chan}$ = %d" % self.obs.numchan

        if self.numsub:
            settings += r",  N$_{sub}$ = %d" % self.numsub
        if self.obs.numsamp:
            settings += r",  N$_{samp}$ = %d" % self.obs.numsamp
        plt.figtext(0.05, 0.005, settings, ha="left", size="small")

        plt.yscale("log")
        plt.xlabel(r"Dispersion Measure (pc cm$^{-3}$)")
        plt.ylabel(r"Smearing (s)")
        plt.xlim(allDMs.min(), allDMs.max())
        plt.ylim(0.3 * tot_smear.min(), 2.5 * tot_smear.max())
        leg = plt.legend(loc="lower right")
        plt.setp(leg.texts, size="small")
        plt.setp(leg.legendHandles, linewidth=2)
        if fn is not None:
            # Save figure to file
            plt.savefig(fn, orientation="landscape", papertype="letter")
        else:
            # Show figure interactively
            def keypress(event):
                if event.key in ["q", "Q"]:
                    plt.close()

            fig.canvas.mpl_connect("key_press_event", keypress)
            plt.show()
Esempio n. 14
0
def Multi_Gaussian_Ratings(pfd, debug=False):
    """
    Calculate ratings that depend on a fit of multiple Gaussian profile
    components.

    Parameters
    ----------
    pfd : class
        An instance of the prepfold.pfd class
    debug : boolean
        If True, plot the profile and best-fit Gaussians

    Returns
    -------
    names : list
        A list of ratings names
    ratings : list
        A list of ratings values
    """
    # The ratings names
    name1 = "Number_of_Gaussians"
    name2 = "Pulse_Width_Rating"

    # De-disperse the profile at the best DM
    pfd.dedisperse(DM=pfd.bestdm, doppler=1)
    # Internally rotate the data cube so that is aligned with best fold values
    pfd.adjust_period()
    # Get the best fold profile
    profile = N.sum(N.sum(pfd.profs, axis=1), axis=0)
    # Get the period from bestprof, if it exists
    if hasattr(pfd.bestprof, "p0"):
        P0  = pfd.bestprof.p0
    # Otherwise use the barycentric or topocentric folding periods
    else:
        if   pfd.bary_p1 != 0.0: P0 = pfd.bary_p1
        elif pfd.topo_p1 != 0.0: P0 = pfd.topo_p1
    # Get the center observing frequency
    f_ctr   = (pfd.hifreq + pfd.lofreq)/2
    # Fit up to MAX_GAUSSIANS Gaussians to the profile
    gaussian_params, red_chi2, ngaussians = \
        PT.fit_gaussians_presto(profile, pfd.avgprof, N.sqrt(pfd.varprof),
                             MAX_GAUSSIANS, F_STAT_THRESHOLD)

    if debug:
        phases    = N.arange(pfd.proflen, dtype=N.float)/pfd.proflen
        gaussians = PT.make_gaussians_presto(gaussian_params, pfd.proflen)
        PL.plot(phases, profile)
        PL.plot(phases, gaussians)
        PL.show()

    # Create a list for storing the FWHMs of the Gaussians
    fwhms = []
    # If we were able to fit at least one Gaussian...
    if ngaussians != 0:
        # Get and store the FWHM for each Gaussian
        for nn in xrange(ngaussians):
            fwhms.append(gaussian_params[1+3*nn+1])
        # Calculate the DM smearing time
        dm_smear_sec = PU.dm_smear(pfd.bestdm, pfd.chan_wid, f_ctr)
        # Calculate the expected minimum pulse width
        width_phase  = N.sqrt(dm_smear_sec**2 + pfd.dt**2)/P0
        # Compare the expected minimum and actual pulse widths
        width_ratio  = width_phase/min(fwhms)
    # If no Gaussians could be fit to the profile, store bogus metrics
    else:
        width_ratio = -1.0

    # Store the ratings
    rating1 = ngaussians
    rating2 = width_ratio

    return [name1,name2],[rating1,rating2]
Esempio n. 15
0
def Multi_Gaussian_Ratings(pfd, debug=False):
    """
    Calculate ratings that depend on a fit of multiple Gaussian profile
    components.

    Parameters
    ----------
    pfd : class
        An instance of the prepfold.pfd class
    debug : boolean
        If True, plot the profile and best-fit Gaussians

    Returns
    -------
    names : list
        A list of ratings names
    ratings : list
        A list of ratings values
    """
    # The ratings names
    name1 = "Number_of_Gaussians"
    name2 = "Pulse_Width_Rating"

    # De-disperse the profile at the best DM
    pfd.dedisperse(DM=pfd.bestdm, doppler=1)
    # Internally rotate the data cube so that is aligned with best fold values
    pfd.adjust_period()
    # Get the best fold profile
    profile = N.sum(N.sum(pfd.profs, axis=1), axis=0)
    # Get the period from bestprof, if it exists
    if hasattr(pfd.bestprof, "p0"):
        P0 = pfd.bestprof.p0
    # Otherwise use the barycentric or topocentric folding periods
    else:
        if pfd.bary_p1 != 0.0: P0 = pfd.bary_p1
        elif pfd.topo_p1 != 0.0: P0 = pfd.topo_p1
    # Get the center observing frequency
    f_ctr = (pfd.hifreq + pfd.lofreq) / 2
    # Fit up to MAX_GAUSSIANS Gaussians to the profile
    gaussian_params, red_chi2, ngaussians = \
        PT.fit_gaussians_presto(profile, pfd.avgprof, N.sqrt(pfd.varprof),
                             MAX_GAUSSIANS, F_STAT_THRESHOLD)

    if debug:
        phases = N.arange(pfd.proflen, dtype=N.float) / pfd.proflen
        gaussians = PT.make_gaussians_presto(gaussian_params, pfd.proflen)
        PL.plot(phases, profile)
        PL.plot(phases, gaussians)
        PL.show()

    # Create a list for storing the FWHMs of the Gaussians
    fwhms = []
    # If we were able to fit at least one Gaussian...
    if ngaussians != 0:
        # Get and store the FWHM for each Gaussian
        for nn in xrange(ngaussians):
            fwhms.append(gaussian_params[1 + 3 * nn + 1])
        # Calculate the DM smearing time
        dm_smear_sec = PU.dm_smear(pfd.bestdm, pfd.chan_wid, f_ctr)
        # Calculate the expected minimum pulse width
        width_phase = N.sqrt(dm_smear_sec**2 + pfd.dt**2) / P0
        # Compare the expected minimum and actual pulse widths
        width_ratio = width_phase / min(fwhms)
    # If no Gaussians could be fit to the profile, store bogus metrics
    else:
        width_ratio = -1.0

    # Store the ratings
    rating1 = ngaussians
    rating2 = width_ratio

    return [name1, name2], [rating1, rating2]
Esempio n. 16
0
        counterpart = j
        break
#      print f1,fwant
    if counterpart == False:
      print "Didn't find counterpart frequency for %f" % f0
      sub.set_weight(i,0.0)
      continue
#    else:
#      print counterpart,f1
#    print f0, f1
#    sys.exit()
#    print f0,f1

    p = sub.get_folding_period()

    smear = (psr_utils.dm_smear(dm,chbw,f0) 
            + psr_utils.dm_smear(dm,chbw,f1)) / p

    delay = (psr_utils.delay_from_DM(dm,f0) 
            - psr_utils.delay_from_DM(dm,f1)) / p

    delay -= int(delay)
    if delay<-0.5: delay += 1.0
    if delay>0.5: delay -= 1.0

    #print i, smear, delay

    for pol in range(2):
        if pol == 0:
          correction = pol0correction/2.0
        else:
Esempio n. 17
0
    def __init__(self, loDM, hiDM, obs, numsub=0, resolution=0.0, verbose=False):
        """DDplan object constructor.
            
            Inputs:
                loDM: Low DM to consider (pc cm-3)
                hiDM: High DM to consider (pc cm-3)
                obs: Observation object
                numsub: Number of subbands to use (Default = Don't subband)
                resolution: Acceptable smearing in ms (Default = Least smearing possible)
                verbose: Print information to screen (Default = False)
        """
        self.loDM = loDM
        self.hiDM = hiDM
        self.obs = obs
        self.numsub = numsub
        self.req_resolution = resolution * 0.001  # In seconds
        self.current_downfact = self.obs.allow_factors[0]
        self.current_dDM = ALLOW_DMSTEPS[0]

        self.DDsteps = []  # list of dedispersion steps

        # Calculate optimal smearing
        self.calc_min_smearing(verbose=verbose)

        # Calculate initial downsampling
        while (self.obs.dt * self.get_next_downfact()) < self.resolution:
            self.current_downfact = self.get_next_downfact()
        if verbose:
            print "        New dt is %d x %.12g s = %.12g s" % (
                self.current_downfact,
                self.obs.dt,
                self.current_downfact * self.obs.dt,
            )

        # Calculate the appropriate initial dDM
        dDM = guess_DMstep(self.obs.dt * self.current_downfact, 0.5 * self.obs.BW, self.obs.fctr)
        if verbose:
            print "Best guess for optimal initial dDM is %.3f" % dDM
        while self.get_next_dDM() < dDM:
            self.current_dDM = self.get_next_dDM()
        self.DDsteps.append(
            DDstep(self, self.current_downfact, self.loDM, self.current_dDM, numsub=self.numsub, smearfact=SMEARFACT)
        )

        # Calculate the next steps
        while self.DDsteps[-1].hiDM < self.hiDM:
            # Determine the new downsample factor
            self.current_downfact = self.get_next_downfact()
            eff_dt = self.obs.dt * self.current_downfact

            # Determine the new DM step
            while psr_utils.dm_smear(0.5 * self.get_next_dDM(), self.obs.BW, self.obs.fctr) < FF * eff_dt:
                self.current_dDM = self.get_next_dDM()

            # Get the next step
            self.DDsteps.append(
                DDstep(
                    self,
                    self.current_downfact,
                    self.DDsteps[-1].hiDM,
                    self.current_dDM,
                    numsub=self.numsub,
                    smearfact=SMEARFACT,
                )
            )

        # Calculate the predicted amount of time that will be spent in searching
        # this batch of DMs as a fraction of the total
        wfs = [step.numDMs / float(step.downsamp) for step in self.DDsteps]
        self.work_fracts = np.asarray(wfs) / np.sum(wfs)
Esempio n. 18
0
def apply_dm(inprof, period, dm, chan_width, freqs, tsamp, \
                do_delay=True, do_smear=True, do_scatter=True,
                verbose=True):
    """Given a profile apply DM delays, smearing, and scattering 
        within each channel as is appropriate for the given params.

        Inputs:
            inprof: The profile to modify.
            period: The profiles period (in seconds)
            dm: The DM (in pc cm-3)
            chan_width: The width of each channel (in MHz)
            freqs: The list of frequencies (in MHz)
            tsamp: Sample time of the recipient filterbank file (in seconds).
            do_delay: Boolean, if True apply DM delays to each channel.
                The highest freq channel is not shifted. (Default: True)
            do_smear: Boolean, if True apply DM smearing to each channel.
                (Default: True)
            do_scatter: Boolean, if True apply scattering to each channel.
                (Default: True)

        Outputs:
            vecprof: The delayed and smeared VectorProfile.
    """
    weq = inprof.get_equivalent_width()
    nfreqs = len(freqs)
    if verbose:
        print "Applying DM to profile (DM = %.2f; %d channels)..." % \
                (dm, nfreqs)
    # A list of profiles, one for each channel
    profiles = []

    if dm <= 0:
        warnings.warn("DM will not be applied because it is 0 (or smaller?!)")
        do_delay = False
        do_smear = False
        do_scatter = False

    if do_delay:
        phasedelays = get_phasedelays(dm, freqs, period)
    else:
        phasedelays = np.zeros(nfreqs)

    # Prepare for smear campaign
    smeartimes = psr_utils.dm_smear(dm, abs(chan_width), freqs) # In seconds
    smearphases = smeartimes/period
    
    # Prepare to scatter
    scattertimes = psr_utils.pulse_broadening(dm, freqs)*1e-3 # In seconds
    scatterphases = scattertimes/period

    if DEBUG:
        for ichan, (freq, smear, scatt, delay) in \
                enumerate(zip(freqs, smearphases, scatterphases, phasedelays)):
            print "    Chan #%d - Freq: %.3f MHz -- " \
                  "Smearing, scattering, delay (all in phase): " \
                  "%g, %g, %g" % (ichan, freq, smear, scatt, delay)
    oldprogress = 0
    sys.stdout.write(" %3.0f %%\r" % oldprogress)
    sys.stdout.flush()
#    ylim = None
#    ylim2 = None
#    ylim3 = None
#    ylim4 = None
#    ylim5 = None
    for ii, (delayphs, smearphs, scattphs) in \
                enumerate(zip(phasedelays, smearphases, scatterphases)):
        #########
        # DEBUG: plot all profiles
#        plt.clf()
#        ax = plt.subplot(5,1,1)
#        inprof.plot()
#        if ylim is not None:
#            ax.set_ylim(ylim)
#        else:
#            ylim = ax.get_ylim()

        if do_smear and not ((smearphs < 0.2*weq) or (smearphs < (tsamp/period))):
            # Only smear if requested and smearing-phase is large enough
#            bc = boxcar_factory(smearphs, delayphs)
#            ax2 = plt.subplot(5,1,2,sharex=ax)
#            bc.plot()
#            if ylim2 is not None:
#                ax2.set_ylim(ylim2)
#            else:
#                ylim2 = ax2.get_ylim()
            if DEBUG:
                print "Smearing"
            tmpprof = inprof.smear(smearphs, delayphs, npts=NUMPOINTS)
        else:
            tmpprof = inprof.delay(delayphs)
            phs = np.linspace(0, 1, NUMPOINTS+1)
            tmpprof = SplineProfile(tmpprof(phs))
#        ax3 = plt.subplot(5,1,3,sharex=ax)
#        if ylim3 is not None:
#            ax3.set_ylim(ylim3)
#        else:
#            ylim3 = ax3.get_ylim()
#        tmpprof.plot()
        if do_scatter and not ((scattphs < 0.2*weq) or (scattphs < (tsamp/period))):
            # Only scatter if requested and scattering-phase is large enough
#            ex = exponential_factory(scattphs)
#            ax4 = plt.subplot(5,1,4,sharex=ax)
#            ex.plot()
#            if ylim4 is not None:
#                ax4.set_ylim(ylim4)
#            else:
#                ylim4 = ax4.get_ylim()
            if DEBUG:
                print "Scattering"
            tmpprof = tmpprof.scatter(scattphs, npts=NUMPOINTS)
#        ax5 = plt.subplot(5,1,5,sharex=ax)
#        tmpprof.plot()
#        if ylim5 is not None:
#            ax5.set_ylim(ylim5)
#        else:
#            ylim5 = ax5.get_ylim()
        profiles.append(tmpprof)
#        plt.xlim(0,1)
#        plt.xlabel("Phase")
#        plt.suptitle("Prof %d (%f MHz)" % (ii, freqs[ii]))
#        plt.savefig("prof%d.png" % ii)
        #########
        # Print progress to screen
        progress = int(100.0*ii/nfreqs)
        if progress > oldprogress: 
            sys.stdout.write(" %3.0f %%\r" % progress)
            sys.stdout.flush()
            oldprogress = progress
    sys.stdout.write("Done   \n")
    sys.stdout.flush()
    dispersedprof = DispersedProfile(profiles, dm=dm, freqs=freqs, period=period, 
                                     intrinsic=inprof, delayed=do_delay)
    return dispersedprof
Esempio n. 19
0
    def __init__(self, loDM, hiDM, obs, numsub=0, resolution=0.0, \
                    verbose=False):
        """DDplan object constructor.
            
            Inputs:
                loDM: Low DM to consider (pc cm-3)
                hiDM: High DM to consider (pc cm-3)
                obs: Observation object
                numsub: Number of subbands to use (Default = Don't subband)
                resolution: Acceptable smearing in ms (Default = Least smearing possible)
                verbose: Print information to screen (Default = False)
        """
        self.loDM = loDM
        self.hiDM = hiDM
        self.obs = obs
        self.numsub = numsub
        self.req_resolution = resolution * 0.001  # In seconds
        self.current_downfact = self.obs.allow_factors[0]
        self.current_dDM = ALLOW_DMSTEPS[0]

        self.DDsteps = []  # list of dedispersion steps

        # Calculate optimal smearing
        self.calc_min_smearing(verbose=verbose)

        # Calculate initial downsampling
        while (self.obs.dt * self.get_next_downfact()) < self.resolution:
            self.current_downfact = self.get_next_downfact()
        if verbose:
            print "        New dt is %d x %.12g s = %.12g s" % \
                    (self.current_downfact, self.obs.dt, \
                        self.current_downfact*self.obs.dt)

        # Calculate the appropriate initial dDM
        dDM = guess_DMstep(self.obs.dt*self.current_downfact, \
                            0.5*self.obs.BW, self.obs.fctr)
        if verbose:
            print "Best guess for optimal initial dDM is %.3f" % dDM
        while (self.get_next_dDM() < dDM):
            self.current_dDM = self.get_next_dDM()
        self.DDsteps.append(DDstep(self, self.current_downfact, \
                                    self.loDM, self.current_dDM, \
                                    numsub=self.numsub, \
                                    smearfact=SMEARFACT))

        # Calculate the next steps
        while self.DDsteps[-1].hiDM < self.hiDM:
            # Determine the new downsample factor
            self.current_downfact = self.get_next_downfact()
            eff_dt = self.obs.dt * self.current_downfact

            # Determine the new DM step
            while psr_utils.dm_smear(0.5*self.get_next_dDM(), self.obs.BW, \
                                        self.obs.fctr) < FF*eff_dt:
                self.current_dDM = self.get_next_dDM()

            # Get the next step
            self.DDsteps.append(DDstep(self, self.current_downfact, \
                                        self.DDsteps[-1].hiDM, \
                                        self.current_dDM, \
                                        numsub=self.numsub, \
                                        smearfact=SMEARFACT))

        # Calculate the predicted amount of time that will be spent in searching
        # this batch of DMs as a fraction of the total
        wfs = [step.numDMs / float(step.downsamp) for step in self.DDsteps]
        self.work_fracts = np.asarray(wfs) / np.sum(wfs)
Esempio n. 20
0
def apply_dm(inprof, period, dm, chan_width, freqs, tsamp, \
                do_delay=True, do_smear=True, do_scatter=True,
                verbose=True):
    """Given a profile apply DM delays, smearing, and scattering 
        within each channel as is appropriate for the given params.

        Inputs:
            inprof: The profile to modify.
            period: The profiles period (in seconds)
            dm: The DM (in pc cm-3)
            chan_width: The width of each channel (in MHz)
            freqs: The list of frequencies (in MHz)
            tsamp: Sample time of the recipient filterbank file (in seconds).
            do_delay: Boolean, if True apply DM delays to each channel.
                The highest freq channel is not shifted. (Default: True)
            do_smear: Boolean, if True apply DM smearing to each channel.
                (Default: True)
            do_scatter: Boolean, if True apply scattering to each channel.
                (Default: True)

        Outputs:
            vecprof: The delayed and smeared VectorProfile.
    """
    weq = inprof.get_equivalent_width()
    nfreqs = len(freqs)
    if verbose:
        print("Applying DM to profile (DM = %.2f; %d channels)..." % \
                (dm, nfreqs))
    # A list of profiles, one for each channel
    profiles = []

    if dm <= 0:
        warnings.warn("DM will not be applied because it is 0 (or smaller?!)")
        do_delay = False
        do_smear = False
        do_scatter = False

    if do_delay:
        phasedelays = get_phasedelays(dm, freqs, period)
    else:
        phasedelays = np.zeros(nfreqs)

    # Prepare for smear campaign
    smeartimes = psr_utils.dm_smear(dm, abs(chan_width), freqs) # In seconds
    smearphases = smeartimes/period
    
    # Prepare to scatter
    scattertimes = psr_utils.pulse_broadening(dm, freqs)*1e-3 # In seconds
    scatterphases = scattertimes/period

    if DEBUG:
        for ichan, (freq, smear, scatt, delay) in \
                enumerate(zip(freqs, smearphases, scatterphases, phasedelays)):
            print("    Chan #%d - Freq: %.3f MHz -- " \
                  "Smearing, scattering, delay (all in phase): " \
                  "%g, %g, %g" % (ichan, freq, smear, scatt, delay))
    oldprogress = 0
    sys.stdout.write(" %3.0f %%\r" % oldprogress)
    sys.stdout.flush()
#    ylim = None
#    ylim2 = None
#    ylim3 = None
#    ylim4 = None
#    ylim5 = None
    for ii, (delayphs, smearphs, scattphs) in \
                enumerate(zip(phasedelays, smearphases, scatterphases)):
        #########
        # DEBUG: plot all profiles
#        plt.clf()
#        ax = plt.subplot(5,1,1)
#        inprof.plot()
#        if ylim is not None:
#            ax.set_ylim(ylim)
#        else:
#            ylim = ax.get_ylim()

        if do_smear and not ((smearphs < 0.2*weq) or (smearphs < (tsamp/period))):
            # Only smear if requested and smearing-phase is large enough
#            bc = boxcar_factory(smearphs, delayphs)
#            ax2 = plt.subplot(5,1,2,sharex=ax)
#            bc.plot()
#            if ylim2 is not None:
#                ax2.set_ylim(ylim2)
#            else:
#                ylim2 = ax2.get_ylim()
            if DEBUG:
                print("Smearing")
            tmpprof = inprof.smear(smearphs, delayphs, npts=NUMPOINTS)
        else:
            tmpprof = inprof.delay(delayphs)
            phs = np.linspace(0, 1, NUMPOINTS+1)
            tmpprof = SplineProfile(tmpprof(phs))
#        ax3 = plt.subplot(5,1,3,sharex=ax)
#        if ylim3 is not None:
#            ax3.set_ylim(ylim3)
#        else:
#            ylim3 = ax3.get_ylim()
#        tmpprof.plot()
        if do_scatter and not ((scattphs < 0.2*weq) or (scattphs < (tsamp/period))):
            # Only scatter if requested and scattering-phase is large enough
#            ex = exponential_factory(scattphs)
#            ax4 = plt.subplot(5,1,4,sharex=ax)
#            ex.plot()
#            if ylim4 is not None:
#                ax4.set_ylim(ylim4)
#            else:
#                ylim4 = ax4.get_ylim()
            if DEBUG:
                print("Scattering")
            tmpprof = tmpprof.scatter(scattphs, npts=NUMPOINTS)
#        ax5 = plt.subplot(5,1,5,sharex=ax)
#        tmpprof.plot()
#        if ylim5 is not None:
#            ax5.set_ylim(ylim5)
#        else:
#            ylim5 = ax5.get_ylim()
        profiles.append(tmpprof)
#        plt.xlim(0,1)
#        plt.xlabel("Phase")
#        plt.suptitle("Prof %d (%f MHz)" % (ii, freqs[ii]))
#        plt.savefig("prof%d.png" % ii)
        #########
        # Print progress to screen
        progress = int(100.0*ii/nfreqs)
        if progress > oldprogress: 
            sys.stdout.write(" %3.0f %%\r" % progress)
            sys.stdout.flush()
            oldprogress = progress
    sys.stdout.write("Done   \n")
    sys.stdout.flush()
    dispersedprof = DispersedProfile(profiles, dm=dm, freqs=freqs, period=period, 
                                     intrinsic=inprof, delayed=do_delay)
    return dispersedprof
Esempio n. 21
0
    def __init__(self, ddplan, downsamp, loDM, dDM, \
                    numDMs=0, numsub=0, smearfact=2.0):
        """DDstep object constructor.

            Inputs:
                ddplan: DDplan object this DDstep is part of.
                downsamp: Downsampling factor.
                loDM: Low DM edge of this DDstep (pc cm-3)
                dDM: DM step size to use (pc cm-3)
                numDMs: Number of DMs. If numDMs=0 compute numDMs
                        based on DM range and spacing.
                        (Default: 0)
                numsub: Number of subbands to use. (Default: no subbanding).
                smearfact: Allowable smearing in a single channel, relative
                        to other smearing contributions (Default: 2.0)
        """
        self.ddplan = ddplan
        self.downsamp = downsamp
        self.loDM = loDM
        self.dDM = dDM
        self.numsub = numsub
        self.BW_smearing = psr_utils.dm_smear(dDM*0.5, self.ddplan.obs.BW, \
                                                self.ddplan.obs.fctr)
        self.numprepsub = 0
        if numsub:
            # Calculate the maximum subband smearing we can handle
            DMs_per_prepsub = 2
            while True:
                next_dsubDM = (DMs_per_prepsub + 2) * dDM
                next_ss = psr_utils.dm_smear(next_dsubDM*0.5, \
                                    self.ddplan.obs.BW/numsub, \
                                    self.ddplan.obs.fctr)
                # The 0.8 is a small fudge factor to make sure that the subband
                # smearing is always the smallest contribution
                if next_ss > 0.8*min(self.BW_smearing, \
                                        self.ddplan.obs.dt*self.downsamp):
                    self.dsubDM = DMs_per_prepsub * dDM
                    self.DMs_per_prepsub = DMs_per_prepsub
                    self.sub_smearing = psr_utils.dm_smear(self.dsubDM*0.5,
                                            self.ddplan.obs.BW/self.numsub, \
                                            self.ddplan.obs.fctr)
                    break
                DMs_per_prepsub += 2
        else:
            self.dsubDM = dDM
            self.sub_smearing = 0.0

        # Calculate the nominal DM to move to the next step
        cross_DM = self.DM_for_smearfact(smearfact)
        if cross_DM > self.ddplan.hiDM:
            cross_DM = self.ddplan.hiDM
        if numDMs == 0:
            self.numDMs = int(np.ceil((cross_DM - self.loDM) / self.dDM))
            if numsub:
                self.numprepsub = int(
                    np.ceil(self.numDMs * self.dDM / self.dsubDM))
                self.numDMs = self.numprepsub * DMs_per_prepsub
        else:
            self.numDMs = numDMs
        self.hiDM = loDM + self.numDMs * dDM
        self.DMs = np.arange(self.numDMs, dtype='d') * self.dDM + self.loDM

        # Calculate a few more smearing values
        self.chan_smear = psr_utils.dm_smear(self.DMs, \
                                            self.ddplan.obs.chanwidth, \
                                            self.ddplan.obs.fctr)
        self.tot_smear = np.sqrt((self.ddplan.obs.dt)**2.0 + \
                                     (self.ddplan.obs.dt*self.downsamp)**2.0 + \
                                     self.BW_smearing**2.0 + \
                                     self.sub_smearing**2.0 + \
                                     self.chan_smear**2.0)