Bus Creator — Control Systems/Signal Routing
Control_Systems/Signal_Routing/Bus_Creator · 2 input / 1 output port(s) at insert · exports to Python, MATLAB, Java, Rust, C, C++
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.
Bus Creator
Control Systems / Signal Routing
Packs several signals into one bus: a single wire carrying named elements, so a group of related signals can be routed together and taken apart again by a Bus Selector at the far end.
Ports
- Inputs – two by default, and the count is user-editable. Each one becomes one element of the bus, in port order. An input accepts any signal type except another bus, and the element takes whatever that input carries – its type and its size are copied, not chosen here.
- Output (
bus) – the bus. Its "size" is the list of elements rather than a number of rows and columns, which is why the block face shows the element count.
Parameters
- Element names – a comma-separated list, one name per input, in port order. These are what a Bus Selector picks by, so they must be unique and none may be blank. Adding an input without adding a name is an error the build reports.
- Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period.
Notes
- Routing only – no value is scaled, converted or reordered. What arrives on input n is what element n carries.
- A bus cannot contain another bus. Connecting one to an input is refused with the element's name, rather than silently flattened.
- Algebraic, with no state, and no state space: there is no A/B/C/D that describes packing differently typed signals into one.
- The element types are decided by what you connect, so changing an upstream block's output type changes the bus. Both ends are checked when the model is built: two bus wires fit together only if their elements match in order, name, type and size.
Code export
Exported to Python (a dict) and MATLAB (a struct),
keyed by the element names above – so the generated code selects an element by the same
name the Bus Selector does.
Exported to C, C++, Java and Rust as a declared record:
a struct (a static class in Java) named Bus0, Bus1, and
so on, one per distinct bus in the model, with one field per element under the element's own
name. Two buses with the same elements, in the same order, of the same types and sizes, share
one record. Each field is stored the way a signal of that type and size is stored in that
language: a matrix of doubles for a numeric element, text for a String. Because each element
name becomes a field, it must be a plain identifier (a letter or underscore, then letters,
digits or underscores) and not a reserved word of C, C++, Java or Rust; export to those four
refuses any other name and says which one. Simulink sets the same rule for bus element names.
Not exported to VHDL, Verilog, SystemVerilog or PLC Structured Text. Each refuses by name at export, with its own reason: the HDL trio needs a fixed bit width, and the Structured Text exporter emits no type declarations at all. Select the elements you need with a Bus Selector and route them separately if the model has to generate code for one of those.
Simulink bridge
Import and export, mapped to simulink/Signal Routing/Bus Creator. The
port count crosses as Inputs. "Sampling Time (s)" does not
cross. Simulink's Bus Creator is a virtual block with no SampleTime
parameter at all, so an explicit rate here is reported as staying on the ICore
side, in the export report and as a warning in the generated script.
The element names cross as the names of the input lines. Simulink has no
element-name setting: it names each element after the line into its port, and
signal1, signal2, and so on for an unnamed line. So an
export names each input line after its element, and a Bus Selector in Simulink then
finds the element by the same name. On import, a Simulink Bus Creator that a
Bus Selector reads becomes this block, its elements named after its input
lines, or signalK where a line has no name. A Bus Creator that only feeds
blocks reading it as a vector becomes a Mux, because that is what Simulink
computes there. One source line can carry only one name, so a signal feeding two bus
elements of different names keeps the first, and the export says so.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Signal_Routing/Bus_Creator |
| family | Control_Systems/Signal_Routing |
| solver environment class | ICoreBlock_0_Control_Systems_1_Signal_Routing_2_Bus_Creator |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Signal_Routing/Bus_Creator/ICoreBlock_0_Control_Systems_1_Signal_Routing_2_Bus_Creator.cpp |
| header | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Signal_Routing/Bus_Creator/ICoreBlock_0_Control_Systems_1_Signal_Routing_2_Bus_Creator.h |
| default size on canvas | 40 × 110 px |
| ports at insert | 2 in, 1 out |
| code generators implemented | Python, MATLAB, Java, Rust, C, C++ |
Ports#
| # | Direction | Signal type | Description label |
|---|---|---|---|
| 1 | in | ICoreDouble | — |
| 2 | in | ICoreDouble | — |
| 3 | out | ICoreBus | — |
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 |
|---|---|---|
Element names | a, b | not crossed |
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/Bus Creator |
| port-count rule | PortsParam::MuxCount |
SampleTime parameter | no — the counterpart defines none; the rate stays on the ICore side |
| deliberately not crossed | Element names |
Caveat (shown to the user): Simulink names a bus's elements after its input LINES (signal1..N when a line is unnamed, measured on R2026a), so the names cross as line names: the export names each input line, the import reads them
Catalog contract: src/ICoreBlocks/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).
Bus Creator -- packs its inputs into one bus signal The block that OWNS a bus spec. Names come from config; element types and sizes are inferred from whatever is connected, which is why the spec is built in the sizing loop and not in loadBlockConfig() -- an upstream type is not resolved until the loop has run.
Code export: Python and MATLAB build a record from an EXPRESSION, so a bus reaches them with nothing declared anywhere. C, C++, Java and Rust declare one record type per distinct spec (FEATURES_TO_ADD.md BF1.3), and the bodies here are plain copies into it. HDL and PLC refuse a bus by name.
Per step the shape is fixed (BF1.4): each element is written IN PLACE, and an input whose value is not its element's rows x cols stops the run by name instead of reshaping the element under its spec.
Sample results#
This block carries a ICoreBus signal, whose value is text rather than a number and is not something a plot has an axis for. The samples are in the table below, exactly as the run recorded them.
| t | in ICoreDouble-Out-0 | in ICoreDouble-Out-0 | out ICoreBus-Out-0 |
|---|---|---|---|
| 0 | -2 | -2 | {'a': -2, 'b': -2} |
| 0.04 | 0.5 | 0.5 | {'a': 0.5, 'b': 0.5} |
| 0.08 | -2 | -2 | {'a': -2, 'b': -2} |
| 0.12 | 0.5 | 0.5 | {'a': 0.5, 'b': 0.5} |
| 0.16 | -2 | -2 | {'a': -2, 'b': -2} |
| 0.2 | 0.5 | 0.5 | {'a': 0.5, 'b': 0.5} |
| 0.24 | -2 | -2 | {'a': -2, 'b': -2} |
| 0.28 | 0.5 | 0.5 | {'a': 0.5, 'b': 0.5} |
| 0.32 | -2 | -2 | {'a': -2, 'b': -2} |
| 0.36 | 0.5 | 0.5 | {'a': 0.5, 'b': 0.5} |
| 0.4 | -2 | -2 | {'a': -2, 'b': -2} |
| 0.44 | 0.5 | 0.5 | {'a': 0.5, 'b': 0.5} |
| 0.48 | -2 | -2 | {'a': -2, 'b': -2} |
| 0.52 | 0.5 | 0.5 | {'a': 0.5, 'b': 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) | — |
ramp | Ramp: slope 1 from t = 0 | — |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | — |
step | Step: 0 -> 1 at t = 1 s | — |
Plotted: table — Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample
Category static · sample time 0.01 · 60 steps · commit 31d36c2c3 · produced by docsSample --out <folder> --blocks Bus_Creator,Bus_Selector,Logical_Operator,Relational_Operator,Bitwise_Operator,Switch --steps 60 · data docs/generated/samples/Control_Systems__Signal_Routing__Bus_Creator.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).