Main Content

Create and Update S-Function Run-Time Parameters

About Run-Time Parameters

You can create internal representations of external S-function dialog box parameters called run-time parameters. Every run-time parameter corresponds to one or more dialog box parameters and can have the same value and data type as its corresponding external parameters or a different value or data type. If a run-time parameter differs in value or data type from its external counterpart, the dialog parameter is said to have been transformed to create the run-time parameter. The value of a run-time parameter that corresponds to multiple dialog parameters is typically a function of the values of the dialog parameters. The Simulink® engine allocates and frees storage for run-time parameters and provides functions for updating and accessing them, thus eliminating the need for S-functions to perform these tasks. Run-time parameters facilitate the following kinds of S-function operations:

  • Computed parameters

    Often the output of a block is a function of the values of several dialog parameters. For example, suppose a block has two parameters, the volume and density of some object, and the output of the block is a function of the input signal and the mass of the object. In this case, the mass can be viewed as a third internal parameter computed from the two external parameters, volume and density. An S-function can create a run-time parameter corresponding to the computed weight, thereby eliminating the need to provide special case handling for weight in the output computation. See Creating Run-Time Parameters from Multiple S-Function Parameters for more information.

  • Data type conversions

    Often a block needs to change the data type of a dialog parameter to facilitate internal processing. For example, suppose that the output of the block is a function of the input and a dialog parameter and the input and dialog parameter are of different data types. In this case, the S-function can create a run-time parameter that has the same value as the dialog parameter but has the data type of the input signal, and use the run-time parameter in the computation of the output.

  • Code generation

    During code generation, the Simulink Coder™ product writes all run-time parameters automatically to the model.rtw file, eliminating the need for the S-function to perform this task via an mdlRTW method.

The sfcndemo_runtime Simulink model contains four example S-functions that create run-time parameters.

Creating Run-Time Parameters

In a C S-function, you can create run-time parameters in a number of ways. The following sections describe different methods for creating run-time parameters in a C S-function.

Creating Run-Time Parameters All at Once

Use the SimStruct function ssRegAllTunableParamsAsRunTimeParams in mdlSetWorkWidths to create run-time parameters corresponding to all tunable parameters. This function requires that you pass it an array of names, one for each run-time parameter. The Simulink Coder product uses these names as the names of the parameters during code generation. The S-function sfun_runtime1.c shows how to create run-time parameters all at once.

This approach to creating run-time parameters assumes that there is a one-to-one correspondence between an S-function run-time parameters and its tunable dialog parameters. This might not be the case. For example, an S-function might want to use a computed parameter whose value is a function of several dialog parameters. In such cases, the S-function might need to create the run-time parameters individually.

Creating Run-Time Parameters Individually

To create run-time parameters individually, the S-function mdlSetWorkWidths method should

  1. Specify the number of run-time parameters it intends to use, using ssSetNumRunTimeParams.

  2. Use ssRegDlgParamAsRunTimeParam to register a run-time parameter that corresponds to a single dialog parameter, even if there is a data type transformation, or ssSetRunTimeParamInfo to set the attributes of a run-time parameter that corresponds to more than one dialog parameter.

The following example uses ssRegDlgParamAsRunTimeParam and is taken from the S-function sfun_runtime3.c. This example creates a run-time parameter directly from the dialog parameter and with the same data type as the first input port's signal.

static void mdlSetWorkWidths(SimStruct *S)
{
    /* Get data type of input to use for run-time parameter */
    DTypeId      dtId         = ssGetInputPortDataType(S, 0);

    /* Define name of run-time parameter */
    const char_T *rtParamName = "Gain";

    ssSetNumRunTimeParams(S, 1); /* One run-time parameter */
    if (ssGetErrorStatus(S) != NULL) return;
    ssRegDlgParamAsRunTimeParam(S, GAIN_IDX, 0, rtParamName, dtId);
}
#endif /* MDL_SET_WORK_WIDTHS */

The next example uses ssSetRunTimeParamInfo and is taken from the S-function sfun_runtime2.c.

static void mdlSetWorkWidths(SimStruct *S)
{
    ssParamRec p; /* Initialize an ssParamRec structure */
    int        dlgP = GAIN_IDX; /* Index of S-function parameter */

    /* Configure run-time parameter information */
    p.name             = "Gain";
    p.nDimensions      = 2;
    p.dimensions       = (int_T *) mxGetDimensions(GAIN_PARAM(S));
    p.dataTypeId       = SS_DOUBLE;
    p.complexSignal    = COMPLEX_NO;
    p.data             = (void *)mxGetPr(GAIN_PARAM(S));
    p.dataAttributes   = NULL;
    p.nDlgParamIndices = 1;
    p.dlgParamIndices  = &dlgP;
    p.transformed      = false;
    p.outputAsMatrix   = false;   
    
    /* Set number of run-time parameters */
    if (!ssSetNumRunTimeParams(S, 1)) return;

    /* Set run-time parameter information */
    if (!ssSetRunTimeParamInfo(S, 0, &p)) return;
}

