Skip to content

The Hilbert transform and the analytic signal

Use the Hilbert transform to remove a real signal's negative frequencies, then read its envelope and instantaneous frequency off one spinning arrow.

Before this15.5 · 19.4 · 3 more
Chapter 27 · Lesson 2 of 5

First, the picture

Half of a real signal’s spectrum is enough. Below, a signal’s spectrum is added to that of a quarter-turned copy: watch the stems at negative bins cancel while those at positive bins double.

Add a quarter turn, lose the negative half

x[n] = cos(2π·6n/64) + 0.5 cos(2π·16n/64): its DFT ÷ 64, bins −32 to 31.

A real signal: 0.50 at bins 6 and −6, 0.25 at 16 and −16, a mirror image.

showing
x
at k = 6
0.50
at k = −6
0.50
0.00 / 12.00 s
Describe this picture

The DFT of x[n]=cos⁡(2π⋅6n/64)+0.5cos⁡(2π⋅16n/64)x[n]=\cos(2\pi\cdot6n/64)+0.5\cos(2\pi\cdot16n/64), divided by 64, for bins −32 to 31. One panel: value ÷ NN from −0.6 to 1.1 against the bin kk. Stems with round heads show the DFT of xx, stems with square heads, just beside them, the DFT of jx^j\hat x, and stems with filled diamonds their sum. The readouts are what is showing and the values at k=6k=6 and k=−6k=-6. The clip plays once, in 12 s, and has no control. It opens on the real signal: 0.50 at bins 6 and −6 and 0.25 at 16 and −16, a mirror image. From 3 s the square-headed stems grow in: jj times the Hilbert transform is the same on the positive side and negated on the negative side, so the readouts show 0.50 and −0.50. From 7 s each square-headed stem slides onto its round-headed partner and rides up on its tip, and each pair becomes one diamond-headed stem. At the end the sum is 1.00 at bin 6, 0.50 at bin 16 and nothing at negative bins: the analytic signal is one-sided.

Half a spectrum is enough

A real signal’s spectrum comes in mirror pairs. “A real signal has a mirrored spectrum” in Properties of the Fourier transform (8.2) showed it: the spectrum at a negative frequency is the conjugate of the spectrum at the matching positive one. So the negative half tells you nothing new.

Where do the pairs come from? A cosine is two arrows spinning opposite ways, as in “Two points spinning opposite ways” of Complex exponentials & phasors (3.4). The backward arrow is there only to cancel the forward arrow’s imaginary part.

On this page I throw the backward arrows away. A tone is then one spinning arrow, and so is a signal with one main frequency at a time. The arrow’s length shows how strong the signal is at each moment, and its turning shows how fast it oscillates.

The tool that does it is the filter of “A Hilbert transformer” in Special FIR filters (19.4). Let’s give it a name and a formula first.

The Hilbert transform

The sign function sgn\mathrm{sgn} gives 1 for a positive number, −1 for a negative one and 0 for 0. The Hilbert transform is the filter with the frequency response

H(ejΩ)=−j sgn Ω,H(e^{j\Omega})=-j\,\mathrm{sgn}\,\Omega,

for −π<Ω<π-\pi<\Omega<\pi. This is 19.4’s ideal Hilbert transformer: −j-j for 0<Ω<π0<\Omega<\pi, and +j+j for −π<Ω<0-\pi<\Omega<0. Its output is written x^[n]\hat x[n], “x hat”. In “Draws pile up into a density” of Random variables for signals (24.1), a hat meant an estimate; on a signal xx it means the Hilbert transform.

Multiplying by −j-j turns an arrow a quarter turn back, −π/2-\pi/2 rad (−90°). Multiplying by +j+j turns it a quarter turn forward. So the forward arrow of a cosine turns back and its backward twin turns forward, and 19.4 showed what comes out: a sine. In the same way a sine becomes −cos⁡-\cos.

