Writing S-Functions | ![]() ![]() |
S-Function Concepts
Understanding these key concepts should enable you to build S-functions correctly:
Direct Feedthrough
Direct feedthrough means that the output (or the variable sample time for variable sample time blocks) is controlled directly by the value of an input port. A good rule of thumb is that an S-function input port has direct feedthrough if:
mdlOutputs
or flag==3
) is a function of the input u
. That is, there is direct feedthrough if the input u
is accessed in mdlOutputs
. Outputs may also include graphical outputs, as in the case of an XY Graph scope.mdlGetTimeOfNextVarHit
or flag==4
) of a variable sample time S-function accesses the input u
.An example of a system that requires its inputs (i.e., has direct feedthrough) is the operation , where u is the input, k is the gain, and y is the output.
An example of a system that does not require its inputs (i.e., does not have direct feedthrough) is this simple integration algorithm
where x is the state, is the state derivative with respect to time, u is the input and y is the output. Note that
is the variable that Simulink integrates. It is very important to set the direct feedthrough flag correctly because it affects the execution order of the blocks in your model and is used to detect algebraic loops.
Dynamically Sized Arrays
S-functions can be written to support arbitrary input dimensions. In this case, the actual input dimensions are determined dynamically when a simulation is started by evaluating the dimensions of the input vector driving the S-function. The input dimensions can also be used to determine the number of continuous states, the number of discrete states, and the number of outputs.
M-file S-functions can have only one input port and that input port can accept only one-dimensional (vector) signals. However, the signals can be of varying width.Within an M-file S-function, to indicate that the input width is dynamically sized, specify a value of -1 for the appropriate fields in the sizes
structure, which is returned during the mdlInitializeSizes
call. You can determine the actual input width when your S-function is called by using length(u)
. If you specify a width of 0, then the input port will be removed from the S-function block.
A C S-function can have multiple I/O ports and the ports can have different dimensions. The number of dimensions and the size of each dimension can be determined dynamically.
For example, the illustration below shows two instances of the same S-Function block in a model.
The upper S-Function block is driven by a block with a three-element output vector. The lower S-Function block is driven by a block with a scalar output. By specifying that the S-Function block has dynamically sized inputs, the same S-function can accommodate both situations. Simulink automatically calls the block with the appropriately sized input vector. Similarly, if other block characteristics, such as the number of outputs or the number of discrete or continuous states, are specified as dynamically sized, Simulink defines these vectors to be the same length as the input vector.
C S-functions give you more flexibility in specifying the widths of input and output ports. See Input and Output Ports.
Setting Sample Times and Offsets
Both M-file and C MEX S-functions allow a high degree of flexibility in specifying when an S-function executes. Simulink provides the following options for sample times:
A sample time hit occurs at time values determined by this formula
TimeHit = (n *
period) + offset
where n
, an integer, is the current simulation step. The first value of n
is always zero.
If you define a discrete sample time, Simulink calls the S-function mdlOutput
and mdlUpdate
routines at each sample time hit (as defined in the above equation).
A block can inherit its sample time from:
To set a block's sample time as inherited, use -1 in M-file S-functions and INHERITED_SAMPLE_TIME
in C S-functions as the sample time. For more information on the propagation of sample times, see "Sample Time Colors" in Using Simulink.
S-functions can be either single or multirate; a multirate S-function has multiple sample times.
Sample times are specified in pairs in this format: [sample_time,
offset_time
]. The valid sample time pairs are
[CONTINUOUS_SAMPLE_TIME, 0.0] [CONTINUOUS_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET][
discrete_sample_time_period,
offset]
[VARIABLE_SAMPLE_TIME, 0.0]
CONTINUOUS_SAMPLE_TIME = 0.0 FIXED_IN_MINOR_STEP_OFFSET = 1.0 VARIABLE_SAMPLE_TIME = -2.0
and the italics indicate a real value is required.
Alternatively, you can specify that the sample time is inherited from the driving block. In this case the S-function can have only one sample time pair
[INHERITED_SAMPLE_TIME, 0.0]
[INHERITED_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET]
INHERITED_SAMPLE_TIME = -1.0
The following guidelines may help you specify sample times:
CONTINUOUS_SAMPLE_TIME
, 0.0
] sample time.
[CONTINUOUS_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET]
sample time.discrete_sample_time_period
, offset
], discrete_sample_period
> 0.0
and
0.0
offset
<
discrete_sample_period
[VARIABLE_SAMPLE_TIME, 0.0]
The mdlGetTimeOfNextVarHit
routine is called to get the time of the next sample hit for the variable step discrete task.
If your S-function has no intrinsic sample time, then you must indicate that your sample time is inherited. There are two cases:
[INHERITED_SAMPLE_TIME, 0.0]
sample time.[INHERITED_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET]
sample time.The Scope block is a good example of this type of block. This block should run at the rate, either continuous or discrete, of its driving block, but should never run in minor step. If it did, the scope display would show the intermediate computations of the solver rather than the final result at each time point.
![]() | Implementing S-Functions | S-Function Examples | ![]() |