Main Content

Input and Output Ports

Creating Input Ports for C S-Functions

To create and configure input ports, the mdlInitializeSizes method should first specify the number of S-function input ports, using ssSetNumInputPorts. Then, for each input port, the method should specify

  • The dimensions of the input port (see Initializing Input Port Dimensions)

    If you want your S-function to inherit its dimensionality from the port to which it is connected, you should specify that the port is dynamically sized in mdlInitializeSizes (see Sizing an Input Port Dynamically).

  • Whether the input port allows scalar expansion of inputs (see Scalar Expansion of Inputs)

  • Whether the input port has direct feedthrough, using ssSetInputPortDirectFeedThrough

    A port has direct feedthrough if the input is used in either the mdlOutputs or mdlGetTimeOfNextVarHit functions. The direct feedthrough flag for each input port can be set to either 1=yes or 0=no. It should be set to 1 if the input, u, is used in the mdlOutputs or mdlGetTimeOfNextVarHit routine. Setting the direct feedthrough flag to 0 tells the Simulink® engine that u is not used in either of these S-function routines. Violating this leads to unpredictable results.

  • The data type of the input port, if not the default double

    Use ssSetInputPortDataType to set the input port's data type. If you want the data type of the port to depend on the data type of the port to which it is connected, specify the data type as DYNAMICALLY_TYPED. In this case, you must provide implementations of the mdlSetInputPortDataType and mdlSetDefaultPortDataTypes methods to enable the data type to be set correctly during signal propagation.

  • The numeric type of the input port, if the port accepts complex-valued signals

    Use ssSetInputPortComplexSignal to set the input port's numeric type. If you want the numeric type of the port to depend on the numeric type of the port to which it is connected, specify the numeric type as COMPLEX_INHERITED. In this case, you must provide implementations of the mdlSetInputPortComplexSignal and mdlSetDefaultPortComplexSignals methods to enable the numeric type to be set correctly during signal propagation.

You can configure additional input port properties using other S-function macros. See Input and Output Ports in the “SimStruct Macros and Functions Listed by Usage” section for more information.

Note

The mdlInitializeSizes method must specify the number of ports before setting any properties. If it attempts to set a property of a port that doesn't exist, it is accessing invalid memory and a segmentation violation occurs.

Initializing Input Port Dimensions

You can set input port dimensions using one of the following macros:

  • If the input signal must be one-dimensional and the input port width is w, use

    ssSetInputPortWidth(S, inputPortIdx, w)
    
  • If the input signal must be a matrix of dimension m-by-n, use

    ssSetInputPortMatrixDimensions(S, inputPortIdx, m, n)
    
  • Otherwise, if the input signal can have either one or two dimensions, use

    ssSetInputPortDimensionInfo(S, inputPortIdx, dimsInfo)
    

    You can use this function to fully or partially initialize the port dimensions (see next section).

Sizing an Input Port Dynamically

If your S-function does not require that its input signals have specific dimensions, you can set the dimensionality of the input ports to match the dimensionality of the signals connected to them.

To dynamically dimension an input port:

  • Specify some or all of the dimensions of the input port as dynamically sized in mdlInitializeSizes.

    If the input port can accept a signal of any dimensionality, use

    ssSetInputPortDimensionInfo(S, inputPortIdx, DYNAMIC_DIMENSION)
    

    to set the dimensionality of the input port.

    If the input port can accept only vector (1-D) signals but the signals can be of any size, use

    ssSetInputPortWidth(S, inputPortIdx, DYNAMICALLY_SIZED)
    

    to specify the dimensionality of the input port.

    If the input port can accept only matrix signals but can accept any row or column size, use

    ssSetInputPortMatrixDimensions(S, inputPortIdx, 
       DYNAMICALLY_SIZED, DYNAMICALLY_SIZED)
    
  • Provide an mdlSetInputPortDimensionInfo method that sets the dimensions of the input port to the size of the signal connected to it.

    The Simulink engine invokes this method during signal propagation when it has determined the dimensionality of the signal connected to the input port.

  • Provide an mdlSetDefaultPortDimensionInfo method that sets the dimensions of the block's ports to a default value. See sfun_dynsize.c for an example that implements this macro.

    The engine invokes this method during signal propagation when it cannot determine the dimensionality of the signal connected to some or all of the block's input ports. This can happen, for example, if an input port is unconnected. If the S-function does not provide this method, the signal propagation routine sets the dimension of the block's ports to 1-D scalar.

Example: Defining Multiple S-Function Input Ports

The following code in mdlInitializeSizes configures an S-function with two input ports. See Input and Output Ports in the “SimStruct Macros and Functions Listed by Usage” section for more information on the macros used in this example.

if (!ssSetNumInputPorts(S, 2)) return;

