def mkl_toeplitz_multiplication(c, r, A, A_padded=False, out=None, fft_len=None): """ Compute numpy.dot(scipy.linalg.toeplitz(c,r), A) using the FFT from the mkl_fft package. Parameters ---------- c: ndarray the first column of the Toeplitz matrix r: ndarray the first row of the Toeplitz matrix A: ndarray the matrix to multiply on the right A_padded: bool, optional the A matrix can be pre-padded with zeros by the user, if this is the case set to True out: ndarray, optional an ndarray to store the output of the multiplication fft_len: int, optional specify the length of the FFT to use """ if not has_mklfft: raise ValueError( "Import mkl_fft package unavailable. Install from https://github.com/LCAV/mkl_fft" ) m = c.shape[0] n = r.shape[0] if fft_len is None: fft_len = int(2 ** np.ceil(np.log2(m + n - 1))) zp = fft_len - m - n + 1 if (not A_padded and A.shape[0] != n) or (A_padded and A.shape[0] != fft_len): raise ValueError("A dimensions not compatible with toeplitz(c,r)") x = np.concatenate((c, np.zeros(zp, dtype=c.dtype), r[-1:0:-1])) xf = fft.rfft(x, n=fft_len) if out is not None: fft.rfft(A, n=fft_len, axis=0, out=out) else: out = fft.rfft(A, n=fft_len, axis=0) out *= xf[:, None] if A_padded: fft.irfft(out, n=fft_len, axis=0, out=A) else: A = fft.irfft(out, n=fft_len, axis=0) return A[ :m, ]
def synthesis(self, X=None): """ Perform time synthesis of frequency domain to real signal using the inverse DFT. :param X: Real input signal in time domain. Must be of size (N/2+1,D). Default is previously computed DFT. :type X: numpy array (complex64) :param plot_time: Whether or not to plot time waveform. :type plot_time: bool :rtype: Time domain signal, numpy array of size (N,D) and of type float32. """ # check for valid input if X is not None: if self.D != 1: if X.shape != (self.nbin, self.D): raise ValueError('Invalid input dimensions.') elif self.D == 1: if X.ndim != 1 and X.shape[0] != self.nbin: raise ValueError('Invalid input dimensions.') self.X[:, ] = X # inverse DFT if self.transform == 'fftw': self.b[:] = self.X self.x[:, ] = self.backward() elif self.transform == 'mkl': self.x[:, ] = mkl_fft.irfft(self.X, axis=0) else: self.x[:, ] = irfft(self.X, axis=0) # apply window if needed if self.synthesis_window is not None: np.multiply(self.synthesis_window, self.x[:, ], self.x[:, ]) return self.x
def test_rfft(self): n_tests = 1000 n_max = 2 d_max = 100 norm = 'ortho' inplace = True scrambled = True dtype = np.float64 passed = True for i in range(n_tests): ndim = np.random.randint(1,high=n_max+1) axis = np.random.randint(0,high=ndim) dims = np.random.randint(1,high=d_max+1,size=(ndim)) x = np.array(np.random.normal(size=dims), dtype=dtype) x = np.asfortranarray(x) X = rfft(x, axis=axis, norm=norm, scrambled=scrambled) Y = np.fft.rfft(x, axis=axis, norm=norm) x_ = irfft(X, n=x.shape[axis], axis=axis, norm=norm, scrambled=scrambled) if not np.allclose(X,Y): print(' Failed forward with ndim=%d axis=%d dims=' % (ndim, axis), dims) passed = False if not np.allclose(x, x_): print(' Failed backward with ndim=%d axis=%d dims=' % (ndim, axis), dims) passed = False self.assertTrue(passed)
def autocorr(x): """Fast autocorrelation computation using the FFT""" X = fft.rfft(x, n=2 * x.shape[0]) r = fft.irfft(np.abs(X) ** 2) return r[: x.shape[0]] / (x.shape[0] - 1)
def test5(self): for a in range(0,3): for ovwr_x in [True, False]: for dt, atol in zip([np.float32, np.float64], [4e-7, 4e-15]): x = self.t3.copy().astype(dt) f1 = mkl_fft.irfft(x, axis=a, overwrite_x=ovwr_x) f2 = mkl_fft.rfft(f1, axis=a, overwrite_x=ovwr_x) assert_allclose(f2, self.t3.astype(dt), atol=atol)
def test3(self): for a in range(0,2): for ovwr_x in [True, False]: for dt, atol in zip([np.float32, np.float64], [2e-7, 2e-15]): x = self.m2.copy().astype(dt) f1 = mkl_fft.rfft(x, axis=a, overwrite_x=ovwr_x) f2 = mkl_fft.irfft(f1, axis=a, overwrite_x=ovwr_x) assert_allclose(f2, self.m2.astype(dt), atol=atol, err_msg=(a, ovwr_x))
def test_scale_1d_array(self): X = np.ones((8, 4, 4,), dtype='d') f1 = mkl_fft.fft(X, axis=1, forward_scale=0.25) f2 = mkl_fft.fft(X, axis=1) r_tol, a_tol = _get_rtol_atol(X) assert_allclose(4*f1, f2, rtol=r_tol, atol=a_tol) X1 = mkl_fft.ifft(f1, axis=1, forward_scale=0.25) assert_allclose(X, X1, rtol=r_tol, atol=a_tol) f3 = mkl_fft.rfft(X, axis=0, forward_scale=0.5) X2 = mkl_fft.irfft(f3, axis=0, forward_scale=0.5) assert_allclose(X, X2, rtol=r_tol, atol=a_tol)
def test_scale_1d_vector(self): X = np.ones(128, dtype='d') f1 = mkl_fft.fft(X, forward_scale=0.25) f2 = mkl_fft.fft(X) r_tol, a_tol = _get_rtol_atol(X) assert_allclose(4*f1, f2, rtol=r_tol, atol=a_tol) X1 = mkl_fft.ifft(f1, forward_scale=0.25) assert_allclose(X, X1, rtol=r_tol, atol=a_tol) f3 = mkl_fft.rfft(X, forward_scale=0.5) X2 = mkl_fft.irfft(f3, forward_scale=0.5) assert_allclose(X, X2, rtol=r_tol, atol=a_tol)
def test_rfft(self): n_tests = 1000 n_max = 2 d_max = 100 norm = 'ortho' inplace = True scrambled = True dtype = np.float64 passed = True for i in range(n_tests): ndim = np.random.randint(1, high=n_max + 1) axis = np.random.randint(0, high=ndim) dims = np.random.randint(1, high=d_max + 1, size=(ndim)) x = np.array(np.random.normal(size=dims), dtype=dtype) x = np.asfortranarray(x) X = rfft(x, axis=axis, norm=norm, scrambled=scrambled) Y = np.fft.rfft(x, axis=axis, norm=norm) x_ = irfft(X, n=x.shape[axis], axis=axis, norm=norm, scrambled=scrambled) if not np.allclose(X, Y): print( ' Failed forward with ndim=%d axis=%d dims=' % (ndim, axis), dims) passed = False if not np.allclose(x, x_): print( ' Failed backward with ndim=%d axis=%d dims=' % (ndim, axis), dims) passed = False self.assertTrue(passed)
def deconvolve(y, s, length=None, thresh=0.0): ''' Deconvolve an excitation signal from an impulse response Parameters ---------- y : ndarray The recording s : ndarray The excitation signal length: int, optional the length of the impulse response to deconvolve thresh : float, optional ignore frequency bins with power lower than this ''' # FFT length including zero padding n = y.shape[0] + s.shape[0] - 1 # let FFT size be even for convenience if n % 2 != 0: n += 1 # when unknown, pick the filter size as size of test signal if length is None: length = n # Forward transforms Y = fft.rfft(np.array(y, dtype=np.float32), n=n) / np.sqrt(n) S = fft.rfft(np.array(s, dtype=np.float32), n=n) / np.sqrt(n) # Only do the division where S is large enough H = np.zeros(*Y.shape, dtype=Y.dtype) I = np.where(np.abs(S) > thresh) H[I] = Y[I] / S[I] # Inverse transform h = fft.irfft(H, n=n) return h[:length]
def correlate(x1, x2, interp=1, phat=False): ''' Compute the cross-correlation between x1 and x2 Parameters ---------- x1,x2: array_like The data arrays interp: int, optional The interpolation factor for the output array, default 1. phat: bool, optional Apply the PHAT weighting (default False) Returns ------- The cross-correlation between the two arrays ''' N1 = x1.shape[0] N2 = x2.shape[0] N = N1 + N2 - 1 X1 = fft.rfft(x1, n=N) X2 = fft.rfft(x2, n=N) if phat: eps1 = np.mean(np.abs(X1)) * 1e-10 X1 /= (np.abs(X1) + eps1) eps2 = np.mean(np.abs(X2)) * 1e-10 X2 /= (np.abs(X2) + eps2) m = np.minimum(N1, N2) out = fft.irfft(X1 * np.conj(X2), n=int(N * interp)) return np.concatenate([out[-interp * (N2 - 1):], out[:(interp * N1)]])
def test2(self): x = self.v1.copy() f1 = mkl_fft.irfft(x) f2 = mkl_fft.rfft(f1) assert_allclose(f2,x)
def wiener_deconvolve(y, x, length=None, noise_variance=1., let_n_points=15, let_div_base=2): ''' Deconvolve an excitation signal from an impulse response We use Wiener filter Parameters ---------- y : ndarray The recording x : ndarray The excitation signal length: int, optional the length of the impulse response to deconvolve noise_variance : float, optional estimate of the noise variance let_n_points: int number of points to use in the LET approximation let_div_base: float the divider used for the LET grid ''' # FFT length including zero padding n = y.shape[0] + x.shape[0] - 1 # let FFT size be even for convenience if n % 2 != 0: n += 1 # when unknown, pick the filter size as size of test signal if length is None: length = n # Forward transforms Y = fft.rfft(np.array(y, dtype=np.float32), n=n) / np.sqrt(n) # recording X = fft.rfft(np.array(x, dtype=np.float32), n=n) / np.sqrt( n) # test signal # Squared amplitude of test signal X_sqm = np.abs(X)**2 # approximate SNR SNR_hat = np.maximum(1e-7, ((np.linalg.norm(Y)**2 / np.linalg.norm(X)**2) - noise_variance)) / noise_variance dividers = let_div_base**np.linspace(-let_n_points / 2, let_n_points, let_n_points) SNR_grid = SNR_hat / dividers # compute candidate points G = (X_sqm[:, None] / (X_sqm[:, None] + 1. / SNR_grid[None, :])) * Y[:, None] H_candidates = G / X[:, None] # find the best linear combination of the candidates weights = np.linalg.lstsq(G, Y)[0] # compute the estimated filter H = np.squeeze(np.dot(H_candidates, weights)) h = fft.irfft(H, n=n) return h[:length]