That holds for every frequency strictly between 0 and π\pi. At 0 the response is 0, because sgn 0=0\mathrm{sgn}\,0=0. At π\pi, where the two sides meet, it is set to 0 as well. A constant and the alternation 1,−1,1,…1,-1,1,\dots have no sine partner: sin⁡(0⋅n)\sin(0\cdot n) and sin⁡(πn)\sin(\pi n) are 0 at every sample.

Add it back as an imaginary part

Now take the signal and add jj times its Hilbert transform. The result is the analytic signal:

xan[n]=x[n]+jx^[n].x_\text{an}[n]=x[n]+j\hat x[n].

Its frequency response is 1+j(−j sgn Ω)=1+sgn Ω1+j(-j\,\mathrm{sgn}\,\Omega)=1+\mathrm{sgn}\,\Omega. That is 2 for positive frequencies, 0 for negative ones, and 1 at 0 and at π\pi. The negative half is gone and the positive half is doubled.

Let’s watch that happen on a signal of N=64N=64 samples, two cosines on exact DFT bins:

x[n]=cos⁡(2π 6n/64)+0.5cos⁡(2π 16n/64).\begin{aligned} x[n]&=\cos(2\pi\,6n/64)\\ &\quad+0.5\cos(2\pi\,16n/64). \end{aligned}

I divide its DFT by NN, so that each arrow’s size can be read off directly. Each cosine gives half its size at its two bins: 0.5 at bins 6 and −6, and 0.25 at bins 16 and −16. Bin −6 is bin 58, by “Bins in hertz, and the mirror” in The DFT (13.2).

The Hilbert transform makes both cosines sines. A sine’s two arrows are 12jejΩ0n\tfrac1{2j}e^{j\Omega_0n} and −12je−jΩ0n-\tfrac1{2j}e^{-j\Omega_0n}. Multiplied by jj, they become 12ejΩ0n\tfrac12e^{j\Omega_0n} and −12e−jΩ0n-\tfrac12e^{-j\Omega_0n}. On the positive side that is the cosine’s own arrow; on the negative side it is the cosine’s arrow reversed.

Add a quarter turn, lose the negative half

The picture at the top of the page does this for the two cosines. Watch each square-headed stem slide onto its round-headed partner: at bin 6 the pair adds up to 1.00, and at bin −6 it cancels to 0.00.

Think of two people pushing a swing. On one side of zero the two spectra push in step and the stems add up. On the other side they push against each other and cancel.

Notice the power. The signal’s power, the mean of x[n]2x[n]^2, is 0.625. The analytic signal’s, the mean of ∣xan[n]∣2\lvert x_\text{an}[n]\rvert^2, is 1.250: twice as much.

13.2’s “Energy in time and in bins” says why. Divided by NN, the bins’ squares add up to the power. The signal has 2⋅0.52+2⋅0.252=0.6252\cdot0.5^2+2\cdot0.25^2=0.625. The analytic signal has 12+0.52=1.251^2+0.5^2=1.25. Each pair of size aa becomes one stem of size 2a2a, and (2a)2(2a)^2 is twice 2a22a^2.

That doubling needs a signal with nothing at 0 or at π\pi: those two bins are kept as they are, not doubled.

A spinning arrow’s length and speed

Start with one tone, x[n]=Acos⁡(Ω0n+ϕ)x[n]=A\cos(\Omega_0n+\phi), with 0<Ω0<π0<\Omega_0<\pi. Its Hilbert transform is Asin⁡(Ω0n+ϕ)A\sin(\Omega_0n+\phi), so

xan[n]=Aej(Ω0n+ϕ).x_\text{an}[n]=Ae^{j(\Omega_0n+\phi)}.

That is one arrow of length AA. Its angle is the tone’s phase at sample nn, and it turns by Ω0\Omega_0 every sample. The worked example below does this by hand.

Most signals are not one steady tone. Their strength and their frequency change as they go. The analytic signal gives a name to each of them at every sample:

  • the envelope is the arrow’s length, ∣xan[n]∣\lvert x_\text{an}[n]\rvert;
  • the instantaneous phase is its angle, ∠xan[n]\angle x_\text{an}[n], in (−π,π](-\pi,\pi] as in Complex numbers for signals (3.3);
  • the instantaneous frequency is how far it turns from one sample to the next, in cycles per sample.

