Exemplo n.º 1
0
def fftconvolve(in1, in2, mode="full", pad_to_power_of_two=True):
    """Convolve two N-dimensional arrays using FFT. See convolve.

    """
    s1 = array(in1.shape)
    s2 = array(in2.shape)
    complex_result = (N.issubdtype(in1.dtype, N.complex) or
                      N.issubdtype(in2.dtype, N.complex))
    size = s1 + s2 - 1

    if pad_to_power_of_two:
        # Use 2**n-sized FFT; it might improve performance
        fsize = 2 ** N.ceil(N.log2(size))
    else:
        # Padding to a power of two might degrade performance, too
        fsize = size
    IN1 = N.fft.fftn(in1, fsize)
    IN1 *= N.fft.fftn(in2, fsize)
    fslice = tuple([slice(0, int(sz)) for sz in size])
    ret = N.fft.ifftn(IN1)[fslice].copy()
    del IN1
    if not complex_result:
        ret = ret.real
    if mode == "full":
        return ret
    elif mode == "same":
        if product(s1, axis=0) > product(s2, axis=0):
            osize = s1
        else:
            osize = s2
        return _centered(ret, osize)
    elif mode == "valid":
        return _centered(ret, abs(s2 - s1) + 1)
Exemplo n.º 2
0
    def fftconvolve(in1, in2, mode="same", threads=1):
        """Same as above but with pyfftw added in"""
        in1 = np.asarray(in1)
        in2 = np.asarray(in2)

        if in1.ndim == in2.ndim == 0:  # scalar inputs
            return in1 * in2
        elif not in1.ndim == in2.ndim:
            raise ValueError("in1 and in2 should have the same dimensionality")
        elif in1.size == 0 or in2.size == 0:  # empty arrays
            return np.array([])

        s1 = np.array(in1.shape)
        s2 = np.array(in2.shape)
        complex_result = (np.issubdtype(in1.dtype, complex)
                          or np.issubdtype(in2.dtype, complex))
        shape = s1 + s2 - 1

        # Check that input sizes are compatible with 'valid' mode
        if sig._inputs_swap_needed(mode, s1, s2):
            # Convolution is commutative; order doesn't have any effect on output
            in1, s1, in2, s2 = in2, s2, in1, s1

        # Speed up FFT by padding to optimal size for FFTPACK
        fshape = [sig.fftpack.helper.next_fast_len(int(d)) for d in shape]
        fslice = tuple([slice(0, int(sz)) for sz in shape])
        # Pre-1.9 NumPy FFT routines are not threadsafe.  For older NumPys, make
        # sure we only call rfftn/irfftn from one thread at a time.
        if not complex_result and (sig._rfft_mt_safe
                                   or sig._rfft_lock.acquire(False)):
            try:
                sp1 = rfftn(in1, fshape, threads=threads)
                sp2 = rfftn(in2, fshape, threads=threads)
                ret = (irfftn(sp1 * sp2, fshape,
                              threads=threads)[fslice].copy())
            finally:
                if not sig._rfft_mt_safe:
                    sig._rfft_lock.release()
        else:
            # If we're here, it's either because we need a complex result, or we
            # failed to acquire _rfft_lock (meaning rfftn isn't threadsafe and
            # is already in use by another thread).  In either case, use the
            # (threadsafe but slower) SciPy complex-FFT routines instead.
            sp1 = fftn(in1, fshape, threads=threads)
            sp2 = fftn(in2, fshape, threads=threads)
            ret = ifftn(sp1 * sp2, threads=threads)[fslice].copy()
            if not complex_result:
                ret = ret.real

        if mode == "full":
            return ret
        elif mode == "same":
            return sig._centered(ret, s1)
        elif mode == "valid":
            return sig._centered(ret, s1 - s2 + 1)
        else:
            raise ValueError("Acceptable mode flags are 'valid',"
                             " 'same', or 'full'.")
