Represent Subsystem and Variant Models in Generated Code
Required products: Simulink®, Embedded Coder®, Simulink Coder™
Using Simulink, you can create models that are based on a modular design platform that comprises a fixed common structure with a finite set of variable components. The variability helps you develop a single design with variable components. For more information, see What Are Variants and When to Use Them. When you implement variants in the generated code, you can:
Reuse generated code from a set of application models that share functionality with minor variations.
Share generated code with a third party that activates one of the variants in the code.
Validate the supported variants for a model and then choose to activate one variant for a particular application, without regenerating and re-validating the code.
Generate code for the default variant that is selected when an active variant does not exist.
Using Embedded Coder, you can generate code from Simulink models containing one or more variant choices. The generated code contains preprocessor conditionals that control the activation of each variant choice.
This example shows how to represent variant choices in a Simulink model and then prepare the model so that those variant choices are represented in generated code.
Step 1: Represent Variant Choices in Simulink
Variant choices are two or more configurations of a component in your model. This
example uses the model rtwdemo_preprocessor_subsys
to illustrate how to
represent variant choices inside Variant Subsystem blocks. For other ways to
represent variant choices, see Compare Variant Blocks.
Open the model
rtwdemo_preprocessor_subsys
.open_system('rtwdemo_preprocessor_subsys')
The model contains two Variant Subsystem blocks: LeftController and RightController.
Note
You can only add Inport, Outport, Subsystem, and Model blocks inside a Variant Subsystem block.
Open the LeftController block.
The LeftController block serves as the container for the variant choices. It contains two variant choices represented using Subsystem blocks Nonlinear and Linear. The nonlinear controller subsystems implement hysteresis, whereas the linear controller subsystems act as simple low-pass filters.
The Subsystem blocks have the same number of inports and outports as the containing Variant Subsystem block.
Variant choices can have different numbers of inports and outports. See Map Inports and Outports of Variant Choices in Variant Subsystem.
Open the Nonlinear block.
The Nonlinear block represents one variant choice that Simulink activates when a condition is satisfied. The Linear block represents another variant choice.
Tip
When you are prototyping variant choices, you can create empty Subsystem blocks with no inputs or outputs inside a Variant Subsystem block. The empty subsystem recreates the situation in which that subsystem is inactive without the need for completely modeling the variant choice.
Step 2: Specify Conditions That Control Variant Choice Selection
You can switch between variant choices by constructing conditional expressions called variant controls for each variant choice represented in a Variant Subsystem block. Variant controls determine which variant choice is active, and changing the value of a variant control causes the active variant choice to switch.
A variant control is a Boolean expression that activates a specific variant choice when
it evaluates to true
.
For more information, see Introduction to Variant Controls.
Right-click the LeftController block and select Block Parameters (Subsystem).
The Condition column displays the Boolean expression that when
true
activates each variant choice. In this example, these conditions are specified usingSimulink.Variant
objectsLINEAR
andNONLINEAR
.Use these commands to specify a variant control using a
Simulink.Variant
object.LINEAR = Simulink.Variant; LINEAR.Condition = 'VSSMODE==0'; NONLINEAR = Simulink.Variant; NONLINEAR.Condition = 'VSSMODE==1';
Here,
VSSMODE
is called a variant control variable that can be specified in one of the ways listed in Types of Variant Control Variables (Operands) in Variant Blocks.Define the variant control variable
VSSMODE
.You can define
VSSMODE
as a scalar variable or as aSimulink.Parameter
object. In addition to enabling the specification of parameter value,Simulink.Parameter
objects allow you to specify other attributes such as data type that are required for generating code.VSSMODE = Simulink.Parameter; VSSMODE.Value = 1; VSSMODE.DataType = 'int32'; VSSMODE.CoderInfo.StorageClass = 'Custom'; VSSMODE.CoderInfo.CustomStorageClass = 'ImportedDefine'; VSSMODE.CoderInfo.CustomAttributes.HeaderFile = 'rtwdemo_importedmacros.h';
Variant control variables defined as
Simulink.Parameter
objects can have one of these storage classes.Define
orImportedDefine
with header file specifiedCompilerFlag
SystemConstant (AUTOSAR)
Your own custom storage class that defines data as a macro
You can also convert a scalar variant control variable into a
Simulink.Parameter
object. See Convert Variant Control Variables into Simulink.Parameter Objects.
Step 3: Configure Model for Generating Preprocessor Conditionals
Code generated for each variant choice is enclosed within C preprocessor conditionals
#if
, #else
, #elif
, and
#endif
. Therefore, the active variant is selected at compile time and
the preprocessor conditionals determine which sections of the code to execute.
In the Modeling tab of the Simulink toolstrip, click Model Settings.
Select the Code Generation pane, and set System target file to
ert.tlc
.In the Report pane, select Create code generation report.
In the Configuration Parameters dialog box, clear Ignore custom storage classes and click Apply.
In your model, right-click the LeftController block and select Block Parameters (Subsystem).
Set the Variant activation time parameter to
code compile
.When you select this option, Simulink analyzes all variant choices during an update diagram or simulation. This analysis provides early validation of the code generation readiness of all variant choices.
Build the model.
Step 4: Review Generated Code
The code generation report contains a section dedicated to the subsystems that have variants controlled by preprocessor conditionals.
In the C Code tab of the toolstrip, select Open Report.
Select the Code Variant Report from the left.
In this example, the generated code includes references to the
Simulink.Variant
objectsLINEAR
andNONLINEAR
. The code also includes the definitions of macros corresponding to those variants. The definitions depend on the value ofVSSMODE
, which is supplied in an external header filertwdemo_importedmacros.h
. The active variant is determined by using preprocessor conditionals (#if
) on the macros (#define
)LINEAR
andNONLINEAR
.Select the
rtwdemo_preprocessor_subsys_types.h
file from the left.This file contains the definitions of macros
LINEAR
andNONLINEAR
.#ifndef LINEAR #define LINEAR (VSSMODE == 0) #endif #ifndef NONLINEAR #define NONLINEAR (VSSMODE == 1) #endif
Select the
rtwdemo_preprocessor_subsys.c
file from the left.In this file, calls to the step and initialization functions of each variant are conditionally compiled.
/* Outputs for Atomic SubSystem: '<Root>/LeftController' */ #if LINEAR /* Output and update for atomic system: '<S1>/Linear' */ ... #elif NONLINEAR /* Output and update for atomic system: '<S1>/Nonlinear' */ ... #endif
Limitations
When you are generating code for Variant Subsystem blocks, the blocks cannot have:
Mass matrices
Function call ports
Outports with constant sample time
Simscape™ blocks
The port numbers and names for each active child subsystem must belong to a subset of the port numbers and names of the parent Variant Subsystem block.