Signal Editor — Control Systems/Sources
Control_Systems/Sources/Signal_Editor · 0 input / 1 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.
Signal Editor
Control Systems / Sources
A source playing back a signal the user authors as a table of breakpoints: a list of times and the value the signal takes at each, joined by the chosen interpolation.
Between two breakpoints, y = Vi + mi·(t − Ti) for linear interpolation, where mi is that segment's slope, or simply y = Vi for a zero-order hold.
Ports
- Output – the played-back signal, always a scalar. It has no inputs; the whole waveform comes from the table below.
Parameters
- Time Breakpoints – the times at which the signal is defined, as a row vector. Must be strictly increasing, and must have the same number of entries as the values below. They need not be evenly spaced, and need not line up with the block's sampling time.
- Signal Values – the value at each of those times, in the same order and of the same length.
- Interpolation – how the signal moves between two breakpoints:
- Linear – the default; a straight line from one to the next, so the output is continuous.
- Zero Order Hold – the value is held from each breakpoint until the next, giving a staircase that steps at the breakpoints.
- Output After Final Value – what happens once the last breakpoint
has passed:
- Holding final value – the default; the last value continues indefinitely.
- Setting to zero – the output drops to zero. Note the drop is a step unless the last value is already zero.
- Extrapolation – the last segment's slope carries on, so the signal keeps rising or falling. With a zero-order hold there is no slope to continue and this behaves as holding.
- Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period. It is separate from the breakpoint times: this is how often the table is sampled, not how often it changes, so a rate coarser than the gaps between breakpoints will step straight over some of them.
Before the first breakpoint
The first value is held. A table starting at t = 0 – the usual case – never sees this, but one that starts later begins flat at V0 rather than at zero.
Code export
All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text. The whole table is structural and is baked into the exported body as an unrolled chain of comparisons – one branch per segment, with each segment's slope computed at export time rather than in the generated code. Nothing about the table is tunable afterwards: changing the signal means re-exporting, which is the honest reflection of it being the block's definition rather than a setting. A long table therefore produces a long body, one branch per breakpoint.
The three HDL targets are simulation-only: they read the testbench's simulation time and compare in real arithmetic, quantizing only on the way out to the fixed-point signal port.
Simulink bridge
Neither direction. Simulink's Signal Editor does not hold its
data in the block: it names an external MAT-file, a scenario inside it and a
signal inside that (FileName, ActiveScenario,
ActiveSignal). The bridge writes .m scripts, so exporting this block
would mean authoring a MAT-file of timeseries objects beside the script and
relying on the two staying together, and importing one would mean reading a file
that may not be present. Neither is a mapping that can be asserted honestly, so
the bridge reports this block and skips it.
The behaviour matches, though, and the two option lists deliberately use
Simulink's own words – Interpolation against its
Interpolate, and Output After Final Value against its
OutputAfterFinalValue, whose three settings have the same names
here. Moving a model by hand means transferring the data and nothing else.
Notes
- Stateless and time-driven: the output is a function of the current time alone, so there is nothing to reset and a re-run reproduces it exactly.
- Linear interpolation makes the output continuous but its slope discontinuous at every breakpoint. A continuous solver does not step onto those corners, so a downstream derivative will show a spike at each one.
- Scalar only, and one signal per block. Simulink's counterpart can carry a whole scenario of several signals; use one block per signal, or a Mux.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Sources/Signal_Editor |
| family | Control_Systems/Sources |
| solver environment class | ICoreBlock_0_Control_Systems_1_Sources_2_Signal_Editor |
| source | src/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/Sources/Signal_Editor/ICoreBlock_0_Control_Systems_1_Sources_2_Signal_Editor.cpp |
| header | src/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/Sources/Signal_Editor/ICoreBlock_0_Control_Systems_1_Sources_2_Signal_Editor.h |
| default size on canvas | 80 × 70 px |
| ports at insert | 0 in, 1 out |
| code generators implemented | Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text |
Ports#
| # | Direction | Signal type | Description label |
|---|---|---|---|
| 1 | 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 |
|---|---|---|
Time Breakpoints | [0 1 2 3] | — |
Signal Values | [0 1 1 0] | — |
Interpolation | Linear%~%Zero Order Hold~~Linear | — |
Output After Final Value | Holding final value%~%Setting to zero%~%Extrapolation~~Ho… | — |
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): Simulink's Signal Editor keeps its data in an external MAT-file rather than in the block (FileName, ActiveScenario, ActiveSignal), so there is no set of block parameters to map: exporting would mean authoring a MAT-file of timeseries objects beside the generated script, and importing would mean reading a file that may not be present. The BEHAVIOUR matches, and the Interpolation and Output After Final Value options use Simulink's own names, so a model can be moved by hand by transferring the data alone
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.
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).
Signal Editor block — playback of a user-authored piecewise signal A table of (time, value) breakpoints played back against the simulation clock, with a choice of interpolation between them and a choice of what happens after the last one:
t < T[0] y = V[0] (held before the table starts) T[i] <= t < T[i+1] Linear: y = V[i] + m[i]*(t - T[i]), m[i] = (V[i+1]-V[i])/(T[i+1]-T[i]) ZOH: y = V[i] t == T[n-1] y = V[n-1] t > T[n-1] the "Output After Final Value" policy
ONE RULE, FORMATTED TEN TIMES. The playback rule is built ONCE, in buildBranches(), as a language-neutral ordered list of (condition, value) pairs; each of the ten backends only chooses punctuation for the if / else-if chain. Ten hand-written searches over the same table is exactly the shape of code where the backends drift apart -- an off-by-one in the segment lookup, a
<where another wrote<=-- and code-export verification would then fail on whichever language got it wrong, with a residual that looks like broken maths. The table is unrolled into the chain rather than emitted as an array, so no backend needs array-literal syntax or a loop, and the five with awkward array support cost nothing extra.WHY THERE IS NO SIMULINK BRIDGE. Simulink's Signal Editor does not carry its data in the block at all: it names an external .mat file, a scenario within it and a signal within that (FileName / ActiveScenario / ActiveSignal, verified against the R2026a dialog). The bridge writes .m scripts, so exporting one of these blocks would mean authoring a MAT-file of timeseries objects beside the script and hoping the two stay together -- and importing one would mean reading a file that may not be present. Neither is a mapping this catalog can honestly assert, so the block registers Support::None with that reason and the bridge reports it. The BEHAVIOUR is the same, and the two "Interpolate" and "OutputAfterFinalValue" settings deliberately use Simulink's own words, so a model can be moved by hand without translating anything but the data.
Code export: all ten targets. The three HDL ones are SIMULATION-ONLY -- they read the testbench's
sim_timeand compare in real arithmetic, quantizing only on the way out.
Sample results#
Plotted: free — No input: the block run alone
Category source · sample time 0.1 · 60 steps · commit ccf005c8 · produced by docsSample --out <folder> --steps 60 · data docs/generated/samples/Control_Systems__Sources__Signal_Editor.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).