Exemplo n.º 3
0
    def fftconvolve(in1, in2, mode="same", threads=1):
        """Same as above but with pyfftw added in"""
        in1 = np.asarray(in1)
        in2 = np.asarray(in2)

        if in1.ndim == in2.ndim == 0:  # scalar inputs
            return in1 * in2
        elif not in1.ndim == in2.ndim:
            raise ValueError("in1 and in2 should have the same dimensionality")
        elif in1.size == 0 or in2.size == 0:  # empty arrays
            return np.array([])

        s1 = np.array(in1.shape)
        s2 = np.array(in2.shape)
        complex_result = (np.issubdtype(in1.dtype, complex) or
                          np.issubdtype(in2.dtype, complex))
        shape = s1 + s2 - 1

        # Check that input sizes are compatible with 'valid' mode
        if sig._inputs_swap_needed(mode, s1, s2):
            # Convolution is commutative; order doesn't have any effect on output
            in1, s1, in2, s2 = in2, s2, in1, s1

        # Speed up FFT by padding to optimal size for FFTPACK
        fshape = [sig.fftpack.helper.next_fast_len(int(d)) for d in shape]
        fslice = tuple([slice(0, int(sz)) for sz in shape])
        # Pre-1.9 NumPy FFT routines are not threadsafe.  For older NumPys, make
        # sure we only call rfftn/irfftn from one thread at a time.
        if not complex_result and (sig._rfft_mt_safe or sig._rfft_lock.acquire(False)):
            try:
                sp1 = rfftn(in1, fshape, threads=threads)
                sp2 = rfftn(in2, fshape, threads=threads)
                ret = (irfftn(sp1 * sp2, fshape, threads=threads)[fslice].copy())
            finally:
                if not sig._rfft_mt_safe:
                    sig._rfft_lock.release()
        else:
            # If we're here, it's either because we need a complex result, or we
            # failed to acquire _rfft_lock (meaning rfftn isn't threadsafe and
            # is already in use by another thread).  In either case, use the
            # (threadsafe but slower) SciPy complex-FFT routines instead.
            sp1 = fftn(in1, fshape, threads=threads)
            sp2 = fftn(in2, fshape, threads=threads)
            ret = ifftn(sp1 * sp2, threads=threads)[fslice].copy()
            if not complex_result:
                ret = ret.real

        if mode == "full":
            return ret
        elif mode == "same":
            return sig._centered(ret, s1)
        elif mode == "valid":
            return sig._centered(ret, s1 - s2 + 1)
        else:
            raise ValueError("Acceptable mode flags are 'valid',"
                             " 'same', or 'full'.")
Exemplo n.º 4
0
def _fftconvolve(in1, in2, mode="full", axis=None):
    """ Convolve two N-dimensional arrays using FFT. See convolve.

    This is a fix of scipy.signal.fftconvolve, adding an axis argument and
    importing locally the stuff only needed for this function
    
    """
    #Locally import stuff only required for this:
    from scipy.fftpack import fftn, fft, ifftn, ifft
    from scipy.signal.signaltools import _centered
    from numpy import array, product


    s1 = array(in1.shape)
    s2 = array(in2.shape)
    complex_result = (np.issubdtype(in1.dtype, np.complex) or
                      np.issubdtype(in2.dtype, np.complex))

    if axis is None:
        size = s1+s2-1
        fslice = tuple([slice(0, int(sz)) for sz in size])
    else:
        equal_shapes = s1==s2
        # allow equal_shapes[axis] to be False
        equal_shapes[axis] = True
        assert equal_shapes.all(), 'Shape mismatch on non-convolving axes'
        size = s1[axis]+s2[axis]-1
        fslice = [slice(l) for l in s1]
        fslice[axis] = slice(0, int(size))
        fslice = tuple(fslice)

    # Always use 2**n-sized FFT
    fsize = 2**np.ceil(np.log2(size))
    if axis is None:
        IN1 = fftn(in1,fsize)
        IN1 *= fftn(in2,fsize)
        ret = ifftn(IN1)[fslice].copy()
    else:
        IN1 = fft(in1,fsize,axis=axis)
        IN1 *= fft(in2,fsize,axis=axis)
        ret = ifft(IN1,axis=axis)[fslice].copy()
    if not complex_result:
        del IN1
        ret = ret.real
    if mode == "full":
        return ret
    elif mode == "same":
        if product(s1,axis=0) > product(s2,axis=0):
            osize = s1
        else:
            osize = s2
        return _centered(ret,osize)
    elif mode == "valid":
        return _centered(ret,abs(s2-s1)+1)
