Skip to content

Commit 2e04473

Browse files
a-drenalineDietBru
andauthored
DOC: signal.hilbert: update to reflect implementation (scipy#21378)
--------- Co-authored-by: Dietrich Brunn <[email protected]>
1 parent faaff15 commit 2e04473

File tree

1 file changed

+33
-29
lines changed

1 file changed

+33
-29
lines changed

scipy/signal/_signaltools.py

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2316,9 +2316,13 @@ def deconvolve(signal, divisor):
23162316

23172317

23182318
def hilbert(x, N=None, axis=-1):
2319-
"""
2320-
Compute the analytic signal, using the Hilbert transform.
2319+
r"""FFT-based computation of the analytic signal.
23212320
2321+
The analytic signal is calculated by filtering out the negative frequencies and
2322+
doubling the amplitudes of the positive frequencies in the FFT domain.
2323+
The imaginary part of the result is the hilbert transform of the real-valued input
2324+
signal.
2325+
23222326
The transformation is done along the last axis by default.
23232327
23242328
Parameters
@@ -2337,24 +2341,27 @@ def hilbert(x, N=None, axis=-1):
23372341
23382342
Notes
23392343
-----
2340-
The analytic signal ``x_a(t)`` of signal ``x(t)`` is:
2344+
The analytic signal ``x_a(t)`` of a real-valued signal ``x(t)``
2345+
can be expressed as [1]_
23412346
2342-
.. math:: x_a = F^{-1}(F(x) 2U) = x + i y
2347+
.. math:: x_a = F^{-1}(F(x) 2U) = x + i y\ ,
23432348
23442349
where `F` is the Fourier transform, `U` the unit step function,
2345-
and `y` the Hilbert transform of `x`. [1]_
2350+
and `y` the Hilbert transform of `x`. [2]_
23462351
23472352
In other words, the negative half of the frequency spectrum is zeroed
2348-
out, turning the real-valued signal into a complex signal. The Hilbert
2353+
out, turning the real-valued signal into a complex-valued signal. The Hilbert
23492354
transformed signal can be obtained from ``np.imag(hilbert(x))``, and the
23502355
original signal from ``np.real(hilbert(x))``.
23512356
23522357
References
23532358
----------
23542359
.. [1] Wikipedia, "Analytic signal".
23552360
https://en.wikipedia.org/wiki/Analytic_signal
2356-
.. [2] Leon Cohen, "Time-Frequency Analysis", 1995. Chapter 2.
2357-
.. [3] Alan V. Oppenheim, Ronald W. Schafer. Discrete-Time Signal
2361+
.. [2] Wikipedia, "Hilbert Transform".
2362+
https://en.wikipedia.org/wiki/Hilbert_transform
2363+
.. [3] Leon Cohen, "Time-Frequency Analysis", 1995. Chapter 2.
2364+
.. [4] Alan V. Oppenheim, Ronald W. Schafer. Discrete-Time Signal
23582365
Processing, Third Edition, 2009. Chapter 12.
23592366
ISBN 13: 978-1292-02572-8
23602367
@@ -2363,41 +2370,38 @@ def hilbert(x, N=None, axis=-1):
23632370
In this example we use the Hilbert transform to determine the amplitude
23642371
envelope and instantaneous frequency of an amplitude-modulated signal.
23652372
2373+
Let's create a chirp of which the frequency increases from 20 Hz to 100 Hz and
2374+
apply an amplitude modulation:
2375+
23662376
>>> import numpy as np
23672377
>>> import matplotlib.pyplot as plt
23682378
>>> from scipy.signal import hilbert, chirp
2369-
2370-
>>> duration = 1.0
2371-
>>> fs = 400.0
2372-
>>> samples = int(fs*duration)
2373-
>>> t = np.arange(samples) / fs
2374-
2375-
We create a chirp of which the frequency increases from 20 Hz to 100 Hz and
2376-
apply an amplitude modulation.
2377-
2379+
...
2380+
>>> duration, fs = 1, 400 # 1 s signal with sampling frequency of 400 Hz
2381+
>>> t = np.arange(int(fs*duration)) / fs # timestamps of samples
23782382
>>> signal = chirp(t, 20.0, t[-1], 100.0)
23792383
>>> signal *= (1.0 + 0.5 * np.sin(2.0*np.pi*3.0*t) )
23802384
2381-
The amplitude envelope is given by magnitude of the analytic signal. The
2385+
The amplitude envelope is given by the magnitude of the analytic signal. The
23822386
instantaneous frequency can be obtained by differentiating the
23832387
instantaneous phase in respect to time. The instantaneous phase corresponds
23842388
to the phase angle of the analytic signal.
23852389
23862390
>>> analytic_signal = hilbert(signal)
23872391
>>> amplitude_envelope = np.abs(analytic_signal)
23882392
>>> instantaneous_phase = np.unwrap(np.angle(analytic_signal))
2389-
>>> instantaneous_frequency = (np.diff(instantaneous_phase) /
2390-
... (2.0*np.pi) * fs)
2391-
2392-
>>> fig, (ax0, ax1) = plt.subplots(nrows=2)
2393-
>>> ax0.plot(t, signal, label='signal')
2394-
>>> ax0.plot(t, amplitude_envelope, label='envelope')
2395-
>>> ax0.set_xlabel("time in seconds")
2393+
>>> instantaneous_frequency = np.diff(instantaneous_phase) / (2.0*np.pi) * fs
2394+
...
2395+
>>> fig, (ax0, ax1) = plt.subplots(nrows=2, sharex='all', tight_layout=True)
2396+
>>> ax0.set_title("Amplitude-modulated Chirp Signal")
2397+
>>> ax0.set_ylabel("Amplitude")
2398+
>>> ax0.plot(t, signal, label='Signal')
2399+
>>> ax0.plot(t, amplitude_envelope, label='Envelope')
23962400
>>> ax0.legend()
2397-
>>> ax1.plot(t[1:], instantaneous_frequency)
2398-
>>> ax1.set_xlabel("time in seconds")
2399-
>>> ax1.set_ylim(0.0, 120.0)
2400-
>>> fig.tight_layout()
2401+
>>> ax1.set(xlabel="Time in seconds", ylabel="Phase in rad", ylim=(0, 120))
2402+
>>> ax1.plot(t[1:], instantaneous_frequency, 'C2-', label='Instantaneous Phase')
2403+
>>> ax1.legend()
2404+
>>> plt.show()
24012405
24022406
"""
24032407
x = np.asarray(x)

0 commit comments

Comments
 (0)