Main Content

Configure Dimension Variants for S-Function Blocks

To configure symbolic dimensions for S-function blocks, you can use the following C/C++ functions. You can configure S-functions to support forward propagation, backward propagation, or forward and backward propagation of symbolic dimensions during simulation.

Many of these functions return the variable SymbDimsId. A SymbDimsId is a unique integer value. This value corresponds to each symbolic dimension specification that you create or is the result of a mathematical operation that you perform with symbolic dimensions.

C/C++ S-FunctionsPurpose

ssSetSymbolicDimsSupport

Specify whether or not an S-function supports symbolic dimensions.

mdlSetInputPortSymbolicDimensions

Specify the symbolic dimensions of an input port and how those dimensions propagate forward.

mdlSetOutputPortSymbolicDimensions

Specify the symbolic dimensions of an output port and how those dimensions propagate backward.

ssRegisterSymbolicDimsExpr

Create a SymbDimsId from an expression string (aExpr). The expression string must form a valid syntax in C.

ssRegisterSymbolicDims

Create a SymbDimsId from a vector of SymbDimsIds.

ssRegisterSymbolicDimsString

Create a SymbDimsId from an identifier string (aString).

ssRegisterSymbolicDimsIntValue

Create a SymbDimsId from an integer value (aIntValue)

ssRegisterSymbolicDimsPlus

Create a SymbDimsId by adding two symbolic dimensions.

ssRegisterSymbolicDimsMinus

Create a SymbDimsId by subtracting two symbolic dimensions.

ssRegisterSymbolicDimsMultiply

Create a SymbDimsId by multiplying two symbolic dimensions.

ssRegisterSymbolicDimsDivide

Create a SymbDimsId by dividing two symbolic dimensions.

ssGetNumSymbolicDims

Get the number of dimensions for a SymbDimsId.

ssGetSymbolicDim

Get a SymbDimsId from a vector of SymbDimsIds.

ssSetInputPortSymbolicDimsId

Set the precompiled SymbDimsId of an input port. You can call this function from inside the mdlInitializeSizes function.

ssGetCompInputPortSymbolicDimsId

Get the compiled SymbDimsId of an input port.

ssSetCompInputPortSymbolicDimsId

Set the compiled SymbDimsId of an input port.

ssSetOutputPortSymbolicDimsId

Set the precompiled SymbDimsId of an output port. You can call this function from inside the mdlInitializeSizes function.

ssGetCompOutputPortSymbolicDimsId

Get the compiled SymbDimsId of an output port.

ssSetCompOutputPortSymbolicDimsId

Set the compiled SymbDimsId of an output port.

ssSetCompDWorkSymbolicDimsId

Set the compiled SymbDimsId of an index of a block’s data type work (DWork) vector.

S-Function That Supports Forward Propagation of Symbolic Dimensions

The model ex_msymbdims_sfcn_one contains an S-function that subtracts the symbolic dimension B from a symbolic input dimension, A + B. It does not support backward propagation of symbolic dimensions because the compiled symbolic dimensions of the input ports are not set. Symbolic dimensions are set for the output port, so forward propagation occurs.

After simulation, the model shows the propagated dimensions.

Model with an S-function and symbolic dimensions

The sfun_symbdims_sfcn_one.c file contains this code.

#define S_FUNCTION_NAME  sfun_symbdims_sfcn_one
#define S_FUNCTION_LEVEL 2

#include "simstruc.h"

#include <assert.h>

/* Function: mdlInitializeSizes ===============================================
 * Abstract:
 *   Setup sizes of the various vectors.
 */
static void mdlInitializeSizes(SimStruct *S)
{
    ssSetNumSFcnParams(S, 0); /* Number of expected parameters */
    
    ssSetNumContStates(S, 0);
    ssSetNumDiscStates(S, 0);

    if (!ssSetNumInputPorts(S, 1)) return;
    ssSetInputPortDirectFeedThrough(S, 0, 1);
    ssSetInputPortDimensionInfo(S, 0, DYNAMIC_DIMENSION);
    ssSetInputPortRequiredContiguous(S, 0, 1);
    
    if (!ssSetNumOutputPorts(S,1)) return;
    ssSetOutputPortDimensionInfo(S, 0, DYNAMIC_DIMENSION);   
    ssSetNumSampleTimes(S, 1);

    ssSetNumRWork(S, 0);
    ssSetNumIWork(S, 0);
    ssSetNumPWork(S, 0);

    ssSetNumModes(S, 0);
    ssSetNumNonsampledZCs( S, 0);
    
    ssAllowSignalsWithMoreThan2D(S);
    
    ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE);
    
    ssSetSymbolicDimsSupport(S, true);
}


