Time Delay Estimator — System Identification/Correlation
System_Identification/Correlation/Time_Delay_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.
Time Delay Estimator
System Identification / Correlation
Estimates the transport delay between two signals by running cross-correlation. Each step it correlates the current y against every recent sample of u – R[i] ← λ·R[i] + y[k]·u[k−i] for each lag i from 0 to the maximum – and reports the lag whose correlation is largest in magnitude. For y = g·u[k−d] that lag is d.
Ports
- u – the reference signal, scalar. It is what fills the history, so every lag is this one signal delayed.
- y – the delayed signal, scalar. What u is being correlated against.
- delay – the estimated delay in SAMPLES, scalar, always a whole number in [0, Maximum Lag]. Multiply by the sampling time for seconds.
- peak – the SIGNED correlation at that lag, scalar. Its sign is the sign of the plant gain; its magnitude is what the search ranked by.
Parameters
- Maximum Lag (samples) – the largest delay the block can report, a whole number of 0 or more. The search covers every lag from 0 to this value inclusive, so a delay beyond it is reported as whichever lag inside the window happens to correlate best – size it above the delay you expect.
- Forgetting Factor – λ, how fast old products are discounted, in (0,1]. Values just below 1 (0.9–0.99) track a delay that changes; 1 makes the correlations plain growing sums, which never settle and drift without bound, so it is offered but not recommended.
- Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period.
Notes
- Ties go to the LOWEST lag. The search scans upward and replaces the best only on a strictly greater magnitude, so when two lags tie the smaller one wins. This is the same convention as Machine Learning / Preprocessing / Argmax Decision, and it is spelled identically in all ten export targets.
- The search ranks by magnitude, the output carries the sign. A plant with negative gain correlates most strongly negatively, so ranking by the signed value would report the wrong lag for it entirely. Ranking by |R| fixes that, and the signed value still leaves on the peak port.
- The peak is a RAW correlation, not a normalized coefficient. It is comparable between lags of the same run, but not between runs at different signal levels – it scales with the amplitudes of u and y. Normalizing it would take a square root and a division per sample, which would make the HDL exports simulation-only; that trade was made in favour of synthesizable hardware. Divide it downstream if an absolute confidence is wanted.
- Stateful and discrete only. The state is the u history and the correlations. There is no warm-up: the history starts at zeros, which is exactly u[k] = 0 for k < 0, and an all-zero correlation set reports lag 0 by the tie rule above. The estimate is meaningless until enough data has accumulated, which is a property of the statistic rather than a state the block guards.
- No state space, deliberately. Correlating two signals multiplies two things that both move, and the argmax is a discontinuous selection, so no A/B/C/D is true of it. Model reduction reports the block as unmergeable, which is the honest answer.
- This is the natural pre-step to any identification with unknown dead time, and the calibration measurement for the two transport-delay blocks.
Code export
All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text. The maximum lag and λ are fixed at export time, so every array bound is a compile-time constant.
The three HDL targets are genuinely synthesizable Q16.16 – the recursion is multiply-accumulate and the search is a comparison chain, with no division anywhere. One caveat inherited from Argmax Decision: two lags whose correlations sit within a fixed-point quantum of each other can rank the other way round in hardware, and because the output is an index that moves the answer by a whole sample rather than by a small amount. It matters only when two lags are genuinely tied, which for a real delay in a well-excited signal they are not.
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/Correlation/Time_Delay_Estimator |
| family | System_Identification/Correlation |
| solver environment class | ICoreBlock_0_System_Identification_1_Correlation_2_Time_Delay_Estimator |
| source | src/ICoreSDK/ICoreBlockLibrary/Blocks/System_Identification/Correlation/Time_Delay_Estimator/ICoreBlock_0_System_Identification_1_Correlation_2_Time_Delay_Estimator.cpp |
| header | src/ICoreSDK/ICoreBlockLibrary/Blocks/System_Identification/Correlation/Time_Delay_Estimator/ICoreBlock_0_System_Identification_1_Correlation_2_Time_Delay_Estimator.h |
| default size on canvas | 100 × 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 |
|---|---|---|
Maximum Lag (samples) | 8 | — |
Forgetting Factor | 0.98 | — |
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 … 0 |
ramp | Ramp: slope 1 from t = 0 | 0 … 0 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | 0 … 0 |
table | Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample | 0 … 0 |
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__Correlation__Time_Delay_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).