Generated reference › LMS Filter — System Identification/Adaptive Filters
kind: generated#block#system-identification-adaptive-filters

LMS Filter — System Identification/Adaptive Filters

System_Identification/Adaptive_Filters/LMS_Filter · 2 input / 3 output port(s) at insert · exports to Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Description#

The block's own DESCRIPTION_HTML, rendered verbatim — the same text the config dialog's info panel and the library navigator show. Fix a wrong sentence in the block's .cpp (R-D9), never here.

LMS Filter

System Identification / Adaptive Filters

An adaptive FIR filter that tunes its own taps to make its output match a desired signal. Each step it forms the tap line x = [u[k], u[k−1], … u[k−L+1]], produces y = w′·x, measures e = d − y, and steps the weights along the instantaneous gradient: w[k+1] = w[k] + 2μ·e·x. Normalized LMS divides that step by the tap power, which makes the convergence rate independent of how loud the input is.

Ports

  • u – the filter input, scalar. It is what fills the tap line, so the whole of x is this one signal delayed.
  • d – the desired (reference) signal, scalar. What the filter is being asked to reproduce from u.
  • y – the filter output w′·x, scalar, computed from the weights as they stood BEFORE this sample's update.
  • e – the error d − y, scalar. This is the signal the filter is minimising, and in an interference-cancelling wiring it is the useful output rather than y.
  • w – the weight vector, [L,1] from Filter Length, carrying the weights AFTER this sample's update. Published after rather than before deliberately: a dropped or mis-scaled step then shows on the first samples instead of hiding inside y until the filter converges somewhere different.

Parameters

  • Filter Length – the number of taps L, a positive whole number. It sets the tap line depth, the width of the w port, and how far back in u the filter can reach.
  • Step Size – μ, the adaptation gain, entering the update as . Larger converges faster and sits noisier at the solution; too large diverges. For plain LMS stability needs roughly μ < 1/(L·E[u²]); for NLMS the normalizer removes the signal-power term and 0 < μ < 1 is the usable band.
  • Initial Weights – the seed for w. A scalar is broadcast to all L taps; a vector of exactly L entries is taken in order. Anything else is reported and stops the run.
  • Adaptation Method – which update law runs:
    • LMSw += 2μ·e·x. Multiply-accumulate only, no division.
    • Normalized LMS (NLMS)w += 2μ·e·x ÷ max(x′x, Epsilon). The step is scaled by the current tap power, so a loud stretch of input does not overshoot and a quiet one does not stall.
  • NLMS Epsilon – the FLOOR under the normalizer, not an added term: the divisor is max(x′x, Epsilon), so a silent tap line cannot divide by zero. Unused by the LMS method. It floors rather than regularizes so that on any tap line carrying real signal the value changes nothing at all.
  • Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period.

Code export

All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text. L, μ, the method and Epsilon are fixed at export time, so every array bound is a compile-time constant and the weights are seeded from Initial Weights in each target – read from the configuration, never from the running filter, whose weights have already moved by the time an export is taken.

The three HDL targets depend on the method, which is the one thing worth knowing before choosing one:

  • LMS exports as genuinely synthesizable Q16.16 fixed point. The update is multiply-accumulate with no division, so it stays in the same fixed-point datapath the signal ports already use.
  • Normalized LMS exports as simulation-only: the normalizer is a data-dependent divide, so the recursion is carried in double arithmetic and quantized only on the way out to the fixed-point ports.

μ, Epsilon and the initial weights are baked into the body at export time rather than exposed as tunable parameters – they are structural here, since changing L changes every array bound in the emitted core.

Simulink bridge

Neither direction. The System Identification Toolbox is not installed on this machine, so a bridge could not be verified against the real block even if it were written; the bridge reports this block with that reason rather than silently dropping it.

