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 _compute_rating(self, cand): """Return a rating for the candidate. The rating value is the the fraction of sub-ints that deviate from the phase of the pulse. Input: cand: A Candidate object to rate. Output: value: The rating value. """ tvph = cand.get_from_cache('time_vs_phase') pfd = cand.get_from_cache('pfd') bestprof = tvph.get_profile() new_template = np.zeros_like(bestprof) bin_offsets = np.empty(pfd.npart) # The following loop creates a better template by removing wiggle, but # it does not change the actual subints for ii, subint in enumerate(tvph.data): # Measure the phase offset phase_offset = psr_utils.measure_phase_corr(subint, bestprof) # The following is needed to put phase offsets on the interval # (-0.5,0.5] if phase_offset > 0.5: phase_offset -= 1.0 # Caclulate the offset in bins bin_offset = int(round(pfd.proflen * phase_offset)) # Update the new template new_template += psr_utils.rotate(subint, -bin_offset) # Now calculate the wiggle using the updated template for ii, subint in enumerate(tvph.data): phase_offset = psr_utils.measure_phase_corr(subint, new_template) if phase_offset > 0.5: phase_offset -= 1.0 bin_offsets[ii] = int(round(pfd.proflen * phase_offset)) # Calculate the various metrics if method == "GOODFRAC": # good fraction wigglescore = sum(abs(bin_offsets) < TOL*pfd.proflen)/ \ float(pfd.npart) elif method == "WANDER": # total wander wigglescore = sum(abs(bin_offsets)) / (pfd.proflen * pfd.npart) elif method == "OFFSTD": # offset std wigglescore = bin_offsets.std() elif method == "OFFMAX": # offset max wigglescore = bin_offsets.max() else: raise utils.RatingError("Unrecognized method for wiggle " \ "rating (%s)" % method) return wigglescore
def _compute_rating(self, cand): """Return a rating for the candidate. The rating value is the the fraction of sub-ints that deviate from the phase of the pulse. Input: cand: A Candidate object to rate. Output: value: The rating value. """ tvph = cand.get_from_cache('time_vs_phase') pfd = cand.get_from_cache('pfd') bestprof = tvph.get_profile() new_template = np.zeros_like(bestprof) bin_offsets = np.empty(pfd.npart) # The following loop creates a better template by removing wiggle, but # it does not change the actual subints for ii, subint in enumerate(tvph.data): # Measure the phase offset phase_offset = psr_utils.measure_phase_corr(subint, bestprof) # The following is needed to put phase offsets on the interval # (-0.5,0.5] if phase_offset > 0.5: phase_offset -= 1.0 # Caclulate the offset in bins bin_offset = int(round(pfd.proflen*phase_offset)) # Update the new template new_template += psr_utils.rotate(subint, -bin_offset) # Now calculate the wiggle using the updated template for ii, subint in enumerate(tvph.data): phase_offset = psr_utils.measure_phase_corr(subint, new_template) if phase_offset > 0.5: phase_offset -= 1.0 bin_offsets[ii] = int(round(pfd.proflen*phase_offset)) # Calculate the various metrics if method == "GOODFRAC": # good fraction wigglescore = sum(abs(bin_offsets) < TOL*pfd.proflen)/ \ float(pfd.npart) elif method == "WANDER": # total wander wigglescore = sum(abs(bin_offsets))/(pfd.proflen*pfd.npart) elif method == "OFFSTD": # offset std wigglescore = bin_offsets.std() elif method == "OFFMAX": # offset max wigglescore = bin_offsets.max() else: raise utils.RatingError("Unrecognized method for wiggle " \ "rating (%s)" % method) return wigglescore
def _compute_rating(self, cand): """Return a rating for the candidate. The rating value is the the fraction of subbands that deviate from the position of the pulse. Input: cand: A SPCandidate object to rate. Output: value: The rating value. """ wdd = cand.waterfall_dd spd = cand.spd prof = wdd.get_profile() new_template = np.zeros_like(prof) bin_offsets = np.empty(spd.waterfall_nsubs) # The following loop creates a better template by removing wiggle, but # it does not change the actual subbands for ii, subband in enumerate(wdd.data): # Measure the pulse offset pulse_offset = psr_utils.measure_phase_corr(subband, prof, zoom=1) # Caclulate the offset in bins bin_offset = int(round(spd.waterfall_nbins * pulse_offset)) # Update the new template new_template += psr_utils.rotate(subband, -bin_offset) # Now calculate the wiggle using the updated template for ii, subband in enumerate(wdd.data): pulse_offset = psr_utils.measure_phase_corr(subband, new_template, zoom=1) bin_offsets[ii] = int(round(spd.waterfall_nbins * pulse_offset)) # Calculate the various metrics if method == "GOODFRAC": # good fraction wigglescore = sum(abs(bin_offsets) < TOL*spd.waterfall_nbins)/ \ float(spd.waterfall_nsubs) elif method == "WANDER": # total wander wigglescore = sum( abs(bin_offsets)) / (spd.waterfall_nbins * spd.waterfall_nsubs) elif method == "OFFSTD": # offset std wigglescore = bin_offsets.std() elif method == "OFFMAX": # offset max wigglescore = bin_offsets.max() else: raise utils.RatingError("Unrecognized method for wiggle " \ "rating (%s)" % method) return wigglescore
def _compute_rating(self, cand): """Return a rating for the candidate. The rating value is the the fraction of subbands that deviate from the position of the pulse. Input: cand: A SPCandidate object to rate. Output: value: The rating value. """ wdd = cand.waterfall_dd spd = cand.spd prof = wdd.get_profile() new_template = np.zeros_like(prof) bin_offsets = np.empty(spd.waterfall_nsubs) # The following loop creates a better template by removing wiggle, but # it does not change the actual subbands for ii, subband in enumerate(wdd.data): # Measure the pulse offset pulse_offset = psr_utils.measure_phase_corr(subband, prof, zoom=1) # Caclulate the offset in bins bin_offset = int(round(spd.waterfall_nbins*pulse_offset)) # Update the new template new_template += psr_utils.rotate(subband, -bin_offset) # Now calculate the wiggle using the updated template for ii, subband in enumerate(wdd.data): pulse_offset = psr_utils.measure_phase_corr(subband, new_template, zoom=1) bin_offsets[ii] = int(round(spd.waterfall_nbins*pulse_offset)) # Calculate the various metrics if method == "GOODFRAC": # good fraction wigglescore = sum(abs(bin_offsets) < TOL*spd.waterfall_nbins)/ \ float(spd.waterfall_nsubs) elif method == "WANDER": # total wander wigglescore = sum(abs(bin_offsets))/(spd.waterfall_nbins*spd.waterfall_nsubs) elif method == "OFFSTD": # offset std wigglescore = bin_offsets.std() elif method == "OFFMAX": # offset max wigglescore = bin_offsets.max() else: raise utils.RatingError("Unrecognized method for wiggle " \ "rating (%s)" % method) return wigglescore
def get_phase_shift(self, phases, weights, polyco_phase0): # Compute phase at start of this block if options.profile: polyco_phase0 = 0.0 else: phases -= polyco_phase0 phases[phases < 0.] += 1 profile = np.histogram(phases, bins=self.bins)[0] # This is older version from Matthew Kerr #profile = np.histogram(phases,bins=self.bins[:-1])[0] if not self.profile_only: # Compute shift from profile # Try using FFTFIT first shift, eshift, snr, esnr, b, errb, ngood = self._measure_phase( profile, self.template, True) # tau and tau_err are the predicted phase of the pulse arrival tau, tau_err = shift / len(profile), eshift / len(profile) # Note: "error" flags are shift = 0.0 and eshift = 999.0 # If that failed, use a time-domain correlation if (np.fabs(shift) < 1e-7 and np.fabs(eshift - 999.0) < 1e-7): print >> sys.stderr, "Warning! Bad return from FFTFIT. Using PRESTO correlation..." # Not enough structure in the template profile for FFTFIT # so use time-domain correlations instead tau = psr_utils.measure_phase_corr(profile, self.template) # This needs to be changed tau_err = 0.1 / len(profile) #tau = np.random.rand(1)[0];tau_err = np.random.rand(1)[0]*0.01 # testing redchi, prob = self._prof_chisq(profile) return tau, tau_err, prob, 0 else: # This doesn't work very well since it doesn't pause after the any # but the first plot. pl.ioff() #does this help the pausing problem? pl.figure(1) bbins = np.arange(2.0 * len(profile)) / len(profile) pl.bar(bbins, np.concatenate((profile, profile)), width=bbins[1]) #bins = np.arange(2.0*len(profile)+1)/len(profile) #pl.plot(bins,list(profile)+list(profile)+[0.0],linestyle='steps-post') pl.grid(1) pl.xlabel('Pulse Phase') pl.ylabel('Number of Photons') #pl.title('Profile') pl.show() of = file('profile.bestprof', "w") print >> of, "# Profile generated by polyfold.py" for i, np in zip(range(len(profile)), profile): print >> of, "%d %d" % (i, np) of.close() return 0, 0, 0, 0
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 getErr(profile,templatefilenm): '''Based off of Pulsar Timing and Relativistic Gravity, J.H. Taylor, Phil. Trans. R. Soc. Lond. A 1992 341, 117-134 Appendix A Usage: give this a profile, a template, and a number of harmonics and it will calculate the offset and output an error''' #################################################################### ### Calculate sigscal ### #################################################################### k=int(len(profile)/2) template = psr_utils.read_profile(templatefilenm, normalize=0) template=template profile=profile a=1 offset=psr_utils.measure_phase_corr(profile-min(profile), template-min(template)) Pfft=FFT.rfft(profile-min(profile)) Tfft=FFT.rfft(template-min(template)) Pamp=[] Tamp=[] Pph=[] Tph=[] for i in range(0,k): Pamp.append(sqrt(real(Pfft[i]*conjugate(Pfft[i])))) Tamp.append(sqrt(real(Tfft[i]*conjugate(Tfft[i])))) Pph.append(arctan(1*imag(Pfft[i])/real(Pfft[i]))) Tph.append(arctan(1*imag(Tfft[i])/real(Tfft[i]))) b=0 total=0 denom=0 for i in range(1,k): b+=Pamp[i]*Tamp[i]*cos(Tph[i]-Pph[i]+i*offset*2*pi) total+=Tamp[i]*Tamp[i] denom+=i*i*Pamp[i]*Tamp[i]*cos(Tph[i]-Pph[i]+i*offset*2*pi) b=b/total sigscale=(abs(1/(2*b*denom))) ##################################################################### ### Done SigScale, start Poisson Variations ### ##################################################################### it=1000#do 'it' iterations variation=Num.zeros(len(profile)) Offsets=[] for i in range (0, it): for j in range (0,len(profile)): if profile[j]>=0: variation[j]=double(Num.random.poisson(profile[j],1)) if profile[j]<=0: variation[j]=0 Offsets.append(psr_utils.measure_phase_corr(variation-min(variation), template-min(template))) Offsets=np.array(Offsets) #This fixes the error being way too big is the shift was around 0 or 1 (The std # would then be averaging values near 0 and 1) k=0 for i in range (0,len(Offsets)): Offsets[i]= Offsets[i] - offset; if Offsets[i] < -0.5: Offsets[i] += 1.0 if Offsets[i] > 0.5: Offsets[i] -= 1.0 if abs(Offsets[i]) > 0.2: Offsets[i]=0 k=k+1 if k>=1: sys.stderr.write("Warning: May be Double peaked, attempting to correct:\nThere are "+str(k)+ " of "+ str(it) + " offsets > 0.2 phase away from the average offset .\n") sigma=std(Offsets) #print 'sigma = ',sigma return sigma
sys.stderr.write("Note: Downsampling the data for '%s'\n"%fold_pfd.filenm) try: # Try using FFTFIT first shift,eshift,snr,esnr,b,errb,ngood = measure_phase(prof, template, rotate_prof) # tau and tau_err are the predicted phase of the pulse arrival tau, tau_err = shift/len(prof), eshift/len(prof) # Note: "error" flags are shift = 0.0 and eshift = 999.0 # If that failed, use a time-domain correlation if (Num.fabs(shift) < 1e-7 and Num.fabs(eshift-999.0) < 1e-7): sys.stderr.write('Warning! Bad return from FFTFIT. Using PRESTO correlation...\n') # Not enough structure in the template profile for FFTFIT # so use time-domain correlations instead tau = 1-psr_utils.measure_phase_corr(prof, template) tau_err = getErr(prof,templatefilenm)#Use poisson error estimate # Send the TOA to STDOUT toaf = t0f + (tau*p + offset)/SECPERDAY + sumsubdelays[jj] newdays = int(Num.floor(toaf)) psr_utils.write_princeton_toa(t0i+newdays, toaf-newdays, tau_err*p*1000000.0, 0000, fold_pfd.bestdm, obs=obs, name=str(sys.argv[-1][5:14]))#[5:13])) if (otherouts): print "FFTFIT results: b = %.4g +/- %.4g SNR = %.4g +/- %.4g" % \ (b, errb, snr, esnr) print "Offset= ", tau, " +/- ", tau_err except ValueError, fftfit.error:
# Note: "error" flags are shift = 0.0 and eshift = 999.0 # If that failed, use a time-domain correlation if (Num.fabs(shift) < 1e-7 and Num.fabs(eshift - 999.0) < 1e-7): sys.stderr.write( "Warning! Bad return from FFTFIT. May be due to inadequate signal-to-noise.\n" ) tau = None if tau is None: sys.stderr.write( "Warning: using PRESTO correlation - reported error is incorrect...\n" ) # Not enough structure in the template profile for FFTFIT # so use time-domain correlations instead tau = psr_utils.measure_phase_corr(prof, template) # This needs to be changed tau_err = 0.1 / len(prof) # Calculate correction for dedispersion to true channel # center freqs that used a slightly different pulse # period. dd_phs_2 = subdelays2[jj] * (1.0 / p - 1.0 / p_dedisp) # Sum up several phase shifts tau_tot = Num.fmod(tau + sumsubdelays_phs[jj] + dd_phs_2 + 3.0, 1.0) if (tau_tot > 0.5): tau_tot -= 1.0 # Send the TOA to STDOUT toaf = t0f + (tau_tot * p + offset) / SECPERDAY
def Phase_Wiggle_Ratings(pfd, method="GOODFRAC"): """ Calculate a metric for the phase wiggle in time and frequency. Parameters ---------- pfd : class An instance of the prepfold.pfd class method : string The method to use to calculate the phase wiggle metrics \"GOODFRAC\" - The fraction of sub-intervals/sub-bands with a wiggle less than some threshold \"WANDER\" - The total phase wander normalized by the number of profile bins and the number of sub-intervals/sub-bands Returns ------- names : list A list of ratings names ratings : list A list of ratings values """ # The ratings names name1 = "Phase_Wiggle_Time" name2 = "Phase_Wiggle_Freq" # 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 subints. subints = N.sum(pfd.profs, axis=1) # Get the subbands. subbands = N.sum(pfd.profs, axis=0) # Get the template ("best") profile template = N.sum(subints, axis=0) # Make an array for storing a new template new_template = N.zeros_like(template) # Make an arrary for storing the offsets (in phase bins) bin_offsets_time = N.empty(pfd.npart) bin_offsets_freq = N.empty(pfd.npart) # The following loop creats a better template by removing wiggle, but # it does not change the actual subints for ii,subint in enumerate(subints): # Measure the phase offset phase_offset = PU.measure_phase_corr(subint, template) # The following is needed to put phase offsets on the interval # (-0.5,0.5] if phase_offset > 0.5: phase_offset -= 1.0 # Caclulate the offset in bins bin_offset = int(round(pfd.proflen*phase_offset)) # Update the new template new_template += PU.rotate(subint, -bin_offset) # Now calculate the wiggle using the updated template for ii,(subint,subband) in enumerate(zip(subints,subbands)): phase_offset_time = PU.measure_phase_corr(subint, new_template) if phase_offset_time > 0.5: phase_offset_time -= 1.0 bin_offsets_time[ii] = int(round(pfd.proflen*phase_offset_time)) phase_offset_freq = PU.measure_phase_corr(subband, new_template) if phase_offset_freq > 0.5: phase_offset_freq -= 1.0 bin_offsets_freq[ii] = int(round(pfd.proflen*phase_offset_freq)) # Calcultae the various metrics good_fraction_time = sum(abs(bin_offsets_time) < \ PHASE_DRIFT_TOLERANCE*pfd.proflen)/ \ float(pfd.npart) total_wander_time = sum(abs(bin_offsets_time))/(pfd.proflen*pfd.npart) good_fraction_freq = sum(abs(bin_offsets_freq) < \ PHASE_DRIFT_TOLERANCE*pfd.proflen)/ \ float(pfd.npart) total_wander_freq = sum(abs(bin_offsets_freq))/(pfd.proflen*pfd.nsub) # Make the appropriate metric the rating if method == "GOODFRAC": rating1 = good_fraction_time rating2 = good_fraction_freq if method == "WANDER" : rating1 = total_wander_time rating2 = total_wander_freq return [name1,name2],[rating1,rating2]
def Phase_Wiggle_Ratings(pfd, method="GOODFRAC"): """ Calculate a metric for the phase wiggle in time and frequency. Parameters ---------- pfd : class An instance of the prepfold.pfd class method : string The method to use to calculate the phase wiggle metrics \"GOODFRAC\" - The fraction of sub-intervals/sub-bands with a wiggle less than some threshold \"WANDER\" - The total phase wander normalized by the number of profile bins and the number of sub-intervals/sub-bands Returns ------- names : list A list of ratings names ratings : list A list of ratings values """ # The ratings names name1 = "Phase_Wiggle_Time" name2 = "Phase_Wiggle_Freq" # 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 subints. subints = N.sum(pfd.profs, axis=1) # Get the subbands. subbands = N.sum(pfd.profs, axis=0) # Get the template ("best") profile template = N.sum(subints, axis=0) # Make an array for storing a new template new_template = N.zeros_like(template) # Make an arrary for storing the offsets (in phase bins) bin_offsets_time = N.empty(pfd.npart) bin_offsets_freq = N.empty(pfd.npart) # The following loop creats a better template by removing wiggle, but # it does not change the actual subints for ii, subint in enumerate(subints): # Measure the phase offset phase_offset = PU.measure_phase_corr(subint, template) # The following is needed to put phase offsets on the interval # (-0.5,0.5] if phase_offset > 0.5: phase_offset -= 1.0 # Caclulate the offset in bins bin_offset = int(round(pfd.proflen * phase_offset)) # Update the new template new_template += PU.rotate(subint, -bin_offset) # Now calculate the wiggle using the updated template for ii, (subint, subband) in enumerate(zip(subints, subbands)): phase_offset_time = PU.measure_phase_corr(subint, new_template) if phase_offset_time > 0.5: phase_offset_time -= 1.0 bin_offsets_time[ii] = int(round(pfd.proflen * phase_offset_time)) phase_offset_freq = PU.measure_phase_corr(subband, new_template) if phase_offset_freq > 0.5: phase_offset_freq -= 1.0 bin_offsets_freq[ii] = int(round(pfd.proflen * phase_offset_freq)) # Calcultae the various metrics good_fraction_time = sum(abs(bin_offsets_time) < \ PHASE_DRIFT_TOLERANCE*pfd.proflen)/ \ float(pfd.npart) total_wander_time = sum(abs(bin_offsets_time)) / (pfd.proflen * pfd.npart) good_fraction_freq = sum(abs(bin_offsets_freq) < \ PHASE_DRIFT_TOLERANCE*pfd.proflen)/ \ float(pfd.npart) total_wander_freq = sum(abs(bin_offsets_freq)) / (pfd.proflen * pfd.nsub) # Make the appropriate metric the rating if method == "GOODFRAC": rating1 = good_fraction_time rating2 = good_fraction_freq if method == "WANDER": rating1 = total_wander_time rating2 = total_wander_freq return [name1, name2], [rating1, rating2]
def getErr(profile, templatefilenm): '''Based off of Pulsar Timing and Relativistic Gravity, J.H. Taylor, Phil. Trans. R. Soc. Lond. A 1992 341, 117-134 Appendix A Usage: give this a profile, a template, and a number of harmonics and it will calculate the offset and output an error''' #################################################################### ### Calculate sigscal ### #################################################################### k = int(len(profile) / 2) template = psr_utils.read_profile(templatefilenm, normalize=0) template = template profile = profile a = 1 offset = psr_utils.measure_phase_corr(profile - min(profile), template - min(template)) Pfft = FFT.rfft(profile - min(profile)) Tfft = FFT.rfft(template - min(template)) Pamp = [] Tamp = [] Pph = [] Tph = [] for i in range(0, k): Pamp.append(sqrt(real(Pfft[i] * conjugate(Pfft[i])))) Tamp.append(sqrt(real(Tfft[i] * conjugate(Tfft[i])))) Pph.append(arctan(1 * imag(Pfft[i]) / real(Pfft[i]))) Tph.append(arctan(1 * imag(Tfft[i]) / real(Tfft[i]))) b = 0 total = 0 denom = 0 for i in range(1, k): b += Pamp[i] * Tamp[i] * cos(Tph[i] - Pph[i] + i * offset * 2 * pi) total += Tamp[i] * Tamp[i] denom += i * i * Pamp[i] * Tamp[i] * cos(Tph[i] - Pph[i] + i * offset * 2 * pi) b = b / total sigscale = (abs(1 / (2 * b * denom))) ##################################################################### ### Done SigScale, start Poisson Variations ### ##################################################################### it = 1000 #do 'it' iterations variation = Num.zeros(len(profile)) Offsets = [] for i in range(0, it): for j in range(0, len(profile)): if profile[j] >= 0: variation[j] = double(Num.random.poisson(profile[j], 1)) if profile[j] <= 0: variation[j] = 0 Offsets.append( psr_utils.measure_phase_corr(variation - min(variation), template - min(template))) Offsets = np.array(Offsets) #This fixes the error being way too big is the shift was around 0 or 1 (The std # would then be averaging values near 0 and 1) k = 0 for i in range(0, len(Offsets)): Offsets[i] = Offsets[i] - offset if Offsets[i] < -0.5: Offsets[i] += 1.0 if Offsets[i] > 0.5: Offsets[i] -= 1.0 if abs(Offsets[i]) > 0.2: Offsets[i] = 0 k = k + 1 if k >= 1: sys.stderr.write( "Warning: May be Double peaked, attempting to correct:\nThere are " + str(k) + " of " + str(it) + " offsets > 0.2 phase away from the average offset .\n") sigma = std(Offsets) #print 'sigma = ',sigma return sigma