To find that turn, multiply the arrow by the conjugate of the one before. The angle of the product is the difference of the two angles, mod 2π2\pi:

finst[n]=∠(xan[n] xan∗[n−1])2π.f_\text{inst}[n]=\frac{\angle\big(x_\text{an}[n]\,x_\text{an}^*[n-1]\big)}{2\pi}.

This step belongs between samples n−1n-1 and nn. It is right as long as the arrow turns less than half a turn per sample, and an analytic signal’s frequencies lie between 0 and half a turn.

A chirp under a bell

Here is a signal whose strength and frequency both change. It is a chirp, the gliding tone of “Reading a chirp” in Spectrograms & the STFT (15.5), under a Gaussian envelope, the bell of Random variables for signals (24.1):

x[n]=e−12(n−25680)2⋅cos⁡(2π(0.04n+0.16 n22⋅511)),\begin{aligned} x[n]&=e^{-\frac12\left(\frac{n-256}{80}\right)^2}\\ &\quad\cdot\cos\Big(2\pi\big(0.04n+\tfrac{0.16\,n^2}{2\cdot511}\big)\Big), \end{aligned}

for n=0n=0 to 511. The bell peaks at 1 at n=256n=256, with a standard deviation of 80 samples. The cosine’s angle turns by 2π(0.04+0.16n/511)2\pi(0.04+0.16n/511) per sample near nn. So its frequency rises along a straight line, from 0.04 cycles per sample at the start to 0.20 at the end.

I compute its analytic signal with the FFT, in three steps. Take the 512-point DFT. Keep bins 0 and 256 as they are, double bins 1 to 255 and set bins 257 to 511, the negative frequencies, to 0. Then take the inverse DFT.

This is exactly what scipy.signal.hilbert does. Despite its name, it returns the analytic signal xanx_\text{an}, not x^\hat x; x^\hat x is its imaginary part.

A spinning arrow's length and speed

A chirp from 0.04 to 0.20 cycles/sample under a Gaussian envelope, 512 samples.

At n = 64 the envelope is only 0.056: a short arrow, turning at 0.0600 cycles per sample.

n
64
envelope
0.056
frequency
0.0600 cycles/sample
0.00 / 14.00 s
Describe this picture

A chirp from 0.04 to 0.20 cycles/sample under a Gaussian envelope, 512 samples, in three panels. The first, the signal, draws x[n]x[n] as a thin solid line from −1.2 to 1.2 against nn from 0 to 511, with dashed lines at ±∣xan[n]∣\pm\lvert x_\text{an}[n]\rvert, the envelope, from n=64n=64 to the current sample. The second, the instantaneous frequency, from 0 to 0.25 cycles/sample against nn, draws the chirp’s straight line dotted over the whole record and the estimate from the arrow solid, from n=64n=64 to the current sample. The third, a square complex plane from −1.1 to 1.1 on both axes, draws the arrow xan[n]x_\text{an}[n] with its last 20 tips as small dots. The readouts are nn, the envelope and the frequency in cycles/sample. The frequency readout averages the two steps on either side of nn, so that the value sits at nn rather than half a sample before it. The clip opens at n=64n=64: the envelope is only 0.056, a short arrow turning at 0.0600 cycles per sample. From 2.5 s the sample runs to 256, the centre, where the arrow is longest, 1.000, and turns at 0.1202 cycles per sample, on the chirp’s line. From 9 s it runs on to 448, where the arrow has shrunk to 0.056 and turns at 0.1804. When the clip ends, a full-width slider “Sample n” moves from 64 to 448, and the caption gives the envelope and the turning speed at that sample.

Watch the arrow as the sample runs across the pulse. Its length rises to 1.000 at the centre and falls again with the bell, while its turning speed climbs steadily, from 0.0600 to 0.1804 cycles per sample.

Notice how closely the two lines in the frequency panel agree. From n=64n=64 to 448 the estimate follows the chirp’s line to within 1.4×10−41.4\times10^{-4} cycles per sample. Over the same samples the arrow’s length matches the bell to within 4.5×10−54.5\times10^{-5}.

