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
The model contains two Variant Subsystem blocks: LeftController and RightController.
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.
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
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
trueactivates each variant choice. In this example, these conditions are specified using
Use these commands to specify a variant control using a
LINEAR = Simulink.Variant; LINEAR.Condition = 'VSSMODE==0'; NONLINEAR = Simulink.Variant; NONLINEAR.Condition = 'VSSMODE==1';
VSSMODEis 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
You can define
VSSMODEas a scalar variable or as a
Simulink.Parameterobject. In addition to enabling the specification of parameter value,
Simulink.Parameterobjects 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.Parameterobjects can have one of these storage classes.
ImportedDefinewith header file specified
Your own custom storage class that defines data as a macro
You can also convert a scalar variant control variable into a
Simulink.Parameterobject. 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
#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
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
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
NONLINEAR. The code also includes the definitions of macros corresponding to those variants. The definitions depend on the value of
VSSMODE, which is supplied in an external header file
rtwdemo_importedmacros.h. The active variant is determined by using preprocessor conditionals (
#if) on the macros (
rtwdemo_preprocessor_subsys_types.hfile from the left.
This file contains the definitions of macros
#ifndef LINEAR #define LINEAR (VSSMODE == 0) #endif #ifndef NONLINEAR #define NONLINEAR (VSSMODE == 1) #endif
rtwdemo_preprocessor_subsys.cfile 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
When you are generating code for Variant Subsystem blocks, the blocks cannot have:
Function call ports
Outports with constant sample time
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.