Skip to content

Downsampling and decimation

Keep every M-th sample and every frequency is multiplied by M and folded; filter first, compute only the kept outputs, and decimate in stages.

Before this21.4 · 8 more
Chapter 22 · Lesson 1 of 4

First, the picture

Here are two tones, at 0.10π and 0.35π rad/sample, and I keep only every MM-th sample, for MM = 1 to 4. Watch the second tone’s line: from M=3M=3 on it passes π and folds back.

Keep every M-th sample: the spectrum stretches and folds

x[n] = cos(0.10πn) + 0.5cos(0.35πn); keep every M-th sample.

M = 1, every sample kept: two tones, at 0.10π and 0.35π rad/sample.

M
1
0.35π tone lands at
0.35π rad/sample
0.00 / 16.00 s
Describe this picture

Three stacked panels for x[n]=cos⁡(0.10πn)+0.5cos⁡(0.35πn)x[n]=\cos(0.10\pi n)+0.5\cos(0.35\pi n). The first shows x[n]x[n] for samples 0 to 47, from −1.6 to 1.6: kept samples are stems with dot heads, dropped ones are open rings. The second is the spectrum of x[n]x[n], amplitude from 0 to 1.1 against Ω from 0 to π rad/sample. Each tone is a vertical line as tall as its amplitude, labelled with its Ω. The third, the spectrum after keeping every MM-th sample, shows where the two lines land. A folded line has an open ring at its top and the label “folded”, and while a line moves a dotted arc shows its path, bouncing off π. The clip steps MM from 1 to 4, and the readouts give MM and where the 0.35π tone lands: 0.35π, 0.70π, then 0.95π and 0.60π, both folded. The caption names both tones’ places at each step and ends: “Keeping every M-th sample multiplies every frequency by M; what passes π folds back.” After the clip a slider named “Keep every M-th” sets MM from 1 to 8, and for MM above 4 the caption reads like “M = 6: the tones land at 0.60π and 0.10π (folded).”

Keep every M-th sample: the spectrum stretches and folds

In Shifting, reversing and scaling time (2.1) we sped a signal up by a whole number MM: y[n]=x[Mn]y[n]=x[Mn]. You keep every MM-th sample and throw the rest away. On this page I call that downsampling by MM, and I write the result as xd[n]=x[Mn]x_d[n]=x[Mn], with d for downsampled.

Why throw samples away? A converter that samples fast, as in Anti-aliasing and practical converters (10.4), hands over far more samples than the band you keep needs. Fewer samples means less to store and less to compute. But dropping samples does something to the frequencies, and that is what this page is about.

Let’s take two tones:

x[n]=cos⁡(0.10πn)+0.5cos⁡(0.35πn).\begin{aligned} x[n]&=\cos(0.10\pi n)\\ &\quad+0.5\cos(0.35\pi n). \end{aligned}

Keep every MM-th sample by putting MnMn in place of nn:

xd[n]=cos⁡(0.10πMn)+0.5cos⁡(0.35πMn).\begin{aligned} x_d[n]&=\cos(0.10\pi Mn)\\ &\quad+0.5\cos(0.35\pi Mn). \end{aligned}

Read each cosine as cos⁡((MΩ) n)\cos\big((M\Omega)\,n\big). Every frequency Ω\Omega is multiplied by MM. The amplitudes do not change: a cosine of amplitude 1 still has amplitude 1 when you skip some of its samples.

What happens when MΩM\Omega passes π\pi? Frequency in discrete time (12.1) showed that Ω\Omega and Ω+2π\Omega+2\pi give the same samples. A cosine is even, so Ω\Omega and −Ω-\Omega give the same samples too. So a frequency past π\pi is the same as one below it: subtract 2π2\pi, then drop the sign.

For M=3M=3 the second tone goes to 1.05π1.05\pi. Subtract 2π2\pi to get −0.95π-0.95\pi, and drop the sign: 0.95π0.95\pi. This is the fold of Sampling & aliasing (10.1), in rad/sample instead of hertz.

