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
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
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
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
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
def ifft(x): global plan1D if plan1D == None and Plan: plan1D = fftpack.get_fft_plan(x, axes=(-1)) return fftpack.ifft(x, overwrite_x=owrite, plan=plan1D)