Main Content

Preserve Variables in Generated Code

As you iteratively develop a model, you capture the values of signals and states that model execution generates. You also tune parameter values during execution to observe results on the signals and states. You can then base your design decisions upon analysis of these outputs. To access signal, state, and parameter data in a rapid prototyping environment, you can configure the generated code to store the data in addressable memory.

Depending on the system target file that you use (such as grt.tlc), by default, optimization settings can make the generated code more efficient by:

  • Eliminating unnecessary global and local storage for signals and some states.

    However, the optimizations do not eliminate storage for root-level Inport and Outport blocks, which represent the primary inputs and outputs of a system. To access this data, you do not need to take optimizations into consideration.

  • Inlining the numeric values of block parameters. The code does not store the parameters in memory, so you cannot interact with the parameters during code execution.

To generate code that instead allocates addressable memory for this data, you can disable the optimizations, or override the optimizations by specifying code generation settings for individual data items.

Access Signal, State, and Parameter Data During Execution

As you iteratively develop a model, you capture output signal and state data that model execution generates. You also tune parameter values during execution to observe results on the outputs. You can then base your design decisions upon analysis of these outputs. To access this signal, state, and parameter data in a rapid prototyping environment, you can configure the generated code to store the data in addressable memory.

By default, optimization settings make the generated code more efficient by eliminating unnecessary signal storage and inlining the numeric values of block parameters. To generate code that instead allocates addressable memory for this data, you can disable the optimizations or specify code generation settings for individual data items.

Explore Example Model

Run a script that prepares the model rtwdemo_configrpinterface for this example.

prepare_rtwdemo_configrpinterface

This data is configured for code generation:

  • Parameters UPPER, LOWER, K1, Table1, and Table2

  • Signals In1, In2, In3, In4, and Out1

  • States X (delay) and mode (data store memory write)

Open the example model, rtwdemo_configrpinterface.

rtwdemo_configrpinterface

The model loads numeric MATLAB variables into the model workspace. The workspace variables set some block parameters in the model. However, the Gain block in the model uses the literal value 2.

Disable Optimizations

1. In the model, clear the model configuration parameter Signal storage reuse. When you clear this optimization and other optimizations such as Eliminate superfluous local variables (expression folding), the generated code allocates memory for signal lines. Clearing Signal storage reuse disables most of the other optimizations.

set_param('rtwdemo_configrpinterface','OptimizeBlockIOStorage','off')

2. Set the model configuration parameter Default parameter behavior to Tunable. When set to Tunable, this configuration parameter causes the generated code to allocate memory for block parameters and workspace variables.

set_param('rtwdemo_configrpinterface','DefaultParameterBehavior','Tunable')

3. Generate code.

rtwbuild('rtwdemo_configrpinterface')
### Starting build procedure for: rtwdemo_configrpinterface
### Successful completion of code generation for: rtwdemo_configrpinterface

Build Summary

Top model targets built:

Model                      Action          Rebuild Reason                                    
=============================================================================================
rtwdemo_configrpinterface  Code generated  Code generation information file does not exist.  

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

4. In the code generation report, view the file rtwdemo_configrpinterface.h. This header file defines a structure type that contains signal data. The structure contains fields that each represent a signal line in the model. For example, the output signal of the Gain block, whose name is Gain, appears as the field Gain.

file = fullfile('rtwdemo_configrpinterface_grt_rtw','rtwdemo_configrpinterface.h');
rtwdemodbtype(file,'/* Block signals (default storage) */',...
    'B_rtwdemo_configrpinterface_T;',1,1)
/* Block signals (default storage) */
typedef struct {
  real_T Delay;                        /* '<Root>/Delay' */
  real_T Table2;                       /* '<Root>/Table2' */
  real_T Table1;                       /* '<Root>/Table1' */
  real_T Gain;                         /* '<Root>/Gain' */
  boolean_T RelOp1;                    /* '<Root>/RelOp1' */
  boolean_T RelOp2;                    /* '<Root>/RelOp2' */
  boolean_T LogOp;                     /* '<Root>/LogOp' */
  boolean_T DataStoreRead;             /* '<Root>/Data Store Read' */
} B_rtwdemo_configrpinterface_T;

