Main Content

Control Signal and State Initialization in the Generated Code

To initialize signals and discrete states with custom values for simulation and code generation, you can use signal objects and block parameters. Data initialization increases application reliability and is a requirement of safety critical applications. Initializing signals for both simulation and code generation can expedite transitions between phases of Model-Based Design.

For basic information about specifying initial values for signals and discrete states in a model, see Initialize Signals and Discrete States.

Signal and State Initialization in the Generated Code

The initialization behavior for code generation is the same as that for model simulation with the following exceptions:

  • RSim executables can use the Data Import/Export pane of the Configuration Parameters dialog box to load input values from MAT-files. GRT and ERT executables cannot load input values from MAT-files.

  • The initial value for a block output signal or root level input or output signal can be overwritten by an external (calling) program.

  • Setting the initial value for persistent signals is relevant if the value is used or viewed by an external application.

When you generate code, initialization statements are placed in model.c or model.cpp in the initialize code of the model.

For example, consider the model SignalObjectInitialValue.

openExample("SignalObjectInitialValue")

A model that uses Data Store Write and Data Store Read blocks to write to and to read from a store represented by the Data Store Memory block X2.

If you create and initialize signal objects in the base workspace, the code generator places initialization code for the signals in the file SignalObjectInitialValue.c under the SignalObjectInitialValue_initialize function, as shown below.

 /* Model initialize function */
    
     void SignalObjectInitialValue_initialize(void)

     {
        .
        .
        .
 /* exported global signals */
 S3 = -3.0;

 S2 = -2.0;
         .
         .
         .
/* exported global states */
X1 = 0.0;
X2 = 0.0;

/* external inputs */
S1 = -4.5;
         .
         .
         .

The following code shows the initialization code for the enabled subsystem's Unit Delay block state X1 and output signal S2.

void MdlStart(void) {
          .
          .
          .
 /* InitializeConditions for UnitDelay: '<S2>/Unit Delay' */
  X1 = aa1;

 /* Start for enable system: '<Root>/Enabled Subsystem (state X1 inside)' */

  /* virtual outports code */

  /* (Virtual) Outport Block: '<S2>/Out1' */

  S2 = aa2;

}

For an enabled subsystem, the initial value is also used as a reset value if the subsystem's Outport block parameter Output when disabled is set to reset. The following code from SignalObjectInitialValue.c shows the assignment statement for S3 as it appears in the model output function SignalObjectInitialValue_output.

/* Model output function */

static void SignalObjectInitialValue_output(void)
{
         .
         .
         .
 /* Disable for enable system: '<Root>/Enabled Subsystem (state X1 inside)' */

    /* (Virtual) Outport Block: '<S2>/Out1' */

    S2 = aa2;

Generate Tunable Initial Conditions

You can represent initial conditions for signals and states by creating tunable global variables in the generated code. These variables allow you to restart an application by using initial conditions that are stored in memory.

If you set Configuration Parameters > Optimization > Default parameter behavior to Tunable, initial conditions appear as tunable fields of the global parameters structure.

Whether you set Default parameter behavior to Tunable or Inlined, you can use a tunable parameter to specify the InitialValue property of a signal object or the Initial condition parameter of a block. For basic information about tunable parameters, see Create Tunable Calibration Parameter in the Generated Code.

This example shows how to use tunable parameters to specify initial conditions for signals and states.

Explore Example Model

Open the example model SignalObjectInitialValue and configure it to show the generated names of blocks. The signal S2 uses a Simulink.Signal object in the base workspace.

Double-click the Simulink.Signal object S2 to view its properties. The Initial value property is set to aa2. The object uses the variable aa2 to specify an initial condition for the signal S2. The Storage class property is set to ExportedGlobal. To use a Simulink.Signal object to initialize a signal, the signal object must use a storage class other than Auto or, if the corresponding data category in the Code Mapping Editor uses a storage class setting other than Default, Model default.

On the Optimization pane, in the Configuration Parameters dialog box, click Configure. The variable aa2 is a tunable parameter that uses the storage class ExportedGlobal.

In the model, open the Enabled Subsystem. In the Outport block dialog box, the parameter Output when disabled is set to reset. When the subsystem becomes disabled, the output signal S2 resets to the initial value aa2.

Open the Unit Delay block dialog box. On the State Attributes tab, the State name box is set to X1.

Open the Enable block dialog box. The parameter States when enabling is set to reset. When the subsystem transitions from a disabled state to an enabled state, it resets internal block states, such as X1, to their initial values.

In the base workspace, double-click the Simulink.Signal object X1 to view its properties. The Initial value property is set to aa1.

Double-click the Simulink.Parameter object aa1 to view its properties. The Storage class property is set to ExportedGlobal. You can generate tunable initial conditions for block states by using tunable parameters such as aa1 and Simulink.Signal objects such as X1.

Generate and Inspect Code

Generate code with the example model.

### Starting build procedure for: SignalObjectInitialValue
### Successful completion of build procedure for: SignalObjectInitialValue

Build Summary

Top model targets:

Model                     Build Reason                                         Status                        Build Duration
===========================================================================================================================
SignalObjectInitialValue  Information cache folder or artifacts were missing.  Code generated and compiled.  0h 0m 38.165s 

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 45.092s

In the code generation report, view the file SignalObjectInitialValue.c. The code uses global variables to represent the block state X1 and the signal S2.

/* Exported block states */
real_T X1;                             /* '<S1>/Unit Delay' */

/* Exported block signals */
real_T S1;                             /* '<Root>/In1' */
real_T S3;                             /* '<Root>/Signal Conversion' */
real_T S2;                             /* '<S1>/Unit Delay' */

The code uses global variable to represent the tunable parameter aa1.

/* Exported block parameters */
real_T aa1 = -2.5;                     /* Variable: aa1

The model initialization function uses the tunable parameter aa1 to initialize the state X1. The function also uses the tunable parameter aa2 to initialize the signal S2.

  /* SystemInitialize for Enabled SubSystem: '<Root>/Enabled Subsystem (state X1 inside)' */
  /* InitializeConditions for UnitDelay: '<S1>/Unit Delay' */
  X1 = aa1;

  /* SystemInitialize for UnitDelay: '<S1>/Unit Delay' incorporates:
   *  Outport: '<S1>/Out1'
   */
  S2 = 0.0;

In the model step function, when the Enabled Subsystem transitions from a disabled state to an enabled state, the Unit Delay block state X1 resets to its initial value.

  if (rtb_PulseGenerator > 0) {
    if (!SignalObjectInitialValue_DW.EnabledSubsystemstateX1inside_M) {
      /* InitializeConditions for UnitDelay: '<S1>/Unit Delay' */
      X1 = aa1;
      SignalObjectInitialValue_DW.EnabledSubsystemstateX1inside_M = true;
    }

    /* UnitDelay: '<S1>/Unit Delay' */
    S2 = X1;

    /* Update for UnitDelay: '<S1>/Unit Delay' incorporates:
     *  Inport: '<Root>/In1'
     */
    X1 = S1;
  } else if (SignalObjectInitialValue_DW.EnabledSubsystemstateX1inside_M) {
    /* Disable for UnitDelay: '<S1>/Unit Delay' incorporates:
     *  Outport: '<S1>/Out1'
     */
    S2 = 0.0;
    SignalObjectInitialValue_DW.EnabledSubsystemstateX1inside_M = false;
  }

  /* End of Outputs for SubSystem: '<Root>/Enabled Subsystem (state X1 inside)' */

  /* DataStoreWrite: '<Root>/Data Store Write' */
  X2 = S2;

  /* SignalConversion: '<Root>/Signal Conversion' incorporates:
   *  DataStoreRead: '<Root>/Data Store Read'
   */
  S3 = X2;
}

/* Model initialize function */
void SignalObjectInitialValue_initialize(void)
{
  /* Registration code */

  /* initialize error status */
  rtmSetErrorStatus(SignalObjectInitialValue_M, (NULL));

  /* block I/O */

  /* exported global signals */
  S3 = -3.0;

  /* states (dwork) */
  (void) memset((void *)&SignalObjectInitialValue_DW, 0,
                sizeof(DW_SignalObjectInitialValue_T));

  /* exported global states */
  X1 = 0.0;
  X2 = 0.0;

  /* external inputs */
  S1 = -4.5;

  /* Start for DiscretePulseGenerator: '<Root>/Pulse Generator' */
  SignalObjectInitialValue_DW.clockTickCounter = -2;

  /* Start for DataStoreMemory: '<Root>/Data Store Memory' */
  X2 = -3.5;

  /* SystemInitialize for Enabled SubSystem: '<Root>/Enabled Subsystem (state X1 inside)' */
  /* InitializeConditions for UnitDelay: '<S1>/Unit Delay' */
  X1 = aa1;

  /* SystemInitialize for UnitDelay: '<S1>/Unit Delay' incorporates:
   *  Outport: '<S1>/Out1'
   */
  S2 = 0.0;

  /* End of SystemInitialize for SubSystem: '<Root>/Enabled Subsystem (state X1 inside)' */
}

/* Model terminate function */
void SignalObjectInitialValue_terminate(void)
{
  /* (no terminate code required) */
}

If the Enabled Subsystem becomes disabled during code execution, the algorithm uses the tunable initial condition aa2 to set the value of the signal S2.

  } else {

  } else if (SignalObjectInitialValue_DW.EnabledSubsystemstateX1inside_M) {
    /* Disable for UnitDelay: '<S1>/Unit Delay' incorporates:
     *  Outport: '<S1>/Out1'
     */
    S2 = 0.0;
    SignalObjectInitialValue_DW.EnabledSubsystemstateX1inside_M = false;
  }

