Specify S-Function Sample Times - MATLAB & Simulink (original) (raw)

About Sample Times

You can specify the sample-time behavior of your S-functions in mdlInitializeSampleTimes. Your S-function can inherit its rates from the blocks that drive it or define its own rates.

You can specify your S-function rates (i.e., sample times) as

With block-based sample times, the S-function specifies a set of operating rates for the block as a whole during the initialization phase of the simulation. With port-based sample times, the S-function specifies a sample time for each input and output port individually during initialization. During the simulation phase, with block-based sample times, the S-function processes all inputs and outputs each time a sample hit occurs for the block. By contrast, with port-based sample times, the block processes a particular port only when a sample hit occurs for that port.

For example, consider two sample rates, 0.5 and 0.25 seconds, respectively:

You should use port-based sample times if your application requires unequal sample rates for input and output execution or if you do not want the overhead associated with running input and output ports at the highest sample rate of your block.

In some applications, an S-Function block might need to operate internally at one or more sample rates while inputting or outputting signals at other rates. The hybrid block- and port-based method of specifying sample rates allows you to create such blocks.

In typical applications, you specify only one block-based sample time. Advanced S-functions might require the specification of port-based or multiple block sample times.

Block-Based Sample Times

C MEX S-functions specify block-based sample time information in