The file defines a structure type that contains block parameter data. For example, the Gain parameter of the Gain block appears as the field Gain_Gain. The other fields of the structure represent other block parameters and workspace variables from the model, including initial conditions for signals and states.

rtwdemodbtype(file,'/* Parameters (default storage) */',...
    '/* Real-time Model Data Structure */',1,0)
/* Parameters (default storage) */
struct P_rtwdemo_configrpinterface_T_ {
  Table1_Type Table1;                  /* Variable: Table1
                                        * Referenced by: '<Root>/Table1'
                                        */
  Table2_Type Table2;                  /* Variable: Table2
                                        * Referenced by: '<Root>/Table2'
                                        */
  real_T LOWER;                        /* Variable: LOWER
                                        * Referenced by: '<Root>/Constant2'
                                        */
  real_T UPPER;                        /* Variable: UPPER
                                        * Referenced by: '<Root>/Constant1'
                                        */
  real_T Gain_Gain;                    /* Expression: 2
                                        * Referenced by: '<Root>/Gain'
                                        */
  real_T Delay_InitialCondition;       /* Expression: 0
                                        * Referenced by: '<Root>/Delay'
                                        */
  uint32_T Table2_maxIndex[2];         /* Computed Parameter: Table2_maxIndex
                                        * Referenced by: '<Root>/Table2'
                                        */
  boolean_T DataStoreMemory_InitialValue;
                             /* Computed Parameter: DataStoreMemory_InitialValue
                              * Referenced by: '<Root>/Data Store Memory'
                              */
};

5. View the file rtwdemo_configrpinterface_data.c. This source file allocates global memory for a parameter structure and initializes the field values based on the parameter values in the model.

6. View the source file rtwdemo_configrpinterface.c. The code allocates global memory for a structure variable that contains signal data.

file = fullfile('rtwdemo_configrpinterface_grt_rtw','rtwdemo_configrpinterface.c');
rtwdemodbtype(file,'/* Block signals (default storage) */',...
    'B_rtwdemo_configrpinterface_T rtwdemo_configrpinterface_B;',1,1)
/* Block signals (default storage) */
B_rtwdemo_configrpinterface_T rtwdemo_configrpinterface_B;

The code algorithm in the model step function calculates the signal values. It then assigns these values to the fields of the signal structure. To perform the calculations, the algorithm uses the parameter values from the fields of the parameter structure.

Exclude Data Items from Optimizations

When you want to select code generation optimizations such as Signal storage reuse, you can preserve individual data items from the optimizations. The generated code then allocates addressable memory for the items.

Select the optimizations that you previously cleared.

set_param('rtwdemo_configrpinterface','OptimizeBlockIOStorage','on')
set_param('rtwdemo_configrpinterface','LocalBlockOutputs','on')
set_param('rtwdemo_configrpinterface','DefaultParameterBehavior','Inlined')

1. In the C Code tab, select Code Interface > Individual Element Code Mappings.

2. In the Code Mappings editor, inspect the Signals/States tab.

3. In the model, select the output signal of the Gain block.

4. Pause on the ellipsis that appears above or below the signal line to open the action bar. Click the Add Signal button. In the Code Mappings editor, the Signals node expands and lists the signal that you added.

cm = coder.mapping.api.get('rtwdemo_configrpinterface');
gain_ports = get_param('rtwdemo_configrpinterface/Gain','PortHandles');
gain_outPort = gain_ports.Outport;
addSignal(cm,gain_outPort);

5. Apply the default storage class for Outports to the signal by setting Storage Class to Model default.

setSignal(cm,gain_outPort,'StorageClass','Model default','Identifier','Gain');

6. In the model, select the Gain block.

