Skip to content

Upsampling and interpolation

Raise the sample rate by putting zeros between samples, see the images they bring, and remove them with a low-pass of gain L.

Before this22.1 · 5 more
Chapter 22 · Lesson 2 of 4

First, the picture

To raise a sample rate, I start by putting zeros between the samples. Here a tone, cos⁡(0.40πn)\cos(0.40\pi n), gets L−1L-1 zeros after each sample, for LL from 1 to 4. Watch its spectrum: the tone’s line slides down, and new lines appear in the space it left.

Insert zeros: the spectrum squeezes and images appear

x[n] = cos(0.40πn), with L − 1 zeros put after each sample.

L = 1: the tone at 0.40π rad/sample, amplitude 1.

L
1
tone at
0.40π rad/sample
each line
1.000
0.00 / 16.00 s
Describe this picture

Two stacked panels. The first is xu[n]x_u[n] for samples 0 to 47, from −1.2 to 1.2: the original samples are stems with dot heads, and the inserted zeros are open rings on the axis. The second is the spectrum, amplitude from 0 to 1.1 against Ω from 0 to π rad/sample. The tone is a line with a dot at its top, labelled “tone”, and each image a line with an open ring, labelled “image”. The readouts are LL, where the tone is, and the height of each line. The clip steps LL from 1 to 4 as the zeros slide in and the lines move and split. At L=1L=1 the tone is at 0.40π with amplitude 1. At L=2L=2 it is at 0.20π, with an image at 0.80π, each 0.500. At L=3L=3 the lines are at 0.13π, 0.53π and 0.80π, each 0.333. At L=4L=4 the tone is at 0.10π and three images at 0.40π, 0.60π and 0.90π, each 0.250, and the caption ends: “Zeros divide every frequency by L and bring L − 1 images; a filter has to remove them.” After the clip a slider named “Upsample by L” sets LL from 1 to 6. At 5 the caption reads “L = 5: lines at 0.08π, 0.32π, 0.48π, 0.72π, 0.88π, each 0.200.” At 6 there are six lines, at 0.07π, 0.27π, 0.40π, 0.60π, 0.73π and 0.93π, each 0.167.

Insert zeros: the spectrum squeezes and images appear

In Downsampling and decimation (22.1) we lowered the sample rate by keeping every MM-th sample. Now I want to go the other way and raise it. Shifting, reversing and scaling time (2.1) already met the problem. Slowing down by 2 asks for samples halfway between the measured ones, at instants that were never measured.

So let’s leave the gaps empty first and fill them later. To raise the rate by a whole number LL, I put L−1L-1 zeros after each sample. This is upsampling by LL, also called zero insertion or zero-stuffing. I write the result xu[n]x_u[n]:

