Repository navigation
Feedforward Compensation Algorithm
Relevant source files
The following files were used as context for generating this wiki page:
- scripts/verify_lockin_vs_nonlinear_real_device.py
- src/core/nonlinear_analyzer_core.py
- src/gui/widgets/feedforward_compensator.py
- tests/logic_verification/gui/test_nonlinear_analyzer_gui.py
- tests/logic_verification/gui/widgets/test_feedforward_compensator.py
- tests/logic_verification/measurement_modules/test_lockin_vs_nonlinear.py
- tests/logic_verification/measurement_modules/test_nonlinear_analyzer.py
The Feedforward Compensation subsystem implements the Iterative Linear-Inverse Compensated Feedforward (LICFF) algorithm. This system uses a Parallel Hammerstein Model (PHM) identified from the Nonlinear System Identification module to pre-distort audio signals, effectively cancelling both linear frequency response errors and nonlinear harmonic distortions in the playback chain.
The LICFF algorithm operates by applying a series of inverse kernels to the input signal. Unlike simple linear equalization, LICFF accounts for the interaction between frequency-dependent gain and nonlinear power-series terms. The implementation supports both real-time processing and iterative offline compensation for high-precision laboratory measurements.
The LICFFEngine is the primary computational entity, responsible for parsing the PHM model and preparing the inverse filters.
"LICFF Engine Data Flow"
graph TD
subgraph "Model Parsing"
A["JSON Model File"] --> B["LICFFEngine.parse_model()"]
B --> C["Power Series Kernels (q0-q5)"]
end
subgraph "Filter Preparation"
C --> D["LICFFEngine._prepare_buffers_for_length()"]
D --> E["FFT of Kernels (Q_fft)"]
D --> F["Tikhonov Regularized Inverse (F_inv_lin)"]
end
subgraph "Signal Processing"
G["Input Signal (u)"] --> H["LICFFEngine.compensate()"]
F --> H
E --> H
H --> I["Pre-distorted Signal (u_comp)"]
end
Sources: src/gui/widgets/feedforward_compensator.py:36-73, src/gui/widgets/feedforward_compensator.py:187-200
The engine consumes kernels LICFFEngine.parse_model function, these are mapped directly to power-series coefficients src/gui/widgets/feedforward_compensator.py:98-104.
To ensure stability and prevent digital clipping, the engine:
-
Normalizes kernels based on the peak of the linear response
$h_1$ src/gui/widgets/feedforward_compensator.py:125-134. -
Thresholds high-order kernels (e.g.,
$h_4, h_5$ ) against a noise floor (typically -40 dB to -80 dB relative to$h_1$ ) to prevent compensating for measurement noisesrc/gui/widgets/feedforward_compensator.py:107-122.
The linear inverse filter solve_eps_in to perform a logarithmic bisection search for an src/gui/widgets/feedforward_compensator.py:160-185.
For nonlinear compensation, the compensate method can run iteratively. In each iteration, it calculates the predicted nonlinear distortion of the current pre-distorted signal and subtracts it from the input src/gui/widgets/feedforward_compensator.py:440-470.
A critical component of the compensator is ensuring that the pre-distortion does not cause system instability.
"Stability Management and Out-of-Band Handling"
graph TD
[u_comp_signal] --> [LICFFEngine.compensate()]
[LICFFEngine.compensate()] --> [Check Out-of-Band Mode]
subgraph "OOB Handling"
[Check Out-of-Band Mode] -- "bypass_aligned" --> [Apply Bandpass Filter]
[Check Out-of-Band Mode] -- "full_compensation" --> [Unfiltered Output]
end
subgraph "Stabilization Logic"
[Apply Bandpass Filter] --> [stabilize_poly]
[stabilize_poly] --> [Polynomial Root Reflection]
[Polynomial Root Reflection] --> [Stable u_comp]
end
Sources: src/gui/widgets/feedforward_compensator.py:59-60, src/gui/widgets/feedforward_compensator.py:201-215
Since measurement models are only valid within the sweep range (e.g., 20Hz - 20kHz), the engine provides several modes defined in out_of_band_mode:
-
bypass_aligned: Applies a zero-phase bandpass filter matching the model's valid range to the compensated signal, ensuring no attempt is made to correct DC or ultrasonic regions where the model is undefined
src/gui/widgets/feedforward_compensator.py:201-225. - full_compensation: Allows the inverse filter to operate across the entire Nyquist bandwidth (risky).
| Entity | Role | Location |
|---|---|---|
LICFFEngine |
Core DSP implementation of the LICFF algorithm. | src/gui/widgets/feedforward_compensator.py:36-36 |
OfflineFFCompWorker |
QThread wrapper for batch processing WAV files. | src/gui/widgets/feedforward_compensator.py:545-545 |
FeedforwardCompensator |
Module-level logic for managing model state. | src/gui/widgets/feedforward_compensator.py:657-657 |
solve_eps_in |
Bisection search for regularization parameters. | src/gui/widgets/feedforward_compensator.py:160-160 |
forward_model |
Simulates system output for a given input. | src/gui/widgets/feedforward_compensator.py:349-349 |
The algorithm is verified through test_licff_engine_basic and test_compensate_delay_cancellation_nonlinear, which ensure that:
- Linear delays in the model are correctly cancelled by the inverse filter
tests/logic_verification/gui/widgets/test_feedforward_compensator.py:177-213. - Noise thresholding correctly zeros out insignificant high-order kernels
tests/logic_verification/gui/widgets/test_feedforward_compensator.py:138-175. - The iterative process converges for known nonlinearities (e.g., quadratic/cubic systems)
tests/logic_verification/gui/widgets/test_feedforward_compensator.py:71-92.
Sources: src/gui/widgets/feedforward_compensator.py:1-600, tests/logic_verification/gui/widgets/test_feedforward_compensator.py:1-231