7. In the Property Inspector, set the gain value to the model workspace parameter object K1.

8. In the Code Mappings editor, on the Parameters tab, expand Model Parameters.

9. Select parameter K1. Apply a storage class other than Auto by setting Storage class. For example, use the storage class Model default. By using Model default, K1 acquires the default storage class specified for model parameters, Default, and appears as a field of the global parameters structure.

set_param('rtwdemo_configrpinterface/Gain','Gain','K1');
setModelParameter(cm,'K1','StorageClass','Model default');

10. Generate code.

rtwbuild('rtwdemo_configrpinterface')
### Starting build procedure for: rtwdemo_configrpinterface
### Successful completion of code generation for: rtwdemo_configrpinterface

Build Summary

Top model targets built:

Model                      Action          Rebuild Reason                   
============================================================================
rtwdemo_configrpinterface  Code generated  Generated code was out of date.  

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

11. In the code generation report, view the file rtwdemo_configrpinterface.h. The structure that contains signal data now defines only one field, Gain, which represents the test-pointed output of the Gain block.

file = fullfile('rtwdemo_configrpinterface_grt_rtw','rtwdemo_configrpinterface.h');
rtwdemodbtype(file,'/* Block signals (default storage) */',...
    'B_rtwdemo_configrpinterface_T;',1,1)
/* Block signals (default storage) */
typedef struct {
  real_T Gain;                         /* '<Root>/Gain' */
} B_rtwdemo_configrpinterface_T;

The structure that contains block parameter data defines one field, K1, which represents the parameter object K1.

rtwdemodbtype(file,'/* Parameters (default storage) */',...
    '/* Real-time Model Data Structure */',1,0)
/* Parameters (default storage) */
struct P_rtwdemo_configrpinterface_T_ {
  int8_T K1;                           /* Variable: K1
                                        * Referenced by: '<Root>/Gain'
                                        */
};

Access Data Through Generated Interfaces

You can configure the generated code to contain extra code and files so that you can access model data through standardized interfaces. For example, use the C API to log signal data and tune parameters during execution.

Copy this custom source code into a file named ex_myHandCode.c in your current folder.

#include "ex_myHandHdr.h"
 
#define paramIdx 0 /* Index of the target parameter, 
determined by inspecting the array of structures generated by the C API. */
#define sigIdx 0 /* Index of the target signal, 
determined by inspecting the array of structures generated by the C API. */
 
void tuneFcn(rtwCAPI_ModelMappingInfo *mmi, time_T *tPtr)
{
    /* Take action with the parameter value only at 
       the beginning of simulation and at the 5-second mark. */
    if (*tPtr == 0 || *tPtr == 5) {
        
        /* Local variables to store information extracted from 
           the model mapping information (mmi). */
        void** dataAddrMap;
        const rtwCAPI_DataTypeMap *dataTypeMap;
        const rtwCAPI_ModelParameters *params;
        int_T addrIdx;
        uint16_T dTypeIdx;
        uint8_T slDataType;
        
        /* Use built-in C API macros to extract information. */
        dataAddrMap = rtwCAPI_GetDataAddressMap(mmi);
        dataTypeMap = rtwCAPI_GetDataTypeMap(mmi);
        params = rtwCAPI_GetModelParameters(mmi);
        addrIdx = rtwCAPI_GetModelParameterAddrIdx(params,paramIdx);
        dTypeIdx =  rtwCAPI_GetModelParameterDataTypeIdx(params,paramIdx);
        slDataType = rtwCAPI_GetDataTypeSLId(dataTypeMap, dTypeIdx);
        
        /* Handle data types 'double' and 'int8'. */
        switch (slDataType) {
            
            case SS_DOUBLE: {
                real_T* dataAddress;
                dataAddress = dataAddrMap[addrIdx];
                /* At the 5-second mark, increment the parameter value by 1. */
                if (*tPtr == 5) {
                    (*dataAddress)++;
                }
                printf("Parameter value is %f\n", *dataAddress);
                break;
            }
            
            case SS_INT8: {
                int8_T* dataAddress;
                dataAddress = dataAddrMap[addrIdx];
                if (*tPtr == 5) {
                    (*dataAddress)++;
                }
                printf("Parameter value is %i\n", *dataAddress);
                break;
            }
        }
    }
}
 