Generate Tunable Initial Condition Structure for Bus

When you use a MATLAB® structure to specify initialization values for the signal elements in a bus, you can create a tunable global structure in the generated code.

If you set Configuration Parameters > Optimization > Default parameter behavior to Tunable, the initial condition appears as a tunable substructure of the global parameters structure.

Whether you set Default parameter behavior to Tunable or Inlined, you can specify the initial condition by using a tunable Simulink.Parameter object whose value is a structure. If you apply a storage class other than Auto to the parameter object, the structure is tunable in the generated code.

To generate efficient code by avoiding data type mismatches between the structure and the bus, use either:

  • Typed expressions to specify the values of the structure fields. Match the data type of each field with the data type of the corresponding signal element.

  • A Simulink.Bus object to control the data types of the structure fields and the signal elements.

For basic information about using structures to initialize buses, and to decide how to control field data types, see Specify Initial Conditions for Bus Elements.

Generate Tunable Initial Condition Structure

This example shows how to use a tunable structure parameter to initialize a virtual bus.

Open the example model and configure it to show the generated names of blocks.

model = 'TunableInitStruct';
load_system(model)
set_param(model,'SimulationCommand','Update',...
    'HideAutomaticNames','off')
open_system(model)

On the Modeling tab, click Model Data Editor.