Notice that there is no clock and no analog part here. Aliasing happens inside the computer, from nothing more than dropping samples.

Think of a film projector that skips frames. A turning wheel seems to turn faster, and past some speed it seems to turn backwards. That backwards turn is the fold. The picture at the top of the page drops samples from these two tones for MM = 1, 2, 3 and 4, and moves each line to where it lands.

Notice that the 0.35π tone folds as soon as M=3M=3, because 3⋅0.35π=1.05π3\cdot0.35\pi=1.05\pi is past π\pi. The 0.10π tone moves up without folding, and neither line changes height.

After the clip, use the slider to set MM up to 8. Look at M=6M=6: the second tone lands at 0.10π, exactly where the first tone was in x[n]x[n].

Then try M=8M=8. Both tones land on 0.80π, and the two lines stand side by side. They are now the same cosine, since cos⁡(2.8πn)=cos⁡(0.8πn)\cos(2.8\pi n)=\cos(0.8\pi n), so xd[n]=1.5cos⁡(0.8πn)x_d[n]=1.5\cos(0.8\pi n). Two tones became one, and nothing in the samples can split them again.

The spectrum after downsampling

For two tones the rule was: multiply each Ω\Omega by MM, then fold. For a whole spectrum it reads

Xd(ejΩ)=1M∑k=0M−1X(ej(Ω−2πk)/M).X_d(e^{j\Omega})=\frac1M\sum_{k=0}^{M-1}X\big(e^{j(\Omega-2\pi k)/M}\big).

Here XX is the DTFT of xx (The DTFT, 12.2), and XdX_d is the DTFT of xdx_d.

Read the k=0k=0 term first. X(ejΩ/M)X(e^{j\Omega/M}) is XX stretched by MM: whatever XX had at Ω0\Omega_0 now sits at MΩ0M\Omega_0. The other M−1M-1 terms are the same stretched spectrum, shifted by 2πk2\pi k. All MM terms are scaled by 1/M1/M.

Why the shifted copies? A spectrum of samples repeats every 2π2\pi (12.1), but the stretched one repeats only every 2πM2\pi M. The copies fill the gaps, so the result repeats every 2π2\pi again.

Where a copy overlaps the stretched original, the two add. That is aliasing: the overlapping copies of The sampling theorem (10.2).

And the 1/M1/M, when the lines in the instrument kept their heights? A tone’s spectrum is made of arrows (12.2). Stretching the Ω\Omega axis by MM makes each arrow’s area MM times larger, δ(Ω/M)=M δ(Ω)\delta(\Omega/M)=M\,\delta(\Omega). That MM cancels the 1/M1/M, so a sinusoid keeps its amplitude.

When does nothing alias? If XX is zero for π/M<∣Ω∣≤π\pi/M<\lvert\Omega\rvert\le\pi, the stretched spectrum ends at π\pi. The copies, 2π2\pi away, then do not overlap it. So nothing aliases when the signal has no content above π/M\pi/M.

Where the formula comes from

Start from the DTFT of xdx_d:

Xd(ejΩ)=∑nx[Mn] e−jΩn.X_d(e^{j\Omega})=\sum_n x[Mn]\,e^{-j\Omega n}.

Write m=Mnm=Mn. The sum then runs only over the mm that are multiples of MM, and Ωn=Ωm/M\Omega n=\Omega m/M. To let it run over every mm, I need a switch c[m]c[m] that is 1 when mm is a multiple of MM and 0 otherwise. The MM-th roots of unity of Complex numbers for signals (3.3) give one:

c[m]=1M∑k=0M−1ej2πkm/M.c[m]=\frac1M\sum_{k=0}^{M-1}e^{j2\pi km/M}.

When mm is a multiple of MM, every term is 1 and c[m]=M/M=1c[m]=M/M=1. Otherwise the MM arrows are equal steps round the circle, and they add to 0, as in The DFT (13.2). Put c[m]c[m] in and swap the two sums:

Xd(ejΩ)=∑mc[m] x[m] e−jΩm/M=1M∑k=0M−1∑mx[m] e−jΩ−2πkMm.\begin{aligned} X_d(e^{j\Omega})&=\sum_m c[m]\,x[m]\,e^{-j\Omega m/M}\\ &=\frac1M\sum_{k=0}^{M-1}\sum_m x[m]\,e^{-j\frac{\Omega-2\pi k}{M}m}. \end{aligned}

The inner sum is the DTFT of xx at (Ω−2πk)/M(\Omega-2\pi k)/M, and that gives the formula.

The maths behind it · selection matrices

Downsampling is a selection matrix: the rows of the identity, every MM-th one kept. It is wide and short, so it has a null space, and every signal in that null space is lost. Aliasing is two different signals with the same image under this matrix.

Filter first, then keep every M-th

The cure is the one of 10.4: remove what would fold before it can fold. Low-pass first, then keep every MM-th sample. The pair is called decimation, and the low-pass is the decimation filter.

How strong must the filter be, and where? With M=4M=4, let’s keep 0 to 0.2π, which becomes 0 to 0.8π after downsampling.

A component at Ω\Omega lands at 4Ω4\Omega, and past π\pi it folds to 2π−4Ω2\pi-4\Omega. That is inside the kept band when 2π−4Ω≤0.8π2\pi-4\Omega\le0.8\pi, which is when Ω≥0.3π\Omega\ge0.3\pi.

So content from 0.2π up to 0.3π lands at 2π−4⋅0.3π=0.8π2\pi-4\cdot0.3\pi=0.8\pi or above, outside the kept band, and the stop band may start at 0.3π. With a kept band from 0 to Ωpass\Omega_\text{pass}, the same steps give

Ωstop=2πM−Ωpass.\Omega_\text{stop}=\frac{2\pi}{M}-\Omega_\text{pass}.

This is 10.4’s fstop=fs−fpassf_\text{stop}=f_s-f_\text{pass} in the units of the new rate, which is 2π/M2\pi/M on the old Ω\Omega axis. The stop band does not have to start at π/M\pi/M.

For the filter I use a Kaiser design from Window-method FIR design (19.1). For 60 dB, β=0.1102 (60−8.7)=5.6533\beta=0.1102\,(60-8.7)=5.6533. The transition runs from 0.2π to 0.3π, so ΔΩ=0.1π\Delta\Omega=0.1\pi, and Kaiser’s length formula asks for 74 taps.

I take 75, so that the delay is a whole number of samples, 37. The cutoff goes in the middle of the transition, 0.25π: in SciPy, firwin(75, 0.25, window=('kaiser', 5.6533)). I call it the 75-tap low-pass. It stays within ±0.00111 of 1 up to 0.2π, and from 0.3π it is at most −60.38 dB.

It is like blurring a photo slightly before you shrink it, so that fine stripes do not turn into false patterns. The instrument puts the 75-tap low-pass in front of the M=4M=4 case. Its levels are in dB re 1: 20log⁡1020\log_{10} of the amplitude, so amplitude 1 is 0 dB and amplitude 0.5 is −6.0 dB.

Filter first, then keep every M-th

The same two tones, M = 4, with and without the 75-tap low-pass (cutoff 0.25π).

No filter, M = 4: the 0.35π tone lands at 0.60π, only 6 dB below the wanted tone.

filter
off
wanted at 0.40π
0.0 dB
alias at 0.60π
−6.0 dB
Anti-alias filter
0.00 / 13.00 s
Describe this picture