void logFcn(rtwCAPI_ModelMappingInfo *mmi, time_T *tPtr)
{
    /* Take action with the signal value only when 
       the simulation time is an integer value. */
    if (*tPtr-(int_T)*tPtr == 0) {
        
        /* Local variables to store information extracted from 
           the model mapping information (mmi). */
        void** dataAddrMap;
        const rtwCAPI_DataTypeMap *dataTypeMap;
        const rtwCAPI_Signals *sigs;
        int_T addrIdx;
        uint16_T dTypeIdx;
        uint8_T slDataType;
        
        /* Use built-in C API macros to extract information. */
        dataAddrMap = rtwCAPI_GetDataAddressMap(mmi);
        dataTypeMap = rtwCAPI_GetDataTypeMap(mmi);
        sigs = rtwCAPI_GetSignals(mmi);
        addrIdx = rtwCAPI_GetSignalAddrIdx(sigs,sigIdx);
        dTypeIdx =  rtwCAPI_GetSignalDataTypeIdx(sigs,sigIdx);
        slDataType = rtwCAPI_GetDataTypeSLId(dataTypeMap, dTypeIdx);
        
        /* Handle data types 'double' and 'single'. */
        switch (slDataType) {
            
            case SS_DOUBLE: {
                real_T* dataAddress;
                dataAddress = dataAddrMap[addrIdx];
                printf("Signal value is %f\n", *dataAddress);
                break;
            }
            
            case SS_SINGLE: {
                real32_T* dataAddress;
                dataAddress = dataAddrMap[addrIdx];
                printf("Signal value is %f\n", *dataAddress);
                break;
            }
        }
    }
}

2. Copy this custom header code into a file named ex_myHandHdr.h in your current folder.

#include <stdio.h>
#include <string.h>
#include <math.h>
/* Include rtw_modelmap.h for definitions of C API macros. */
#include "rtw_modelmap.h"
#include "builtin_typeid_types.h"
#include "rtwtypes.h"
void tuneFcn(rtwCAPI_ModelMappingInfo *mmi, time_T *tPtr);
void logFcn(rtwCAPI_ModelMappingInfo *mmi, time_T *tPtr);

These files use the C API to access signal and parameter data in the code that you generate from the example model.

3. Set model configuration parameters Header file and Source files to #include "ex_myHandHdr.h" and ex_myHandCode.c, respectively.

set_param('rtwdemo_configrpinterface','CustomHeaderCode','#include "ex_myHandHdr.h"')
set_param('rtwdemo_configrpinterface','CustomSource','ex_myHandCode.c')

4. Select model configuration parameter MAT-file Logging. The generated executable runs only until the simulation stop time (which you set in the model configuration parameters).

set_param('rtwdemo_configrpinterface','MatFileLogging','on')

5. Select C API model configuration parameters parameters, signals, states, and root-level I/O.

set_param('rtwdemo_configrpinterface','RTWCAPIParams','on')
set_param('rtwdemo_configrpinterface','RTWCAPISignals','on')
set_param('rtwdemo_configrpinterface','RTWCAPIStates','on')
set_param('rtwdemo_configrpinterface','RTWCAPIRootIO','on')

6. Load the Custom Code block library.

custcode

7. Add a System Outputs block to the model.

add_block('custcode/System Outputs','rtwdemo_configrpinterface/System Outputs')

8. In the System Outputs block dialog box, set System Outputs Function Execution Code to this code:

{
rtwdemo_configrpinterface_U.input2++;
rtwCAPI_ModelMappingInfo *MMI = &(rtmGetDataMapInfo(rtwdemo_configrpinterface_M).mmi);
tuneFcn(MMI, rtmGetTPtr(rtwdemo_configrpinterface_M));
}