On the Inports/Outports tab, the Data Types column shows that each Inport block in the model uses a different output data type.

Open the Bus Creator block dialog box. The block output is a virtual bus.

In the Configuration Parameters dialog box, open the Optimization pane. The configuration parameter Default parameter behavior is set to Tunable. By default, block parameters, including initial conditions, appear in the generated code as tunable fields of the global parameters structure.

In the Model Data Editor, inspect the States tab.

For the Unit Delay block, set Initial Value to a structure that specifies an initial condition for each of the three signal elements. To generate efficient code, match the data types of the structure fields with the data types of the corresponding signal elements. For example, set Initial Value to the expression struct('thermocpl',15.23,'magFlow',uint32(79),'posSwitch',false).

set_param([model,'/Unit Delay'],'InitialCondition',...
    'struct(''thermocpl'',15.23,''magFlow'',uint32(79),''posSwitch'',false)')

Generate code from the example model.

slbuild(model)
### Starting build procedure for: TunableInitStruct
### Successful completion of build procedure for: TunableInitStruct

Build Summary

Top model targets:

Model              Build Reason                                         Status                        Build Duration
====================================================================================================================
TunableInitStruct  Information cache folder or artifacts were missing.  Code generated and compiled.  0h 0m 12.907s 

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 13.701s