/*If underspecified for propagation, say i/o are scalars.*/
#if defined(MATLAB_MEX_FILE)
#define MDL_SET_DEFAULT_PORT_DIMENSION_INFO
static void mdlSetDefaultPortDimensionInfo(SimStruct *S)
{
    if( (ssGetOutputPortWidth(S, 0) == DYNAMICALLY_SIZED) 
        && (ssGetInputPortWidth(S, 0) == DYNAMICALLY_SIZED) ) {
        ssSetOutputPortMatrixDimensions(S, 0, 1, 1 );
    }
}
#endif

#if defined(MATLAB_MEX_FILE)
#define MDL_SET_INPUT_PORT_SYMBOLIC_DIMENSIONS
static void mdlSetInputPortSymbolicDimensions(SimStruct* S, 
   int_T portIndex, SymbDimsId symbDimsId)
{
    assert(0 == portIndex);
    // Set the compiled input symbolic dimension.
    ssSetCompInputPortSymbolicDimsId(S,  portIndex, symbDimsId);
	// Register "B" and get its symbolic dimensions id.
    const SymbDimsId symbolId = ssRegisterSymbolicDimsString(S, "B");
	// Subtract "B" from the input symbolic dimension.
    const SymbDimsId outputDimsId = 
       ssRegisterSymbolicDimsMinus(S, symbDimsId, symbolId);
    ssSetCompOutputPortSymbolicDimsId(S, portIndex, outputDimsId);
}
#endif

#if defined(MATLAB_MEX_FILE)
#define MDL_SET_OUTPUT_PORT_SYMBOLIC_DIMENSIONS
static void mdlSetOutputPortSymbolicDimensions(SimStruct *S, 
   int_T portIndex, SymbDimsId symbDimsId)
{
    assert(0 == portIndex);
   // The input dimensions are not set, so this S-function only
	// supports forward propagation.
    ssSetCompOutputPortSymbolicDimsId(S, portIndex, symbDimsId);
}
#endif

/* Function: mdlInitializeSampleTimes =========================================
 * Abstract:
 *    Specify that we inherit our sample time from the driving block.
 *    However, we don't execute in minor steps.
 */
static void mdlInitializeSampleTimes(SimStruct *S)
{
    ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME);
    ssSetOffsetTime(S, 0, 0.0);
    ssSetModelReferenceSampleTimeDefaultInheritance(S);    
}
/* Function: mdlOutputs =======================================================
 * Abstract:
 *    y=u';
 */
static void mdlOutputs(SimStruct *S, int_T tid)
{
}

/* Function: mdlTerminate =====================================================
 * Abstract:
 *    No termination needed, but we are required to have this routine.
 */
static void mdlTerminate(SimStruct *S)
{
    UNUSED_ARG(S); /* unused input argument */
}

#ifdef  MATLAB_MEX_FILE    /* Is this file being compiled as a MEX-file? */
#include "simulink.c"      /* MEX-file interface mechanism */
#else
#include "cg_sfun.h"       /* Code generation registration function */
#endif

The Simulink.Parameter objects A and B contain these definitions.

A = Simulink.Parameter;
A.DataType = 'int32';
A.Value = 6;
A.Min=5;
A.Max=7;
A.CoderInfo.StorageClass = 'Custom';
A.CoderInfo.CustomStorageClass = 'ImportedDefine';
A.CoderInfo.CustomAttributes.HeaderFile = 'ImportedDefinitions.h';

B = Simulink.Parameter;
B.DataType = 'int32';
B.Value = 10;
B.Min=9;
B.Max=11;
B.CoderInfo.StorageClass = 'Custom';
B.CoderInfo.CustomStorageClass = 'ImportedDefine';
B.CoderInfo.CustomAttributes.HeaderFile = 'ImportedDefinitions.h';
The ImportedDefinitions header file contains this code.
#ifndef _IMPORTEDDEFINITIONS_H_
#define _IMPORTEDDEFINITIONS_H_
#define A 6
#define B 10
#endif

In the Configuration Parameters dialog box, the Custom Code pane contains the #include statement.

#include "ImportedDefinitions.h"

The sfun_symbdims_sfcn_one S-function is inlined, so a TLC file with this code must be present on the path with the model and other supporting files.

%implements "sfun_symbdims_sfcn_two" "C"

%function BlockInstanceSetup(block, system) void
%endfunction

%% Function: BlockOutputSignal =================================================
%function BlockOutputSignal(block,system,portIdx,ucv,lcv,idx,retType) void
%endfunction

