Manual Variant Source — Control Systems/Signal Routing
Control_Systems/Signal_Routing/Manual_Variant_Source · 2 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.
Manual Variant Source
Control Systems / Signal Routing
Passes one of its inputs straight through, chosen by a setting rather than by a signal: y = uk, where k is Active Choice. The choice is part of the model, so it is the same on every sample of the run and the branches that are not selected are not read at all.
Ports
- u1 … uN – the branches, at least two of them. Add or remove inputs from the block's port settings; each may be any size [m,n], and they need NOT agree with each other – only the selected branch is ever read, so the others are unconstrained. That is the difference between this block and Manual Switch, which requires its two inputs to match because either may become its output.
- Output – y, the selected branch unchanged, of that branch's size [m,n].
Parameters
- Active Choice – which branch reaches the output, counted from 1. This selects the branch rather than retuning it, so each value is a separate code path. A value below 1 or above the number of input ports is reported and stops the run rather than being wrapped or clamped silently.
- Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period. This one does not cross to Simulink: its block has no rate parameter at all (measured), so a positive value here is reported as not having crossed.
Code export
All ten targets: Python, MATLAB, Java, Rust,
C, C++, VHDL, Verilog, SystemVerilog and
PLC Structured Text. The choice is not a tunable parameter on the
exported core: it is resolved at export time, so the generated body is a plain
copy of the selected branch and no other branch appears in it. Re-export after
changing the choice. The three HDL targets are fully synthesizable – a copy
needs no arithmetic, so nothing is evaluated in real.
Simulink bridge
Import and export, mapped to
simulink/Signal Routing/Manual Variant Source. "Active Choice" to the
promoted mask parameter LabelModeActiveChoice, whose values Simulink
spells V_1, V_2, … – measured against
R2026a, where a bare 1 is a hard error rather than a coercion. The
input-port count crosses as NumChoices, which is what moves
Simulink's own ports; its accepted range is 2 to 25 (measured – a 1
and a 26 are both refused as out of range), so a block with more
branches than that is reported rather than written. A choice beyond
that is reported rather than written. The rate does not cross: the block
has no SampleTime parameter (measured – "ManualVariantSource
block (mask) does not have a parameter named 'SampleTime'"), so passing one would
abort the generated script.
Notes
- Algebraic, with no state: the output depends only on the current input.
- The unselected branches leave the run, as Simulink removes them from its compiled model: a block that feeds only an unselected input does not execute and is not exported, however far upstream; one that also feeds something else still runs for it. Changed on 2026-09-30: before that ICore solved the whole diagram and discarded the unselected result, so a branch with a side effect (a recorder, a file write, a Stop Simulation) fired here and not in Simulink.
- Not linear in the reduction sense – the block has several inputs, so it is not SISO and model reduction refuses it. It deliberately carries no state space: one naming only the selected branch would quietly discard the others.
- To choose on a SIGNAL rather than a setting, use Signal Routing / Multiport Switch; for exactly two branches with a matched-size rule, use Signal Routing / Manual Switch.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Signal_Routing/Manual_Variant_Source |
| family | Control_Systems/Signal_Routing |
| solver environment class | ICoreBlock_0_Control_Systems_1_Signal_Routing_2_Manual_Variant_Source |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Signal_Routing/Manual_Variant_Source/ICoreBlock_0_Control_Systems_1_Signal_Routing_2_Manual_Variant_Source.cpp |
| header | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Signal_Routing/Manual_Variant_Source/ICoreBlock_0_Control_Systems_1_Signal_Routing_2_Manual_Variant_Source.h |
| default size on canvas | 80 × 90 px |
| ports at insert | 2 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 | u1 |
| 2 | in | ICoreDouble | u2 |
| 3 | 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 |
|---|---|---|
Active Choice | 1 | LabelModeActiveChoice |
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/Signal Routing/Manual Variant Source |
| port-count rule | PortsParam::VariantNumChoices |
SampleTime parameter | no — the counterpart defines none; the rate stays on the ICore side |
| always set | GeneratePreprocessorConditionals = off |
| ICore config | Simulink parameter | Value translation |
|---|---|---|
Active Choice | LabelModeActiveChoice | passes through |
Caveat (shown to the user): the active choice crosses as
LabelModeActiveChoice, whose values Simulink spells V_1, V_2, ... , and the branch count asNumChoices, which Simulink accepts only in 2..25; the block has NO SampleTime parameter, so a rate set here does not cross. The unselected branches are removed on both sides: from Simulink's compiled model, and from ICore's run and export (BF3.4)
Catalog contract: src/ICoreBlocks/ICoreCoder/ICoreCommandSystem/SimulinkBridge/ICoreSimulinkBlockCatalog.h
Description vs code#
The checker has a blind spot here — it could not resolve something (a grouped port bullet, a computed config name), which is reported and never counted as a pass. A reader has to settle it:
B0Ports lists 2 entries for 3 ports (2 in, 1 out), and the 2 they cover does not reconcile — grouped, or one undocumented? a reader must say
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).
Manual Variant Source -- one of N branches, chosen by a setting rather than by a signal y = u<k>, with k = "Active Choice" and fixed for the whole run. There is no control port: the choice belongs to the model, so it is resolved at EXPORT time and the generated core carries the selected branch alone -- no comparison, no read of any other input, and in the three HDL targets no extra logic. Signal_Routing/Multiport_Switch is the block whose choice arrives on a wire; Signal_Routing/Manual_Switch is this one fixed at exactly two inputs.
⚠ THE BRANCHES MAY BE DIFFERENT SIZES, and that is deliberate rather than unchecked. Only the selected branch is read, so nothing constrains the others. MEASURED against R2026a: a Manual Variant Source with [1 2 3] on choice 1 and [7 8] on choice 2 answers [1 2 3] and [7 8] respectively -- Simulink does not require them to agree either, because the unselected branch is not in the compiled model at all. Manual Switch's equal-size rule is a switch's rule, and this is a variant.
THE UNSELECTED BRANCHES LEAVE THE RUN, as Simulink removes them (FEATURES_TO_ADD.md BF3.4, since 2026-09-30): loadBlockConfig() marks every other input inactive, and the build prunes whatever fed only those (ICoreModelBuild::pruneInactiveVariants) -- in the live run and in every export, which builds the same way. Before that the whole diagram ran and the result was discarded, so a branch with a SIDE EFFECT (a recorder, a file write, a stop) fired here and not in Simulink.
⚠ SIMULINK NUMBERS AND SPELLS THE CHOICE ITS OWN WAY, and both halves are measured, not guessed. The active choice is the PROMOTED mask parameter
LabelModeActiveChoice, and its legal values areV_1,V_2, ... -- a bare1and aChoice_1are both hard set_param errors that abort the whole generated script. The port count is theNumChoicesspinbox, whose accepted range is 2..25 -- a1and a26are both refused as "out of range".Algebraic and stateless. No state space -- see the header.
Sample results#
| t | in ICoreDouble-Out-0 | in ICoreDouble-Out-0 | out ICoreDouble-Out-0 |
|---|---|---|---|
| 0 | -2 | -2 | -2 |
| 0.4 | 0.5 | 0.5 | 0.5 |
| 0.8 | -2 | -2 | -2 |
| 1.2 | 0.5 | 0.5 | 0.5 |
| 1.6 | -2 | -2 | -2 |
| 2 | 0.5 | 0.5 | 0.5 |
| 2.4 | -2 | -2 | -2 |
| 2.8 | 0.5 | 0.5 | 0.5 |
| 3.2 | -2 | -2 | -2 |
| 3.6 | 0.5 | 0.5 | 0.5 |
| 4 | -2 | -2 | -2 |
| 4.4 | 0.5 | 0.5 | 0.5 |
| 4.8 | -2 | -2 | -2 |
| 5.2 | 0.5 | 0.5 | 0.5 |
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 |
ramp | Ramp: slope 1 from t = 0 | 0 … 5.8 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | -1 … 0.9996 |
step | Step: 0 -> 1 at t = 1 s | 0 … 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 9ea2d4774 · produced by docsSample --out <folder> --blocks Manual_Variant_Source --steps 60 · data docs/generated/samples/Control_Systems__Signal_Routing__Manual_Variant_Source.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).