def __init__(self, low_frequency_cutoff, high_frequency_cutoff, snr_threshold, tlen, delta_f, dtype, segment_list, template_output, use_cluster, downsample_factor=1, upsample_threshold=1, upsample_method='pruned_fft', gpu_callback_method='none'): """ Create a matched filter engine. Parameters ---------- low_frequency_cutoff : {None, float}, optional The frequency to begin the filter calculation. If None, begin at the first frequency after DC. high_frequency_cutoff : {None, float}, optional The frequency to stop the filter calculation. If None, continue to the the nyquist frequency. snr_threshold : float The minimum snr to return when filtering segment_list : list List of FrequencySeries that are the Fourier-transformed data segments template_output : complex64 Array of memory given as the 'out' parameter to waveform.FilterBank use_cluster : boolean If true, cluster triggers above threshold using a window; otherwise, only apply a threshold. downsample_factor : {1, int}, optional The factor by which to reduce the sample rate when doing a heirarchical matched filter upsample_threshold : {1, float}, optional The fraction of the snr_threshold to trigger on the subsampled filter. upsample_method : {pruned_fft, str} The method to upsample or interpolate the reduced rate filter. """ # Assuming analysis time is constant across templates and segments, also # delta_f is constant across segments. self.tlen = tlen self.flen = self.tlen / 2 + 1 self.delta_f = delta_f self.dtype = dtype self.snr_threshold = snr_threshold self.flow = low_frequency_cutoff self.fhigh = high_frequency_cutoff self.gpu_callback_method = gpu_callback_method if downsample_factor == 1: self.snr_mem = zeros(self.tlen, dtype=self.dtype) self.corr_mem = zeros(self.tlen, dtype=self.dtype) self.segments = segment_list if use_cluster: self.matched_filter_and_cluster = self.full_matched_filter_and_cluster # setup the threasholding/clustering operations for each segment self.threshold_and_clusterers = [] for seg in self.segments: thresh = events.ThresholdCluster(self.snr_mem[seg.analyze]) self.threshold_and_clusterers.append(thresh) else: self.matched_filter_and_cluster = self.full_matched_filter_thresh_only # Assuming analysis time is constant across templates and segments, also # delta_f is constant across segments. self.htilde = template_output self.kmin, self.kmax = get_cutoff_indices(self.flow, self.fhigh, self.delta_f, self.tlen) # Set up the correlation operations for each analysis segment corr_slice = slice(self.kmin, self.kmax) self.correlators = [] for seg in self.segments: corr = Correlator(self.htilde[corr_slice], seg[corr_slice], self.corr_mem[corr_slice]) self.correlators.append(corr) # setup up the ifft we will do self.ifft = IFFT(self.corr_mem, self.snr_mem) elif downsample_factor >= 1: self.matched_filter_and_cluster = self.heirarchical_matched_filter_and_cluster self.downsample_factor = downsample_factor self.upsample_method = upsample_method self.upsample_threshold = upsample_threshold N_full = self.tlen N_red = N_full / downsample_factor self.kmin_full, self.kmax_full = get_cutoff_indices( self.flow, self.fhigh, self.delta_f, N_full) self.kmin_red, _ = get_cutoff_indices(self.flow, self.fhigh, self.delta_f, N_red) if self.kmax_full < N_red: self.kmax_red = self.kmax_full else: self.kmax_red = N_red - 1 self.snr_mem = zeros(N_red, dtype=self.dtype) self.corr_mem_full = FrequencySeries(zeros(N_full, dtype=self.dtype), delta_f=self.delta_f) self.corr_mem = Array(self.corr_mem_full[0:N_red], copy=False) self.inter_vec = zeros(N_full, dtype=self.dtype) else: raise ValueError("Invalid downsample factor")
class MatchedFilterControl(object): def __init__(self, low_frequency_cutoff, high_frequency_cutoff, snr_threshold, tlen, delta_f, dtype, segment_list, template_output, use_cluster, downsample_factor=1, upsample_threshold=1, upsample_method='pruned_fft', gpu_callback_method='none'): """ Create a matched filter engine. Parameters ---------- low_frequency_cutoff : {None, float}, optional The frequency to begin the filter calculation. If None, begin at the first frequency after DC. high_frequency_cutoff : {None, float}, optional The frequency to stop the filter calculation. If None, continue to the the nyquist frequency. snr_threshold : float The minimum snr to return when filtering segment_list : list List of FrequencySeries that are the Fourier-transformed data segments template_output : complex64 Array of memory given as the 'out' parameter to waveform.FilterBank use_cluster : boolean If true, cluster triggers above threshold using a window; otherwise, only apply a threshold. downsample_factor : {1, int}, optional The factor by which to reduce the sample rate when doing a heirarchical matched filter upsample_threshold : {1, float}, optional The fraction of the snr_threshold to trigger on the subsampled filter. upsample_method : {pruned_fft, str} The method to upsample or interpolate the reduced rate filter. """ # Assuming analysis time is constant across templates and segments, also # delta_f is constant across segments. self.tlen = tlen self.flen = self.tlen / 2 + 1 self.delta_f = delta_f self.dtype = dtype self.snr_threshold = snr_threshold self.flow = low_frequency_cutoff self.fhigh = high_frequency_cutoff self.gpu_callback_method = gpu_callback_method if downsample_factor == 1: self.snr_mem = zeros(self.tlen, dtype=self.dtype) self.corr_mem = zeros(self.tlen, dtype=self.dtype) self.segments = segment_list if use_cluster: self.matched_filter_and_cluster = self.full_matched_filter_and_cluster # setup the threasholding/clustering operations for each segment self.threshold_and_clusterers = [] for seg in self.segments: thresh = events.ThresholdCluster(self.snr_mem[seg.analyze]) self.threshold_and_clusterers.append(thresh) else: self.matched_filter_and_cluster = self.full_matched_filter_thresh_only # Assuming analysis time is constant across templates and segments, also # delta_f is constant across segments. self.htilde = template_output self.kmin, self.kmax = get_cutoff_indices(self.flow, self.fhigh, self.delta_f, self.tlen) # Set up the correlation operations for each analysis segment corr_slice = slice(self.kmin, self.kmax) self.correlators = [] for seg in self.segments: corr = Correlator(self.htilde[corr_slice], seg[corr_slice], self.corr_mem[corr_slice]) self.correlators.append(corr) # setup up the ifft we will do self.ifft = IFFT(self.corr_mem, self.snr_mem) elif downsample_factor >= 1: self.matched_filter_and_cluster = self.heirarchical_matched_filter_and_cluster self.downsample_factor = downsample_factor self.upsample_method = upsample_method self.upsample_threshold = upsample_threshold N_full = self.tlen N_red = N_full / downsample_factor self.kmin_full, self.kmax_full = get_cutoff_indices( self.flow, self.fhigh, self.delta_f, N_full) self.kmin_red, _ = get_cutoff_indices(self.flow, self.fhigh, self.delta_f, N_red) if self.kmax_full < N_red: self.kmax_red = self.kmax_full else: self.kmax_red = N_red - 1 self.snr_mem = zeros(N_red, dtype=self.dtype) self.corr_mem_full = FrequencySeries(zeros(N_full, dtype=self.dtype), delta_f=self.delta_f) self.corr_mem = Array(self.corr_mem_full[0:N_red], copy=False) self.inter_vec = zeros(N_full, dtype=self.dtype) else: raise ValueError("Invalid downsample factor") def full_matched_filter_and_cluster(self, segnum, template_norm, window): """ Return the complex snr and normalization. Calculated the matched filter, threshold, and cluster. Parameters ---------- segnum : int Index into the list of segments at MatchedFilterControl construction against which to filter. template_norm : float The htilde, template normalization factor. window : int Size of the window over which to cluster triggers, in samples Returns ------- snr : TimeSeries A time series containing the complex snr. norm : float The normalization of the complex snr. corrrelation: FrequencySeries A frequency series containing the correlation vector. idx : Array List of indices of the triggers. snrv : Array The snr values at the trigger locations. """ norm = (4.0 * self.delta_f) / sqrt(template_norm) self.correlators[segnum].correlate() self.ifft.execute() snrv, idx = self.threshold_and_clusterers[ segnum].threshold_and_cluster(self.snr_threshold / norm, window) if len(idx) == 0: return [], [], [], [], [] logging.info("%s points above threshold" % str(len(idx))) return self.snr_mem, norm, self.corr_mem, idx, snrv def full_matched_filter_thresh_only(self, segnum, template_norm, window): """ Return the complex snr and normalization. Calculated the matched filter, threshold, and cluster. Parameters ---------- segnum : int Index into the list of segments at MatchedFilterControl construction against which to filter. template_norm : float The htilde, template normalization factor. window : int Size of the window over which to cluster triggers, in samples. This is IGNORED by this function, and provided only for API compatibility. Returns ------- snr : TimeSeries A time series containing the complex snr. norm : float The normalization of the complex snr. corrrelation: FrequencySeries A frequency series containing the correlation vector. idx : Array List of indices of the triggers. snrv : Array The snr values at the trigger locations. """ norm = (4.0 * self.stilde_delta_f) / sqrt(template_norm) self.correlators[segnum].correlate() self.ifft.execute() snrv, idx = events.threshold_only( self.snr_mem[self.segments[segnum].analyze], self.snr_threshold / norm) if len(idx) == 0: return [], [], [], [], [] logging.info("%s points above threshold" % str(len(idx))) return self.snr_mem, norm, self.corr_mem, idx, snrv def heirarchical_matched_filter_and_cluster(self, htilde, template_norm, stilde, window): """ Return the complex snr and normalization. Calculated the matched filter, threshold, and cluster. Parameters ---------- htilde : FrequencySeries The template waveform. Must come from the FilterBank class. template_norm : float The htilde, template normalization factor. stilde : FrequencySeries The strain data to be filtered. window : int The size of the cluster window in samples. Returns ------- snr : TimeSeries A time series containing the complex snr at the reduced sample rate. norm : float The normalization of the complex snr. corrrelation: FrequencySeries A frequency series containing the correlation vector. idx : Array List of indices of the triggers. snrv : Array The snr values at the trigger locations. """ from pycbc.fft.fftw_pruned import pruned_c2cifft, fft_transpose norm = (4.0 * stilde.delta_f) / sqrt(template_norm) correlate(htilde[self.kmin_red:self.kmax_red], stilde[self.kmin_red:self.kmax_red], self.corr_mem[self.kmin_red:self.kmax_red]) ifft(self.corr_mem, self.snr_mem) if not hasattr(stilde, 'red_analyze'): stilde.red_analyze = \ slice(stilde.analyze.start/self.downsample_factor, stilde.analyze.stop/self.downsample_factor) idx_red, snrv_red = events.threshold( self.snr_mem[stilde.red_analyze], self.snr_threshold / norm * self.upsample_threshold) if len(idx_red) == 0: return [], None, [], [], [] idx_red, _ = events.cluster_reduce(idx_red, snrv_red, window / self.downsample_factor) logging.info("%s points above threshold at reduced resolution"\ %(str(len(idx_red)),)) # The fancy upsampling is here if self.upsample_method == 'pruned_fft': idx = (idx_red + stilde.analyze.start/self.downsample_factor)\ * self.downsample_factor idx = smear(idx, self.downsample_factor) # cache transposed versions of htilde and stilde if not hasattr(self.corr_mem_full, 'transposed'): self.corr_mem_full.transposed = zeros(len(self.corr_mem_full), dtype=self.dtype) if not hasattr(htilde, 'transposed'): htilde.transposed = zeros(len(self.corr_mem_full), dtype=self.dtype) htilde.transposed[self.kmin_full:self.kmax_full] = htilde[ self.kmin_full:self.kmax_full] htilde.transposed = fft_transpose(htilde.transposed) if not hasattr(stilde, 'transposed'): stilde.transposed = zeros(len(self.corr_mem_full), dtype=self.dtype) stilde.transposed[self.kmin_full:self.kmax_full] = stilde[ self.kmin_full:self.kmax_full] stilde.transposed = fft_transpose(stilde.transposed) correlate(htilde.transposed, stilde.transposed, self.corr_mem_full.transposed) snrv = pruned_c2cifft(self.corr_mem_full.transposed, self.inter_vec, idx, pretransposed=True) idx = idx - stilde.analyze.start idx2, snrv = events.threshold(Array(snrv, copy=False), self.snr_threshold / norm) if len(idx2) > 0: correlate(htilde[self.kmax_red:self.kmax_full], stilde[self.kmax_red:self.kmax_full], self.corr_mem_full[self.kmax_red:self.kmax_full]) idx, snrv = events.cluster_reduce(idx[idx2], snrv, window) else: idx, snrv = [], [] logging.info("%s points at full rate and clustering" % len(idx)) return self.snr_mem, norm, self.corr_mem_full, idx, snrv else: raise ValueError("Invalid upsample method")
def __init__(self, low_frequency_cutoff, high_frequency_cutoff, snr_threshold, tlen, delta_f, dtype, segment_list, template_output, use_cluster, downsample_factor=1, upsample_threshold=1, upsample_method='pruned_fft', gpu_callback_method='none', cluster_function='symmetric'): """ Create a matched filter engine. Parameters ---------- low_frequency_cutoff : {None, float}, optional The frequency to begin the filter calculation. If None, begin at the first frequency after DC. high_frequency_cutoff : {None, float}, optional The frequency to stop the filter calculation. If None, continue to the the nyquist frequency. snr_threshold : float The minimum snr to return when filtering segment_list : list List of FrequencySeries that are the Fourier-transformed data segments template_output : complex64 Array of memory given as the 'out' parameter to waveform.FilterBank use_cluster : boolean If true, cluster triggers above threshold using a window; otherwise, only apply a threshold. downsample_factor : {1, int}, optional The factor by which to reduce the sample rate when doing a heirarchical matched filter upsample_threshold : {1, float}, optional The fraction of the snr_threshold to trigger on the subsampled filter. upsample_method : {pruned_fft, str} The method to upsample or interpolate the reduced rate filter. cluster_function : {symmetric, str}, optional Which method is used to cluster triggers over time. If 'findchirp', a sliding forward window; if 'symmetric', each window's peak is compared to the windows before and after it, and only kept as a trigger if larger than both. """ # Assuming analysis time is constant across templates and segments, also # delta_f is constant across segments. self.tlen = tlen self.flen = self.tlen / 2 + 1 self.delta_f = delta_f self.dtype = dtype self.snr_threshold = snr_threshold self.flow = low_frequency_cutoff self.fhigh = high_frequency_cutoff self.gpu_callback_method = gpu_callback_method if cluster_function not in ['symmetric', 'findchirp']: raise ValueError("MatchedFilter: 'cluster_function' must be either 'symmetric' or 'findchirp'") self.cluster_function = cluster_function self.segments = segment_list self.htilde = template_output if downsample_factor == 1: self.snr_mem = zeros(self.tlen, dtype=self.dtype) self.corr_mem = zeros(self.tlen, dtype=self.dtype) if use_cluster and (cluster_function == 'symmetric'): self.matched_filter_and_cluster = self.full_matched_filter_and_cluster_symm # setup the threasholding/clustering operations for each segment self.threshold_and_clusterers = [] for seg in self.segments: thresh = events.ThresholdCluster(self.snr_mem[seg.analyze]) self.threshold_and_clusterers.append(thresh) elif use_cluster and (cluster_function == 'findchirp'): self.matched_filter_and_cluster = self.full_matched_filter_and_cluster_fc else: self.matched_filter_and_cluster = self.full_matched_filter_thresh_only # Assuming analysis time is constant across templates and segments, also # delta_f is constant across segments. self.kmin, self.kmax = get_cutoff_indices(self.flow, self.fhigh, self.delta_f, self.tlen) # Set up the correlation operations for each analysis segment corr_slice = slice(self.kmin, self.kmax) self.correlators = [] for seg in self.segments: corr = Correlator(self.htilde[corr_slice], seg[corr_slice], self.corr_mem[corr_slice]) self.correlators.append(corr) # setup up the ifft we will do self.ifft = IFFT(self.corr_mem, self.snr_mem) elif downsample_factor >= 1: self.matched_filter_and_cluster = self.heirarchical_matched_filter_and_cluster self.downsample_factor = downsample_factor self.upsample_method = upsample_method self.upsample_threshold = upsample_threshold N_full = self.tlen N_red = N_full / downsample_factor self.kmin_full, self.kmax_full = get_cutoff_indices(self.flow, self.fhigh, self.delta_f, N_full) self.kmin_red, _ = get_cutoff_indices(self.flow, self.fhigh, self.delta_f, N_red) if self.kmax_full < N_red: self.kmax_red = self.kmax_full else: self.kmax_red = N_red - 1 self.snr_mem = zeros(N_red, dtype=self.dtype) self.corr_mem_full = FrequencySeries(zeros(N_full, dtype=self.dtype), delta_f=self.delta_f) self.corr_mem = Array(self.corr_mem_full[0:N_red], copy=False) self.inter_vec = zeros(N_full, dtype=self.dtype) else: raise ValueError("Invalid downsample factor")
class MatchedFilterControl(object): def __init__(self, low_frequency_cutoff, high_frequency_cutoff, snr_threshold, tlen, delta_f, dtype, segment_list, template_output, use_cluster, downsample_factor=1, upsample_threshold=1, upsample_method='pruned_fft', gpu_callback_method='none', cluster_function='symmetric'): """ Create a matched filter engine. Parameters ---------- low_frequency_cutoff : {None, float}, optional The frequency to begin the filter calculation. If None, begin at the first frequency after DC. high_frequency_cutoff : {None, float}, optional The frequency to stop the filter calculation. If None, continue to the the nyquist frequency. snr_threshold : float The minimum snr to return when filtering segment_list : list List of FrequencySeries that are the Fourier-transformed data segments template_output : complex64 Array of memory given as the 'out' parameter to waveform.FilterBank use_cluster : boolean If true, cluster triggers above threshold using a window; otherwise, only apply a threshold. downsample_factor : {1, int}, optional The factor by which to reduce the sample rate when doing a heirarchical matched filter upsample_threshold : {1, float}, optional The fraction of the snr_threshold to trigger on the subsampled filter. upsample_method : {pruned_fft, str} The method to upsample or interpolate the reduced rate filter. cluster_function : {symmetric, str}, optional Which method is used to cluster triggers over time. If 'findchirp', a sliding forward window; if 'symmetric', each window's peak is compared to the windows before and after it, and only kept as a trigger if larger than both. """ # Assuming analysis time is constant across templates and segments, also # delta_f is constant across segments. self.tlen = tlen self.flen = self.tlen / 2 + 1 self.delta_f = delta_f self.dtype = dtype self.snr_threshold = snr_threshold self.flow = low_frequency_cutoff self.fhigh = high_frequency_cutoff self.gpu_callback_method = gpu_callback_method if cluster_function not in ['symmetric', 'findchirp']: raise ValueError("MatchedFilter: 'cluster_function' must be either 'symmetric' or 'findchirp'") self.cluster_function = cluster_function self.segments = segment_list self.htilde = template_output if downsample_factor == 1: self.snr_mem = zeros(self.tlen, dtype=self.dtype) self.corr_mem = zeros(self.tlen, dtype=self.dtype) if use_cluster and (cluster_function == 'symmetric'): self.matched_filter_and_cluster = self.full_matched_filter_and_cluster_symm # setup the threasholding/clustering operations for each segment self.threshold_and_clusterers = [] for seg in self.segments: thresh = events.ThresholdCluster(self.snr_mem[seg.analyze]) self.threshold_and_clusterers.append(thresh) elif use_cluster and (cluster_function == 'findchirp'): self.matched_filter_and_cluster = self.full_matched_filter_and_cluster_fc else: self.matched_filter_and_cluster = self.full_matched_filter_thresh_only # Assuming analysis time is constant across templates and segments, also # delta_f is constant across segments. self.kmin, self.kmax = get_cutoff_indices(self.flow, self.fhigh, self.delta_f, self.tlen) # Set up the correlation operations for each analysis segment corr_slice = slice(self.kmin, self.kmax) self.correlators = [] for seg in self.segments: corr = Correlator(self.htilde[corr_slice], seg[corr_slice], self.corr_mem[corr_slice]) self.correlators.append(corr) # setup up the ifft we will do self.ifft = IFFT(self.corr_mem, self.snr_mem) elif downsample_factor >= 1: self.matched_filter_and_cluster = self.heirarchical_matched_filter_and_cluster self.downsample_factor = downsample_factor self.upsample_method = upsample_method self.upsample_threshold = upsample_threshold N_full = self.tlen N_red = N_full / downsample_factor self.kmin_full, self.kmax_full = get_cutoff_indices(self.flow, self.fhigh, self.delta_f, N_full) self.kmin_red, _ = get_cutoff_indices(self.flow, self.fhigh, self.delta_f, N_red) if self.kmax_full < N_red: self.kmax_red = self.kmax_full else: self.kmax_red = N_red - 1 self.snr_mem = zeros(N_red, dtype=self.dtype) self.corr_mem_full = FrequencySeries(zeros(N_full, dtype=self.dtype), delta_f=self.delta_f) self.corr_mem = Array(self.corr_mem_full[0:N_red], copy=False) self.inter_vec = zeros(N_full, dtype=self.dtype) else: raise ValueError("Invalid downsample factor") def full_matched_filter_and_cluster_symm(self, segnum, template_norm, window): """ Return the complex snr and normalization. Calculated the matched filter, threshold, and cluster. Parameters ---------- segnum : int Index into the list of segments at MatchedFilterControl construction against which to filter. template_norm : float The htilde, template normalization factor. window : int Size of the window over which to cluster triggers, in samples Returns ------- snr : TimeSeries A time series containing the complex snr. norm : float The normalization of the complex snr. corrrelation: FrequencySeries A frequency series containing the correlation vector. idx : Array List of indices of the triggers. snrv : Array The snr values at the trigger locations. """ norm = (4.0 * self.delta_f) / sqrt(template_norm) self.correlators[segnum].correlate() self.ifft.execute() snrv, idx = self.threshold_and_clusterers[segnum].threshold_and_cluster(self.snr_threshold / norm, window) if len(idx) == 0: return [], [], [], [], [] logging.info("%s points above threshold" % str(len(idx))) return self.snr_mem, norm, self.corr_mem, idx, snrv def full_matched_filter_and_cluster_fc(self, segnum, template_norm, window): """ Return the complex snr and normalization. Calculated the matched filter, threshold, and cluster. Parameters ---------- segnum : int Index into the list of segments at MatchedFilterControl construction against which to filter. template_norm : float The htilde, template normalization factor. window : int Size of the window over which to cluster triggers, in samples Returns ------- snr : TimeSeries A time series containing the complex snr. norm : float The normalization of the complex snr. corrrelation: FrequencySeries A frequency series containing the correlation vector. idx : Array List of indices of the triggers. snrv : Array The snr values at the trigger locations. """ norm = (4.0 * self.delta_f) / sqrt(template_norm) self.correlators[segnum].correlate() self.ifft.execute() idx, snrv = events.threshold(self.snr_mem[self.segments[segnum].analyze], self.snr_threshold / norm) idx, snrv = events.cluster_reduce(idx, snrv, window) if len(idx) == 0: return [], [], [], [], [] logging.info("%s points above threshold" % str(len(idx))) return self.snr_mem, norm, self.corr_mem, idx, snrv def full_matched_filter_thresh_only(self, segnum, template_norm, window): """ Return the complex snr and normalization. Calculated the matched filter, threshold, and cluster. Parameters ---------- segnum : int Index into the list of segments at MatchedFilterControl construction against which to filter. template_norm : float The htilde, template normalization factor. window : int Size of the window over which to cluster triggers, in samples. This is IGNORED by this function, and provided only for API compatibility. Returns ------- snr : TimeSeries A time series containing the complex snr. norm : float The normalization of the complex snr. corrrelation: FrequencySeries A frequency series containing the correlation vector. idx : Array List of indices of the triggers. snrv : Array The snr values at the trigger locations. """ norm = (4.0 * self.stilde_delta_f) / sqrt(template_norm) self.correlators[segnum].correlate() self.ifft.execute() snrv, idx = events.threshold_only(self.snr_mem[self.segments[segnum].analyze], self.snr_threshold / norm) if len(idx) == 0: return [], [], [], [], [] logging.info("%s points above threshold" % str(len(idx))) return self.snr_mem, norm, self.corr_mem, idx, snrv def heirarchical_matched_filter_and_cluster(self, segnum, template_norm, window): """ Return the complex snr and normalization. Calculated the matched filter, threshold, and cluster. Parameters ---------- segnum : int Index into the list of segments at MatchedFilterControl construction template_norm : float The htilde, template normalization factor. window : int Size of the window over which to cluster triggers, in samples Returns ------- snr : TimeSeries A time series containing the complex snr at the reduced sample rate. norm : float The normalization of the complex snr. corrrelation: FrequencySeries A frequency series containing the correlation vector. idx : Array List of indices of the triggers. snrv : Array The snr values at the trigger locations. """ from pycbc.fft.fftw_pruned import pruned_c2cifft, fft_transpose htilde = self.htilde stilde = self.segments[segnum] norm = (4.0 * stilde.delta_f) / sqrt(template_norm) correlate(htilde[self.kmin_red:self.kmax_red], stilde[self.kmin_red:self.kmax_red], self.corr_mem[self.kmin_red:self.kmax_red]) ifft(self.corr_mem, self.snr_mem) if not hasattr(stilde, 'red_analyze'): stilde.red_analyze = \ slice(stilde.analyze.start/self.downsample_factor, stilde.analyze.stop/self.downsample_factor) idx_red, snrv_red = events.threshold(self.snr_mem[stilde.red_analyze], self.snr_threshold / norm * self.upsample_threshold) if len(idx_red) == 0: return [], None, [], [], [] idx_red, _ = events.cluster_reduce(idx_red, snrv_red, window / self.downsample_factor) logging.info("%s points above threshold at reduced resolution"\ %(str(len(idx_red)),)) # The fancy upsampling is here if self.upsample_method=='pruned_fft': idx = (idx_red + stilde.analyze.start/self.downsample_factor)\ * self.downsample_factor idx = smear(idx, self.downsample_factor) # cache transposed versions of htilde and stilde if not hasattr(self.corr_mem_full, 'transposed'): self.corr_mem_full.transposed = zeros(len(self.corr_mem_full), dtype=self.dtype) if not hasattr(htilde, 'transposed'): htilde.transposed = zeros(len(self.corr_mem_full), dtype=self.dtype) htilde.transposed[self.kmin_full:self.kmax_full] = htilde[self.kmin_full:self.kmax_full] htilde.transposed = fft_transpose(htilde.transposed) if not hasattr(stilde, 'transposed'): stilde.transposed = zeros(len(self.corr_mem_full), dtype=self.dtype) stilde.transposed[self.kmin_full:self.kmax_full] = stilde[self.kmin_full:self.kmax_full] stilde.transposed = fft_transpose(stilde.transposed) correlate(htilde.transposed, stilde.transposed, self.corr_mem_full.transposed) snrv = pruned_c2cifft(self.corr_mem_full.transposed, self.inter_vec, idx, pretransposed=True) idx = idx - stilde.analyze.start idx2, snrv = events.threshold(Array(snrv, copy=False), self.snr_threshold / norm) if len(idx2) > 0: correlate(htilde[self.kmax_red:self.kmax_full], stilde[self.kmax_red:self.kmax_full], self.corr_mem_full[self.kmax_red:self.kmax_full]) idx, snrv = events.cluster_reduce(idx[idx2], snrv, window) else: idx, snrv = [], [] logging.info("%s points at full rate and clustering" % len(idx)) return self.snr_mem, norm, self.corr_mem_full, idx, snrv else: raise ValueError("Invalid upsample method")
def __init__(self, low_frequency_cutoff, high_frequency_cutoff, snr_threshold, tlen, delta_f, dtype, segment_list, template_output, window, downsample_factor=1, upsample_threshold=1, upsample_method='pruned_fft', gpu_callback_method='none'): """ Create a matched filter engine. Parameters ---------- low_frequency_cutoff : {None, float}, optional The frequency to begin the filter calculation. If None, begin at the first frequency after DC. high_frequency_cutoff : {None, float}, optional The frequency to stop the filter calculation. If None, continue to the the nyquist frequency. snr_threshold : float The minimum snr to return when filtering segment_list : list List of FrequencySeries that are the Fourier-transformed data segments template_output : complex64 Array of memory given as the 'out' parameter to waveform.FilterBank window : int The size of the cluster window in samples. downsample_factor : {1, int}, optional The factor by which to reduce the sample rate when doing a heirarchical matched filter upsample_threshold : {1, float}, optional The fraction of the snr_threshold to trigger on the subsampled filter. upsample_method : {pruned_fft, str} The method to upsample or interpolate the reduced rate filter. """ self.tlen = tlen self.flen = self.tlen / 2 + 1 self.delta_f = delta_f self.dtype = dtype self.snr_threshold = snr_threshold self.flow = low_frequency_cutoff self.fhigh = high_frequency_cutoff self.gpu_callback_method = gpu_callback_method if downsample_factor == 1: self.matched_filter_and_cluster = self.full_matched_filter_and_cluster self.snr_mem = zeros(self.tlen, dtype=self.dtype) self.corr_mem = zeros(self.tlen, dtype=self.dtype) self.segments = segment_list # Assuming analysis time is constant across templates and segments, also # delta_f is constant across segments. self.stilde_delta_f = segment_list[0].delta_f self.htilde = template_output self.kmin, self.kmax = get_cutoff_indices(self.flow, self.fhigh, self.segments[0].delta_f, self.tlen) self.corr_slice = slice(self.kmin, self.kmax) self.corr_np = numpy.array(self.corr_mem.data[self.corr_slice], copy = False) self.hcorr = numpy.array(self.htilde.data[self.corr_slice], copy = False) self.correlators = [] for i in range(0, len(self.segments)): self.correlators.append(Correlator(self.hcorr, numpy.array(self.segments[i].data[self.corr_slice], copy = False), self.corr_np)) self.ifft = IFFT(self.corr_mem, self.snr_mem) self.threshold_and_clusterers = [] for i in range(0, len(self.segments)): self.threshold_and_clusterers.append(events.ThresholdCluster( numpy.array(self.snr_mem.data[self.segments[i].analyze], copy=False), window)) elif downsample_factor >= 1: self.matched_filter_and_cluster = self.heirarchical_matched_filter_and_cluster self.downsample_factor = downsample_factor self.upsample_method = upsample_method self.upsample_threshold = upsample_threshold N_full = self.tlen N_red = N_full / downsample_factor self.kmin_full, self.kmax_full = get_cutoff_indices(self.flow, self.fhigh, self.delta_f, N_full) self.kmin_red, _ = get_cutoff_indices(self.flow, self.fhigh, self.delta_f, N_red) if self.kmax_full < N_red: self.kmax_red = self.kmax_full else: self.kmax_red = N_red - 1 self.snr_mem = zeros(N_red, dtype=self.dtype) self.corr_mem_full = FrequencySeries(zeros(N_full, dtype=self.dtype), delta_f=self.delta_f) self.corr_mem = Array(self.corr_mem_full[0:N_red], copy=False) self.inter_vec = zeros(N_full, dtype=self.dtype) else: raise ValueError("Invalid downsample factor")
class MatchedFilterControl(object): def __init__(self, low_frequency_cutoff, high_frequency_cutoff, snr_threshold, tlen, delta_f, dtype, segment_list, template_output, window, downsample_factor=1, upsample_threshold=1, upsample_method='pruned_fft', gpu_callback_method='none'): """ Create a matched filter engine. Parameters ---------- low_frequency_cutoff : {None, float}, optional The frequency to begin the filter calculation. If None, begin at the first frequency after DC. high_frequency_cutoff : {None, float}, optional The frequency to stop the filter calculation. If None, continue to the the nyquist frequency. snr_threshold : float The minimum snr to return when filtering segment_list : list List of FrequencySeries that are the Fourier-transformed data segments template_output : complex64 Array of memory given as the 'out' parameter to waveform.FilterBank window : int The size of the cluster window in samples. downsample_factor : {1, int}, optional The factor by which to reduce the sample rate when doing a heirarchical matched filter upsample_threshold : {1, float}, optional The fraction of the snr_threshold to trigger on the subsampled filter. upsample_method : {pruned_fft, str} The method to upsample or interpolate the reduced rate filter. """ self.tlen = tlen self.flen = self.tlen / 2 + 1 self.delta_f = delta_f self.dtype = dtype self.snr_threshold = snr_threshold self.flow = low_frequency_cutoff self.fhigh = high_frequency_cutoff self.gpu_callback_method = gpu_callback_method if downsample_factor == 1: self.matched_filter_and_cluster = self.full_matched_filter_and_cluster self.snr_mem = zeros(self.tlen, dtype=self.dtype) self.corr_mem = zeros(self.tlen, dtype=self.dtype) self.segments = segment_list # Assuming analysis time is constant across templates and segments, also # delta_f is constant across segments. self.stilde_delta_f = segment_list[0].delta_f self.htilde = template_output self.kmin, self.kmax = get_cutoff_indices(self.flow, self.fhigh, self.segments[0].delta_f, self.tlen) self.corr_slice = slice(self.kmin, self.kmax) self.corr_np = numpy.array(self.corr_mem.data[self.corr_slice], copy = False) self.hcorr = numpy.array(self.htilde.data[self.corr_slice], copy = False) self.correlators = [] for i in range(0, len(self.segments)): self.correlators.append(Correlator(self.hcorr, numpy.array(self.segments[i].data[self.corr_slice], copy = False), self.corr_np)) self.ifft = IFFT(self.corr_mem, self.snr_mem) self.threshold_and_clusterers = [] for i in range(0, len(self.segments)): self.threshold_and_clusterers.append(events.ThresholdCluster( numpy.array(self.snr_mem.data[self.segments[i].analyze], copy=False), window)) elif downsample_factor >= 1: self.matched_filter_and_cluster = self.heirarchical_matched_filter_and_cluster self.downsample_factor = downsample_factor self.upsample_method = upsample_method self.upsample_threshold = upsample_threshold N_full = self.tlen N_red = N_full / downsample_factor self.kmin_full, self.kmax_full = get_cutoff_indices(self.flow, self.fhigh, self.delta_f, N_full) self.kmin_red, _ = get_cutoff_indices(self.flow, self.fhigh, self.delta_f, N_red) if self.kmax_full < N_red: self.kmax_red = self.kmax_full else: self.kmax_red = N_red - 1 self.snr_mem = zeros(N_red, dtype=self.dtype) self.corr_mem_full = FrequencySeries(zeros(N_full, dtype=self.dtype), delta_f=self.delta_f) self.corr_mem = Array(self.corr_mem_full[0:N_red], copy=False) self.inter_vec = zeros(N_full, dtype=self.dtype) else: raise ValueError("Invalid downsample factor") def full_matched_filter_and_cluster(self, segnum, template_norm): """ Return the complex snr and normalization. Calculated the matched filter, threshold, and cluster. Parameters ---------- segnum : int Index into the list of segments at MatchedFilterControl construction against which to filter. template_norm : float The htilde, template normalization factor. Returns ------- snr : TimeSeries A time series containing the complex snr. norm : float The normalization of the complex snr. corrrelation: FrequencySeries A frequency series containing the correlation vector. idx : Array List of indices of the triggers. snrv : Array The snr values at the trigger locations. """ norm = (4.0 * self.stilde_delta_f) / sqrt(template_norm) self.correlators[segnum].correlate() self.ifft.execute() snrv, idx = self.threshold_and_clusterers[segnum].threshold_and_cluster(self.snr_threshold / norm) if len(idx) == 0: return [], [], [], [], [] logging.info("%s points above threshold" % str(len(idx))) return self.snr_mem, norm, self.corr_mem, idx, snrv def heirarchical_matched_filter_and_cluster(self, htilde, template_norm, stilde, window): """ Return the complex snr and normalization. Calculated the matched filter, threshold, and cluster. Parameters ---------- htilde : FrequencySeries The template waveform. Must come from the FilterBank class. template_norm : float The htilde, template normalization factor. stilde : FrequencySeries The strain data to be filtered. window : int The size of the cluster window in samples. Returns ------- snr : TimeSeries A time series containing the complex snr at the reduced sample rate. norm : float The normalization of the complex snr. corrrelation: FrequencySeries A frequency series containing the correlation vector. idx : Array List of indices of the triggers. snrv : Array The snr values at the trigger locations. """ from pycbc.fft.fftw_pruned import pruned_c2cifft, fft_transpose norm = (4.0 * stilde.delta_f) / sqrt(template_norm) correlate(htilde[self.kmin_red:self.kmax_red], stilde[self.kmin_red:self.kmax_red], self.corr_mem[self.kmin_red:self.kmax_red]) ifft(self.corr_mem, self.snr_mem) if not hasattr(stilde, 'red_analyze'): stilde.red_analyze = \ slice(stilde.analyze.start/self.downsample_factor, stilde.analyze.stop/self.downsample_factor) idx_red, snrv_red = events.threshold(self.snr_mem[stilde.red_analyze], self.snr_threshold / norm * self.upsample_threshold) if len(idx_red) == 0: return [], None, [], [], [] idx_red, _ = events.cluster_reduce(idx_red, snrv_red, window / self.downsample_factor) logging.info("%s points above threshold at reduced resolution"\ %(str(len(idx_red)),)) # The fancy upsampling is here if self.upsample_method=='pruned_fft': idx = (idx_red + stilde.analyze.start/self.downsample_factor)\ * self.downsample_factor idx = smear(idx, self.downsample_factor) # cache transposed versions of htilde and stilde if not hasattr(self.corr_mem_full, 'transposed'): self.corr_mem_full.transposed = zeros(len(self.corr_mem_full), dtype=self.dtype) if not hasattr(htilde, 'transposed'): htilde.transposed = zeros(len(self.corr_mem_full), dtype=self.dtype) htilde.transposed[self.kmin_full:self.kmax_full] = htilde[self.kmin_full:self.kmax_full] htilde.transposed = fft_transpose(htilde.transposed) if not hasattr(stilde, 'transposed'): stilde.transposed = zeros(len(self.corr_mem_full), dtype=self.dtype) stilde.transposed[self.kmin_full:self.kmax_full] = stilde[self.kmin_full:self.kmax_full] stilde.transposed = fft_transpose(stilde.transposed) correlate(htilde.transposed, stilde.transposed, self.corr_mem_full.transposed) snrv = pruned_c2cifft(self.corr_mem_full.transposed, self.inter_vec, idx, pretransposed=True) idx = idx - stilde.analyze.start idx2, snrv = events.threshold(Array(snrv, copy=False), self.snr_threshold / norm) if len(idx2) > 0: correlate(htilde[self.kmax_red:self.kmax_full], stilde[self.kmax_red:self.kmax_full], self.corr_mem_full[self.kmax_red:self.kmax_full]) idx, snrv = events.cluster_reduce(idx[idx2], snrv, window) else: idx, snrv = [], [] logging.info("%s points at full rate and clustering" % len(idx)) return self.snr_mem, norm, self.corr_mem_full, idx, snrv else: raise ValueError("Invalid upsample method")