Weighted Sample Time Math — Control Systems/Base Blocks
Control_Systems/Base_Blocks/Weighted_Sample_Time_Math · 1 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.
Weighted Sample Time Math
Control Systems / Base Blocks
Does arithmetic between the input and the block's own sample time, scaled by a weight: y = u <op> (Ts·w), applied entry by entry. It is how a rate-dependent constant – a per-step increment, a discrete integrator's step, a frequency in samples – is written once and follows the model's rate instead of being retyped whenever that rate changes.
Ports
- Input – the signal u, of any size [m,n]. The two only operations ignore it, but the port stays: it is what fixes the output size and the rate.
- Output – y, of the SAME size [m,n]. The block never reshapes a signal.
Parameters
- Operation – which arithmetic runs. This selects the code path
rather than retuning one, so each option is a separate branch in all ten export
targets.
- u + Ts*w – adds the weighted sample time. The default, as in Simulink.
- u - Ts*w – subtracts it.
- u * (Ts*w) – scales the input by it.
- u / (Ts*w) – divides the input by it. Requires a nonzero weight.
- Ts*w only – the output is the weighted sample time itself, the same value in every entry. The input is ignored, though its size still sets the output's.
- 1/(Ts*w) only – the output is the RECIPROCAL of the weighted sample time, in every entry. Note this is 1/(Ts·w) and not w/Ts. Requires a nonzero weight.
- Weight – the factor w the sample time is multiplied by.
Scalar; defaults to
1, which makes the block plain sample-time arithmetic. Must be nonzero for the two dividing operations, which are reported and stop the run otherwise rather than exporting a core that divides by zero. - 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 not just scheduling: the rate the block ends up running at IS the Ts in the arithmetic above, so changing it changes the output.
Code export
All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text.
The product Ts·w – not the weight on its own – is exposed as the generated core's single tunable parameter. That is deliberate: a deployed core runs at one fixed rate, so Ts is structural there and retuning w alone would be meaningless without it. Retuning the product is exactly retuning w at the exported rate. The operation is fixed into the arithmetic at export time, since it selects which code is emitted.
Add, subtract and multiply are native Q16.16 on the three HDL targets and
fully synthesizable. The two dividing operations are
simulation-only there: division has no Q16.16 primitive, so those cores
convert at the port boundary and divide in real arithmetic –
the same choice the Divide block makes. They also carry no infinity, so a zero
divisor answers 0 rather than ±Inf.
Simulink bridge
Import and export, mapped to simulink/Math Operations/Weighted Sample Time
Math. "Operation" goes to TsampMathOp, one option for one option
(+, -, *, /,
Ts Only, 1/Ts Only), so that round trip is lossless;
"Weight" goes to weightValue as a pass-through value.
TsampMathImp is written as a fixed Online Calculations:
its alternative is a fixed-point scaling adjustment with no meaning for the
doubles ICore carries, and an imported block set to it is reported rather than
silently accepted.
The rate does NOT cross, and on this block that is worth stating twice:
Simulink's Weighted Sample Time Math defines no SampleTime parameter
at all – it takes its rate from the signal driving it – so the entry
sets hasSampleTimeParam = false and "Sampling Time (s)" stays on the
ICore side. Since the rate is part of this block's ARITHMETIC, an ICore block
carrying an explicit rate exports to a Simulink block that will inherit a
different one and compute something else. Drive both sides at the same rate.
Notes
- Algebraic, with no state: the output depends only on the current input and on the block's rate.
- State space: carried only for u * (Ts*w) and u / (Ts*w), which are the two linear operations, and only when the block has an explicit positive "Sampling Time (s)". An inherited rate is not resolved until the model is built, and model reduction reads the state space without building one – so rather than merge a D derived from a guess, the block reports why it has none. The other four operations are affine or constant, which A/B/C/D cannot carry, exactly as for Bias.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Base_Blocks/Weighted_Sample_Time_Math |
| family | Control_Systems/Base_Blocks |
| solver environment class | ICoreBlock_0_Control_Systems_1_Base_Blocks_2_Weighted_Sample_Time_Math |
| source | src/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/Base_Blocks/Weighted_Sample_Time_Math/ICoreBlock_0_Control_Systems_1_Base_Blocks_2_Weighted_Sample_Time_Math.cpp |
| header | src/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/Base_Blocks/Weighted_Sample_Time_Math/ICoreBlock_0_Control_Systems_1_Base_Blocks_2_Weighted_Sample_Time_Math.h |
| default size on canvas | 90 × 70 px |
| ports at insert | 1 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 | in | ICoreDouble | — |
| 2 | 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 |
|---|---|---|
Operation | u + Ts*w%~%u - Ts*w%~%u * (Ts*w)%~%u / (Ts*w)%~%Ts*w only… | TsampMathOp |
Weight | 1 | weightValue |
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/Math Operations/Weighted Sample Time Math |
| port-count rule | PortsParam::None |
SampleTime parameter | no — the counterpart defines none; the rate stays on the ICore side |
| always set | TsampMathImp = Online Calculations |
| ICore config | Simulink parameter | Value translation |
|---|---|---|
Operation | TsampMathOp | u + Ts*w → +, u - Ts*w → -, u * (Ts*w) → *, u / (Ts*w) → /, Ts*w only → Ts Only, 1/(Ts*w) only → 1/Ts Only |
Weight | weightValue | passes through |
Caveat (shown to the user): the rate does not cross: Simulink's Weighted Sample Time Math defines no SampleTime parameter -- it takes its rate from the driving signal -- and on this block the rate is part of the ARITHMETIC, so drive both sides at the same rate or they compute different things
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).
Weighted Sample Time Math block -- arithmetic against the block's own sample time y = u <op> (Ts*w), entry by entry, where Ts is the rate this block runs at and w is a configured weight. The six operations were MEASURED against the real Simulink block rather than read off the documentation, because two of them are easy to get subtly wrong:
"+" y = u + Ts*w "-" y = u - Ts*w "*" y = u * (Ts*w) "/" y = u / (Ts*w) "Ts Only" y = Ts*w -- the input is ignored entirely "1/Ts Only" y = 1 / (Ts*w) -- NOT w/Ts, which is the tempting reading
(Measured at Ts = 0.01, w = -2.5: "1/Ts Only" answers -40 = 1/(0.01*-2.5), not -250 = w/Ts.)
WHERE Ts COMES FROM, AND WHY THE STATE SPACE IS CONDITIONAL. Ts is getSamplingTime(), which ICoreModelBuild resolves in assignBlockSamplingTimes() -- and that runs AFTER initializePortsSignalMatrixSize(), i.e. after loadBlockConfig(). So Ts is authoritative in compute_h and in every generator (both run after a completed build) but NOT inside loadBlockConfig, which is where a state space would have to be derived. The model reduction commands read the state space off the solver environment WITHOUT building the model, so a D built from an unresolved rate would be silently wrong rather than merely absent -- a wrong matrix merged into a plant is worse than a refused merge. The block therefore carries a state space only when its own "Sampling Time (s)" config is positive, which is the one case where Ts is knowable without a build, AND the operation is one of the two linear ones.
HDL. Add, subtract and multiply are native Q16.16 and fully synthesizable. The two DIVIDING operations are simulation-only
realarithmetic with a zero guard, which is the same choice -- and the same code shape -- the Divide block makes for its own division.
Sample results#
| t | in ICoreDouble-Out-0 | out ICoreDouble-Out-0 |
|---|---|---|
| 0 | -2 | -1.9 |
| 0.4 | 0.5 | 0.6 |
| 0.8 | -2 | -1.9 |
| 1.2 | 0.5 | 0.6 |
| 1.6 | -2 | -1.9 |
| 2 | 0.5 | 0.6 |
| 2.4 | -2 | -1.9 |
| 2.8 | 0.5 | 0.6 |
| 3.2 | -2 | -1.9 |
| 3.6 | 0.5 | 0.6 |
| 4 | -2 | -1.9 |
| 4.4 | 0.5 | 0.6 |
| 4.8 | -2 | -1.9 |
| 5.2 | 0.5 | 0.6 |
Every 4th of 60 samples, from the table stimulus.
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 … 1.1 |
ramp | Ramp: slope 1 from t = 0 | 0.1 … 5.9 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | -0.9 … 1.1 |
step | Step: 0 -> 1 at t = 1 s | 0.1 … 1.1 |
Plotted: table — Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample
Category static · sample time 0.1 · 60 steps · commit ccf005c8 · produced by docsSample --out <folder> --steps 60 · data docs/generated/samples/Control_Systems__Base_Blocks__Weighted_Sample_Time_Math.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).