Main Content

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 Bus Signals (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 only configure the I/O arguments step method style of the C++ class interface for the referenced model when using a nonvirtual bus or when using the Default style of the C++ class interface.

  • You can only configure function prototype control for the referenced model 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.

GoalTechnique

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 struct by using typed expressions to set the field values.

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.

GoalTechnique

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 double. The generated algorithm uses explicit typecasts to reconcile the data type mismatches.

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 Simulink.Bus object to control the data types of the fields and the signal elements simultaneously.

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 Simulink.Bus object to control the data types of the structure fields and the signal elements simultaneously.

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)

  1. Open the Type Editor.

    typeeditor

  2. Create a bus object, myBus, that corresponds to the bus.

    Bus object named myBus in the Type Editor

  3. Create an initial condition structure initStruct. Used untyped expressions to set the field values. To enhance readability of the field signalElement2, use the Boolean value false instead of 0.

    initStruct.signalElement1 = 3;
    initStruct.signalElement2 = false;
    initStruct.signalElement3 = 17.35;
    

  4. To represent the structure, create a Simulink.Parameter object.

    initStruct = Simulink.Parameter(initStruct);
    

  5. 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.

  6. Use the bus object to specify the data type of the parameter object.

    initStruct.DataType = 'Bus: myBus';

  7. 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.

  1. On the Modeling tab, click Model Advisor.

  2. Click OK.

  3. Under By Task > Modeling Signals and Parameters using Buses, select Check structure parameter usage with bus signals.

  4. 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.

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).

Related Topics