def template_prof(input_profs, sum=True): """ Phase aligns and sums (if sum=True) multiple input profiles from different observations to create a single high S/N template profile. input_profs - np.asarray((prof1,prof2,...)) of input profiles to be combined. prof1 is the profile to which the others are aligned """ Nprof = np.shape(input_profs)[0] bins = input_profs[0].size aligned_profs = np.empty(np.shape(input_profs)) for i in range(Nprof): offset = psr_utils.measure_phase_corr(input_profs[i], input_profs[0]) #print 'Phase offset '+str(i)+' = '+str(offset) bin_offset = -offset * bins aligned_profs[i] = psr_utils.fft_rotate(input_profs[i], bin_offset) if sum is False: return aligned_profs else: template_prof = aligned_profs.sum(0) for i in range(Nprof): offset = psr_utils.measure_phase_corr(input_profs[i], template_prof) bin_offset = -offset * bins aligned_profs[i] = psr_utils.fft_rotate(input_profs[i], bin_offset) template_prof = aligned_profs.sum(0) return template_prof
def template_2d(input_profs, sum=True): """ Phase aligns and sums multiple input 2D profiles from different observations to create a single high S/N template profile, while keeping full frequency resolution. input_profs - np.asarray((prof1,prof2,...)) of input profiles to be combined. prof1 is the profile to which the others are aligned """ Nprof = np.shape(input_profs)[0] bins = input_profs[0].shape[1] channels = input_profs[0].shape[0] aligned_profs = np.empty(np.shape(input_profs)) for i in range(Nprof): #offset=psr_utils.measure_phase_corr(input_profs[i].sum(0),input_profs[0].sum(0)) offset = psr_utils.measure_phase_corr( np.nanmean(input_profs[i], axis=0), np.nanmean(input_profs[0], axis=0)) #print 'Phase offset '+str(i)+' = '+str(offset) bin_offset = -offset * bins print bin_offset ################ for jj in np.arange(channels): aligned_profs[i][jj] = psr_utils.fft_rotate( input_profs[i][jj], bin_offset) if sum is False: return aligned_profs else: #template_prof=aligned_profs.sum(0) template_prof = np.nanmean(aligned_profs, axis=0) for i in range(Nprof): #offset=psr_utils.measure_phase_corr(input_profs[i].sum(0),template_prof.sum(0)) offset = psr_utils.measure_phase_corr( np.nanmean(input_profs[i], axis=0), np.nanmean(template_prof, axis=0)) bin_offset = -offset * bins for jj in np.arange(channels): aligned_profs[i][jj] = psr_utils.fft_rotate( input_profs[i][jj], bin_offset) #template_prof=aligned_profs.sum(0) template_prof = np.nanmean(aligned_profs, axis=0) return template_prof
def prof_align(prof, template_prof, return_more=False): # Get amplitudes and phases from FFTing the input data profile t_prof_fft, t_prof_amp, t_prof_phase = cprof(template_prof) # Now run fftfit to match the profiles and out the shifts and scales shift,eshift,snr,esnr,b,errb,ngood = fftfit(prof,t_prof_amp,t_prof_phase) prof_rot = pu.fft_rotate(prof, shift) if(return_more): return shift, eshift, snr, esnr, b, errb, prof_rot else: return prof_rot
def baseline_search(prof_2d, nchan, off_pulse_size, subfreqs, LOFAR=True): nbin = prof_2d.shape[1] binspersec = nbin / 0.0016627 tmp_fp = np.empty(np.shape(prof_2d)) mask = np.zeros(np.shape(prof_2d), dtype=bool) mask[:, :off_pulse_size] = 1 binstep = 3 binshift_range = np.arange(0, nbin, binstep) if LOFAR is False: dmstep = 0.002 ## WSRT dm_range = np.arange(0, 0.05, dmstep) ## WSRT else: dmstep = 0.0005 ## LOFAR dm_range = np.arange(0, 0.01, dmstep) ## LOFAR fit = np.empty((binshift_range.size, dm_range.size)) for binshift in binshift_range: for dm in dm_range: subdelays = psr_utils.delay_from_DM(dm, subfreqs) hifreqdelay = subdelays[-1] subdelays = subdelays - hifreqdelay delaybins = subdelays * binspersec + binshift for jj in range(nchan): tmp_prof = prof_2d[jj, :].copy() tmp_fp[jj] = psr_utils.fft_rotate(tmp_prof, delaybins[jj]) fit[binshift / binstep, int(dm / dmstep)] = np.nanmean(tmp_fp[mask]) best = np.unravel_index(fit.argmin(), fit.shape) Bin = best[0] * binstep DM = best[1] * dmstep subdelays = psr_utils.delay_from_DM(DM, subfreqs) hifreqdelay = subdelays[-1] subdelays = subdelays - hifreqdelay delaybins = subdelays * binspersec + Bin for jj in range(nchan): tmp_prof = prof_2d[jj, :].copy() tmp_fp[jj] = psr_utils.fft_rotate(tmp_prof, delaybins[jj]) base_perchan = np.nanmean(tmp_fp[:, :off_pulse_size], axis=1) return base_perchan, DM
def dedisperse(self, DM=None, interp=0, doppler=1): """ dedisperse(DM=self.bestdm, interp=0, doppler=1): Rotate (internally) the profiles so that they are de-dispersed at a dispersion measure of DM. Use FFT-based interpolation if 'interp' is non-zero (NOTE: It is off by default!). Doppler shift subband frequencies if doppler is non-zero. (NOTE: It is *ON* by default. This default behaviour is different with respect to PRESTO's prepfold.py) """ if DM is None: DM = self.bestdm # Note: Since TEMPO Doppler corrects observing frequencies, for # TOAs, at least, we need to de-disperse using topocentric # observing frequencies. if doppler: freqs = psr_utils.doppler(self.subfreqs, self.avgvoverc) else: freqs = self.subfreqs self.subdelays = psr_utils.delay_from_DM(DM, freqs) self.hifreqdelay = self.subdelays[-1] self.subdelays = self.subdelays - self.hifreqdelay delaybins = self.subdelays * self.binspersec - self.subdelays_bins if interp: new_subdelays_bins = delaybins for ii in range(self.npart): for jj in range(self.nsub): tmp_prof = self.profs[ii, jj, :] self.profs[ii, jj] = psr_utils.fft_rotate( tmp_prof, delaybins[jj]) # Note: Since the rotation process slightly changes the values of the # profs, we need to re-calculate the average profile value self.avgprof = (self.profs / self.proflen).sum() else: new_subdelays_bins = Num.floor(delaybins + 0.5) #print "DEBUG: in myprepfold.py -- DM, new_subdelays_bins:", DM, new_subdelays_bins for ii in range(self.nsub): rotbins = int(new_subdelays_bins[ii]) % self.proflen if rotbins: # i.e. if not zero subdata = self.profs[:, ii, :] self.profs[:, ii] = Num.concatenate( (subdata[:, rotbins:], subdata[:, :rotbins]), 1) self.subdelays_bins += new_subdelays_bins self.sumprof = self.profs.sum(0).sum(0) if Num.fabs((self.sumprof / self.proflen).sum() - self.avgprof) > 1.0: print "self.avgprof is not the correct value!" self.currdm = DM
def dedisperse(self, DM=None, interp=0, doppler=1): """ dedisperse(DM=self.bestdm, interp=0, doppler=1): Rotate (internally) the profiles so that they are de-dispersed at a dispersion measure of DM. Use FFT-based interpolation if 'interp' is non-zero (NOTE: It is off by default!). Doppler shift subband frequencies if doppler is non-zero. (NOTE: It is *ON* by default. This default behaviour is different with respect to PRESTO's prepfold.py) """ if DM is None: DM = self.bestdm # Note: Since TEMPO Doppler corrects observing frequencies, for # TOAs, at least, we need to de-disperse using topocentric # observing frequencies. if doppler: freqs = psr_utils.doppler(self.subfreqs, self.avgvoverc) else: freqs = self.subfreqs self.subdelays = psr_utils.delay_from_DM(DM, freqs) self.hifreqdelay = self.subdelays[-1] self.subdelays = self.subdelays-self.hifreqdelay delaybins = self.subdelays*self.binspersec - self.subdelays_bins if interp: new_subdelays_bins = delaybins for ii in range(self.npart): for jj in range(self.nsub): tmp_prof = self.profs[ii,jj,:] self.profs[ii,jj] = psr_utils.fft_rotate(tmp_prof, delaybins[jj]) # Note: Since the rotation process slightly changes the values of the # profs, we need to re-calculate the average profile value self.avgprof = (self.profs/self.proflen).sum() else: new_subdelays_bins = Num.floor(delaybins+0.5) #print "DEBUG: in myprepfold.py -- DM, new_subdelays_bins:", DM, new_subdelays_bins for ii in range(self.nsub): rotbins = int(new_subdelays_bins[ii])%self.proflen if rotbins: # i.e. if not zero subdata = self.profs[:,ii,:] self.profs[:,ii] = Num.concatenate((subdata[:,rotbins:], subdata[:,:rotbins]), 1) self.subdelays_bins += new_subdelays_bins self.sumprof = self.profs.sum(0).sum(0) if Num.fabs((self.sumprof/self.proflen).sum() - self.avgprof) > 1.0: print "self.avgprof is not the correct value!" self.currdm = DM
def time_vs_phase(self, p=None, pd=None, pdd=None, interp=0): """ time_vs_phase(p=*bestp*, pd=*bestpd*, pdd=*bestpdd*): Return the 2D time vs. phase profiles shifted so that the given period and period derivative are applied. Use FFT-based interpolation if 'interp' is non-zero. (NOTE: It is off by default as in prepfold!). """ # Cast to single precision and back to double precision to # emulate prepfold_plot.c, where parttimes is of type "float" # but values are upcast to "double" during computations. # (surprisingly, it affects the resulting profile occasionally.) parttimes = self.start_secs.astype('float32').astype('float64') # Get delays f_diff, fd_diff, fdd_diff = self.freq_offsets(p, pd, pdd) #print "DEBUG: in myprepfold.py -- parttimes", parttimes delays = psr_utils.delay_from_foffsets(f_diff, fd_diff, fdd_diff, parttimes) # Convert from delays in phase to delays in bins bin_delays = Num.fmod(delays * self.proflen, self.proflen) - self.pdelays_bins # Rotate subintegrations # subints = self.combine_profs(self.npart, 1)[:,0,:] # Slower than sum by ~9x subints = Num.sum(self.profs, axis=1).squeeze() if interp: new_pdelays_bins = bin_delays for ii in range(self.npart): tmp_prof = subints[ii, :] # Negative sign in num bins to shift because we calculated delays # Assuming +ve is shift-to-right, psr_utils.rotate assumes +ve # is shift-to-left subints[ii, :] = psr_utils.fft_rotate(tmp_prof, -new_pdelays_bins[ii]) else: new_pdelays_bins = Num.floor(bin_delays + 0.5) indices = Num.outer(Num.arange(self.proflen), Num.ones(self.npart)) indices = Num.mod(indices - new_pdelays_bins, self.proflen).T indices += Num.outer(Num.arange(self.npart)*self.proflen, \ Num.ones(self.proflen)) subints = subints.flatten('C')[indices.astype('i8')] return subints
def time_vs_phase(self, p=None, pd=None, pdd=None, interp=0): """ time_vs_phase(p=*bestp*, pd=*bestpd*, pdd=*bestpdd*): Return the 2D time vs. phase profiles shifted so that the given period and period derivative are applied. Use FFT-based interpolation if 'interp' is non-zero. (NOTE: It is off by default as in prepfold!). """ # Cast to single precision and back to double precision to # emulate prepfold_plot.c, where parttimes is of type "float" # but values are upcast to "double" during computations. # (surprisingly, it affects the resulting profile occasionally.) parttimes = self.start_secs.astype('float32').astype('float64') # Get delays f_diff, fd_diff, fdd_diff = self.freq_offsets(p, pd, pdd) #print "DEBUG: in myprepfold.py -- parttimes", parttimes delays = psr_utils.delay_from_foffsets(f_diff, fd_diff, fdd_diff, parttimes) # Convert from delays in phase to delays in bins bin_delays = Num.fmod(delays * self.proflen, self.proflen) - self.pdelays_bins # Rotate subintegrations # subints = self.combine_profs(self.npart, 1)[:,0,:] # Slower than sum by ~9x subints = Num.sum(self.profs, axis=1).squeeze() if interp: new_pdelays_bins = bin_delays for ii in range(self.npart): tmp_prof = subints[ii,:] # Negative sign in num bins to shift because we calculated delays # Assuming +ve is shift-to-right, psr_utils.rotate assumes +ve # is shift-to-left subints[ii,:] = psr_utils.fft_rotate(tmp_prof, -new_pdelays_bins[ii]) else: new_pdelays_bins = Num.floor(bin_delays+0.5) indices = Num.outer(Num.arange(self.proflen), Num.ones(self.npart)) indices = Num.mod(indices-new_pdelays_bins, self.proflen).T indices += Num.outer(Num.arange(self.npart)*self.proflen, \ Num.ones(self.proflen)) subints = subints.flatten('C')[indices.astype('i8')] return subints
def time_vs_phase(self, p=None, pd=None, pdd=None, interp=0): """ time_vs_phase(p=*bestp*, pd=*bestpd*, pdd=*bestpdd*): Return the 2D time vs. phase profiles shifted so that the given period and period derivative are applied. Use FFT-based interpolation if 'interp' is non-zero (NOTE: It is off by default!). Dedisperses the datacube, if necessary. Other than running self.dedisperse(), the datacube is not modified. """ # Cast to single precision and back to double precision to # emulate prepfold_plot.c, where parttimes is of type "float" # but values are upcast to "double" during computations. # (surprisingly, it affects the resulting profile occasionally.) parttimes = self.start_secs.astype('float32').astype('float64') # Get delays f_diff, fd_diff, fdd_diff = self.freq_offsets(p, pd, pdd) delays = psr_utils.delay_from_foffsets(f_diff, fd_diff, fdd_diff, parttimes) # Convert from delays in phase to delays in bins bin_delays = Num.fmod(delays * self.proflen, self.proflen) # Rotate subintegrations subints = self.combine_profs(self.npart, 1)[:,0,:] for ii in range(self.npart): tmp_prof = subints[ii,:] # Negative sign in num bins to shift because we calculated delays # Assuming +ve is shift-to-right, psr_utils.rotate assumes +ve # is shift-to-left if interp: subints[ii,:] = psr_utils.fft_rotate(tmp_prof, -bin_delays[ii]) else: subints[ii,:] = psr_utils.rotate(tmp_prof, -Num.floor(bin_delays[ii]+0.5)) return subints
def adjust_period(self, p=None, pd=None, pdd=None, interp=0): """ adjust_period(p=*bestp*, pd=*bestpd*, pdd=*bestpdd*): Rotate (internally) the profiles so that they are adjusted to the given period and period derivatives. By default, use the 'best' values as determined by prepfold's seaqrch. This should orient all of the profiles so that they are almost identical to what you see in a prepfold plot which used searching. Use FFT-based interpolation if 'interp' is non-zero. (NOTE: It is off by default, as in prepfold!) """ if self.fold_pow == 1.0: bestp = self.bary_p1 bestpd = self.bary_p2 bestpdd = self.bary_p3 else: bestp = self.topo_p1 bestpd = self.topo_p2 bestpdd = self.topo_p3 if p is None: p = bestp if pd is None: pd = bestpd if pdd is None: pdd = bestpdd # Cast to single precision and back to double precision to # emulate prepfold_plot.c, where parttimes is of type "float" # but values are upcast to "double" during computations. # (surprisingly, it affects the resulting profile occasionally.) parttimes = self.start_secs.astype('float32').astype('float64') # Get delays f_diff, fd_diff, fdd_diff = self.freq_offsets(p, pd, pdd) delays = psr_utils.delay_from_foffsets(f_diff, fd_diff, fdd_diff, parttimes) # Convert from delays in phase to delays in bins bin_delays = Num.fmod(delays * self.proflen, self.proflen) - self.pdelays_bins if interp: new_pdelays_bins = bin_delays.astype(int) else: new_pdelays_bins = Num.floor(bin_delays+0.5).astype(int) # Rotate subintegrations for ii in range(self.nsub): for jj in range(self.npart): tmp_prof = self.profs[jj,ii,:] # Negative sign in num bins to shift because we calculated delays # Assuming +ve is shift-to-right, psr_utils.rotate assumes +ve # is shift-to-left if interp: self.profs[jj,ii] = psr_utils.fft_rotate(tmp_prof, -new_pdelays_bins[jj]) else: self.profs[jj,ii] = psr_utils.rotate(tmp_prof, \ -new_pdelays_bins[jj]) self.pdelays_bins += new_pdelays_bins if interp: # Note: Since the rotation process slightly changes the values of the # profs, we need to re-calculate the average profile value self.avgprof = (self.profs/self.proflen).sum() self.sumprof = self.profs.sum(0).sum(0) if Num.fabs((self.sumprof/self.proflen).sum() - self.avgprof) > 1.0: print "self.avgprof is not the correct value!" # Save current p, pd, pdd self.curr_p1, self.curr_p2, self.curr_p3 = p, pd, pdd
# Resample the template profile to have the correct number of bins (if required) if not len(template) == numbins: oldlen = len(template) template = sinc_interp.periodic_interp(template, numbins)[::oldlen] else: if gaussfitfile is not None: template = psr_utils.read_gaussfitfile(gaussfitfile, numbins) else: template = psr_utils.gaussian_profile(numbins, 0.0, gaussianwidth) # Normalize it template -= min(template) template /= max(template) # Rotate it so that it becomes a "true" template according to FFTFIT shift, eshift, snr, esnr, b, errb, ngood = measure_phase( template, template) template = psr_utils.fft_rotate(template, shift) # Determine the off-pulse bins if bkgd_vals is not None: Pgplot.plotxy(template, labx="Phase bins") Pgplot.plotxy(template[bkgd_vals], Num.arange(numbins)[bkgd_vals], line=None, symbol=2, color='red') Pgplot.closeplot() offpulse_inds = bkgd_vals onpulse_inds = set(Num.arange(numbins)) - set(bkgd_vals) else: offpulse_inds = Num.compress(template <= bkgd_cutoff, Num.arange(numbins))
def adjust_period(self, p=None, pd=None, pdd=None, interp=0): """ adjust_period(p=*bestp*, pd=*bestpd*, pdd=*bestpdd*): Rotate (internally) the profiles so that they are adjusted to the given period and period derivatives. By default, use the 'best' values as determined by prepfold's seaqrch. This should orient all of the profiles so that they are almost identical to what you see in a prepfold plot which used searching. Use FFT-based interpolation if 'interp' is non-zero. (NOTE: It is off by default, as in prepfold!) """ if self.fold_pow == 1.0: bestp = self.bary_p1 bestpd = self.bary_p2 bestpdd = self.bary_p3 else: bestp = self.topo_p1 bestpd = self.topo_p2 bestpdd = self.topo_p3 if p is None: p = bestp if pd is None: pd = bestpd if pdd is None: pdd = bestpdd # Cast to single precision and back to double precision to # emulate prepfold_plot.c, where parttimes is of type "float" # but values are upcast to "double" during computations. # (surprisingly, it affects the resulting profile occasionally.) parttimes = self.start_secs.astype('float32').astype('float64') # Get delays f_diff, fd_diff, fdd_diff = self.freq_offsets(p, pd, pdd) delays = psr_utils.delay_from_foffsets(f_diff, fd_diff, fdd_diff, parttimes) # Convert from delays in phase to delays in bins bin_delays = Num.fmod(delays * self.proflen, self.proflen) - self.pdelays_bins if interp: new_pdelays_bins = bin_delays else: new_pdelays_bins = Num.floor(bin_delays+0.5) # Rotate subintegrations for ii in range(self.nsub): for jj in range(self.npart): tmp_prof = self.profs[jj,ii,:] # Negative sign in num bins to shift because we calculated delays # Assuming +ve is shift-to-right, psr_utils.rotate assumes +ve # is shift-to-left if interp: self.profs[jj,ii] = psr_utils.fft_rotate(tmp_prof, -new_pdelays_bins[jj]) else: self.profs[jj,ii] = psr_utils.rotate(tmp_prof, \ -new_pdelays_bins[jj]) self.pdelays_bins += new_pdelays_bins if interp: # Note: Since the rotation process slightly changes the values of the # profs, we need to re-calculate the average profile value self.avgprof = (self.profs/self.proflen).sum() self.sumprof = self.profs.sum(0).sum(0) if Num.fabs((self.sumprof/self.proflen).sum() - self.avgprof) > 1.0: print "self.avgprof is not the correct value!" # Save current p, pd, pdd self.curr_p1, self.curr_p2, self.curr_p3 = p, pd, pdd
template = psr_utils.read_profile(templatefilenm) # Resample the template profile to have the correct number of bins (if required) if not len(template)==numbins: oldlen = len(template) template = sinc_interp.periodic_interp(template, numbins)[::oldlen] else: if gaussfitfile is not None: template = psr_utils.read_gaussfitfile(gaussfitfile, numbins) else: template = psr_utils.gaussian_profile(numbins, 0.0, gaussianwidth) # Normalize it template -= min(template) template /= max(template) # Rotate it so that it becomes a "true" template according to FFTFIT shift,eshift,snr,esnr,b,errb,ngood = measure_phase(template, template) template = psr_utils.fft_rotate(template, shift) # Determine the off-pulse bins if bkgd_vals is not None: Pgplot.plotxy(template, labx="Phase bins") Pgplot.plotxy(template[bkgd_vals], Num.arange(numbins)[bkgd_vals], line=None, symbol=2, color='red') Pgplot.closeplot() offpulse_inds = bkgd_vals onpulse_inds = set(Num.arange(numbins)) - set(bkgd_vals) else: offpulse_inds = Num.compress(template<=bkgd_cutoff, Num.arange(numbins)) onpulse_inds = Num.compress(template>bkgd_cutoff, Num.arange(numbins)) Pgplot.plotxy(template) Pgplot.plotxy([bkgd_cutoff, bkgd_cutoff], [0.0, numbins], color='red') Pgplot.closeplot()