Represent Variant Conditions of Enumerated Type in Generated Code
You can generate code from a Simulink® model using variant control variables with values of Simulink-supported enumeration types. Enumerated types improve code readability because the condition values in control expressions are represented as meaningful names instead of integers. For more information on enumeration types, see Use Enumerated Data in Simulink Models. In this section, you will learn:
How to generate C code from a model with variant conditions using enumerated types.
How the enumerated values in variant conditions are represented in the generated code.
Use Enumerated Type Derived From Built-In Integer Type
This section explains how to generate C code from a Simulink model with variant condition values of enumerated type derived from the built-in integer type int32
.
Open the slexVariantSubsystems
model.
model = "slexVariantSubsystems";
open_system(model)
In this model, the Controller
block specifies two potential variants, the Linear controller
and Nonlinear controller
subsystems. The control expression for the Linear controller
subsystem is V == ControllerChoice.Linear
. The control expression for the Nonlinear controller
subsystem is V == ControllerChoice.NonLinear
.
blockPath = "slexVariantSubsystems/Controller"; lCtrlPath = model+"/Controller/Linear Controller"; nlCtrlPath = model+"/Controller/Nonlinear Controller"; set_param(lCtrlPath,"VariantControl","V == ControllerChoice.Linear"); set_param(nlCtrlPath,"VariantControl","V == ControllerChoice.Nonlinear");
Here, ControllerChoice
is an integer-based enumeration class derived from the built-in data type, int32
. The class is defined in the ControllerChoice.m
file. The class has two enumeration values, Linear
and Nonlinear
. These enumerated values have underlying integer values 0
and 1
.
type ControllerChoice.m
classdef ControllerChoice < int32 enumeration Linear (0), Nonlinear (1), end %All the methods below can be optionally used to configure %the enumeration in the generated code methods (Static = true) %% Description of the enumeration function retVal = getDescription() retVal = 'Controller...'; end %% Default value of the enumeration function retVal = getDefaultValue() retVal = ControllerChoice.Linear; end %% Specify whether the generated code imports/exports the definition %% of the enum used in the variant control expression function retVal = getDataScope() retVal = 'Exported'; end %% Get the header file to import from/export to the definition of the %% enumeration in the generated code function retVal = getHeaderFile() retVal = 'Controller.h'; end end end
Switch Between Variant Choices and Generate Code
1. Click Simulation > Run and see the variant conditions propagate to the blocks. By default, the model use the Linear controller
subsystem for simulations.
V = ControllerChoice.Linear; sim(model);
2. To modify the active choice, set the value of V
to ControllerChoice.Nonlinear
, then simulate the model again. The model use the Nonlinear controller
subsystem during simulation.
V = ControllerChoice.Nonlinear; sim(model);
3. To generate code that chooses between variants using if
and else if
conditional statements, specify the Variant activation time of the Controller
block to startup
.
set_param(blockPath,"VariantActivationTime","startup");
4. Specify the system target configuration file as grt.tlc
.
set_param(model, "SystemTargetFile","grt.tlc");
5. In the Apps tab of the toolstrip, navigate to Simulink Coder. For detailed information on settings to generate code, see Generate Code Using Simulink Coder.
6. In the C code tab, select Build > Generate code. Alternatively, enter this command in the Command Window.
slbuild(model);
### Starting build procedure for: slexVariantSubsystems ### Successful completion of build procedure for: slexVariantSubsystems Build Summary Top model targets: Model Build Reason Status Build Duration ======================================================================================================================== slexVariantSubsystems Information cache folder or artifacts were missing. Code generated and compiled. 0h 0m 17.217s 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 20.899s
7. In the C Code tab, select Open Report.
8. In the slexVariantSubsystems.c
file, the variable slex_V_VariantControlExpression
stores the value of the variant control variable V
. Its value is set to Nonlinear
, which means that the Nonlinear Controller
variant choice is the default active variant choice when you execute the code.
cfile=fullfile(pwd, "slexVariantSubsystems_grt_rtw", "slexVariantSubsystems.c"); coder.example.extractLines(cfile, "/* Normal MATLAB Variables with Startup variant activation time */", "/* Block states (default storage) */", 1, 0);
/* Normal MATLAB Variables with Startup variant activation time */ ControllerChoice slex_V_VariantControlExpression = Nonlinear;
9. The code also includes the variant choices Linear
and NonLinear
guarded by if
and else if
conditional statements. These conditional statements enable you to conditionally execute startup routines based on the variant condition that evaluates to true
. For more information, Run Executables for Variant Blocks Without Recompiling Code for Changing Active Choices Using Startup Activation Time.
coder.example.extractLines(cfile, "/* Outputs for Atomic SubSystem: '<Root>/Controller' */", "/* End of Outputs for SubSystem: '<S1>/Nonlinear Controller' */", 1, 1);
/* Outputs for Atomic SubSystem: '<Root>/Controller' */ if (slex_V_VariantControlExpression == Linear) { /* Outputs for Atomic SubSystem: '<S1>/Linear Controller' */ /* Update for DiscreteTransferFcn: '<S2>/Discrete Transfer Fcn' */ denAccum = (sine2 - 0.09 * slexVariantSubsystems_DW.DiscreteTransferFcn_states[0]) - 0.5 * slexVariantSubsystems_DW.DiscreteTransferFcn_states[1]; /* Sum: '<S2>/Add' incorporates: * DiscreteTransferFcn: '<S2>/Discrete Transfer Fcn' */ rtb_VariantMergeForOutportOut1 = ((0.7 * slexVariantSubsystems_DW.DiscreteTransferFcn_states[1] + slexVariantSubsystems_DW.DiscreteTransferFcn_states[0]) + rtb_sine1) + rtb_sine3; /* Update for DiscreteTransferFcn: '<S2>/Discrete Transfer Fcn' */ slexVariantSubsystems_DW.DiscreteTransferFcn_states[1] = slexVariantSubsystems_DW.DiscreteTransferFcn_states[0]; slexVariantSubsystems_DW.DiscreteTransferFcn_states[0] = denAccum; /* End of Outputs for SubSystem: '<S1>/Linear Controller' */ /* End of Outputs for SubSystem: '<Root>/Controller' */ } else if (slex_V_VariantControlExpression == Nonlinear) { /* Outputs for Atomic SubSystem: '<S1>/Nonlinear Controller' */ /* Sum: '<S3>/Add' incorporates: * Lookup_n-D: '<S3>/1-D Lookup Table' * Sin: '<Root>/sine2' */ rtb_VariantMergeForOutportOut1 = (rtb_sine1 + look1_binlxpw(sine2, slexVariantSubsystems_ConstP.uDLookupTable_bp01Data, slexVariantSubsystems_ConstP.uDLookupTable_tableData, 10U)) + rtb_sine3;
10. To view the definitions of Linear
and Nonlinear
choices, open the Controller.h
file. The choices are defined using #define
macros.
cfile=fullfile(pwd, "slexVariantSubsystems_grt_rtw", "Controller.h"); coder.example.extractLines(cfile, "#ifndef Controller_h_", "/* Controller_h_ */", 1, 1);
#ifndef Controller_h_ #define Controller_h_ #include "rtwtypes.h" typedef int32_T ControllerChoice; /* enum ControllerChoice */ #define Linear (0) /* Default value */ #define Nonlinear (1) #endif /* Controller_h_ */
If you are using Embedded Coder® with an ERT-based system target file, for example, ert.tlc
, and you want to generate a code that encloses the Linear
and Nonlinear
variant choices in preprocessor conditionals #if
and #elif
, specify the Variant activation time parameter of the Controller
block to code compile
. These conditions enable you to conditionally compile variant choices as described in Compile Code Conditionally for Variations of Component Represented Using Variant Block.
Use In-Memory Enumerated Type Derived From Simulink.defineIntEnumType
This section explains how to generate code from a model having variant control variables of enumerated type derived from Simulink.defineIntEnumType
.
1. Open the slexVariantSubsystems
model.
open_system(model)
2. Define an in-memory enumeration class Controller
using the
function. The class has two enumeration values, Simulink.defineIntEnumType
LinearChoice
and NonlinearChoice
. These enumerated values have underlying integer values 0
and 1
.
Simulink.defineIntEnumType('Controller',... {'LinearChoice','NonlinearChoice'}, [0;1],'Description','Controller',... 'DefaultValue','LinearChoice','HeaderFile','Controller.h','DataScope',... 'Exported');
Specify the control expression for the Linear controller
subsystem as V == Controller.LinearChoice
and the control expression for the Nonlinear controller
subsystem as V == Controller.NonLinearChoice
.
set_param(lCtrlPath,"VariantControl","V == Controller.LinearChoice"); set_param(nlCtrlPath,"VariantControl","V == Controller.NonlinearChoice");
2. Set the value of V
to Controller.NonlinearChoice
.
V = Controller.NonlinearChoice;
3. In the C code tab, select Build > Generate code. Alternatively, enter this command in the Command Window.
slbuild(model);
### Starting build procedure for: slexVariantSubsystems ### Successful completion of build procedure for: slexVariantSubsystems Build Summary Top model targets: Model Build Reason Status Build Duration ==================================================================================================== slexVariantSubsystems Generated code was out of date. Code generated and compiled. 0h 0m 8.3629s 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 9.3208s
The variable slex_V_VariantControlExpression
stores the value of the variant control variable V
, as the above example also shows.
cfile=fullfile(pwd, "slexVariantSubsystems_grt_rtw", "slexVariantSubsystems.c"); coder.example.extractLines(cfile, "/* Normal MATLAB Variables with Startup variant activation time */", "/* Block states (default storage) */", 1, 0);
/* Normal MATLAB Variables with Startup variant activation time */ Controller slex_V_VariantControlExpression = NonlinearChoice;
The LinearChoice
and NonlinearChoice
choices are defined as enumeration in the Controller.h
file.
cfile=fullfile(pwd, "slexVariantSubsystems_grt_rtw", "Controller.h"); coder.example.extractLines(cfile, "#ifndef Controller_h_", "/* Controller_h_ */", 1, 1);
#ifndef Controller_h_ #define Controller_h_ #include "rtwtypes.h" typedef enum { LinearChoice = 0, /* Default value */ NonlinearChoice } Controller;
Note
For variant blocks with the startup
activation time, only enumerations that are defined using these techniques are supported:
Using the function
Simulink.defineIntEnumType
.
By subclassing built-in integer data types
int8
,int16
,int32
,uint8
, oruint16
, or by subclassingSimulink.IntEnumType
. These enumerations are also supported when permanently stored in a Simulink data dictionary. See Enumerations in Data Dictionary.
See Also
Types of Variant Control Variables (Operands) in Variant Blocks