Two stacked panels for the same two tones and M=4M=4, with and without the 75-tap low-pass (cutoff 0.25π). The first, before dropping, shows level in dB re 1, from −90 to 5, against Ω from 0 to π rad/sample. The two tones are vertical lines rising to their levels, the filter’s gain is a dashed curve labelled “low-pass”, floored at −90 dB, and a dotted level marks −60 dB. The second, after keeping every 4th, has the same axes: the wanted line at 0.40π has a dot at its top and the folded line at 0.60π an open ring. The readouts are the filter, the wanted tone at 0.40π and the alias at 0.60π. The clip starts with the filter off: 0.0 dB and −6.0 dB. Then the filter’s gain draws, passing 0 to 0.2π and stopping everything from 0.3π. The 0.35π line drops by 68.14 dB while the 0.10π line stays at 0.00 dB. Last the second panel’s lines move, and the alias ends at −74.2 dB. After the clip two buttons in a group named “Anti-alias filter”, “filter off” and “filter on”, switch between the two states.

Watch the alias at 0.60π: without the filter it is only 6 dB below the wanted tone, and after it, −74.2 dB, below the 60 dB line.

Notice where the filter’s stop band starts: at 0.3π, not at π/4\pi/4. Its wide transition, from 0.2π to 0.3π, does no harm, because whatever lies there lands at 0.8π or above, outside the kept band.

Compute only what you keep

The filter makes one output for every input sample, and then three of every four are thrown away, so why compute them? Each output is a sum of 75 products, and I only need every 4th one. Computing only those costs 75 multiplies per output, not 4×75=3004\times75=300. Polyphase structures (22.4) builds this into the filter’s structure.

In SciPy, upfirdn(h, x, 1, 4) filters with h and keeps every 4th output, and it computes only those. decimate(x, 4, ftype='fir') does the same job with its own filter, an 81-tap Hamming design with cutoff 0.25π, and by default it removes the filter’s delay. Without ftype it uses an order-8 Chebyshev IIR filter (Analog prototype filters, 20.1), which this page leaves out.

One stage or two

A bigger drop costs more. Take 96 kHz down to 12 kHz, so M=8M=8, keeping 0 to 5 kHz with a 60 dB stop band. The stop-edge rule, in hertz, puts each stage’s stop edge at its output rate minus 5 kHz.

In one stage the stop edge is 12−5=712-5=7 kHz. The transition is only 2 kHz wide at a 96 kHz rate, and Kaiser’s formula asks for 176 taps: 176 multiplies per output.

Now do it in two stages, 4 then 2. The first goes from 96 to 24 kHz, with its stop edge at 24−5=1924-5=19 kHz. Its transition, 5 to 19 kHz, is 14 kHz wide, so it needs only 26 taps. Whatever lies between 5 and 12 kHz after it is the second stage’s job.

The second stage goes from 24 to 12 kHz, with its stop edge at 7 kHz. Its transition is 2 kHz wide again, but at a 24 kHz rate that is four times wider in Ω\Omega, so it needs 45 taps. The first stage runs twice for each final output, so the cost is 2×26+45=972\times26+45=97 multiplies per output, 55 % of one stage. This is multistage decimation.

The table adds a third design: three stages that each halve the rate.

DesignRatesStop edgesTapsMultiplies per output
one stage, 896 → 12 kHz7 kHz176176
two stages, 4 then 296 → 24 → 12 kHz19, 7 kHz26, 452 × 26 + 45 = 97
three stages, 2, 2, 296 → 48 → 24 → 12 kHz43, 19, 7 kHz11, 14, 454 × 11 + 2 × 14 + 45 = 117

The early stages are short because their transition bands are wide: Kaiser’s length grows as 1/ΔΩ1/\Delta\Omega (19.1). Three stages cost 117, more than two here: the two halving stages cost 4×11+2×14=724\times11+2\times14=72 per output, against 2×26=522\times26=52 for the first stage of the two-stage design.

The table counts every tap. A halving stage can use a half-band filter (Special FIR filters, 19.4), in which every other tap is zero, and skip those multiplies.

Worked example

Let’s redo the page’s numbers by hand where we can, and with SciPy where we can’t.

