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]
def deconvolve(y, s, noise, periodogram_len=64):
    '''
    Wiener deconvolution of an excitation signal from an impulse response

    Parameters
    ----------

    y : ndarray
        The recording
    s : ndarray
        The excitation signal
    noise: ndarray
        The noise reference signal

    Returns
    -------
    h_len : int
        The length of the impulse response
    '''

    # 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

    # Compute the periodogram of the noise signal
    N = periodogram(noise, periodogram_len, n=n)

    # Forward transforms
    Y = fft.rfft(y, n=n, axis=0) / np.sqrt(n)
    S = fft.rfft(s, n=n, axis=0) / np.sqrt(n)

    # Wiener deconvolution
    if Y.ndim > 1:
        S = S[:, None]

    H = Y * np.conj(S) / (np.abs(S)**2 + N)

    # Inverse transform
    h = fft.irfft(H, n=n, axis=0)

    return h
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]
示例#4
0
    def synthesis(self, X=None):
        """
        Perform time synthesis of frequency domain to real signal using the 
        inverse DFT.

        Parameters
        ----------
        X: numpy array (complex64)
            Real input signal in time domain. Must be of size (N/2+1,D).
            Default is previously computed DFT.
        plot_time: bool
            Whether or not to plot time waveform.

        Returns
        -------
        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
示例#5
0
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)]])