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")
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
- Initialization Behavior Summary for Signal Objects
- Specify Initial Conditions for Bus Elements
- C Data Code Interface Configuration for Model Interface Elements
- Startup, Reset, and Shutdown Function Interfaces
- How Generated Code Stores Internal Signal, State, and Parameter Data
- Initialization of Signal, State, and Parameter Data in the Generated Code
- Remove Zero-Initialization Code (Embedded Coder)