DSP·GUIDEOUT LOUD
Book episodes

Episode 13 · Digital Filters · Book chapters 17, 18 · 31m27s

Custom Filters and FFT Convolution

Arbitrary responses, why deconvolution disappoints, the Wiener filter, and overlap-add for very long kernels.

The original recording, including numerical examples and figure cues. Switching versions starts at the beginning.

0:0031:27

Choose a playback speed that feels comfortable. Open in Google Drive to download or play on a phone.

Save for offline listening:Detailed MP3Driving MP3
Figures

Designing an arbitrary response

Write down the gain you want at each frequency, set the phase to zero, inverse transform, swap the halves to centre the kernel, truncate and window, normalise. That is the whole method.

One caution: sharp corners in the response you request produce long kernels and heavy ringing. Smooth the request over several bins and you get a much shorter, better-behaved filter. Never specify a filter sharper than you actually need.

Why deconvolution disappoints

In the frequency domain, undoing a blur looks trivial — convolution is multiplication, so divide. With no noise that works perfectly. With noise it fails, often catastrophically.

Wherever the distortion attenuated heavily, almost nothing of the signal survived; what remains there is mostly noise. Dividing by a small number multiplies that noise enormously. With a signal-to-noise ratio of 1000:1, a frequency attenuated a hundredfold comes back restored but noisy; one attenuated ten-thousandfold comes back as 90% amplified garbage.

The honest rule: you can invert the distortion only where the attenuation is smaller than your signal-to-noise ratio. Beyond that, stop. The principled way to decide is the Wiener filter, which sets each frequency’s gain to signal power over signal plus noise power — pass where signal dominates, reject where noise does, slide smoothly between. That reframes what a filter is: an expression of belief about which parts of a measurement carry information.

Making long kernels practical

Overlap-add: why the tails must be carried forward

Figure
block 1block 2block 3output — overlapping tails summed
Each block of input, convolved with an M-point kernel, produces a result that is M−1 samples longer than the block. Those extra samples (amber) belong to the next block’s territory, so they are held back and added into the start of the next block’s output. The sum is bit-for-bit identical to convolving the whole signal at once — it works because convolution distributes over addition. The state you carry is always exactly kernel-length-minus-one samples, no matter how long the signal runs.

Direct convolution wins below roughly 30–60 kernel points. Above that, FFT convolution wins and the margin grows without limit. Notably, its cost is driven by the transform length rather than the kernel length — so once you are using it, extra sharpness is nearly free in computation. Never in latency, though: you cannot produce output until a full block has arrived, and that delay is inherent.

Key points

  1. To design a filter with an arbitrary frequency response: write down the gain you want at each frequency, set the phase to zero, inverse transform, swap the halves to center the kernel, truncate and window, then normalize.
  2. Sharp corners in the response you request produce long kernels and heavy ringing. Smooth the requested response over several bins and you get a much shorter, better behaved filter. Never specify a filter sharper than you need.
  3. Deconvolution looks trivial in the frequency domain — divide by the distortion's response — and this works perfectly only when there is no noise.
  4. It fails because wherever the distortion attenuated heavily, almost nothing of the signal survived, so what remains is mostly noise. Dividing by a small number amplifies that noise enormously, often producing a result worse than the input.
  5. The real limit is that where the distortion destroyed the information, no processing recovers it. You can only undo a distortion in the frequency regions where enough signal survived above the noise floor.
  6. The Wiener filter sets the gain at each frequency to the signal power divided by the signal power plus the noise power. It passes frequencies where signal dominates, rejects those where noise dominates, and slides smoothly in between.
  7. That reframes what a filter is: an expression of belief about which parts of a measurement carry information. A low pass filter is just the special case of believing signal is low and noise is high.
  8. Wiener deconvolution combines the two — divide where the signal to noise ratio is good, roll smoothly to zero where it is poor — which answers the question of where to stop dividing in a principled way.
  9. The Wiener filter minimizes average squared error and is for recovering a waveform. The matched filter maximizes peak signal to noise ratio and is for detecting a known signal and its arrival time. Recovering and detecting are different questions with different optimal answers.
  10. Transforming an entire long signal at once needs the whole signal in memory and produces no output until it finishes, which is impossible for a stream. So the signal is processed in segments.
  11. Convolving a segment of length L with an M point kernel produces L plus M minus one samples, so each segment's output overlaps the next by M minus one samples.
  12. Overlap-add keeps the M minus one sample tail from each segment and adds it into the start of the next segment's output. The result is bit for bit identical to convolving the whole signal at once, and it works because convolution distributes over addition.
  13. Transform the kernel once and reuse it across all segments; only the incoming segments need transforming.
  14. Direct convolution wins below roughly thirty to sixty kernel points. Above that, FFT convolution wins and the margin grows without limit.
  15. Quantitatively: with a signal to noise ratio of a thousand to one, a frequency attenuated a hundredfold comes back restored but with a local ratio of only ten to one, and a frequency attenuated ten thousandfold comes back as ninety percent amplified noise. You can invert the distortion only where the attenuation is smaller than your signal to noise ratio.
  16. Thresholding the correction works but introduces a sharp edge in the frequency domain, which means ringing in the time domain. You trade noise amplification for ringing artifacts.
  17. With a four point kernel and ten sample segments, each block produces thirteen outputs; you emit ten and carry three forward to add into the next block. The state you hold is always kernel length minus one, regardless of signal length.
  18. Block processing latency is at least one block. At forty eight kilohertz a two thousand and forty eight point block is about forty three milliseconds — fine for playback, unusable for a performer monitoring themselves. Partitioned convolution fixes this by processing the start of the kernel directly and the bulk by FFT.
  19. With FFT convolution the cost is driven by the transform length rather than the kernel length, so a two thousand point kernel costs about the same as a two hundred point one. Extra sharpness becomes nearly free in computation — but never in latency, which is set by the segment length and never goes away.