In the code generation report, view the file TunableInitStruct_types.h. The code defines a structure type whose fields use the data types that you specified in the struct expression.

file = fullfile('TunableInitStruct_grt_rtw','TunableInitStruct_types.h');
coder.example.extractLines(file,'#ifndef DEFINED_TYPEDEF_FOR_struct_','}',1,1)
#ifndef DEFINED_TYPEDEF_FOR_struct_mqGi1jsItE0G7cf1bNqMu_
#define DEFINED_TYPEDEF_FOR_struct_mqGi1jsItE0G7cf1bNqMu_

typedef struct {
  real_T thermocpl;
  uint32_T magFlow;
  boolean_T posSwitch;
} struct_mqGi1jsItE0G7cf1bNqMu;

View the file TunableInitStruct.h. The struct type definition of the global parameters structure contains a substructure, UnitDelay_InitialCondition, which represents the Initial condition parameter of the Unit Delay block.

file = fullfile('TunableInitStruct_grt_rtw','TunableInitStruct.h');
coder.example.extractLines(file,'struct P_TunableInitStruct_T_ {','UnitDelay_InitialCondition;',1,1)
struct P_TunableInitStruct_T_ {
  struct_mqGi1jsItE0G7cf1bNqMu UnitDelay_InitialCondition;

View the file TunableInitStruct_data.c. This source file allocates memory for the global parameters structure. The substructure UnitDelay_InitialCondition appears.

file = fullfile('TunableInitStruct_grt_rtw','TunableInitStruct_data.c');
coder.example.extractLines(file,'/* Block parameters (default storage) */','}',1,1)
/* Block parameters (default storage) */
P_TunableInitStruct_T TunableInitStruct_P = {
  /* Mask Parameter: UnitDelay_InitialCondition
   * Referenced by:
   *   '<Root>/Unit Delay'
   *   '<Root>/Unit Delay'
   *   '<Root>/Unit Delay'
   */
  {
    15.23,
    79U,
    0
  },

View the file TunableInitStruct.c. The model initialization function uses the fields of the substructure to initialize the block states.

file = fullfile('TunableInitStruct_grt_rtw','TunableInitStruct.c');
coder.example.extractLines(file,'* InitializeConditions for UnitDelay generated from: ''<Root>/Unit Delay'' */',...
    'TunableInitStruct_P.UnitDelay_InitialCondition.posSwitch',1,1)
  /* InitializeConditions for UnitDelay generated from: '<Root>/Unit Delay' */
  TunableInitStruct_DW.UnitDelay_1_DSTATE =
    TunableInitStruct_P.UnitDelay_InitialCondition.thermocpl;

  /* InitializeConditions for UnitDelay generated from: '<Root>/Unit Delay' */
  TunableInitStruct_DW.UnitDelay_2_DSTATE =
    TunableInitStruct_P.UnitDelay_InitialCondition.magFlow;

  /* InitializeConditions for UnitDelay generated from: '<Root>/Unit Delay' */
  TunableInitStruct_DW.UnitDelay_3_DSTATE =
    TunableInitStruct_P.UnitDelay_InitialCondition.posSwitch;

Use Bus Object to Specify Data Types

If you create a bus object, you can use it to specify the data type of each element and the tunable initial condition structure. Before code generation, the Simulink.Parameter object casts the values of the structure fields to the data types of the signal elements. For basic information about creating bus objects and using them in models, see Specify Bus Properties with Bus Objects.

Open the example model and configure it to show the generated names of blocks.

model = 'InitialStructBusObject';
load_system(model)
set_param(model,'SimulationCommand','Update',...
    'HideAutomaticNames','off')
open_system(model)

In the base workspace, double-click the Simulink.Bus object ComponentData. The object defines three signal elements: thermocpl, magFlow, and posSwitch. The elements each use a different data type.

In the model, open the Model Data Editor (on the Modeling tab, click Model Data Editor). The Inports/Outports tab shows that for the Inport block DataIn, the output data type (Data Type column) is set to Bus: ComponentData.

At the command prompt, create the structure parameter initStruct. You can specify the field values by using untyped expressions. To improve readability, specify the field posSwitch with a Boolean value.

initStruct = struct(...
    'thermocpl',15.23,...
    'magFlow',79,...
    'posSwitch',false...
    );

initStruct = Simulink.Parameter(initStruct);

In the Model Data Editor, inspect the Parameters tab.

In the model, click the Unit Delay block. The Model Data Editor highlights the row that corresponds to the Initial condition parameter of the block.

In the Model Data Editor, set the parameter value (Value column) to initStruct.

set_param([model,'/Unit Delay'],'InitialCondition','initStruct')

Click the Show/refresh additional information button. The parameter object, initStruct, appears in the data table as a row.

Use the Data Type column to set the data type of initStruct to Bus: ComponentData.

initStruct.DataType = 'Bus: ComponentData';

Set the Change View drop-down list to Code.

Use the Storage Class column to apply the storage class ExportedGlobal to initStruct.

initStruct.StorageClass = 'ExportedGlobal';

Generate code from the example model.

slbuild(model)
### Starting build procedure for: InitialStructBusObject
### Successful completion of build procedure for: InitialStructBusObject

Build Summary

Top model targets:

Model                   Build Reason                                         Status                        Build Duration
=========================================================================================================================
InitialStructBusObject  Information cache folder or artifacts were missing.  Code generated and compiled.  0h 0m 8.7542s 

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 9.7096s

In the code generation report, view the file InitialStructBusObject_types.h. The code creates a structure type ComponentData whose fields use the data types in the bus object.

file = fullfile('InitialStructBusObject_grt_rtw','InitialStructBusObject_types.h');
coder.example.extractLines(file,'#ifndef DEFINED_TYPEDEF_FOR_ComponentData_','}',1,1)
#ifndef DEFINED_TYPEDEF_FOR_ComponentData_
#define DEFINED_TYPEDEF_FOR_ComponentData_

typedef struct {
  real_T thermocpl;
  uint32_T magFlow;
  boolean_T posSwitch;
} ComponentData;

View the file InitialStructBusObject.c. The code creates a global variable to represent the tunable parameter object initStruct.

file = fullfile('InitialStructBusObject_grt_rtw','InitialStructBusObject.c');
coder.example.extractLines(file,'/* Exported block parameters */','Variable: initStruct',1,1)
/* Exported block parameters */
ComponentData initStruct = {
  15.23,
  79U,
  0
} ;                                    /* Variable: initStruct

The model initialization function uses the structure fields to initialize the block states.

coder.example.extractLines(file,'/* InitializeConditions for UnitDelay generated from: ''<Root>/Unit Delay'' */',...
    '= initStruct.posSwitch;',1,1)
  /* InitializeConditions for UnitDelay generated from: '<Root>/Unit Delay' */
  InitialStructBusObject_DW.UnitDelay_1_DSTATE = initStruct.thermocpl;

  /* InitializeConditions for UnitDelay generated from: '<Root>/Unit Delay' */
  InitialStructBusObject_DW.UnitDelay_2_DSTATE = initStruct.magFlow;

  /* InitializeConditions for UnitDelay generated from: '<Root>/Unit Delay' */
  InitialStructBusObject_DW.UnitDelay_3_DSTATE = initStruct.posSwitch;

To change the data type of a signal element, specify the new type in the bus object. The signal element in the model uses the new type. Before simulation and code generation, the parameter object initStruct casts the corresponding structure field to the new type.

See Also

|

Related Topics