Notes

  • Stateful and discrete only. The state is the weight vector and the tap line. Both start from their seeds, and unlike the recursive identification blocks there is no warm-up: a tap line of zeros is exactly the definition of u[k] = 0 for k < 0, so the filter is correct from the first sample.
  • No state space, deliberately. The output is a product of two things that both move – the weights and the signal – so the map is nonlinear and no A/B/C/D is true of it. Model reduction reports the block as unmergeable, which is the honest answer.
  • What the filter converges to is set by the excitation. If u does not stir the part of the response d needs, no step size identifies it – pair this with a rich excitation such as a PRBS or multisine source.

Code facts#

FactValue
registered typeSystem_Identification/Adaptive_Filters/LMS_Filter
familySystem_Identification/Adaptive_Filters
solver environment classICoreBlock_0_System_Identification_1_Adaptive_Filters_2_LMS_Filter
sourcesrc/ICoreSDK/ICoreBlockLibrary/Blocks/System_Identification/Adaptive_Filters/LMS_Filter/ICoreBlock_0_System_Identification_1_Adaptive_Filters_2_LMS_Filter.cpp
headersrc/ICoreSDK/ICoreBlockLibrary/Blocks/System_Identification/Adaptive_Filters/LMS_Filter/ICoreBlock_0_System_Identification_1_Adaptive_Filters_2_LMS_Filter.h
default size on canvas100 × 80 px
ports at insert2 in, 3 out
code generators implementedPython, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Ports#

#DirectionSignal typeDescription label
1inICoreDouble
2inICoreDouble
3outICoreDouble
4outICoreDouble
5outICoreDouble

Ports the constructor creates. A block whose port list changes with its configuration adds or removes ports at load time; the count above is the one a freshly inserted block has.

Configuration variables#

Config variableDefaultSimulink parameter
Filter Length4
Step Size0.05
Initial Weights0
Adaptation MethodLMS%~%Normalized LMS (NLMS)~~LMS
NLMS Epsilon1e-12

Every block also carries Sampling Time (s) from ICoreBlockSolverEnvironment: zero or less inherits the solver's rate, a positive value runs the block at that period.

supportSupport::None
Simulink path
port-count rulePortsParam::None
SampleTime parameteryes

Caveat (shown to the user): the System Identification Toolbox is not installed on this machine, so a bridge could not be verified against the real block even if it were written

Catalog contract: src/ICoreSDK/ICoreCoder/ICoreCommandSystem/SimulinkBridge/ICoreSimulinkBlockCatalog.h

Description vs code#

The lists agree. check_block_descriptions.py finds no disagreement between the description's Ports, Parameters, Code export and Simulink bridge lists and the code's.

The verdict above is tools/docs/check_block_descriptions.py (P7.1), which compares LISTS. It cannot read a sentence: "stateless" on a block with a state, an initial-value semantic the recursion does not implement, a "not synthesizable" caveat the HDL banner contradicts. That is the agent audit (P7.3) on BLOCK_DESCRIPTION_AUDIT.md, and this tool's green is not a substitute for one.

Sample results#

LMS Filter — Step: 0 -> 1 at t = 1 sLMS Filter — Step: 0 -> 1 at t = 1 s00.51012345t (s)in ICoreDouble-Out-0in ICoreDouble-Out-0out ICoreDouble-Out-0out ICoreDouble-Out-1out ICoreDouble-Out-2 [4x1] entry 0

The same rig also ran:

StimulusWhat it isOutput range
impulseImpulse: one sample of 1 at k = 5, 0 elsewhere (Repeating Sequence Stair)0 … 0
rampRamp: slope 1 from t = 0-5.611e15 … 4.866e14
sineSine Wave: amplitude 1, 2 rad/s, no phase, no bias-1.001 … 1.003
tableRepeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample-2.679 … 3.14

Plotted: step — Step: 0 -> 1 at t = 1 s

Category dynamic · sample time 0.1 · 60 steps · commit ccf005c8 · produced by docsSample --out <folder> --steps 60 · data docs/generated/samples/System_Identification__Adaptive_Filters__LMS_Filter.json · the SVG is generated from those numbers by tools/docs/plot_svg.py, so it is a run and not a drawing (R-D10).