Frequency Point Estimator — System Identification/Frequency Domain
System_Identification/Frequency_Domain/Frequency_Point_Estimator · 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 Point Estimator
System Identification / Frequency Domain
Measures one point of the u→y frequency response, live, by the correlation (lock-in) method. It multiplies both signals by a reference cos(ωt) and sin(ωt) at the configured frequency, keeps exponentially-forgotten averages of the four products, and divides the resulting phasors: G = Y ÷ U. Noise at every other frequency averages towards zero by construction, so this is a cheap and very robust commissioning measurement.
Ports
- u – the excitation signal, scalar.
- y – the measured response, scalar.
- Re G – the real part of the response at the configured frequency, scalar.
- Im G – the imaginary part, scalar.
Parameters
- Frequency (Hz) – the single frequency the estimate is made at. The excitation must actually contain it: a signal that does not stir this frequency leaves the denominator at its floor and the answer means nothing.
- Forgetting Factor – λ, how fast old products are discounted, in (0,1]. Just below 1 (0.9–0.99) tracks a response that drifts; 1 makes the four correlations plain growing sums, which never settle, so it is offered but not recommended.
- Epsilon – the FLOOR under the divisor, not an added term: the denominator is max(Uc² + Us², Epsilon), so an excitation with no content at this frequency cannot divide by zero. It floors rather than regularizes, so on any signal that does excite the frequency 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. It also sets the reference's per-sample rotation, so it must be small enough to resolve the frequency – below half a period, by Nyquist.
Notes
- Re/Im, not magnitude/phase, deliberately. Recovering phase needs atan2, which the ten export targets do not carry evenly – IEC 61131-3 has ATAN but no ATAN2, and the HDL targets have neither. Feed these two into Robotics / Coordinate Transforms / Cartesian to Polar, which already exists, if magnitude and phase are what you want.
- The reference is generated by rotation, not by calling sin/cos. The block carries the reference phasor as state and turns it by one sample's angle each step, from two constants fixed when the model is built. That is why it needs no trigonometry at all in any exported language.
- Stateful and discrete only. The state is the reference phasor and the four correlations, all seeded at the start of the run. The estimate is meaningless until several periods have been averaged, which is a property of the statistic rather than a state the block guards.
- No state space, deliberately: the output divides two quantities that both move, so no A/B/C/D is true of it. Model reduction reports the block as unmergeable, which is the honest answer.
- The natural partner of a Multisine Generator or PRBS Generator excitation – put one of those in, and read the response off here.
Code export
All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text. λ, Epsilon and the reference's two rotation constants are baked into the body at export time, so no target computes a trigonometric function or reads a clock.
The three HDL targets are simulation-only: the recursion is carried in double arithmetic and quantized only on the way out. That is because G = Y ÷ U is a data-dependent divide – not because of the reference, which is plain multiply-add and would have been synthesizable on its own.
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.
Code facts#
| Fact | Value |
|---|---|
| registered type | System_Identification/Frequency_Domain/Frequency_Point_Estimator |
| family | System_Identification/Frequency_Domain |
| solver environment class | ICoreBlock_0_System_Identification_1_Frequency_Domain_2_Frequency_Point_Estimator |
| source | src/ICoreSDK/ICoreBlockLibrary/Blocks/System_Identification/Frequency_Domain/Frequency_Point_Estimator/ICoreBlock_0_System_Identification_1_Frequency_Domain_2_Frequency_Point_Estimator.cpp |
| header | src/ICoreSDK/ICoreBlockLibrary/Blocks/System_Identification/Frequency_Domain/Frequency_Point_Estimator/ICoreBlock_0_System_Identification_1_Frequency_Domain_2_Frequency_Point_Estimator.h |
| default size on canvas | 110 × 70 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 | — |
| 2 | in | ICoreDouble | — |
| 3 | out | ICoreDouble | — |
| 4 | out | ICoreDouble | — |
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 |
|---|---|---|
Frequency (Hz) | 1 | — |
Forgetting Factor | 0.98 | — |
Epsilon | 1e-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.
Simulink bridge#
| support | Support::None |
| Simulink path | — |
| port-count rule | PortsParam::None |
SampleTime parameter | yes |
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#
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 ccf005c8 · produced by docsSample --out <folder> --steps 60 · data docs/generated/samples/System_Identification__Frequency_Domain__Frequency_Point_Estimator.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).