Main Content

Generate Efficient Code by Specifying Data Types for Block Parameters

To generate more efficient code, match the data types of block parameters (such as the Gain parameter of a Gain block) with signal data types. Alternatively, you can store parameters in smaller data types.

Eliminate Unnecessary Typecasts and Shifts by Matching Data Types

These examples show how to generate efficient code by configuring a block parameter to use the same data type as a signal that the block operates on.

Store Data Type Information in Model

Open the example model ConfigurationRapidPrototypingInterface and configure it to show the generated names of blocks.

open_system('ConfigurationRapidPrototypingInterface')
set_param('ConfigurationRapidPrototypingInterface','HideAutomaticNames','off')

On the Modeling tab, click Model Data Editor.

In the Model Data Editor, select the Parameters tab.

In the model, select the Gain block. In the Model Data Editor, the Data Type column shows that the data type of the Gain parameter of the block is set to Inherit: Same as input. With this setting, the Gain parameter of this block uses the same data type as the input signal.

In the Code Mappings editor, under Parameters, set the storage class for K1 to ExportedGlobal.

In the Model Data Editor, set Change view to Design.

In the data table, for the row that represents K1, in the Data Type column, select Auto. With this setting, the parameter object acquires its data type from the block parameters that use the object (in this case, the Gain block parameter).

Alternatively, to create and configure the object, use these commands at the command prompt:

cm = coder.mapping.api.get('ConfigurationRapidPrototypingInterface');
setModelParameter(cm,'K1','StorageClass','ExportedGlobal');
hws = get_param(bdroot, 'modelworkspace');
hws.setVariablePart('K1.DataType','Auto');

Generate code from the model.

slbuild('ConfigurationRapidPrototypingInterface')
### Starting build procedure for: ConfigurationRapidPrototypingInterface
### Successful completion of code generation for: ConfigurationRapidPrototypingInterface

Build Summary

Top model targets built:

Model                                   Action           Rebuild Reason                                    
===========================================================================================================
ConfigurationRapidPrototypingInterface  Code generated.  Code generation information file does not exist.  

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 14.557s

The generated file ConfigurationRapidPrototypingInterface.c defines the global variable K1 by using the data type real_T.

