# -*- coding: utf-8 -*- # Copyright 2014 João Felipe Santos, jfsantos@emt.inrs.ca # # This file is part of the SRMRpy library, and is licensed under the # MIT license: https://github.com/jfsantos/SRMRpy/blob/master/LICENSE import numpy as np from numpy.fft import fft, ifft # This is copied straight from scipy.signal. The reason is that scipy.signal's version # will always use the fft and ifft functions from fftpack. If you have Anaconda with an MKL # license, you can install the package mklfft, which will plug the faster MKL FFT functions # into numpy. 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 ``np.imag(hilbert(x))``, and the original signal from ``np.real(hilbert(x))``. References ---------- .. [1] Wikipedia, "Analytic signal". http://en.wikipedia.org/wiki/Analytic_signal """ x = np.asarray(x) if np.iscomplexobj(x): raise ValueError("x must be real.") if N is None: N = x.shape[axis] # Make N multiple of 16 to make sure the transform will be fast if N % 16: N = int(np.ceil(N/16)*16) if N <= 0: raise ValueError("N must be positive.") Xf = fft(x, N, axis=axis) h = np.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 len(x.shape) > 1: ind = [np.newaxis] * x.ndim ind[axis] = slice(None) h = h[ind] y = ifft(Xf * h, axis=axis) return y[:x.shape[axis]]