Data Type Conversion — Control Systems/Signal Attributes
Control_Systems/Signal_Attributes/Data_Type_Conversion · 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.
Data Type Conversion
Control Systems / Signal Attributes
Changes a signal's data type and nothing else: y = u, entry by entry, with the output carrying the type you choose. This is the only block that changes a type – everywhere else a link joins two ports of the same type or is refused, so a conversion is always something you put in the wire on purpose and can see on the canvas.
Ports
- Input – the signal u, of any size [m,n]. It accepts any numeric type: floating point, integer, fixed point or boolean, and an enumerated type. Text and buses are refused, because converting them is a different operation with different answers.
- Output – the same values y, of the SAME size [m,n], carrying the type set below. The block never reshapes a signal.
Parameters
- Output data type – the type the output port carries. The list is every numeric type the application knows, so it grows when the application does, then fixdt(1,16,8), an example of a fixed-point type – any fixdt(signed, word length, fraction length) is chosen by writing it so, as Simulink spells it – then Enum: Name for each enumerated type the project defines, and then Inherit: Inherit via back propagation. Defaults to a 64-bit float, which converts nothing.
- Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period.
How the conversion happens
The block passes the number through unchanged; the output port applies the type when the value is stored. An integer type truncates toward zero and then wraps to its width, so 3.7 becomes 3 and 200 into an 8-bit signed integer becomes −56. A fixed-point type fixdt(s, w, f) is a w-bit integer, signed when s is 1, times 2−f: the value is truncated toward zero onto that grid and wraps to w bits, so 0.3 into fixdt(1,8,4) becomes 0.25, −0.3 becomes −0.25 and 8.5 becomes −7.5, and fixdt(s, w, 0) is the w-bit integer. The word may be 1 to 53 bits (a double holds every such value exactly) and the fraction −64 to 64; fixdt(s, w), whose scaling Simulink leaves to best precision, and a slope and bias are refused when the model is built. A boolean stores 1 for any non-zero value and 0 otherwise. A 32-bit float keeps only what a 32-bit float can hold. A value that is not finite becomes 0 in an integer or boolean output, because neither has a representation for it, and that is reported once per port per run.
The rule is applied in exactly one place, which is what makes a simulation and the code generated from it agree on the answer rather than agree approximately.
Enumerated types
A project defines an enumerated type with defineEnum: named
members, each with a whole-number underlying value. Converting from an
enumerated signal gives each member's underlying value in the chosen type, so a
member whose value is 7 becomes 7, and 1 in a boolean output. Converting
to an enumerated type (Enum: Name) takes an integer input
or another enumerated signal, and keeps each value as the member with that
underlying value. A floating-point or boolean input is refused when the model
is built, and so is a type the project does not define. A value that no member
has stops the simulation at the step where it appears, naming the block, the
value and the type; it is never rounded or replaced by the default. Simulink
behaves the same way in each case.
Inherit via back propagation
With this choice the output takes its type from where it is consumed, as Simulink's does: when the model is built, it becomes the one numeric type every block it feeds accepts – a boolean into a Logical Operator, a 64-bit float into a Gain or when nothing narrows the choice. Through a subsystem boundary the blocks inside count. If the blocks it feeds accept no type in common, or several but not a 64-bit float, the build stops and names the output; choose its type then. Simulink refuses both cases too. A Bitwise Operator takes the one integer type its own setting chooses, so that is the type here, where Simulink refuses a floating default it cannot narrow.
Code export
Python, MATLAB, Java, Rust, C, C++ and PLC Structured Text carry every type this block offers. The generated core stores signals in its own floating-point type and applies the chosen type where the simulation applies it, so the two hold the same number.
An enumerated input or output is carried as its whole-number underlying value, as a 32-bit integer is: Python, MATLAB, Java, Rust, C, C++ and PLC Structured Text carry it, and VHDL, Verilog and SystemVerilog refuse it by name, as they refuse a 32-bit integer.
VHDL, Verilog and SystemVerilog hold every signal in a 16.16 fixed-point word, and carry what that word holds exactly: a 64-bit float, a boolean, the integers of 16 bits and below except the unsigned 16-bit one, and a fixed-point type with at most 16 fraction bits and 15 integer bits, each with the type applied where the simulation applies it. Any other setting is refused by name at export time with the reason – never exported as a number that would differ from the simulation.
Simulink bridge
Import and export, mapped to simulink/Signal Attributes/Data Type
Conversion. "Output data type" crosses as OutDataTypeStr
(back propagation as Inherit: Inherit via back propagation), and
"Sampling Time (s)" as SampleTime, as on every block. An
enumerated output type crosses as Enum: Name, and the
type itself as a Simulink.defineIntEnumType line at the top of
the exported script; an import reads that line back, or a classdef file of
the type's name beside the script. A fixed-point output type crosses as its
fixdt(s,w,f). An integer or fixed-point output type is written
with RndMeth Zero, Simulink's name for this block's
rounding toward zero (Simulink's own default is Floor, which would turn
−0.5 into −1); an imported block with any other rounding still
truncates, and the import says so. Simulink's
"Input and output to have equal" choice does not cross: this block always
converts the value, which is Simulink's "Real World Value" setting, and the
stored-integer reading has no counterpart here.
Notes
- Algebraic, with no state: the output depends only on the current input.
- Carries no state space, although y = u would be one. A model reduction that absorbed this block into a neighbouring plant would absorb the TYPE with it and silently drop the conversion, which is the one thing the block is for.
- Choosing a 64-bit float output converts nothing and is the default, so dropping the block into a diagram changes no value until you set the type.
- A 64-bit integer output is exact only to about 9 007 199 254 740 992 (253): values are carried as doubles during a run, and a double cannot hold every 64-bit integer.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Signal_Attributes/Data_Type_Conversion |
| family | Control_Systems/Signal_Attributes |
| solver environment class | ICoreBlock_0_Control_Systems_1_Signal_Attributes_2_Data_Type_Conversion |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Signal_Attributes/Data_Type_Conversion/ICoreBlock_0_Control_Systems_1_Signal_Attributes_2_Data_Type_Conversion.cpp |
| header | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Signal_Attributes/Data_Type_Conversion/ICoreBlock_0_Control_Systems_1_Signal_Attributes_2_Data_Type_Conversion.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 |
|---|---|---|
Output data type | outputTypeComboSpec() | — |
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 Attributes/Data Type Conversion |
| port-count rule | PortsParam:: |
SampleTime parameter | yes |
Caveat (shown to the user): "the output type crosses as OutDataTypeStr
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).
Data Type Conversion -- the one way to change a signal's type y = u. The block does not convert anything; its OUTPUT PORT does, because a port applies its kind to every value written into it and does it exactly once. So "converting" here is declaring the output port to be of the chosen type and passing the number through, and the generated body in all ten languages is a copy.
That is also why this block has no per-language arithmetic to reconcile -- there is none. What it does have is the first CONFIG-SELECTED OUTPUT TYPE in the library: the combo is built from the signal-type registry rather than from a literal list, so a type added to the registry is offered here on the same commit, with no edit in this file.
Sample results#
| t | in ICoreDouble-Out-0 | out ICoreDouble-Out-0 |
|---|---|---|
| 0 | -2 | -2 |
| 0.04 | 0.5 | 0.5 |
| 0.08 | -2 | -2 |
| 0.12 | 0.5 | 0.5 |
| 0.16 | -2 | -2 |
| 0.2 | 0.5 | 0.5 |
| 0.24 | -2 | -2 |
| 0.28 | 0.5 | 0.5 |
| 0.32 | -2 | -2 |
| 0.36 | 0.5 | 0.5 |
| 0.4 | -2 | -2 |
| 0.44 | 0.5 | 0.5 |
| 0.48 | -2 | -2 |
| 0.52 | 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 … 0.59 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | 0 … 0.9246 |
step | Step: 0 -> 1 at t = 1 s | 0 … 0 |
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 1bdd228c3 · produced by docsSample --out <folder> --blocks Data_Type_Conversion --steps 60 · data docs/generated/samples/Control_Systems__Signal_Attributes__Data_Type_Conversion.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).