Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Matched filter — derivation, covariance flavours, and the link to 3D-Var

Matched filter for hyperspectral methane retrieval

The matched filter (MF) is the maximum-SNR linear detector for a known target signature in additive Gaussian noise. In hyperspectral methane retrieval it is the workhorse baseline — fast, closed-form, and surprisingly competitive with full variational retrievals when the signal is weak and the scene is statistically homogeneous. This note derives the MF from scratch, lays out the four covariance flavours implemented in plumax.matched_filter, and shows the exact sense in which the MF is the one-step limit of the dual / PSAS 3D-Var solver from the companion 00_variational_derivation.md.

The derivation borrows notation from Funk et al. [1], Theiler & Foy [2], and Thompson et al. [3]; the operator-based implementation mirrors the structured-linear-algebra view of Golub & Van Loan [4] and the Woodbury-friendly design in gaussx.

1. The signal model

We observe a per-pixel radiance spectrum x∈RBx \in \mathbb{R}^B (one vector per pixel of the scene, with BB spectral bands). The model is

x  =  μ  +  α t  +  ε,ε∼N(0,Σ),x \;=\; \mu \;+\; \alpha\, t \;+\; \varepsilon, \qquad \varepsilon \sim \mathcal{N}(0, \Sigma),

where

Under this model, the log-likelihood of a pixel is, up to additive constants,

ℓ(α∣x)  =  −12 (x−μ−αt)⊤Σ−1(x−μ−αt).\ell(\alpha \mid x) \;=\; -\tfrac{1}{2}\,(x - \mu - \alpha t)^\top \Sigma^{-1} (x - \mu - \alpha t).

Setting ∂ℓ/∂α=0\partial \ell / \partial \alpha = 0 gives the maximum-likelihood estimator of the amplitude:

  α^(x)  =  (x−μ)⊤Σ−1tt⊤Σ−1t  \boxed{\;\hat\alpha(x) \;=\; \frac{(x - \mu)^\top \Sigma^{-1} t}{t^\top \Sigma^{-1} t}\;}

This is the matched filter. It is unbiased (E[α^]=α\mathbb{E}[\hat\alpha] = \alpha), has the minimum variance among all unbiased linear estimators (Gauss–Markov), and maximises SNR in the Neyman–Pearson sense for detecting the alternative α>0\alpha > 0 against the null α=0\alpha = 0.

1.1 The SNR and detection threshold

Under the null (α=0\alpha = 0) the score α^(x)\hat\alpha(x) is N(0,1/(t⊤Σ−1t))\mathcal{N}(0, 1/(t^\top \Sigma^{-1} t)). Under an alternative with amplitude α\alpha it is N(α,1/(t⊤Σ−1t))\mathcal{N}(\alpha, 1/(t^\top \Sigma^{-1} t)). So the detection SNR is

SNR(α)  =  αt⊤Σ−1t,\mathrm{SNR}(\alpha) \;=\; \alpha \sqrt{t^\top \Sigma^{-1} t},

and the Gaussian detection threshold for a false-alarm rate (FAR) is

τFAR  =  Φ−1(1−FAR)t⊤Σ−1t.\tau_{\mathrm{FAR}} \;=\; \frac{\Phi^{-1}(1 - \mathrm{FAR})}{\sqrt{t^\top \Sigma^{-1} t}}.

Both are implemented in matched_filter.core as matched_filter_snr and detection_threshold.

2. Practical decomposition: precompute once, apply per pixel

Equation (5) is deceptively cheap. Per pixel, it’s a dot product of length BB — except Σ−1\Sigma^{-1} appears. Done naively, you invert a B×BB \times B matrix once, but that discards the chance to exploit any structure in Σ\Sigma.

The right decomposition is

w  :=  Σ−1t,z  :=  t⊤w  =  t⊤Σ−1t.w \;:=\; \Sigma^{-1} t, \qquad z \;:=\; t^\top w \;=\; t^\top \Sigma^{-1} t.

Then per pixel

α^(x)  =  (x−μ)⋅wz\hat\alpha(x) \;=\; \frac{(x - \mu) \cdot w}{z}

— one scalar solve and one scalar, followed by one dot product per pixel (a BLAS call when vectorised over the image). This is exactly what apply_image in core.py does:

def apply_image(cube, mean, cov_op, target):
    w = gx.solve(cov_op, target)      # ← Σ⁻¹ t, one solve
    z = jnp.dot(target, w)             # ← scalar
    residual = cube - mean             # ← broadcast
    scores = einops.einsum(residual, w, "H W B, B -> H W")
    return scores / z