Exemplo n.º 5
0
def _fftconvolve(in1, in2, mode="full", axis=None):
    """ Convolve two N-dimensional arrays using FFT. See convolve.

    This is a fix of scipy.signal.fftconvolve, adding an axis argument and
    importing locally the stuff only needed for this function
    
    """
    #Locally import stuff only required for this:
    from scipy.fftpack import fftn, fft, ifftn, ifft
    from scipy.signal.signaltools import _centered
    from numpy import array, product


    s1 = array(in1.shape)
    s2 = array(in2.shape)
    complex_result = (np.issubdtype(in1.dtype, np.complex) or
                      np.issubdtype(in2.dtype, np.complex))

    if axis is None:
        size = s1+s2-1
        fslice = tuple([slice(0, int(sz)) for sz in size])
    else:
        equal_shapes = s1==s2
        # allow equal_shapes[axis] to be False
        equal_shapes[axis] = True
        assert equal_shapes.all(), 'Shape mismatch on non-convolving axes'
        size = s1[axis]+s2[axis]-1
        fslice = [slice(l) for l in s1]
        fslice[axis] = slice(0, int(size))
        fslice = tuple(fslice)

    # Always use 2**n-sized FFT
    fsize = 2**np.ceil(np.log2(size))
    if axis is None:
        IN1 = fftn(in1,fsize)
        IN1 *= fftn(in2,fsize)
        ret = ifftn(IN1)[fslice].copy()
    else:
        IN1 = fft(in1,fsize,axis=axis)
        IN1 *= fft(in2,fsize,axis=axis)
        ret = ifft(IN1,axis=axis)[fslice].copy()
    if not complex_result:
        del IN1
        ret = ret.real
    if mode == "full":
        return ret
    elif mode == "same":
        if product(s1,axis=0) > product(s2,axis=0):
            osize = s1
        else:
            osize = s2
        return _centered(ret,osize)
    elif mode == "valid":
        return _centered(ret,abs(s2-s1)+1)
Exemplo n.º 6
0
def convolve_two_arrays(array1, array2):
    """Convolution based off the convolution theorem"""
    if len(array1) < len(array2):
        diff = len(array2) - len(array1)
        array1 = numpy.pad(
            array1, (int(numpy.floor(diff / 2)), int(numpy.ceil(diff / 2))),
            'constant',
            constant_values=0)
    elif len(array2) < len(array1):
        diff = len(array1) - len(array2)
        array2 = numpy.pad(
            array2, (int(numpy.floor(diff / 2)), int(numpy.ceil(diff / 2))),
            'constant',
            constant_values=0)

    #The next 8 lines follow closely with scipy.signal.fftconvolve
    shape = np.maximum(np.array(array1.shape), np.array(array2.shape))
    s1 = np.array(array1.shape)
    s2 = np.array(array2.shape)
    shape = s1 + s2 - 1
    fshape = [fftpack.helper.next_fast_len(d) for d in shape]
    fslice = tuple([slice(sz) for sz in shape])
    array1_fft = DFT(array1, fshape)
    array2_fft = DFT(array2, fshape)

    #Perform convolution
    convolved_arr = numpy.asarray(numpy.real(IDFT(array1_fft *
                                                  array2_fft)))[fslice]
    ret = _centered(convolved_arr, s1)  #Recover wanted array
    return ret
Exemplo n.º 7
0
def fft_convolve(v1, v2):
    s1 = v1.shape[-1]
    s2 = v2.shape[-1]
    valid = abs(s2-s1) + 1
    fsize = 2**np.ceil(np.log2(s1+s2-1))

    convolver = (EPS + signal.fft(v2, fsize, axis=-1))
    convolved = np.real(signal.ifft(convolver * signal.fft(v1, fsize, axis=-1), axis=-1))
    return _centered(convolved, valid)
