Waveform Generator — Control Systems/Sources
Control_Systems/Sources/Waveform_Generator · 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.
Waveform Generator
Control Systems / Sources
A source producing one of six parameterized waveforms. Everything except constant starts at Delay; before that the output is Bias. With τ = t − Delay and φ = frac(f·τ):
- sinusoid – y = A·sin(ω·τ + φ0) + bias
- square – +A + bias while φ < duty, −A + bias after (bipolar)
- sawtooth – y = A·(2φ − 1) + bias, a ramp rising from −A to +A
- pulse – +A + bias while φ < duty, bias after (unipolar)
- step – y = A + bias once the delay has passed
- constant – y = A + bias for all t
Ports
- Output – the generated signal, always a scalar. It has no inputs.
Parameters
- Waveform – which of the six to generate. This selects the implementation rather than retuning one, so each is a separate code path, and several of the parameters below apply only to some of them.
- Amplitude – the peak A. Applies to every waveform; for step and constant it is the level itself.
- Frequency (Hz) – cycles per second, used by sinusoid, square, sawtooth and pulse. Ignored by step and constant. Must be greater than zero.
- Phase (rad) – the phase offset of the sinusoid, in radians. Ignored by the other five.
- Bias – a constant offset added to every waveform, and the value produced before Delay.
- Duty Cycle (%) – the percentage of each cycle spent high, used by square and pulse. Between 0 and 100; 50 gives an even square.
- Delay (s) – when the waveform starts. Before it the output is Bias. It is a genuine start time rather than a phase shift, so the first cycle always begins at its own beginning. constant ignores it.
- Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period. It also sets how finely the waveform is resolved, so a coarse rate visibly aliases a fast one.
The sawtooth rises here, and falls on Signal Generator
Deliberately. The Signal Generator block mirrors simulink/Sources/Signal Generator, whose sawtooth was measured falling from +A to −A; this block follows the conventional rising ramp of a waveform-notation generator. Reach for whichever matches the model you are reproducing.
Code export
All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text. Each uses a per-block local sample clock rather than a global one. The chosen Waveform and all of its timing – frequency, phase, duty cycle and delay – are structural and are baked into the exported body, so the generated core carries the one waveform rather than a run-time switch; Amplitude and Bias stay tunable, being a pure scale and offset that appear as a multiplier and an addend in every branch.
The three HDL targets are simulation-only: they read the testbench's simulation time and carry the phase in real arithmetic, quantizing only on the way out to the fixed-point signal ports. The timing is inlined there as exact real literals rather than quantized into Q16.16 parameter ports, because a rate carrying the 1.5×10−5 Q-format step would accumulate a phase error that grows with the length of the run.
Simulink bridge
Neither direction. Simulink's Waveform Generator defines its
output through a WaveformDefinition of signal-notation strings, and
that definition is not reachable through set_param –
the block's dialog parameters are only OutMin, OutMax,
OutDataTypeStr, LockScale, RndMeth,
SaturateOnIntegerOverflow, SelectedSignal and
SampleTime, with no waveform parameter among them. The bridge writes
.m scripts driven by set_param, so there is nothing it could emit
that would carry the waveform, and nothing it could read back. Rather than assert
a mapping that could never be checked, the bridge reports this block and skips
it.
The waveform names above are Simulink's own, so a model can be moved by hand: place the Simulink block, and write the matching notation into its dialog.
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.
- square, sawtooth, pulse and step are discontinuous. A continuous solver does not step onto their jumps, so a transition lands on whichever sample follows it; at a coarse rate that is visible as jitter in the edge position.
- Scalar only. Use several blocks, or a Mux, for a vector of waveforms.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Sources/Waveform_Generator |
| family | Control_Systems/Sources |
| solver environment class | ICoreBlock_0_Control_Systems_1_Sources_2_Waveform_Generator |
| source | src/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/Sources/Waveform_Generator/ICoreBlock_0_Control_Systems_1_Sources_2_Waveform_Generator.cpp |
| header | src/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/Sources/Waveform_Generator/ICoreBlock_0_Control_Systems_1_Sources_2_Waveform_Generator.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 |
|---|---|---|
Waveform | sinusoid%~%square%~%sawtooth%~%pulse%~%step%~%constant~~s… | — |
Amplitude | 1 | — |
Frequency (Hz) | 1 | — |
Phase (rad) | 0 | — |
Bias | 0 | — |
Duty Cycle (%) | 50 | — |
Delay (s) | 0 | — |
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 Waveform Generator defines its output through a WaveformDefinition of signal-notation strings, which is not reachable through set_param: the block's dialog exposes only OutMin, OutMax, OutDataTypeStr, LockScale, RndMeth, SaturateOnIntegerOverflow, SelectedSignal and SampleTime, with no waveform parameter among them. The bridge writes .m scripts driven by set_param, so there is nothing it could emit to carry the waveform and nothing it could read back. The waveform names here are Simulink's own, so a model can be moved by hand by writing the matching notation into the Simulink block's dialog
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).
Waveform Generator block — six parameterized waveforms from one block Everything but
constantstarts at Delay; before it the output is Bias. With tau = t - Delay and phi = frac(f*tau):sinusoid y = A*sin(w*tau + phase) + bias square y = +A + bias while phi < duty, -A + bias after (bipolar) sawtooth y = A*(2*phi - 1) + bias (RISING) pulse y = +A + bias while phi < duty, bias after (unipolar) step y = A + bias constant y = A + bias, for all t (the one waveform Delay does not apply to)
WHY EVERY PERIODIC WAVEFORM IS GATED ON t >= Delay, and not merely phase-shifted. It makes the argument of frac() non-negative everywhere it is evaluated, which is what lets all ten backends spell it the same way. Structured Text has no floor: it has TRUNC, which rounds toward ZERO, and the two agree only for non-negative arguments. Phase-shifting instead would put negative times into frac() before the waveform starts, and the ST core alone would disagree with the other nine -- a one-backend failure with no obvious cause.
NOTE THE SAWTOOTH RISES, and Signal Generator's FALLS. That is not an oversight: Signal Generator mirrors simulink/Sources/Signal Generator, whose sawtooth was measured falling from +A to -A, while this block follows the conventional rising ramp of a waveform-notation generator. Both are documented on their own block; they are different blocks, not one behaviour written twice.
ONE RULE, FORMATTED TEN TIMES. buildBranches() produces the waveform as a language-neutral ordered list of (condition, value) pairs, and each backend only chooses punctuation. Six waveforms across ten targets is sixty chances to get a comparison backwards; this reduces it to one. The two places languages genuinely differ -- Rust's postfix
x.sin()and ST's wrapped truncation -- are passed in as MathSyntax rather than switched on.WHY THERE IS NO SIMULINK BRIDGE. Simulink's Waveform Generator defines its output through a WaveformDefinition of signal-notation strings, and that definition is not reachable through set_param at all. Verified against R2026a: the block's DialogParameters are only OutMin, OutMax, OutDataTypeStr, LockScale, RndMeth, SaturateOnIntegerOverflow, SelectedSignal and SampleTime -- no waveform parameter among them -- and set_param on 'WaveformDefinition', 'SignalDefinition' and 'Waveforms' each fail with "block (mask) does not have a parameter named ...", while 'IOSignalStrings' rejects the value. The bridge writes .m scripts driven by set_param, so there is nothing it could emit that would carry the waveform. It registers Support::None with that reason rather than asserting a mapping that nothing could check.
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__Waveform_Generator.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).