Matlab Design Adaptive Filter
MathWorksOfficialCreated by MathWorks
- Skill
- Tool integration
- Science and research
- BSD-2-Clause
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured approach to implementing adaptive filters using the DSP System Toolbox. It replaces deprecated adaptfilt functions with modern dsp.*Filter System objects, ensuring robust performance for tasks like system identification, noise cancellation, and active noise control. The skill emphasizes best practices for filter configuration, stability, and weight extraction, providing specific workflows for various adaptive algorithms including LMS, RLS, and Frequency Domain Adaptive Filters.
What it does
- Provides a standardized workflow for adaptive filter design using System objects.
- Offers guidance on selecting the appropriate algorithm based on input characteristics and performance requirements.
- Details the implementation of active noise control using Filtered-X LMS.
- Explains how to manage filter state and extract coefficients correctly across different object types.
- Includes patterns for low-latency long filter implementation using partitioned FDAF.
- Provides best practices for ensuring stability, including step-size calculation and coefficient freezing.
When to use it
- When performing system identification, noise cancellation, or echo cancellation.
- When implementing active noise control (ANC) or adaptive prediction.
- When migrating legacy code from deprecated adaptfilt objects to modern System objects.
- When you need to compare the performance of different adaptive filtering algorithms.
- When designing filters that require real-time, frame-based processing.
Advantages
- Ensures stability and convergence by utilizing optimized System objects.
- Provides clear, reliable methods for weight extraction and state management.
- Offers specific solutions for complex scenarios like long-filter low-latency requirements.
- Promotes consistent coding patterns that prevent common errors like manual weight-update loops.
- Facilitates easier maintenance by using current, supported toolbox functionality.
Usage examples
- “How do I implement a normalized LMS filter for system identification?”
- The agent provides a code snippet using dsp.LMSFilter with Method='Normalized LMS', demonstrates the use of maxstep() to calculate a stable step size, and shows the streaming loop for processing data frames.
- “What is the correct way to implement active noise control?”
- The agent outlines the two-stage workflow: first estimating the secondary path using dsp.LMSFilter, then configuring dsp.FilteredXLMSFilter with the estimated path for the controller.
- “How can I achieve low latency with a long adaptive filter?”
- The agent recommends using dsp.FrequencyDomainAdaptiveFilter with the 'Partitioned constrained FDAF' method, explaining how to set BlockLength to control latency.
- “How do I stop a filter from adapting while keeping it running?”
- The agent explains the use of the AdaptInputPort property for dsp.LMSFilter or the LockCoefficients property for dsp.FrequencyDomainAdaptiveFilter to freeze updates.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/matlab/matlab-design-adaptive-filter/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip matlab-design-adaptive-filter.zip -d .agents/skills
Documentation by MathWorks
Adaptive Filtering
Implementation guideline — Use DSP System Toolbox System objects to implement adaptive filters. Do not implement manual weight-update loops.
When to Use
System identification — Model unknown FIR or IIR systems online
Noise or interference cancellation — Recover signals from noise-corrupted measurement
Echo cancellation — Suppress acoustic or line echo
Active noise control — Feedforward ANC with secondary path
Inverse system identification — Equalization and deconvolution
Adaptive prediction — Linear prediction and speech coding
Algorithm evaluation — Compare adaptive filter algorithm performance
Migrating from deprecated
adaptfilt.*objects — Replaced bydsp.*FilterSystem objects (removed in R2020a)Any task involving
dsp.LMSFilter,dsp.RLSFilter,dsp.FilteredXLMSFilter,dsp.FrequencyDomainAdaptiveFilter,dsp.AffineProjectionFilter, ormaxstep()
When NOT to Use
Static (non-adaptive) FIR/IIR filter design — Use
matlab-design-digital-filterKalman filtering or state estimation — Use Control System Toolbox
Deep learning-based denoising — Use Deep Learning Toolbox
Simulink adaptive filter blocks — Use when working in Simulink (different modeling workflow)
Workflow
Every adaptive filtering task follows this five-step workflow:
1. Analyze the Problem
Before writing code, determine:
Topology — System identification, inverse system identification, noise cancellation, ANC, or prediction?
Signal characteristics — White or colored input? Stationary or time-varying?
Constraints — Filter length, latency budget, computational cost, real-time?
Filter length — Match or slightly exceed the unknown system order
2. Select Object and Method
Use the routing table to pick the right System object:
| Scenario | Object | Method/Config |
|---|---|---|
| General-purpose, white input | dsp.LMSFilter | 'Normalized LMS' |
| Colored/correlated input | dsp.AffineProjectionFilter | ProjectionOrder=4-8 |
| Fast convergence needed | dsp.RLSFilter | ForgettingFactor=0.99 |
| Tracking time-varying system | dsp.RLSFilter | ForgettingFactor=0.95-0.99 |
| Active noise control | dsp.FilteredXLMSFilter | Requires secondary path estimate |
| Long filters (>256 taps) | dsp.FrequencyDomainAdaptiveFilter | 'Constrained FDAF' |
| Long filter + low latency | dsp.FrequencyDomainAdaptiveFilter | 'Partitioned constrained FDAF' |
| Low-complexity (no multiplies) | dsp.LMSFilter | 'Sign-Data LMS' or 'Sign-Sign LMS' |
For detailed selection guidance, see references/object-selection.md.
3. Configure
Step size (critical for stability):
lms = dsp.LMSFilter(Length=L, Method="Normalized LMS");
[muMax, muMaxMSE] = maxstep(lms, x);
lms.StepSize = 0.3 * muMaxMSE;maxstep() is available only for:
dsp.LMSFilter(Methods:'LMS','Normalized LMS','Sign-Error LMS')dsp.BlockLMSFilter
For all other objects, see references/maxstep-reference.md.
Filter length: Set to unknown system order + 1 (or slightly longer if order is uncertain).
4. Run in Streaming Loop
All adaptive filter System objects process data frame-by-frame:
for k = 1:numFrames
xFrame = x((k-1)*frameSize+1 : k*frameSize);
dFrame = d((k-1)*frameSize+1 : k*frameSize);
[y, err, wts] = lms(xFrame, dFrame);
endIn simulation, use dsp.FIRFilter or dsp.IIRFilter for the unknown system. These objects automatically maintain internal filter state across frames.
5. Verify Convergence and Extract Weights
Weight extraction differs by object and is a common source of errors:
| Object | Extraction Method |
|---|---|
dsp.LMSFilter | Third output: [y, e, w] = lms(x, d) |
dsp.RLSFilter | Property: rls.Coefficients |
dsp.FilteredXLMSFilter | Property: fxlms.Coefficients (negated for ANC) |
dsp.FrequencyDomainAdaptiveFilter | See references/fdaf-filter.md — partitioned vs non-partitioned differ |
dsp.AffineProjectionFilter | Property: ap.Coefficients |
Important: dsp.LMSFilter does NOT have a .Coefficients property. The third output argument is the only way to access weights.
For full details, see references/weight-extraction.md.
Key Functions
| Function/Object | Purpose | Toolbox |
|---|---|---|
dsp.LMSFilter | LMS/NLMS/Sign variants (5 methods) | DSP System Toolbox |
dsp.RLSFilter | Recursive Least Squares (5 methods) | DSP System Toolbox |
dsp.AffineProjectionFilter | Affine Projection (colored input) | DSP System Toolbox |
dsp.FilteredXLMSFilter | Filtered-X LMS (ANC) | DSP System Toolbox |
dsp.FrequencyDomainAdaptiveFilter | FDAF (long filters, 4 methods) | DSP System Toolbox |
dsp.BlockLMSFilter | Block LMS (frame-based) | DSP System Toolbox |
dsp.AdaptiveLatticeFilter | Lattice (numerical stability) | DSP System Toolbox |
dsp.FastTransversalFilter | Fast transversal (O(N) RLS) | DSP System Toolbox |
maxstep() | Maximum stable step size | DSP System Toolbox |
msesim() | Simulated MSE learning curves | DSP System Toolbox |
Patterns
System Identification
unknownSys = dsp.FIRFilter(Numerator=fir1(31, 0.4));
lms = dsp.LMSFilter(Length=32, Method="Normalized LMS");
[muMax, muMaxMSE] = maxstep(lms, randn(1000, 1));
lms.StepSize = 0.3 * muMaxMSE;
for k = 1:numFrames
xFrame = randn(frameSize, 1);
dFrame = unknownSys(xFrame);
[~, ~, wts] = lms(xFrame, dFrame);
endActive Noise Control (Two-Stage)
% Stage 1: Estimate the secondary path
estFilter = dsp.LMSFilter(Length=secPathLen, Method="Normalized LMS");
[~, ~, secPathEst] = estFilter(probeSignal, secPathOutput);
% Stage 2: Configure the FxLMS controller
fxlms = dsp.FilteredXLMSFilter(Length=ctrlLen, ...
SecondaryPathCoefficients=secPathTrue, ...
SecondaryPathEstimate=secPathEst.');
[y, e] = fxlms(reference, errorMic);See references/fxlms-filter.md for the full ANC workflow.
Low-Latency Long Filter (Partitioned FDAF)
Use partitioned FDAF when you need a long adaptive filter with low processing latency.
fdaf = dsp.FrequencyDomainAdaptiveFilter( ...
Length=2048, ...
BlockLength=128, ...
Method="Partitioned constrained FDAF", ...
StepSize=0.5);
for k = 1:numBlocks
xBlock = x((k-1)*128+1 : k*128);
dBlock = d((k-1)*128+1 : k*128);
[y, e] = fdaf(xBlock, dBlock);
end
% Latency = BlockLength/fs = 128/16000 = 8 msSee references/fdaf-filter.md for method strings and FFTCoefficients extraction.
Freeze Adaptation (Stop Learning, Keep Filtering)
% dsp.LMSFilter — use AdaptInputPort
lms = dsp.LMSFilter(Length=32, AdaptInputPort=true);
adaptFlag = true;
for k = 1:numFrames
if k > freezeFrame, adaptFlag = false; end
[y, e, w] = lms(xFrame, dFrame, adaptFlag);
endFor dsp.FrequencyDomainAdaptiveFilter, use LockCoefficients instead. This object does not support AdaptInputPort. See references/fdaf-filter.md.
Conventions
Always use
dsp.*FilterSystem objects — Never implement weight-update loops manuallyAlways call
maxstep()for step size when available (LMS, NLMS, Sign-Error, BlockLMS)Always use
AdaptInputPort=truefor freeze/adapt control — Never wrap in if/elseAlways use
dsp.FIRFilterfor unknown system simulation — It maintains state across framesNever access
.Coefficientsondsp.LMSFilter— It doesn't exist; use third outputNever access
.Coefficientsondsp.FrequencyDomainAdaptiveFilter— Use.FFTCoefficients+ IFFTNever use
adaptfilt.*functions (adaptfilt.lms,adaptfilt.nlms,adaptfilt.rls, etc.) — The entire package was removed in R2020a and will error. Always usedsp.*FilterSystem objects.Prefer
'Normalized LMS'over'LMS'as the default method — Robust to input power variationsPrefer
'Constrained FDAF'over'Unconstrained FDAF'— Prevents spectral leakage
Common Mistakes
| Mistake | Why It's Wrong | Correct Approach |
|---|---|---|
Manual LMS loop (w = w + mu*e*x) | Error-prone, no state management, no optimized C code | Use dsp.LMSFilter with the appropriate Method |
| Hardcoded step size without stability check | May diverge or converge too slowly | Call maxstep() and use 30% of muMaxMSE |
filter(h, 1, x) per frame without state | Breaks continuity at frame boundaries | Use dsp.FIRFilter (manages state internally) |
lms.Coefficients | Property does not exist for dsp.LMSFilter | Use third output: [y, e, w] = lms(x, d) |
fdaf.Coefficients | Property does not exist for FDAF | Use real(ifft(fdaf.FFTCoefficients)) |
'Constrained FDAF' with BlockLength < Length | Silently runs but does NOT partition | Must use 'Partitioned constrained FDAF' |
| Standard LMS for ANC (ignoring secondary path) | Diverges — gradient is misaligned | Use dsp.FilteredXLMSFilter |
maxstep() on Sign-Data or Sign-Sign LMS | Throws error — unsupported | Tune StepSize empirically (start small, e.g., 0.005) |
Calling maxstep() on dsp.RLSFilter | Function does not exist for RLS | RLS uses ForgettingFactor, not step size |
| Sign-based LMS with default zero weights | sign(0)=0 stalls adaptation permanently | Set InitialConditions to small nonzero values |
Using adaptfilt.* (lms, nlms, rls, etc.) | Entire package removed in R2020a; code will not run | Replace with dsp.LMSFilter, dsp.RLSFilter, etc. |
References
Object Selection Guide — Full decision matrix
dsp.LMSFilter — methods, maxstep, AdaptInputPort, weights
dsp.RLSFilter — ForgettingFactor, methods, coefficients
dsp.FilteredXLMSFilter — ANC workflow, secondary path properties
dsp.FrequencyDomainAdaptiveFilter — Partitioned mode, FFTCoefficients
Other Filters — AP, BlockLMS, Lattice, FTF
Weight Extraction — per-object coefficient access
maxstep Reference — Compatibility and fallbacks
Copyright 2026 The MathWorks, Inc.
Files
- ATTRIBUTION.mdAdded by AutoGineer1.0 KiB
- LICENSELicence file added by AutoGineer1.4 KiB
- SKILL.md11.2 KiB
- manifest.yaml426 B
- references/fdaf-filter.md5.9 KiB
- references/fxlms-filter.md3.9 KiB
- references/lms-filter.md3.9 KiB
- references/maxstep-reference.md2.9 KiB
- references/object-selection.md3.9 KiB
- references/other-filters.md3.8 KiB
- references/rls-filter.md3.4 KiB
- references/weight-extraction.md2.8 KiB
references/fdaf-filter.md
dsp.FrequencyDomainAdaptiveFilter
When to use dsp.FrequencyDomainAdaptiveFilter
Long filters (> 256 taps) — Time-domain LMS becomes computationally expensive
Real-time block-based processing — Audio hardware buffers
Echo cancellation with long room impulse responses — Handles 1000-8000 tap systems effectively
Need both a long filter and low latency — Use partitioned mode to achieve both simultaneously
Methods (4 variants)
| Method | Partitioned? | Constrained? | Use Case |
|---|---|---|---|
'Constrained FDAF' | No | Yes | Standard; prevents spectral leakage |
'Unconstrained FDAF' | No | No | Slightly faster, may introduce spectral leakage |
'Partitioned constrained FDAF' | Yes | Yes | Long filters with low latency |
'Partitioned unconstrained FDAF' | Yes | No | Partitioned processing without constraint |
Critical: Partitioned Mode
The problem: Non-partitioned FDAF requires BlockLength = Length. For a 2048-tap filter at 16 kHz, this results in 128 ms latency, which is too high for real-time applications.
The solution: 'Partitioned constrained FDAF' splits the filter into Length/BlockLength partitions, each processed using a small FFT. The latency drops to BlockLength/fs.
fdaf = dsp.FrequencyDomainAdaptiveFilter( ...
Length=2048, ...
BlockLength=128, ...
Method="Partitioned constrained FDAF", ...
StepSize=0.5);
% Latency = 128/16000 = 8 ms (not 128 ms!)Silent failure trap: Using 'Constrained FDAF' (non-partitioned) with BlockLength < Length does NOT error. Instead, it silently runs without actual partitioning. The FFTCoefficients becomes a 1×(Length+BlockLength) vector instead of the correct P×(2*BlockLength) matrix. Only 'Partitioned constrained FDAF' enables true multi-partition processing.
Construction
fdaf = dsp.FrequencyDomainAdaptiveFilter( ...
Length=filterLength, ...
BlockLength=blockSize, ...
Method="Partitioned constrained FDAF", ...
StepSize=0.5, ...
AveragingFactor=0.9, ...
InitialPower=0.01);Key Properties
| Property | Purpose | Notes |
|---|---|---|
Length | Adaptive filter length (taps) | Defines the full impulse response length |
BlockLength | Processing frame size | Input size must match this value exactly |
Method | Algorithm variant | See the Methods table above |
StepSize | Convergence rate parameter bounded in the range [0, 1] | Default is 1.0 which often diverges — start with 0.3–0.5 |
AveragingFactor | Exponential smoothing of power estimate | Default is 0.9; values ≥0.99 can cause instability due to power estimate updating too slowly |
InitialPower | Seeds the power estimate | Important for early convergence |
LockCoefficients | Enable/disable adaptation (true/false) | Tunable; when true, freezes coefficients; can toggle between calls without reset |
Freeze Adaptation
Use LockCoefficients — NOT AdaptInputPort (which does not exist on this object):
fdaf.LockCoefficients = true; % Freeze coefficient updates
[y, e] = fdaf(xBlock, dBlock); % Filtering continues, no adaptationNo maxstep() or msesim() support
maxstep() and msesim() are NOT available for dsp.FrequencyDomainAdaptiveFilter.
Tune the step size empirically
Start with values around 0.3 to 0.5 and reduce if the algorithm becomes unstable.
State Management
Statesis a read-only property (cannot be modified or set to zero manually)release(fdaf)clears ALL internal state (FFTCoefficients, States, Power become[]). Also, discards the adapted coefficientsreset(fdaf)zeroes state and coefficients while keeping the object lockedTo clear internal state without losing adapted weights, set
LockCoefficients = true, passLength/BlockLengthblocks of zeros, then pass your signal
fdaf.LockCoefficients = true;
% Flush state with zero input
for k = 1:(fdaf.Length / fdaf.BlockLength)
fdaf(zeros(fdaf.BlockLength,1), zeros(fdaf.BlockLength,1));
end
% Resume with actual signal
[y, e] = fdaf(xBlock, dBlock);Input Requirements
Input frame length must be divisible by
BlockLength(multiples work, e.g., frame length = 128 with BlockLength = 64)Both input (x) and desired (d) signals must be column vectors
Lengthmust be evenly divisible byBlockLengthin partitioned mode (hard error otherwise)
Weight Extraction (FFTCoefficients)
FDAF stores weights in the frequency domain. There is no .Coefficients property.
Non-partitioned mode:
fftW = fdaf.FFTCoefficients; % 1×(Length+BlockLength) vector
timeDomainW = real(ifft(fftW));
adaptedWeights = timeDomainW(1:fdaf.Length);Partitioned mode:
fftW = fdaf.FFTCoefficients; % P×(2*BlockLength) matrix
% P = Length/BlockLength partitions, each row is one partition's FFT
% Reconstruct time-domain coefficients
P = size(fftW, 1);
adaptedWeights = zeros(fdaf.Length, 1);
for p = 1:P
wPartition = real(ifft(fftW(p, :)));
adaptedWeights((p-1)*fdaf.BlockLength + (1:fdaf.BlockLength)) = wPartition(1:fdaf.BlockLength);
endStreaming Pattern
fdaf = dsp.FrequencyDomainAdaptiveFilter( ...
Length=2048, BlockLength=128, ...
Method="Partitioned constrained FDAF", ...
StepSize=0.1);
unknownSys = dsp.FIRFilter(Numerator=roomIR);
numBlocks = 5000;
for k = 1:numBlocks
xBlock = randn(128, 1);
dBlock = unknownSys(xBlock);
[y, e] = fdaf(xBlock, dBlock);
endLatency Comparison
| Configuration | Latency | Use Case |
|---|---|---|
'Constrained FDAF', BlockLength=Length=2048 | 128 ms @16kHz | Offline/non-real-time |
'Partitioned constrained FDAF', BlockLength=128 | 8 ms @16kHz | Real-time echo cancellation |
'Partitioned constrained FDAF', BlockLength=64 | 4 ms @16kHz | Low-latency ANC headphones |
Copyright 2026 The MathWorks, Inc.
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
The author says: >=R2024b
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- MathWorks
- Publisher
- MathWorks (Official)
- Source
- matlab/matlab-agentic-toolkit · skills-catalog/signal-processing/matlab-design-adaptive-filter · commit 2a7f215
- Licence
- BSD 2-Clause License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE.md)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by MathWorks.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download matlab-design-adaptive-filter.zip