Wavelets
Wavelets tile time and frequency together, catching brief transients that Fourier spreads across every bin.
Why Does This Exist?
Fourier tones last forever: a brief spike needs every frequency bin to describe, so frequency filtering cannot separate spikes from noise. Wavelets oscillate briefly (zero mean, compact support) and tile scales: narrow copies catch spikes, wide copies catch swells. Thresholding small coefficients denoises while preserving edges, and the fast wavelet transform runs in . Stationary-tone analysis stays on the Fourier page; filter arithmetic is the convolution theorem.
The one idea you need first
The Haar mother wavelet is then over unit width: differencing adjacent averages. Dilations set the scale, translations set the position. Coefficients measure change at scale near .
Think of It Like This
Reading with zoom levels
A map reader zooms out for highways (wide wavelets: coarse structure), to streets for routing (mid scales), to door numbers for the final step (narrow wavelets: transients). No single zoom serves all three, and a whole-atlas average (Fourier tone) never shows the door.
Wavelet analysis keeps all zooms at once, each coefficient tagged with place and scale. Denoising keeps legible labels at every zoom and erases speckles: the door number survives while paper grain goes.
How It Actually Works
Multiresolution: averages plus details recurse (filter bank: low-pass/high-pass plus downsample). Orthogonal wavelets (Haar, Daubechies-) preserve energy across scales. Denoising: threshold details ( to zero, soft-shrink the rest), invert. is the universal threshold.
Worked example
Signal length : smooth background plus a spike of height at position , noise . Finest-scale Haar details: spike coefficient about ; noise details scatter with . Threshold . Spike : kept. About of noise details fall below: zeroed. Reconstruction keeps the spike within while MSE falls from to about . Fourier low-pass at the same noise cut would shave the spike to (half gone with the "noise").
Code
def haar_step(xs: list[float]) -> tuple[list[float], list[float]]: avg = [(a + b) / 2 for a, b in zip(xs[0::2], xs[1::2])] # coarse det = [(a - b) / 2 for a, b in zip(xs[0::2], xs[1::2])] # detail return avg, det
xs = [0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0] # spike at index 2avg, det = haar_step(xs)print([round(v, 2) for v in avg]) # -> [0.0, 1.5, 0.0, 0.0]print([round(v, 2) for v in det]) # -> [0.0, 1.5, 0.0, 0.0]The spike lands wholly in pair index (average and detail ): localized to two numbers, where Fourier would spread it over all eight bins.
Watch Out For
Denoising transients with Fourier low-pass by habit
Low-pass treats spikes as high-frequency noise by definition: the spike in the example loses half its height. If edges and spikes matter (seismic picks, QRS complexes), reach for wavelets first and verify spike heights before and after.
Thresholding with the wrong sigma estimate
Noise estimated from all coefficients (including signal) overshoots, and the threshold eats real details. Estimate from the finest-scale median ( for Gaussian noise) where signal is sparsest, then threshold coarser scales with it.
The Quick Version
- Wavelets localize in time and scale where Fourier localizes in frequency only.
- Haar differencing plus filter banks give multiresolution analysis.
- The spike scores against threshold : kept, while of noise zeroes.
- Reconstruction MSE falls from to with spike height preserved.
- Fourier low-pass would halve the spike; match the basis to transients.
- Estimate noise from finest-scale medians, never from all coefficients.