Think of a lighthouse. How bright its beam is and how fast it sweeps are two separate facts, and you can read both. The analytic signal does the same for a signal: the length and the speed come apart.

Where the FFT method fails

Why do the traces stop at 64 and 448? There the envelope has fallen to 0.056 of its peak. Further out, the measured frequency goes wrong, by up to 0.298 cycles per sample at the very end.

The Hilbert transform at one sample uses samples far away on both sides. Its taps, 2/(πm)2/(\pi m) for odd mm in 19.4, shrink only slowly. Near the ends of the record those samples are missing: the FFT method uses the other end instead, as if the record repeated.

The error this causes is small. The arrow should be the bell’s height, turned to the chirp’s angle, and it is never more than 0.0075 away from that. But at n=511n=511 the bell is only 0.0062, and the FFT method gives a length of 0.0032. There the error, 0.0075, is larger than the arrow itself, so its angle means nothing.

In real time there is no whole record to transform. Then 19.4’s FIR Hilbert transformer gives x^\hat x sample by sample. Its 31-tap design delays its output by 15 samples, so xx is delayed by 15 samples too before the two are paired.

Single sideband

Amplitude modulation (27.1) sent a message x[n]x[n] as DSB, x[n]cos⁡Ω1nx[n]\cos\Omega_1n. Its spectrum has two sidebands around the carrier: the upper sideband above Ω1\Omega_1 and the lower sideband below it. They are mirror images, so they carry the same message twice.

The analytic signal sends it once. Move xanx_\text{an} up to the carrier and keep the real part:

Re (xan[n] ejΩ1n)=x[n]cos⁡Ω1n−x^[n]sin⁡Ω1n.\begin{aligned} &\mathrm{Re}\,\big(x_\text{an}[n]\,e^{j\Omega_1n}\big)\\ &\quad=x[n]\cos\Omega_1n-\hat x[n]\sin\Omega_1n. \end{aligned}

xanx_\text{an} has only positive frequencies, so after the move they all sit above Ω1\Omega_1. Taking the real part adds their mirror image below −Ω1-\Omega_1. That is only the upper sideband: single sideband, or SSB.

If the message’s frequencies run from 0 up to some highest frequency, DSB fills a band twice that wide around the carrier, and SSB a band once that wide. That needs a carrier above the message’s highest frequency, and a band that ends below π\pi. For one tone, x[n]=cos⁡Ω0nx[n]=\cos\Omega_0n, SSB gives cos⁡((Ω1+Ω0)n)\cos\big((\Omega_1+\Omega_0)n\big): one line, where DSB has two, at Ω1±Ω0\Omega_1\pm\Omega_0. Change the minus to a plus, and you keep the lower sideband instead.

Worked example

1. One tone by hand. Write a cosine as two arrows, cos⁡Ω0n=12ejΩ0n+12e−jΩ0n\cos\Omega_0n=\tfrac12e^{j\Omega_0n}+\tfrac12e^{-j\Omega_0n}, with 0<Ω0<π0<\Omega_0<\pi. Its Hilbert transform is

x^[n]=sin⁡Ω0n=12jejΩ0n−12je−jΩ0n.\hat x[n]=\sin\Omega_0n=\tfrac1{2j}e^{j\Omega_0n}-\tfrac1{2j}e^{-j\Omega_0n}.

Times jj, that is 12ejΩ0n−12e−jΩ0n\tfrac12e^{j\Omega_0n}-\tfrac12e^{-j\Omega_0n}. Add the cosine, and the backward arrows cancel: xan[n]=ejΩ0nx_\text{an}[n]=e^{j\Omega_0n}. Its length is 1 at every sample, and it turns by Ω0\Omega_0 per sample.

2. The FFT method on four samples. Take x=1,0,−1,0x=1,0,-1,0 for n=0,1,2,3n=0,1,2,3, which is cos⁡(πn/2)\cos(\pi n/2). Its DFT is 0,2,0,20,2,0,2. With N=4N=4, bin 1 is the positive frequency, bin 3 the negative one and bin 2 is N/2N/2.