9. In the block dialog box, set System Outputs Function Exit Code to this code:

{
rtwCAPI_ModelMappingInfo *MMI = &(rtmGetDataMapInfo(rtwdemo_configrpinterface_M).mmi);
logFcn(MMI, rtmGetTPtr(rtwdemo_configrpinterface_M));
}

Alternatively, to configure the System Outputs block, at the command prompt, use these commands:

temp.TLCFile = 'custcode';
temp.Location = 'System Outputs Function';
temp.Middle = sprintf(['{\nrtwdemo_configrpinterface_U.input2++;'...
    '\nrtwCAPI_ModelMappingInfo *MMI = '...
    '&(rtmGetDataMapInfo(rtwdemo_configrpinterface_M).mmi);'...
    '\ntuneFcn(MMI, rtmGetTPtr(rtwdemo_configrpinterface_M));\n}']);
temp.Bottom = sprintf(['{\nrtwCAPI_ModelMappingInfo *MMI = '...
    '&(rtmGetDataMapInfo(rtwdemo_configrpinterface_M).mmi);'...
    '\nlogFcn(MMI, rtmGetTPtr(rtwdemo_configrpinterface_M));\n}']);
set_param('rtwdemo_configrpinterface/System Outputs','RTWdata',temp)

10. Generate code.

rtwbuild('rtwdemo_configrpinterface')
### Starting build procedure for: rtwdemo_configrpinterface
### Successful completion of code generation for: rtwdemo_configrpinterface

Build Summary

Top model targets built:

Model                      Action          Rebuild Reason                   
============================================================================
rtwdemo_configrpinterface  Code generated  Generated code was out of date.  

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

11. In the code generation report, view the interface file rtwdemo_configrpinterface_capi.c. This file initializes the arrays of structures that you can use to interact with data items through the C API. For example, in the array of structures rtBlockSignals, the first structure (index 0) describes the test-pointed output signal of the Gain block in the model.

file = fullfile('rtwdemo_configrpinterface_grt_rtw','rtwdemo_configrpinterface_capi.c');
rtwdemodbtype(file,'/* Block output signal information */',...
    '/* Individual block tuning',1,0)
/* Block output signal information */
static const rtwCAPI_Signals rtBlockSignals[] = {
  /* addrMapIndex, sysNum, blockPath,
   * signalName, portNumber, dataTypeIndex, dimIndex, fxpIndex, sTimeIndex
   */
  { 0, 0, TARGET_STRING("rtwdemo_configrpinterface/Gain"),
    TARGET_STRING(""), 0, 0, 0, 0, 0 },

  {
    0, 0, (NULL), (NULL), 0, 0, 0, 0, 0
  }
};

The fields of the structure, such as addrMapIndex, indicate indices into other arrays of structures, such as rtDataAddrMap, that describe the characteristics of the signal. These characteristics include the address of the signal data (a pointer to the data), the numeric data type, and the dimensions of the signal.

12. In the file rtwdemo_configrpinterface.c, view the code algorithm in the model step function. The algorithm first executes the code that you specified in the System Outputs block.

