Adaptive notch tracking¶
Tutorial goal
Track and suppress a sinusoidal interferer with a stable second-order notch model.
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¶
Notch filters are a compact way to remove narrowband interference. This tutorial uses a small adaptive example to show how a stable recursive structure can follow an interfering tone.
Key idea and equations¶
A second-order notch has a pair of zeros near the interference frequency and stable poles whose radius controls bandwidth.
How to read the result¶
Inspect the estimated notch frequency and the before/after error or suppression metric.
Run command¶
python examples/adaptive_notch_tracking.py
Source code¶
1"""Adaptive notch tracking demo.
2
3Run after installing the package:
4 python examples/adaptive_notch_tracking.py
5"""
6
7import numpy as np
8
9from lattice_dsp import AdaptiveNotch
10
11rng = np.random.default_rng(123)
12fs = 8_000
13n = np.arange(8_000)
14theta_true = 0.31 * np.pi
15frequency_hz = theta_true * fs / (2 * np.pi)
16
17x = np.sin(theta_true * n) + 0.05 * rng.normal(size=n.size)
18notch = AdaptiveNotch(theta=0.8, pole_radius=0.98, mu=0.005)
19y = notch.process(x)
20
21print("true frequency [Hz]: ", round(frequency_hz, 2))
22print("estimated frequency [Hz]:", round(notch.theta * fs / (2 * np.pi), 2))
23print("input RMS: ", float(np.sqrt(np.mean(x * x))))
24print("output RMS: ", float(np.sqrt(np.mean(y[-2000:] * y[-2000:]))))