file = fullfile('ConfigurationRapidPrototypingInterface_grt_rtw','ConfigurationRapidPrototypingInterface.c');
coder.example.extractLines(file,'/* Exported block parameters */','real_T K1 = 2.0;',1,1)
/* Exported block parameters */
real_T K1 = 2.0;                       /* Variable: K1

The generated code algorithm in the model step function uses K1 directly without typecasting.

coder.example.extractLines(file,'output =',...
    '10U',1,1)
    output = K1 * look1_binlc((*input2), rtCP_Table1_bp01Data,
      rtCP_Table1_tableData, 10U);

In the Code Mappings editor, under Parameters, you can optionally set the storage class for K1 to Inherit: Inherit via internal rule (the default).

In this case, the block parameter chooses the same data type as the input signal, double. However, when you use Inherit: Inherit via internal rule, under other circumstances (for example, when you use fixed-point data types), the block parameter might choose a different data type.

Store Data Type Information in Parameter Object

When you use a Simulink.Parameter object to export or import parameter data from the generated code to your external code, for example by applying the storage class ImportedExtern, you can specify data type information in the parameter object. To match the data type of the parameter object with a signal data type, create a Simulink.NumericType or Simulink.AliasType object. You can strictly control the data type that the parameter object uses in the generated code, eliminating the risk that Simulink® chooses a different data type when you make changes to the model.

At the command prompt, create a Simulink.NumericType object that represents the data type double.

myType = Simulink.NumericType;
myType.DataTypeMode = 'Double';

Use the Model Data Editor Data Type column to set these data types to myType:

  • The parameter object. Use the Parameters tab.

  • The Inport block named In2. Use the Inports/Outports tab. Due to data type propagation, the input signal of the Gain block also uses myType.

Use the Model Data Editor Parameters tab to set the data type of the Gain block parameter to Inherit: Inherit from 'Gain'.

Use this data type object as the data type of the parameter object.

Alternatively, to configure the object and the blocks, use these commands at the command prompt:

K1.DataType = 'myType';
set_param('ConfigurationRapidPrototypingInterface/In2','OutDataTypeStr','myType')
set_param('ConfigurationRapidPrototypingInterface/Gain','ParamDataTypeStr','Inherit: Inherit from ''Gain''')

Generate code from the model.

slbuild('ConfigurationRapidPrototypingInterface')
### Starting build procedure for: ConfigurationRapidPrototypingInterface
### Successful completion of code generation for: ConfigurationRapidPrototypingInterface

Build Summary

Top model targets built:

Model                                   Action           Rebuild Reason                   
==========================================================================================
ConfigurationRapidPrototypingInterface  Code generated.  Generated code was out of date.  

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 8.9592s

The global variable K1 continues to use the data type real_T.

file = fullfile('ConfigurationRapidPrototypingInterface_grt_rtw','ConfigurationRapidPrototypingInterface.c');
coder.example.extractLines(file,'/* Exported block parameters */','real_T K1 = 2.0;',1,1)
/* Exported block parameters */
real_T K1 = 2.0;                       /* Variable: K1

Close the code generation report.

Reduce Memory Consumption by Storing Parameter Value in Small Data Type

When you use a parameter object (for example, Simulink.Parameter) to set block parameter values, you can configure the object to appear in the generated code as a tunable global variable. By default, the parameter object and the corresponding global variable typically uses the same data type as the signal or signals on which the block operates. For example, if the input signal of a Gain block uses the data type int16, the parameter object typically use the same data type. To reduce the amount of memory that this variable consumes, specify that the variable use a smaller integer data type such as int8.

Store Parameter Value in Integer Data Type

Open the model ConfigurationRapidPrototypingInterface and set the properties of the model.

open_system('ConfigurationRapidPrototypingInterface')
set_param('ConfigurationRapidPrototypingInterface','HideAutomaticNames','off')
set_param('ConfigurationRapidPrototypingInterface','ShowPortDataTypes','on')
set_param('ConfigurationRapidPrototypingInterface','SimulationCommand','Update')

Many of the signals in the model use the data type double.

On the Modeling tab, click Model Data Editor.

In the Model Data Editor, inspect the Parameters tab.

Click the Show/refresh additional information button.

Next to the Filter contents box, activate the Filter using selection button.

In the model, click the Gain block. The Model Data Editor shows one row that corresponds to the Gain parameter of the block and one row that corresponds to the MATLAB® variable K1, which sets the parameter value to 2. K1 resides in the model workspace.

In the C Code tab, select Code Interface > Default Code Mappings. In the Code Mappings editor, under Parameters, set the storage class for K1 to ExportedGlobal.

cm = coder.mapping.api.get('ConfigurationRapidPrototypingInterface');
setModelParameter(cm,'K1','StorageClass','ExportedGlobal');

In the C Code tab, select Code Interface > Default Code Mappings. In the Model Data Editor, set Change view to Design and ensure that the Data Type column for K1 is int8.

hws = get_param(bdroot, 'modelworkspace');
hws.setVariablePart('K1.DataType','int8');

For the row that represents the Gain block parameter, in the Data Type column, set the drop-down list to Inherit: Inherit from 'Gain'. With this setting, the Gain parameter of the block inherits the int8 data type from the parameter object.

set_param('ConfigurationRapidPrototypingInterface/Gain','ParamDataTypeStr',...
    'Inherit: Inherit from ''Gain''')

Generate code from the model.

slbuild('ConfigurationRapidPrototypingInterface')
### Starting build procedure for: ConfigurationRapidPrototypingInterface
### Successful completion of code generation for: ConfigurationRapidPrototypingInterface

Build Summary

Top model targets built:

Model                                   Action           Rebuild Reason                                    
===========================================================================================================
ConfigurationRapidPrototypingInterface  Code generated.  Code generation information file does not exist.  

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 33.935s

The generated file ConfigurationRapidPrototypingInterface.c defines the global variable K1 by using the data type int8_T, which corresponds to the data type int8 in Simulink®.

file = fullfile('ConfigurationRapidPrototypingInterface_grt_rtw','ConfigurationRapidPrototypingInterface.c');
coder.example.extractLines(file,'/* Exported block parameters */','int8_T K1 = 2;',1,1)
/* Exported block parameters */
int8_T K1 = 2;                         /* Variable: K1

The code algorithm in the model step function uses K1 to calculate the output of the Gain block. The algorithm casts K1 to the data type real_T (double) because the signals involved in the calculation use the data type real_T.

coder.example.extractLines(file,'output =',...
    '10U',1,1)
    output = (real_T)K1 * look1_binlc((*input2), rtCP_Table1_bp01Data,
      rtCP_Table1_tableData, 10U);

Store Fixed-Point Parameter Value in Smaller Integer Data Type

Suppose you configure the signals in your model to use fixed-point data types. You want a gain parameter to appear in the generated code as a tunable global variable. You know the range of real-world values that you expect the parameter to assume (for example, between 0 and 4). If you can meet your application requirements despite reduced precision, you can reduce memory consumption by configuring the parameter to use a different data type than the input and output signals of the block.

Open the example model FixedPointDirectForm and configure it to show the generated names of blocks.

open_system('FixedPointDirectForm')
set_param('FixedPointDirectForm','HideAutomaticNames','off')

Update the block diagram. Signals in this model use signed fixed-point data types with a word length of 16 and binary-point-only scaling.

Open the Gain5 block dialog box. The Gain parameter is set to 1.85. Suppose you want to configure this parameter.

Set Gain to myGainParam and click Apply.

Click the action button (with three vertical dots) next to the parameter value. Select Create.

In the Create New Data dialog box, set Value to Simulink.Parameter(1.85) and click Create. The Simulink.Parameter object myGainParam appears in the base workspace.

Open the Simulink Coder app. In the C Code tab, select Code Interface > Default Code Mappings. In the Code Mappings editor, under Parameters, set the storage class for myGainParam to ExportedGlobal. With this setting, myGainParam appears in the generated code as a global variable.

In the block dialog box, on the Parameter Attributes tab, set Parameter minimum to 0 and Parameter maximum to 4.

Set Parameter data type to fixdt(0,8) and click Apply.

Click the Show Data Type Assistant button. The Data Type Assistant shows that the expression fixdt(0,8) specifies an unsigned fixed-point data type with a word length of 8 and best-precision scaling. When you simulate or generate code, the block parameter chooses a fraction length (scaling) that enables the data type to represent values between the parameter minimum and maximum (0 and 4) with the best possible precision.

In the Data Type Assistant, set Scaling to Binary point. Click Calculate Best-Precision Scaling, Fixed-point details, and Refresh Details. The information under Fixed-point details shows that a fraction length of 5 can represent the parameter values with a precision of 0.03125.

Set Scaling back to Best precision and click OK. In this example, when you simulate or generate code, the block parameter chooses a fraction length of 5.

Alternatively, you can use these commands at the command prompt to create the object and configure the block:

myGainParam = Simulink.Parameter(1.85);
myGainParam.CoderInfo.StorageClass = 'ExportedGlobal';
set_param('FixedPointDirectForm/Gain5','Gain','myGainParam')
set_param('FixedPointDirectForm/Gain5','ParamMin','0','ParamMax','4')
set_param('FixedPointDirectForm/Gain5','ParamDataTypeStr','fixdt(0,8)')

Generate code from the model.

evalc('slbuild(''FixedPointDirectForm'')');

The generated file FixedPointDirectForm.c defines the global variable myGainParam by using the data type uint8_T, which corresponds to the specified word length, 8. The code initializes the variable by using an integer value that, given the fraction length of 5, represents the real-world parameter value 1.85.

file = fullfile('FixedPointDirectForm_grt_rtw','FixedPointDirectForm.c');
coder.example.extractLines(file,'/* Exported block parameters */','uint8_T myGainParam = 59U;',1,1)
/* Exported block parameters */
uint8_T myGainParam = 59U;             /* Variable: myGainParam

The code algorithm uses myGainParam to calculate the output of the Gain5 block. The algorithm uses a C shift to scale the result of the calculation.

coder.example.extractLines(file,'/* Gain: ''<Root>/Gain5'' incorporates:',...
'/* Gain: ''<Root>/Gain'' incorporates:',1,0)
  /* Gain: '<Root>/Gain5' incorporates:
   *  UnitDelay: '<Root>/Unit Delay1'
   */
  FixedPointDirectForm_B.Gain5 = (int16_T)((myGainParam * rtb_UnitDelay1) >> 5);

Related Topics