The next two sections discuss how to specify block-based sample times for C MEX S-functions. A third section presents a simple example that shows how to specify sample times in mdlInitializeSampleTimes. For a detailed example, see [mixedm.c](https://mdsite.deno.dev/matlab:sfunddg%5Fcb%5Fedit%28'mixedm'%29;).

Specifying the Number of Sample Times in mdlInitializeSizes

To configure your S-function for block-based sample times, use

where numSampleTimes > 0. This tells the Simulink® engine that your S-function has block-based sample times. the engine calls mdlInitializeSampleTimes, which in turn sets the sample times.

Setting Sample Times and Specifying Function Calls in mdlInitializeSampleTimes

mdlInitializeSampleTimes specifies two pieces of execution information:

You specify the sample times as pairs[ sampletime, offsettime], using these macros

where sampleTimePairIndex and_offsetTimePairIndex_ starts at 0.

The valid sample time pairs are (uppercase values are macros defined in[simstruc.h](https://mdsite.deno.dev/matlab:edit%28[matlabroot%20'/simulink/include/simstruc.h']%29;)):

[CONTINUOUS_SAMPLE_TIME, 0.0 ] [CONTINUOUS_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET] [discretesampleperiod, offset ] [VARIABLE_SAMPLE_TIME , 0.0 ]

Alternatively, you can specify that the sample time is inherited from the driving block, in which case the S-function can have only one sample time pair,

[INHERITED_SAMPLE_TIME, 0.0 ]

or

[INHERITED_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET]

Note

If your S-function inherits its sample time, you should specify whether it is safe to use the S-function in a referenced model, i.e., a model referenced by another model. See Specifying Model Reference Sample Time Inheritance for more information.

The following guidelines might help in specifying sample times:

If your function has no intrinsic sample time, you must indicate that it is inherited according to the following guidelines:

To check for a sample hit during execution (in mdlOutputs or mdlUpdate), use the ssIsSampleHit or ssIsContinuousTask macro. For example, use the following code fragment to check for a continuous sample hit:

To determine whether the third (discrete) task has a hit, use the following code fragment:

The Simulink engine always assigns an index of 0 to the continuous sample rate, if it exists, however you get incorrect results if you use ssIsSampleHit(S,0,tid).

Example: mdlInitializeSampleTimes

This example specifies that there are two discrete sample times with periods of 0.01 and 0.5 seconds.

static void mdlInitializeSampleTimes(SimStruct S) { ssSetSampleTime(S, 0, 0.01); ssSetOffsetTime(S, 0, 0.0); ssSetSampleTime(S, 1, 0.5); ssSetOffsetTime(S, 1, 0.0); } / End of mdlInitializeSampleTimes. */

Specifying Port-Based Sample Times

You cannot use port-based sample times with S-functions that have neither input ports nor output ports. If an S-function uses port-based sample times and has no ports, the S-function produces errors when the Simulink model is updated or run. If the number of input or output ports on an S-function is variable, extra protection should be added into the S-function to ensure the total number of ports does not go to zero.

To use port-based sample times in your C MEX S-function, you must specify the number of sample times as port-based in the S-functionmdlInitializeSizes method:

You must also specify the sample time of each input and output port in the S-function mdlInitializeSizes method, using the following macros

The call to ssSetNumSampleTimes can be placed before or after the port-based sample times are actually specified inmdlInitializeSizes. However, ifssSetNumSampleTimes does not configure the S-function to use port-based sample times, any sample times set on the ports will be ignored.

For any given port, you can specify

Specifying Inherited Sample Time for a Port

To specify that a port's sample time is inherited in a C MEX S-function, themdlInitializeSizes method should set its period to-1 and its offset to 0. For example, the following code specifies inherited sample time for a C MEX S-function first input port:

ssSetInputPortSampleTime(S, 0, -1); ssSetInputPortOffsetTime(S, 0, 0);

When you specify port-based sample times, the Simulink engine calls mdlSetInputPortSampleTime andmdlSetOutputPortSampleTime to determine the rates of inherited signals.

Once all rates have been determined, the engine callsmdlInitializeSampleTimes. Even though there is no need to initialize port-based sample times at this point, the engine invokes this method to give your S-function an opportunity to configure function-call connections. Your S-function must thus provide an implementation for this method regardless of whether it uses port-based sample times or function-call connections. Although you can provide an empty implementation, you might want to use it to check the appropriateness of the sample times that the block inherited during sample time propagation. Use [ssGetInputPortSampleTime](ssgetinputportsampletime.html) and [ssGetOutputPortSampleTime](ssgetoutputportsampletime.html) inmdlInitializeSampleTimes to obtain the values of the inherited sample times. For example, the following code inmdlInitializeSampleTimes checks if the S-function first input inherited a continuous sample time.

if (!ssGetInputPortSampleTime(S,0)) { ssSetErrorStatus(S,"Cannot inherit a continuous sample time.") };

Note

If you specify that your S-function ports inherit their sample time, you should also specify whether it is safe to use the S-function in a referenced model, i.e., a model referenced by another model. See Specifying Model Reference Sample Time Inheritance for more information.

If you write TLC code to generate inlined code from an S-function, and if the TLC code contains an Outputs function, you must modify the TLC code if these conditions are true:

In this case, the TLC code must generate code for the constant-valued output port by using the function OutputsForTID instead of the function Outputs. For more information, see Specifying Constant Sample Time (Inf) for a Port.

To prevent ports from inheriting a sample time of Inf, set the option SS_OPTION_DISALLOW_CONSTANT_SAMPLE_TIME in the S-function code. In this case, you can use the TLC function Outputs to generate code for constant-valued output ports.

Specifying Constant Sample Time (Inf) for a Port

If your S-function uses port-based sample times, it can set a sample time ofInf on any of its ports. A port-based sample time ofInf means that the signal entering or leaving the port stays constant.

To make a port output a constant value, the S-function must:

To see an example of how to create ports which output a constant value, see[sfun_port_constant.c](https://mdsite.deno.dev/matlab:sfunddg%5Fcb%5Fedit%28'sfun%5Fport%5Fconstant'%29;), the source file for the[sfcndemo_port_constant](https://mdsite.deno.dev/matlab:sfcndemo%5Fport%5Fconstant) example.

If you write TLC code to generate inlined code from an S-function, and if the TLC code contains an Outputs function, modify the TLC code if all these conditions are true:

In this case, the TLC code must generate code for the constant-valued output port by using the function OutputsForTID instead of the function Outputs. The functionOutputsForTID generates output code for the constant-valued component of the S-function. If you configure a model to generate multitasking code, OutputsForTID also generates output code for the periodic components of the S-function.

For example, view the TLC file sfun_port_constant.tlc for the C S-function sfun_port_constant.c in the model[sfcndemo_port_constant](https://mdsite.deno.dev/matlab:sfcndemo%5Fport%5Fconstant). In the model, the input of the block S-Function2 has a constant value throughout the simulation. In the S-function code, the first output port inherits the sample time of the input port, so the output port also has a constant value. The S-function code directly specifies a constant value for the second output port.

In the TLC code, if the port has a constant value, the functionOutputs does not generate code for the first output port. The function does not generate code for the second output port under any circumstances because the port always has a constant value.

For this S-function, OutputsForTID generates code for output ports that have a constant value. The code generator invokes the functionOutputsForTID, and sets the argumenttid to the task identifier that corresponds to constant values. Only if the task identifier of an output port corresponds to constant values does ,OutputsForTID then generate code for the port.

Configuring Port-Based Sample Times for Use in Triggered Subsystems

To use a C MEX S-function in a triggered subsystem, your port-based sample time S-function must perform the following tasks.

{
/* If the S-function resides in a triggered subsystem,
the sample time and offset passed to this method
are both equal to INHERITED_SAMPLE_TIME. Therefore,
if triggered, the following lines set the sample time
and offset of the input port to INHERITED_SAMPLE_TIME.*/
ssSetInputPortSampleTime(S, portIdx, sampleTime);
ssSetInputPortOffsetTime(S, portIdx, offsetTime);

/* If triggered, set the output port to inherited, as well */  
if (ssSampleAndOffsetAreTriggered(sampleTime,offsetTime)) {  
    ssSetOutputPortSampleTime(S, 0, INHERITED_SAMPLE_TIME);  
    ssSetOutputPortOffsetTime(S, 0, INHERITED_SAMPLE_TIME);  
    /* Note, if there are additional input and output ports  
       on this S-function, they should be set to either  
       inherited or constant at this point, as well. */  
}  

}
There is no way for an S-function residing in a triggered subsystem to predict whether the Simulink engine will callmdlSetInputPortSampleTime ormdlSetOutputPortSampleTime to set its port sample times. For this reason, both methods must be able to set the sample times of all ports correctly so the engine has to call only one of the methods a single time.

See [sfun_port_triggered.c](https://mdsite.deno.dev/matlab:sfunddg%5Fcb%5Fedit%28'sfun%5Fport%5Ftriggered'%29;), the source file for the[sfcndemo_port_triggered](https://mdsite.deno.dev/matlab:sfcndemo%5Fport%5Ftriggered) example model, for an example of how to create an S-function that can be used in a triggered subsystem.

Hybrid Block-Based and Port-Based Sample Times

The hybrid method of assigning sample times combines the block-based and port-based methods. You first specify, in mdlInitializeSizes, the total number of rates at which your block operates, including both block and input and output rates, using ssSetNumSampleTimes.

You then set the SS_OPTION_PORT_SAMPLE_TIMES_ASSIGNED option, using ssSetOptions, to tell the simulation engine that you are going to use the port-based method to specify the rates of the input and output ports individually. Next, as in the block-based method, you specify the periods and offsets of all of the block's rates, both internal and external, using

ssSetSampleTime ssSetOffsetTime

Finally, as in the port-based method, you specify the rates for each port, using

ssSetInputPortSampleTime(S, idx, period) ssSetInputPortOffsetTime(S, idx, offset) ssSetOutputPortSampleTime(S, idx, period) ssSetOutputPortOffsetTime(S, idx, offset)

Note that each of the assigned port rates must be the same as one of the previously declared block rates. For an example S-function, see [mixedm.c](https://mdsite.deno.dev/matlab:sfunddg%5Fcb%5Fedit%28'mixedm'%29;).

Note

If you use the SS_OPTION_PORT_SAMPLE_TIMES_ASSIGNED option, your S-function cannot inherit sample times. Instead, you must specify the rate at which each input and output port runs.

Multirate S-Function Blocks

In a multirate S-Function block, you can encapsulate the code that defines each behavior in the mdlOutputs andmdlUpdate functions with a statement that determines whether a sample hit has occurred. In a C MEX S-function, thessIsSampleHit macro determines whether the current time is a sample hit for a specified sample time. The macro has this syntax:

ssIsSampleHit(S, st_index, tid)

where S is the SimStruct,st_index identifies a specific sample time index, andtid is the task ID (tid is an argument to the mdlOutputs and mdlUpdate functions).

For example, these statements in a C MEX S-function specify three sample times: one for continuous behavior and two for discrete behavior.

ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME); ssSetSampleTime(S, 1, 0.75); ssSetSampleTime(S, 2, 1.0);

In the mdlUpdate function, the following statement encapsulates the code that defines the behavior for the sample time of 0.75 second.

if (ssIsSampleHit(S, 1, tid)) { }

The second argument, 1, corresponds to the second sample time, 0.75 second.

Use the following lines to encapsulate the code that defines the behavior for the continuous sample hit:

Example of Defining a Sample Time for a Continuous Block

This example defines a sample time for a block that is continuous.

/* Initialize the sample time and offset. */ static void mdlInitializeSampleTimes(SimStruct *S) { ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME); ssSetOffsetTime(S, 0, 0.0); }

You must add this statement to the mdlInitializeSizes function.

ssSetNumSampleTimes(S, 1);

Example of Defining a Sample Time for a Hybrid Block

This example defines sample times for a hybrid S-Function block.

/* Initialize the sample time and offset. */ static void mdlInitializeSampleTimes(SimStruct S) { / Continuous state sample time and offset. */ ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME); ssSetOffsetTime(S, 0, 0.0);

/* Discrete state sample time and offset. */ ssSetSampleTime(S, 1, 0.1); ssSetOffsetTime(S, 1, 0.025); }

In the second sample time, the offset causes the Simulink engine to call the mdlUpdate function at these times: 0.025 second, 0.125 second, 0.225 second, and so on, in increments of 0.1 second.

The following statement, which indicates how many sample times are defined, also appears in the mdlInitializeSizes function.

ssSetNumSampleTimes(S, 2);

Multirate S-Functions and Sample Time Hit Calculations

For fixed-step solvers, Simulink uses integer arithmetic, rather than floating-point arithmetic, to calculate the sample time hits. Consequently, task times are integer multiples of their corresponding sample time periods.

This calculation method becomes important if you consider performing Boolean logic based upon task times in multirate S-functions. For example, consider an S-function that has two sample times. The fact that (ssIsSampleHit(S, idx1) == true && ssIsSampleHit(S,idx2) == true, does not guarantee that ssGetTaskTime(S, idx1) == ssGetTaskTime(S, idx2).

Synchronizing Multirate S-Function Blocks

If tasks running at different rates need to share data, you must ensure that data generated by one task is valid when accessed by another task running at a different rate. You can use the ssIsSpecialSampleHit macro in themdlUpdate or mdlOutputs routine of a multirate S-function to ensure that the shared data is valid. This macro returnstrue if a sample hit has occurred at one rate and a sample hit has also occurred at another rate in the same time step. It thus permits a higher rate task to provide data needed by a slower rate task at a rate the slower task can accommodate. When using the ssIsSpecialSampleHit macro, the slower sample time must be an integer multiple of the faster sample time.

Suppose, for example, that your model has an input port operating at one rate (with a sample time index of 0) and an output port operating at a slower rate (with a sample time index of 1). Further, suppose that you want the output port to output the value currently on the input. The following example illustrates usage of this macro.

if (ssIsSampleHit(S, 0, tid) { if (ssIsSpecialSampleHit(S, 0, 1, tid) { /* Transfer input to output memory. */ ... } }

if (ssIsSampleHit(S, 1, tid) { /* Emit output. */ ... }

In this example, the first block runs when a sample hit occurs at the input rate. If the hit also occurs at the output rate, the block transfers the input to the output memory. The second block runs when a sample hit occurs at the output rate. It transfers the output in its memory area to the block's output.

Note that higher-rate tasks always run before slower-rate tasks. Thus, the input task in the preceding example always runs before the output task, ensuring that valid data is always present at the output port.

Specifying Model Reference Sample Time Inheritance

If your C MEX S-function inherits its sample times from the blocks that drive it, your S-function should specify whether referenced models containing your S-function can inherit sample times from their parent model. If the S-function output does not depend on its inherited sample time, use the ssSetModelReferenceSampleTimeInheritanceRule macro to set the S-function sample time inheritance rule toUSE_DEFAULT_FOR_DISCRETE_INHERITANCE. Otherwise, set the rule to DISALLOW_SAMPLE_TIME_INHERITANCE to disallow sample-time inheritance for referenced models that include S-functions whose outputs depend on their inherited sample time and thereby avoid inadvertent simulation errors.

Note

If your S-function does not set this flag, the Simulink engine assumes that it does not preclude a referenced model containing it from inheriting a sample time. However, the engine optionally warns you that the referenced model contains S-functions that do not specify a sample-time inheritance rule (see Blocks Whose Outputs Depend on Inherited Sample Time).

If you are uncertain whether an existing S-function output depends on its inherited sample time, check whether it invokes any of the following C macros:

or TLC functions:

If your S-function does not invoke any of these macros or functions, its output does not depend on its inherited sample time and hence it is safe to use in referenced models that inherit their sample time.

Sample-Time Inheritance Rule Example

As an example of an S-function that precludes a referenced model from inheriting its sample time, consider an S-function that has the followingmdlOutputs method:

static void mdlOutputs(SimStruct *S, int_T tid) { const real_T u = (const real_T) ssGetInputPortSignal(S,0); real_T *y = ssGetOutputPortSignal(S,0); y[0] = ssGetSampleTime(S,tid) * u[0]; }

The output of this S-function is its inherited sample time, hence its output depends on its inherited sample time, and hence it is unsafe to use in a referenced model. For this reason, this S-function should specify its model reference inheritance rule as follows:

ssSetModelReferenceSampleTimeInheritanceRule (S, DISALLOW_SAMPLE_TIME_INHERITANCE);

See Also

ssSetSampleTime | ssGetSampleTime | ssSetInputPortSampleTime

Topics