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.

Gaussian plume — state estimation of a time-varying emission rate

State estimation — tracking a time-varying emission rate

Many real methane point sources are episodic: the emission rate Q(t) drifts, ramps, or switches abruptly between operating regimes. If we have a sequence of downwind concentration measurements at times t=1…Tt = 1 \dots T, we can treat Q_t as a latent state evolving via a random walk and sample the entire trajectory jointly with NumPyro. That is state estimation, and it sits on the parameter-estimation notebook like a smoothing pass sits on a batch fit.

The state-space model here is:

Qt∼Normal(Qt−1,σQ),yt,i∼Normal(fplume(Qt,ri,w,s)+b,  σobs)Q_t \sim \mathrm{Normal}(Q_{t-1}, \sigma_Q), \qquad y_{t,i} \sim \mathrm{Normal}\big(f_{\mathrm{plume}}(Q_t, \mathbf{r}_i, \mathbf{w}, s) + b,\; \sigma_{\mathrm{obs}}\big)

with a log-normal prior on Q1Q_1, a half-normal on the random-walk increment σQ\sigma_Q, and a shared scalar background bb. The forward operator fplumef_{\mathrm{plume}} is the same plume_concentration we’ve used in the previous two notebooks.

1. Simulate a synthetic trajectory

We emulate 30 satellite passes at roughly hourly cadence. The true Q_t is a smooth ramp from 0.05 kg/s up to 0.20 kg/s with a single abrupt drop at t=20t = 20 (a simulated compressor shutdown event), plus small Gaussian jitter. At each time step we measure concentrations at 6 downwind receptors.

<Figure size 900x360 with 1 Axes>

Receptor layout is fixed over time: six points along a downwind transect, ground level. Wind and stability class are held constant (realistic for short overpass sequences; the model trivially extends to time-varying wind).

<Figure size 1000x430 with 2 Axes>

2. State-space model with a random-walk prior on Q

The NumPyro model below is ~25 lines: a vectorised latent q of length T (sampled via numpyro.plate), a random-walk transition enforced as a factor, a half-normal background, and a plated likelihood over the (T, N_rx) observation tensor. We vmap the forward model over the latent sequence so the full likelihood is a single JIT-compiled kernel.

We run NUTS with a short config. A T = 30 random walk with N_rx = 6 observations per step gives a latent dimension of ~31 plus two hyperparameters — well within a single-chain NUTS budget.

Posterior shape: (800, 30)
Background posterior: 5.818e-06
Walk σ_Q posterior:   0.1977

3. Compare to a per-timestep independent fit

To see what the random-walk prior actually buys us, we also fit each QtQ_t independently (ignoring the temporal correlation). With only 6 receptors per time step the independent fits are much noisier; the state-space model borrows strength from neighbouring times to smooth through the noise, while still tracking the abrupt step at t=20t = 20.

Final plot: the truth in bold, the independent-fit means with their per-time credible intervals, and the state-space posterior over QtQ_t as a shaded envelope.

<Figure size 1100x480 with 1 Axes>

Summary

The random-walk prior on QtQ_t gives the inference a built-in smoother: transient observation noise is averaged across time while the large step at t=20t = 20 is still recovered. Tightening the prior on σQ\sigma_Q would produce more aggressive smoothing (useful when Q is known to be smooth); loosening it recovers the independent-fit behaviour. With time-varying wind or stability, each of those can enter the same state-space structure — stack them into receptor_coords and dispersion_params axes and the model extends naturally.