def compress_waveform(htilde, sample_points, tolerance, interpolation, precision, decomp_scratch=None, psd=None): """Retrieves the amplitude and phase at the desired sample points, and adds frequency points in order to ensure that the interpolated waveform has a mismatch with the full waveform that is <= the desired tolerance. The mismatch is computed by finding 1-overlap between `htilde` and the decompressed waveform; no maximimization over phase/time is done, a PSD may be used. .. note:: The decompressed waveform is only garaunteed to have a true mismatch <= the tolerance for the given `interpolation` and for no PSD. However, since no maximization over time/phase is performed when adding points, the actual mismatch between the decompressed waveform and `htilde` is better than the tolerance, using no PSD. Using a PSD does increase the mismatch, and can lead to mismatches > than the desired tolerance, but typically by only a factor of a few worse. Parameters ---------- htilde : FrequencySeries The waveform to compress. sample_points : array The frequencies at which to store the amplitude and phase. More points may be added to this, depending on the desired tolerance. tolerance : float The maximum mismatch to allow between a decompressed waveform and `htilde`. interpolation : str The interpolation to use for decompressing the waveform when computing overlaps. precision : str The precision being used to generate and store the compressed waveform points. decomp_scratch : {None, FrequencySeries} Optionally provide scratch space for decompressing the waveform. The provided frequency series must have the same `delta_f` and length as `htilde`. psd : {None, FrequencySeries} The psd to use for calculating the overlap between the decompressed waveform and the original full waveform. Returns ------- CompressedWaveform The compressed waveform data; see `CompressedWaveform` for details. """ fmin = sample_points.min() df = htilde.delta_f sample_index = (sample_points / df).astype(int) amp = utils.amplitude_from_frequencyseries(htilde) phase = utils.phase_from_frequencyseries(htilde) comp_amp = amp.take(sample_index) comp_phase = phase.take(sample_index) if decomp_scratch is None: outdf = df else: outdf = None hdecomp = fd_decompress(comp_amp, comp_phase, sample_points, out=decomp_scratch, df=outdf, f_lower=fmin, interpolation=interpolation) kmax = min(len(htilde), len(hdecomp)) htilde = htilde[:kmax] hdecomp = hdecomp[:kmax] mismatch = 1. - filter.overlap( hdecomp, htilde, psd=psd, low_frequency_cutoff=fmin) if mismatch > tolerance: # we'll need the difference in the waveforms as a function of frequency vecdiffs = vecdiff(htilde, hdecomp, sample_points, psd=psd) # We will find where in the frequency series the interpolated waveform # has the smallest overlap with the full waveform, add a sample point # there, and re-interpolate. We repeat this until the overall mismatch # is > than the desired tolerance added_points = [] while mismatch > tolerance: minpt = vecdiffs.argmax() # add a point at the frequency halfway between minpt and minpt+1 add_freq = sample_points[[minpt, minpt + 1]].mean() addidx = int(round(add_freq / df)) # ensure that only new points are added if addidx in sample_index: diffidx = vecdiffs.argsort() addpt = -1 while addidx in sample_index: addpt -= 1 try: minpt = diffidx[addpt] except IndexError: raise ValueError("unable to compress to desired tolerance") add_freq = sample_points[[minpt, minpt + 1]].mean() addidx = int(round(add_freq / df)) new_index = numpy.zeros(sample_index.size + 1, dtype=int) new_index[:minpt + 1] = sample_index[:minpt + 1] new_index[minpt + 1] = addidx new_index[minpt + 2:] = sample_index[minpt + 1:] sample_index = new_index sample_points = (sample_index * df).astype( real_same_precision_as(htilde)) # get the new compressed points comp_amp = amp.take(sample_index) comp_phase = phase.take(sample_index) # update the vecdiffs and mismatch hdecomp = fd_decompress(comp_amp, comp_phase, sample_points, out=decomp_scratch, df=outdf, f_lower=fmin, interpolation=interpolation) hdecomp = hdecomp[:kmax] new_vecdiffs = numpy.zeros(vecdiffs.size + 1) new_vecdiffs[:minpt] = vecdiffs[:minpt] new_vecdiffs[minpt + 2:] = vecdiffs[minpt + 1:] new_vecdiffs[minpt:minpt + 2] = vecdiff(htilde, hdecomp, sample_points[minpt:minpt + 2], psd=psd) vecdiffs = new_vecdiffs mismatch = 1. - filter.overlap( hdecomp, htilde, psd=psd, low_frequency_cutoff=fmin) added_points.append(addidx) logging.info("mismatch: %f, N points: %i (%i added)" % (mismatch, len(comp_amp), len(added_points))) return CompressedWaveform(sample_points, comp_amp, comp_phase, interpolation=interpolation, tolerance=tolerance, mismatch=mismatch, precision=precision)
def compress_waveform(htilde, sample_points, tolerance, interpolation, decomp_scratch=None): """Retrieves the amplitude and phase at the desired sample points, and adds frequency points in order to ensure that the interpolated waveform has a mismatch with the full waveform that is <= the desired tolerance. The mismatch is computed by finding 1-overlap between `htilde` and the decompressed waveform; no maximimization over phase/time is done, nor is any PSD used. .. note:: The decompressed waveform is only garaunteed to have a true mismatch <= the tolerance for the given `interpolation` and for no PSD. However, since no maximization over time/phase is performed when adding points, the actual mismatch between the decompressed waveform and `htilde` is better than the tolerance, using no PSD. Using a PSD does increase the mismatch, and can lead to mismatches > than the desired tolerance, but typically by only a factor of a few worse. Parameters ---------- htilde : FrequencySeries The waveform to compress. sample_points : array The frequencies at which to store the amplitude and phase. More points may be added to this, depending on the desired tolerance. tolerance : float The maximum mismatch to allow between a decompressed waveform and `htilde`. interpolation : str The interpolation to use for decompressing the waveform when computing overlaps. decomp_scratch : {None, FrequencySeries} Optionally provide scratch space for decompressing the waveform. The provided frequency series must have the same `delta_f` and length as `htilde`. Returns ------- CompressedWaveform The compressed waveform data; see `CompressedWaveform` for details. """ fmin = sample_points.min() df = htilde.delta_f sample_index = (sample_points / df).astype(int) amp = utils.amplitude_from_frequencyseries(htilde) phase = utils.phase_from_frequencyseries(htilde) comp_amp = amp.take(sample_index) comp_phase = phase.take(sample_index) if decomp_scratch is None: outdf = df else: outdf = None out = decomp_scratch hdecomp = fd_decompress(comp_amp, comp_phase, sample_points, out=decomp_scratch, df=outdf, f_lower=fmin, interpolation=interpolation) mismatch = 1. - filter.overlap(hdecomp, htilde, low_frequency_cutoff=fmin) if mismatch > tolerance: # we'll need the difference in the waveforms as a function of frequency vecdiffs = vecdiff(htilde, hdecomp, sample_points) # We will find where in the frequency series the interpolated waveform # has the smallest overlap with the full waveform, add a sample point # there, and re-interpolate. We repeat this until the overall mismatch # is > than the desired tolerance added_points = [] while mismatch > tolerance: minpt = vecdiffs.argmax() # add a point at the frequency halfway between minpt and minpt+1 add_freq = sample_points[[minpt, minpt+1]].mean() addidx = int(add_freq/df) new_index = numpy.zeros(sample_index.size+1, dtype=int) new_index[:minpt+1] = sample_index[:minpt+1] new_index[minpt+1] = addidx new_index[minpt+2:] = sample_index[minpt+1:] sample_index = new_index sample_points = (sample_index * df).astype( real_same_precision_as(htilde)) # get the new compressed points comp_amp = amp.take(sample_index) comp_phase = phase.take(sample_index) # update the vecdiffs and mismatch hdecomp = fd_decompress(comp_amp, comp_phase, sample_points, out=decomp_scratch, df=outdf, f_lower=fmin, interpolation=interpolation) new_vecdiffs = numpy.zeros(vecdiffs.size+1) new_vecdiffs[:minpt] = vecdiffs[:minpt] new_vecdiffs[minpt+2:] = vecdiffs[minpt+1:] new_vecdiffs[minpt:minpt+2] = vecdiff(htilde, hdecomp, sample_points[minpt:minpt+2]) vecdiffs = new_vecdiffs mismatch = 1. - filter.overlap(hdecomp, htilde, low_frequency_cutoff=fmin) added_points.append(addidx) logging.info("mismatch: %f, N points: %i (%i added)" %(mismatch, len(comp_amp), len(added_points))) return CompressedWaveform(sample_points, comp_amp, comp_phase, interpolation=interpolation, tolerance=tolerance, mismatch=mismatch)