Pulse Generator — Control Systems/Sources
Control_Systems/Sources/Pulse_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.
Pulse Generator
Control Systems / Sources
A source producing a rectangular pulse train of a fixed period, width and phase:
y = amplitude for the first part of every cycle, y = 0 for the rest
The block holds its position in the cycle as a counter, so the waveform is built from whole samples and repeats exactly rather than drifting.
Ports
- Output – the pulse train, always a scalar. It has no inputs; the waveform comes from the block's own cycle counter and the parameters below.
Parameters
- Pulse Type – what the three timings below are measured in. The
waveform is the same either way; only the units change.
- Time based – period and phase delay in seconds, pulse width as a percentage of the period. Each must work out to a whole number of samples at the block's rate (see the note below).
- Sample based – all three in samples: the period is a count of samples, the pulse width is how many of them are high, and the phase delay is how many the cycle starts late.
- Amplitude – the high value, a single number. The low value is always zero. Negative amplitudes are allowed and simply invert the train.
- Period – the cycle length, in seconds or samples per the type above. Must be greater than zero.
- Pulse Width – how much of each cycle is high: a percentage from 0 to 100 when time based, a count of samples from 0 to the period when sample based. Zero gives a permanently low output, the full period a permanently high one.
- Phase Delay – how far into the cycle the train starts, in seconds or samples. Zero or more; a delay of a whole period is the same as no delay.
- Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period. On this block it is also what the three timings are measured against, so changing it changes which configurations are legal.
The timings must be whole samples
Every edge of a pulse train falls on a sample instant, so a period, width or phase delay that is not a whole number of samples has no sample at which to change. Simulink refuses such a configuration outright – it is a hard error there, not a warning – and so does this block: the run stops with a message naming the block and the offending value. Sample based configurations satisfy the rule by construction, since their parameters already ARE counts.
Code export
All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text. The amplitude is exposed as a tunable parameter; the three timings are baked into the arithmetic at export time, being structural – a pulse train whose cycle could be changed on a built core would be a different block. Because the whole waveform comes from a counter and not from a clock, the three HDL targets are not simulation-only here: they are an ordinary counting register with a comparison, exactly as Counter Limited is.
Simulink bridge
Import and export, mapped to simulink/Sources/Pulse Generator.
"Pulse Type" to PulseType (the two values are Simulink's own strings,
so the mapping is 1:1 and lossless both ways), "Amplitude" to
Amplitude, "Period" to Period, "Pulse Width" to
PulseWidth, "Phase Delay" to PhaseDelay, and
"Sampling Time (s)" to SampleTime as on every block. The units of the
three timings follow the pulse type on both sides, which is why they carry the
same values without conversion. TimeSource is always written as
Use simulation time: this block has no second input port to take a time
from, so there is no choice to offer.
Notes
- Stateful: the whole state is the position in the cycle, which starts at (−phase delay) mod period at the beginning of every run – so a re-run reproduces the train exactly, as does a freshly exported core.
- Discrete by nature, so it always takes its period from its own "Sampling Time (s)".
- See Variable Pulse Generator for a train whose period and duty arrive on ports rather than from configuration, and PWM for a duty cycle driven by an input signal.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Sources/Pulse_Generator |
| family | Control_Systems/Sources |
| solver environment class | ICoreBlock_0_Control_Systems_1_Sources_2_Pulse_Generator |
| source | src/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/Sources/Pulse_Generator/ICoreBlock_0_Control_Systems_1_Sources_2_Pulse_Generator.cpp |
| header | src/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/Sources/Pulse_Generator/ICoreBlock_0_Control_Systems_1_Sources_2_Pulse_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 |
|---|---|---|
Pulse Type | Time based%~%Sample based~~Time based | PulseType |
Amplitude | 1 | Amplitude |
Period | 10 | Period |
Pulse Width | 5 | PulseWidth |
Phase Delay | 0 | PhaseDelay |
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::Both |
| Simulink path | simulink/Sources/Pulse Generator |
| port-count rule | PortsParam::None |
SampleTime parameter | yes |
| always set | TimeSource = Use simulation time |
| ICore config | Simulink parameter | Value translation |
|---|---|---|
Pulse Type | PulseType | Time based → Time based, Sample based → Sample based |
Amplitude | Amplitude | passes through |
Period | Period | passes through |
Pulse Width | PulseWidth | passes through |
Phase Delay | PhaseDelay | passes through |
Caveat (shown to the user): the three timings carry the same values in both directions - their units follow the pulse type on both sides, so nothing is converted
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).
Pulse Generator block — a square wave from a cycle position counter y[k] = amplitude while (k - delay) mod period < onTime y[k] = 0 otherwise all three in SAMPLES
WHY IT IS A COUNTER AND NOT A CLOCK, in both pulse types. The obvious reading of the time-based form is y(t) = amp * (mod(t - phase, period) < period*width/100), evaluated on the simulation clock -- and that is what it means, but it is NOT how it can be computed. Every edge in that expression sits exactly ON a sample instant, so the comparison is decided by whether a floating-point mod lands on 0.25 or on 0.24999999999999997, and one such slip is a full-amplitude error for a whole sample rather than a rounding difference.
Simulink settles the question outright: a time-based Pulse Generator in a fixed-step model whose period, pulse width or phase delay is not an integer multiple of the step is a HARD ERROR there, not a warning --
"The computed sample time (0.001) is not an integer multiple of the fixed step size (0.01). The period, pulse width and phase delay parameters of this block need to be integer multiples of the fixed step size"
-- so the reference itself only ever runs on whole sample counts. This block therefore converts the three timings to sample counts once, in loadBlockConfig, and refuses the same configurations Simulink refuses (see verifyInitializedPortSignals). What is left is exact integer arithmetic, which buys three things at once: the live run and all ten exported cores are bit-identical, there is no boundary to get wrong, and the HDL targets are an ordinary synthesizable counter rather than simulation-only.
The two pulse types then differ ONLY in how the three counts are derived, which is exactly the difference Simulink draws: Time based period [s], pulse width [% of period], phase delay [s] Sample based period [samples], pulse width [samples], phase delay [samples]
THE PHASE DELAY IS FOLDED INTO THE STARTING COUNT rather than subtracted every sample. The counter starts at (-delay) mod period, taken positive, so counter[k] = (k - delay) mod period with no negative modulo anywhere -- which matters because C, Rust and Verilog take the sign of the LEFT operand there while VHDL and Python take the right, and a block that relied on the difference would compute two different waveforms across the ten backends.
Discrete by nature (setDiscreteOnlyBlock): the cycle advances once per SAMPLE, so the block must take its period from its own "Sampling Time (s)" rather than be pushed through a continuous solver's intermediate stages, which would advance the counter several times per
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__Pulse_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).