file = fullfile('rtwdemo_configrpinterface_grt_rtw','rtwdemo_configrpinterface.c');
rtwdemodbtype(file,'/* user code (Output function Body) */',...
    '/* Logic: ''<Root>/LogOp'' incorporates:',1,0)
  /* user code (Output function Body) */

  /* System '<Root>' */
  {
    rtwdemo_configrpinterface_U.input2++;
    rtwCAPI_ModelMappingInfo *MMI = &(rtmGetDataMapInfo
      (rtwdemo_configrpinterface_M).mmi);
    tuneFcn(MMI, rtmGetTPtr(rtwdemo_configrpinterface_M));
  }

  /* DataStoreWrite: '<Root>/Data Store Write' incorporates:
   *  Constant: '<Root>/Constant1'
   *  Constant: '<Root>/Constant2'
   *  Inport: '<Root>/In1'
   *  Logic: '<Root>/LogOp'
   *  RelationalOperator: '<Root>/RelOp1'
   *  RelationalOperator: '<Root>/RelOp2'
   */
  mode = ((input1 > 10.0) || (input1 < -10.0));

  /* Gain: '<Root>/Gain' incorporates:
   *  Inport: '<Root>/In2'
   *  Lookup_n-D: '<Root>/Table1'
   */
  rtwdemo_configrpinterface_B.Gain = (real_T)rtwdemo_configrpinterface_P.K1 *
    look1_binlc((*input2), rtCP_Table1_bp01Data, rtCP_Table1_tableData, 10U);

  /* Switch: '<Root>/Switch' incorporates:
   *  DataStoreRead: '<Root>/Data Store Read'
   */
  if (mode) {
    /* Outport: '<Root>/Out1' */
    output = rtwdemo_configrpinterface_B.Gain;
  } else {
    /* Outport: '<Root>/Out1' incorporates:
     *  UnitDelay: '<Root>/Delay'
     */
    output = rtwdemo_configrpinterface_DW.X;
  }

  /* End of Switch: '<Root>/Switch' */

  /* Lookup_n-D: '<Root>/Table2' incorporates:
   *  Inport: '<Root>/In3'
   *  Inport: '<Root>/In4'
   */
  rtwdemo_configrpinterface_DW.X = look2_binlc((*input3), (*input4),
    rtCP_Table2_bp01Data, rtCP_Table2_bp02Data, rtCP_Table2_tableData,
    rtCP_Table2_maxIndex, 3U);

  /* user code (Output function Trailer) */

  /* System '<Root>' */
  {
    rtwCAPI_ModelMappingInfo *MMI = &(rtmGetDataMapInfo
      (rtwdemo_configrpinterface_M).mmi);
    logFcn(MMI, rtmGetTPtr(rtwdemo_configrpinterface_M));
  }

  /* Matfile logging */
  rt_UpdateTXYLogVars(rtwdemo_configrpinterface_M->rtwLogInfo,
                      (&rtwdemo_configrpinterface_M->Timing.taskTime0));

  /* signal main to stop simulation */
  {                                    /* Sample time: [1.0s, 0.0s] */
    if ((rtmGetTFinal(rtwdemo_configrpinterface_M)!=-1) &&
        !((rtmGetTFinal(rtwdemo_configrpinterface_M)-
           rtwdemo_configrpinterface_M->Timing.taskTime0) >
          rtwdemo_configrpinterface_M->Timing.taskTime0 * (DBL_EPSILON))) {
      rtmSetErrorStatus(rtwdemo_configrpinterface_M, "Simulation finished");
    }
  }

  /* Update absolute time for base rate */
  /* The "clockTick0" counts the number of times the code of this task has
   * been executed. The absolute time is the multiplication of "clockTick0"
   * and "Timing.stepSize0". Size of "clockTick0" ensures timer will not
   * overflow during the application lifespan selected.
   * Timer of this task consists of two 32 bit unsigned integers.
   * The two integers represent the low bits Timing.clockTick0 and the high bits
   * Timing.clockTickH0. When the low bit overflows to 0, the high bits increment.
   */
  if (!(++rtwdemo_configrpinterface_M->Timing.clockTick0)) {
    ++rtwdemo_configrpinterface_M->Timing.clockTickH0;
  }

  rtwdemo_configrpinterface_M->Timing.taskTime0 =
    rtwdemo_configrpinterface_M->Timing.clockTick0 *
    rtwdemo_configrpinterface_M->Timing.stepSize0 +
    rtwdemo_configrpinterface_M->Timing.clockTickH0 *
    rtwdemo_configrpinterface_M->Timing.stepSize0 * 4294967296.0;
}

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

  /* initialize non-finites */
  rt_InitInfAndNaN(sizeof(real_T));

  /* initialize real-time model */
  (void) memset((void *)rtwdemo_configrpinterface_M, 0,
                sizeof(RT_MODEL_rtwdemo_configrpinte_T));
  rtmSetTFinal(rtwdemo_configrpinterface_M, 10.0);
  rtwdemo_configrpinterface_M->Timing.stepSize0 = 1.0;

  /* Setup for data logging */
  {
    static RTWLogInfo rt_DataLoggingInfo;
    rt_DataLoggingInfo.loggingInterval = NULL;
    rtwdemo_configrpinterface_M->rtwLogInfo = &rt_DataLoggingInfo;
  }

  /* Setup for data logging */
  {
    rtliSetLogXSignalInfo(rtwdemo_configrpinterface_M->rtwLogInfo, (NULL));
    rtliSetLogXSignalPtrs(rtwdemo_configrpinterface_M->rtwLogInfo, (NULL));
    rtliSetLogT(rtwdemo_configrpinterface_M->rtwLogInfo, "");
    rtliSetLogX(rtwdemo_configrpinterface_M->rtwLogInfo, "");
    rtliSetLogXFinal(rtwdemo_configrpinterface_M->rtwLogInfo, "");
    rtliSetLogVarNameModifier(rtwdemo_configrpinterface_M->rtwLogInfo, "rt_");
    rtliSetLogFormat(rtwdemo_configrpinterface_M->rtwLogInfo, 0);
    rtliSetLogMaxRows(rtwdemo_configrpinterface_M->rtwLogInfo, 1000);
    rtliSetLogDecimation(rtwdemo_configrpinterface_M->rtwLogInfo, 1);
    rtliSetLogY(rtwdemo_configrpinterface_M->rtwLogInfo, "");
    rtliSetLogYSignalInfo(rtwdemo_configrpinterface_M->rtwLogInfo, (NULL));
    rtliSetLogYSignalPtrs(rtwdemo_configrpinterface_M->rtwLogInfo, (NULL));
  }

  /* block I/O */
  (void) memset(((void *) &rtwdemo_configrpinterface_B), 0,
                sizeof(B_rtwdemo_configrpinterface_T));

  /* Storage classes */
  output = 0.0;

  /* states (dwork) */
  (void) memset((void *)&rtwdemo_configrpinterface_DW, 0,
                sizeof(DW_rtwdemo_configrpinterface_T));

  /* exported global states */
  mode = false;

  /* Initialize DataMapInfo substructure containing ModelMap for C API */
  rtwdemo_configrpinterface_InitializeDataMapInfo();

  /* Matfile logging */
  rt_StartDataLoggingWithStartTime(rtwdemo_configrpinterface_M->rtwLogInfo, 0.0,
    rtmGetTFinal(rtwdemo_configrpinterface_M),
    rtwdemo_configrpinterface_M->Timing.stepSize0, (&rtmGetErrorStatus
    (rtwdemo_configrpinterface_M)));

  /* Start for DataStoreMemory: '<Root>/Data Store Memory' */
  mode = false;

  /* InitializeConditions for Lookup_n-D: '<Root>/Table2' incorporates:
   *  UnitDelay: '<Root>/Delay'
   */
  rtwdemo_configrpinterface_DW.X = 0.0;
}

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