The key move is gx.solve(cov_op, target). Because cov_op is an abstract lineax.AbstractLinearOperator, the solve dispatches on structure: a dense operator triggers a Cholesky, a diagonal operator triggers a per-element divide, and a low-rank update λI + V D V^\top triggers Woodbury — with no change to the MF kernel above.

3. Four flavours of Σ\Sigma

The four reference files in jej_vc_snippets/methane_retrieval/ originally wrote out four separate implementations of equation (5), one per covariance model. In the operator-based view they collapse into four estimation routines that all return the same type — a lineax.AbstractLinearOperator.

Covariance estimators and the operators they produce.

Estimator

Formula

Operator type

Per-pixel cost

estimate_cov_empirical

Σ^=1N∑i(xi−μ)(xi−μ)⊤\hat\Sigma = \frac{1}{N}\sum_i (x_i - \mu)(x_i - \mu)^\top

MatrixLinearOperator (dense)

O(B2)\mathcal{O}(B^2) once, then O(B)\mathcal{O}(B)

estimate_cov_shrunk (Ledoit–Wolf, OAS)

Σ^λ=(1−λ)Σ^+λF\hat\Sigma_\lambda = (1-\lambda)\hat\Sigma + \lambda F

MatrixLinearOperator (dense, PD)

same

estimate_cov_lowrank

Σ^=τI+VDV⊤\hat\Sigma = \tau I + V D V^\top, VV top-kk SVD

gaussx.LowRankUpdate (Woodbury)

O(B⋅k+k3)\mathcal{O}(B \cdot k + k^3) once, then O(B)\mathcal{O}(B)

gmm_cluster_background

(μc,Σc)(\mu_c, \Sigma_c) per GMM cluster cc

List of operators above, per cluster

per-cluster amortised

The Ledoit–Wolf and OAS estimators come from sklearn.covariance; the randomised low-rank SVD comes from sklearn.decomposition.TruncatedSVD. Because MF estimation is off the JAX gradient path — the background is treated as a fixed input — we lean on scikit-learn freely. Only the per-pixel application stays in JAX, vectorised with jax.vmap / einsum for GPU-friendly batching.

3.1 Why low-rank + Tikhonov matters

For nsamples≫Bn_{\text{samples}} \gg B and a homogeneous scene, the spectral covariance is approximately low-rank: a handful of surface-reflectance PCs explain most of the variance. Writing Σ=τI+VDV⊤\Sigma = \tau I + V D V^\top with V∈RB×kV \in \mathbb{R}^{B \times k} and D∈Rk×kD \in \mathbb{R}^{k \times k} diagonal lets us apply Woodbury:

Σ−1  =  τ−1I  −  τ−1V(D−1+τ−1V⊤V)−1V⊤τ−1.\Sigma^{-1} \;=\; \tau^{-1} I \;-\; \tau^{-1} V \bigl(D^{-1} + \tau^{-1} V^\top V\bigr)^{-1} V^\top \tau^{-1}.

The inner inverse is k×kk \times k, so w=Σ−1tw = \Sigma^{-1} t costs O(Bk+k3)\mathcal{O}(B k + k^3) instead of O(B3)\mathcal{O}(B^3). For a typical hyperspectral methane setup (B=400B = 400, k=16k = 16), this is a ~1000× speedup on the MF precompute — visible to the user only in that estimate_cov_lowrank returns a gaussx.LowRankUpdate instead of a dense operator.

4. Relationship to 3D-Var

3D-Var minimises (see 00_variational_derivation.md, eq. 2):

J(δx)  =  12 δx⊤B−1δx  +  12 (d−H′δx)⊤R−1(d−H′δx),J(\delta x) \;=\; \tfrac{1}{2}\, \delta x^\top B^{-1} \delta x \;+\; \tfrac{1}{2}\,(d - H' \delta x)^\top R^{-1} (d - H' \delta x),

where d=y−H(xb)d = y - H(x_b) is the innovation and H′H' is the tangent-linear of the forward operator. The PSAS / dual path solves in observation space:

(H′BH′⊤+R)λ  =  d,δx^  =  BH′⊤λ.(H' B H'^\top + R) \lambda \;=\; d, \qquad \hat{\delta x} \;=\; B H'^\top \lambda.

The MF is exactly the PSAS analysis with a flat (infinite-variance) prior and identity state-space coupling.

Take B=σB2IB = \sigma_B^2 I with σB→∞\sigma_B \to \infty, R=ΣR = \Sigma, and H′δx=αtH' \delta x = \alpha t (the tangent-linear sees a unit plume amplitude as the target signature). Then equation (13) becomes

