Writing S-Functions | ![]() ![]() |
Work Vectors
If your S-function needs persistent memory storage, use S-function work vectors instead of static or global variables. If you use static or global variables, they are used by multiple instances of your S-function. This occurs when you have multiple S-Function blocks in a Simulink model and the same S-function C MEX-file has been specified. The ability to keep track of multiple instances of an S-function is called reentrancy.
You can create an S-function that is reentrant by using work vectors. These are persistent storage locations that Simulink manages for an S-function. Integer, floating-point (real), pointer, and general data types are supported. The number of elements in each vector can be specified dynamically as a function of the number of inputs to the S-function.
Work vectors have several advantages:
For example, suppose you'd like to track the previous value of each input signal element entering input port 1 of your S-function. Either the discrete-state vector or the real-work vector could be used for this, depending upon whether the previous value is considered a discrete state (that is, compare the unit delay and the memory block). If you do not want the previous value to be logged when states are saved, use the real-work vector, rwork
. To do this, in mdlInitializeSizes specify the length of this vector by using ssSetNumRWork. Then in either mdlStart or mdlInitializeConditions, initialize the rwork
vector ssGetRWork. In mdlOutputs, you can retrieve the previous inputs by using ssGetRWork. In mdlUpdate, update the previous value of the rwork
vector by using ssGetInputPortRealSignalPtrs.
Use the macros in this table to specify the length of the work vectors for each instance of your S-function in mdlInitializeSizes
.
Macro |
Description |
ssSetNumContStates |
Width of the continuous-state vector |
ssSetNumDiscStates |
Width of the discrete-state vector |
ssSetNumDWork |
Width of the data type work vector |
ssSetNumRWork |
Width of the real-work vector |
ssSetNumIWork |
Width of the integer-work vector |
ssSetNumPWork |
Width of the pointer-work vector |
ssSetNumModes |
Width of the mode-work vector |
ssSetNumNonsampledZCs |
Width of the nonsampled zero-crossing vector |
Specify vector widths in mdlInitializeSizes
. There are three choices:
mdlStart
, mdlInitializeConditions
, and S-function routines called in the simulation loop.
DYNAMICALLY_SIZED
define. The default behavior for dynamically sized vectors is to set them to the overall block width. Simulink does this after propagating line widths and sample times. The block width is the width of the signal passing through your block. In general this is equal to the output port width.
If the default behavior of dynamically sized vectors does not meet your needs, use mdlSetWorkWidths
and the macros listed in Table 7-1, Macros Used in Specifying Vector Widths, to set the sizes of the work vectors explicitly. mdlSetWorkWidths
also allows you to set your work vector lengths as functions of the block sample time and/or port widths.
The continuous states are used when you have a state that needs to be integrated by one of Simulink's solvers. When you specify continuous states, you must return the states' derivatives in mdlDerivatives
. The discrete state vector is used to maintain state information that changes at fixed intervals. Typically the discrete state vector is updated in place in mdlUpdate
.
The integer, real, and pointer work vectors are storage locations that are not logged by Simulink during simulations. They maintain persistent data between calls to your S-function.
![]() | Synchronizing Multirate S-Function Blocks | Work Vectors and Zero Crossings | ![]() |