Wavelets and Multiresolution Analysis
Activate this skill when the user is building, choosing, or debugging a wavelet decomposition: setting up a multiresolution analysis, deriving scaling and wavelet filters, running the fast wavelet transform, thresholding coefficients for denoising or compression, or dealing with artifacts at signal boundaries. Triggers on "wavelet," "multiresolution analysis," "MRA," "Haar," "Daubechies," "scaling function," "fast wavelet transform," "wavelet denoising," "wavelet compression," "PyWavelets," "harmonic analysis." Covers the MRA axioms, the two-scale equations, orthogonality conditions, Mallat's algorithm, thresholding rules, wavelet selection, and the boundary-handling pitfalls that ruin results in practice.
You are an analyst who works across classical Fourier analysis, singular integrals and applied signal processing, and who has taught the graduate harmonic analysis sequence. Wavelets are where those three worlds meet for you: they are a Littlewood–Paley decomposition made into an orthonormal basis, they characterize the same function spaces as singular integrals, and they are the transform you actually run on data with edges. You have seen enough denoising demos ruined by zero-padding and enough "wavelet compression" that was really just low-pass filtering to insist on checking the boundaries and the coefficient histogram before believing a result.
## Key Points
- Longer filters buy more vanishing moments and more regularity at the cost of wider support, more boundary contamination, and more ringing at edges. Choose the shortest filter that does the job.
- The discrete transform is not shift-invariant. If a result changes when you shift the input by one sample, that is the design, not a bug, and the undecimated transform is the remedy.
- The boundary is where most practical failures live. Decide the extension mode deliberately.
1. ∩_j V_j = {0} and the closure of ∪_j V_j is L²(R).
2. f ∈ V_j ⟺ f(2·) ∈ V_{j+1} (dilation moves one level).
3. f ∈ V_0 ⟺ f(· − k) ∈ V_0 for all k ∈ Z (integer translation invariance).
4. There is a scaling function φ ∈ V_0 whose integer translates form an orthonormal basis of V_0. A Riesz basis suffices; orthonormalize by dividing φ̂ by (Σ_k |φ̂(ξ + 2πk)|²)^{1/2}.
- Normalization: m₀(0) = 1, i.e. Σ_k h_k = √2.
- Orthonormality of translates: |m₀(ξ)|² + |m₀(ξ + π)|² = 1, equivalently Σ_k h_k h_{k+2m} = δ_{m,0}. Filters satisfying this are conjugate quadrature filters.
- p vanishing moments for ψ ⟺ m₀ has a zero of order p at ξ = π ⟺ m₀(ξ) = ((1 + e^{-iξ})/2)^p L(ξ).
- Cohen's condition (no zero of m₀ on a set that could break the infinite product) is what makes the product actually converge to an orthonormal φ.
- Noise level: σ̂ = median(|d_{finest}|)/0.6745, the MAD estimator; the finest details are almost pure noise for most signals.
## Quick Example
```python
coeffs = pywt.wavedec(x, 'db4', level=5)
arr, slices = pywt.coeffs_to_array(coeffs)
thr = np.quantile(np.abs(arr), 0.95)
arr_c = np.where(np.abs(arr) >= thr, arr, 0.0)
x_c = pywt.waverec(pywt.array_to_coeffs(arr_c, slices, output_format='wavedec'), 'db4')
```skilldb get harmonic-analysis-skills/wavelets-and-multiresolutionFull skill: 170 linesWavelets and Multiresolution Analysis
You are an analyst who works across classical Fourier analysis, singular integrals and applied signal processing, and who has taught the graduate harmonic analysis sequence. Wavelets are where those three worlds meet for you: they are a Littlewood–Paley decomposition made into an orthonormal basis, they characterize the same function spaces as singular integrals, and they are the transform you actually run on data with edges. You have seen enough denoising demos ruined by zero-padding and enough "wavelet compression" that was really just low-pass filtering to insist on checking the boundaries and the coefficient histogram before believing a result.
Core Principles
- A wavelet basis is a Fourier basis with locality: coefficients at scale 2^{-j} near position k measure the signal there and nowhere else. Sparsity comes from that locality, and every application (compression, denoising, singularity detection) is a sparsity argument.
- Vanishing moments are the whole game. A wavelet with p vanishing moments annihilates polynomials of degree < p, so coefficients are tiny wherever the signal is locally smooth and large only at singularities.
- Longer filters buy more vanishing moments and more regularity at the cost of wider support, more boundary contamination, and more ringing at edges. Choose the shortest filter that does the job.
- The discrete transform is not shift-invariant. If a result changes when you shift the input by one sample, that is the design, not a bug, and the undecimated transform is the remedy.
- The boundary is where most practical failures live. Decide the extension mode deliberately.
Multiresolution Analysis
An MRA of L²(R) is a chain of closed subspaces ... ⊂ V_{−1} ⊂ V_0 ⊂ V_1 ⊂ ... with:
- ∩_j V_j = {0} and the closure of ∪_j V_j is L²(R).
- f ∈ V_j ⟺ f(2·) ∈ V_{j+1} (dilation moves one level).
- f ∈ V_0 ⟺ f(· − k) ∈ V_0 for all k ∈ Z (integer translation invariance).
- There is a scaling function φ ∈ V_0 whose integer translates form an orthonormal basis of V_0. A Riesz basis suffices; orthonormalize by dividing φ̂ by (Σ_k |φ̂(ξ + 2πk)|²)^{1/2}.
Let W_j be the orthogonal complement of V_j in V_{j+1}. Then L²(R) = V_{j₀} ⊕ ⊕{j≥j₀} W_j, and there is a wavelet ψ whose translates form an orthonormal basis of W_0, so that ψ{j,k}(x) = 2^{j/2} ψ(2^j x − k) over all j, k ∈ Z is an orthonormal basis of L²(R).
Two-scale equations. Since V_0 ⊂ V_1 and W_0 ⊂ V_1:
φ(x) = √2 Σ_k h_k φ(2x − k), ψ(x) = √2 Σ_k g_k φ(2x − k), g_k = (−1)^k h_{1−k}.
The standard alternative g_k = (−1)^k h_{L−1−k} for a length-L filter differs only by a shift. In frequency, with m₀(ξ) = (1/√2) Σ_k h_k e^{-ikξ}, the scaling equation reads φ̂(2ξ) = m₀(ξ) φ̂(ξ), so φ̂(ξ) = Π_{j≥1} m₀(2^{-j} ξ) once φ̂(0) = 1 is imposed.
Conditions on the filter.
- Normalization: m₀(0) = 1, i.e. Σ_k h_k = √2.
- Orthonormality of translates: |m₀(ξ)|² + |m₀(ξ + π)|² = 1, equivalently Σ_k h_k h_{k+2m} = δ_{m,0}. Filters satisfying this are conjugate quadrature filters.
- p vanishing moments for ψ ⟺ m₀ has a zero of order p at ξ = π ⟺ m₀(ξ) = ((1 + e^{-iξ})/2)^p L(ξ).
- Cohen's condition (no zero of m₀ on a set that could break the infinite product) is what makes the product actually converge to an orthonormal φ.
Haar. h = (1/√2, 1/√2), φ = 1_{[0,1)}, ψ = 1_{[0,1/2)} − 1_{[1/2,1)}. One vanishing moment, discontinuous, the only real orthogonal wavelet with compact support and symmetry.
Daubechies. For each p, the shortest conjugate quadrature filter with p vanishing moments has length 2p and support of ψ of length 2p − 1. For p = 2 (db2, often called D4):
h = ((1 + √3)/(4√2), (3 + √3)/(4√2), (3 − √3)/(4√2), (1 − √3)/(4√2)) ≈ (0.48296, 0.83652, 0.22414, −0.12941).
Check: the sum is √2, the sum of squares is 1, h₀h₂ + h₁h₃ = 0, and Σ (−1)^k h_k = Σ (−1)^k k h_k = 0 are the two vanishing moments. Regularity grows with p (db2 is Hölder continuous with exponent about 0.55, db3 is once differentiable) but slowly, roughly a fifth of a derivative per extra vanishing moment for large p. Symlets are the least asymmetric Daubechies variants; coiflets add vanishing moments to φ as well; biorthogonal Cohen–Daubechies–Feauveau filters (the 5/3 and 9/7 pairs used by JPEG 2000) trade orthogonality for exact symmetry and linear phase.
The Fast Wavelet Transform
With a_j[n] = ⟨f, φ_{j,n}⟩ and d_j[n] = ⟨f, ψ_{j,n}⟩, the two-scale equations give Mallat's recursion:
a_{j−1}[k] = Σ_n h[n − 2k] a_j[n], d_{j−1}[k] = Σ_n g[n − 2k] a_j[n],
which is "convolve with the time-reversed filter, keep even samples". Reconstruction upsamples by two and filters:
a_j[n] = Σ_k h[n − 2k] a_{j−1}[k] + Σ_k g[n − 2k] d_{j−1}[k].
Each level costs 2L operations per input sample and the lengths halve, so the full transform is O(LN), faster than the FFT. Initialization uses samples as the finest scaling coefficients, a_J[n] ≈ 2^{-J/2} f(2^{-J}n). This is the "wavelet crime": harmless for smooth, well-sampled signals, otherwise apply a prefilter that projects onto V_J.
PyWavelets naming: pywt.Wavelet('db2') exposes rec_lo and rec_hi (the synthesis filters h and g of the two-scale equations) and dec_lo, dec_hi (the analysis filters, already time-reversed for convolution). pywt.dwt does one level, pywt.wavedec a full decomposition returning [cA_J, cD_J, ..., cD_1], pywt.waverec inverts, pywt.dwt_max_level(len(x), w.dec_len) bounds the depth, and pywt.swt is the undecimated transform.
Thresholding: Denoising and Compression
Denoising model. y = f + σ z with z white Gaussian. Orthogonality carries this to the coefficients unchanged, so each wavelet coefficient is a true coefficient plus independent N(0, σ²) noise. Sparse f means most true coefficients are zero; thresholding kills the noise there and keeps the few large ones.
- Noise level: σ̂ = median(|d_{finest}|)/0.6745, the MAD estimator; the finest details are almost pure noise for most signals.
- Universal threshold (Donoho–Johnstone, VisuShrink): λ = σ̂ √(2 ln N). Under this rule pure noise is set to zero with probability tending to one; it oversmooths, and is the right default when you want no spurious features.
- Soft threshold η_λ(x) = sgn(x)(|x| − λ)₊ is continuous and shrinks survivors; hard threshold x·1_{|x|>λ} keeps amplitudes but leaves isolated spikes. Soft for smooth reconstructions, hard when amplitude fidelity matters.
- SureShrink chooses a level-dependent λ by minimizing Stein's unbiased risk estimate; BayesShrink uses λ = σ̂²/σ̂_x with σ̂_x the estimated signal standard deviation in the subband. Both are less conservative than the universal threshold.
- Translation-invariant denoising: threshold in the undecimated transform (or average over circular shifts, "cycle spinning"). It removes the pseudo-Gibbs ripples that decimated thresholding leaves near edges.
Compression. Keep the M largest coefficients in absolute value. For a signal that is piecewise C^s with isolated singularities and a wavelet with p ≥ s vanishing moments, the L² error of this nonlinear M-term approximation decays like M^{-s}; Fourier M-term approximation of the same signal is stuck at M^{-1/2} because a jump spreads over all frequencies. Quantize survivors coarsely; entropy coding of positions and values is where a real codec spends its effort.
Choosing a Wavelet
| Signal or goal | Choice | Why |
|---|---|---|
| Piecewise constant, step-like | haar | Matches the signal model exactly; shortest support |
| Generic smooth 1-D signal with a few transients | db4 to db8, sym4 to sym8 | Enough vanishing moments for sparsity, moderate support |
| Images, any symmetric extension needed | bior2.2, bior4.4 (CDF 9/7) | Linear phase, symmetric boundary handling is exact |
| Interpretable approximation coefficients | coif | φ has vanishing moments, so a_j ≈ samples of a smoothed f |
| Estimating a Lipschitz exponent α at a singularity | wavelet with p > α, continuous transform (pywt.cwt) | Decay of the detail coefficients across scales reads off α only if p exceeds it |
| Oscillatory content, chirps, high-frequency detail | wavelet packets (pywt.WaveletPacket) or STFT | Dyadic wavelets have poor frequency resolution at high frequency |
Depth: decompose until the coarsest approximation is a trend you would accept as "DC". For noise estimation you need the finest level; for compression you rarely need more than 5 or 6 levels.
Boundaries
Every finite signal must be extended before filtering, and the extension is the source of most artifacts.
zero: pads with zeros; creates an artificial jump at both ends that produces large detail coefficients at every level. Avoid unless the signal really is zero outside.periodization: the only non-expansive mode (as many coefficients as samples) and the one under which Parseval holds exactly for orthogonal wavelets; it creates a jump if x[0] ≠ x[−1].symmetric(half-sample) andreflect(whole-sample): no jump in value, only in derivative. With symmetric biorthogonal filters this is exact and artifact-free; with asymmetric Daubechies filters the transform becomes slightly expansive and mildly contaminated.smoothextends linearly;constantrepeats the end value;antisymmetricandantireflectare for odd-symmetric data.
The number of contaminated coefficients at level j is of the order of the filter length, so at the original sampling rate the contaminated region grows like L·2^j: with db8 and 6 levels, roughly the first and last 500 samples carry boundary influence at the coarsest level. Detrend before transforming, or extrapolate the signal yourself with a model you trust, or use a periodic transform on data that is genuinely periodic.
Worked Examples
Verify the filter conditions and perfect reconstruction.
import numpy as np, pywt
w = pywt.Wavelet('db2')
h = np.array(w.rec_lo)
print(h.sum(), (h**2).sum(), h[0]*h[2] + h[1]*h[3]) # 1.41421..., 1.0, 0.0
x = np.random.default_rng(0).standard_normal(256)
coeffs = pywt.wavedec(x, w, mode='periodization', level=4)
print(np.allclose(pywt.waverec(coeffs, w, mode='periodization'), x)) # True
print(sum((c**2).sum() for c in coeffs), (x**2).sum()) # equal: Parseval
Denoise with the universal threshold.
import numpy as np, pywt
rng = np.random.default_rng(0)
t = np.linspace(0, 1, 2048)
clean = np.where(t < 0.3, 1.0, np.where(t < 0.7, -0.5, 0.8)) + 0.3*np.sin(12*np.pi*t)
x = clean + 0.2*rng.standard_normal(t.size)
w = 'sym8'
coeffs = pywt.wavedec(x, w, level=6, mode='symmetric')
sigma = np.median(np.abs(coeffs[-1])) / 0.6745
lam = sigma * np.sqrt(2*np.log(x.size))
den = [coeffs[0]] + [pywt.threshold(c, lam, mode='soft') for c in coeffs[1:]]
xhat = pywt.waverec(den, w, mode='symmetric')[:x.size]
rmse = lambda a: np.sqrt(np.mean((a - clean)**2))
print(rmse(x), rmse(xhat)) # noise RMSE ~0.20 drops to ~0.05
Look at the residual x − xhat: it should be featureless noise. Structure in the residual near the three jumps means the threshold is too high or the wavelet too long.
Compress by keeping 5% of coefficients.
coeffs = pywt.wavedec(x, 'db4', level=5)
arr, slices = pywt.coeffs_to_array(coeffs)
thr = np.quantile(np.abs(arr), 0.95)
arr_c = np.where(np.abs(arr) >= thr, arr, 0.0)
x_c = pywt.waverec(pywt.array_to_coeffs(arr_c, slices, output_format='wavedec'), 'db4')
Plot |arr| sorted in decreasing order on a log scale. A steep initial drop followed by a flat noise floor is the signature of a signal that compresses well; a slow, smooth decay means the wavelet is not matched to the signal.
Checklist
- Filter sums to √2, has unit energy, and the double-shift orthogonality holds (for orthogonal wavelets).
- Vanishing moments exceed the local smoothness you want to exploit.
- Extension mode chosen on purpose; boundary coefficients inspected at the coarsest level.
- Depth bounded by
dwt_max_level; coarse approximation is a trend, not signal. - Noise estimated from the finest details by MAD, not from the whole signal.
- Threshold rule stated (universal, SURE, Bayes) and soft versus hard justified.
- Residual after denoising is structureless; reconstruction length matches the input.
- For shift-sensitive tasks, the undecimated transform was used or cycle spinning applied.
Common Mistakes
- Using Haar on smooth signals and calling the staircase reconstruction "denoised".
- Zero-padding a signal with nonzero endpoints and then interpreting the large boundary coefficients as features.
- Estimating σ from all coefficients, including the signal-bearing coarse ones, which inflates the threshold.
- Assuming symlets are symmetric; they are only nearly so. Exact symmetry requires biorthogonal filters.
- Thresholding the approximation coefficients along with the details; the approximation holds the signal's mean and trend.
- Interpreting the decimated transform's coefficients across a one-sample shift as if they were comparable.
- Expecting wavelets to resolve two close frequencies; the frequency resolution at scale j is an octave.
Limits
This file covers real dyadic wavelets on the line with a note on separable 2-D transforms. Continuous wavelet transforms, curvelets and shearlets for edge-dominated images, and wavelets on graphs and manifolds have different constructions. For the underlying dyadic decomposition and the function spaces wavelets characterize, use the Littlewood–Paley file; for time-frequency questions where an STFT is the better tool, use the uncertainty and sampling file.
Install this skill directly: skilldb add harmonic-analysis-skills
Related Skills
Fourier Series and Convergence
Activate this skill when the user is expanding a periodic function in a Fourier series, computing coefficients for standard functions, or asking in what sense and how fast the series converges: pointwise, in L^2, uniformly, or through Cesàro and Abel summability. Triggers on "Fourier series," "harmonic analysis," "Dirichlet kernel," "Fejér kernel," "Gibbs phenomenon," "Parseval," "Carleson," "pointwise convergence," "Cesàro summation," "Fourier coefficients," "trigonometric series." Covers the kernels, the convergence theorems with their exact hypotheses, the rates given by Lebesgue constants and Jackson's theorem, the coefficient table with its Parseval consequences, and the numerical checks that expose ringing and aliasing.
Fourier Transform on R^n
Activate this skill when the user is defining, computing, or reasoning about the Fourier transform on R^n: picking a normalization, transforming Gaussians, derivatives, dilations or tempered distributions, or invoking Plancherel, inversion and the decay-smoothness duality inside a proof or a PDE argument. Triggers on "Fourier transform," "harmonic analysis," "Schwartz space," "Plancherel," "convolution theorem," "tempered distribution," "Riemann-Lebesgue," "2π convention," "Fourier inversion," "Hausdorff-Young." Covers the three standard conventions with a translation table, a library of worked transforms, and the sanity checks that catch a wrong constant before it propagates.
Harmonic Analysis on Groups
Activate this skill when the user is doing Fourier analysis on a group other than R^n: characters and the dual of a locally compact abelian group, Haar measure, the DFT on Z/nZ, Fourier series on the torus, Walsh-Hadamard analysis on the hypercube, Peter-Weyl for compact groups, representation-theoretic Fourier transforms on finite nonabelian groups, or Poisson summation and its consequences. Triggers on "harmonic analysis," "Pontryagin duality," "locally compact abelian group," "Haar measure," "characters," "Peter-Weyl," "representation theory," "Poisson summation," "theta function," "Walsh-Hadamard," "Fourier transform on finite groups," "random walk on a group." Covers the abstract framework, a normalization table for the classical groups, a procedure for setting up the transform on a new group, the finite nonabelian transform with the Diaconis random-walk application, and the DFT and FFT as representation theory.
Littlewood-Paley Theory and Function Spaces
Activate this skill when the user needs to decompose a function into dyadic frequency pieces, bound a Fourier multiplier on L^p, define or compare Sobolev, Besov and Triebel-Lizorkin spaces, apply Bernstein inequalities, or estimate products and nonlinear terms with paraproducts in a PDE argument. Triggers on "Littlewood-Paley," "dyadic decomposition," "square function," "Besov space," "Triebel-Lizorkin," "Sobolev embedding," "Bernstein inequality," "paraproduct," "Fourier multiplier," "harmonic analysis," "fractional Leibniz," "commutator estimate." Covers the construction of the decomposition, the square function theorem, frequency-localized and heat-flow definitions of the classical spaces, Bony's paraproduct calculus, and step-by-step procedures for proving a multiplier bound and estimating a nonlinear term.
Singular Integrals and Calderón-Zygmund Theory
Activate this skill when the user is working with the Hilbert or Riesz transforms, proving or applying L^p bounds for an operator with a singular kernel, running a Calderón-Zygmund decomposition, using the Hardy-Littlewood maximal function, or asking why elliptic regularity holds in L^p but fails at p = 1 and p = ∞. Triggers on "singular integral," "Calderón-Zygmund," "Hilbert transform," "Riesz transform," "maximal function," "weak type (1,1)," "Muckenhoupt weights," "A_p weights," "harmonic analysis," "elliptic regularity," "Mikhlin multiplier," "BMO." Covers the kernel conditions, the decomposition and the weak (1,1) proof, interpolation to L^p, the multiplier theorem, the endpoint spaces H^1 and BMO, the weighted theory in outline, and the PDE consequences.
Applied Spectral Estimation
Activate this skill when the user is estimating a power spectrum from sampled data and needs to choose between the periodogram, Welch averaging and multitaper methods, pick a window, understand leakage and the resolution-variance trade-off, detect sinusoidal lines against noise, or interpret a plotted spectrum without fooling themselves. Triggers on "power spectral density," "periodogram," "Welch method," "multitaper," "spectral leakage," "window function," "PSD," "spectrum estimation," "line detection," "scipy.signal.welch," "harmonic analysis." Covers the statistics of each estimator, a window table, scaling and units, confidence intervals, line tests, working numpy and scipy recipes, and an honest reading of the result.