Generated reference › Frequency Domain Filter Identification — Control Systems/Signal Modeling
kind: generated#block#control-systems-signal-modeling

Frequency Domain Filter Identification — Control Systems/Signal Modeling

b/a

Control_Systems/Signal_Modeling/Frequency_Domain_Filter_Identification · 2 input / 2 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.

Frequency-Domain Filter Identification

Control Systems / Signal Modeling

Fits a filter b/a of numerator order nb and denominator order na to a measured frequency response, sample by sample – MATLAB's invfreqz(h, w, nb, na, wt) in the discrete domain and invfreqs(h, w, nb, na, wt) in the continuous one. The response arrives as its real and imaginary parts; the frequency grid w and the weights wt are parameters, not signals. With a(1) = 1, the fit minimizes the weighted equation error over the grid:

Σi wt(i)·|a(wi)·h(wi) − b(wi)|²,   with z−1 = e−jω in the discrete domain and s = jω in the continuous one

which is one linear least-squares problem whose design matrix is fixed by the grid, solved through the normal equations.

Ports

  • Re – the real part of the response, an [nf,1] column with one entry per frequency in the order the Frequencies parameter lists them. nf is read off the wire and must equal the number of frequencies, at most 64.
  • Im – the imaginary part, the same size as Re. A response that is real on the whole grid is fed zeros here.
  • b – the numerator coefficients, [nb+1, 1]: in descending powers of z−1 in the discrete domain, of s in the continuous one.
  • a – the denominator coefficients, [na+1, 1], with a(1) = 1.

Parameters

  • Domain – which basis the fit is written in.
    • Discrete – invfreqz: powers of z−1 = e−jω, so the frequencies are in radians per sample and normally lie in [0, π].
    • Continuous – invfreqs: powers of s = jω, so the frequencies are in radians per second and unbounded above.
  • Numerator Order – nb, 0 to 8. It sets the height of b.
  • Denominator Order – na, 1 to 8. It sets the height of a.
  • Frequencies – the grid, a row or column vector of 1 to 64 values, in radians per sample or radians per second as Domain decides. Its length is the required height of Re and Im, and 2·nf must be at least nb + na + 1 so the fit has as many real equations as unknowns.
  • Weights – wt, MATLAB's weighting vector: one positive value per frequency, or a single value for all of them (which changes nothing, since a common factor cancels). The row of the design matrix at each frequency is scaled by √wt, as both .m files do.
  • 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, from one program, so every target does the same arithmetic in the same order as the simulation. The grid, the weights and the orders are structural: the whole design matrix is folded into the exported code as constants, and only the response is read from the ports. Re-export after changing any of them.

The three HDL targets run the fit in real arithmetic and quantize only at the ports: simulation-only, not offered as synthesizable. A least-squares solve has a division by a pivot and a data-dependent row exchange, neither of which belongs in a Q16.16 datapath.

Simulink bridge

None (Support::None). invfreqz and invfreqs are Signal Processing Toolbox functions and that toolbox ships no Simulink library, so there is no path a diagram could name. The bridge reports this block rather than dropping it silently, and it has no parity testbench; code export verification covers all ten languages.

Notes

  • Verified against R2026a: see the source banner for the responses and the measured agreement with invfreqz and invfreqs.
  • ⚠ The one-shot equation-error fit is the whole block. MATLAB's two functions also offer an iterative Gauss-Newton refinement of the output error, reached by passing a maximum iteration count, and that is not offered here: each step re-stabilizes the denominator through its roots, and a root finder is not a bounded program the ten export targets can share. The two answers are different fits, not one approximating the other – on the responses this block was measured over, the refinement moves the coefficients by up to 0.059 (numerator) and 0.204 (denominator) in the discrete domain, and 0.77 and 1.04 in the continuous one.
  • Real coefficients only, which is MATLAB's default. The 'complex' option of those functions – which keeps the complex normal equations instead of their real part, and admits frequencies outside [0, π] – is not offered.
  • The least-squares step is the normal equations solved by Gaussian elimination with partial pivoting. MATLAB forms the same normal equations and factors them instead; the two differ by rounding, which grows with how ill-conditioned the grid and the response are.
  • A grid that does not determine the filter – too few distinct frequencies, a response of all zeros, a repeated point – makes the elimination divide by zero, and both outputs are NaN for that sample. MATLAB's backslash answers Inf or NaN there too, with a warning.
  • Algebraic: every output depends on this sample's response alone. It is a fit, not a filter, so it carries no state space.

Code facts#

