Generate Code for Nonvirtual Buses
If you have Simulink® Coder™, whether you use a virtual or nonvirtual bus can make a significant difference in the efficiency, size, and readability of generated code.
A virtual bus does not appear as a structure or any other coherent unit in generated code. A separate copy of any algorithm that manipulates the bus exists for each element. In general, virtual buses do not affect the generated code.
A nonvirtual bus appears as a structure in generated code, and only one copy exists of any algorithm that uses the bus. The use of a structure in the generated code can be helpful when tracing the correspondence between the model and the code.
For example, suppose a bus passes through a Unit Delay block. For
simplicity, the bus contains only three elements: a
, b
,
and c
.
Virtual buses do not require type
definitions.
The generated model
.h
file defines one
Unit Delay block for each element of the virtual bus.
typedef struct { real_T UnitDelay_1_DSTATE; /* '<Root>/Unit Delay' */ real_T UnitDelay_2_DSTATE; /* '<Root>/Unit Delay' */ real_T UnitDelay_3_DSTATE; /* '<Root>/Unit Delay' */ } DW_model_T;
Nonvirtual buses require type definitions. Simulink.Bus
objects appear in
the generated model
_types.h
file as structures
for nonvirtual buses.
typedef struct { real_T a; real_T b; real_T c; } BusObject;
The generated model
.h
file defines one
Unit Delay block for the nonvirtual bus, using the
BusObject
structure.
typedef struct { BusObject UnitDelay_DSTATE; /* '<Root>/Unit Delay' */ } DW_model_T;
To group signals into structures in the generated code, use nonvirtual buses. See Organize Data into Structures in Generated Code (Simulink Coder).
To efficiently generate code for a model that uses buses, see Generate Efficient Code for Buses (Simulink Coder). Generating code for nonvirtual buses can result in multiple copies of some buses.
If you use a nonvirtual bus as an input to or an output from a referenced model:
You can configure the
I/O arguments step method
style of the C++ class interface for the referenced model only when using a nonvirtual bus or when using theDefault
style of the C++ class interface.You can configure function prototype control for the referenced model only when using a nonvirtual bus.
Control Data Types of Initial Condition Structure Fields
You can use a MATLAB® structure to initialize the signal elements in a bus. See Specify Initial Conditions for Bus Elements.
When you create a MATLAB structure to initialize a bus that contains elements that use numeric data
types other than double
, you need to set the values of structure fields.
The technique that you choose to set the values can influence the efficiency and readability
of the generated code.
To avoid manually matching the field data types with the data types of the signal elements, use untyped expressions to set the field values. As you develop and rapidly prototype a model, use this technique for convenience.
To generate more efficient production code and to avoid floating-point storage in the code, match the data types of the structure fields with the data types of the corresponding signal elements.
For examples and more information about tunable initial conditions in the generated code, see Control Signal and State Initialization in the Generated Code (Simulink Coder).
Inline Numeric Values of Structure Fields in the Generated Code
If you set the Default parameter behavior configuration
parameter to Inlined
, by default, the field values of the
initial condition structure appear in the generated code as inlined numbers (non-tunable).
For these structures, use untyped expressions to set the field values in Simulink. The field values do not require data types because the structure is not
tunable in the generated code.
However, if you later set Default parameter behavior to
Tunable
or apply a storage class to the structure by using a
Simulink.Parameter
object, the code can contain floating-point storage
and inefficient explicit typecasts and bit shifts. To avoid these issues, consider
matching the data types of the structure fields with the data types of the corresponding
signal elements.
Generate Tunable Structure Specified Directly in a Block Dialog Box
Suppose that you specify an initial condition structure directly in a block dialog
box, or in a Simulink.Signal
object, with an expression such as
struct('signal1',5,'signal2',7.2)
(instead of storing the structure
in a variable or Simulink.Parameter
object). In this case, to generate a
tunable structure in the code, you set Default parameter behavior to
Tunable
.
Use the table to decide how to control the data types of the fields in these initial condition structures.
Goal | Technique | |
---|---|---|
Use a nonvirtual bus. | Use untyped expressions to set the field values. | |
Use a virtual bus. | Avoid manually matching the field data types with those of the signal elements. | Use untyped expressions to set the field values. |
Generate more efficient code and avoid floating-point storage. | Match the structure field data types with the signal element types.
Store the data type information in the |
Generate Tunable Structure Stored in a Variable or Parameter Object
Suppose that you store an initial condition structure in a variable or
Simulink.Parameter
object that you create in the base workspace or a
data dictionary. For example, you use this technique to share the structure between
multiple blocks, or to generate a tunable structure when you set Default
parameter behavior to Inlined
. In this case, use
the table to decide how to control the data types of the fields in the initial condition
structure.
Goal | Technique | |
---|---|---|
Avoid manually matching the field data types with those of the signal elements. | Use untyped expressions to set the field values. In the generated
code, the structure fields use the data type | |
Generate more efficient code and avoid floating-point storage. | Match the structure field data types with the signal element types.
Store the data type information in the structure fields or use a
To use the Model Advisor to check your model for potentially expensive data type mismatches, see Check structure parameter usage with bus signals. | |
Initialize an array of buses in a referenced model by using an array of structures. Pass the array of structures to the referenced model as the value of a model argument in the Model block. | Match the structure field data types with the signal element types.
Store the data type information in the structure fields or use a
If you do not pass the structure to the referenced model as a model argument, follow the other guidelines for nonvirtual buses to decide how to control the data types. |
Use Untyped Expressions to Set Field Values
You can use untyped expressions to set the structure field values. The fields
implicitly use the data type double
. Set the field values to represent
the ideal, real-world initialization values.
You avoid manually matching the field data types with the data types of the corresponding signal elements. However, depending on the virtuality of the bus, the method that you use to apply the initial condition, and other factors, you can introduce floating-point storage and potentially inefficient typecasts in the generated code.
Suppose that you create a bus myBusSig
with these signal elements.
Each element uses a specific data type.
myBusSig signalElement1 (int32) signalElement2 (boolean) signalElement3 (single)
Create an initial condition structure initStruct
. Use untyped
expressions to specify the field values. Optionally, to enhance readability of the Boolean
field signalElement2
, use the value false
instead of
0
.
initStruct.signalElement1 = 3; initStruct.signalElement2 = false; initStruct.signalElement3 = 17.35;
If you use the function Simulink.Bus.createMATLABStruct
to create
the structure, the function stores data type information in the structure fields. After
you create the structure, you can optionally use untyped expressions to change the field
values. See Use Simulink.Bus.createMATLABStruct to Create Structure.
Store Data Type Information in Structure Fields
To store data type information in the structure fields, use typed expressions to set
the field values, or use the function Simulink.Bus.createMATLABStruct
to create the structure. Use these techniques to generate efficient code by eliminating
floating-point storage and potentially inefficient explicit typecasts.
To avoid manually applying new data types to the structure fields when you change the
data types of the corresponding signal elements, consider using a
Simulink.Bus
object to control the data types in the structure and the
bus simultaneously.
Use Typed Expressions to Set Field Values. Suppose that you create a bus myBusSig
with these elements, which
use specific data types.
signalElement1 (int32)
signalElement2 (boolean)
signalElement3 (single)
Create an initial condition structure initStruct
by using typed
expressions to set the field values. Match the data types of the fields with the data
types of the corresponding signal elements.
initStruct.signalElement1 = int32(3); initStruct.signalElement2 = false; initStruct.signalElement3 = single(17.35);
The structure fields store data type information. If you later change the data type of a signal element, manually apply the new data type to the corresponding structure field.
To match a fixed-point data type, set the field value by using a fi
(Fixed-Point Designer) object.
Change Field Value by Preserving Data Type Information. Suppose that you change the value of a field in an existing initial condition
structure. To preserve the data type information in the field you can use subscripted
assignment, with the syntax (:)
.
initStruct.signalElement3(:) = 16.93;
If you do not use subscripted assignment, you must remember to preserve the data type by using a typed expression.
initStruct.signalElement3 = single(16.93);
If you do not use either of these techniques, the field loses the data type information.
initStruct.signalElement3 = 16.93; % Field data type is now 'double'.
Use Simulink.Bus.createMATLABStruct
to Create
Structure. You can use the function Simulink.Bus.createMATLABStruct
to
create a structure whose fields all have ground values, typically 0
.
If you configure the data types of the signal elements before using the function, for
example by setting the output data types of the blocks that generate the signal
elements, each field in the output structure uses the same data type as the
corresponding signal element. The fields store the data type information as if you use
typed expressions to set the values.
You can initialize some of the signal elements with a value other than ground by
passing a partial structure to the function. When you create this partial structure,
match the data type of each field with the data type of the corresponding signal element
by using typed expressions. For more information and examples, see Simulink.Bus.createMATLABStruct
.
When you later change the value of a field in the structure, choose one of these techniques to set the new value:
Untyped expression. The field value no longer stores the data type information.
Typed expression or subscripted assignment. The field value continues to store the data type information.
Use Bus Object as Data Type of Initial Condition Structure
Whether you store data type information in the structure fields or use untyped
expressions to set the field values, you can use a Simulink.Bus
object as
the data type of the entire initial condition structure. You can then manage the field
values and data types independently.
If you use this technique, consider using untyped expressions to set the field values.
Then, you do not need to match the field data types manually when you change the data
types of the signal elements. To control the data types of the fields and the signal
elements, use the DataType
property of the elements in the
bus object.
Suppose that you use a Bus Creator block to create a bus
myBusSig
with these elements:
signalElement1 (int32)
signalElement2 (boolean)
signalElement3 (single)
Open the Type Editor.
typeeditor
Create a bus object,
myBus
, that corresponds to the bus.Create an initial condition structure
initStruct
. Used untyped expressions to set the field values. To enhance readability of the fieldsignalElement2
, use the Boolean valuefalse
instead of0
.initStruct.signalElement1 = 3; initStruct.signalElement2 = false; initStruct.signalElement3 = 17.35;
To represent the structure, create a
Simulink.Parameter
object.initStruct = Simulink.Parameter(initStruct);
Use the parameter object to specify an initial condition for the bus. For example, in a Unit Delay block dialog box, set Initial condition to
initStruct
.Use the bus object to specify the data type of the parameter object.
initStruct.DataType = 'Bus: myBus';
Use the bus object to specify the data type of the bus. For example, in the Bus Creator block dialog box, set Output data type to
Bus: myBus
.
During simulation and in the generated code, the structure fields and the signal elements use the data types that you specify in the bus object. Before simulation and code generation, the parameter object casts the structure fields to the data types that you specify in the bus object.
For basic information about bus objects, see Specify Bus Properties with Bus Objects.
Configure Data Types for Existing Structure
To remove data type information from all the fields of a structure, you can write a
custom function that replaces the field values with double
numbers. Use
the example function castStructToDbl
as a template.
function outStruct = castStructToDbl(inStruct) %outStruct = castStructToDbl(inStruct) casts the leaf fields of inStruct to %doubles and returns the resulting structure as outStruct. This function %operates on nested structures and one-dimensional arrays of structures. % %Use this function on a structure parameter that you previously created for %bus signal initialization. The resulting structure contains only doubles, %logicals, and instances of enumerated types. When you simulate, the bus %elements cast the values of the structure fields. % %To prevent loss of data, save the original structure inStruct in %a MAT-file or .m file. % %This function casts only leaf fields whose data types are floating-point, %integer, and fixed-point types. % Copy the input struct. outStruct = inStruct; % Get a list of all of the field names. Even if the structure contains % nested structures, this list includes only the names of the fields of % inStruct. fieldNamesList = fieldnames(inStruct); % If this structure is an array of structures, iterate through the % structures. for j = 1:length(inStruct) for i = 1:length(fieldNamesList) tempField = inStruct(j).(fieldNamesList{i}); % If this field is another structure, use castStructToDbl(). if isstruct(tempField) outStruct(j).(fieldNamesList{i}) = castStructToDbl(tempField); % If this field is not a structure, a Boolean, or an % enum, but is numeric, then cast it to double. elseif ~isenum(tempField) && ~islogical(tempField) && isnumeric(tempField) outStruct(j).(fieldNamesList{i}) = cast(tempField,'double'); end % if end % for end % for end % function
To convert a structure that uses doubles to one that stores data type information, you
can create a reference structure using the function Simulink.Bus.createMATLABStruct
. You can then write a custom function to
cast the field values to the data types in the reference structure. Use the example
function castStructFromDbl
as a template.
function outStruct = castStructFromDbl(inStruct,refStruct) %outStruct = castStructFromDbl(inStruct,refStruct) casts the leaf fields of %inStruct to the data types used by the corresponding fields of refStruct %and returns the resulting structure as outStruct. % %Use this function on a structure parameter, inStruct, that you previously %created for bus signal initialization. The fields of outStruct %use the ideal values specified in inStruct and the data types specified in %refStruct. % %To create refStruct, use the function Simulink.Bus.createMATLABStruct to %generate a structure from a bus signal in a model or from a bus object. %Each field in the generated structure uses the same data type as the %corresponding bus element. % %To prevent loss of data, save the original structure inStruct in %a MAT-file or .m file. % %This function casts only leaf fields of inStruct whose data types are floating-point, %integer, and fixed-point types. % Copy the input struct. outStruct = inStruct; % Get a list of all of the field names. Even if the structure contains % nested structures, this list includes only the names of the fields of % inStruct. fieldNamesList = fieldnames(inStruct); % If this structure is an array of structures, iterate through the % structures. for j = 1:length(inStruct) for i = 1:length(fieldNamesList) tempField = inStruct(j).(fieldNamesList{i}); % If this field is another structure, use castStructFromDbl(). if isstruct(tempField) tempfieldref = refStruct.(fieldNamesList{i}); outStruct(j).(fieldNamesList{i}) = castStructFromDbl(tempField,tempfieldref); % If this field is not a structure, a Boolean, or an % enum, but is numeric, then cast it to the corresponding type in % refStruct. elseif ~isenum(tempField) && ~islogical(tempField) && isnumeric(tempField) outStruct(j).(fieldNamesList{i}) = cast(tempField,'like',... refStruct.(fieldNamesList{i})); end % if end % for end % for end % function
Check for Mismatched Data Types with Model Advisor
To detect when the data types of structure fields are not consistent with associated bus elements, use the Model Advisor.
On the Modeling tab, click Model Advisor.
Click OK.
Under By Task > Modeling Signals and Parameters using Buses, select Check structure parameter usage with bus signals.
Click the Run This Check button.
Code Generation for Arrays of Buses
When you generate code for a model that includes an array of buses, a
typedef
that represents the underlying bus type appears in the
*_types.h
file.
Code generation produces an array of C structures that you can integrate with legacy C code that uses arrays of structures. As necessary, code for bus variables (arrays) is generated in the following structures:
Block IO
States
External inputs
External outputs
Here is a simplified example of some generated code for an array of buses.
For basic information about code generation for nonvirtual buses, which appear in the code as structures, see Organize Data into Structures in Generated Code (Simulink Coder).