Transfer Function Estimate — Control Systems/Spectral Measurements
Control_Systems/Spectral_Measurements/Transfer_Function_Estimate · 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.
Transfer Function Estimate
Control Systems / Spectral Measurements
The frequency response from x to y estimated by Welch's method –
MATLAB's tfestimate – over a sliding window: K windowed
L-point segments of the input x and the output y, their spectra averaged and
divided:
H1(m) = Pyx(m) ÷ Pxx(m) (tfestimate's default), or H2(m) = Pyy(m) ÷ Pxy(m).
That is tfestimate(x, y, window, noverlap, L) over the last
W = L + (K−1)·hop samples. The answer is complex; it is published as
its real and imaginary parts on two ports, because an ICore signal
carries doubles. Its magnitude is the gain and its angle the phase of the system
from x to y at each bin.
Ports
- x – the system's input, a scalar stream.
- y – the system's output, a scalar stream.
- Re – the real part of the estimate, a column of L/2 + 1 entries, DC first and Nyquist last; entry m is at m/L cycles per sample.
- Im – the imaginary part, the same size.
Parameters
- Segment Length – L, the transform length, an even whole number from 4 to 32. It sets the frequency resolution and the number of output bins.
- Segments – K, how many segments are averaged, from 1 to 8. One is allowed: a single segment is the empirical ratio Y/X, noisy but meaningful.
- Segment Overlap – how far the segments overlap.
- None (0%) – the hop is L.
- Half (50%) – the hop is L/2. MATLAB's default, and this block's.
- Three quarters (75%) – the hop is L/4; needs L divisible by four.
- Window – the taper applied to each segment: Hamming
(MATLAB's default), Hann or Rectangular, the symmetric forms
hammingandhannreturn. - Estimator – which ratio:
- H1 – Pyx/Pxx, tfestimate's default: unbiased when the noise is on the output.
- H2 – Pyy/Pxy: unbiased when the noise is on the input.
- 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. Every transform is a fixed weighted sum of window taps, computed once at export time, so no emitted core contains a sine, a cosine or a loop over data; the two windows become shift registers. All five settings are structural.
The three HDL targets are simulation-only: they carry the
arithmetic in real and quantize only at the port boundary, as
Magnitude-Squared Coherence's do – the answer is a ratio of run-time
quantities.
Simulink bridge
No equivalent a bridge can write (Support::None), and the
block that exists is named here rather than denied. DSP System Toolbox's
dspspect3/Discrete Transfer Function Estimator computes the H1 estimate,
but, measured on R2026a: it answers on one complex port, where this block
presents Re and Im on two real ones; driven one sample per step it publishes once
every hop samples, so its output runs at a lower rate than its input; and
its windows are the periodic forms – its steady-state outputs equal
tfestimate with hann(L,'periodic') over the W samples ending one sample before
each output, while this block uses the symmetric window tfestimate uses by
default. So no configuration crosses and no parity testbench is owed.
Notes
- Stateful and inherently discrete: two shift registers of W
samples, advanced once per sample (
setDiscreteOnlyBlock(true)), and zero-prefilled at the start of every run. - A silent window answers 0, not MATLAB's NaN: the denominators are floored at 10−30, as Magnitude-Squared Coherence floors its own. The first samples of a run, while the window is still filling from zeros, are the usual place to meet it.
- Related blocks. Magnitude-Squared Coherence reads the same averaged sums and says how far to trust this estimate bin by bin; Cross Power Spectral Density is its numerator; System Identification / Frequency Point Estimator tracks the response at ONE frequency recursively rather than at every bin of a window.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Spectral_Measurements/Transfer_Function_Estimate |
| family | Control_Systems/Spectral_Measurements |
| solver environment class | ICoreBlock_0_Control_Systems_1_Spectral_Measurements_2_Transfer_Function_Estimate |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Spectral_Measurements/Transfer_Function_Estimate/ICoreBlock_0_Control_Systems_1_Spectral_Measurements_2_Transfer_Function_Estimate.cpp |
| header | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Spectral_Measurements/Transfer_Function_Estimate/ICoreBlock_0_Control_Systems_1_Spectral_Measurements_2_Transfer_Function_Estimate.h |
| default size on canvas | 160 × 86 px |
| ports at insert | 2 in, 2 out |
| code generators implemented | Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text |
Ports#
| # | Direction | Signal type | Description label |
|---|---|---|---|
| 1 | in | ICoreDouble | x |
| 2 | in | ICoreDouble | y |
| 3 | out | ICoreDouble | Re |
| 4 | out | ICoreDouble | Im |
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 variable | Default | Simulink parameter |
|---|---|---|
Segment Length | 8 | not crossed |
Segments | 4 | not crossed |
Segment Overlap | WC::OVL_NONE%~%WC::OVL_HALF%~%WC::OVL_3Q~~WC::OVL_HALF | not crossed |
Window | WC::WIN_HAMMING%~%WC::WIN_HANN%~%WC::WIN_RECT~~WC::WIN_HA… | not crossed |
Estimator | H1%~%H2~~H1 | not crossed |
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.
Simulink bridge#
| support | Support::None |
| Simulink path | — |
| port-count rule | PortsParam::None |
SampleTime parameter | yes |
| deliberately not crossed | Segment Length, Segments, Segment Overlap, Window, Estimator |
Caveat (shown to the user): dspspect3/Discrete Transfer Function Estimator computes the H1 estimate and is named here rather than denied, but no port-to-port mapping exists, for three reasons measured on R2026a: it answers on ONE COMPLEX port where this block presents Re and Im on two real ones; driven one sample per step it publishes once every hop samples, so its output rate is not its input's; and its windows are the PERIODIC forms (its steady-state outputs equal tfestimate with hann(L,'periodic') over the W samples ending one sample before each output, to 4.4e-16), where this block uses the symmetric window tfestimate uses by default
Catalog contract: src/ICoreBlocks/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.
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).
Transfer Function Estimate -- MATLAB's tfestimate over a sliding window, as Re and Im H1(m) = Pyx(m) / Pxx(m) = SUM_s conj(X_s) Y_s / SUM_s |X_s|^2 tfestimate's default H2(m) = Pyy(m) / Pxy(m) = SUM_s |Y_s|^2 / SUM_s X_s conj(Y_s)
over the last W = L + (K-1)*hop samples of the input x and the output y, K windowed L-point segments. Welch's normalising constants cancel in both ratios, so with Magnitude-Squared Coherence's four averaged sums -- pr + j pi = SUM conj(X) Y, pxx, pyy -- H1 is (pr + j pi) / pxx and H2 is pyy (pr + j pi) / (pr^2 + pi^2). The sums, the table and the emitted multiply-accumulates are that block's, shared through ICoreWelchCrossSupport: this is not a second implementation of Welch.
⚠ MEASURED AGAINST R2026a BEFORE ANY C++ WAS WRITTEN, over hamming, hann and rectwin at L = 8, K = 4, 50 % overlap: H1 as (pr + j pi)/pxx agrees with tfestimate to 1.5e-16, and its conjugate disagrees by 1.7-1.9; H2 as pyy/(pr - j pi) agrees with tfestimate(...,'Estimator', 'H2') to 2.2e-16. So the conjugate sits on x in H1 and on y in the Pxy of H2, and a core that put it on the other side would publish the transfer function of the time-reversed system.
⚠ THE SIMULINK BLOCK EXISTS AND CANNOT BE THE BRIDGE, for the three reasons Cross Power Spectral Density records for its own: dspspect3/Discrete Transfer Function Estimator answers on ONE COMPLEX port; driven one sample per step it publishes once every HOP samples; and its windows are PERIODIC -- its steady-state outputs equal tfestimate with hann(8,'periodic') over the W samples ending one sample before each output, to 4.4e-16. Support::None, the block named.
A silent x window answers 0 rather than MATLAB's NaN: the denominators are floored at 1e-30, as the coherence floors its own.
The three HDL targets are SIMULATION-ONLY real arithmetic, as the coherence's are.
Sample results#
The same rig also ran:
| Stimulus | What it is | Output range |
|---|---|---|
impulse | Impulse: one sample of 1 at k = 5, 0 elsewhere (Repeating Sequence Stair) | 0 … 1 |
ramp | Ramp: slope 1 from t = 0 | 0 … 1 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | 0 … 1 |
table | Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample | 1 … 1 |
Plotted: step — Step: 0 -> 1 at t = 1 s
Category dynamic · sample time 0.1 · 60 steps · commit 93133d604 · produced by docsSample --out <folder> --blocks Gain_Scheduled_Lead_Lag Controller_1D Controller_Blend_1D Controller_2D Controller_3D Observer_Form_1D Self_Conditioned_1D Line_Of_Sight_Access Orbit_Propagator_Kepler Attitude_Dynamics Attitude_Profile_Nadir_Pointing Attitude_Profile_Geographic_Pointing Multitaper_PSD Cross_Power_Spectral_Density Transfer_Function_Estimate Envelope_Spectrum Compose_String Scan_String --steps 60 · data docs/generated/samples/Control_Systems__Spectral_Measurements__Transfer_Function_Estimate.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).