%% Function: Outputs ===========================================================
%%
%function Outputs(block, system) Output


  %assign rollVars = ["U", "Y"]
  %roll idx = RollRegions, lcv = RollThreshold, block, "Roller", rollVars
    %%
    %assign u  = LibBlockInputSignal( 0, "", lcv, idx)
    %assign y  = LibBlockOutputSignal(0, "", lcv, idx)
                                                           
    %<y> = %<u>;
                                                      
  %endroll

%endfunction %% Outputs

To generate a MEX function, at the command-line, enter this command:

mex sfun_symbdims_sfcn_one.c

Generate code for the model. The ex_msymbdims_sfcn_one_step function contains this code. The S-function code is set inline.

/* Model step function */
void ex_msymbdims_sfcn_one_step(void)
{
  int32_T i;

  /* Gain: '<Root>/Gain' incorporates:
   *  Inport: '<Root>/In1'
   */
  for (i = 0; i < A; i++) {
    ex_msymbdims_sfcn_one_B.MatrixConcatenate[i] = 2.0 *
      ex_msymbdims_sfcn_one_U.In1[i];
  }

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

  /* Gain: '<Root>/Gain2' incorporates:
   *  Inport: '<Root>/In2'
   */
  for (i = 0; i < B; i++) {
    ex_msymbdims_sfcn_one_B.MatrixConcatenate[A + i] = 2.0 *
      ex_msymbdims_sfcn_one_U.In2[i];
  }

  /* End of Gain: '<Root>/Gain2' */

  /* S-Function (sfun_symbdims_sfcn_one): '<Root>/Minus' incorporates:
   *  Outport: '<Root>/Out7'
   */
  {
    int_T i1;
    const real_T *u0 = &ex_msymbdims_sfcn_one_B.MatrixConcatenate[0];
    real_T *y0 = &ex_msymbdims_sfcn_one_Y.Out7[0];
    for (i1=0; i1 < ((A + B)); i1++) {
      y0[i1] = u0[i1];
    }
  }
}

S-Function That Supports Forward and Backward Propagation of Symbolic Dimensions

This S-function transposes two symbolic dimensions. It supports forward and backward propagation of symbolic dimensions because the compiled symbolic dimension of both the input and output ports are set.

static void mdlInitializeSizes(SimStruct *S)
{
     // Enable symbolic dimensions for the s-function.
     ssSetSymbolicDimsSupport(S, true);
}

#if defined(MATLAB_MEX_FILE)
#define MDL_SET_INPUT_PORT_SYMBOLIC_DIMENSIONS
static void mdlSetInputPortSymbolicDimensions(SimStruct* S, 
   int_T portIndex, SymbDimsId symbDimsId)
{
    assert(0 == portIndex);
    
    ssSetCompInputPortSymbolicDimsId(S,  portIndex, symbDimsId);
    
    assert(2U == ssGetNumSymbolicDims(S, symbDimsId));
    
    if (SL_INHERIT == 
        ssGetCompOutputPortSymbolicDimsId(S, portIndex)) {

        const SymbDimsId idVec[] = {
            ssGetSymbolicDim(S, symbDimsId, 1),
            ssGetSymbolicDim(S, symbDimsId, 0)};
        // Register the transposed dimensions.
       // Set the output symbolic dimension to the resulting id.
  const SymbDimsId outputDimsId = 
            ssRegisterSymbolicDims(S, idVec, 2U);

        ssSetCompOutputPortSymbolicDimsId(S, portIndex, 
           outputDimsId);
    }
}
#endif

#if defined(MATLAB_MEX_FILE)
#define MDL_SET_OUTPUT_PORT_SYMBOLIC_DIMENSIONS
static void mdlSetOutputPortSymbolicDimensions(SimStruct *S, 
    int_T portIndex, SymbDimsId symbDimsId)
{
    assert(0 == portIndex);
    ssSetCompOutputPortSymbolicDimsId(S, portIndex, symbDimsId);

    assert(2U == ssGetNumSymbolicDims(S, symbDimsId));
    
    if (SL_INHERIT == 
        ssGetCompInputPortSymbolicDimsId(S, portIndex)) {

        const SymbDimsId idVec[] = {
            ssGetSymbolicDim(S, symbDimsId, 1),
            ssGetSymbolicDim(S, symbDimsId, 0)};
        const SymbDimsId inputDimsId = 
            ssRegisterSymbolicDims(S, idVec, 2U);
        // Register the transposed dimensions.
       // Set the input symbolic dimension to the resulting id.
        ssSetCompInputPortSymbolicDimsId(S, portIndex, inputDimsId);
    }
}
#endif

Related Topics