Adaptive one-step AR prediction

Tutorial goal

Use a stable adaptive recursive model for one-step signal prediction.

Note

New to the terminology? See the lattice DSP concept map and the causality/data-use guide for how online, offline, block, and MIMO examples should be read.

Context

AR prediction is the scalar setting where lattice filters are historically very natural. The model predicts the current sample from past samples while preserving a stable recursive parameterization.

Key idea and equations

A one-step predictor estimates

\[\hat{x}[n] = g(x[n-1], x[n-2], \ldots),\qquad e[n]=x[n]-\hat{x}[n].\]

How to read the result

The final prediction error should be smaller than the initial error after the predictor adapts.

Run command

python examples/adaptive_prediction_ar.py

Run status

Return code: 0

Captured stdout

learned reflection: [0.211, 0.0431]
learned numerator: [-0.5415, 0.1499, 0.1625]
initial prediction MSE: 0.9473323949351461
final prediction MSE: 0.10241638741994595

Source code

 1"""AR-style prediction with stable reflection updates.
 2
 3The predictor estimates x[n] from previous samples using a stable IIR model.
 4This is a compact example; production AR estimation should add model-order
 5selection, stationarity checks, and validation on held-out data.
 6"""
 7
 8from __future__ import annotations
 9
10import numpy as np
11
12from lattice_dsp import AdaptiveLatticeLadderNLMS, LatticeIIR
13
14rng = np.random.default_rng(7)
15innovation = rng.normal(scale=0.3, size=5000)
16source = LatticeIIR([0.65, -0.35], [1.0, 0.0, 0.0])
17x = np.asarray(source.process(innovation), dtype=float)
18
19# Predict x[n] from x[n-1]. The input stream is delayed by one sample.
20predictor_input = np.concatenate([[0.0], x[:-1]])
21desired = x
22
23predictor = AdaptiveLatticeLadderNLMS(
24    initial_reflection=[0.0, 0.0],
25    initial_taps=[0.0, 0.0, 0.0],
26    mu_taps=0.05,
27    mu_reflection=0.001,
28    margin=1e-4,
29)
30errors = np.asarray(predictor.adapt_block(predictor_input.tolist(), desired.tolist()), dtype=float)
31
32print("learned reflection:", np.round(predictor.reflection, 4).tolist())
33print("learned numerator:", np.round(predictor.numerator, 4).tolist())
34print("initial prediction MSE:", float(np.mean(errors[:500] ** 2)))
35print("final prediction MSE:", float(np.mean(errors[-500:] ** 2)))