Generate Code for Model References Connected to Variant Blocks
This example shows how to use Model blocks with variant blocks to reuse and incrementally load, build, and generate code for multiple variations of a component.
When you generate code for a referenced model hierarchy, the code generator places the code for the top model in the code generation folder and the code for referenced models in an slprj
folder. Within the slprj
folder, the subfolders further categorize the generated code by each referenced model and by file type, such as source code, header files, and other necessary files for compilation.
If you have an Embedded Coder® license, custom targets must declare themselves as compliant with the referenced model if they support Model blocks. For more information, see Support Model Referencing.
To get started with an example on how to generate code for a referenced model, see Generate Code for Model Reference Hierarchy.
Explore the Model
Open the slexVariantMdlRefCondProp
model from the Propagate Variant Conditions to Enable or Disable Model or Subsystem References in Hierarchy example.
This model contains two Model blocks sub1
and sub2
. The sub1
block references the model slexVariantMdlRefCondProp_sub1
and serves as an input to the Variant Source1
block. The sub2
block references the model slexVariantMdlRefCondProp_sub2
. The output of sub2
is determined by the variant conditions for the Variant Sink block in the slexVariantMdlRefCondProp_sub2
model.
The variant conditions at the input and the output ports of the Variant Source and Variant Sink blocks determine the activation and deactivation of connected blocks. In this model, the Variant Source1
block has a variant condition V == 1
that propagates to the Model block sub1
during simulation. Here, V
is a scalar MATLAB™ variant control variable. You can specify V
as a different type of variant control variable based on your requirements as described in Types of Variant Control Variables (Operands) in Variant Blocks.
If sub1
is active, the blocks within sub1
are also active. If sub1
is inactive, the blocks within sub1
are also inactive, making sub1
conditional.
You can also convert a subsystem to a referenced model. For more details, see Convert Subsystems to Referenced Models.
model = "slexVariantMdlRefCondProp";
open_system(model);
Specify the value of V
as 1
. Simulate the model to observe the active and inactive variant choices.
V = 1; sim(model);
Configure Model to Generate Code with Preprocessor #if
Conditionals
By default, Simulink® supports generating code only for a specific choice of a variant block. You can customize your model to generate code for multiple choices of the block by using the Variant activation time parameter. The different choices are guarded by preprocessor conditional statements #if
by using the Variant activation time parameter. These conditional statements enable you to conditionally compile the code to selectively include or exclude code based on the variant condition that evaluates to true
. You are not required to regenerate code each time the value of the variant control variable changes. Additionally, this approach allows to analyze variant choices for potential incompatibilities, such as data type and dimension mismatches, prior to simulation and code generation. For more information, see Activate Variant During Different Stages of Simulation and Code Generation Workflow.
To generate code with preprocessor conditionals #if
and #elif
, you must have an Embedded Coder license and the model must specify an ERT-based system target file, for example, ert.tlc
. You must also set the Variant activation time parameter of the Variant Source1
and Variant Sink
blocks to code compile
.
1. In the Apps tab of the toolstrip, navigate to Embedded Coder. For detailed information on the settings to generate code, see Generate Code Using Embedded Coder.
2. In the C code tab, select Build > Generate code. The code generator generates code for the top model and a library module called a model reference target for each referenced model. The code for the top model is placed in the code generation folder and the code for referenced models is placed in an slprj
folder.
slexVariantMdlRefCondProp_ert_rtw
- The build folder containing the generated code for the top model.
slprj
>ert
>slexVariantMdlRefCondProp_sub1
andslprj
>ert
>slexVariantMdlRefCondProp_sub2
- The folders containing the generated code for the referenced models.
slexVariantMdlRefCondProp.slxc
- The Simulink cache file for the top model.
slexVariantMdlRefCondProp_sub1.slxc
andslexVariantMdlRefCondProp_sub2.slxc
- The Simulink cache files for the referenced models.
slbuild(model);
### Searching for referenced models in model 'slexVariantMdlRefCondProp'. ### Found 2 model reference targets to update. ### Starting serial model reference code generation build. ### Starting build procedure for: slexVariantMdlRefCondProp_sub1 ### Successful completion of build procedure for: slexVariantMdlRefCondProp_sub1 ### Starting build procedure for: slexVariantMdlRefCondProp_sub2 ### Successful completion of build procedure for: slexVariantMdlRefCondProp_sub2 ### Starting build procedure for: slexVariantMdlRefCondProp ### Successful completion of build procedure for: slexVariantMdlRefCondProp Build Summary Model reference code generation targets: Model Build Reason Status Build Duration ====================================================================================================================================== slexVariantMdlRefCondProp_sub1 Target (slexVariantMdlRefCondProp_sub1.c) did not exist. Code generated and compiled. 0h 0m 19.395s slexVariantMdlRefCondProp_sub2 Target (slexVariantMdlRefCondProp_sub2.c) did not exist. Code generated and compiled. 0h 0m 7.246s Top model targets: Model Build Reason Status Build Duration ============================================================================================================================ slexVariantMdlRefCondProp Information cache folder or artifacts were missing. Code generated and compiled. 0h 0m 15.101s 3 of 3 models built (0 models already up to date) Build duration: 0h 0m 50.704s
3.Open the slexVariantMdlRefCondProp.c
file. The header files and instances referring to the Model blocks are guarded in preprocessor conditionals #if
and #elif
. The preprocessor conditionals enable you to conditionally compile the code based on the variant conditions that evaluate to true
. For more information, see Compile Code Conditionally for Variations of Component Represented Using Variant Block.
cfile=fullfile(pwd, "slexVariantMdlRefCondProp_ert_rtw", "slexVariantMdlRefCondProp.c"); coder.example.extractLines(cfile, "#include ""slexVariantMdlRefCondProp.h""", "#endif", 1, 0); coder.example.extractLines(cfile, '/* Model step', '/* Model initialize', 1, 0);
#include "slexVariantMdlRefCondProp.h" #include <math.h> #include "rtwtypes.h" #include <string.h> #include "slexVariantMdlRefCondProp_sub2.h" #if V == 1 #include "slexVariantMdlRefCondProp_sub1.h" /* Model step function */ void slexVariantMdlRefCondProp_step(void) { real_T rtb_sub2_o1; real_T rtb_sub2_o2; real_T rtb_sub2_o3; /* Sin: '<Root>/Sine1' incorporates: * ModelReference: '<Root>/sub1' * Sin: '<Root>/Sine2' * Sin: '<Root>/Sine3' * Sum: '<Root>/Add' */ #if V == 1 rtb_sub2_o2 = sin(((real_T)slexVariantMdlRefCondProp_DW.counter + slexVariantMdlRefCondProp_P.Sine1_Offset) * 2.0 * 3.1415926535897931 / slexVariantMdlRefCondProp_P.Sine1_NumSamp) * slexVariantMdlRefCondProp_P.Sine1_Amp + slexVariantMdlRefCondProp_P.Sine1_Bias; slexVariantMdlRefCondProp_sub1(&rtb_sub2_o2, &slexVariantMdlRefCondProp_Y.Out1); #elif V == 2 /* Sin: '<Root>/Sine2' */ rtb_sub2_o2 = sin(((real_T)slexVariantMdlRefCondProp_DW.counter_i + slexVariantMdlRefCondProp_P.Sine2_Offset) * 2.0 * 3.1415926535897931 / slexVariantMdlRefCondProp_P.Sine2_NumSamp) * slexVariantMdlRefCondProp_P.Sine2_Amp + slexVariantMdlRefCondProp_P.Sine2_Bias; /* Sin: '<Root>/Sine3' */ rtb_sub2_o1 = sin(((real_T)slexVariantMdlRefCondProp_DW.counter_f + slexVariantMdlRefCondProp_P.Sine3_Offset) * 2.0 * 3.1415926535897931 / slexVariantMdlRefCondProp_P.Sine3_NumSamp) * slexVariantMdlRefCondProp_P.Sine3_Amp + slexVariantMdlRefCondProp_P.Sine3_Bias; /* VariantMerge generated from: '<Root>/Variant Source1' incorporates: * Sum: '<Root>/Add' */ slexVariantMdlRefCondProp_Y.Out1 = rtb_sub2_o2 + rtb_sub2_o1; #endif /* End of Sin: '<Root>/Sine1' */ /* ModelReference: '<Root>/sub2' */ slexVariantMdlRefCondProp_sub2(&rtb_sub2_o1, &rtb_sub2_o2, &rtb_sub2_o3, &(slexVariantMdlRefCondProp_DW.sub2_InstanceData.rtdw)); /* Outport: '<Root>/Out2' incorporates: * Gain: '<Root>/Gain4' */ slexVariantMdlRefCondProp_Y.Out2 = slexVariantMdlRefCondProp_P.Gain4_Gain * rtb_sub2_o1; /* Gain: '<Root>/Gain1' incorporates: * Gain: '<Root>/Gain6' * Outport: '<Root>/Out3' * Outport: '<Root>/Out4' * Sin: '<Root>/Sine1' * Sin: '<Root>/Sine2' * Sin: '<Root>/Sine3' */ #if V == 3 slexVariantMdlRefCondProp_Y.Out3 = slexVariantMdlRefCondProp_P.Gain1_Gain * rtb_sub2_o2; #elif V == 4 /* Outport: '<Root>/Out4' incorporates: * Gain: '<Root>/Gain6' */ slexVariantMdlRefCondProp_Y.Out4 = slexVariantMdlRefCondProp_P.Gain6_Gain * rtb_sub2_o3; #elif V == 1 /* Update for Sin: '<Root>/Sine1' */ slexVariantMdlRefCondProp_DW.counter++; if (slexVariantMdlRefCondProp_DW.counter == slexVariantMdlRefCondProp_P.Sine1_NumSamp) { slexVariantMdlRefCondProp_DW.counter = 0; } #elif V == 2 /* Update for Sin: '<Root>/Sine2' */ slexVariantMdlRefCondProp_DW.counter_i++; if (slexVariantMdlRefCondProp_DW.counter_i == slexVariantMdlRefCondProp_P.Sine2_NumSamp) { slexVariantMdlRefCondProp_DW.counter_i = 0; } /* Update for Sin: '<Root>/Sine3' */ slexVariantMdlRefCondProp_DW.counter_f++; if (slexVariantMdlRefCondProp_DW.counter_f == slexVariantMdlRefCondProp_P.Sine3_NumSamp) { slexVariantMdlRefCondProp_DW.counter_f = 0; } #endif /* End of Gain: '<Root>/Gain1' */ }
Configure Model to Generate Code with if
Conditions
You can customize your model to generate code for multiple variant choices guarded by if
and else if
conditional statements in the generated code. These conditions enable code execution to selectively include or exclude startup routines based on variant conditions that evaluate to true
during execution. You are not required to recompile the code each time the value of the variant control variable changes. Additionally, this approach allows you to analyze variant choices for potential incompatibilities, such as data type and dimension mismatches, prior to simulation and code generation. For more information, see Activate Variant During Different Stages of Simulation and Code Generation Workflow.
To generate code with if
conditional statements to choose between variants make sure that the Variant activation time parameter in both the Variant Source1
and Variant Sink
blocks is set to startup
.
set_param(model+"/Variant Source1","VariantActivationTime","startup"); set_param(model+"_sub2/Variant Sink","VariantActivationTime","startup");
1. In the Apps tab of the toolstrip, navigate to Simulink Coder. For detailed information on the settings to generate code, see Generate Code Using Simulink Coder.
2. In the C code tab, select Build > Generate code.
The code generator produces a standalone executable for the top model and a library module called a model reference target for each referenced model. The code for the top model is placed in the code generation folder and the code for referenced models is placed in an slprj
folder. The subfolders in slprj
are separate places for different types of files. For folder information, see Manage Build Process Folders.
slexVariantMdlRefCondProp_grt_rtw
- The build folder containing the generated code for the top model.
slprj
>grt
>slexVariantMdlRefCondProp_sub1
andslprj
>grt
>slexVariantMdlRefCondProp_sub2
- The folders containing the generated code for the referenced models.
slexVariantMdlRefCondProp.exe
- The executable created by the build process.
slexVariantMdlRefCondProp.slxc
- The Simulink cache file for the top model.
slexVariantMdlRefCondProp_sub1.slxc
andslexVariantMdlRefCondProp_sub2.slxc
- The Simulink cache files for the referenced models.
3.The header files contain the necessary declarations and definitions for all variant choices. Since the code generator cannot determine which variant will be used at compile time, these header files are not guarded. They are included in their entirety to support any variant choice that might be chosen at startup.
However, The instances referring to the Model blocks are guarded in if
conditional statements. These if
statements enable you to conditionally execute startup routines based on the variant condition that evaluates to true
. For more information, see Run Executables for Variant Blocks Without Recompiling Code for Changing Active Choices Using Startup Activation Time.
Note
When the Variant activation time for a variant block is set to update diagram
or update diagram analyze all choices
, references to Model blocks connected to inactive variant choices are not included in the generated code.