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: Model Build Reason Status Build Duration ============================================================================================================================ ConfigurationRapidPrototypingInterface Information cache folder or artifacts were missing. Code generated. 0h 0m 11.963s 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 14.415s
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 usesmyType
.
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: Model Build Reason Status Build Duration ======================================================================================================== ConfigurationRapidPrototypingInterface Generated code was out of date. Code generated. 0h 0m 8.5459s 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 11.626s
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: Model Build Reason Status Build Duration ============================================================================================================================ ConfigurationRapidPrototypingInterface Information cache folder or artifacts were missing. Code generated. 0h 0m 13.708s 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 14.623s
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);