What a filter or a room does to a sound.
On this page
A filter, a microphone and a room change a sound in the same way: each output sample is a weighted sum of current and past input samples. For a linear, time-invariant (LTI) system, its reply to one click, the impulse response h, tells what it does to any input.
A system takes a signal in and gives one out: an equalizer (EQ) in a music app, the microphone in a phone, the room a voice travels through. Write the input as x[n] and the output as y[n], where n counts samples, and write H{x} for the output the system gives for input x. The definitions follow chapter 2 of Anushiravani (2016), which models a recording’s EQ and room this way. The same model later describes a room’s echoes and an adaptive filter, one that keeps learning while it runs.
A second microphone, one sample farther from the talker, hears each sample one step late at half the amplitude. Its impulse response is h = [0, 0.5]. Figure 2 sends three inputs through it (illustrative numbers).
So speech and noise that reach one microphone come out as two parts that add, the starting point of spectral subtraction.
Now the first input arrives one sample later (Figure 3, illustrative numbers).
Two familiar systems break the rules. A microphone preamplifier (preamp) driven past its range clips, so twice the input is no longer twice the output: not linear. A phone moved during a call changes the path to its microphone, so the reply depends on when a sound arrives: not time-invariant. An adaptive filter, which keeps re-learning, handles that case.
A unit impulse δ[n] is one click: 1 at n = 0 and 0 everywhere else. A system’s output for it is its impulse response h[n]. A hand clap is close to a click, so a clap recorded in a room is close to the room’s impulse response. This page uses a stand-in room, h = [1, 0.5, 0.25]: the direct sound, then two echoes at half and a quarter height, one sample apart, 62.5 μs for audio sampled at 16 kHz (illustrative numbers; real reflections are milliseconds apart). Any signal is a row of clicks, each scaled by one sample value (Figure 4).
Each click in x comes out as a copy of h, scaled by the click’s height (linear) and starting at the click’s time (time-invariant). The output is the copies added, column by column.
Figure 5. 1y[2] adds one bar per copy, h read backwards (illustrative).
A convolution layer in a convolutional neural network (CNN) computes the same sums without the flip, so strictly it is a cross-correlation, the same sliding sum with h read forwards. A learned kernel, the layer’s own h, absorbs the flip; a fixed filter or a measured room does not.
Speech front ends, the first steps that turn audio into features for a model, often apply pre-emphasis, h2 = [1, −0.97], a filter that lifts high frequencies (the 0.97 default on the audio features page). Put it after a single echo, h1 = [1, 0.5], and send x = [1, 2, 3] through both (Figure 6, illustrative numbers).
An LTI system changes each sine wave only in size and in timing, the starting point of finite and infinite impulse response (FIR and IIR) filters. So in the frequency domain, convolution becomes one multiply per frequency bin, one frequency slot of the spectrum: the spectrum of y is the spectrum of x times the spectrum of h, as the Fourier page shows. A copy of a voice at half height 100 ms later, an h with 1 at n = 0 and 0.5 at n = 1,600 at 16 kHz, multiplies the spectrum by a comb, evenly spaced peaks and dips, 10 Hz apart (illustrative numbers).
The direct sum costs N × M multiplies. One second of 48 kHz audio through a one-second room is 48,000 × 48,000, about 2.3 billion. The route through the fast Fourier transform (FFT), the quick way to compute a spectrum, uses the rule of section 7, that convolution in time becomes multiplication of spectra. It pads both signals with zeros to at least N + M − 1 = 95,999 samples, so no copy wraps around, rounded up to the power of two L = 217 = 131,072 that FFTs run fastest on. It then runs three FFTs, one for x, one for h and one inverse to get y back, each about L log2 L operations, about 6.7 million in all by this rough count (Figure 7).
numpy.convolve computes the direct sum. scipy.signal.fftconvolve takes the FFT route, which its documentation calls much faster for arrays longer than about 500 samples. A short filter runs as a direct sum on every sample as audio streams in; a room response thousands of taps long goes through FFTs a block at a time.
The stand-in room from section 4, with x and h three samples each, through both functions from section 8.
import numpy as np
import scipy.signal as sps
x = np.array([1.0, 2.0, 3.0])
h = np.array([1.0, 0.5, 0.25])
y = np.convolve(x, h)
y_fft = sps.fftconvolve(x, h)
assert np.allclose(y, y_fft)
ys = np.convolve(x, h, "same")
"same" keeps the middle N = 3 values, [2.5, 4.25, 2], so the output lines up with the input.| What you see | Cause | Fix |
|---|---|---|
| Output longer than the input | Full convolution keeps every overlap, N + M − 1 samples | Mode "same", or trim the tail |
| The tail wraps onto the start | An FFT multiply without padding is circular, so samples past the end wrap around to the start | Pad both with zeros to at least N + M − 1 (Fourier, section 9) |
| Twice the input is not twice the output | A stage clips, so the chain is not linear | Lower the gain before that stage |
Convolution becomes multiplication in frequency; the spectrum itself is built on Fourier Transform and the FFT.