xu[n]={x[n/L],L divides n,0,otherwise.x_u[n]=\begin{cases}x[n/L], & L\text{ divides }n,\\ 0, & \text{otherwise.}\end{cases}

Nothing is lost. Every original sample is still there, now LL places from the next one.

What do the zeros do to a tone? Take x[n]=cos⁡(0.40πn)x[n]=\cos(0.40\pi n) and L=2L=2. At even nn, xu[n]=x[n/2]=cos⁡(0.40π⋅n/2)=cos⁡(0.20πn)x_u[n]=x[n/2]=\cos(0.40\pi\cdot n/2)=\cos(0.20\pi n), and at odd nn it is 0. The factor 12(1+(−1)n)\tfrac12\big(1+(-1)^n\big) is 1 at even nn and 0 at odd nn, so

xu[n]=cos⁡(0.20πn)⋅12(1+(−1)n)=12cos⁡(0.20πn)+12cos⁡(0.80πn).\begin{aligned} x_u[n]&=\cos(0.20\pi n)\cdot\tfrac12\big(1+(-1)^n\big)\\ &=\tfrac12\cos(0.20\pi n)+\tfrac12\cos(0.80\pi n). \end{aligned}

The second line takes one step. (−1)n(-1)^n is ejπne^{j\pi n}, and by Properties of the DTFT (12.3), multiplying by it slides every line of a spectrum by π\pi. The tone’s lines at ±0.20π\pm0.20\pi move to 1.20π1.20\pi and 0.80π0.80\pi. On the circle of Frequency in discrete time (12.1), 1.20π1.20\pi is −0.80π-0.80\pi, so the product is cos⁡(0.80πn)\cos(0.80\pi n).

So the zeros did two things. The tone moved to half its frequency, 0.20π0.20\pi. And a second tone appeared at π−0.20π=0.80π\pi-0.20\pi=0.80\pi, which was not in xx at all. I call it an image.

The tone and its image each have amplitude 12\tfrac12.

Think of a picket fence with a blank picket painted in after every real one. The old rhythm is still there, at half the pace, and a new, false rhythm sits beside it. The picture at the top of the page does this to the tone for LL from 1 to 4.

Watch two things. Every line’s height falls as 1/L1/L: 1, 0.500, 0.333, 0.250. And the tone slides down to 0.40π/L0.40\pi/L, while new image lines grow in the space the tone left. After the clip, the slider goes on to L=5L=5 and 6.

Squeezed by L

Why does every frequency divide by LL? Write the DTFT of xux_u (The DTFT, 12.2). Only the terms with n=Lmn=Lm are not zero, and there xu[Lm]=x[m]x_u[Lm]=x[m]:

Xu(ejΩ)=∑nxu[n] e−jΩn=∑mx[m] e−jΩLm=X(ejΩL).\begin{aligned} X_u(e^{j\Omega})&=\sum_n x_u[n]\,e^{-j\Omega n}\\ &=\sum_m x[m]\,e^{-j\Omega Lm}\\ &=X(e^{j\Omega L}). \end{aligned}

So the new spectrum is the old one, read at ΩL\Omega L. What sat at Ω\Omega now sits at Ω/L\Omega/L: the spectrum is squeezed by LL. The old spectrum repeats every 2π2\pi (12.1), so the new one repeats every 2π/L2\pi/L. That fits LL copies into one turn, and the extra copies are the images.

Now follow a tone at Ω1\Omega_1. The old spectrum has its line at Ω1\Omega_1 and at every copy, Ω1+2πk\Omega_1+2\pi k. The new one has a line wherever ΩL\Omega L hits one of those, so at

Ω=Ω1+2πkL,k=0,…,L−1.\Omega=\frac{\Omega_1+2\pi k}{L},\qquad k=0,\dots,L-1.

Larger kk only repeat these a whole turn further on. Fold each one into 0 to π\pi, as in 22.1. For Ω1=0.40π\Omega_1=0.40\pi and L=4L=4 that gives 0.10π0.10\pi, 0.60π0.60\pi, 1.10π1.10\pi and 1.60π1.60\pi, which fold to 0.10π0.10\pi, 0.60π0.60\pi, 0.90π0.90\pi and 0.40π0.40\pi.

Why is each line 1/L1/L high? For L=2L=2 the factor 12(1+(−1)n)\tfrac12\big(1+(-1)^n\big) did it. For any LL the same job is done by

1L∑k=0L−1ej2πkn/L.\frac1L\sum_{k=0}^{L-1}e^{j2\pi kn/L}.

When LL divides nn, every arrow is 1 and the factor is 1. Otherwise the LL arrows are spread evenly round the circle and cancel, like the rows of The DFT as a matrix (13.5). So for the tone, xu[n]x_u[n] is cos⁡(Ω1n/L)\cos(\Omega_1n/L) times this factor.

Each arrow ej2πkn/Le^{j2\pi kn/L} slides the squeezed tone by 2πk/L2\pi k/L (12.3) and carries the weight 1/L1/L. That makes LL lines, each a cosine of amplitude 1/L1/L.

The maths behind it · transposed selection matrices

Downsampling was a wide selection matrix: rows of the identity, every MM-th kept. Upsampling is its transpose: a tall matrix that places each sample and pads with zeros. Interpolation, the filter after upsampling, is a matrix whose columns are shifted copies of the interpolation pulse: a basis of in-between functions.

Remove the images, and multiply by L

The zeros moved the tone to the right place, Ω1/L\Omega_1/L, and added images. So the repair is a low-pass that keeps the squeezed spectrum and removes the rest. The old band, 0 to π\pi, now fills 0 to π/L\pi/L, so the cutoff is π/L\pi/L.

The tone also came out LL times too small. So the filter gets a gain of LL as well. A low-pass at π/L\pi/L with gain LL is the interpolation filter.

For L=4L=4 the cutoff is π/4=0.25π\pi/4=0.25\pi, and 22.1 already has that filter. It is the 75-tap low-pass, a Kaiser design (Window-method FIR design, 19.1) with β=5.6533\beta=5.6533 and cutoff 0.25π0.25\pi. It passes 0 to 0.2π0.2\pi within ±0.00111\pm0.00111, stays at least 60.38 dB down from 0.3π0.3\pi, and delays by 37 samples. Here I multiply its taps by 4.

Will it do? The tone sits at 0.10π0.10\pi, in the pass band. The images sit at 0.40π0.40\pi, 0.60π0.60\pi and 0.90π0.90\pi, all past 0.3π0.3\pi, in the stop band.

In fact it serves any xx with nothing above 0.8π0.8\pi. That content squeezes to at most 0.2π0.2\pi, and its nearest image starts at (2π−0.8π)/4=0.3π(2\pi-0.8\pi)/4=0.3\pi.

Think of a flip-book with a blank page after every drawing. The filter draws the in-between pictures.

The second panel gives levels in dB re 1: a line of amplitude AA sits at 20log⁡10A20\log_{10}A. So the four lines of amplitude 0.250 sit at −12.0 dB, and the filter’s gain of 4 is +12.04 dB.

Remove the images, and multiply by L

L = 4: the zero-stuffed tone through the 75-tap low-pass of 22.1, times 4 (cutoff 0.25π).

L = 4: the tone at 0.10π and three images, all at −12.0 dB.

tone amplitude
0.250
largest image
−12.0 dB
0.00 / 13.00 s
Describe this picture

Two stacked panels for L=4L=4: the zero-stuffed tone through the 75-tap low-pass of 22.1, times 4, with cutoff 0.25π. The first is the signal for samples 0 to 47, from −1.2 to 1.2. The zero-stuffed input is stems with dot heads and open rings for its zeros. The output is stems with square heads, moved back by its delay of 37 samples so that it lines up, and the sine cos⁡(0.10πn)\cos(0.10\pi n) is a thin dashed curve labelled “sine”. The second is the spectrum, level in dB re 1 from −90 to 15 against Ω from 0 to π rad/sample. The filter’s gain is a dashed curve labelled “low-pass × 4”, the tone and images are lines, and the images have open rings at their tops. The readouts are the tone’s amplitude and the largest image. The clip opens on the tone at 0.10π and three images, all at −12.0 dB, reading 0.250 and −12.0 dB. Then the filter’s gain draws: about 4 (12.03 to 12.05 dB) up to 0.2π, and at least 60 dB lower from 0.3π. Last the lines move to their filtered levels and the output stems grow into the gaps. The readouts end at 1.000 and −72.4 dB, and the samples lie on the sine.

Watch the images sink and the gaps fill. The images fell from −12.0 dB to −72.4, −74.3 and −79.6 dB. The tone, which was 0.250, came out at 1.000. And in time, the output samples lie on the sine to within 0.0006.

Why the gain is L, and why the gaps fill with the right values

The gain is LL because zero insertion divided the tone’s amplitude by LL. Only one sample in LL carries the signal, and the filter has to bring the level back.

Why does the output land on the sine? The filter’s taps are a windowed sinc, centred on tap 37. Taps 4, 8, 12, … away from the centre are 0, because the ideal low-pass at 0.25π0.25\pi has sin⁡(0.25πm)=0\sin(0.25\pi m)=0 when mm is a multiple of 4. The centre tap of 4h4h is 0.99969.

Take an output at the place of an original sample. The input’s other non-zero samples are 4, 8, 12, … places away, so they meet only zero taps. The output there is 0.99969 times the original sample, so the original samples are kept almost exactly.

In between, every non-zero tap adds in a scaled pulse from each nearby original sample. The ideal taps times 4 are sin⁡(πm/4)/(πm/4)=sinc(m/4)\sin(\pi m/4)/(\pi m/4)=\mathrm{sinc}(m/4): a sinc pulse that is 0 at every old sample instant. That is the sum of Reconstruction (10.3), a sinc pulse at every sample, added, now done in discrete time and cut to 75 taps by the window.

The same 75 taps decimated by 4 in 22.1. Here, times 4, they interpolate by 4. In SciPy, upfirdn(4*h, x, 4) inserts the zeros and filters in one call. resample_poly(x, 4, 1) does the same with a Kaiser filter of its own, and it removes the delay for you.

Notice that three inputs in every four are zeros. For each output, only 18 or 19 of the 75 taps meet a non-zero input, and the rest multiply zeros. Polyphase structures (22.4) skips those multiplications.

Worked example

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

1. The images of 0.40π0.40\pi. The lines sit at (0.40π+2πk)/L(0.40\pi+2\pi k)/L, folded into 0 to π\pi. For L=3L=3: k=0k=0 gives 0.40π/3=0.1333π0.40\pi/3=0.1333\pi, k=1k=1 gives 2.40π/3=0.8000π2.40\pi/3=0.8000\pi, and k=2k=2 gives 4.40π/3=1.4667π4.40\pi/3=1.4667\pi, which folds to 2π−1.4667π=0.5333π2\pi-1.4667\pi=0.5333\pi.

The same rule gives these lines, each of amplitude 1/L1/L:

FactorLines (rad/sample)Each line
L=2L=20.20π0.20\pi, 0.80π0.80\pi0.500
L=3L=30.1333π0.1333\pi, 0.5333π0.5333\pi, 0.8000π0.8000\pi0.333
L=4L=40.10π0.10\pi, 0.40π0.40\pi, 0.60π0.60\pi, 0.90π0.90\pi0.250

2. After the filter. The tone’s amplitude becomes 0.25⋅4 ∣H(ej0.10π)∣=1.00000.25\cdot4\,\lvert H(e^{j0.10\pi})\rvert=1.0000. Each image becomes 0.25⋅4 ∣H∣=∣H∣0.25\cdot4\,\lvert H\rvert=\lvert H\rvert at its frequency: −72.4497 dB at 0.40π0.40\pi, −74.3090 dB at 0.60π0.60\pi and −79.6460 dB at 0.90π0.90\pi.

3. The taps against the sinc. Next to the centre, 4h4h is 0.89836, 0.63167 and 0.29499. The ideal sinc(m/4)\mathrm{sinc}(m/4) for m=1,2,3m=1,2,3 is 0.90032, 0.63662 and 0.30011. The window and SciPy’s scaling pull each tap down slightly.

4. One in-between value. Take an output one place after an original sample where the sine is at its peak. The sine there is cos⁡(0.10π)=0.95106\cos(0.10\pi)=0.95106. The filter gives 0.95096, which is 0.0001 low. The original sample beside it comes out at 0.99969 in place of 1.

Where you’ll meet this

Digital-to-analog converters upsample by 4 to 256 before the analog filter. The images then sit far above the audio band, so a gentle analog filter removes them. That is the easier filter of Anti-aliasing and practical converters (10.4), on the output side, and sigma-delta converters (Oversampling and noise shaping, 11.3) take it furthest.

Audio effects that would otherwise alias, such as distortion, run at a raised rate (Audio effects, 29.2). Zooming an image is interpolation along its rows and then its columns.

A ratio that is not a whole number is Resampling by any factor (22.3). In Filter banks (23.1), each band is upsampled and filtered like this, and the bands are added to rebuild the signal.

The maths behind it · kernel interpolation

Filling the missing observations of a regular time series with a smooth kernel is kernel interpolation. The sinc is the band-limited choice of kernel. A window trades accuracy for a short kernel, as in 19.1.

Reference card

QuantityFormulaNotes
Upsamplingxu[n]=x[n/L]x_u[n]=x[n/L] if LL divides nn, else 0L−1L-1 zeros inserted
SpectrumXu(ejΩ)=X(ejΩL)X_u(e^{j\Omega})=X(e^{j\Omega L})squeezed by LL
Lines of a tone at Ω1\Omega_1(Ω1+2πk)/L(\Omega_1+2\pi k)/L, k=0,…,L−1k=0,\dots,L-1, foldedk=0k=0 the tone, the rest images; amplitude 1/L1/L each
Interpolation filterlow-pass at π/L\pi/L, gain LLkeeps the tone, removes the images
Its tapswindowed sinc(m/L)\mathrm{sinc}(m/L)0 at every multiple of LL from the centre
Same filterdecimates by MM, or, times LL, interpolates by L=ML=M22.1 and 22.2

End of lesson 22.2

Where to go next.

Phasorium
LibraryEvery lesson, in order

Parts

About Phasorium
Look