예제 #1
0
파일: test_fftpack.py 프로젝트: zhaohb/cupy
 def test_fft_multiple_plan_error(self, dtype):
     # hack: avoid testing the cases when the output array is of size 0
     # because cuFFT and numpy raise different kinds of exceptions
     if self.n == 0:
         return
     import cupy
     import cupyx.scipy.fftpack as fftpack
     x = testing.shaped_random(self.shape, cupy, dtype)
     plan = fftpack.get_fft_plan(x, shape=self.n, axes=self.axis)
     with pytest.raises(RuntimeError) as ex, plan:
         fftpack.fft(x, n=self.n, axis=self.axis, plan=plan)
     assert 'Use the cuFFT plan either as' in str(ex.value)
예제 #2
0
def hilbert_2D(Volume_spectra: cp.ndarray) -> cp.array:
    """
    Compute the analytic signal, using the Hilbert transform. \
    The transformation is done along the last axis.

    Args:
        Volume_spectra::cp.ndarray
        2nd order tensor containing spectras raw data. Last dimension is depth encoding.

    Returns:
        Analytical signal of Volume_spectra::cp.ndarray
        :rtype: cp.ndarray

    Notes
    -----
    The analytic signal ``x_a(t)`` of signal ``x(t)`` is:
    .. math:: x_a = F^{-1}(F(x) 2U) = x + i y

    """

    if cp.iscomplexobj(Volume_spectra):
        raise ValueError("x must be real.")

    Volume_spectra = fftpack.fft(Volume_spectra,
                                  axis=-1,
                                  overwrite_x=True)[:,:Arguments.dimension[2]//2]

    dum =  cp.zeros_like(Volume_spectra)

    Volume_spectra = cp.concatenate( (Volume_spectra*2,dum), axis=1)

    return cp.fft.ifft(Volume_spectra, axis=1)
예제 #3
0
파일: cepstrum.py 프로젝트: mfkiwl/cusignal
def real_cepstrum(x, n=None, axis=-1):
    r"""
    Calculates the real cepstrum of an input sequence x where the cepstrum is
    defined as the inverse Fourier transform of the log magnitude DFT
    (spectrum) of a signal. It's primarily used for source/speaker separation
    in speech signal processing

    Parameters
    ----------
    x : ndarray
        Input sequence, if x is a matrix, return cepstrum in direction of axis
    n : int
        Size of Fourier Transform; If none, will use length of input array
    axis: int
        Direction for cepstrum calculation

    Returns
    -------
    ceps : ndarray
        Complex cepstrum result
    """
    x = cp.asarray(x)

    spectrum = fft.fft(x, n=n, axis=axis)
    ceps = fft.ifft(cp.log(cp.abs(spectrum)), n=n, axis=axis).real

    return ceps
예제 #4
0
def cceps(x, n=None, axis=-1):
    r"""
    Calculates the complex cepstrum of a real valued input sequence x
    where the cepstrum is defined as the inverse Fourier transform
    of the log magnitude DFT (spectrum) of a signal. It's primarily
    used for source/speaker separation in speech signal processing.

    The input is altered to have zero-phase at pi radians (180 degrees)
    Parameters
    ----------
    x : ndarray
        Input sequence, if x is a matrix, return cepstrum in direction of axis
    n : int
       Size of Fourier Transform; If none, will use length of input array
    axis: int
        Direction for cepstrum calculation
    Returns
    -------
    ceps : ndarray
        Complex cepstrum result
    """
    x = cp.asarray(x)

    h = fft.fft(x, n=n, axis=axis)
    ah = cceps_unwrap(cp.angle(h))
    logh = cp.log(cp.abs(h)) + 1j * ah
    cceps = fft.ifft(logh, n=n, axis=axis).real

    return cceps
예제 #5
0
def fft(x):
    global plan1D
    #print("Plan1D",plan1D)
    if plan1D == None and Plan:
        plan1D = fftpack.get_fft_plan(x, axes=(-1))

    return fftpack.fft(x, overwrite_x=owrite, plan=plan1D)
예제 #6
0
def process_2D(Volume_spectra: cp.ndarray, coordinates: cp.ndarray,
               dispersion: cp.array) -> np.array:
    """
    This function process 2D array of spectrum to return adjusted Bscan.

    :param Volume_spectra: 2nd order tensor containing spectras raw data. Last dimension is depth encoding.
    :type Volume_spectra: cp.ndarray
    :param coordinates: 2D array containing coordinates for k-linearization interpolation.
    :type coordinates: cp.ndarray
    :param dispersion: Array with value for dispersion compensation.
    :type dispersion: cp.array
    """

    if Arguments.dimension[1] == 1:
        Volume_spectra = cp.expand_dims(Volume_spectra, axis=0)
        coordinates = cp.array([coordinates[1]])
        Volume_spectra = detrend_1D(Volume_spectra)
        Volume_spectra = compensate_dispersion_2D(Volume_spectra, dispersion)
        Volume_spectra = linearize_spectra_1D(Volume_spectra, coordinates)

    else:
        Volume_spectra = detrend_2D(Volume_spectra)
        Volume_spectra = compensate_dispersion_2D(Volume_spectra, dispersion)
        Volume_spectra = linearize_spectra_2D(Volume_spectra, coordinates)

    if Arguments.shift:
        Volume_spectra = spectrum_shift_2D(Volume_spectra)

    Volume_spectra = fftpack.fft(
        Volume_spectra, axis=1,
        overwrite_x=True)[:, :Arguments.dimension[2] // 2]

    return cp.asnumpy(cp.absolute(Volume_spectra))
예제 #7
0
파일: cepstrum.py 프로젝트: mfkiwl/cusignal
def complex_cepstrum(x, n=None, axis=-1):
    r"""
    Calculates the complex cepstrum of a real valued input sequence x
    where the cepstrum is defined as the inverse Fourier transform
    of the log magnitude DFT (spectrum) of a signal. It's primarily
    used for source/speaker separation in speech signal processing.

    The input is altered to have zero-phase at pi radians (180 degrees)
    Parameters
    ----------
    x : ndarray
        Input sequence, if x is a matrix, return cepstrum in direction of axis
    n : int
       Size of Fourier Transform; If none, will use length of input array
    axis: int
        Direction for cepstrum calculation
    Returns
    -------
    ceps : ndarray
        Complex cepstrum result
    """
    x = cp.asarray(x)

    def _unwrap(x):
        r"""
        Unwrap phase for complex cepstrum calculation; helper function
        """

        samples = len(x)
        unwrapped = cp.unwrap(x)
        center = math.floor((samples + 1) / 2)
        ndelay = cp.round_(unwrapped[center] / cp.pi)
        unwrapped -= cp.pi * ndelay * cp.arange(samples) / center

        return unwrapped, ndelay

    spectrum = fft.fft(x, n=n, axis=axis)
    unwrapped_phase, ndelay = _unwrap(cp.angle(spectrum))
    log_spectrum = cp.log(cp.abs(spectrum)) + 1j * unwrapped_phase
    ceps = fft.ifft(log_spectrum, n=n, axis=axis).real

    return ceps, ndelay
예제 #8
0
파일: resample.py 프로젝트: zz4fap/cusignal
def resample(x, num, t=None, axis=0, window=None, domain="time"):
    """
    Resample `x` to `num` samples using Fourier method along the given axis.

    The resampled signal starts at the same value as `x` but is sampled
    with a spacing of ``len(x) / num * (spacing of x)``.  Because a
    Fourier method is used, the signal is assumed to be periodic.

    Parameters
    ----------
    x : array_like
        The data to be resampled.
    num : int
        The number of samples in the resampled signal.
    t : array_like, optional
        If `t` is given, it is assumed to be the sample positions
        associated with the signal data in `x`.
    axis : int, optional
        The axis of `x` that is resampled.  Default is 0.
    window : array_like, callable, string, float, or tuple, optional
        Specifies the window applied to the signal in the Fourier
        domain.  See below for details.
    domain : string, optional
        A string indicating the domain of the input `x`:

        ``time``
           Consider the input `x` as time-domain. (Default)
        ``freq``
           Consider the input `x` as frequency-domain.

    Returns
    -------
    resampled_x or (resampled_x, resampled_t)
        Either the resampled array, or, if `t` was given, a tuple
        containing the resampled array and the corresponding resampled
        positions.

    See Also
    --------
    decimate : Downsample the signal after applying an FIR or IIR filter.
    resample_poly : Resample using polyphase filtering and an FIR filter.

    Notes
    -----
    The argument `window` controls a Fourier-domain window that tapers
    the Fourier spectrum before zero-padding to alleviate ringing in
    the resampled values for sampled signals you didn't intend to be
    interpreted as band-limited.

    If `window` is a function, then it is called with a vector of inputs
    indicating the frequency bins (i.e. fftfreq(x.shape[axis]) ).

    If `window` is an array of the same length as `x.shape[axis]` it is
    assumed to be the window to be applied directly in the Fourier
    domain (with dc and low-frequency first).

    For any other type of `window`, the function `cusignal.get_window`
    is called to generate the window.

    The first sample of the returned vector is the same as the first
    sample of the input vector.  The spacing between samples is changed
    from ``dx`` to ``dx * len(x) / num``.

    If `t` is not None, then it represents the old sample positions,
    and the new sample positions will be returned as well as the new
    samples.

    As noted, `resample` uses FFT transformations, which can be very
    slow if the number of input or output samples is large and prime;
    see `scipy.fftpack.fft`.

    Examples
    --------
    Note that the end of the resampled data rises to meet the first
    sample of the next cycle:

    >>> import cusignal
    >>> import cupy as cp

    >>> x = cp.linspace(0, 10, 20, endpoint=False)
    >>> y = cp.cos(-x**2/6.0)
    >>> f = cusignal.resample(y, 100)
    >>> xnew = cp.linspace(0, 10, 100, endpoint=False)

    >>> import matplotlib.pyplot as plt
    >>> plt.plot(x, y, 'go-', xnew, f, '.-', 10, y[0], 'ro')
    >>> plt.legend(['data', 'resampled'], loc='best')
    >>> plt.show()
    """
    x = asarray(x)
    Nx = x.shape[axis]

    if domain == "time":
        X = fftpack.fft(x, axis=axis)
    elif domain == "freq":
        X = x
    else:
        raise NotImplementedError("domain should be 'time' or 'freq'")

    if window is not None:
        if callable(window):
            W = window(fftpack.fftfreq(Nx))
        elif isinstance(window, ndarray):
            if window.shape != (Nx,):
                raise ValueError("window must have the same length as data")
            W = window
        else:
            W = ifftshift(get_window(window, Nx))
        newshape = [1] * x.ndim
        newshape[axis] = len(W)
        W.shape = newshape
        X = X * W
    sl = [slice(None)] * x.ndim
    newshape = list(x.shape)
    newshape[axis] = num
    N = int(cp.minimum(num, Nx))
    Y = zeros(newshape, "D")
    sl[axis] = slice(0, (N + 1) // 2)
    Y[sl] = X[sl]
    sl[axis] = slice(-(N - 1) // 2, None)
    Y[sl] = X[sl]
    y = fftpack.ifft(Y, axis=axis) * (float(num) / float(Nx))

    if x.dtype.char not in ["F", "D"]:
        y = y.real

    if t is None:
        return y
    else:
        new_t = arange(0, num) * (t[1] - t[0]) * Nx / float(num) + t[0]
        return y, new_t
예제 #9
0
def channelize_poly(x, h, n_chans):
    """
    Polyphase channelize signal into n channels

    Parameters
    ----------
    x : array_like
        The input data to be channelized
    h : array_like
        The 1-D input filter; will be split into n
        channels of int number of taps
    n_chans : int
        Number of channels for channelizer

    Returns
    ----------
    yy : channelized output matrix

    Notes
    ----------
    Currently only supports simple channelizer where channel
    spacing is equivalent to the number of channels used (zero overlap).
    Number of filter taps (len of filter / n_chans) must be <=32.

    """

    dtype = cp.promote_types(x.dtype, h.dtype)

    x = asarray(x, dtype=dtype)
    h = asarray(h, dtype=dtype)

    # number of taps in each h_n filter
    n_taps = int(len(h) / n_chans)
    if n_taps > 32:
        raise NotImplementedError(
            "The number of calculated taps ({}) in  \
            each filter is currently capped at 32. Please reduce filter \
                length or number of channels".format(
                n_taps
            )
        )

    if n_taps > 32:
        raise NotImplementedError(
            "Number of taps ({}) must be less than (32).".format(n_taps)
        )

    # number of outputs
    n_pts = int(len(x) / n_chans)

    if x.dtype == cp.float32 or x.dtype == cp.complex64:
        y = cp.empty((n_pts, n_chans), dtype=cp.complex64)
    elif x.dtype == cp.float64 or x.dtype == cp.complex128:
        y = cp.empty((n_pts, n_chans), dtype=cp.complex128)

    _channelizer(x, h, y, n_chans, n_taps, n_pts)

    # Remove with CuPy v8
    if (x.dtype, n_pts, n_taps, n_chans) in _cupy_fft_cache:
        plan = _cupy_fft_cache[(x.dtype, n_pts, n_taps, n_chans)]
    else:
        plan = _cupy_fft_cache[
            (x.dtype, n_pts, n_taps, n_chans)
        ] = fftpack.get_fft_plan(y, axes=-1)

    return cp.conj(fftpack.fft(y, overwrite_x=True, plan=plan)).T
예제 #10
0
def hilbert(x, N=None, axis=-1):
    """
    Compute the analytic signal, using the Hilbert transform.

    The transformation is done along the last axis by default.

    Parameters
    ----------
    x : array_like
        Signal data.  Must be real.
    N : int, optional
        Number of Fourier components.  Default: ``x.shape[axis]``
    axis : int, optional
        Axis along which to do the transformation.  Default: -1.

    Returns
    -------
    xa : ndarray
        Analytic signal of `x`, of each 1-D array along `axis`

    Notes
    -----
    The analytic signal ``x_a(t)`` of signal ``x(t)`` is:

    .. math:: x_a = F^{-1}(F(x) 2U) = x + i y

    where `F` is the Fourier transform, `U` the unit step function,
    and `y` the Hilbert transform of `x`. [1]_

    In other words, the negative half of the frequency spectrum is zeroed
    out, turning the real-valued signal into a complex signal.  The Hilbert
    transformed signal can be obtained from ``cp.imag(hilbert(x))``, and the
    original signal from ``cp.real(hilbert(x))``.

    Examples
    ---------
    In this example we use the Hilbert transform to determine the amplitude
    envelope and instantaneous frequency of an amplitude-modulated signal.

    >>> import cupy as cp
    >>> import matplotlib.pyplot as plt
    >>> from cusignal import hilbert, chirp

    >>> duration = 1.0
    >>> fs = 400.0
    >>> samples = int(fs*duration)
    >>> t = cp.arange(samples) / fs

    We create a chirp of which the frequency increases from 20 Hz to 100 Hz and
    apply an amplitude modulation.

    >>> signal = chirp(t, 20.0, t[-1], 100.0)
    >>> signal *= (1.0 + 0.5 * cp.sin(2.0*cp.pi*3.0*t) )

    The amplitude envelope is given by magnitude of the analytic signal. The
    instantaneous frequency can be obtained by differentiating the
    instantaneous phase in respect to time. The instantaneous phase corresponds
    to the phase angle of the analytic signal.

    >>> analytic_signal = hilbert(signal)
    >>> amplitude_envelope = cp.abs(analytic_signal)
    >>> instantaneous_phase = cp.unwrap(cp.angle(analytic_signal))
    >>> instantaneous_frequency = (cp.diff(instantaneous_phase) /
    ...                            (2.0*cp.pi) * fs)

    >>> fig = plt.figure()
    >>> ax0 = fig.add_subplot(211)
    >>> ax0.plot(cp.asnumpy(t), cp.asnumpy(signal), label='signal')
    >>> ax0.plot(cp.asnumpy(t), cp.asnumpy(amplitude_envelope), \
        label='envelope')
    >>> ax0.set_xlabel("time in seconds")
    >>> ax0.legend()
    >>> ax1 = fig.add_subplot(212)
    >>> ax1.plot(t[1:], instantaneous_frequency)
    >>> ax1.set_xlabel("time in seconds")
    >>> ax1.set_ylim(0.0, 120.0)

    References
    ----------
    .. [1] Wikipedia, "Analytic signal".
           https://en.wikipedia.org/wiki/Analytic_signal
    .. [2] Leon Cohen, "Time-Frequency Analysis", 1995. Chapter 2.
    .. [3] Alan V. Oppenheim, Ronald W. Schafer. Discrete-Time Signal
           Processing, Third Edition, 2009. Chapter 12.
           ISBN 13: 978-1292-02572-8

    """
    x = asarray(x)
    if iscomplexobj(x):
        raise ValueError("x must be real.")
    if N is None:
        N = x.shape[axis]
    if N <= 0:
        raise ValueError("N must be positive.")

    Xf = fftpack.fft(x, N, axis=axis)
    h = zeros(N)
    if N % 2 == 0:
        h[0] = h[N // 2] = 1
        h[1 : N // 2] = 2
    else:
        h[0] = 1
        h[1 : (N + 1) // 2] = 2

    if x.ndim > 1:
        ind = [newaxis] * x.ndim
        ind[axis] = slice(None)
        h = h[tuple(ind)]
    x = fftpack.ifft(Xf * h, axis=axis)
    return x