(σB2tt⊤+Σ) λ=d    ⇒    λ=Σ−1d−Σ−1tt⊤Σ−1σB−2+t⊤Σ−1t d.(\sigma_B^2 t t^\top + \Sigma)\, \lambda = d \;\;\Rightarrow\;\; \lambda = \Sigma^{-1} d - \frac{\Sigma^{-1} t t^\top \Sigma^{-1}}{\sigma_B^{-2} + t^\top \Sigma^{-1} t}\, d.

As σB→∞\sigma_B \to \infty the second term saturates, and a short calculation gives

δx^PSAS  =  d⊤Σ−1tt⊤Σ−1t⏟= α^MF(x=μ+d) t.\hat{\delta x}_{\mathrm{PSAS}} \;=\; \underbrace{\frac{d^\top \Sigma^{-1} t}{t^\top \Sigma^{-1} t}}_{=\,\hat\alpha_{\mathrm{MF}}(x = \mu + d)}\, t.

So running a single CG iteration of run_dual_psas with the flat prior and linearised H′H' gives the MF score as a by-product. The MF is therefore not a heuristic: it is the exact, closed-form, flat-prior dual 3D-Var solution, and the SNR / threshold formulas follow without further work.

The corollary is that when BB is not flat — i.e. when we have real prior information about the VMR field (spatial smoothness, a climatological mean, etc.) — the full 3D-Var retrieval strictly dominates the MF. See notebook 01_mf_vs_3dvar.ipynb for a numerical comparison on the same scene.

5. Where the target signature tt comes from

For methane, t(ν)t(\nu) is the spectral signature of a unit VMR enhancement. From the Beer–Lambert forward model L(ν)=L0(ν) exp⁡(−a(ν) ΔVMR)L(\nu) = L_0(\nu)\,\exp(-a(\nu)\,\Delta\mathrm{VMR}), the Taylor expansion at the background state gives

t(ν)  =  ∂L∂(ΔVMR)∣ΔVMR=0  =  −L0(ν)⋅a(ν).t(\nu) \;=\; \frac{\partial L}{\partial (\Delta \mathrm{VMR})}\Big|_{\Delta\mathrm{VMR}=0} \;=\; -L_0(\nu) \cdot a(\nu).

Rather than hard-coding this, we take the JVP of the existing observation operator:

t = linear_target_from_obs(obs, vmr_background, pattern="uniform")
#   internally: jax.jvp(obs.forward, (vmr_background,), (ones,))

This guarantees the target is exactly consistent with whatever forward model (PSF, GSD, SRF) the retrieval uses — no drift between “target generator” and “forward model” implementations. For strong plumes where Beer–Lambert saturation matters, nonlinear_target_from_obs(obs, x_b, amplitude=α) computes the exact finite-amplitude response L(xb+α δx)−L(xb)L(x_b + \alpha\,\delta x) - L(x_b) instead.

6. Summary

The pieces of plumax.matched_filter:

Module

Role

core.py

apply_pixel, apply_image, matched_filter_snr, detection_threshold — equation (5) + equations (6)–(7). Dispatches on cov_op structure via gaussx.solve.

target.py

linear_target_from_obs (JVP) and nonlinear_target_from_obs (finite-amplitude).

background.py

estimate_mean (robust variants), estimate_cov_{empirical,shrunk,lowrank} — sklearn in, lineax/gaussx operators out.

cluster.py

gmm_cluster_background, adaptive_window_background — spatially varying (μ,Σ)(\mu, \Sigma) when the scene is heterogeneous.

streaming.py

WelfordAccumulator, streaming_background — for multi-scene / multi-file background aggregation.

io.py

apply_image_xarray, open_multi_scene — xarray glue (dimensional metadata, Dask chunks, open_mfdataset).

The two companion notebooks:

Footnotes
  1. Funk, C. C., Theiler, J., Roberts, D. A., & Borel, C. C. (2001). Clustering to improve matched filter detection of weak gas plumes in hyperspectral thermal imagery. IEEE TGRS, 39(7).

  2. Theiler, J. & Foy, B. R. (2006). Effect of signal contamination in matched-filter detection of the signal on a cluttered background. IEEE GRSL, 3(1).

  3. Thompson, D. R., et al. (2015). Real-time remote detection and measurement for airborne imaging spectroscopy: a case study with methane. AMT, 8.

  4. Golub, G. H. & Van Loan, C. F. (2013). Matrix Computations (4th ed.). Johns Hopkins.