Exemplo n.º 8
0
def fftconvolve(in1, in2, mode="full", axis=None):
    """Convolve two N-dimensional arrays using FFT. See convolve.

    """
    s1 = array(in1.shape)
    s2 = array(in2.shape)
    complex_result = (np.issubdtype(in1.dtype, np.complex) or
                      np.issubdtype(in2.dtype, np.complex))
    if axis is None:
        size = s1+s2-1
        fslice = tuple([slice(0, int(sz)) for sz in size])
    else:
        equal_shapes = s1==s2
        # allow equal_shapes[axis] to be False
        equal_shapes[axis] = True
        assert equal_shapes.all(), 'Shape mismatch on non-convolving axes'
        size = s1[axis]+s2[axis]-1
        fslice = [slice(l) for l in s1]
        fslice[axis] = slice(0, int(size))
        fslice = tuple(fslice)

    # Always use 2**n-sized FFT
    fsize = 2**np.ceil(np.log2(size))
    if axis is None:
        IN1 = fftn(in1,fsize)
        IN1 *= fftn(in2,fsize)
        ret = ifftn(IN1)[fslice].copy()
    else:
        IN1 = fft(in1,fsize,axis=axis)
        IN1 *= fft(in2,fsize,axis=axis)
        ret = ifft(IN1,axis=axis)[fslice].copy()
    del IN1
    if not complex_result:
        ret = ret.real
    if mode == "full":
        return ret
    elif mode == "same":
        if product(s1,axis=0) > product(s2,axis=0):
            osize = s1
        else:
            osize = s2
        return _centered(ret,osize)
    elif mode == "valid":
        return _centered(ret,abs(s2-s1)+1)
Exemplo n.º 9
0
def _fftconvolve_18(in1, in2, int2_fft, mode="same"):
    """
    scipy routine scipy.signal.fftconvolve with kernel already fourier transformed
    """
    in1 = signaltools.asarray(in1)
    in2 = signaltools.asarray(in2)

    if in1.ndim == in2.ndim == 0:  # scalar inputs
        return in1 * in2
    elif not in1.ndim == in2.ndim:
        raise ValueError("in1 and in2 should have the same dimensionality")
    elif in1.size == 0 or in2.size == 0:  # empty arrays
        return signaltools.array([])

    s1 = signaltools.array(in1.shape)
    s2 = signaltools.array(in2.shape)

    shape = s1 + s2 - 1

    # Check that input sizes are compatible with 'valid' mode
    if signaltools._inputs_swap_needed(mode, s1, s2):
        # Convolution is commutative; order doesn't have any effect on output
        in1, s1, in2, s2 = in2, s2, in1, s1

    # Speed up FFT by padding to optimal size for FFTPACK
    fshape = [signaltools.fftpack.helper.next_fast_len(int(d)) for d in shape]
    fslice = tuple([slice(0, int(sz)) for sz in shape])
    # Pre-1.9 NumPy FFT routines are not threadsafe.  For older NumPys, make
    # sure we only call rfftn/irfftn from one thread at a time.

    ret = np.fft.irfftn(np.fft.rfftn(in1, fshape) * int2_fft,
                        fshape)[fslice].copy()
    #np.fft.rfftn(in2, fshape)

    if mode == "full":
        return ret
    elif mode == "same":
        return signaltools._centered(ret, s1)
    elif mode == "valid":
        return signaltools._centered(ret, s1 - s2 + 1)
    else:
        raise ValueError("Acceptable mode flags are 'valid',"
                         " 'same', or 'full'.")
Exemplo n.º 10
0
def _fftconvolve_14(in1, in2, int2_fft, mode="same"):
    """
    scipy routine scipy.signal.fftconvolve with kernel already fourier transformed
    """
    in1 = signaltools.asarray(in1)
    in2 = signaltools.asarray(in2)

    if in1.ndim == in2.ndim == 0:  # scalar inputs
        return in1 * in2
    elif not in1.ndim == in2.ndim:
        raise ValueError("in1 and in2 should have the same dimensionality")
    elif in1.size == 0 or in2.size == 0:  # empty arrays
        return signaltools.array([])

    s1 = signaltools.array(in1.shape)
    s2 = signaltools.array(in2.shape)

    shape = s1 + s2 - 1

    # Speed up FFT by padding to optimal size for FFTPACK
    fshape = [signaltools._next_regular(int(d)) for d in shape]
    fslice = tuple([slice(0, int(sz)) for sz in shape])
    # Pre-1.9 NumPy FFT routines are not threadsafe.  For older NumPys, make
    # sure we only call rfftn/irfftn from one thread at a time.

    ret = signaltools.irfftn(
        signaltools.rfftn(in1, fshape) * int2_fft, fshape)[fslice].copy()
    #np.fft.rfftn(in2, fshape)

    if mode == "full":
        return ret
    elif mode == "same":
        return signaltools._centered(ret, s1)
    elif mode == "valid":
        return signaltools._centered(ret, s1 - s2 + 1)
    else:
        raise ValueError("Acceptable mode flags are 'valid',"
                         " 'same', or 'full'.")