The S-function sfun_runtime2.c defines the parameters GAIN_IDX and GAIN_PARAM as follows, prior to using these parameters in mdlSetWorkWidths.

#define GAIN_IDX  1
#define GAIN_PARAM(S) ssGetSFcnParam(S,GAIN_IDX)

Creating Run-Time Parameters from Multiple S-Function Parameters

Use the ssSetRunTimeParamInfo function in mdlSetWorkWidths to create run-time parameters as a function of multiple S-function parameters. For example, consider an S-function with two S-function parameters, density and volume. The S-function inputs a force (F) and outputs an acceleration (a). The mdlOutputs method calculates the force using the equation F=m*a, where the mass (m) is the product of the density and volume.

The S-function sfun_runtime4.c implements this example using a single run-time parameter to store the mass. The S-function begins by defining the run-time parameter data type, as well as variables associated with volume and density.

#define RUN_TIME_DATA_TYPE SS_DOUBLE
#if RUN_TIME_DATA_TYPE == SS_DOUBLE
typedef real_T RunTimeDataType;
#endif

#define VOL_IDX  0
#define VOL_PARAM(S) ssGetSFcnParam(S,VOL_IDX)

#define DEN_IDX   1
#define DEN_PARAM(S) ssGetSFcnParam(S,DEN_IDX)

The mdlSetWorkWidths method then initializes the run-time parameter, as follows.

static void mdlSetWorkWidths(SimStruct *S)
{
    ssParamRec p; /* Initialize an ssParamRec structure */
    int               dlg[2]; /* Stores dialog indices */
    real_T vol      = *mxGetPr(VOL_PARAM(S));
    real_T den      = *mxGetPr(DEN_PARAM(S));
    RunTimeDataType   *mass;
    
    /* Initialize dimensions for the run-time parameter as a
     * local variable. The Simulink engine makes a copy of this
     * information to store in the run-time parameter. */
    int_T  massDims[2] = {1,1};
    
    /* Allocate memory for the run-time parameter data. The S-function
     * owns this memory location. The Simulink engine does not copy the data.*/
    if ((mass=(RunTimeDataType*)malloc(1)) == NULL) {
        ssSetErrorStatus(S,"Memory allocation error");
        return;
    }

    /* Store the pointer to the memory location in the S-function 
     * userdata. Since the S-function owns this data, it needs to
     * free the memory during mdlTerminate */
    ssSetUserData(S, (void*)mass);
    
    /* Call a local function to initialize the run-time 
     * parameter data. The Simulink engine checks that the data is not
     * empty so an initial value must be stored. */
    calcMass(mass, vol, den);

    /* Specify mass as a function of two S-function dialog parameters */
    dlg[0] = VOL_IDX;
    dlg[1] = DEN_IDX;
    
    /* Configure run-time parameter information. */
    p.name             = "Mass";
    p.nDimensions      = 2;
    p.dimensions       = massDims;
    p.dataTypeId       = RUN_TIME_DATA_TYPE;
    p.complexSignal    = COMPLEX_NO;
    p.data             = mass;
    p.dataAttributes   = NULL;
    p.nDlgParamIndices = 2;
    p.dlgParamIndices  = &dlg
    p.transformed      = RTPARAM_TRANSFORMED;
    p.outputAsMatrix   = false;
    
    /* Set number of run-time parameters  */
    if (!ssSetNumRunTimeParams(S, 1)) return;

    /* Set run-time parameter information */
    if (!ssSetRunTimeParamInfo(S,0,&p)) return;
            
}

The local function calcMass updates the run-time parameter value in mdlSetWorkWidths and in mdlProcessParameters, when the values of density or volume are tuned.

/* Function: calcMass ==============================================
 * Abstract:
 *      Local function to calculate the mass as a function of volume
 *      and density.
 */
static void calcMass(RunTimeDataType *mass, real_T vol, real_T den)
{
  *mass = vol * den;
}

The mdlOutputs method uses the stored mass to calculate the force.

/* Function: mdlOutputs ==========================================
 * Abstract:
 *
 *   Output acceleration calculated as input force divided by mass.   
 */
