Writing S-Functions | ![]() ![]() |
Data View
S-function blocks have input and output signals, parameters, internal states, plus other general work areas. In general, block inputs and outputs are written to, and read from, a block I/O vector. Inputs can also come from
Block outputs can also go to the external outputs via the root outport blocks. In addition to input and output signals, S-functions can have:
S-function blocks can be parameterized by passing parameters them using the S-function block dialog box.
The following picture shows the general mapping between these various types of data.
An S-function's mdlInitializeSizes routine sets the sizes of the various signals and vectors. S-function methods called during the simulation loop can determine the sizes and values of the signals.
An S-function method can access input signals in two ways:
Accessing Signals Using Pointers
During the simulation loop, accessing the input signals is performed using
InputRealPtrs uPtrs = ssGetInputPortRealSignalPtrs(S,portIndex
)
This is an array of pointers, where portIndex
starts at 0. There is one for each input port. To access an element of this signal you must use
*uPtrs[element]
Note that input array pointers may point at noncontiguous places in memory. You can retrieve the output signal by using this code.
real_T *y = ssGetOutputPortSignal(S,outputPortIndex);
Accessing Contiguous Input Signals
An S-function's mdlInitializeSizes
method can specify that the elements of its input signals must occupy contiguous areas of memory, using ssSetInputPortRequiredContiguous. If the inputs are contiguous, other methods can use ssGetInputPortSignal to access the inputs.
Accessing Input Signal of Individual Ports
This section describes how to access all input signals of a particular port and write them to the output port. The figure above shows that the input array of pointers may point to noncontiguous entries in the block I/O vector. The output signals of a particular port form a contiguous vector. Therefore, the correct way to access input elements and write them to the output elements (assuming the input and output ports have equal widths) is to use this code.
int_T element; int_T portWidth = ssGetInputPortWidth(S,inputPortIndex); InputRealPtrs uPtrs = ssGetInputPortRealSignalPtrs(S,inputPortIndex); real_T *y = ssGetOutputPortSignal(S,outputPortIdx); for (elemet=0; element<portWidth; element++) { y[element] = *uPtrs[element]; }
A common mistake is to try and access the input signals via pointer arithmetic. For example, if you were to place
real_T *u = *uPtrs
; /* Incorrect */
just below the initialization of uPtrs
and replace the inner part of the above loop with
*y++ = *u++;
/* Incorrect */
the code compiles, but the MEX-file may crash Simulink. This is because it is possible to access invalid memory (which depends on how you build your model). When accessing the input signals incorrectly, a crash will happen when the signals entering your S-function block are not contiguous. Noncontiguous signal data occur when signals pass through virtual connection blocks such as the Mux or Selector blocks.
To verify that you are correctly accessing wide input signals, pass a replicated signal to each input port of your S-function. This is done by creating a Mux block with the number of input ports equal to the width of the desired signal entering your S-function. Then the driving source should be connected to each input port as shown in this figure.
![]() | Process View | Writing Callback Methods | ![]() |