FactValue
registered typeControl_Systems/Signal_Modeling/Frequency_Domain_Filter_Identification
familyControl_Systems/Signal_Modeling
solver environment classICoreBlock_0_Control_Systems_1_Signal_Modeling_2_Frequency_Domain_Filter_Identification
sourcesrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Signal_Modeling/Frequency_Domain_Filter_Identification/ICoreBlock_0_Control_Systems_1_Signal_Modeling_2_Frequency_Domain_Filter_Identification.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Signal_Modeling/Frequency_Domain_Filter_Identification/ICoreBlock_0_Control_Systems_1_Signal_Modeling_2_Frequency_Domain_Filter_Identification.h
default size on canvas170 × 90 px
ports at insert2 in, 2 out
code generators implementedPython, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Ports#

#DirectionSignal typeDescription label
1inICoreDoubleRe
2inICoreDoubleIm
3outICoreDoubleb
4outICoreDoublea

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
DomainDiscrete%~%Continuous~~Discrete—
Numerator Order2—
Denominator Order2—
Frequencies[0.2 0.6 1 1.4 1.8 2.2 2.6 3]—
Weights1—

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): invfreqz and invfreqs are Signal Processing Toolbox functions, not Simulink library blocks -- that toolbox ships no Simulink library at all -- so there is no path a diagram could name; the block is reported rather than dropped when a model crosses

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

Description vs code#

The checker has a blind spot here — it could not resolve something (a grouped port bullet, a computed config name), which is reported and never counted as a pass. A reader has to settle it:

  • B0 every stimulus in the sample errored — cross-checks skipped

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.

File banner (developer view)#

The top comment of the block's .cpp — the maths, the realization and the export strategy, addressed to whoever changes it. It must not contradict the description above (P7.5).

Frequency-Domain Filter Identification -- MATLAB's invfreqz and invfreqs on a fixed grid A filter b(z)/a(z) (or b(s)/a(s)) fitted to a measured frequency response, one fit per sample, from the response's real and imaginary parts on two input ports and a frequency grid that is configuration rather than signal. With sqrt(wt) weighting the rows, a(1) = 1 and the response h(i) at the grid point w(i), the equations solved are

discrete SUM(c=1..na) a(c+1) e^(-j c w) h - SUM(k=0..nb) b(k+1) e^(-j k w) = -h continuous SUM(c=1..na) a(c+1) (jw)^(na-c) h - SUM(k=0..nb) b(k+1) (jw)^(nb-k) = -(jw)^na h

in the least-squares sense over their real and imaginary halves -- which is exactly what invfreqz.m and invfreqs.m form, and what they return when called with no iteration count.

Measured against R2026a on a 16-point grid 0.11 .. 2.81 weighted 1.6 down to 0.7, over the 41 responses H0 + H1*u the verification rig itself builds -- the EXPORTED Python core, not just the live run: discrete b and a agree with invfreqz(h, w, 2, 3, wt) to 2.1e-13 and 8.0e-13 continuous b and a agree with invfreqs(h, w, 2, 3, wt) to 1.5e-12 and 2.2e-12 and a response taken FROM a filter of the configured orders is recovered as that filter: 9.7e-15 on b and 3.8e-14 on a (discrete), 7.2e-13 and 1.1e-12 (continuous).

What is not offered: the iterative Gauss-Newton refinement those two functions run when given a maximum iteration count. It re-stabilizes the denominator through its ROOTS at every step, and a root finder is not a bounded program ten languages can share. Over the same 41 responses the refinement moves the answer by up to 0.059 (numerator) and 0.204 (denominator) in the discrete domain, and 0.77 and 1.04 in the continuous one -- so the one-shot fit is a different answer from the refined one, not an approximation of it. The description says so where a user reads it.

Support::None: invfreqz and invfreqs are Signal Processing Toolbox functions and that toolbox ships no Simulink library.

Sample results#

No stimulus produced a sampled output in this rig — Invalid input size at Frequency-Domain Filter Identification block: ICore Blocks/Home/Frequency Domain Filter Identification. That is a fact about the single-block rig, not a verdict on the block: an offline batch fit, a block whose output only appears at onSolverFinish, or one that needs a driven environment cannot be exercised alone.

Category unsampled · sample time 0.1 · 60 steps · commit 875fdbf564cf31a145283edf6a75dc1d64d1090a · produced by docsSample --out <folder> --blocks Wigner_Ville_Distribution Cross_Wigner_Ville_Distribution Inverse_STFT Fourier_Synchrosqueezed_Transform Time_Frequency_Ridges Frequency_Domain_Filter_Identification Fill_Gaps EOM_6DOF_ECEF_Quaternion EOM_6DOF_Custom_Variable_Mass_ECEF_Quaternion EOM_6DOF_Simple_Variable_Mass_ECEF_Quaternion ECI_To_ECEF_Rotation_Matrix ECI_Position_To_LLA LLA_To_ECI_Position ECI_Position_To_AER --steps 60

Sample data: docs/generated/samples/Control_Systems__Signal_Modeling__Frequency_Domain_Filter_Identification.json