FXLMS is the reference broadband feedforward controller in this codebase.
Filtered-X LMS combines a causal reference microphone, an FIR control filter, and an identified secondary-path estimate. In the repository benchmark suite it is the strongest general-purpose controller: fast to converge, straightforward to tune, and capable of deep attenuation when the secondary-path model is usable.
Core Equations
The control output is an FIR inner product:
\[y(n) = \sum_{i=0}^{N-1} w_i(n) x(n-i)\]The reference is filtered through the secondary-path estimate:
\[x'(n) = \sum_{i=0}^{M-1} c_i x(n-i)\]The adaptive update is then:
\[w_i(n+1) = w_i(n) - \mu e(n) x'(n-i)\]The negative sign matters. This repository follows the acoustic superposition convention used in active noise cancellation, where the anti-noise adds at the error sensor rather than subtracting electrically.
Why It Works Well Here
The benchmark suite shows 61.127 dB attenuation in the primary broadband case with convergence by sample 256. That combination of strong steady-state performance and fast convergence is why FXLMS is the first controller to try unless the disturbance is strongly periodic or the reference microphone is contaminated.
Running RMS
The residual drops quickly and stabilizes at a very low floor in the matched broadband scenario.
Step-size sweep
The sweep shows a clean improvement curve until the controller crosses into instability at an overly aggressive step size.
Tuning Notes
- Start with a moderate controller order and a conservative step size.
- Treat the secondary-path estimate quality as a stability requirement, not just a performance refinement.
- Increase the step size until convergence is fast enough, then stop short of the instability cliff visible in the sweep.
- If long-run drift becomes a problem, move to Leaky FXLMS rather than forcing FXLMS to do regularization itself.
Using It From C++
#include "anc/fxlms_controller.h"
anc::FxlmsConfig config;
config.controllerOrder = 48;
config.secondaryEstimate = {0.0, 0.12, 0.38, 0.21, -0.05};
config.stepSize = 0.005;
config.leakage = 1.0;
anc::FxlmsController controller(config);
for (std::size_t sample = 0; sample < reference.size(); ++sample) {
const double control = controller.synthesize(reference[sample]);
const double error = disturbance[sample] + secondaryPath(control);
controller.adapt(error);
}
The controller exposes weights() and filteredReferenceHistory() when you need instrumentation or debugging around adaptation state.
CLI Reproduction
build\Debug\anc_cli.exe `
--algorithm fxlms `
--summary analysis_output\raw\fxlms_broadband_summary.csv `
--timeseries analysis_output\raw\fxlms_broadband_timeseries.csv `
--samples 12000 `
--controller-order 48 `
--step-size 0.005