1. Where the tones land. Multiply 0.10π and 0.35π by MM, then fold into 0 to π. To fold, subtract whole turns of 2π2\pi until the frequency is within π\pi of 0, and drop the sign.

Keep every M-th0.10π tone lands at0.35π tone lands at
20.20π0.70π
30.30π0.95π, folded
40.40π0.60π, folded
50.50π0.25π, folded
60.60π0.10π, folded
70.70π0.45π, folded
80.80π0.80π, folded

At M=8M=8 both tones land on 0.80π.

2. The decimation filter. For 60 dB, β=0.1102⋅51.3=5.6533\beta=0.1102\cdot51.3=5.6533. The transition is ΔΩ=0.1π=0.3142\Delta\Omega=0.1\pi=0.3142 rad/sample, and the length formula gives Nh−1≥(60−7.95)/(2.285⋅0.3142)=72.51N_h-1\ge(60-7.95)/(2.285\cdot0.3142)=72.51. So Nh−1=73N_h-1=73 and Nh=74N_h=74, which I make 75, with a delay of (75−1)/2=37(75-1)/2=37 samples.

SciPy measures the 75 taps: within ±0.00111 of 1 up to 0.2π, at most −60.38 dB from 0.3π, and −68.14 dB at 0.35π. The alias after filtering is −6.02−68.14=−74.16-6.02-68.14=-74.16 dB re 1. As in 19.1, every 4th tap from the centre is 0: 18 of the 75.

3. Stages. Kaiser’s formula gives 176 taps for one stage, and 26 and 45 for two. So the cost is 176 against 2×26+45=972\times26+45=97 multiplies per output. At 12 000 outputs a second that is 2.11 million against 1.16 million multiplies a second. On the 100 MHz processor of Real-time processing (21.4), that is 2.1 % against 1.2 %.

Kaiser’s formula is an estimate, as 19.1 found. Checked one tap at a time, the stop band first reaches −60 dB at 181 taps for one stage, and at 28 and 45 taps for two. That is 181 against 101, and two stages still cost 56 %.

Where you’ll meet this

A sigma-delta converter (Oversampling and noise shaping, 11.3) runs its 1-bit loop at megahertz rates. Its digital low-pass is a decimator, built in stages, that brings the rate down to 48 kHz or whatever the output needs.

Software-defined radios sample a wide band fast and decimate down to the rate one channel needs. Audio tools decimate when they turn a 96 kHz recording into 48 kHz. Data loggers sample a sensor fast and store fewer, filtered samples.

The reverse, raising the rate, is Upsampling and interpolation (22.2). Changing the rate by any ratio is Resampling by any factor (22.3). Computing only the kept outputs, built into the structure, is Polyphase structures (22.4), and banks of decimating filters are Filter banks (23.1).

The maths behind it · thinning a time series

Thinning a time series, keeping every MM-th observation, aliases its seasonal patterns the same way. Monthly data kept once a year cannot see the seasons at all: every kept value falls in the same month. Averaging before thinning is the low-pass.

Reference card

QuantityFormulaNotes
Downsamplingxd[n]=x[Mn]x_d[n]=x[Mn]every frequency × M, then folded
SpectrumXd(ejΩ)=1M∑k=0M−1X(ej(Ω−2πk)/M)X_d(e^{j\Omega})=\frac1M\sum_{k=0}^{M-1}X\big(e^{j(\Omega-2\pi k)/M}\big)M stretched copies
No aliasingX=0X=0 for ∣Ω∣>π/M\lvert\Omega\rvert > \pi/Motherwise filter first
Decimationlow-pass, then keep every M-thcompute only the kept outputs
Stop edge2π/M−Ωpass2\pi/M-\Omega_\text{pass}protects 00 to Ωpass\Omega_\text{pass}
Multistageshort early stages, wide transitions97 against 176 per output here

End of lesson 22.1

Where to go next.

Phasorium
LibraryEvery lesson, in order

Parts

About Phasorium
Look