Exemplo n.º 11
0
def numpy_normxcorr(templates, stream, pads, *args, **kwargs):
    """
    Compute the normalized cross-correlation using numpy and bottleneck.

    :param templates: 2D Array of templates
    :type templates: np.ndarray
    :param stream: 1D array of continuous data
    :type stream: np.ndarray
    :param pads: List of ints of pad lengths in the same order as templates
    :type pads: list

    :return: np.ndarray of cross-correlations
    :return: np.ndarray channels used
    """
    import bottleneck
    from scipy.signal.signaltools import _centered

    # Generate a template mask
    used_chans = ~np.isnan(templates).any(axis=1)
    # Currently have to use float64 as bottleneck runs into issues with other
    # types: https://github.com/kwgoodman/bottleneck/issues/164
    stream = stream.astype(np.float64)
    templates = templates.astype(np.float64)
    template_length = templates.shape[1]
    stream_length = len(stream)
    fftshape = next_fast_len(template_length + stream_length - 1)
    # Set up normalizers
    stream_mean_array = bottleneck.move_mean(
        stream, template_length)[template_length - 1:]
    stream_std_array = bottleneck.move_std(
        stream, template_length)[template_length - 1:]
    # because stream_std_array is in denominator or res, nan all 0s
    stream_std_array[stream_std_array == 0] = np.nan
    # Normalize and flip the templates
    norm = ((templates - templates.mean(axis=-1, keepdims=True)) /
            (templates.std(axis=-1, keepdims=True) * template_length))
    norm_sum = norm.sum(axis=-1, keepdims=True)
    stream_fft = np.fft.rfft(stream, fftshape)
    template_fft = np.fft.rfft(np.flip(norm, axis=-1), fftshape, axis=-1)
    res = np.fft.irfft(template_fft * stream_fft,
                       fftshape)[:, 0:template_length + stream_length - 1]
    res = ((_centered(res, stream_length - template_length + 1)) -
           norm_sum * stream_mean_array) / stream_std_array
    res[np.isnan(res)] = 0.0
    # res[np.isinf(res)] = 0.0
    for i, pad in enumerate(pads):  # range(len(pads)):
        res[i] = np.append(res[i], np.zeros(pad))[pad:]
    return res.astype(np.float32), used_chans
Exemplo n.º 12
0
    def run(self, f0=None, fir=None):
        """Run the lock-in amplifier at reference frequency ``f0``,
        using the finite impulse response filter ``fir``.
        """
        if f0 is None:
            self.f0 = f0 = self.f0_est
        if fir is not None:
            self.fir = fir

        self.z = z = signal.fftconvolve(self.x * np.exp(-2j*np.pi*f0*self.t),
                                        2*self.fir,
                                        "same")

        n_fir = self.fir.size
        indices = np.arange(self.t.size)
        # Valid region mask
        # This is borrowed explicitly from scipy.signal.sigtools.fftconvolve
        self.m = m = np.zeros_like(self.t, dtype=bool)
        self.m[_centered(indices, self.t.size - n_fir + 1)] = True

        self.A = abs(self.z)
        self.phi = np.angle(self.z)
Exemplo n.º 13
0
    def run(self, f0=None, fir=None):
        """Run the lock-in amplifier at reference frequency ``f0``,
        using the finite impulse response filter ``fir``.
        """
        if f0 is None:
            self.f0 = f0 = self.f0_est
        if fir is not None:
            self.fir = fir

        self.z = z = signal.fftconvolve(self.x * np.exp(-2j*np.pi*f0*self.t),
                                        2*self.fir,
                                        "same")

        n_fir = self.fir.size
        indices = np.arange(self.t.size)
        # Valid region mask
        # This is borrowed explicitly from scipy.signal.sigtools.fftconvolve
        self.m = m = np.zeros_like(self.t, dtype=bool)
        self.m[_centered(indices, self.t.size - n_fir + 1)] = True

        self.A = abs(self.z)
        self.phi = np.angle(self.z)
def _broadcasted_convolution(in1, in2, orig_shape):
    fwr = in1[:, :, :, np.newaxis] * np.swapaxes(in2[:, :, :, np.newaxis], 0,
                                                 3)
    fwr = fwr.reshape(len(in1), *fwr.shape[1:3], len(in2))
    e = ifftn(fwr, s=fwr.shape[1:3], axes=[1, 2])
    return _centered(e, (len(in1), *orig_shape, len(in2)))