for (i = 0; i < 2; i++) {
  /* Input has direct feedthrough */
  ssSetInputPortDirectFeedThrough(S, i, 1);

  /* Input is a real signal */
  ssSetInputPortComplexSignal(S, i, COMPLEX_NO);

  /* Input is a dynamically sized 2-D matrix */
  ssSetInputPortMatrixDimensions(S ,i, 
     DYNAMICALLY_SIZED, DYNAMICALLY_SIZED);

  /* Input inherits its sample time */
  ssSetInputPortSampleTime(S, i,INHERITED_SAMPLE_TIME);

  /* Input signal must be contiguous */
  ssSetInputPortRequiredContiguous(S, i, 1);

  /* The input port cannot share memory */
  ssSetInputPortOverWritable(S, i, 0);
}

During signal propagation, the Simulink engine calls this S-function's mdlSetInputPortDimensionInfo macro to initialize the input port dimensions. In this example, mdlSetInputPortDimensionInfo sets the input dimensions to the candidate dimensions passed to the macro by the engine.

#if defined(MATLAB_MEX_FILE)
#define MDL_SET_INPUT_PORT_DIMENSION_INFO
static void mdlSetInputPortDimensionInfo(SimStruct        *S,
                                  int_T            port,
                                  const DimsInfo_T *dimsInfo)
{
    if(!ssSetInputPortDimensionInfo(S, port, dimsInfo)) return;
}
#endif

For an example that configures an S-function with multiple input and output ports, open the Simulink model sfcndemo_sfun_multiport and inspect the S-function sfun_multiport.c.

Creating Output Ports for C S-Functions

To create and configure output ports, the mdlInitializeSizes method should first specify the number of S-function output ports, using ssSetNumOutputPorts. Then, for each output port, the method should specify

See Creating Input Ports for C S-Functions for an example showing how to initialize an S-function input port. You use the same procedure to initialize the S-function output ports, but with the corresponding output port macro.

Scalar Expansion of Inputs

Scalar expansion of inputs refers conceptually to the process of expanding scalar input signals to the same dimensions as wide input signals connected to other S-function input ports. This is done by setting each element of the expanded signal to the value of the scalar input.

A Level-2 MATLAB® S-function uses the default scalar expansion rules if the input and output ports are specified as dynamically sized (see Scalar Expansion of Inputs and Parameters in Using Simulink).

With scalar expansion on, the S-function mdlInitializeSizes method should specify that the input and output ports are dynamically sized. The Simulink engine uses a default method to set the dimensions of the input and output ports. If the block has more than two inputs, the input signals can be scalar or wide signals, where the wide signals all have the same number of elements. In this case, the engine sets the dimensions of the output ports to the width of the wide input signals and expands any scalar inputs to this width. If the wide inputs are driven by 1-D and 2-D vectors, the output is a 2-D vector signal, and the scalar inputs are expanded to a 2-D vector signal.

If scalar expansion is not on, the engine assumes that all ports (input and output ports) must have the same dimensions, and it sets all port dimensions to the same dimensions specified by one of the driving blocks.

Note

The engine ignores the scalar expansion option if the S-function specifies or controls the dimensions of its input and output ports either by initializing the dimensions in mdlInitializeSizes, using mdlSetInputPortWidth and mdlSetOutputPortWidth, or using mdlSetInputPortDimensionInfo, mdlSetOutputPortDimensionInfo, and mdlSetDefaultPortDimensionInfo.

The best way to understand how to use scalar expansion is to consider the example sfcndemo_sfun_multiport. This model contains three S-function blocks, each with multiple input ports. The S-function sfun_multiport.c used in these blocks sets the SS_OPTION_ALLOW_INPUT_SCALAR_EXPANSION option in its mdlInitializeSizes method, allowing scalar expansion of the inputs. The S-function specifies that its inputs and outputs are dynamically sized. Therefore, during signal propagation, the engine sets the width of the input ports to the width of the signal connected to the port, and the width of the output ports to the width of any wide input signal. The mdlOutputs method performs an element-by-element sum on the input signals, expanding any scalar inputs, as needed.

/* Calculate an element-by-element sum of the input signals.
   yWidth is the width of the output signal. */

for (el = 0; el < yWidth; el++) {

   int_T  port;
   real_T sum = 0.0;
   for (port = 0; port < nInputPorts; port++) {
      /* Get the input signal value */
      InputRealPtrsType uPtrs = 
                   ssGetInputPortRealSignalPtrs(S,port);

      if (el < ssGetInputPortWidth(S,port)) {
         /* Input is a wide signal. Use specific element */
         sum = sum + ((real_T)signs[port] * (*uPtrs[el]));

      } else { 
         /* Use the scalar value to expand the signal */
         sum = sum + ((real_T)signs[port] * (*uPtrs[0]));
      }
   }
}

Masked Multiport S-Functions

If you are developing masked multiport S-function blocks whose number of ports varies based on some parameter, and want to place them in a Simulink library, you must specify that the mask modifies the appearance of the block. To do this, execute the command

  set_param(blockname,'MaskSelfModifiable','on')

at the MATLAB command prompt before saving the library, where blockname is the full path to the block. Failure to specify that the mask modifies the appearance of the block means that an instance of the block in a model reverts to the number of ports in the library whenever you load the model or update the library link.