This code first perturbs the input signal input2 by incrementing the value of the signal each time the step function executes. The code then uses the built-in macro rtmGetDataMapInfo to extract model mapping information from the model data structure rtwdemo_configrpinterface_M. The pointer MMI points to the extracted mapping information, which allows the functions tuneFcn and logFcn to access the information contained in the arrays of structures that the C API file rtwdemo_configrpinterface_capi.c defines.

13. View the function tuneFcn in the file ex_myHandCode.c. This function uses the C API (through the model mapping information mmi) and a pointer to the simulation time to print the value of the parameter K1 at specific times during code execution. When the simulation time reaches 5 seconds, the function changes the parameter value in memory. By using a switch case block, the function can access the parameter data whether the data type is int8 or double.

14. View the code algorithm in the model step function again. Near the end of the function, the algorithm executes the code that you specified in the System Outputs block. This code calls the function logFcn.

rtwdemodbtype(file,'/* user code (Output function Trailer) */',...
    '/* Matfile logging */',1,0)
  /* user code (Output function Trailer) */

  /* System '<Root>' */
  {
    rtwCAPI_ModelMappingInfo *MMI = &(rtmGetDataMapInfo
      (rtwdemo_configrpinterface_M).mmi);
    logFcn(MMI, rtmGetTPtr(rtwdemo_configrpinterface_M));
  }