Keep bins 0 and 2, double bin 1 and clear bin 3: 0,4,0,00,4,0,0. The inverse DFT is 14⋅4 ej2πn/4=ejπn/2\tfrac14\cdot4\,e^{j2\pi n/4}=e^{j\pi n/2}, that is 1,j,−1,−j1,j,-1,-j. So x^=0,1,0,−1\hat x=0,1,0,-1, which is sin⁡(πn/2)\sin(\pi n/2).

The envelope is 1 at every sample. Each step is j⋅1∗=jj\cdot1^*=j, a quarter turn, so finst=0.25f_\text{inst}=0.25 cycles per sample: one turn in 4 samples.

3. The clip’s centre. At n=256n=256 the bell is 1, and the arrow’s length is 1.000. The steps on either side are 0.1200 and 0.1203 cycles per sample, and their mean is 0.1202. The chirp’s line gives 0.04+0.16⋅256/511=0.12020.04+0.16\cdot256/511=0.1202.

Where you’ll meet this

Ultrasound scanners form their pictures from envelopes. Each echo line is a burst of a few megahertz, and the brightness of a pixel comes from the burst’s envelope. Radar receivers find their pulses the same way.

Single-sideband radio, used by radio amateurs and on long-range aviation and marine voice channels, sends each voice once, in half the bandwidth of DSB. Machine monitoring reads the envelope of a vibration: a bearing fault shows up as a repeating knock in it. Audio analysis uses the instantaneous frequency to follow a tone whose pitch glides, as the instrument followed the chirp.

An FM receiver reads the message straight off the instantaneous frequency: Frequency and phase modulation (27.4). A complex signal built from two real ones, as xanx_\text{an} is from xx and x^\hat x, is also the idea behind I/Q and complex baseband (27.3).

In continuous time the Hilbert transform is a convolution with 1/(πt)1/(\pi t). For more, see Oppenheim and Schafer, Discrete-Time Signal Processing (3rd ed., 2010), ch. 12, and R. G. Lyons, Understanding Digital Signal Processing (3rd ed., 2011), ch. 9.

The maths behind it · diagonal matrices

In the DFT basis the FFT method is a diagonal matrix: weight 1 on bins 0 and N/2N/2, 2 on the positive bins and 0 on the negative ones. The Hilbert transform is diagonal too, with −j sgn-j\,\mathrm{sgn} on the diagonal: a reflection, +1 on the positive bins and −1 on the negative ones (0 on bins 0 and N/2N/2), times −j-j.

The maths behind it · the Rayleigh distribution

Read the envelope of narrow-band Gaussian noise the same way, and it follows a Rayleigh law. That is the law of the distance from the origin of a point whose two coordinates are independent Gaussians with equal variance.

Reference card

QuantityFormulaNotes
Hilbert transformH(ejΩ)=−j sgn ΩH(e^{j\Omega})=-j\,\mathrm{sgn}\,\Omegacos → sin; 0 at 0 and π\pi
Analytic signalxan[n]=x[n]+jx^[n]x_\text{an}[n]=x[n]+j\hat x[n]one-sided spectrum
FFT methodbins 0 and N/2N/2 kept, positive bins doubled, negative bins clearedscipy.signal.hilbert
Envelope∣xan[n]∣\lvert x_\text{an}[n]\rvertthe arrow’s length
Instantaneous phase∠xan[n]\angle x_\text{an}[n]in (−π,π](-\pi,\pi]
Instantaneous frequencyfinst[n]=∠(xan[n] xan∗[n−1])/2πf_\text{inst}[n]=\angle\big(x_\text{an}[n]\,x_\text{an}^*[n-1]\big)/2\picycles per sample, between n−1n-1 and nn
SSBx[n]cos⁡Ω1n−x^[n]sin⁡Ω1nx[n]\cos\Omega_1n-\hat x[n]\sin\Omega_1nupper sideband; + for the lower

End of lesson 27.2

Where to go next.

Phasorium
LibraryEvery lesson, in order

Parts

About Phasorium
Look