static void mdlOutputs(SimStruct *S, int_T tid)
{
    real_T *y1              = ssGetOutputPortRealSignal(S,0);
    InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
    RunTimeDataType *mass   = 
        (RunTimeDataType *)((ssGetRunTimeParamInfo(S,0))->data);
  
     /*
     * Output acceleration = force / mass
     */
     y1[0] = (*uPtrs[0]) / *mass;
}

Lastly, the mdlTerminate method frees the memory allocated for the run-time parameter in mdlSetWorkWidths.

/* Function: mdlTerminate ==========================================
 * Abstract:
 *      Free the user data.
 */
static void mdlTerminate(SimStruct *S)
{
    /* Free memory used to store the run-time parameter data*/
   RunTimeDataType *mass = ssGetUserData(S);
    if (mass != NULL) {
        free(mass);
    } 
}

To run the example, open the Simulink model:

Updating Run-Time Parameters

Whenever you change the values of S-function dialog parameters during simulation, the Simulink engine invokes the S-function mdlCheckParameters method to validate the changes. If the changes are valid, the engine invokes the S-function mdlProcessParameters method at the beginning of the next time step. This method should update the S-function run-time parameters to reflect the changes in the dialog parameters.

In a C S-function, update the run-time parameters using the method appropriate for how the run-time parameters were created, as described in the following sections.

Updating All Parameters at Once

In a C MEX S-function, if there is a one-to-one correspondence between the S-function tunable dialog parameters and the run-time parameters, i.e., the run-time parameters were registered using ssRegAllTunableParamsAsRunTimeParams, the S-function can use the SimStruct function ssUpdateAllTunableParamsAsRunTimeParams to accomplish this task. This function updates each run-time parameter to have the same value as the corresponding dialog parameter. See sfun_runtime1.c for an example.

Updating Parameters Individually

If there is not a one-to-one correspondence between the S-function dialog and run-time parameters or the run-time parameters are transformed versions of the dialog parameters, the mdlProcessParameters method must update each parameter individually. Choose the method used to update the run-time parameter based on how it was registered.

If you register a run-time parameter using ssSetRunTimeParamInfo, the mdlProcessParameters method uses ssUpdateRunTimeParamData to update the run-time parameter, as shown in sfun_runtime2.c. This function updates the data field in the parameter's attributes record, ssParamRec, with a new value. You cannot directly modify the ssParamRec, even though you can obtain a pointer to the ssParamRec using ssGetRunTimeParamInfo.

If you register a run-time parameter using ssRegDlgParamAsRunTimeParam, the mdlProcessParameters method uses ssUpdateDlgParamAsRunTimeParam to update the run-time parameter, as is shown in sfun_runtime3.c.

Updating Parameters as Functions of Multiple S-Function Parameters

If you register a run-time parameter as a function of multiple S-function parameters, the mdlProcessParameters method uses ssUpdateRunTimeParamData to update the run-time parameter.

The S-function sfun_runtime4.c provides an example. In this example, the mdlProcessParameters method calculates a new value for the run-time parameter and passes the value to the pointer of the run-time parameter's memory location, which was allocated during the call to mdlSetWorkWidths. The mdlProcessParameters method then passes the updated run-time parameter's pointer to ssUpdateRunTimeParamData.

Tuning Run-Time Parameters

Tuning a dialog parameter tunes the corresponding run-time parameter during simulation and in code generated only if the dialog parameter meets the following conditions:

  • The S-function marks the dialog parameter as tunable, using ssSetSFcnParamTunable.

  • The dialog parameter is a MATLAB® array of values with a data type supported by the Simulink product.

Note that you cannot tune a run-time parameter whose value is a cell array or structure.

Accessing Run-Time Parameters

You can easily access run-time parameters from the S-function code. In order to access run-time parameter data, choose one of the following methods based on the data type.

  • If the data is of type double:

    real_T *dataPtr = (real_T *) ssGetRunTimeParamInfo(S, #)->data;
  • If the parameter is complex, the real and imaginary parts of the data are interleaved. For example, if a user enters the following:

    K = [1+2i, 3+4i; 5+6i, 7+8i]

    the matrix that is generated is

    K = 
        1+2i     3+4i
        5+6i     7+8i

    The memory for this matrix is laid out as

    [1, 2, 5, 6, 3, 4, 7, 8]

    To access a complex run-time parameter from the S-function code:

    for (i = 0; i<width; i++)
    {
    real_T realData = dataPtr[(2*i)];
    real_T imagData = dataPtr[(2*i)+1];
    }

Note

Matrix elements are written out in column-major format. Real and imaginary values are interleaved.

See Also

Related Topics