def _spectrum_function(self): events = self.events1 for i, eint in show_progress(enumerate(self.energy_intervals)): sub_events = self._get_times_from_energy_range(events, eint, use_pi=self.use_pi) sp = sub_events.size self.spectrum[i] = sp self.spectrum_error[i] = np.sqrt(sp)
def _spectrum_function(self): # Extract events from the reference band and calculate the PDS and # the Poisson noise level. ref_events = self._get_times_from_energy_range(self.events2, self.ref_band[0]) countrate_ref = get_average_ctrate(ref_events, self.gti, self.segment_size) ref_power_noise = poisson_level(norm="abs", meanrate=countrate_ref) results = avg_pds_from_events(ref_events, self.gti, self.segment_size, self.bin_time, silent=True, norm="abs") freq = results["freq"] ref_power = results["power"] m_ave = results.meta["m"] # Select the frequency range to be averaged for the measurement. good = (freq >= self.freq_interval[0]) & (freq < self.freq_interval[1]) n_ave_bin = np.count_nonzero(good) mean_ref_power = np.mean(ref_power[good]) m_tot = m_ave * n_ave_bin # Frequency resolution delta_nu = n_ave_bin * self.delta_nu for i, eint in enumerate(show_progress(self.energy_intervals)): # Extract events from the subject band sub_events = self._get_times_from_energy_range(self.events1, eint) countrate_sub = get_average_ctrate(sub_events, self.gti, self.segment_size) sub_power_noise = poisson_level(norm="abs", meanrate=countrate_sub) results_cross = avg_cs_from_events( sub_events, ref_events, self.gti, self.segment_size, self.bin_time, silent=True, norm="abs", ) results_ps = avg_pds_from_events(sub_events, self.gti, self.segment_size, self.bin_time, silent=True, norm="abs") if results_cross is None or results_ps is None: continue cross = results_cross["power"] sub_power = results_ps["power"] mean = results_ps.meta["mean"] # Is the subject band overlapping with the reference band? # This will be used to correct the error bars, following # Ingram 2019. common_ref = self.same_events and len( cross_two_gtis([eint], self.ref_band)) > 0 Cmean = np.mean(cross[good]) if common_ref: # Equation 6 from Ingram+2019 Cmean -= sub_power_noise Cmean_real = np.abs(Cmean) mean_sub_power = np.mean(sub_power[good]) _, _, _, Ce = error_on_averaged_cross_spectrum( Cmean, mean_sub_power, mean_ref_power, m_tot, sub_power_noise, ref_power_noise, common_ref=common_ref) if not self.return_complex: Cmean = Cmean_real # Convert the cross spectrum to a covariance. cov, cov_e = cross_to_covariance(np.asarray([Cmean, Ce]), mean_ref_power, ref_power_noise, delta_nu) meanrate = mean / self.bin_time if self.norm == "frac": cov, cov_e = cov / meanrate, cov_e / meanrate self.spectrum[i] = cov self.spectrum_error[i] = cov_e
def _spectrum_function(self): # Extract the photon arrival times from the reference band ref_events = self._get_times_from_energy_range(self.events2, self.ref_band[0]) ref_power_noise = poisson_level(norm="none", n_ph=ref_events.size) # Calculate the PDS in the reference band. Needed to calculate errors. results = avg_pds_from_events(ref_events, self.gti, self.segment_size, self.bin_time, silent=True, norm="none") freq = results["freq"] ref_power = results["power"] m_ave = results.meta["m"] # Get the frequency bins to be averaged in the final results. good = self._get_good_frequency_bins(freq) mean_ref_power = np.mean(ref_power[good]) n_ave_bin = np.count_nonzero(good) m_tot = n_ave_bin * m_ave f = (self.freq_interval[0] + self.freq_interval[1]) / 2 for i, eint in enumerate(show_progress(self.energy_intervals)): # Extract the photon arrival times from the subject band sub_events = self._get_times_from_energy_range(self.events1, eint) sub_power_noise = poisson_level(norm="none", n_ph=sub_events.size) results_cross = avg_cs_from_events(sub_events, ref_events, self.gti, self.segment_size, self.bin_time, silent=True, norm="none") results_ps = avg_pds_from_events(sub_events, self.gti, self.segment_size, self.bin_time, silent=True, norm="none") if results_cross is None or results_ps is None: continue cross = results_cross["power"] sub_power = results_ps["power"] Cmean = np.mean(cross[good]) mean_sub_power = np.mean(sub_power[good]) # Is the subject band overlapping with the reference band? # This will be used to correct the error bars, following # Ingram 2019. common_ref = self.same_events and len( cross_two_gtis([eint], self.ref_band)) > 0 _, _, phi_e, _ = error_on_averaged_cross_spectrum( Cmean, mean_sub_power, mean_ref_power, m_tot, sub_power_noise, ref_power_noise, common_ref=common_ref) lag = np.mean((np.angle(cross[good]) / (2 * np.pi * freq[good]))) lag_e = phi_e / (2 * np.pi * f) self.spectrum[i] = lag self.spectrum_error[i] = lag_e
def _spectrum_function(self): # Get the frequency bins to be averaged in the final results. good = self._get_good_frequency_bins() n_ave_bin = np.count_nonzero(good) # Get the frequency resolution of the final spectrum. delta_nu_after_mean = self.delta_nu * n_ave_bin for i, eint in enumerate(show_progress(self.energy_intervals)): # Extract events from the subject band and calculate the count rate # and Poisson noise level. sub_events = self._get_times_from_energy_range(self.events1, eint) countrate_sub = get_average_ctrate(sub_events, self.gti, self.segment_size) sub_power_noise = poisson_level(norm="abs", meanrate=countrate_sub) # If we provided the `events2` array, calculate the rms from the # cospectrum, otherwise from the PDS if not self.same_events: # Extract events from the subject band in the other array, and # calculate the count rate and Poisson noise level. sub_events2 = self._get_times_from_energy_range( self.events2, eint) countrate_sub2 = get_average_ctrate(sub_events2, self.gti, self.segment_size) sub2_power_noise = poisson_level(norm="abs", meanrate=countrate_sub2) # Calculate the cross spectrum results = avg_cs_from_events( sub_events, sub_events2, self.gti, self.segment_size, self.bin_time, silent=True, norm="abs", ) if results is None: continue cross = results["power"] m_ave, mean = [results.meta[key] for key in ["m", "mean"]] mean_power = np.mean(cross[good]) power_noise = 0 rmsnoise = np.sqrt(delta_nu_after_mean * np.sqrt(sub_power_noise * sub2_power_noise)) else: results = avg_pds_from_events(sub_events, self.gti, self.segment_size, self.bin_time, silent=True, norm="abs") if results is None: continue sub_power = results["power"] m_ave, mean = [results.meta[key] for key in ["m", "mean"]] mean_power = np.mean(sub_power[good]) power_noise = sub_power_noise rmsnoise = np.sqrt(delta_nu_after_mean * power_noise) meanrate = mean / self.bin_time rms = np.sqrt( np.abs(mean_power - power_noise) * delta_nu_after_mean) # Assume coherence 0, use Ingram+2019 num = rms**4 + rmsnoise**4 + 2 * rms * rmsnoise den = 4 * m_ave * n_ave_bin * rms**2 rms_err = np.sqrt(num / den) if self.norm == "frac": rms, rms_err = rms / meanrate, rms_err / meanrate self.spectrum[i] = rms self.spectrum_error[i] = rms_err