def fftfilt(b, x): """Apply the FIR filter with coefficients b to the signal x, as if the filter's state is initially all zeros. The output has the same length as x.""" # Zero-pad by at least (len(b) - 1). nfft = int(ceil_pow_2(len(x) + len(b) - 1)) # Create FFT plans. forwardplan = CreateForwardCOMPLEX16FFTPlan(nfft, 0) reverseplan = CreateReverseCOMPLEX16FFTPlan(nfft, 0) # Create temporary workspaces. workspace1 = lal.CreateCOMPLEX16Vector(nfft) workspace2 = lal.CreateCOMPLEX16Vector(nfft) workspace3 = lal.CreateCOMPLEX16Vector(nfft) workspace1.data[:len(x)] = x workspace1.data[len(x):] = 0 lal.COMPLEX16VectorFFT(workspace2, workspace1, forwardplan) workspace1.data[:len(b)] = b workspace1.data[len(b):] = 0 lal.COMPLEX16VectorFFT(workspace3, workspace1, forwardplan) workspace2.data *= workspace3.data lal.COMPLEX16VectorFFT(workspace1, workspace2, reverseplan) # Return result with zero-padding stripped. return workspace1.data[:len(x)] / nfft
def _genqnmfreq(mass, spin, l, m, nmodes, qnmfreq=None): """Convenience function to generate QNM frequencies from lalsimulation. Parameters ---------- mass : float The mass of the black hole (in solar masses). spin : float The dimensionless spin of the black hole. l : int l-index of the harmonic. m : int m-index of the harmonic. nmodes : int The number of overtones to generate. qnmfreq : lal.COMPLEX16Vector, optional LAL vector to write the results into. Must be the same length as ``nmodes``. If None, will create one. Returns ------- lal.COMPLEX16Vector LAL vector containing the complex QNM frequencies. """ if qnmfreq is None: qnmfreq = lal.CreateCOMPLEX16Vector(int(nmodes)) lalsim.SimIMREOBGenerateQNMFreqV2fromFinal( qnmfreq, float(mass), float(spin), int(l), int(m), int(nmodes)) return qnmfreq
def get_lm_f0tau(mass, spin, l, m, nmodes): """Return the f_0 and the tau of each overtone for a given lm mode """ qnmfreq = lal.CreateCOMPLEX16Vector(nmodes) lalsim.SimIMREOBGenerateQNMFreqV2fromFinal(qnmfreq, float(mass), float(spin), l, m, nmodes) f_0 = [qnmfreq.data[n].real / (2 * numpy.pi) for n in range(nmodes)] tau = [1. / qnmfreq.data[n].imag for n in range(nmodes)] return f_0, tau
def lal(self): """ Returns a LAL Object that contains this data """ lal_data = None if self._data.dtype == float32: lal_data = _lal.CreateREAL4Vector(len(self)) elif self._data.dtype == float64: lal_data = _lal.CreateREAL8Vector(len(self)) elif self._data.dtype == complex64: lal_data = _lal.CreateCOMPLEX8Vector(len(self)) elif self._data.dtype == complex128: lal_data = _lal.CreateCOMPLEX16Vector(len(self)) lal_data.data[:] = self.numpy() return lal_data
def lal(self): """ Returns a LAL Object that contains this data """ lal_data = None if type(self._data) is not _numpy.ndarray: raise TypeError("Cannot return lal type from the GPU") elif self._data.dtype == float32: lal_data = _lal.CreateREAL4Vector(len(self)) elif self._data.dtype == float64: lal_data = _lal.CreateREAL8Vector(len(self)) elif self._data.dtype == complex64: lal_data = _lal.CreateCOMPLEX8Vector(len(self)) elif self._data.dtype == complex128: lal_data = _lal.CreateCOMPLEX16Vector(len(self)) lal_data.data[:] = self._data return lal_data
c8.data = c8dat assert (lal.swig_lal_test_copyinout_COMPLEX8Vector(c8)) assert ((c8.data == 3 * c8dat).all()) c8.data = c8dat retn, c8 = lal.swig_lal_test_copyinout_COMPLEX8Vector(c8) assert (retn) assert ((c8.data == 3 * c8dat).all()) c8 = c8dat retn, c8 = lal.swig_lal_test_copyinout_COMPLEX8Vector(c8) assert (retn) assert ((c8 == 3 * c8dat).all()) del c8 del c8out del c8dat lal.CheckMemoryLeaks() c16 = lal.CreateCOMPLEX16Vector(len(c16dat)) c16.data = c16dat c16out = lal.CreateCOMPLEX16Vector(len(c16dat)) c16out.data = numpy.zeros(numpy.shape(c16dat), dtype=c16dat.dtype) assert (lal.swig_lal_test_viewin_COMPLEX16Vector(c16out, c16)) assert ((c16out.data == c16.data).all()) c16out.data = numpy.zeros(numpy.shape(c16dat), dtype=c16dat.dtype) assert (lal.swig_lal_test_viewin_COMPLEX16Vector(c16out, c16dat)) assert ((c16out.data == c16dat).all()) c16out.data = numpy.zeros(numpy.shape(c16dat), dtype=c16dat.dtype) assert (lal.swig_lal_test_viewinout_COMPLEX16Vector(c16out, c16)) assert ((2 * c16out.data == c16.data).all()) c16out.data = numpy.zeros(numpy.shape(c16dat), dtype=c16dat.dtype) assert (lal.swig_lal_test_viewinout_COMPLEX16Vector(c16out, c16dat)) assert ((2 * c16out.data == c16dat).all()) c16.data = c16dat
def truncated_ifft(y, nsamples_out=None): """Truncated inverse FFT. See http://www.fftw.org/pruned.html for a discussion of related algorithms. Perform inverse FFT to obtain truncated autocorrelation time series. This makes use of a folded DFT for a speedup of log(nsamples)/log(nsamples_out) over directly computing the inverse FFT and truncating. Here is how it works. Say we have a frequency-domain signal X[k], for 0 ≤ k ≤ N - 1. We want to compute its DFT x[n], for 0 ≤ n ≤ M, where N is divisible by M: N = cM, for some integer c. The DFT is: N - 1 ______ \ 2 π i k n x[n] = \ exp[-----------] Y[k] / N /------ k = 0 c - 1 M - 1 ______ ______ \ \ 2 π i n (m c + j) = \ \ exp[------------------] Y[m c + j] / / c M /------ /------ j = 0 m = 0 c - 1 M - 1 ______ ______ \ 2 π i n j \ 2 π i n m = \ exp[-----------] \ exp[-----------] Y[m c + j] / N / M /------ /------ j = 0 m = 0 So: we split the frequency series into c deinterlaced sub-signals, each of length M, compute the DFT of each sub-signal, and add them back together with complex weights. Parameters ---------- y : `numpy.ndarray` Complex input vector. nsamples_out : int, optional Length of output vector. By default, same as length of input vector. Returns ------- x : `numpy.ndarray` The first nsamples_out samples of the IFFT of x, zero-padded if First generate the IFFT of a random signal: >>> nsamples_out = 1024 >>> y = np.random.randn(nsamples_out) + np.random.randn(nsamples_out) * 1j >>> plan = CreateReverseCOMPLEX16FFTPlan(nsamples_out, 0) >>> freq = lal.CreateCOMPLEX16Vector(nsamples_out) >>> freq.data = y >>> time = lal.CreateCOMPLEX16Vector(nsamples_out) >>> _ = lal.COMPLEX16VectorFFT(time, freq, plan) >>> x = time.data Now check that the truncated IFFT agrees: >>> np.allclose(x, truncated_ifft(y), rtol=1e-15) True >>> np.allclose(x, truncated_ifft(y, 1024), rtol=1e-15) True >>> np.allclose(x[:128], truncated_ifft(y, 128), rtol=1e-15) True >>> np.allclose(x[:1], truncated_ifft(y, 1), rtol=1e-15) True >>> np.allclose(x[:32], truncated_ifft(y, 32), rtol=1e-15) True >>> np.allclose(x[:63], truncated_ifft(y, 63), rtol=1e-15) True >>> np.allclose(x[:25], truncated_ifft(y, 25), rtol=1e-15) True >>> truncated_ifft(y, 1025) Traceback (most recent call last): ... ValueError: Input is too short: you gave me an input of length 1024, but you asked for an IFFT of length 1025. """ nsamples = len(y) if nsamples_out is None: nsamples_out = nsamples elif nsamples_out > nsamples: raise ValueError( 'Input is too short: you gave me an input of length {0}, ' 'but you asked for an IFFT of length {1}.'.format( nsamples, nsamples_out)) elif nsamples & (nsamples - 1): raise NotImplementedError( 'I am too lazy to implement for nsamples that is ' 'not a power of 2.') # Find number of FFTs. # FIXME: only works if nsamples is a power of 2. # Would be better to find the smallest divisor of nsamples that is # greater than or equal to nsamples_out. nsamples_batch = int(ceil_pow_2(nsamples_out)) c = nsamples // nsamples_batch # FIXME: Implement for real-to-complex FFTs as well. plan = CreateReverseCOMPLEX16FFTPlan(nsamples_batch, 0) input_workspace = lal.CreateCOMPLEX16Vector(nsamples_batch) output_workspace = lal.CreateCOMPLEX16Vector(nsamples_batch) twiddle = exp_i(2 * np.pi * np.arange(nsamples_batch) / nsamples) j = c - 1 input_workspace.data = y[j::c] lal.COMPLEX16VectorFFT(output_workspace, input_workspace, plan) x = output_workspace.data.copy() # Make sure this is a deep copy for j in range(c-2, -1, -1): input_workspace.data = y[j::c] lal.COMPLEX16VectorFFT(output_workspace, input_workspace, plan) x *= twiddle # FIXME: check stability of this recurrence relation. x += output_workspace.data # Now need to truncate remaining samples. if nsamples_out < nsamples_batch: x = x[:nsamples_out] return x
ax.set_ylim(1e-24, 1e-21) if i == len(data) - 1: ax.set_xlabel('frequency (Hz)') else: plt.setp(ax.get_xticklabels(), visible=False) if i == 0: ax.set_title('Noise amp. spectral density') duration = lalsimulation.SimInspiralTaylorF2ReducedSpinChirpTime( 10, mass1*lal.MSUN_SI, mass2*lal.MSUN_SI, 0, lalsimulation.PNORDER_THREE_POINT_FIVE) duration = int(np.ceil(filter.ceil_pow_2(duration))) sample_rate = 16384 nsamples = duration * sample_rate nsamples_fft = nsamples//2 + 1 af = lal.CreateCOMPLEX16Vector(nsamples) f = np.arange(nsamples) / duration hplus, hcross = lalsimulation.SimInspiralChooseFDWaveform( 0, 1/duration, mass1*lal.MSUN_SI, mass2*lal.MSUN_SI, 0, 0, 0, 0, 0, 0, 9, 0, 40, 500 * lal.PC_SI, 0, 0, 0, None, None, lalsimulation.PNORDER_THREE_POINT_FIVE, lalsimulation.PNORDER_NEWTONIAN, lalsimulation.TaylorF2) af.data[:len(hplus.data.data)] = abs2(hplus.data.data + 1j * hcross.data.data) af.data[len(hplus.data.data):] = 0 af.data[0] = 0