15. View the function logFcn in the file ex_myHandCode.c. The function uses the C API to print the value of the test-pointed signal. The function can access the signal data whether the data type is single or double.

16. At the command prompt, run the generated executable rtwdemo_configrpinterface.exe.

system('rtwdemo_configrpinterface')

The parameter and signal values appear in the Command Window output.

For more information about data interfaces, including the C API, see Data Exchange Interfaces.

Configure Data Accessibility

GoalConsiderations and More Information
Configure signals as accessible and parameters as tunable by default

Clear the model configuration parameter Signal storage reuse and set the configuration parameter Default parameter behavior to Tunable. These settings prevent the elimination of storage for signals and prevent parameter inlining. Each block parameter and signal line appears in the generated code as a field of a structure. For more information about these data structures, see How Generated Code Exchanges Data with an Environment and How Generated Code Stores Internal Signal, State, and Parameter Data.

For more information about Default parameter behavior, see Default parameter behavior. For more information about optimizations that eliminate storage for signals, see How Generated Code Stores Internal Signal, State, and Parameter Data and Minimize Computations and Storage for Intermediate Results at Block Outputs.

Preserve accessibility and tunability of a data item after you select optimizations

You can generate more efficient code by selecting optimizations such as Signal storage reuse, but the code generator eliminates storage for as many data items as possible. To exclude individual data items from the optimizations:

  • Configure signals in the Code Mappings editor. In the editor you can set the default configuration for signals, add signals of interest to the code mappings, and then set the storage class for individual signals to the default storage class or another storage class. Signals can be named by setting the Identifier storage class property.

  • Apply a storage class, such as ExportedGlobal, to states and parameters. See C Code Generation Configuration for Model Interface Elements.

Represent a data item as a separate global variable in the generated code

When you disable optimizations, signal lines, block states, and parameters appear in the generated code as fields of structures. You cannot control the names of the structures without Embedded Coder®. To instead store a data item in a separate global variable whose name, file placement, and other characteristics you can control, apply a storage class to a signal, state, or Simulink.Parameter object. See C Code Generation Configuration for Model Interface Elements.

Generate a standardized C-code interface for accessing dataYou can configure the generated code to contain extra code and files so that you can access model data through standardized interfaces. For more information, see Exchange Data Between Generated and External Code Using C API.
Tune parameters and monitor signals during external mode simulation

When you generate code and an external executable from a model, you can simulate the model in external mode to communicate with the running executable. You can tune parameters and monitor signals during the simulation. However, in this simulation mode, parameter tunability limitations that apply to code generation also apply to the simulation. For information about the code generation limitations, see Limitations for Block Parameter Tunability in Generated Code.

For information about external mode, see External Mode Simulations for Parameter Tuning and Signal Monitoring.

Tune parameters and monitor signals with Simulink® Real-Time™

If you have Simulink Real-Time, you can tune parameters and monitor signals during execution of your real-time application. Make signals accessible and parameters tunable by clearing optimizations and applying test points and storage classes. See Parameter Tuning with Simulink Real-Time Explorer (Simulink Real-Time).

Limitations

For information about limitations that apply to the tunability of parameters in the generated code, see Limitations for Block Parameter Tunability in Generated Code.

Related Topics