Main Content

Generate Code from Variant Blocks with Startup Activation Time

This example shows you how to simulate and generate code for variant blocks with startup activation time.

Startup Variants With Discrete Blocks

This example shows you how to simulate and generate code for variant choices of startup variant blocks comprising of discrete blocks. The generated code contains all the variant choices with regular if statements.

Open the model slexVariantSourceAndSinkWithStartup.slx. The Variant Source1 has conditions X==1 and X==2 for its input ports. The block named Variant Source1 has an update diagram activation time. X is a variant control variable and is defined in the PostLoadFcn of File -> Model Properties -> Callbacks. The Sine3 block is active when X==1 is true, and the Sine4 block is active when X==2 is true.

In the block named Variant Source2 block, the first input port is active when V==1 is true. The second input port is active when V==2 is true. The Variant Source2 has a startup activation time.

The block named Variant Sink has the conditions W==1 and W==2 on its output ports. These conditions are propagated to the connected blocks. The Gain5 block is assigned the condition W==1.The second output port of the Variant Sink block has the condition W==2. This condition is propagated to the Out4 block. If you select Allow zero active variant controls on the Variant Sink block, then the Sine5 and Gain4 blocks will be assigned the variant condition W==1|W==2.

open_system('slexVariantSourceAndSinkWithStartup.slx');

You can generate code by clicking on Build ERT or Build GRT. The inline variant blocks Variant Source2 and Variant Sink use the variant condition expression with parameters V and W. These parameters have an 'ExportedGlobal' storage class specification. When you specify a condition expression to determine the active choice, each variant control variable of the expression has a storage class associated with it. By using storage classes, you can control the appearance and placement of the variant control variables in the generated code. Storage classes also prevent the optimizations such as elimination of the storage for variant control variables in the generated code. The variables used in the variant condition expressions must satisfy certain criteria to generate code with Simulink Coder or Embedded Coder. For more information on the storage class specifications with startup activation time, see Storage Classes for Different Variant Activation Times.

Since the Variant Source2 and Variant Sink blocks have startup activation time, all choices are available, and the generated code from Embedded Coder (ERT) or Simulink Coder (GRT) will have regular if conditions.

The code generated with Embedded Coder runs the selected variant.

  if(V == 2) {
      rtb_Gain5 = sin((real_T)slexVariantSourceAndSinkWith_DW.counter * 2.0 *
                   3.1415926535897931 / 10.0);
      rtb_Gain4 = sin((real_T)slexVariantSourceAndSinkWith_DW.counter_h * 2.0 *
                   3.1415926535897931 / 10.0);
      rtb_Sine6 = rtb_Gain5 + rtb_Gain4;
    } else if(V == 1) {
       /* Sin: '<Root>/Sine1' */
       rtb_Sine6 = sin((real_T)slexVariantSourceAndSinkWith_DW.counter_c * 2.0 *
                   3.1415926535897931 / 10.0);
    }
  if((V == 1) || (V == 2)) {
      slexVariantSourceAndSinkWithS_Y.Out1 = 3.0 * rtb_Sine6;
    }

You can select the active variant using custom code via the System Initiliaze block. To change the value of V and W using custom code, navigate to Model Settings > Code Generation > Custom Code. Specify #include "ReadVarControl.h" under Header file and ReadVarControl.c under Source file.

The source file ReadVarControl.c should contain some code to read the value of V or W based on the requirement and set the active variant values.

  #include "rtwtypes.h"
  extern int32_T V;
  extern int32_T W;
  void SetValueOfVarControls()
  {
    // The values of V and W can be read from a sensor or hardware
    // for simplicity it is hardcoded.
    V = 2;
    W = 2;
  }

In the model initialize function, you may find code that sets the values for desired V and W, as shown below.

  void slexVarinatSourceAndSinkWithStartup_initialize(void)
  {
    SetValueOfVarControls();
    utAssert((W == 1) + (W == 2) == 1);
    utAssert((V == 1) + (V == 2) <= 1);
  }

NOTE -

1. The model initialize functions are not guarded in the generated code.

2. The SetUpRuntimeResources, Start, and Initialize methods of blocks are called irrespective of startup variant activation. The methods are not guarded conditionally in code generation.

3. Parameters used as variant control variables in startup activation will not appear in the generated CAPI or ASAP2 interfaces.

4. The values of variant control variables should be changed only in the model_initialize function. You should not change the variant control values in the model_step function using any custom code because the generated code might not handle the state hand off between the variants. You can add a check to the generated code to avoid any changes to the variant control values in the model_step function, but this might impact the performance of the generated code.

5. The utAssert statements in the model initialize function ensure that the generated code behavior for variant blocks matches with simulation. For example, utAssert((V == 1) + (V == 2) <= 1) ensures that you cannot have more than one active variant for Variant Source2.

6. If Allow zero active variant control is not selected, the utAssert statement checks that at least one variant choice is active for such variant blocks. If Allow zero active variant control is selected, it generates code to ensure that you cannot have more than one active variant.

Startup Variants with Continuous State Blocks

This example shows you how to simulate and generate code for variant choices of startup variant blocks comprising of continuous state blocks. In the generated code, the derivatives of the all the continuous blocks are set to zero and then assigned appropriate values in regular if statements.

Consider this model containing a Variant Source block with the startup activation time. The model contains the continuous blocks Integ1 with its Initial condition set to 0 and Integ2 with its Initial condition set to 1. The Variant Source block enables you to activate or deactivate certain parts of your model including the blocks with continuous states. During simulation, the input port of the Variant Source block becomes active when V == 1 evaluates to true, and the input port of the Variant Source block becomes inactive when V == 1 evaluates to false. The states of the inactive continuous blocks are initialized to zero.

To generate the code for the variant choices of startup variant blocks comprising of continuous state blocks, set the solver type to Fixed-step and the code generation target to a non-ERT target such as grt.tlc. The derivatives of the continuous blocks are set to zero in the generated code.

void test_cont2_abs_derivatives(void)
{
 XDot_test_cont2_abs_T *_rtXdot;
 _rtXdot = ((XDot_test_cont2_abs_T *) test_cont2_abs_M->derivs);
/* Derivatives for Integrator: '<Root>/Integrator1' */
_rtXdot->Integrator1_CSTATE = 0.0;
/* Derivatives for Integrator: '<Root>/Integrator' */
_rtXdot->Integrator_CSTATE = 0.0;
/* Derivatives for Integrator: '<Root>/Integrator1' incorporates:
 *  Integrator: '<Root>/Integrator'
 */
if (test_cont2_abs_P.V == 1.0) {
  _rtXdot->Integrator1_CSTATE = test_cont2_abs_B.Integrator;
  _rtXdot->Integrator_CSTATE = test_cont2_abs_B.Gain;
}
}