Sfunctions PDF
Sfunctions PDF
Developing S-Functions
R2019a
How to Contact MathWorks
Phone: 508-647-7000
Introduction to S-Functions
1
What Is an S-Function? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-2
How S-Functions Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-2
Use S-Functions in Models . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-4
v
Selecting an S-Function Implementation
2
Available S-Function Implementations . . . . . . . . . . . . . . . . . . . 2-2
vi Contents
Level-1 MATLAB S-Function Outputs . . . . . . . . . . . . . . . . . . 3-14
Define S-Function Block Characteristics . . . . . . . . . . . . . . . . 3-15
Processing S-Function Parameters . . . . . . . . . . . . . . . . . . . . 3-16
Convert Level-1 MATLAB S-Functions to Level-2 . . . . . . . . . 3-16
Writing S-Functions in C
4
Create a Basic C MEX S-Function . . . . . . . . . . . . . . . . . . . . . . . 4-2
About C MEX S-Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-2
Introducing an Example of a Basic C MEX S-Function . . . . . . . 4-4
Defines and Includes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-6
Callback Method Implementations . . . . . . . . . . . . . . . . . . . . . 4-7
Simulink/Simulink Coder Interfaces . . . . . . . . . . . . . . . . . . . . 4-9
Building the Timestwo Example . . . . . . . . . . . . . . . . . . . . . . . 4-9
vii
Templates for C S-Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-41
About the Templates for C S-Functions . . . . . . . . . . . . . . . . . 4-41
S-Function Source File Requirements . . . . . . . . . . . . . . . . . . 4-41
The SimStruct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-43
Data Types in S-Functions . . . . . . . . . . . . . . . . . . . . . . . . . . 4-44
Compiling C S-Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-44
viii Contents
Convert Level-1 C MEX S-Functions . . . . . . . . . . . . . . . . . . . . 4-94
Guidelines for Converting Level-1 C MEX S-Functions to Level-2
............................................ 4-94
Obsolete Macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-96
ix
Run S-Function Analyzer
7
Check S-Functions Using S-Function Analyzer APIs . . . . . . . . 7-2
Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-2
Setup the Working Environment . . . . . . . . . . . . . . . . . . . . . . . 7-2
Run the S-Function Checks . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-3
Explore and Fix Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-5
x Contents
Using Elementary Work Vectors . . . . . . . . . . . . . . . . . . . . . . 8-21
Additional Work Vector Macros . . . . . . . . . . . . . . . . . . . . . . . 8-22
Elementary Work Vector Examples . . . . . . . . . . . . . . . . . . . . 8-23
xi
Zero Crossings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-42
xii Contents
Create and Update S-Function Run-Time Parameters . . . . . . 10-4
Create Run-Time Parameters . . . . . . . . . . . . . . . . . . . . . . . . 10-5
Update Run-Time Parameters . . . . . . . . . . . . . . . . . . . . . . . . 10-5
xiii
S-Function Callback Methods — Alphabetical List
11
xiv Contents
1
Introduction to S-Functions
What Is an S-Function?
S-functions (system-functions) provide a powerful mechanism for extending the
capabilities of the Simulink environment. An S-function is a computer language
description of a Simulink block written in MATLAB®, C, C++, or Fortran. C, C++, and
Fortran S-functions are compiled as MEX files using the mex utility (see “Build MEX File”
(MATLAB)). As with other MEX files, S-functions are dynamically linked subroutines that
the MATLAB execution engine can automatically load and execute.
S-functions use a special calling syntax called the S-function API that enables you to
interact with the Simulink engine. This interaction is very similar to the interaction that
takes place between the engine and built-in Simulink blocks.
S-functions follow a general form and can accommodate continuous, discrete, and hybrid
systems. By following a set of simple rules, you can implement an algorithm in an S-
function and use the S-Function block to add it to a Simulink model. After you write your
S-function and place its name in an S-Function block (available in the User-Defined
Functions block library), you can customize the user interface using masking (see “Create
Block Masks”).
If you have Simulink Coder™, you can use S-functions with the software. You can also
customize the code generated for S-functions by writing a Target Language Compiler
(TLC) file. For more information, see “S-Functions and Code Generation” (Simulink
Coder).
A Simulink block consists of a set of inputs, a set of states, a set of parameters, and a set
of outputs, where the outputs are a function of the simulation time, the inputs,
parameters, and the states.
1-2
What Is an S-Function?
The following equations express the mathematical relationships between the inputs,
outputs, parameters, states, and simulation time.
y = f 0(t, x, u) (Outputs)
ẋ = f d(t, x, u) (Derivatives)
xdk + 1 = f u(t, xc, xdk, u), (Update)
Simulation Stages
Execution of a Simulink model proceeds in stages. In the Initialization phase, the Simulink
engine incorporates library blocks into the model, propagates signal widths, data types,
and sample times, evaluates block parameters, determines block execution order, and
allocates memory. The engine then enters a simulation loop, where each pass through the
loop is referred to as a simulation step. During each simulation step, the engine executes
each block in the model in the order determined during initialization. For each block, the
engine invokes functions that compute the block states, derivatives, and outputs for the
current sample time. The entire simulation loop then continues until the simulation is
complete.
Model Initialization - Model is prepared for simulation. In this stage, block parameters are
evaluated, block execution order is determined, and memory for each operation is
allocated. After this stage, blocks go through a simulation loop.
Update of Continuous States and Time - Takes place only if the model has continuous
states. you can modify minor step methods such as mdlOutputs, mdlDerivatives, and
mdlZeroCrossing to compute the outputs
An S-function comprises a set of S-function callback methods that perform tasks required
at each simulation stage. During simulation of a model, at each simulation stage, the
Simulink engine calls the appropriate methods for each S-Function block in the model.
Tasks performed by S-function callback methods include:
1-3
1 Introduction to S-Functions
• Incorporating library blocks into the model, and propagating signal widths, data
types, and sample times
• Setting the number and dimensions of input and output ports
• Evaluating block parameters, and determine the block execution order
• Allocating memory and storage areas.
• Calculation of outputs — At his state, outputs are calculated until all the block output
ports are valid for the current time step, namely they are at a certain error range.
• Update discrete states — In this call, the block performs once-per-time-step activities
such as updating discrete states.
• Initialize and Terminate Methods — These optional methods perform initialization and
termination activities required by S-function only once. The initialization activities may
include setting up user data, or initializing state vectors in an S-function. The
termination method performs any actions such as freeing of memory that is required
when the simulation is termination, or when an S-function block is deleted from a
model.
• Integration — This applies to models with continuous states and/or nonsampled zero
crossings. If your S-function has continuous states, the engine calls the output and
derivative portions of your S-function at minor time steps. This is so the solvers can
compute the states for your S-function. If your S-function has nonsampled zero
crossings, the engine also calls the output and zero-crossings portions of your S-
function at minor time steps so that it can locate the zero crossings.
1-4
What Is an S-Function?
Note If the MATLAB path includes a C MEX file and a MATLAB file having the same
name referenced by an S-Function block, the S-Function block uses the C MEX file.
In both S-function block and Level-2 MATLAB S-Function Block Parameters window
allows you to specify parameter values to pass to the corresponding S-function. To use
these fields, you must know the parameters the S-function requires and the order in
which the function requires them. (If you do not know, consult the S-function's author,
documentation, or source code.) Enter the parameters, separated by a comma, in the
order required by the S-function. The parameter values can be constants, names of
variables defined in the MATLAB or model workspace, or MATLAB expressions.
The following example illustrates usage of the Parameters field to enter user-defined
parameters for a Level-2 MATLAB S-function.
1-5
1 Introduction to S-Functions
You can use the masking facility to create custom dialog boxes and icons for your S-
Function blocks. Masked dialog boxes can make it easier to specify additional parameters
for S-functions. For a discussion on masking, see “Create Block Masks”.
1-6
See Also
The most common use of S-functions is to create custom Simulink blocks (see “Block
Creation Basics”). When you use an S-function to create a general-purpose block, you can
use it many times in a model, varying parameters with each instance of the block.
See Also
Level-2 MATLAB S-Function | MATLAB Function | S-Function | S-Function Builder
More About
• “S-Function Concepts” on page 1-8
• “S-Function Callback Methods” on page 1-17
• “S-Function Features and Limitations” on page 2-7
1-7
1 Introduction to S-Functions
S-Function Concepts
In this section...
“Direct Feedthrough” on page 1-8
“Dynamically Sized Arrays” on page 1-9
“Setting Sample Times and Offsets” on page 1-10
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 signal. Typically, an
S-function input port has direct feedthrough if
• The output function (mdlOutputs) is a function of the input u. That is, there is direct
feedthrough if the input u is accessed by mdlOutputs. Outputs can also include
graphical outputs, as in the case of an XY Graph scope.
• The “time of next hit” function (mdlGetTimeOfNextVarHit) of a variable sample
time S-function accesses the input u.
An example of a system that requires its inputs (that is, has direct feedthrough) is the
operation
y = k × u,
An example of a system that does not require its inputs (that is, does not have direct
feedthrough) is the simple integration algorithm
y = x,
ẋ = u,
where x is the state, ẋ is the state derivative with respect to time, u is the input, and y is
the output. Simulink integrates the variable ẋ .
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 (see
“Algebraic Loop Concepts” in Using Simulink). If the simulation results for a model
1-8
S-Function Concepts
containing your S-function do not converge, or the simulation fails, you may have the
direct feedthrough flag set incorrectly. Try turning on the direct feedthrough flag and
setting the Algebraic loop solver diagnostic to warning (see the “Algebraic loop” option
on the “Model Configuration Parameters: Diagnostics” reference page in Simulink
Graphical User Interface). Subsequently running the simulation displays any algebraic
loops in the model and shows if the engine has placed your S-function within an algebraic
loop.
Note A dynamically sized input can have a different size for each instance of the S-
function in a particular model or during different simulations, however the input size of
each instance of the S-function is static over the course of a particular simulation.
A C MEX S-function and Level-2 MATLAB S-function can have multiple input and output
ports and each port can have different dimensions. The number of dimensions and the
size of each dimension can be determined dynamically.
For example, the following illustration 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. The Simulink engine automatically calls the block with the appropriately sized
input vector. Similarly, if other block characteristics, such as the number of outputs or the
1-9
1 Introduction to S-Functions
number of discrete or continuous states, are specified as dynamically sized, the engine
defines these vectors to be the same length as the input vector.
See “Input and Output Ports” on page 9-16 for more information on configuring S-
function input and output ports.
• Continuous sample time — For S-functions that have continuous states and/or
nonsampled zero crossings (see “Simulation Phases in Dynamic Systems” for an
explanation of zero crossings). For this type of S-function, the output changes in minor
time steps.
• Continuous, but fixed in minor time step sample time — For S-functions that need to
execute at every major simulation step, but do not change value during minor time
steps.
• Discrete sample time — If the behavior of your S-function is a function of discrete time
intervals, you can define a sample time to control when the Simulink engine calls the
S-function. You can also define an offset that delays each sample time hit. The value of
the offset cannot exceed the corresponding sample time.
where the integer n is the current simulation step. The first value of n is always zero.
If you define a discrete sample time, the engine calls the S-function mdlOutputs and
mdlUpdate routines at each sample time hit (as defined in the previous equation).
• Variable sample time — A discrete sample time where the intervals between sample
hits can vary. At the start of each simulation step, S-functions with variable sample
times are queried for the time of the next hit.
• Inherited sample time — Sometimes an S-function has no inherent sample time
characteristics (that is, it is either continuous or discrete, depending on the sample
time of some other block in the system). In this case, you can specify that the sample
time is inherited. A simple example of this is a Gain block that inherits its sample time
from the block driving it.
1-10
S-Function Concepts
S-functions can be either single or multirate; a multirate S-function has multiple sample
times.
[CONTINUOUS_SAMPLE_TIME, 0.0]
[CONTINUOUS_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET]
[discrete_sample_time_period, offset]
[VARIABLE_SAMPLE_TIME, 0.0]
where
CONTINUOUS_SAMPLE_TIME = 0.0
FIXED_IN_MINOR_STEP_OFFSET = 1.0
VARIABLE_SAMPLE_TIME = -2.0
Alternatively, you can specify that the sample time is inherited from the driving block. In
this case, the C MEX S-function has only one sample time pair, either
[INHERITED_SAMPLE_TIME, 0.0]
or
[INHERITED_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET]
where
1-11
1 Introduction to S-Functions
INHERITED_SAMPLE_TIME = -1.0
The valid sample time pairs for a Level-2 MATLAB S-function are
where variable names in italics indicate that a real value is required. When using a
continuous sample time, an offset of 1 indicates the output is fixed in minor integration
time steps. An offset of 0 indicates the output changes at every minor integration time
step.
Use the following guidelines for help with specifying sample times:
• A continuous S-function that changes during minor integration steps should register
the [CONTINUOUS_SAMPLE_TIME, 0.0] sample time.
• A continuous S-function that does not change during minor integration steps should
register the [CONTINUOUS_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET]
sample time.
• A discrete S-function that changes at a specified rate should register the discrete
sample time pair, [discrete_sample_time_period, offset], where
and
[VARIABLE_SAMPLE_TIME, 0.0]
1-12
See Also
If your S-function has no intrinsic sample time, you must indicate that your sample time is
inherited. There are two cases:
• An S-function that changes as its input changes, even during minor integration steps,
should register the [INHERITED_SAMPLE_TIME, 0.0] sample time.
• An S-function that changes as its input changes, but does not change during minor
integration steps (that is, remains fixed during minor time steps), should register the
[INHERITED_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET] sample time.
The Scope block is a good example of this type of block. This block runs at the rate of
its driving block, either continuous or discrete, but never runs in minor steps. If it did,
the scope display would show the intermediate computations of the solver rather than
the final result at each time point.
See “Specify S-Function Sample Times” on page 9-26 for information on implementing
different types of sample times in S-functions.
See Also
Level-2 MATLAB S-Function | MATLAB Function | S-Function | S-Function Builder
More About
• “Use S-Functions in Models” on page 1-4
• “S-Function Callback Methods” on page 1-17
• “S-Function Features and Limitations” on page 2-7
1-13
1 Introduction to S-Functions
Implementing S-Functions
In this section...
“MATLAB S-Functions” on page 1-14
“MEX S-Functions” on page 1-15
MATLAB S-Functions
Level-2 MATLAB S-functions allow you to create blocks with many of the features and
capabilities of Simulink built-in blocks, including:
The template consists of a top-level setup function and a set of skeleton local functions,
each of which corresponds to a particular callback method. Each callback method
performs a specific S-function task at a particular point in the simulation. The engine
invokes the local functions using function handles defined in the setup routine. See
“Level-2 MATLAB S-Function Callback Methods” on page 3-4 for a table of the
supported Level-2 MATLAB S-function callback methods.
We recommend that you follow the structure and naming conventions of the templates
when creating Level-2 MATLAB S-functions. This makes it easier for others to understand
and maintain the MATLAB S-functions that you create. See “Write Level-2 MATLAB S-
Functions” on page 3-2 for information on creating Level-2 MATLAB S-functions.
1-14
See Also
MEX S-Functions
Like a Level-2 MATLAB S-function, a MEX S-function consists of a set of callback methods
that the Simulink engine invokes to perform various block-related tasks during a
simulation. MEX S-functions can be implemented in C, C++, or Fortran. The engine
directly invokes MEX S-function routines instead of using function handles as with
MATLAB S-functions. Because the engine invokes the functions directly, MEX S-functions
must follow standard naming conventions specified by the S-function API.
The template contains skeleton implementations of all the required and optional callback
methods that a C MEX S-function can implement.
Level-2 MATLAB and MEX S-functions each have advantages. The advantage of Level-2
MATLAB S-functions is speed of development. Developing Level-2 MATLAB S-functions
avoids the time consuming compile-link-execute cycle required when developing in a
compiled language. Level-2 MATLAB S-functions also have easier access to MATLAB
toolbox functions and can utilize the MATLAB Editor/Debugger.
MEX S-functions are more appropriate for integrating legacy code into a Simulink model.
For more complicated systems, MEX S-functions may simulate faster than MATLAB S-
functions because the Level-2 MATLAB S-function calls the MATLAB execution engine for
every callback method.
See Also
Level-2 MATLAB S-Function | MATLAB Function | S-Function | S-Function Builder
More About
• “S-Function Concepts” on page 1-8
• “S-Function Callback Methods” on page 1-17
1-15
1 Introduction to S-Functions
1-16
S-Function Callback Methods
The S-function callback methods perform tasks required at each simulation stage. During
simulation of a model, at each simulation stage the Simulink engine calls the appropriate
methods for each S-Function block in the model.
• Initialization — Prior to the first simulation loop, the engine initializes the S-function,
including:
1-17
1 Introduction to S-Functions
crossings, the engine also calls the output and zero-crossings portions of your S-
function at minor time steps so that it can locate the zero crossings.
Note See “Simulation Phases in Dynamic Systems” for an explanation of major and
minor time steps.
Some callback methods are optional. The engine invokes an optional callback only if the
S-function defines the callback.
For information on writing callback methods, see “Write Callback Methods” on page 4-
83.
The following callback methods are optional. The engine invokes an optional callback only
if the S-function defines the callback.
• mdlCheckParameters
• mdlDerivatives
• mdlDisable
• mdlEnable
• mdlGetSimState
• mdlGetTimeOfNextVarHit
• mdlInitializeConditions
1-18
S-Function Callback Methods
• mdlProcessParameters
• mdlProjection
• mdlRTW
• mdlSetDefaultPortComplexSignals
• mdlSetDefaultPortDataTypes
• mdlSetDefaultPortDimensionInfo
• mdlSetInputPortComplexSignal
• mdlSetInputPortDataType
• mdlSetInputPortDimensionInfo
• mdlSetInputPortDimensionsModeFcn
• mdlSetInputPortSampleTime
• mdlSetInputPortWidth
• mdlSetOutputPortComplexSignal
• mdlSetOutputPortDataType
• mdlSetOutputPortDimensionInfo
• mdlSetOutputPortSampleTime
• mdlSetOutputPortWidth
• mdlSetSimState
• mdlSetWorkWidths
• mdlSimStatusChange
• mdlSetupRuntimeResources
• mdlCleanupRuntimeResources
• mdlStart
• mdlUpdate
• mdlZeroCrossings
1-19
1 Introduction to S-Functions
• setup – Specifies the sizes of various parameters in the SimStruct, such as the
number of output ports for the block.
• Outputs – Calculates the output of the block.
• Terminate – Performs any actions required at the termination of the simulation. If no
actions are required, this function can be implemented as a stub.
For information on writing callback methods, see “Write Level-2 MATLAB S-Functions” on
page 3-2.
The following callback methods are optional. The engine invokes an optional callback only
if the S-function defines the callback.
• CheckParameters
• Derivatives
• Disable
• Enable
• GetSimState
• InitializeConditions
• PostPropagationSetup
• ProcessParameters
• Projection
• SetInputPortComplexSignal
• SetInputPortDataType
• SetInputPortDimensions
• SetInputPortDimensionsMode
• SetInputPortSampleTime
• SetOutputPortComplexSignal
• SetOutputPortDataType
• SetOutputPortDimensions
• SetOutputPortSampleTime
• SetSimState
1-20
See Also
• SimStatusChange
• Start
• Update
• WriteRTW
See Also
Level-2 MATLAB S-Function | MATLAB Function | S-Function | S-Function Builder
More About
• “S-Function Concepts” on page 1-8
• “Use S-Functions in Models” on page 1-4
• “S-Function Features and Limitations” on page 2-7
1-21
1 Introduction to S-Functions
S-Function Compatibility
User-written level-2 S-functions are backward compatible in terms of their source code
(C/C++). An S-function written in an older release that is recompiled in a newer release
retains the functionality and behavior from the older release.
In addition, user-written level-2 S-function MEX files are backward compatible. For each
release, all example S-function MEX files included in the previous 10 releases of MATLAB
on the Windows® platform (MATLAB) are tested for backward compatibility. In general, S-
function MEX files created more than 10 releases before a new release can work in a new
release if the platform and associated libraries either remain unchanged or maintain
backward compatibility.
Note If a user-written S-function contains code that depends on additional libraries (e.g.,
by using the ‘-l’ option with the MEX command), S-function compatibility might not be
supported with a library update, a newer release of MATLAB, or a platform upgrade.
For best results, recompile the S-function source code in your current version of MATLAB.
For more information on MEX compatibility, see “Version Compatibility” (MATLAB).
1-22
S-Function Examples
S-Function Examples
In this section...
“Overview of Examples” on page 1-23
“Level-2 MATLAB S-Function Examples” on page 1-26
“Level-1 MATLAB S-Function Examples” on page 1-26
“C S-Function Examples” on page 1-27
“Fortran S-Function Examples” on page 1-31
“C++ S-Function Examples” on page 1-32
“Organizing S-Function in a Project” on page 1-32
Overview of Examples
To run an example:
1-23
1 Introduction to S-Functions
1-24
S-Function Examples
It might be helpful to examine some sample S-functions as you read the next chapters.
Code for the examples is stored in the following folder under the MATLAB root folder.
1-25
1 Introduction to S-Functions
Filename Description
csfunc.m Define a continuous system in state-space format.
dsfunc.m Define a discrete system in state-space format.
1-26
S-Function Examples
Filename Description
limintm.m Implement a continuous limited integrator where the
output is bounded by lower and upper bounds and
includes initial conditions.
mixedm.m Implement a hybrid system consisting of a continuous
integrator in series with a unit delay.
sfun_varargm.m Implement an S-function that shows how to use the
MATLAB command varargin.
vsfunc.m Illustrate how to create a variable sample time block.
This S-function implements a variable step delay in
which the first input is delayed by an amount of time
determined by the second input.
C S-Function Examples
The matlabroot/toolbox/simulink/simdemos/simfeatures/src folder (open)
contains examples of C MEX S-functions, many of which have a MATLAB S-function
counterpart. The C MEX S-functions are listed in the following table.
1-27
1 Introduction to S-Functions
1-28
S-Function Examples
1-29
1 Introduction to S-Functions
dx/dt = Ax + Bu
y = Cx + Du
1-30
S-Function Examples
1-31
1 Introduction to S-Functions
Filename Description
slexSfunctionExamplesProject Organize S-function artifacts into a single
project.
See Also
Level-2 MATLAB S-Function | MATLAB Function | S-Function | S-Function Builder
More About
• “S-Function Concepts” on page 1-8
• “Use S-Functions in Models” on page 1-4
• “S-Function Callback Methods” on page 1-17
1-32
2
Selecting an S-Function
Implementation
The following sections describe the uses, features, and differences of these S-function
implementations. The last section compares using a handwritten C MEX S-function, the S-
Function Builder, and the Legacy Code Tool to incorporate an existing C function into
your Simulink model.
2-2
S-Function Types
S-Function Types
Consider the following questions if you are unclear about what type of S-function is best
for your application.
2-3
2 Selecting an S-Function Implementation
Implement S-Functions
The following table gives an overview of how to write different types of S-functions. See
the associated sections of the S-function documentation for more details on how to
implement S-functions using a particular method.
Note For backward compatibility, the following table and sections contain information
about Level-1 MATLAB S-functions. However, use the Level-2 MATLAB S-function API to
develop new MATLAB S-functions.
2-4
Implement S-Functions
2-5
2 Selecting an S-Function Implementation
lct_spec = legacy_code('initialize');
2 Generate and compile the wrapper S-function.
legacy_code('sfcn_cmex_generate', lct_spec);
legacy_code('compile', lct_spec);
3 Instantiate an S-Function block that calls the S-function wrapper.
legacy_code('slblock_generate', lct_spec);
4 Generate a TLC file to inline the S-function during code generation.
legacy_code('sfcn_tlc_generate', lct_spec);
2-6
S-Function Features and Limitations
S-Function Features
The following tables give overviews of the features supported by different types of S-
functions. The first table focuses on handwritten S-functions. The second table compares
the features of S-functions automatically generated by the S-Function Builder or Legacy
Code Tool.
2-7
2 Selecting an S-Function Implementation
2-8
S-Function Features and Limitations
2-9
2 Selecting an S-Function Implementation
2-10
S-Function Features and Limitations
S-Function Limitations
The following table summarizes the major limitations of the different types of S-functions.
Implementation Limitations
Level-1 MATLAB S- Does not support the majority of S-function features. See the “S-Function
function Features and Limitations” on page 2-7 section for information on what
features a Level-1 MATLAB S-function does support.
Level-2 MATLAB S- • Does not support bus input and output signals.
functions • Cannot incorporate legacy code during simulation, only during code
generation through a TLC file.
Handwritten C MEX S- Supports model reference with some limitations. See “S-Functions in
function Referenced Models”.
2-11
2 Selecting an S-Function Implementation
Implementation Limitations
S-Function Builder • Generates S-function code using a wrapper function which incurs
additional overhead.
• Does not support the following S-function features:
• Work vectors
• Port-based sample times
• Multiple sample times or a nonzero offset time
• Dynamically-sized input and output signals for an S-function with
multiple input and output ports
Note S-functions with one input and one output port can have
dynamically-sized signals
Legacy Code Tool • Generates C MEX S-functions for existing functions written in C or C
++ only. The tool does not support transformation of MATLAB or
Fortran functions.
• Can interface with C++ functions, but not C++ objects.
• Does not support simulating continuous or discrete states.
• Does not support use of function pointers as the output of the legacy
function being called.
• Always sets the S-function's flag for direct feedthrough on page 1-8
(sizes.DirFeedthrough) to true.
• Supports only the continuous, but fixed in minor time step, sample
time and offset on page 1-10 option.
• Supports complex numbers, but only with Simulink built-in data
types.
• Does not support the following S-function features:
2-12
S-Functions Incorporate Legacy C Code
Overview
C MEX S-functions allow you to call existing C code within your Simulink models. For
example, consider the simple C function doubleIt.c that outputs a value two times the
value of the function input.
double doubleIt(double u)
{
return(u * 2.0);
}
• Writing a wrapper S-function on page 2-14. Using this method, you hand write a new
C S-function and associated TLC file. This method requires the most knowledge about
the structure of a C S-function.
• Using an S-Function Builder block on page 2-16. Using this method, you enter the
characteristics of the S-function into a block dialog. This method does not require any
knowledge about writing S-functions. However, a basic understanding of the structure
of an S-function can make the S-Function Builder dialog box easier to use.
• Using the Legacy Code Tool on page 2-19. Using this command line method, you
define the characteristics of your S-function in a data structure in the MATLAB
workspace. This method requires the least amount of knowledge about S-functions.
You can also call external C code from a Simulink model using a MATLAB Function block.
For more information see “Integrate C Code Using the MATLAB Function Block”.
The following sections describe how to create S-functions for use in a Simulink simulation
and with Simulink Coder code generation, using the previous three methods. The model
sfcndemo_choosing_sfun contains blocks that use these S-functions. Copy this model
2-13
2 Selecting an S-Function Implementation
and the files doubleIt.c and doubleIt.h from the folder docroot/toolbox/
simulink/sfg/examples into your working folder if you plan to step through the
examples.
To incorporate the legacy code into the S-function, wrapsfcn.c begins by declaring
doubleIt.c with the following line:
extern real_T doubleIt(real_T u);
2-14
S-Functions Incorporate Legacy C Code
Once declared, the S-function can use doubleIt.c in its mdlOutputs method. For
example:
/* Function: mdlOutputs =======================================
* Abstract:
* Calls the doubleIt.c function to multiple the input by 2.
*/
static void mdlOutputs(SimStruct *S, int tid){
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
real_T *y = ssGetOutputPortRealSignal(S,0);
*y = doubleIt(*uPtrs[0]);
}
To compile the wrapsfcn.c S-function, run the following mex command. Make sure that
the doubleIt.c file is in your working folder.
To generate code for the S-function using the Simulink Coder code generator, you need to
write a Target Language Compiler (TLC) file. The following TLC file wrapsfcn.tlc uses
the BlockTypeSetup function to declare a function prototype for doubleIt.c. The TLC
file's Outputs function then tells the Simulink Coder code generator how to inline the
call to doubleIt.c. For example:
%implements "wrapsfcn" "C"
%% File : wrapsfcn.tlc
%% Abstract:
%% Example tlc file for S-function wrapsfcn.c
%%
%closefile buffer
%<LibCacheFunctionPrototype(buffer)>
%%endfunction %% BlockTypeSetup
2-15
2 Selecting an S-Function Implementation
%endfunction %% Outputs
For more information on the TLC, see “Target Language Compiler Basics” (Simulink
Coder).
• The S-function name field in the Parameters pane defines the name
builder_wrapsfcn for the generated S-function.
• The Data Properties pane names the input and output ports as in1 and out1,
respectively.
• The Libraries pane provides the interface to the legacy code.
• The Library/Object/Source files field contains the source file name doubleIt.c.
• The Includes field contains the following line to include the header file that
declares the legacy function:
#include <doubleIt.h>
• The Outputs pane calls the legacy function with the lines:
*out1 = doubleIt(*in1);
2-16
S-Functions Incorporate Legacy C Code
• The Build Info pane selects the Generate wrapper TLC option.
When you click Build, the S-Function Builder generates three files.
• The file begins with a set of #define statements that incorporate the information
from the S-Function Builder. For example, the following lines define the first input
port:
#define NUM_INPUTS 1
/* Input Port 0 */
#define IN_PORT_0_NAME in1
#define INPUT_0_WIDTH 1
#define INPUT_DIMS_0_COL 1
#define INPUT_0_DTYPE real_T
#define INPUT_0_COMPLEX COMPLEX_NO
#define IN_0_FRAME_BASED FRAME_NO
#define IN_0_DIMS 1-D
#define INPUT_0_FEEDTHROUGH 1
• Next, the file declares all the wrapper functions found in the
builder_wrapsfcn_wrapper.c file. This example requires only a wrapper function
for the Outputs code.
extern void builder_wrapsfcn_Outputs_wrapper(const real_T *in1,
real_T *out1);
• Following these definitions and declarations, the file contains the S-function methods,
such as mdlInitializeSizes, that initialize the S-function's input ports, output
ports, and parameters. See “Process View” on page 4-71 for a list of methods that are
called during the S-function initialization phase.
• The file mdlOutputs method calls the builder_wrapsfcn_wrapper.c function. The
method uses the input and output names in1 and out1, as defined in the Data
Properties pane, when calling the wrapper function. For example:
/* Function: mdlOutputs =============================================
*
2-17
2 Selecting an S-Function Implementation
*/
static void mdlOutputs(SimStruct *S, int_T tid)
{
const real_T *in1 = (const real_T*) ssGetInputPortSignal(S,0);
real_T *out1 = (real_T *)ssGetOutputPortRealSignal(S,0);
builder_wrapsfcn_Outputs_wrapper(in1, out1);
}
• The Include Files section includes the doubleIt.h file, along with the standard
S-function header files:
/*
* Include Files
*
*/
#if defined(MATLAB_MEX_FILE)
#include "tmwtypes.h"
#include "simstruc_types.h"
#else
#include "rtwtypes.h"
#endif
/* %%%-SFUNWIZ_wrapper_includes_Changes_BEGIN --- EDIT HERE TO _END */
#include <math.h>
#include <doubleIt.h>
/* %%%-SFUNWIZ_wrapper_includes_Changes_END --- EDIT HERE TO _BEGIN */
*out1 = doubleIt(*in1);
/* %%%-SFUNWIZ_wrapper_Outputs_Changes_END --- EDIT HERE TO _BEGIN */
}
2-18
S-Functions Incorporate Legacy C Code
Note Compared to a handwritten S-function, the S-Function Builder places the call to the
legacy C function down an additional level through the wrapper file
builder_wrapsfcn_wrapper.c.
%%
%endfunction
2-19
2 Selecting an S-Function Implementation
typing lct_wrapsfcn at the MATLAB command prompt. The script creates and compiles
the S-function legacy_wrapsfcn.c and creates the TLC file legacy_wrapsfcn.tlc
via the following commands.
% Create the data structure
def = legacy_code('initialize');
% Generate a TLC-file
legacy_code('sfcn_tlc_generate', def);
/*
* Call the legacy code function
*/
*y1 = doubleIt( *u1);
}
The S-function generated by the Legacy Code Tool differs from the S-function generated
by the S-Function Builder as follows:
• The S-function generated by the S-Function Builder calls the legacy function
doubleIt.c through the wrapper function builder_wrapsfcn_wrapper.c. The S-
function generated by the Legacy Code Tool directly calls doubleIt.c from its
mdlOutputs method.
• The S-Function Builder uses the input and output names entered into the Data
Properties pane, allowing you to customize these names in the S-function. The
2-20
S-Functions Incorporate Legacy C Code
Legacy Code Tool uses the default names y and u for the outputs and inputs,
respectively. You cannot specify customized names to use in the generated S-function
when using the Legacy Code Tool.
• The S-Function Builder and Legacy Code Tool both specify an inherited sample time,
by default. However, the S-Function Builder uses an offset time of 0.0 while the
Legacy Code Tool specifies that the offset time is fixed in minor time steps.
2-21
2 Selecting an S-Function Implementation
%%
%assign u1_val = LibBlockInputSignal(0, "", "", 0)
%assign y1_val = LibBlockOutputSignal(0, "", "", 0)
%%
%switch retType
%case "Signal"
%if portIdx == 0
%return "doubleIt( %<u1_val>)"
%else
%assign errTxt = "Block output port index not supported: %<portIdx>"
%endif
%default
%assign errTxt = "Unsupported return type: %<retType>"
%<LibBlockReportError(block,errTxt)>
%endswitch
%%
%endfunction
2-22
3
A Level-2 MATLAB S-function is MATLAB function that defines the properties and
behavior of an instance of a Level-2 MATLAB S-Function block that references the
MATLAB function in a Simulink model. The MATLAB function itself comprises a set of
callback methods (see “Level-2 MATLAB S-Function Callback Methods” on page 3-4)
that the Simulink engine invokes when updating or simulating the model. The callback
methods perform the actual work of initializing and computing the outputs of the block
defined by the S-function.
To facilitate these tasks, the engine passes a run-time object to the callback methods as
an argument. The run-time object effectively serves as a MATLAB proxy for the S-
3-2
Write Level-2 MATLAB S-Functions
Function block, allowing the callback methods to set and access the block properties
during simulation or model updating.
Run-time objects do not support MATLAB sparse matrices. For example, if the variable
block is a run-time object, the following line in a Level-2 MATLAB S-function produces
an error:
block.Outport(1).Data = speye(10);
Note Other MATLAB programs besides MATLAB S-functions can use run-time objects to
obtain information about a MATLAB S-function in a model that is simulating. See “Access
Block Data During Simulation” in Using Simulink for more information.
To create a MATLAB S-function, make a copy of the template and edit the copy as
necessary to reflect the desired behavior of the S-function you are creating. The following
two sections describe the contents of the MATLAB code template. The section “Example
3-3
3 Writing S-Functions in MATLAB
of Writing a Level-2 MATLAB S-Function” on page 3-6 describes how to write a Level-2
MATLAB S-function that models a unit delay.
Your S-function can contain other methods, depending on the requirements of the block
that the S-function defines. The methods defined by the Level-2 MATLAB S-function API
generally correspond to similarly named methods defined by the C MEX S-function API.
For information on when these methods are called during simulation, see “Process View”
on page 4-71 in “Simulink Engine Interaction with C S-Functions” on page 4-71. For
instructions on how to implement each callback method, see “Write Callback Methods” on
page 4-83.
The following table lists all the Level-2 MATLAB S-function callback methods and their C
MEX counterparts.
3-4
Write Level-2 MATLAB S-Functions
3-5
3 Writing S-Functions in MATLAB
• Specifying the block sample time. See “Specify Sample Time” in Using Simulink for
more information on how to specify valid sample times.
• Setting the number of S-function dialog parameters.
• Registering S-function callback methods by passing the handles of local functions in
the MATLAB S-function to the RegBlockMethod method of the S-Function block's
run-time object. See the documentation for Simulink.MSFcnRunTimeBlock for
information on using the RegBlockMethod method.
3-6
Write Level-2 MATLAB S-Functions
• Call the run-time object's RegBlockMethod method to register the following four
callback methods used in this S-function.
• PostPropagationSetup
• InitializeConditions
• Outputs
• Update
Remove any other registered callback methods from your copy of the template
file. In the calls to RegBlockMethod, the first input argument is the name of the
S-function API method and the second input argument is the function handle to
the associated local function in the MATLAB S-function.
The following setup method from msfcn_unit_delay.m performs the previous list
of steps:
function setup(block)
block.OutputPort(1).Dimensions = 1;
%% Register methods
block.RegBlockMethod('PostPropagationSetup',@DoPostPropSetup);
block.RegBlockMethod('InitializeConditions',@InitConditions);
3-7
3 Writing S-Functions in MATLAB
block.RegBlockMethod('Outputs', @Output);
block.RegBlockMethod('Update', @Update);
If your S-function needs continuous states, initialize the number of continuous states
in the setup method using the run-time object's NumContStates property. Do not
initialize discrete states in the setup method.
3 Initialize the discrete states in the PostPropagationSetup method. A Level-2
MATLAB S-function stores discrete state information in a DWork vector. The default
PostPropagationSetup method in the template file suffices for this example.
%% Setup Dwork
block.NumDworks = 1;
block.Dwork(1).Name = 'x0';
block.Dwork(1).Dimensions = 1;
block.Dwork(1).DatatypeID = 0;
block.Dwork(1).Complexity = 'Real';
block.Dwork(1).UsedAsDiscState = true;
For this example, use the InitializeConditions method to set the discrete state's
initial condition to the value of the S-function's dialog parameter. For example, the
InitializeConditions method in msfcn_unit_delay.m is:
function InitConditions(block)
%% Initialize Dwork
block.Dwork(1).Data = block.DialogPrm(1).Data;
For S-functions with continuous states, use the ContStates run-time object method
to initialize the continuous state data. For example:
3-8
Write Level-2 MATLAB S-Functions
block.ContStates.Data(1) = 1.0;
5 Calculate the S-function's outputs in the Outputs callback method. For this example,
set the output to the current value of the discrete state stored in the DWork vector.
function Output(block)
block.OutputPort(1).Data = block.Dwork(1).Data;
6 For an S-function with continuous states, calculate the state derivatives in the
Derivatives callback method. Run-time objects store derivative data in their
Derivatives property. For example, the following line sets the first state derivative
equal to the value of the first input signal.
block.Derivatives.Data(1) = block.InputPort(1).Data;
This example does not use continuous states and, therefore, does not implement the
Derivatives callback method.
7 Update any discrete states in the Update callback method. For this example, set the
value of the discrete state to the current value of the first input signal.
function Update(block)
block.Dwork(1).Data = block.InputPort(1).Data;
8 Perform any cleanup, such as clearing variables or memory, in the Terminate
method. Unlike C MEX S-functions, Level-2 MATLAB S-function are not required to
have a Terminate method.
3-9
3 Writing S-Functions in MATLAB
name field. If your S-function uses any additional parameters, enter the parameter values
as a comma-separated list in the Block Parameters dialog box Parameters field.
function DoPostPropSetup(block)
%Register dependency rules to update current output size of output port a depending on
%input ports b and c
block.AddOutputDimsDependencyRules(a, [b c], @setOutputVarDims);
%Configure DWork a to have its size reset when input size changes.
block.DWorkRequireResetForSignalSize(a,true);
3-10
See Also
See Also
Level-2 MATLAB S-Function | MATLAB Function | S-Function | S-Function Builder
More About
• “S-Function Concepts” on page 1-8
• “S-Function Examples” on page 1-23
• “Configure Block Features for MATLAB S-Functions”
3-11
3 Writing S-Functions in MATLAB
In this section...
“About the Maintenance of Level-1 MATLAB S-Functions” on page 3-12
“Level-1 MATLAB S-Function Arguments” on page 3-13
“Level-1 MATLAB S-Function Outputs” on page 3-14
“Define S-Function Block Characteristics” on page 3-15
“Processing S-Function Parameters” on page 3-16
“Convert Level-1 MATLAB S-Functions to Level-2” on page 3-16
Note The information provided in this section is intended only for use in maintaining
existing Level-1 MATLAB S-functions. Use the more capable Level-2 API to develop new
MATLAB S-functions (see “Write Level-2 MATLAB S-Functions” on page 3-2). Level-1
MATLAB S-functions support a much smaller subset of the S-function API then Level-2
MATLAB S-functions, and their features are limited compared to built-in blocks.
[sys,x0,str,ts]=f(t,x,u,flag,p1,p2,...)
where f is the name of the S-function. During simulation of a model, the Simulink engine
repeatedly invokes f, using the flag argument to indicate the task (or tasks) to be
performed for a particular invocation. The S-function performs the task and returns the
results in an output vector.
3-12
Maintain Level-1 MATLAB S-Functions
t Current time
x State vector
u Input vector
flag Integer value that indicates the task to be performed by the S-
function
The following table describes the values that flag can assume and lists the
corresponding Level-2 MATLAB S-function method for each value.
3-13
3 Writing S-Functions in MATLAB
Flag Argument
• sys, a generic return argument. The values returned depend on the flag value. For
example, for flag = 3, sys contains the S-function outputs.
• x0, the initial state values (an empty vector if there are no states in the system). x0 is
ignored, except when flag = 0.
• str, originally intended for future use. Level-1 MATLAB S-functions must set this to
the empty matrix, [].
3-14
Maintain Level-1 MATLAB S-Functions
• ts, a two-column matrix containing the sample times and offsets of the block (see
“Specify Sample Time” in Using Simulink for information on how to specify a sample
times and offsets).
For example, if you want your S-function to run at every time step (continuous sample
time), set ts to [0 0]. If you want your S-function to run at the same rate as the
block to which it is connected (inherited sample time), set ts to [-1 0]. If you want it
to run every 0.25 seconds (discrete sample time) starting at 0.1 seconds after the
simulation start time, set ts to [0.25 0.1].
You can create S-functions that do multiple tasks, each at a different sample rate (i.e.,
a multirate S-function). In this case, ts should specify all the sample rates used by
your S-function in ascending order by sample time. For example, suppose your S-
function performs one task every 0.25 second starting from the simulation start time
and another task every 1 second starting 0.1 second after the simulation start time. In
this case, your S-function should set ts equal to [.25 0; 1.0 .1]. This will cause
the Simulink engine to execute the S-function at the following times: [0 0.1 0.25
0.5 0.75 1 1.1 ...]. Your S-function must decide at every sample time which
task to perform at that sample time.
You can also create an S-function that performs some tasks continuously (i.e., at every
time step) and others at discrete intervals.
To provide this information, call the simsizes function at the beginning of the S-
function.
sizes = simsizes;
This function returns an uninitialized sizes structure. You must load the sizes structure
with information about the S-function. The table below lists the fields of the sizes
structure and describes the information contained in each field.
3-15
3 Writing S-Functions in MATLAB
sys = simsizes(sizes);
This passes the information in the sizes structure to sys, a vector that holds the
information for use by the Simulink engine.
3-16
Maintain Level-1 MATLAB S-Functions
function callback method. See the Flag Arguments on page 3-13 table for a mapping of
Level-1 flags to Level-2 callback methods. In addition:
• Store discrete state information for Level-2 MATLAB S-functions in DWork vectors,
initialized in the PostPropagationSetup method.
• Access Level-2 MATLAB S-function dialog parameters using the DialogPrm run-time
object property, instead of passing them into the S-function as function arguments.
• For S-functions with variable sample times, update the NextTimeHit run-time object
property in the Outputs method to set the next sample time hit for the Level-2
MATLAB S-function.
For example, the following table shows how to convert the Level-1 MATLAB S-function
sfundsc2.m to a Level-2 MATLAB S-function. The example uses the Level-2 MATLAB S-
function template msfuntmpl_basic.m as a starting point when converting the Level-1
MATLAB S-function. The line numbers in the table corresponds to the lines of code in
sfundsc2.m.
3-17
3 Writing S-Functions in MATLAB
%% Setup Dwork
block.NumDworks = 1;
block.Dwork(1).Name = 'x0';
block.Dwork(1).Dimensions = 1;
block.Dwork(1).DatatypeID = 0;
block.Dwork(1).Complexity = 'Real';
block.Dwork(1).UsedAsDiscState = true;
%% Initialize Dwork
block.Dwork(1).Data = 0
3-18
Maintain Level-1 MATLAB S-Functions
3-19
4
Writing S-Functions in C
• Handwritten S-function — You can write a C MEX S-function from scratch. (“Create a
Basic C MEX S-Function” on page 4-2 provides a step-by-step example.) See
“Templates for C S-Functions” on page 4-41 for a complete skeleton implementation
of a C MEX S-function that you can use as a starting point for creating your own S-
functions.
• S-Function Builder — This block integrates a C/C++ code and builds a C MEX S-
function from specifications and code fragments that you supply using a graphical user
interface. This eliminates the need for you to write S-functions from scratch. See
“Build S-Functions Automatically” on page 4-10 for more information about the S-
Function Builder.
• Legacy Code Tool — This utility builds a C MEX S-function from existing C code and
specifications that you supply using MATLAB code. See “Integrate C Functions Using
Legacy Code Tool” on page 4-45 for more information about integrating legacy C
code into Simulink models.
Each of these approaches involves a tradeoff between the ease of writing an S-function
and the features supported by the S-function. Although handwritten S-functions support
the widest range of features, they can be difficult to write. The S-Function Builder block
simplifies the task of writing C MEX S-functions but supports fewer features. The Legacy
Code Tool provides the easiest approach to creating C MEX S-functions from existing C
code but supports the fewest features. See “Available S-Function Implementations” on
page 2-2 for more information on the features and limitations of each of these approaches
to writing a C MEX S-function.
4-2
Create a Basic C MEX S-Function
If you have Simulink Coder, in addition to the previous three approaches, the Simulink
Coder product provides a method for generating a C MEX S-function from a graphical
subsystem. If you are new to writing C MEX S-functions, you can build portions of your
application in a Simulink subsystem and use the S-function target to convert it to an S-
function. The generated files provides insight on how particular blocks can be
implemented within an S-function. For details and limitations on using the S-function
target, see “Accelerate Simulation, Reuse Code, or Protect Intellectual Property by Using
S-Function Target” (Simulink Coder).
A C MEX S-function must provide information about the function to the Simulink engine
during the simulation. As the simulation proceeds, the engine, the ODE solver, and the C
MEX S-function interact to perform specific tasks. These tasks include defining initial
conditions and block characteristics, and computing derivatives, discrete states, and
outputs.
As with MATLAB S-functions, the Simulink engine interacts with a C MEX S-function by
invoking callback methods that the S-function implements. Each method performs a
predefined task, such as computing block outputs, required to simulate the block whose
functionality the S-function defines. However, the S-function is free to perform the task in
each method according to the functionality the S-function implements. For example, the
mdlOutputs method must compute the block outputs at the current simulation time.
However, the S-function can calculate these outputs in any way that is appropriate for the
function. This callback-based API allows you to create S-functions, and hence custom
blocks, of any desired functionality.
The set of callback methods that C MEX S-functions can implement is larger than that
available for MATLAB S-functions. C MEX S-functions are required to implement only a
small subset of the callback methods in the S-function API. If your block does not
implement a particular feature, such as matrix signals, you are free to omit the callback
methods needed to implement a feature. This allows you to create simple blocks very
quickly.
4-3
4 Writing S-Functions in C
mdlInitializeSizes is the first routine the Simulink engine calls when interacting
with the S-function. The engine subsequently invokes other S-function methods (all
starting with mdl). At the end of a simulation, the engine calls mdlTerminate.
The following model uses the timestwo S-function to double the amplitude of a sine
wave and plot it in a scope.
The block dialog for the S-function specifies timestwo as the S-function name; the
parameters field is empty.
The timestwo S-function contains the S-function callback methods shown in this figure.
At the end of S-function, include the code snippet as described in “Simulink/Simulink
Coder Interfaces” on page 4-9.
4-4
Create a Basic C MEX S-Function
The contents of timestwo.c are shown below. A description of the code is provided after
the example.
#define S_FUNCTION_NAME timestwo /* Defines and Includes on page 4-6 */
#define S_FUNCTION_LEVEL 2
#include "simstruc.h"
if (!ssSetNumOutputPorts(S,1)) return;
ssSetOutputPortWidth(S, 0, DYNAMICALLY_SIZED);
ssSetNumSampleTimes(S, 1);
4-5
4 Writing S-Functions in C
The first define statement specifies the name of the S-function (timestwo). The second
define statement specifies that the S-function is in the Level 2 format (for more
information about Level 1 and Level 2 S-functions, see “Convert Level-1 C MEX S-
Functions” on page 4-94).
After defining these two items, the example includes simstruc.h, which is a header file
that gives access to the SimStruct data structure and the MATLAB Application Program
Interface (API) functions.
4-6
Create a Basic C MEX S-Function
The simstruc.h file defines a data structure, called the SimStruct, that the Simulink
engine uses to maintain information about the S-function. The simstruc.h file also
defines macros that enable your MEX file to set values in and get values (such as the
input and output signal to the block) from the SimStruct (see “About SimStruct
Functions” on page 12-2).
mdlInitializeSizes
The Simulink engine calls mdlInitializeSizes to inquire about the number of input
and output ports, sizes of the ports, and any other information (such as the number of
states) needed by the S-function.
• Zero parameters
The widths of the input and output ports are dynamically sized. This tells the engine
that the S-function can accept an input signal of any width. By default, the widths of
dynamically sized input and output port are equal when the S-function has only one
input and output port.
• One sample time
Specifying exception-free code speeds up execution of your S-function. You must take
care when specifying this option. In general, if your S-function is not interacting with
the MATLAB environment, you can safely specify this option. For more details, see
“Simulink Engine Interaction with C S-Functions” on page 4-71.
4-7
4 Writing S-Functions in C
mdlInitializeSampleTimes
The Simulink engine calls mdlInitializeSampleTimes to set the sample times of the
S-function. A timestwo block executes whenever the driving block executes. Therefore,
it has a single inherited sample time, INHERITED_SAMPLE_TIME.
mdlOutputs
The engine calls mdlOutputs at each time step to calculate the block outputs. The
timestwo implementation of mdlOutputs multiplies the input signal by 2 and writes the
answer to the output.
The line:
*uPtrs[i]
For more details on accessing input signals, see “Accessing Signals Using Pointers” on
page 4-79.
The line:
real_T *y = ssGetOutputPortRealSignal(S,0);
The line:
obtains the width of the signal passing through the block. The S-function loops over the
inputs to compute the outputs.
mdlTerminate
The engine calls mdlTerminate to provide the S-function with an opportunity to perform
tasks at the end of the simulation. This is a mandatory S-function routine. The timestwo
S-function does not perform any termination actions, and this routine is empty.
4-8
Create a Basic C MEX S-Function
#ifdef MATLAB_MEX_FILE
#include "simulink.c"
#else
#include "cg_sfun.h"
#endif
This trailer is required at the end of every S-function. If it is omitted, any attempt to
compile your S-function will abort with a failure during build of exports file
error message.
mex timestwo.c
at the command line. The mex command compiles and links the timestwo.c file using
the default compiler. The mex command creates a dynamically loadable executable for the
Simulink software to use. If you have multiple MATLAB-supported compilers, you can
change the default using the mex -setup command. See “Change Default Compiler”
(MATLAB) and the list of .
The resulting executable is referred to as a MEX S-function, where MEX stands for
“MATLAB Executable.” The MEX file extension varies from platform to platform. For
example, on a 32–bit Microsoft® Windows system, the MEX file extension is .mexw32.
4-9
4 Writing S-Functions in C
Note For examples of using the S-Function Builder to build S-functions, see the C file S-
functions subsystem of the S-function examples provided with the Simulink product. To
display the examples, enter sfundemos at the MATLAB command line (see “S-Function
Examples” on page 1-23 for more information).
As a result, the HeaderFile for the bus defaults to the empty character vector:
a =
4-10
Build S-Functions Automatically
Simulink.Bus
Description: ''
HeaderFile: ''
Elements: [0x1 double]
b If you wish to specify the header file for the bus, then at the MATLAB command
line:
a.Headerfile = 'Busdef.h'
4-11
4 Writing S-Functions in C
For a demonstration on how to use the S-Function Builder with a bus, see the S-
Function Builder with buses example by entering the following command at
the MATLAB command line:
open_system(fullfile(matlabroot,'/toolbox/simulink/simdemos/simfeatures/',...
'sfbuilder_bususage'))
3 Create a new Simulink model.
4 Copy an instance of the S-Function Builder block from the User-Defined Functions
library in the Library Browser into the new model.
5 Double-click the block to open the S-Function Builder dialog box (see “S-Function
Builder Dialog Box” on page 4-16).
4-12
Build S-Functions Automatically
6 Use the specification and code entry panes on the S-Function Builder dialog box to
enter information and custom source code required to tailor the generated S-function
to your application (see “S-Function Builder Dialog Box” on page 4-16).
7 Click Build on the S-Function Builder to start the build process.
4-13
4 Writing S-Functions in C
The S-Function Builder builds a MEX file that implements the specified S-function
and saves the file in the current folder (see “How the S-Function Builder Builds an S-
Function” on page 4-14).
8 Save the model containing the S-Function Builder block.
Alternatively, you can deploy the generated S-function without using the S-Function
Builder block or exposing the underlying C source file. To do this:
1 Open the Simulink model that will include the S-function.
2 Copy an S-Function block from the User-Defined Functions library in the Library
Browser into the model.
3 Double-click on the S-Function block.
4 In the Block Parameters dialog box that opens, enter the name of the executable file
generated by the S-Function Builder into the S-function name edit field.
5 Enter any parameters needed by the S-function into the S-function parameters edit
field. Enter the parameters in the order they appear in the S-Function Builder dialog
box.
6 Click OK on the S-Function Block Parameters dialog box.
You can use the generated executable file, for example, the .mexw32 file, in any S-
Function block in any model as long as the executable file is on the MATLAB path.
• sfun.c
where sfun is the name of the S-function that you specify in the S-function name
field of the S-Function Builder dialog box. This file contains the C source code
representation of the standard portions of the generated S-function.
4-14
Build S-Functions Automatically
• sfun_wrapper.c
This file contains the custom code that you entered in the S-Function Builder dialog
box.
• sfun.tlc
This file permits the generated S-function to run in Simulink Rapid Accelerator mode
and allows for inlining the S-function during code generation. In addition, this file
generates code for the S-function in Accelerator mode, thus allowing the model to run
faster.
• sfun_bus.h
If you specify any Input port or Output port as a bus in the Data Properties pane
of the S-Function Builder dialog box, but do not specify a header file, then the S-
Function Builder automatically generates this header file.
After generating the S-function source code, the S-Function Builder uses the mex
command to build the MEX file representation of the S-function from the generated
source code and any external custom source code and libraries that you specified.
4-15
4 Writing S-Functions in C
4-16
S-Function Builder Dialog Box
The dialog box contains controls that let you enter information needed for the S-Function
Builder block to build an S-function to your specifications. The controls are grouped into
panes. See the following sections for information on the panes and the controls that they
contain.
4-17
4 Writing S-Functions in C
Note The following sections use the term target S-function to refer to the S-function
specified by the S-Function Builder dialog box.
S-function name
Language
Specifies the target language for S-function. You can choose to generate your S-functions
in C/C++, or you can inherit the model settings.
S-function parameters
This table displays the parameters of the target S-function. Each row of the table
corresponds to a parameter, and each column displays a property of the parameter as
follows:
• Name — Name of the parameter. Define and modify this property from the
“Parameters Pane” on page 4-25.
• Data type — Lists the data type of the parameter. Define and modify this property
from the “Parameters Pane” on page 4-25.
• Value — Specifies the value of the parameter. Enter a valid MATLAB expression in this
field.
Build/Save
Use this button to generate the C source code and executable MEX file from the
information you entered in the S-Function Builder. If the button is labeled Build, the S-
Function Builder generates the source code and executable MEX file. If the button is
4-18
S-Function Builder Dialog Box
labeled Save, it generates only the C source code. Use the Save code only check box on
the Build Info pane to toggle the functionality of this button.
Use the small button at the bottom-right of the Parameters/S-Function Name pane, to
collapse and expand the bottom portion of the S-Function Builder dialog box.
Port/Parameter Pane
This Port/Parameter pane on the left displays the ports and parameters that the dialog
box specifies for the target S-function.
The pane contains a tree control whose top nodes correspond to the target S-function
input ports, output ports, and parameters, respectively. Expanding the Input Ports, Output
Ports, or Parameter node displays the input ports, output ports, or parameters,
respectively, specified for the target S-function. Selecting any of the port or parameter
nodes selects the corresponding entry on the corresponding port or parameter
specification pane.
Initialization Pane
The Initialization pane allows you to specify basic features of the S-function, such as the
width of its input and output ports and its sample time.
The S-Function Builder uses the information that you enter on this pane to generate the
mdlInitializeSizes callback method. The Simulink engine invokes this method during
the model initialization phase of the simulation to obtain basic information about the S-
function. (See “Simulink Engine Interaction with C S-Functions” on page 4-71 for more
information on the model initialization phase.)
4-19
4 Writing S-Functions in C
Discrete states IC
Initial conditions of the discrete states in the S-function. You can enter the values as a
comma-separated list or as a vector (e.g., [0 1 2]). The number of initial conditions
must equal the number of discrete states.
Continuous states IC
Initial conditions of the continuous states in the S-function. You can enter the values as a
comma-separated list or as a vector (e.g., [0 1 2]). The number of initial conditions
must equal the number of continuous states.
Sample mode
Sample mode of the S-function. The sample mode determines the length of the interval
between the times when the S-function updates its output. You can select one of the
following options:
• Inherited
The S-function inherits its sample time from the block connected to its input port.
• Continuous
The S-function updates its outputs at the rate specified in the Sample time value
field of the S-Function Builder dialog box.
Scalar value indicating the interval between updates of the S-function outputs. This field
is enabled only if you select Discrete as the Sample mode.
Note The S-Function Builder does not currently support multiple-block sample times or a
nonzero offset time.
4-20
S-Function Builder Dialog Box
Number of PWorks
The number of data pointers used by the S-function. The PWorks points to the memory
over the lifecycle of the block. For example, you can declare and initialize a pointer to a
file or memory at the Start, and access it in Outputs, Update, and Derivatives panes,
and deallocate it at the Terminate pane. The code written in these panes are called by
mdlStart, mdlOutputs, mdlUpdate, mdlDerivatives, and mdlTerminate. See the
examples Moving Average with Start and Terminate and Permutation using Cpp Classes.
Note Use of PWorks affects the SimState compliance. If you declare PWorks, the use of
SimState save and restore is not allowed. Otherwise, the default SimState compliance
setting, USE_DEFAULT_SIM_STATE, is used.
Array layout
Array layout of your C/C++ code. You can select one of the options listed in the table.
4-21
4 Writing S-Functions in C
• mdlOutputs
• mdlUpdate
• mdlDerivatives
4-22
S-Function Builder Dialog Box
This pane also contains tabbed panes that enable you to specify the attributes of the ports
and parameters that you create. See:
Port name
Name of the port. Edit this field to change the port name.
Dimensions
Lists the number of dimensions of the input signal accepted by the port. To display a list
of supported dimensions, click the adjacent button. To change the port dimensionality,
select a new value from the list. Specify 1-D to size the signal dynamically, regardless of
the actual dimensionality of the signal.
Rows
Specifies the size of the first (or only) dimension of the input signal. Specify -1 to size the
signal dynamically.
Columns
Specifies the size of the second dimension of the input signal (only if the input port
accepts 2-D signals).
Note For input signals with two dimensions, if the rows dimension is dynamically sized,
the columns dimension must also be dynamically sized or set to 1. If the columns
4-23
4 Writing S-Functions in C
dimension is set to some other value, the S-function will compile, but any simulation
containing this S-function will not run due to an invalid dimension specification.
Complexity
Bus
If the input signal to the S-Function Builder block is a bus, then use the drop-down menu
in the Bus column to select 'on'.
Bus Name
Step 2 of the “Build S-Functions Automatically” on page 4-10 instructs you to create a bus
object, if your input signal is a bus. In the field provided in the Bus Name column, enter
the bus name that you defined while creating the inport bus object.
Port name
Name of the port. Edit this field to change the port name.
Dimensions
Lists the number of dimensions of signals output by the port. To display a list of supported
dimensions, click the adjacent button. To change the port dimensionality, select a new
value from the list. Specify 1-D to size the signal dynamically, regardless of the actual
dimensionality of the signal.
Rows
Specifies the size of the first (or only) dimension of the output signal. Specify -1 to size
the signal dynamically.
4-24
S-Function Builder Dialog Box
Columns
Specifies the size of the second dimension of the output signal (only if the port outputs 2-
D signals).
Note For output signals with two dimensions, if one of the dimensions is dynamically
sized the other dimension must also be dynamically sized or set to 1. If the second
dimension is set to some other value, the S-function will compile, but any simulation
containing this S-function will not run due to an invalid dimension specification. In some
cases, the calculations that determine the dimensions of dynamically sized output ports
may be insufficient and both dimensions of the 2-D output signal may need to be hard
coded.
Complexity
Bus
If the output signal to the S-Function Builder block is a bus, then use the drop-down menu
in the Bus column to select 'on'.
Bus Name
Step 2 of the “Build S-Functions Automatically” on page 4-10 instructs you to create a bus
object. In the field provided in the Bus Name column, enter the name that you defined
while creating the outport bus object.
Parameters Pane
The Parameters pane allows you to inspect and modify the properties of the S-function
parameters. The pane consists of a table that lists the properties of the S-function
parameters. Each row of the table corresponds to a parameter. The order in which the
parameters appear corresponds to the order in which the user must specify them in the
S-function parameters field. Each entry in the row displays a property of the parameter
as follows.
Parameter name
4-25
4 Writing S-Functions in C
Data type
Lists the data type of the parameter. Click the adjacent button to display a list of
supported data types. To change the parameter data type, select a new type from the list.
Complexity
Port
Name of the port. This field displays the name entered in the Input ports and Output
ports panes. You cannot edit this field.
Data Type
Data type of the port. Click the adjacent button to display a list of supported data types.
To change the data type, select a different data type from the list.
The remaining fields on this pane are enabled only if the Data Type field specifies a fixed-
point data type. See “Specify Fixed-Point Data Types” for more information.
Libraries Pane
The Libraries pane allows you to specify the location of external code files referenced by
custom code that you enter in other panes of the S-Function Builder dialog box. It
includes the following fields.
Library/Object/Source files
External library, object code, and source files referenced by custom code that you enter
elsewhere on the S-Function Builder dialog box. List each file on a separate line. If the file
resides in the current folder, you need specify only the file name. If the file resides in
another folder, you must specify the full path of the file.
4-26
S-Function Builder Dialog Box
Alternatively, you can also use this field to specify search paths for libraries, object files,
header files, and source files. To do this, enter the tag LIB_PATH, INC_PATH, or
SRC_PATH, respectively, followed by the path name. You can make as many entries of this
kind as you need but each must reside on a separate line.
• c:\customfolder\customfunctions.lib
• d:\matlab7\customobjs\userfunctions.obj
• d:\externalsource\freesource.c
The following entries enable the S-Function Builder to find these files:
SRC_PATH d:\externalsource
LIB_PATH $MATLABROOT\customobjs
LIB_PATH c:\customfolder
customfunctions.lib
userfunctions.obj
freesource.c
As this example illustrates, you can use LIB_PATH to specify both object and library file
paths. You can include the library name in the LIB_PATH declaration, however you must
place the object file name on a separate line. The tag $MATLABROOT indicates a path
relative to the MATLAB installation. You include multiple LIB_PATH entries on separate
lines. The paths are searched in the order specified.
You can also enter preprocessor (-D) directives in this field, for example,
-DDEBUG
Note Do not put quotation marks around the library path, even if the path name has
spaces in it. If you add quotation marks, the compiler will not find the library.
Includes
4-27
4 Writing S-Functions in C
standard C header files (e.g., #include <math.h>). Use quotation marks to enclose
names of custom header files (e.g., #include "myutils.h"). If your S-function uses
custom include files that do not reside in the current folder, you must use the INC_PATH
tag in the Library/Object/Source files field to set the include path for the S-Function
Builder to the directories containing the include files (see “Library/Object/Source files” on
page 4-26).
Declarations of external functions not declared in the header files listed in the Includes
field. Put each declaration on a separate line. The S-Function Builder includes the
specified declarations in the S-function source file that it generates. This allows S-
function code that computes the S-function states or outputs to invoke the external
functions.
Start Pane
Use the Start pane to write code to allocate memory at the start of simulation. The
allocated is referenced by Pworks for use throughout the S-function.
Outputs Pane
Use the Outputs pane to enter code that computes the outputs of the S-function at each
simulation time step. This pane contains the following fields.
Code description
Code for the mdlOutputs function that computes the output of the S-function at each
time step (or sample time hit, in the case of a discrete S-function). When generating the
source code for the S-function, the S-Function Builder inserts the code in this field in a
wrapper function of the form
4-28
S-Function Builder Dialog Box
where sfun is the name of the S-function. The S-Function Builder inserts a call to this
wrapper function in the mdlOutputs callback method that it generates for your S-
function. The Simulink engine invokes the mdlOutputs method at each simulation time
step (or sample time step in the case of a discrete S-function) to compute the S-function
output. The mdlOutputs method in turn invokes the wrapper function containing your
output code. Your output code then actually computes and returns the S-function output.
The mdlOutputs method passes some or all of the following arguments to the outputs
wrapper function.
Argument Description
u0, u1, ... uN Pointers to arrays containing the inputs to the S-function,
where N is the number of input ports specified on the Input
ports pane found on the Data Properties pane. The names of
the arguments that appear in the outputs wrapper function are
the same as the names found on the Input ports pane. The
width of each array is the same as the input width specified for
each input on the Input ports pane. If you specified -1 as an
input width, the width of the array is specified by the wrapper
function's u_width argument (see below).
y0, y1, ... yN Pointer to arrays containing the outputs of the S-function,
where N is the number of output ports specified on the Output
ports pane found on the Data Properties pane. The names of
the arguments that appear in the outputs wrapper function are
the same as the names found on the Output ports pane. The
width of each array is the same as the output width specified
for each output on the Output ports pane. If you specified -1
as the output width, the width of the array is specified by the
wrapper function's y_width argument (see below). Use this
array to pass the outputs that your code computes back to the
Simulink engine.
4-29
4 Writing S-Functions in C
Argument Description
xD Pointer to an array containing the discrete states of the S-
function. This argument appears only if you specified discrete
states on the Initialization pane. At the first simulation time
step, the discrete states have the initial values that you
specified on the Initialization pane. At subsequent sample-
time steps, the states are obtained from the values that the S-
function computes at the preceding time step (see “Discrete
Update Pane” on page 4-32 for more information).
xC Pointer to an array containing the continuous states of the S-
function. This argument appears only if you specified
continuous states on the Initialization pane. At the first
simulation time step, the continuous states have the initial
values that you specified on the Initialization pane. At
subsequent time steps, the states are obtained by numerically
integrating the derivatives of the states at the preceding time
step (see “Continuous Derivatives Pane” on page 4-31 for
more information).
param0, p_width0, param0, param1, ...paramN are pointers to arrays containing
param1, p_width1, ... the S-function parameters, where N is the number of
paramN, p_widthN parameters specified on the Parameters pane found on the
Data Properties pane. p_width0, p_width1, ...p_widthN are
the widths of the parameter arrays. If a parameter is a matrix,
the width equals the product of the dimensions of the arrays.
For example, the width of a 3-by-2 matrix parameter is 6. These
arguments appear only if you specify parameters on the Data
Properties pane.
y_width Width of the array containing the S-function outputs. This
argument appears in the generated code only if you specified -1
as the width of the S-function output. If the output is a matrix,
y_width is the product of the dimensions of the matrix.
u_width Width of the array containing the S-function inputs. This
argument appears in the generated code only if you specified -1
as the width of the S-function input. If the input is a matrix,
u_width is the product of the dimensions of the matrix.
These arguments permit you to compute the output of the block as a function of its inputs
and, optionally, its states and parameters. The code that you enter in this field can invoke
4-30
S-Function Builder Dialog Box
external functions declared in the header files or external declarations on the Libraries
pane. This allows you to use existing code to compute the outputs of the S-function.
Select this check box if the current values of the S-function inputs are used to compute its
outputs. The Simulink engine uses this information to detect algebraic loops created by
directly or indirectly connecting the S-function output to the S-function input.
where sfun is the name of the S-function. The S-Function Builder inserts a call to this
wrapper function in the mdlDerivatives callback method that it generates for the S-
function. The Simulink engine calls the mdlDerivatives method at the end of each time
step to obtain the derivatives of the continuous states (see “Simulink Engine Interaction
with C S-Functions” on page 4-71). The Simulink solver numerically integrates the
derivatives to determine the continuous states at the next time step. At the next time step,
the engine passes the updated states back to the mdlOutputs method (see “Outputs
Pane” on page 4-28).
4-31
4 Writing S-Functions in C
The mdlDerivatives callback method generated for the S-function passes the following
arguments to the derivatives wrapper function:
• u
• y
• dx
• xC
• param0, p_width0, param1, p_width1, ... paramN, p_widthN
• y_width
• u_width
The dx argument is a pointer to an array whose width is the same as the number of
continuous derivatives specified on the Initialization pane. Your code should use this
array to return the values of the derivatives that it computes. See “Outputs Pane” on page
4-28 for the meanings and usage of the other arguments. The arguments allow your code
to compute derivatives as a function of the S-function inputs, outputs, and, optionally,
parameters. Your code can invoke external functions declared on the Libraries pane.
Enter code for the mdlUpdate function to compute the values of the discrete states in the
Code description field on this pane. When generating code, the S-Function Builder takes
the code in this pane and inserts it in a wrapper function of the form
4-32
S-Function Builder Dialog Box
where sfun is the name of the S-function. The S-Function Builder inserts a call to this
wrapper function in the mdlUpdate callback method that it generates for the S-function.
The Simulink engine calls the mdlUpdate method at the end of each time step to obtain
the values of the discrete states at the next time step (see “Simulink Engine Interaction
with C S-Functions” on page 4-71). At the next time step, the engine passes the updated
states back to the mdlOutputs method (see “Outputs Pane” on page 4-28).
The mdlUpdates callback method generated for the S-function passes the following
arguments to the updates wrapper function:
• u
• y
• xD
• param0, p_width0, param1, p_width1, ... paramN, p_widthN
• y_width
• u_width
See “Outputs Pane” on page 4-28 for the meanings and usage of these arguments. Your
code should use the xD (discrete states) variable to return the values of the discrete
states that it computes. The arguments allow your code to compute the discrete states as
functions of the S-function inputs, outputs, and, optionally, parameters. Your code can
invoke external functions declared on the Libraries pane.
Terminate Pane
Use the Terminate pane for writing the code to free up the memory allocated at the
Start pane. Memory referenced by PWorks can also be seen by Terminate, and should
be deallocated here.
4-33
4 Writing S-Functions in C
Compilation diagnostics
Displays information as the S-Function Builder is generating the C source and executable
files.
Make S-Function compatible with model coverage. For more information, see “Coverage
for Custom C/C++ Code in Simulink Models” (Simulink Coverage) in Simulink Coverage™
documentation.
Selecting this option allows you to generate a TLC file. You need to generate a TLC file if
you are running your model in Rapid Accelerator mode or generating Simulink Coder
code from your model. Also, while it is not necessary for Accelerator mode simulations,
the TLC file will generate code for the S-function and thus makes your model run faster in
Accelerator mode.
Makes the SimStruct (S) accessible to the wrapper functions that S-Function Builder
generates. This enables you to use the SimStruct macros and functions with your code
in the Outputs, Continuous Derivatives, and Discrete Updates panes. For example,
with this option enabled, you can use macros such as ssGetT in code that computes the
S-function outputs:
double t = ssGetT(S);
if(t < 2 ) {
y0[0] = u0[0];
} else {
4-34
S-Function Builder Dialog Box
y0[0]= 0.0;
}
Additional methods
Click this button to include additional TLC methods in the TLC file for your S-function.
Check the methods you want to add and click the Close button to include the methods in
your TLC file. For more information, see “Block Target File Methods” (Simulink Coder).
Note You need to build the S-function before running the example model. To build the S-
function, double-click on the S-Function Builder block in the model and click Build on the
S-Function Builder dialog box that opens.
The Initialization pane specifies the number of discrete states and their initial
conditions, as well as sets the sample time of the S-function. This example contains two
discrete states, each initialized to 1, and a discrete sample mode with a sample time of 1.
4-35
4 Writing S-Functions in C
The Data Properties pane specifies the dimensions of the S-function input and output, as
well as initializes the state-space matrices.
The Input ports pane defines the one S-function input port as a 1-D vector with two
rows.
4-36
S-Function Builder Dialog Box
The Output ports pane similarly defines the one S-function output port as a 1-D vector
with two rows.
The Parameters pane defines four parameters, one for each of the four state-space
matrices.
4-37
4 Writing S-Functions in C
The S-function parameters pane at the top of the S-Function Builder contains the
actual values for the state-space matrices, entered as MATLAB expressions. In this
example, each state-space parameter is a two-by-two matrix. Alternatively, you can store
the state-space matrices in variables in the MATLAB workspace and enter the variable
names into the Value field for each parameter.
The Outputs pane calculates the S-function output as a function of the input and state
vectors and the state-space matrices. In the outputs code, reference S-function
parameters using the parameter names defined on the Data Properties — Parameters
pane. Index into 2-D matrices using a scalar index, keeping in mind that S-functions use
zero-based indexing. For example, to access the element C(2,1) in the S-function
parameter C, use C[1]in the S-function code.
4-38
S-Function Builder Dialog Box
The Outputs pane also selects the Inputs are needed in the output function (direct
feedthrough) option since this state-space model has a nonzero D matrix.
The Discrete Update pane updates the discrete states. As with the outputs code, use the
S-function parameter names and index into 2-D matrices using a scalar index, keeping in
mind that S-functions use zero-based indexing. For example, to access the element
A(2,1) in the S-function parameter A, use A[1]in the S-function code. The variable xD
stores the final values of the discrete states.
4-39
4 Writing S-Functions in C
Click the Build button on the S-Function Builder to create an executable for this S-
function. You can now run the model and compare the output to the original discrete
state-space S-function contained in sfcndemo_dsfunc.
4-40
Templates for C S-Functions
Note We recommend that you use the C MEX file template when developing MEX S-
functions.
For S-functions to operate properly, each source module of your S-function that accesses
the SimStruct must contain the following sequence of defines and include
#define S_FUNCTION_NAME your_sfunction_name_here
#define S_FUNCTION_LEVEL 2
#include "simstruc.h"
where your_sfunction_name_here is the name of your S-function (i.e., what you enter
in the S-Function Block Parameters dialog box). These statements give you access to the
SimStruct data structure that contains pointers to the data used by the simulation. The
4-41
4 Writing S-Functions in C
included code also defines the macros used to store and retrieve data in the SimStruct,
described in detail in “Convert Level-1 C MEX S-Functions” on page 4-94. In addition,
the code specifies that you are using the Level-2 S-function format.
Note All S-functions from Simulink version 1.3 through version 2.1 are considered to be
Level-1 S-functions. They are compatible with newer versions of the software, but we
recommend that you write new S-functions in the Level-2 format.
The following headers are included by simstruc.h when compiling as a MEX file.
When compiling your S-function for use with the Simulink Coder product, simstruc.h
includes the following.
Header Files Included by simstruc.h When Used by the Simulink Coder Product
Header File Description
matlabroot/extern/include/tmwtypes.h General types, e.g., real_T
matlabroot/simulink/include/ SimStruct data types, e.g., DTypeId
simstruc_types.h
matlabroot/rtw/c/src/rt_matrx.h Macros for MATLAB API routines
Your S-function must implement the following functions (see “Write Callback Methods” on
page 4-83):
4-42
Templates for C S-Functions
Your S-function must include the following trailer code at the end of the main module
only.
#ifdef MATLAB_MEX_FILE /* Is this being compiled as MEX-file? */
#include "simulink.c" /* MEX-file interface mechanism */
#else
#include "cg_sfun.h" /* Code generation registration func */
#endif
These statements select the appropriate code for your particular application:
Note This trailer code must not be in the body of any S-function routine.
The SimStruct
The file simstruc.h is a C language header file that defines the SimStruct data
structure and its access macros. It encapsulates all the data relating to the model or S-
function, including block parameters and outputs.
There is one SimStruct data structure allocated for the Simulink model. Each S-function
in the model has its own SimStruct associated with it. The organization of these
SimStructs is much like a folder tree. The SimStruct associated with the model is the
root SimStruct. Any SimStruct associated with an S-function is a child SimStruct.
The Simulink product provides a set of macros that S-functions can use to access the
fields of the SimStruct. See “About SimStruct Functions” on page 12-2 for more
information.
4-43
4 Writing S-Functions in C
S-functions are not required to use these data types. For example, you can edit the
example csfunc.c and change real_T to double and int_T to int. If you compile and
simulate the S-function, the results will be identical to the results using the previous data
types.
Compiling C S-Functions
Your S-function can be compiled in one of three modes, defined either by the mex
command or by the Simulink Coder product when the S-function is built:
• MATLAB_MEX_FILE — Indicates that the S-function is being built as a MEX file for use
with the Simulink product.
• RT — Indicates that the S-function is being built with the Simulink Coder product for a
real-time application using a fixed-step solver.
• NRT — Indicates that the S-function is being built with the Simulink Coder product for
a non-real-time application using a variable-step solver.
The build process you use automatically defines the mode for your S-function.
4-44
Integrate C Functions Using Legacy Code Tool
Overview
You can integrate existing C (or C++) functions, such as device drivers, lookup tables,
and general functions and interfaces, into Simulink models by using the Legacy Code
Tool. Using specifications that you supply as MATLAB code, the tool transforms existing
functions into C MEX S-functions that you can include in Simulink models. If you use
Simulink Coder to generate code, Legacy Code Tool can insert an appropriate call to your
C function into the generated code. For details, see “Import Calls to External Code into
Generated Code with Legacy Code Tool” (Simulink Coder).
In comparison to using the S-Function Builder or writing an S-function, Legacy Code Tool
is easier to use and generates optimized code (does not generate wrapper code) often
required by embedded systems. However, consider alternative approaches for a hybrid
system, such as a system that includes a plant and controller, or a system component
written in a language other than C or C++. Alternative approaches are more flexible in
that they support more features and programming languages.
4-45
4 Writing S-Functions in C
• Initialize the Legacy Code Tool data structure for a given C function
• Generate an S-function for use during simulation
• Compile and link the generated S-function into a dynamically loadable executable
• Generate a masked S-function block for calling the generated S-function
• Generate a TLC block file and, if necessary, an sFunction_makecfg.m or
rtwmakecfg.m file for code generation (Simulink Coder product license required)
Note Before you can use legacy_code, ensure that a C compiler is set up for your
MATLAB installation.
The following diagram illustrates a general procedure for using the Legacy Code Tool.
“Integrate C Functions into Simulink Models with Legacy Code Tool” on page 4-48
provides an example that uses the Legacy Code Tool to transform an existing C function
into a C MEX S-function.
4-46
Integrate C Functions Using Legacy Code Tool
If you have a Simulink Coder product license, see “Import Calls to External Code into
Generated Code with Legacy Code Tool” (Simulink Coder) for information on using the
Legacy Code Tool for code generation.
4-47
4 Writing S-Functions in C
Suppose that you have a C function that outputs the value of its floating-point input
multiplied by two. The function is defined in a source file named doubleIt.c, and its
declaration exists in a header file named doubleIt.h.
doubleIt.c doubleIt.h
1 Initialize a MATLAB struct def with fields that represent Legacy Code Tool
properties using the legacy_code function.
def = legacy_code('initialize')
The Legacy Code Tool data structure named def displays its fields in the MATLAB
command window as shown here:
def =
SFunctionName: ''
InitializeConditionsFcnSpec: ''
OutputFcnSpec: ''
StartFcnSpec: ''
TerminateFcnSpec: ''
HeaderFiles: {}
SourceFiles: {}
HostLibFiles: {}
TargetLibFiles: {}
IncPaths: {}
SrcPaths: {}
LibPaths: {}
4-48
Integrate C Functions Using Legacy Code Tool
SampleTime: 'inherited'
Options: [1x1 struct]
2 Specify appropriate values for fields in the Legacy Code Tool data structure to
identify properties of the existing C function. For example, specify the C function
source and header filenames by entering the following commands at the MATLAB
command prompt:
def.SourceFiles = {'doubleIt.c'};
def.HeaderFiles = {'doubleIt.h'};
You must also specify information about the S-function that the Legacy Code Tool
produces from the C code. For example, specify a name for the S-function and its
output function declaration by entering:
def.SFunctionName = 'ex_sfun_doubleit';
def.OutputFcnSpec = 'double y1 = doubleIt(double u1)';
For information about the various data structure fields, see the legacy_code
reference page.
3 Generate an S-function source file from the existing C function by using the
legacy_code function. At the MATLAB command prompt, type:
legacy_code('sfcn_cmex_generate', def);
The Legacy Code Tool uses the information specified in def to create the S-function
source file named ex_sfun_doubleit.c in the current MATLAB folder.
4 Compile and link the S-function source file into a dynamically loadable executable for
Simulink using thelegacy_code function. At the MATLAB command prompt, type:
legacy_code('compile', def);
4-49
4 Writing S-Functions in C
legacy_code('slblock_generate', def);
The Legacy Code Tool configures the block to use the C MEX S-function created in
the previous step. Also, the tool masks the block such that it displays the value of its
OutputFcnSpec property (see the description of the legacy_code function).
6 Add a Sine Wave block of amplitude 1 to the input of the C-MEX S-function block and
a Scope block to the output.
Run the simulation. The C-MEX S-Function block returns the value of its floating-
point input multiplied by two. It behaves like the C function doubleIt.
4-50
Integrate C Functions Using Legacy Code Tool
For basic information about bus signals, see “Buses”. For basic information about
parameter structures, see “Organize Related Block Parameter Definitions in Structures”.
To create bus objects, see “Create Bus Objects with the Bus Editor”.
4-51
4 Writing S-Functions in C
Copy this custom source code into a file named ex_mySrc_LCT.c in your current folder.
#include "ex_myTypes_LCT.h"
The arguments of the function myFcn are pointers to structures. The function accepts an
input signal argument, a parameter argument, and an output signal argument.
Copy this custom header code into a file named ex_myTypes_LCT.h in your current
folder.
#ifndef _MY_TYPES_H_
#define _MY_TYPES_H_
typedef struct {
double sig1;
double sig2;
} sigStructType;
typedef struct {
double param1;
double param2;
double param3;
} paramStructType;
#endif
The file defines the signal and parameter structure types that myFcn uses.
Simulink.importExternalCTypes('ex_myTypes_LCT.h');
4-52
Integrate C Functions Using Legacy Code Tool
The bus objects correspond to the struct types that ex_myTypes_LCT.h defines.
Create a structure variable, def, to store the specifications for an S-function that calls the
external code. Use the function legacy_code to create the structure and set default
values.
def = legacy_code('initialize');
Identify the external source and header files by their file names.
def.SourceFiles = {'ex_mySrc_LCT.c'};
def.HeaderFiles = {'ex_myTypes_LCT.h'};
Specify the prototype of the output function, which the model calls every simulation step,
by copying the prototype of the external function myFcn. Set the names of the arguments
to u1, p1, and y1 to represent the input argument, the parameter argument, and the
output argument. Use the syntax [1] to specify that each argument is a pointer.
def.OutputFcnSpec = ['void myFcn(sigStructType u1[1], ',...
'paramStructType p1[1], sigStructType y1[1])'];
Use the function legacy_code to create the S-function and the corresponding C MEX
executable from the specification, def. Specify the option 'generate_for_sim' to
prepare the S-function for normal and accelerated simulations.
legacy_code('generate_for_sim',def);
Create a masked S-Function block that calls the S-function during simulation.
4-53
4 Writing S-Functions in C
legacy_code('slblock_generate', def);
To use the S-Function block in your model, create a bus signal of type sigStructType to
use as the block input. The block output is also a bus signal. The block mask accepts a
parameter, P1. To set the value of the parameter, use a MATLAB structure whose fields
match those of the structure type paramStructType.
Create a harness model that verifies the execution of the external code during simulation.
open_system('ex_lct_struct')
In the Constant block dialog box, the Constant value parameter is set to a structure
whose fields match those of the structure type sigStructType. On the Signal
Attributes tab, Output data type is set to the bus object sigStructType.
The S-Function block calls the S-function sfun_ex_mySrc_LCT that you created. The
output of the block enters a Bus Selector block, which extracts the signal elements sig1
and sig2.
4-54
Integrate C Functions Using Legacy Code Tool
The S-Function block accepts a parameter through the mask dialog box. Create a
MATLAB structure structParam to use as the value of the parameter.
structParam = struct;
structParam.param1 = 15;
structParam.param2 = 20;
structParam.param3 = 5;
structParam = Simulink.Parameter(structParam);
structParam.DataType = 'Bus: paramStructType';
set_param('ex_lct_struct/sfun_ex_mySrc_LCT','SParameter1','structParam')
Simulate the model. The Scope blocks show that the S-Function block calls the external
function myFcn.
open_system('ex_lct_struct/Scope')
open_system('ex_lct_struct/Scope1')
sim('ex_lct_struct')
ans =
Simulink.SimulationOutput:
tout: [51x1 double]
4-55
4 Writing S-Functions in C
4-56
Integrate C Functions Using Legacy Code Tool
• Placing all required header and source files in the current working folder or in a
hierarchical folder structure
• Generating and placing one or more S-functions in the current working folder
• Having one or more registration files in the same folder
4-57
4 Writing S-Functions in C
The Legacy Code Tool data structure named lct_spec displays its fields in the
MATLAB command window as shown below:
lct_spec =
SFunctionName: ''
InitializeConditionsFcnSpec: ''
OutputFcnSpec: ''
StartFcnSpec: ''
TerminateFcnSpec: ''
HeaderFiles: {}
SourceFiles: {}
HostLibFiles: {}
TargetLibFiles: {}
IncPaths: {}
SrcPaths: {}
LibPaths: {}
SampleTime: 'inherited'
Options: [1x1 struct]
2 Define values for the data structure fields (properties) that apply to your existing C
function and the S-function you intend to generate. Minimally, you must specify
• Source and header files for the existing C function (SourceFiles and
HeaderFiles)
• A name for the S-function (SFunctionName)
• At least one function specification for the S-function
(InitializeConditionsFcnSpec, OutputFcnSpec, StartFcnSpec,
TerminateFcnSpec)
For a complete list and descriptions of the fields in the structure, see the
legacy_code function reference page.
If you define fields that specify compilation resources and you specify relative paths, the
Legacy Code Tool searches for the resources relative to the following directories, in the
following order:
4-58
Integrate C Functions Using Legacy Code Tool
General syntax
return-spec = function-name(argument-spec)
For example, the following character vector specifies a function named doubleIt with
return specification double y1 and input argument specification double u1.
Return Specification
The return specification defines the data type and variable name for the return value of
the existing C function.
return-type return-variable
4-59
4 Writing S-Functions in C
return-variable Token of the form y1, y2, ..., yn, where n is the total number
of output arguments.
If the function does not return a value, you can omit the return specification or specify it
as void.
The following table shows valid function specification syntax for an integer return value.
Use the table to identify the syntax you should use for your C function prototype.
Function Name
The function name that you specify must be the same as your existing C function name.
In this case, the function name in the Legacy Code Tool function specification must be
doubleIt.
You should not specify the name of a C macro. If you must, set the field
Options.isMacro to true in case expression folding is enabled.
Argument Specification
The argument specification defines one or more data type and token pairs that represent
the input, output, parameter, and work vector arguments of the existing C function. The
function input and output arguments map to block input and output ports and parameters
map to workspace parameters.
argument-type argument-token
4-60
Integrate C Functions Using Legacy Code Tool
• Input — u1, u2, ..., un, where n is the total number of input
arguments
• Output — y1, y2, ..., yn, where n is the total number of
output arguments
• Parameter — p1, p2, ..., pn, where n is the total number of
parameter arguments
• Work vectors (persistent memory) — work1, work2, ...,
workn, where n is the total number of work vector arguments
If the function has no arguments, you can omit the argument specification or specify it as
void.
To generate an S-function that calls the preceding function at each time step, set the
Legacy Code Tool data structure field OutputFcnSpec to the following:
Using this function specification, the Legacy Code Tool maps the following information.
If your function requires a Simulink S-function block with multiple input and output ports,
map function arguments to input ports using a uniquely numbered u token. For output
ports, use a uniquely numbered y token. These tokens are described in the preceding
argument specification table. For example, consider the following C function prototype:
void myfunc(double *y2, double u2, double u3, double u1, double *y1);
An OutputFcnSpec character vector mapping the arguments to input and output ports
looks similar to the following:
4-61
4 Writing S-Functions in C
'void myfunc(double y2[1], double u2, double u3, double u1, double y1[1])'
The resulting S-function block includes three input ports and two output ports. The first
input maps to function argument u1, the second input to u2, and the third input to u3.
For the output ports, the function argument y1[1] maps to the first output, and
argument y2[1] maps to the second output. For another example of mapping a function
prototype to multiple input and output ports, see “Using Buses with Legacy Functions
Having Structure Arguments”.
The following table shows valid function specification syntax for arguments of type
integer. Use the table to identify and then adapt the syntax you should use for your C
function prototype.
4-62
Integrate C Functions Using Legacy Code Tool
4-63
4 Writing S-Functions in C
1 You must supply the header file that defines the structure of the bus, defines the
enum type, or defines the data type with the same name as an alias. The structure of
the bus declared in the header file must match the structure of the bus object (for
example, the number and order of elements, data types and widths of elements, and
so on). For an example, see sldemo_lct_bus.
To generate data type objects and enumeration classes that correspond to custom
data types that your C code defines, use the Simulink.importExternalCTypes
function.
2 A bus element can be complex, but only with Simulink built-in data types. Nesting of
arrays to any level is also supported.
3 You must supply the header file that defines the data type only if the numeric data
type is also an alias.
4 You must declare the data as a Simulink.NumericType object (unspecified scaling
is not supported). For examples, see sldemo_lct_fixpt_signals and
sldemo_lct_fixpt_params.
5 Limited to use with Simulink built-in data types. To specify a complex data type,
enclose the built-in data type within angle brackets (<>) and prepend the word
4-64
Integrate C Functions Using Legacy Code Tool
For example:
def.OutputFcnSpec=
foo4(int8 p1[], int8 u1[], double y1[numel(u1)+2][numel(u1)+3], ...
int32 (numel(p1)+numel(u1))*2+size(y1,2))';
4-65
4 Writing S-Functions in C
To integrate a C function using the Legacy Code Tool, the function must adhere to the
following rules:
• The function must not change the value of input arguments. If an input signal is a
passed-by-reference argument to the function, the function must not modify the data
pointed to by the argument.
• The function's return value cannot be a pointer.
• Function specifications you define for the StartFcnSpec,
InitializeConditionsFcnSpec, or TerminateFcnSpec cannot access input or
output arguments. For StartFcnSpec and InitializeConditionsFcnSpec, you
can access output ports if the S-Function option outputsConditionallyWritten is
set to true. With this option setting, the generated S-Function specifies that the
memory associated with each output port cannot be overwritten and is global
(SS_NOT_REUSABLE_AND_GLOBAL).
1 Generate a C MEX S-function based on the information defined in the structure. Call
legacy_code with 'sfcn_cmex_generate' as the first argument and the name of
the data structure as the second argument.
legacy_code('sfcn_cmex_generate', lct_spec);
2 Compile and link the S-function. This step assumes that a C compiler is set up for
your MATLAB installation. Call legacy_code with 'compile' as the first argument
and the name of the data structure as the second argument.
legacy_code('compile', lct_spec);
4-66
Integrate C Functions Using Legacy Code Tool
As a convenience, you can generate, compile, and link the S-function in a single step by
calling legacy_code with the character vector 'generate_for_sim'. The function
also generates a TLC file for accelerated simulations, if the Options.useTlcWithAccel
field of the Legacy Code Tool data structure is set to 1.
Once you have generated a dynamically loadable executable, you or others can use it in a
model by adding an S-Function block that specifies the compiled S-function.
legacy_code('slblock_generate', lct_spec);
The tool masks the block such that it displays the value of the OutputFcnSpec field. You
can then add the block to a model manually.
If you prefer that the Legacy Code Tool add the block to a model automatically, specify the
name of the model as a third argument. For example:
If the specified model (for example, myModel) exists, legacy_code opens the model and
adds the masked S-function block described by the Legacy Code Tool data structure. If
the model does not exist, the function creates a new model with the specified name and
adds the masked S-function block.
1 Generate a TLC block file for the S-function by calling the legacy_code function
with 'sfcn_tlc_generate' as the first argument and the name of the Legacy Code
Tool data structure as the second argument.
4-67
4 Writing S-Functions in C
legacy_code('sfcn_tlc_generate', lct_spec);
Consider the example in “Integrate C Functions into Simulink Models with Legacy
Code Tool” on page 4-48. To generate a TLC file for the model shown at the end of
that example, enter the following command:
legacy_code('sfcn_tlc_generate', def);
2 Force Accelerator mode to use the TLC file by using the ssSetOptions SimStruct
function to set the S-function option SS_OPTION_USE_TLC_WITH_ACCELERATOR.
def = legacy_code('initialize');
def.Options.language = 'C++';
def.Options.language
Note The Legacy Code Tool can interface with C++ functions, but not C++ objects. For a
work around, see “Legacy Code Tool Limitations” on page 4-70 in the Simulink
documentation.
defs1 = lct_register_1;
defs2 = lct_register_2;
defs3 = lct_register_3;
defs = [defs1(:);defs2(:);defs3(:)];
4-68
Integrate C Functions Using Legacy Code Tool
You can then use the following sequence of calls to legacy_code in order to generate
files based on the three registration files:
legacy_code('sfcn_cmex_generate', defs);
legacy_code('compile', defs);
legacy_code('sfcn_tlc_generate', defs);
Alternatively, you can process each registration file separately. For example:
defs1 = lct_register1;
legacy_code('sfcn_cmex_generate', defs1);
legacy_code('compile', defs1);
legacy_code('sfcn_tlc_generate', defs1);
.
.
.
defs2 = lct_register2;
legacy_code('sfcn_cmex_generate', defs2);
legacy_code('compile', defs2);
legacy_code('sfcn_tlc_generate', defs2);
.
.
.
defs3 = lct_register3;
legacy_code('sfcn_cmex_generate', defs3);
legacy_code('compile', defs3);
legacy_code('sfcn_tlc_generate', defs3);
demo simulink
Legacy Code Tool examples are listed in Modeling Features > Custom Blocks with S-
functions, System Objects and Legacy Code Tool.
4-69
4 Writing S-Functions in C
• Generates C MEX S-functions for existing functions written in C or C++. The tool does
not support transformation of MATLAB or Fortran functions.
• Can interface with C++ functions, but not C++ objects. One way of working around
this limitation is to use the S-Function Builder to generate the shell of an S-function
and then call the legacy C++ code from the S-function's mdlOutputs callback
function.
• Does not support simulating continuous or discrete states. This prevents you from
using the mdlUpdate and mdlDerivatives callback functions. If your application
requires this support, see “Using the S-Function Builder to Incorporate Legacy Code”
on page 2-16.
• Always sets the S-functions flag for direct feedthrough on page 1-8
(sizes.DirFeedthrough) to true. Due to this setting and the preceding limitation,
the generated S-function cannot break algebraic loops.
• Supports only the continuous, but fixed in minor time step, sample time and offset on
page 1-10 option.
• Supports complex numbers, but only with Simulink built-in data types.
• Does not support use of function pointers as the output of the legacy function being
called.
• Does not support the following S-function features:
4-70
Simulink Engine Interaction with C S-Functions
You can examine how the Simulink engine interacts with S-functions from two
perspectives:
• Process perspective, i.e., at which points in a simulation the engine invokes the S-
function.
• Data perspective, i.e., how the engine and the S-function exchange information
during a simulation.
Process View
The following figures show the order in which the Simulink engine invokes the callback
methods in an S-function. Solid rectangles indicate callbacks that always occur during
model initialization or at every time step. Dotted rectangles indicate callbacks that may
occur during initialization and/or at some or all time steps during the simulation loop. See
the documentation for each callback method to determine the exact circumstances under
which the engine invokes the callback.
Note The process view diagram represents the execution of S-functions that contain
continuous and discrete states, enable zero-crossing detection, and reside in a model that
uses a variable-step solver. Different solvers omit certain steps in the diagram. For a
better understanding of how the Simulink engine executes your particular S-function, run
the model containing the S-function using the Simulink debugger. For more information,
see “Introduction to the Debugger”.
In the following model initialization loop, the Simulink engine configures the S-function
for an upcoming simulation. The engine always makes the required calls to
mdlInitializeSizes and mdlInitializeSampleTime to set up the fundamental
attributes of the S-function, including input and output ports, S-function dialog
parameters, work vectors, sample times, etc.
The engine calls additional methods, as needed, to complete the S-function initialization.
For example, if the S-function uses work vectors, the engine calls mdlSetWorkWidths.
4-71
4 Writing S-Functions in C
Also, if the mdlInitializeSizes method deferred setting up input and output port
attributes, the engine calls any methods necessary to complete the port initialization,
such as mdlSetInputPortWidth, during signal propagation. The mdlStart method
calls the mdlCheckParameters and mdlProcessParameters methods if the S-function
uses dialog parameters.
4-72
Simulink Engine Interaction with C S-Functions
Note The mdlInitializeSizes callback method also runs when you enter the name of
a compiled S-function into the S-Function Block Parameters dialog box.
After initialization, the Simulink engine executes the following simulation loop. If the
simulation loop is interrupted, either manually or when an error occurs, the engine jumps
directly to the mdlTerminate method. If the simulation was manually halted, the engine
first completes the current time step before invoking mdlTerminate.
4-73
4 Writing S-Functions in C
If your model contains multiple S-Function blocks at a given level of model hierarchy, the
engine invokes a particular method for every S-function before proceeding to the next
method. For example, the engine calls all the mdlInitializeSizes methods before
calling any mdlInitializeSampleTimes methods. The engine uses the block sorted
4-74
Simulink Engine Interaction with C S-Functions
order to determine the order to execute the S-functions. See “What Is Sorted Order?” in
Using Simulink to learn more about how the engine determines the block sorted order.
If you use the Simulink Coder product to generate code for a model containing S-
functions, the Simulink engine does not execute the entire calling sequence outlined
above. Initialization proceeds as outlined above until the engine reaches the mdlStart
method. The engine then calls the S-function methods shown in the following figure,
where the mdlRTW method is unique to the Simulink Coder product.
4-75
4 Writing S-Functions in C
The model contains two nonvirtual subsystems, the conditionally executed enabled
subsystem named Reset and the atomic subsystem named Atomic. Each subsystem
contains an S-Function block that calls the S-function dsfunc.c, which models a discrete
state-space system with two states. The enabled subsystem Reset resets the state values
when the subsystem is enabled, and the output values when the subsystem is disabled.
Using the generic real-time (GRT) target, the generated code for the model-wide Start
function calls the Start functions of the two subsystems before calling the model-wide
MdlInitialize function, as shown in the following code:
void MdlStart(void)
{
/* snip */
MdlInitialize();
4-76
Simulink Engine Interaction with C S-Functions
The Start function for the enabled subsystem calls the subsystem's
InitializeConditions function:
void sfcndemo_enablesub_Reset_Start(void)
{
sfcndemo_enablesub_Reset_Init();
/* snip */
}
void MdlInitialize(void)
{
/* InitializeConditions for atomic SubSystem:
'<Root>/Atomic' */
sfcndemo_enablesub_Atomic_Init();
}
Therefore, the model-wide Start function interleaves calls to the Start and
InitializeConditions functions for the two subsystems and the S-functions they
contain.
For more information about the Simulink Coder product and how it interacts with S-
functions, see “S-Functions and Code Generation” (Simulink Coder).
When you are running a Simulink model in external mode, the calling sequence for S-
function routines changes as shown in the following figure.
4-77
4 Writing S-Functions in C
The engine calls mdlRTW once when it enters external mode and again each time a
parameter changes or when you select Simulation > Update Diagram.
Note Running a Simulink model in external mode requires the Simulink Coder product.
Data View
S-function blocks have input and output signals, parameters, and 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
• Continuous states
• Discrete states
• Other working areas such as real, integer, or pointer work vectors
You can parameterize S-function blocks by passing parameters to them using the S-
Function Block Parameters dialog box.
The following figure shows the general mapping between these various types of data.
4-78
Simulink Engine Interaction with C S-Functions
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.
• Via pointers
• Using contiguous inputs
InputRealPtrsType uPtrs =
ssGetInputPortRealSignalPtrs(S,portIndex)
This returns an array of pointers for the input port with index portIndex, where
portIndex starts at 0. There is one array of pointers for each input port. To access an
element of this array you must use
*uPtrs[element]
The following figure describes how to access the input signals of an S-function with two
inputs.
4-79
4 Writing S-Functions in C
As shown in the previous figure, the input array pointers can point at noncontiguous
places in memory.
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.
This section describes how to access all input signals of a particular port and write them
to the output port. The preceding figure shows that the input array of pointers can 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.
4-80
See Also
int_T element;
int_T portWidth = ssGetInputPortWidth(S,inputPortIndex);
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,inputPortIndex);
real_T *y = ssGetOutputPortSignal(S,outputPortIdx);
A common mistake is to try to access the input signals via pointer arithmetic. For
example, if you were to place
just below the initialization of uPtrs and replace the inner part of the above loop with
the code compiles, but the MEX file might crash the Simulink software. 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 occurs when the signals entering your S-
function block are not contiguous. Noncontiguous signal data occurs when signals pass
through virtual connection blocks such as the Mux or Selector blocks.
To verify that your S-function correctly accesses wide input signals, pass a replicated
signal to each input port of your S-function. To do this, create a Mux block with the
number of input ports equal to the width of the desired signal entering your S-function.
Then, connect the driving source to each S-function input port, as shown in the following
figure. Finally, run your S-function using this input signal to verify that it does not crash
and produces expected results.
See Also
Level-2 MATLAB S-Function | MATLAB Function | S-Function | S-Function Builder
4-81
4 Writing S-Functions in C
More About
• “S-Function Concepts” on page 1-8
• “Use S-Functions in Models” on page 1-4
• “S-Function Callback Methods” on page 1-17
4-82
Write Callback Methods
4-83
4 Writing S-Functions in C
Note For additional information, see “Model Reference Requirements and Limitations”.
To remind you to check for any such dependency problems, an error message appears by
default for any S-function that is used in a Normal mode referenced model and contains
both an mdlProcessParameters function and an mdlStart function. The error
message does not mean that any dependency problems exist, but only that they might
exist.
If you get such an error message, check for any problematic dependencies in the S-
function, and recode as needed to eliminate them. When no such dependencies exist, you
can safely suppress the error message and use the S-function in a Normal mode
referenced model. To certify that the S-function is compliant, and the message is
therefore unnecessary, include the following statement in mdlInitializeSizes:
ssSetModelReferenceNormalModeSupport (S, MDL_START_AND_MDL_PROCESS_PARAMS_OK);
4-84
See Also
The limitations for using S-functions with multiple instances of referenced models in
Normal mode are the same as the limitations that apply to using S-functions with For
Each Subsystem block.
See Also
Level-2 MATLAB S-Function | MATLAB Function | S-Function | S-Function Builder
More About
• “S-Function Concepts” on page 1-8
• “S-Function Features and Limitations” on page 2-7
• “S-Function SimStruct Functions” on page 12-2
4-85
4 Writing S-Functions in C
The examples at the end of this section show how to debug a C MEX S-function during
simulation, using third-party software.
• The first example uses the Microsoft Visual C++® .NET (version 7.0) environment.
• The second example debugs an S-function on The Open Group UNIX® platform.
• Use the S-Function Builder block to generate simple S-functions and study the
contents of the source files.
• Inspect the S-function example models available in sfundemos. The folder
matlabroot/simulink/src (open) contains the S-function source files for these
models.
If your S-function is not compiling, first ensure that the mex command is properly
configured and your S-function includes all necessary files:
4-86
Debug C MEX S-Functions
If the mex command compiles your S-function, but your S-function does not simulate or
the simulation produces incorrect results, inspect your S-function source code to ensure
that:
The following table describes additional common S-function constructs that can lead to
compilation and simulation errors.
4-87
4 Writing S-Functions in C
4-88
Debug C MEX S-Functions
/* If ssSetInputPortRequiredContiguous is 0,
ssGetInputPortSignal returns an invalid pointer.*/
Debugging Techniques
You can use the following techniques for additional assistance with debugging your S-
function.
• Compile the S-function in debug mode using the -g option for the mex command. This
enables additional diagnostics features that are called only when you compile your S-
function in debug mode.
• Place ssPrintf statements inside your callback methods to ensure that they are
running and that they are executing in the order you expect. Also, use ssPrintf
statements to print return values to the MATLAB command prompt to check if your
code is producing the expected results.
• Type feature memstats at the MATLAB command prompt to query the memory
usage.
4-89
4 Writing S-Functions in C
• Use the MATLAB File & folder Comparisons tool, or other text differencing
application, to look for textual changes in different versions of your S-function. This
can help you locate changes that disabled an S-function that previously compiled and
ran. See “Compare Files and Folders and Merge Files” (MATLAB) for instructions on
how to use the File & folder Comparisons tool.
• Use settings on the Configuration Parameters dialog box to check for memory
problems.
You can additionally use third-party software to debug an S-function during simulation, as
shown in the following two examples. These examples use the Simulink model
sfcndemo_timestwo and the C MEX S-function timestwo.c.
Debugging C MEX S-Functions Using the Microsoft Visual C++ .NET Environment
Before beginning the example, save the files sfcndemo_timestwo and timestwo.c into
your working folder.
mex -g timestwo.c
4-90
Debug C MEX S-Functions
clear mex
9 From the Microsoft Development Environment File menu, select Open > File. Select
the timestwo.c source files from the file browser that opens.
10 Set a breakpoint on the desired line of code by right-clicking on the line and selecting
Insert Breakpoint from the context menu. If you have not previously run the model,
the breakpoint may show up with a question mark, indicating that the executable is
not loaded. Subsequently running the model loads the .mexw32 file and removes the
question mark from the breakpoint.
11 Start the simulation from the sfcndemo_timestwo Simulink model. You should be
running the S-function in the Microsoft Development Environment and can debug the
file within that environment.
Before beginning the example, save the files sfcndemo_timestwo and timestwo.c into
your working folder.
mex -g timestwo.c
4-91
4 Writing S-Functions in C
The -D flag starts the MATLAB environment within the specified debugger. For
example, to use the gdb debugging tool on the Linux® platform, enter this command.
matlab -Dgdb
2 Once the debugger has loaded, continue loading the MATLAB environment by typing
run at the debugger prompt (gdb).
run -nodesktop
Note The debugger might stop on spurious segmentation violation signals that result
from interactions with the underlying Java® Virtual Machine (JVM™). You can ignore
these messages and continue, using the cont command. If you are not debugging
segmentation violation signals and want to suppress these messages, enter the
command handle SIGSEGV nostop noprint pass.
3 Open the sfcndemo_timestwo Simulink model.
4 Press Ctrl+C to open the debugger.
5 At the (gdb) prompt, set breakpoints in the source code, for example:
break timestwo.c:37
4-92
See Also
See Also
Level-2 MATLAB S-Function | MATLAB Function | S-Function | S-Function Builder
More About
• “Check S-Functions Using S-Function Analyzer APIs” on page 7-2
4-93
4 Writing S-Functions in C
#define S_FUNCTION_LEVEL 2
• Update the contents of mdlInitializeSizes. In particular, add the following error
handling for the number of S-function parameters:
ssSetNumSFcnParams(S, NPARAMS); /*Number of expected parameters*/
if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
/* Return if number of expected != number of actual parameters */
return;
}
Set up the inputs using:
if (!ssSetNumInputPorts(S, 1)) return; /*Number of input ports */
ssSetInputPortWidth(S, 0, width); /* Width of input
port one (index 0)*/
ssSetInputPortDirectFeedThrough(S, 0, 1); /* Direct feedthrough
or port one */
ssSetInputPortRequiredContiguous(S, 0);
Set up the outputs using:
if (!ssSetNumOutputPorts(S, 1)) return;
ssSetOutputPortWidth(S, 0, width); /* Width of output port
one (index 0) */
4-94
Convert Level-1 C MEX S-Functions
#define MDL_INITIALIZE_CONDITIONS
static void mdlInitializeConditions(SimStruct *S)
{
}
• Access the continuous states using ssGetContStates. The ssGetX macro has
been removed.
• Access the discrete states using ssGetRealDiscStates(S). The ssGetX macro
has been removed.
• For mixed continuous and discrete state S-functions, the state vector no longer
consists of the continuous states followed by the discrete states. The states are
saved in separate vectors and hence might not be contiguous in memory.
• The mdlOutputs prototype has changed from
to
Since y, x, and u are not explicitly passed in to Level-2 S-functions, you must use
to
#define MDL_UPDATE
static void mdlUpdate(SimStruct *S, int_T tid)
{
}
4-95
4 Writing S-Functions in C
#define MDL_DERIVATIVES
static void mdlDerivatives(SimStruct *S)
{
}
On a PC, to use the highest warning levels, you must create a project file inside the
integrated development environment (IDE) for the compiler you are using. Within the
project file, define MATLAB_MEX_FILE and add
matlabroot/simulink/include
matlabroot/extern/include
Obsolete Macros
The following macros are obsolete. Replace each obsolete macro with the macro specified
in the following table.
1. UNIX is a registered trademark of The Open Group in the United States and other countries.
4-96
See Also
See Also
Level-2 MATLAB S-Function | MATLAB Function | S-Function | S-Function Builder
4-97
4 Writing S-Functions in C
More About
• “Create a Basic C MEX S-Function” on page 4-2
4-98
5
The procedure for creating C++ S-functions is nearly the same as that for creating C S-
functions. The following sections explain the differences.
In addition, set up the MEX function to use a C++ compiler (see “Build MEX File”
(MATLAB)). To build the C++ S-function, see “Build C++ S-Functions” on page 5-4.
C++ References
[1] Meyers, S., More Effective C++, Boston, Addison-Wesley, 1996, Item 34
[2] Oualline, S., Practical C++ Programming, Sebastopol, California, O'Reilly, 1995,
Chapter 27
[3] Stroustrup, B., The C++ Programming Language, 3rd Ed., Boston, Addison-Wesley,
1997, Appendix B
5-2
Make C++ Objects Persistent
1 Create a pointer work vector to hold pointers to the persistent object between
method invocations:
static void mdlInitializeSizes(SimStruct *S)
{
...
ssSetNumPWork(S, 1); // reserve element in the pointers vector
// to store a C++ object
...
}
2 Store a pointer to each object that you want to be persistent in the pointer work
vector:
static void mdlStart(SimStruct *S)
{
ssGetPWork(S)[0] = (void *) new counter; // store new C++ object in the
} // pointers vector
3 Retrieve the pointer in any subsequent method invocation to access the object:
static void mdlOutputs(SimStruct *S, int_T tid)
{
counter *c = (counter *) ssGetPWork(S)[0]; // retrieve C++ object from
real_T *y = ssGetOutputPortRealSignal(S,0); // the pointers vector and
y[0] = c->output(); // use member functions of
} // the object
4 Destroy the objects when the simulation terminates:
static void mdlTerminate(SimStruct *S)
{
counter *c = (counter *) ssGetPWork(S)[0]; // retrieve and destroy C++
delete c; // object in the termination
} // function
5-3
5 Creating C++ S-Functions
mex sfun_counter_cpp.cpp
Note The extension of the source file for a C++ S-function must be .cpp to ensure that
the compiler treats the contents of the file as C++ code.
5-4
6
In this section...
“About Creating Level-2 Fortran S-Functions” on page 6-2
“Template File” on page 6-2
“C/Fortran Interfacing Tips” on page 6-2
“Constructing the Gateway” on page 6-7
“Example C MEX S-Function Calling Fortran Code” on page 6-9
Using the C MEX S-function as a gateway is quite simple if you are writing the Fortran
code from scratch. If instead you have legacy Fortran code that exists as a standalone
simulation, there is some work to be done to identify parts of the code that need to be
registered with the Simulink software, such as identifying continuous states if you are
using variable-step solvers or getting rid of static variables if you want to have multiple
copies of the S-function in a Simulink model (see “Port Legacy Code” on page 6-11).
Template File
The file sfuntmpl_gate_fortran.c contains a template for creating a C MEX-file S-
function that invokes a Fortran subroutine in its mdlOutputs method. It works with a
simple Fortran subroutine if you modify the Fortran subroutine name in the code. The
template allocates DWork vectors to store the data that communicates with the Fortran
subroutine. See “How to Use DWork Vectors” on page 8-7 for information on setting up
DWork vectors.
6-2
Create Level-2 Fortran S-Functions
MEX Environment
mex -setup needs to find the MATLAB, C, and the Fortran compilers, but it can work
with only one of these compilers at a time. If you change compilers, you must run mex -
setup between other mex commands.
Test the installation and setup using sample MEX-files from the MATLAB, C, and Fortran
MEX examples in the folder matlabroot/extern/examples/mex (open), as well as S-
function examples.
If using a C compiler on a Microsoft Windows platform, test the mex setup using the
following commands and the example C source code file, yprime.c, in matlabroot/
extern/examples/mex.
cd(fullfile(matlabroot,'\extern\examples\mex'))
mex yprime.c
If using a Fortran compiler, test the mex setup using the following commands and the
example Fortran source code files, yprime.F and yprimefg.F, in matlabroot/
extern/examples/mex.
cd(fullfile(matlabroot,'\extern\examples\mex'))
mex yprimef.f yprimefg.f
Compiler Compatibility
Your C and Fortran compilers need to use the same object format. If you use the
compilers explicitly supported by the mex command this is not a problem. When you use
the C gateway to Fortran, it is possible to use Fortran compilers not supported by the mex
command, but only if the object file format is compatible with the C compiler format.
Common object formats include ELF and COFF.
The compiler must also be configurable so that the caller cleans up the stack instead of
the callee. Intel® Visual Fortran (the replacement for Compaq® Visual Fortran) has the
default stack cleanup as the caller.
Symbol Decorations
Symbol decorations can cause run-time errors. For example, g77 decorates subroutine
names with a trailing underscore when in its default configuration. You can either
recognize this and adjust the C function prototype or alter the Fortran compiler's name
6-3
6 Creating Fortran S-Functions
decoration policy via command-line switches, if the compiler supports this. See the
Fortran compiler manual about altering symbol decoration policies.
If all else fails, use utilities such as od (octal dump) to display the symbol names. For
example, the command
od -s 2 <file>
These binary utilities can be obtained for the Windows platform as well. The MKS, Inc.
company provides commercial versions of powerful utilities for The Open Group UNIX
platforms. Additional utilities can also be obtained free on the Web. hexdump is another
common program for viewing binary files. As an example, here is the output of
od -s 2 sfun_atmos_for.o
on a Linux platform.
0000115 E¨
0000136 E¨
0000271 E¨"
0000467 ˙E¨@
0000530 ˙E¨
0000575 E¨ E 5@
0001267 CfƒVC- :C
0001323 :|.-:8˘#8 Kw6
0001353 ?333@
0001364 333
0001414 01.01
0001425 GCC: (GNU) egcs-2.91.66 19990314/
0001522 .symtab
0001532 .strtab
0001542 .shstrtab
0001554 .text
0001562 .rel.text
0001574 .data
0001602 .bss
0001607 .note
0001615 .comment
0003071 sfun_atmos_for.for
0003101 gcc2_compiled.
0003120 rearth.0
0003131 gmr.1
6-4
Create Level-2 Fortran S-Functions
0003137 htab.2
0003146 ttab.3
0003155 ptab.4
0003164 gtab.5
0003173 atmos_
0003207 exp
0003213 pow_d
Note that Atmos has been changed to atmos_, which the C program must call to be
successful.
With Visual Fortran on 32-bit Windows machines, the symbol is suppressed, so that Atmos
becomes ATMOS (no underscore).
Fortran math library symbols might not match C math library symbols. For example, A^B
in Fortran calls library function pow_dd, which is not in the C math library. In these cases,
you must tell mex to link in the Fortran math library. For gcc environments, these
routines are usually found in /usr/local/lib/libf2c.a, /usr/lib/libf2c.a, or
equivalent.
Note On a UNIX system, the -lf2c option follows the conventional UNIX library linking
syntax, where -l is the library option itself and f2c is the unique part of the library file's
name, libf2c.a. Be sure to use the -L option for the library search path, because -I is
only followed while searching for include files.
The f2c package can be obtained for the Windows and UNIX environments from the
Internet. The file libf2c.a is usually part of g77 distributions, or else the file is not
needed as the symbols match. In obscure cases, it must be installed separately, but even
this is not difficult once the need for it is identified.
On 32-bit Windows machines, using Microsoft Visual C++ and Intel Visual Fortran 10.1,
this example can be compiled using the following two mex commands. Enter each
command on one line. The mex -setup C command must be run to return to the C
compiler before executing the second command. In the second command, replace the
6-5
6 Creating Fortran S-Functions
On 64-bit Windows machines, using Visual C++ and Visual Fortran 10.1, this example can
be compiled using the following two mex commands (each command is on one line). The
mex -setup C command must be run to return to the C compiler before executing the
second command. The variable IFORT_COMPILER10 is the name of the system's
environment variable pointing to the Visual Fortran 10.1 root folder and may vary on your
system. Replace matlabroot with the path name to your MATLAB root folder.
mex -v -c fullfile(matlabroot,'toolbox','simulink','simdemos','simfeatures',
'srcFortran','sfun_atmos_sub.F'), -f fullfile(matlabroot,'bin','win64','mexopts',
'intelf10msvs2005opts.bat'))
CFortran
Or you can try using CFortran to create an interface. CFortran is a tool for automated
interface generation between C and Fortran modules, in either direction. Search the Web
for cfortran or visit
http://www-zeus.desy.de/~burow/cfortran/
for downloading.
On a Windows machine, using Visual C++ with Fortran is best done with Visual Fortran
10.1.
For an up-to-date list of all the supported compilers, see the MathWorks supported and
compatible compiler list at:
https://www.mathworks.com/support/compilers/current_release/
6-6
Create Level-2 Fortran S-Functions
Simple Case
The Fortran code must at least be callable in one-step-at-a-time fashion. If the code
doesn't have any states, it can be called from mdlOutputs and no mdlDerivatives or
mdlUpdate method is required.
If the code has states, you must decide whether the Fortran code can support a variable-
step solver or not. For fixed-step solver only support, the C gateway consists of a call to
the Fortran code from mdlUpdate, and outputs are cached in an S-function DWork vector
so that subsequent calls by the Simulink engine into mdlOutputs will work properly and
the Fortran code won't be called until the next invocation of mdlUpdate. In this case, the
states in the code can be stored however you like, typically in the work vector or as
discrete states.
If instead the code needs to have continuous time states with support for variable-step
solvers, the states must be registered and stored with the engine as doubles. You do this
in mdlInitializeSizes (registering states), then the states are retrieved and sent to
the Fortran code whenever you need to execute it. In addition, the main body of code has
to be separable into a call form that can be used by mdlDerivatives to get derivatives
for the state integration and also by the mdlOutputs and mdlUpdate methods as
appropriate.
Setup Code
If there is a lengthy setup calculation, it is best to make this part of the code separable
from the one-step-at-a-time code and call it from mdlStart. This can either be a separate
SUBROUTINE called from mdlStart that communicates with the rest of the code through
COMMON blocks or argument I/O, or it can be part of the same piece of Fortran code that is
isolated by an IF-THEN-ELSE construct. This construct can be triggered by one of the
input arguments that tells the code if it is to perform either the setup calculations or the
one-step calculations.
6-7
6 Creating Fortran S-Functions
To be able to call Fortran from the Simulink software directly without having to launch
processes, etc., you must convert a Fortran PROGRAM into a SUBROUTINE. This consists of
three steps. The first is trivial; the second and third can take a bit of examination.
1 Change the line PROGRAM to SUBROUTINE subName.
It is customary to strip out all hard-coded cases and output dumps. In the Simulink
environment, you want to convert inputs and outputs into block I/O.
3 If you are converting a standalone simulation to work inside the Simulink
environment, identify the main loop of time integration and remove the loop and, if
you want the Simulink engine to integrate continuous states, remove any time
integration code. Leave time integrations in the code if you intend to make a discrete
time (sampled) S-function.
Arguments to a SUBROUTINE
Most Fortran compilers generate SUBROUTINE code that passes arguments by reference.
This means that the C code calling the Fortran code must use only pointers in the
argument list.
PROGRAM ...
becomes
SUBROUTINE somename( U, X, Y )
A SUBROUTINE never has a return value. You manage I/O by using some of the arguments
for input, the rest for output.
Arguments to a FUNCTION
A FUNCTION has a scalar return value passed by value, so a calling C program should
expect this. The argument list is passed by reference (i.e., pointers) as in the
SUBROUTINE.
If the result of a calculation is an array, then you should use a subroutine, as a FUNCTION
cannot return an array.
6-8
Create Level-2 Fortran S-Functions
While there are several ways for Fortran COMMON blocks to be visible to C code, it is often
recommended to use an input/output argument list to a SUBROUTINE or FUNCTION. If the
Fortran code has already been written and uses COMMON blocks, it is a simple matter to
write a small SUBROUTINE that has an input/output argument list and copies data into
and out of the COMMON block.
The procedure for copying in and out of the COMMON block begins with a write of the
inputs to the COMMON block before calling the existing SUBROUTINE. The SUBROUTINE is
called, then the output values are read out of the COMMON block and copied into the
output variables just before returning.
/*
* Windows uses upper case for Fortran external symbols
*/
#ifdef _WIN32
#define atmos_ ATMOS
#endif
The mdlOutputs method calls the Fortran subroutine using pass-by-reference for the
arguments.
6-9
6 Creating Fortran S-Functions
To see this example working in the sample model sfcndemo_atmos, enter the following
command at the MATLAB command prompt.
sfcndemo_atmos
On 64-bit Windows systems using Intel C++ 12.0 and Intel Visual Fortran 12, you need to
use separate commands to compile the Fortran file and then link it to the C gateway file.
Each command is on one line.
On some UNIX systems where the C and Fortran compilers were installed separately (or
are not aware of each other), you might need to reference the library libf2c.a. To do
this, use the -lf2c flag.
If the libf2c.a library is not on the library path, you need to add the path to the mex
process explicitly with the -L command. For example:
6-10
Port Legacy Code
Telltale signs of implicit advancement are incremented variables such as M=M+1 or X=X
+0.05. If the code has many of these constructs and you determine that it is impractical
to recode the source so as not to “ratchet forward,” you might need to try another
approach using fixed-step solvers.
If it is impractical to find all the implicit states and to separate out the derivative
calculations for the Simulink engine, another approach can be used, but you are limited to
using fixed-step solvers. The technique here is to call the Fortran code from the
mdlUpdate method so the Fortran code is only executed once per major simulation
integration step. Any block outputs must be cached in a work vector so that mdlOutputs
can be called as often as needed and output the values from the work vector instead of
calling the Fortran routine again (causing it to inadvertently advance time). See
sfuntmpl_gate_fortran.c for an example that uses DWork vectors. See “How to Use
DWork Vectors” on page 8-7 for details on allocating data-typed work vectors.
Sample Times
If the Fortran code has an implicit step size in its algorithm, coefficients, etc., ensure that
you register the proper discrete sample time in the C S-function
6-11
6 Creating Fortran S-Functions
mdlInitializeSampleTimes method and only change the block's output values from
the mdlUpdate method.
Store Data
If you plan to have multiple copies of this S-function used in one Simulink model, you
need to allocate storage for each copy of the S-function in the model. The recommended
approach is to use DWork vectors (see “DWork Vector Basics” on page 8-2).
If you plan to have only one copy of the S-function in the model, DWork vectors still
provide the most advanced method for storing data. However, another alternative is to
allocate a block of memory using the malloc command and store the pointer to that
memory in a PWork vector (see “Elementary Work Vectors” on page 8-20). In this case,
you must remember to deallocate the memory using the free command in the S-function
mdlTerminate method.
DOUBLE PRECISION F
:
:
F = F + 1.0
TIME = 0.003 * F
6-12
Port Legacy Code
6-13
7
Prerequisites
To complete the tutorial, you need the following products:
• MATLAB
• Simulink
• Polyspace® (optional)
• C compiler – For most platforms, a default C compiler is supplied with the MATLAB
installation. For a list of supported compilers, see “Change Default Compiler”
(MATLAB). You can also change the default compiler using mex -setup command.
• ex_slexSfunctionCheckExample.slx
• external.c
• external.h
• sfcnModifyMinorStepDiscState.c
7-2
Check S-Functions Using S-Function Analyzer APIs
• sfcnModifyMinorStepDiscState_wrapper.c
• sfcnUpdateModifyContinuous.c
• sfcnUpdateModifyContinuous_wrapper.c
• sfcnUseExternalSrc.c
• slexBadSFcn.c
• slexBadSFcn_wrapper.c
To specify the build information, such as S-function source code, external libraries, and
header files, you can use Simulink.sfunction.analyzer.BuildInfo. In this tutorial,
because we have four S-functions in the model, there are four different BuildInfo
objects. For more information, see Simulink.sfunction.Analyzer and
Simulink.sfunction.analyzer.BuildInfo.
bdInfo1= Simulink.sfunction.analyzer.BuildInfo('sfcnUseExternalSrc.c',...
'ExtraSrcFileList',{'external.c'},...
'SrcPaths',{pwd},'IncPaths',{pwd});
bdInfo2= Simulink.sfunction.analyzer.BuildInfo('sfcnModifyMinorStepDiscState.c',...
'ExtraSrcFileList',{'sfcnModifyMinorStepD
'SrcPaths',{pwd});
bdInfo3= Simulink.sfunction.analyzer.BuildInfo('sfcnUpdateModifyContinuous.c',...
7-3
7 Run S-Function Analyzer
'ExtraSrcFileList',{'sfcnUpdateModifyCont
'SrcPaths',{pwd});
bdInfo4= Simulink.sfunction.analyzer.BuildInfo('slexBadSFcn.c',...
'ExtraSrcFileList',{'slexBadSFcn_wrapper.
'SrcPaths',{pwd});
You can configure the options for executing the S-function analyzer using
Simulink.sfunction.analyzer.Options class. You can enable Polyspace Code
Prover™ check and parameter robustness check, set the maximum model simulation time,
and set the report path. If you do not use the class to specify any of the options, the
default options are applied to the analysis. See
Simulink.sfunction.analyzer.Options for more details.
Note Running Polyspace Code Prover and parameter robustness checks take some time.
Performing Polyspace Code Prover checks requires a Polyspace license. For more
information on using Polyspace checks in the S-function analyzer, see “Enable Polyspace
Checks” on page 7-10. For this tutorial, parameter robustness checks are turned on.
opts = Simulink.sfunction.analyzer.Options();
opts.EnableRobustness = 1;
sfunAnalyzer = Simulink.sfunction.Analyzer(model,'BuildInfo',{bdInfo1,bdInfo2,bdInfo3,b
analysisResult=sfunAnalyzer.run();
sfunAnalyzer.generateReport()
When applied, the generateReport method produces a struct and an HTML report of
the result of S-function analyzer checks.
analysisResult =
7-4
Check S-Functions Using S-Function Analyzer APIs
Platform: 'win64'
Release: '(R2017b)'
SimulinkVersion: '9.0'
ExemptedBlocks: {}
MexConfiguration: [1×1 mex.CompilerConfiguration]
Data: [4×4 struct]
7-5
7 Run S-Function Analyzer
mdlOutputs. To fix this issue, discrete states should only be modified at a major step
guarded by ssIsMajorTimeStep.
The MEX Compile Check description code indicates that there is an unused variable
in the line indicated on the report. This warning is eliminated by deleting the line 208
and rerunning the code.
7-6
Check S-Functions Using S-Function Analyzer APIs
7-7
7 Run S-Function Analyzer
#define MDL_UPDATE
static void mdlUpdate(SimStruct *S, int_T tid)
{
/* update the discrete states here! */
real_T *xD = ssGetDiscStates(S);
}
6
7-8
Check S-Functions Using S-Function Analyzer APIs
To fix the issue in this particular example, delete the ssSetOptions function.
ssSetNumContStates(S, NUM_CONT_STATES);
ssSetNumContStates(S, NUM_CONT_STATES);
ssSetNumDiscStates(S, NUM_DISC_STATES);
ssSetNumDiscStates(S, NUM_DISC_STATES);
if (!ssSetNumInputPorts(S, NUM_INPUTS))
if (!ssSetNumInputPorts(S,
return; NUM_INPUTS)) r
ssSetInputPortWidth(S, 0, INPUT_0_WIDTH);
ssSetInputPortWidth(S, 0, INPUT_0_WIDTH);
ssSetInputPortDataType(S, 0, SS_DOUBLE);
ssSetInputPortDataType(S, 0, SS_DOUBLE);
ssSetInputPortComplexSignal(S, 0, INPUT_0_COMPLEX);
ssSetInputPortComplexSignal(S, 0, INPUT_0
ssSetInputPortDirectFeedThrough(S, ssSetInputPortDirectFeedThrough(S,
0, INPUT_0_FEEDTHROUGH); 0, INP
ssSetInputPortRequiredContiguous(S,ssSetInputPortRequiredContiguous(S,
0, 1); /*direct input signal access*/
0, 1)
if (!ssSetNumOutputPorts(S, NUM_OUTPUTS))
if (!ssSetNumOutputPorts(S,
return; NUM_OUTPUTS))
ssSetOutputPortWidth(S, 0, OUTPUT_0_WIDTH);
ssSetOutputPortWidth(S, 0, OUTPUT_0_WIDTH
ssSetOutputPortDataType(S, 0, SS_DOUBLE);
ssSetOutputPortDataType(S, 0, SS_DOUBLE);
ssSetOutputPortComplexSignal(S, 0, ssSetOutputPortComplexSignal(S,
OUTPUT_0_COMPLEX); 0, OUTPUT
ssSetNumSampleTimes(S, 1); ssSetNumSampleTimes(S, 1);
ssSetNumRWork(S, 0); ssSetNumRWork(S, 0);
ssSetNumIWork(S, 0); ssSetNumIWork(S, 0);
ssSetNumPWork(S, 0); ssSetNumPWork(S, 0);
ssSetNumModes(S, 0); ssSetNumModes(S, 0);
ssSetNumNonsampledZCs(S, 0); ssSetNumNonsampledZCs(S, 0);
}
ssSetOptions(S, SS_OPTION_CAN_BE_CALLED_CONDITIONALLY);
}
When you fix all issues in your model, the report shows green check marks for each group
of checks.
7-9
7 Run S-Function Analyzer
You can check for the use of undocumented APIs in your S-function source code to avoid
any incompatibilities in the future releases. To enable this check, in the
Simulink.sfunction.analyzer.Options object, set EnableUsePublishedOnly to 1.
Alternatively, when building your MEX files, use -DUSE_PUBLISHED_ONLY option. For
example, try building sfcnModifyMinorStepDiscState.c with this option using:
S-function analyzer gives you the option to run Polyspace Code Prover checks on your
code. To enable the check, in the Simulink.sfunction.analyzer.Options object, set
EnablePolyspace to 1. Polyspace Code Prover divides checks into red, green, orange,
and gray checks. For more information on types of checks, see “Code Prover Result and
Source Code Colors” (Polyspace Code Prover).
In the S-function analyzer, the most important error code is red. If the S-function source
code fails execution in all paths, Polyspace Code Prover gives a red check error. For more
information, see “Interpret Polyspace Code Prover Results” (Polyspace Code Prover).
Here is an example on how to troubleshoot the red check error.
7-10
Check S-Functions Using S-Function Analyzer APIs
The red Polyspace Code Prover check indicates that there is a problem in your S-function
source code. To investigate the issue using Polyspace, click the hyperlink in the report.
This link automatically opens a Polyspace Project window. In the Results List pane,
expand Red Check and select the error. The source file opens in the Source window.
From this window, you can fix and save your code the same way as you do in the MATLAB
Editor.
7-11
7 Run S-Function Analyzer
The Polyspace Code Prover error code indicates a problem with a pointer. Pointer *p is
out of bounds because it is used in an earlier loop. Correct the error by replacing this
pointer with a variable of your choice, or deleting *p from this line of code.
7-12
See Also
See Also
Simulink.sfunction.Analyzer | Simulink.sfunction.analyzer.BuildInfo |
Simulink.sfunction.analyzer.Options |
Simulink.sfunction.analyzer.findSfunctions
See Also
More About
• “Troubleshoot S-Function Checks” on page 7-14
See Also
Related Examples
• “Run Quality Checks on S-Functions”
7-13
7 Run S-Function Analyzer
Environment Checks
Environment checks inspect your environment for S-function analyzer APIs. This check
includes the MEX compiler setup check.
This check indicated the presence of the MEX compiler in the current machine. A default C
compiler is included in your MATLAB installation. To see the supported list of compilers,
see “Change Default Compiler” (MATLAB). You can change the default compiler by typing
mex -setup at the command line.
The MEX compile check uses MEX compilers to identify compiler warnings and errors in
the S-function source code.
If you have a Polyspace license, this check uses Polyspace Code Prover to conduct code
analysis. See “Polyspace Verification” (Polyspace Code Prover) for more information.
MdlOutputsModifyContinuousStates
This check indicates that the continuous states of the S-function are modified in the
mdlOutputs method. Continuous states can only be modified at a major time step and
7-14
Troubleshoot S-Function Checks
MdlUpdateModifyContinuousStates
This check indicates whether the continuous states of the S-function are modified in the
mdlUpdate method. Continuous states can only be modified at a major time step and
requires the ssSetSolverNeedsReset macro to reset the S-function solver. Changing
the S-function states without resetting the solver can lead to unexpected results.
MinorStepModifyDiscreteStates
This check indicates whether the discrete states of the S-function are modified in its
mdlOutputs method at a minor step. Discrete states of an S-function can only be
modified at a major step, guarded by sslsMajorTimeStep.
MinorStepModifyModes
This check investigates whether the mode vector of the S-function is modified in the
mdlOutputs at a minor step. Mode step of the S-function can only be modified at a major
time step, guarded by ssIsMajorTimeStep function.
GlobalStaticAsInvisibleState
This check indicates whether the S-function is using static or global variables to
represent internal states. To avoid unexpected behavior that results from having the S-
function in multiple S-function blocks, declare the S-function states explicitly using
ssSetNumDiscreteStates or using data store memory function APIs.
ContinuousStateWithoutContinuousSampleTime
This check inspects whether the S-function continuous sample time is explicitly declared
when it has continuous states. You can use ssSetSampleTime to specify continuous
sample time when S-function has continuous states.
CombinedMdlOutputsMdlUpdateWithDiscreteState
This check inspects whether the S-function mdlUpdate and mdlOutputs methods are
combined when the S-function has discrete states. When the S-function has discrete
states, define mdlUpdate and mdlOutputs methods separately and modify discrete
states only in the mdlUpdate method.
7-15
7 Run S-Function Analyzer
DeclareCanBeConditionalExecWithState
TestHarnessCreationError
This error code indicates that the S-function analyzer encounters an error when creating
test harness for the input S-functions in a Simulink library. Possible reasons could be a
missing .mex file or mask parameter definitions.
ModelCompileError
The S-function analyzer encounters error when compiling the input model. You can try to
recompile the model and check the diagnostic viewer for more information.
See Also
Simulink.sfunction.Analyzer | Simulink.sfunction.analyzer.BuildInfo |
Simulink.sfunction.analyzer.Options |
Simulink.sfunction.analyzer.findSfunctions
More About
• “Check S-Functions Using S-Function Analyzer APIs” on page 7-2
7-16
See Also
See Also
Related Examples
• “Run Quality Checks on S-Functions”
7-17
8
You can create an S-function that is reentrant by using DWork vectors that the engine
manages for each particular instance of the S-function.
Note DWork vectors are the most generalized and versatile type of work vector and the
following sections focus on their use. The Simulink product provides additional
elementary types of work vectors that support floating-point, integer, pointer, and mode
data. You can find a discussion of these work vectors in “Elementary Work Vectors” on
page 8-20.
8-2
DWork Vector Basics
DWork vectors provide the most flexibility for setting data types, names, etc., of the data
in the simulation and during code generation. The following list describes all the
properties that you can set on a DWork vector:
• Data type
• Size
• Numeric type, either real or complex
• Name
• Usage type (see “Types of DWork Vectors” on page 8-5)
• Simulink Coder identifier
• Simulink Coder storage class
• Simulink Coder C type qualifier
See “How to Use DWork Vectors” on page 8-7 for instructions on how to set these
properties. The three Simulink Coder properties pertain only to code generation and have
no effect during simulation.
To see how this connection is useful, consider an S-function that uses a global variable to
store data. If more than one copy of the S-function exists in a model, each instance of the
S-function must carefully allocate, manipulate, and deallocate each piece of memory it
uses.
In an S-function that uses DWork vectors, the engine, not the S-function, manages the
memory for the DWork vector. At the start of a simulation, the engine allocates the
memory required for each instance of the S-function based on the size and the data type
of the DWork vector contents. At the end of the simulation, the engine automatically
deallocates the memory.
Note You have no control over how the engine allocates memory for DWork vectors
during simulation. When using the Simulink Coder software, you can use storage classes
to customize the memory allocation during code generation. See the
8-3
8 Using Work Vectors
The engine also performs special tasks based on the type of DWork vector used in the S-
function. For example, it includes DWork vectors that store discrete state information in
the model-wide state vector and makes them available during state logging.
8-4
Types of DWork Vectors
S-functions register the DWork vector type using the ssSetDWorkUsageType macro.
This macro accepts one of the four usage types described in the following table.
8-5
8 Using Work Vectors
8-6
How to Use DWork Vectors
In this section...
“Using DWork Vectors in C MEX S-Functions” on page 8-7
“DWork Vector C MEX Macros” on page 8-10
“Using DWork Vectors With Legacy Code” on page 8-11
ssSetNumDWork(S, 2);
Although the mdlInitializeSizes method tells the Simulink engine how many
DWork vectors the S-function will use, the engine does not allocate memory for the
DWork vectors, at this time.
An S-function can defer specifying the number of DWork vectors until all information
about the S-function inputs is available by passing the value DYNAMICALLY_SIZED to
the ssSetNumDWork macro. If an S-function defers specifying the number of DWork
vectors in mdlInitializeSizes, it must provide a mdlSetWorkWidths method to
set up the DWork vectors.
2 If the S-function does not provide an mdlSetWorkWidths method, the
mdlInitializeSizes method sets any applicable attributes for each DWork vector.
For example, the following lines initialize the widths and data types of the DWork
vectors initialized in the previous step.
ssSetDWorkWidth(S, 0, 2);
ssSetDWorkWidth(S, 1, 1);
ssSetDWorkDataType(S, 0, SS_DOUBLE);
ssSetDWorkDataType(S, 1, SS_BOOLEAN);
8-7
8 Using Work Vectors
The following table lists attributes you can set for a DWork vector and shows an
example of the macro that sets it. See ssSetDWorkRTWStorageClass for a list of
supported storage classes.
Attribute Macro
Data type ssSetDWorkDataType(S, 0, SS_DOUBLE);
Size ssSetDWorkWidth(S, 0, 2);
Name ssSetDWorkName(S, 0, "sfcnState");
Usage type ssSetDWorkUsageType(S, 0,
SS_DWORK_USED_AS_DSTATE);
Numeric type, either real or ssSetDWorkComplexSignal(S, 0, COMPLEX_NO);
complex
Simulink Coder identifier ssSetDWorkRTWIdentifier(S, 0, "Gain");
Simulink Coder storage class ssSetDWorkRTWStorageClass(S, 0, 2);
Simulink Coder C type qualifier ssSetDWorkRTWTypeQualifier(S, 0, "volatile");
3 In mdlStart, initialize the values of any DWork vectors that should be set only at the
beginning of the simulation. Use the ssGetDWork macro to retrieve a pointer to each
DWork vector and initialize the values. For example, the following mdlStart method
initializes the first DWork vector.
static void mdlStart(SimStruct *S)
{
real_T *x = (real_T*) ssGetDWork(S,0);
The Simulink engine allocates memory for the DWork vector before calling the
mdlStart method. Because the mdlStart method is called only once at the
beginning of the simulation, do not use it for data or states that need to be
reinitialized, for example, when reenabling a disabled subsystem containing the S-
function.
4 In mdlInitializeConditions, initialize the values of any DWork vectors that need
to be reinitialized at certain points in the simulation. The engine executes
mdlInitializeConditions at the beginning of the simulation and any time an
enabled subsystem containing the S-function is reenabled. See the mdlStart
8-8
How to Use DWork Vectors
example in the previous step for the commands used to initialize DWork vector
values.
5 In mdlOutputs, mdlUpdate, etc., use the ssGetDWork macro to retrieve a pointer
to the DWork vector and use or update the DWork vector values. For example, for a
DWork vector storing two discrete states, the following mdlOutputs and mdlUpdate
methods calculate the output and update the discrete state values.
/* y=Cx+Du */
y[0]=C[0][0]*x[0]+C[0][1]*x[1]+D[0][0]*U(0)+D[0][1]*U(1);
y[1]=C[1][0]*x[0]+C[1][1]*x[1]+D[1][0]*U(0)+D[1][1]*U(1);
}
}
#define MDL_UPDATE
/* Function: mdlUpdate ===============================================
* Abstract:
* xdot = Ax + Bu
*/
static void mdlUpdate(SimStruct *S, int_T tid)
{
real_T tempX[2] = {0.0, 0.0};
real_T *x = (real_T*) ssGetDWork(S, 0);
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
/* xdot=Ax+Bu */
tempX[0]=A[0][0]*x[0]+A[0][1]*x[1]+B[0][0]*U(0)+B[0][1]*U(1);
tempX[1]=A[1][0]*x[0]+A[1][1]*x[1]+B[1][0]*U(0)+B[1][1]*U(1);
x[0]=tempX[0];
x[1]=tempX[1];
}
8-9
8 Using Work Vectors
You do not have to include any code in the mdlTerminate method to deallocate the
memory used to store the DWork vector. Similarly, if you are generating inlined code for
the S-function, you do not have to write an mdlRTW method to access the DWork vector in
the TLC file. The Simulink software handles these aspects of the DWork vector for you.
Macro Description
ssSetNumDWork Specify the number of DWork
vectors.
ssGetNumDWork Query the number of DWork vectors.
ssGetDWork Get a pointer to a specific DWork
vector.
ssGetDWorkComplexSignal Determine if a specific DWork vector
is real or complex.
ssGetDWorkDataType Get the data type of a DWork vector.
ssGetDWorkName Get the name of a DWork vector.
ssGetDWorkRTWIdentifier Get the identifier used to declare a
DWork vector in the generated code.
ssGetDWorkRTWIdentifierMustResolveToSignalObjec Indicate if a DWork vector must
t resolve to a Simulink.Signal
object in the MATLAB workspace.
ssGetDWorkRTWStorageClass Get the storage class of a DWork
vector.
ssGetDWorkRTWTypeQualifier Get the C type qualifier used to
declare a DWork vector in the
generated code.
ssGetDWorkUsageType Determine how a DWork vector is
used in the S-function.
ssGetDWorkUsedAsDState Determine if a DWork vector stores
discrete states.
ssGetDWorkWidth Get the size of a DWork vector.
8-10
How to Use DWork Vectors
Macro Description
ssSetDWorkComplexSignal Specify if the elements of a DWork
vector are real or complex.
ssSetDWorkDataType Specify the data type of a DWork
vector.
ssSetDWorkName Specify the name of a DWork vector.
ssSetDWorkRTWIdentifier Specify the identifier used to declare
a DWork vector in the generated
code.
ssSetDWorkRTWIdentifierMustResolveToSignalObjec Specify if a DWork vector must
t resolve to a Simulink.Signal
object.
ssSetDWorkRTWStorageClass Specify the storage class for a
DWork vector.
ssSetDWorkRTWTypeQualifier Specify the C type qualifier used to
declare a DWork vector in the
generated code.
ssSetDWorkUsageType Specify how a DWork vector is used
in the S-function.
ssSetDWorkUsedAsDState Specify that a DWork vector stores
discrete state values.
ssSetDWorkWidth Specify the width of a DWork vector.
You can also use DWork vectors to store the state of legacy code. The template file
sfuntmpl_gate_fortran.c shows how to use DWork vectors to interact with legacy
Fortran code. The Legacy Code Tool uses DWork vectors to maintain the states of legacy
8-11
8 Using Work Vectors
C or C++ code incorporated through the tool. See “Integrate C Functions Using Legacy
Code Tool” on page 4-45 for more information on the Legacy Code Tool.
8-12
DWork Vector Examples
The following portion of the mdlInitializeSizes method initializes the DWork vector
and all code generation properties associated with it.
ssSetNumDWork(S, 1);
ssSetDWorkWidth(S, 0, 1);
ssSetDWorkDataType(S, 0, SS_DOUBLE);
/* Storage class */
sc = ((int_T) *((real_T*) mxGetPr(SC_PARAM(S)))) - 1;
ssSetDWorkRTWStorageClass(S, 0, sc);
8-13
8 Using Work Vectors
* Abstract:
* Initialize both continuous states to zero
*/
static void mdlInitializeConditions(SimStruct *S)
{
real_T *x = (real_T*) ssGetDWork(S,0);
The mdlOutputs method assigns the DWork vector value to the S-function output.
/* Function: mdlOutputs ========================================
* Abstract:
* y = x
*/
static void mdlOutputs(SimStruct *S, int_T tid)
{
real_T *y = ssGetOutputPortRealSignal(S,0);
real_T *x = (real_T*) ssGetDWork(S,0);
/*
* Increment the state by the input
* U is defined as U(element) (*uPtrs[element])
*/
x[0] += U(0);
}
8-14
DWork Vector Examples
ssSetNumDWork(S, 1);
ssSetDWorkWidth(S, 0, 1);
ssSetDWorkDataType(S, 0, SS_DOUBLE);
ssSetDWorkUsageType(S,0, SS_DWORK_USED_AS_SCRATCH);
The remainder of the S-function uses the scratch DWork vector exactly as it would any
other type of DWork vector. The InitializeConditions method sets the initial value
and the mdlOutputs method uses the value stored in the DWork vector.
#define MDL_INITIALIZE_CONDITIONS
/* Function: mdlInitializeConditions ================================ */
static void mdlInitializeConditions(SimStruct *S)
{
real_T *x = (real_T*) ssGetDWork(S,0);
/* Initialize the dwork to 0 */
x[0] = 0.0;
}
/* Function: mdlOutputs ============================================= */
static void mdlOutputs(SimStruct *S, int_T tid)
{
real_T *y = ssGetOutputPortRealSignal(S,0);
real_T *x1 = (real_T*) ssGetDWork(S,1);
x[0] = 2000;
y[0] = x[0] * 2;
}
If you have Simulink Coder, the Simulink Coder software handles scratch DWork
differently from other DWork vectors when generating code for inlined S-function. To
inline the S-function, create the following Target Language Compiler (TLC) file to
describe the mdlOutputs method.
%implements sfun_dscratch "C"
When the Simulink Coder software generates code for the model, it inlines the S-function
and declares the second DWork vector as a local scratch vector. For example, the model
outputs function contains the following lines:
/* local scratch DWork variables */
real_T SFunction_DWORK1;
SFunction_DWORK1 = 2000.0;
If the S-function used a general DWork vector instead of a scratch DWork vector,
generating code with the same TLC file would have resulted in the DWork vector being
included in the data structure, as follows:
8-15
8 Using Work Vectors
sfcndemo_dscratch_DWork.SFunction_DWORK1 = 2000.0;
The mdlInitializeSizes method then configures the DWork vector as a DState vector
using a call to ssSetDWorkUsedAsDState. This is equivalent to calling the
ssSetDWorkUsageType macro with the value SS_DWORK_USED_AS_DSTATE. The
mdlInitializeSizes method sets the width and data type of the DState vector and
gives the state a name using ssSetDWorkName.
Note DWork vectors configured as DState vectors must be assigned a name for the
Simulink engine to register the vector as discrete states. The function
Simulink.BlockDiagram.getInitialStates(mdl) returns the assigned name in the
label field for the initial states.
ssSetNumContStates(S, 0);
ssSetNumDiscStates(S, 0);
ssSetNumSampleTimes(S, 1);
ssSetNumRWork(S, 0);
ssSetNumIWork(S, 0);
ssSetNumPWork(S, 0);
ssSetNumModes(S, 0);
ssSetNumNonsampledZCs(S, 0);
ssSetNumDWork(S, 1);
ssSetDWorkUsedAsDState(S, 0, SS_DWORK_USED_AS_DSTATE);
ssSetDWorkWidth(S, 0, 2);
8-16
DWork Vector Examples
ssSetDWorkDataType(S, 0, SS_DOUBLE);
ssSetDWorkName(S, 0, "SfunStates");
ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE);
}
The mdlInitializeConditions method initializes the DState vector values using the
pointer returned by ssGetDWork.
#define MDL_INITIALIZE_CONDITIONS
/* Function: mdlInitializeConditions ===============================
* Abstract:
* Initialize both discrete states to one.
*/
static void mdlInitializeConditions(SimStruct *S)
{
real_T *x0 = (real_T*) ssGetDWork(S, 0);
int_T lp;
for (lp=0;lp<2;lp++) {
*x0++=1.0;
}
}
The mdlOutputs method then uses the values stored in the DState vector to compute the
output of the discrete state-space equation.
/* Function: mdlOutputs ========================================
* Abstract:
* y = Cx + Du
*/
static void mdlOutputs(SimStruct *S, int_T tid)
{
real_T *y = ssGetOutputPortRealSignal(S,0);
real_T *x = (real_T*) ssGetDWork(S, 0);
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
/* y=Cx+Du */
y[0]=C[0][0]*x[0]+C[0][1]*x[1]+D[0][0]*U(0)+D[0][1]*U(1);
y[1]=C[1][0]*x[0]+C[1][1]*x[1]+D[1][0]*U(0)+D[1][1]*U(1);
}
Finally, the mdlUpdate method updates the DState vector with new values for the
discrete states.
#define MDL_UPDATE
/* Function: mdlUpdate ============================================
* Abstract:
* xdot = Ax + Bu
*/
static void mdlUpdate(SimStruct *S, int_T tid)
{
8-17
8 Using Work Vectors
/* xdot=Ax+Bu */
tempX[0]=A[0][0]*x[0]+A[0][1]*x[1]+B[0][0]*U(0)+B[0][1]*U(1);
tempX[1]=A[1][0]*x[0]+A[1][1]*x[1]+B[1][0]*U(0)+B[1][1]*U(1);
x[0]=tempX[0];
x[1]=tempX[1];
}
The mdlInitializeSizes method sets the number of DWork vectors and zero-crossing
vectors (see “Zero Crossings” on page 9-42) to DYNAMICALLY_SIZED. The
DYNAMICALLY_SIZED setting allows the Simulink engine to defer specifying the work
vector sizes until it knows the dimensions of the input, allowing the S-function to support
an input with an arbitrary width.
static void mdlInitializeSizes(SimStruct *S)
{
ssSetNumSFcnParams(S, 0);
if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
return; /* Parameter mismatch reported by the Simulink engine */
}
ssSetNumContStates( S, 0);
ssSetNumDiscStates( S, 0);
if (!ssSetNumOutputPorts(S,1)) return;
ssSetOutputPortWidth(S, 0, DYNAMICALLY_SIZED);
ssSetNumSampleTimes(S, 1);
ssSetNumRWork(S, 0);
ssSetNumIWork(S, 0);
ssSetNumPWork(S, 0);
ssSetNumDWork(S, 1);
ssSetNumModes(S, 0);
8-18
DWork Vector Examples
ssSetDWorkWidth(S,0,DYNAMICALLY_SIZED);
ssSetNumNonsampledZCs(S, DYNAMICALLY_SIZED);
The Simulink engine initializes the number of zero-crossing vectors and DWork vectors to
the number of elements in the signal coming into the first S-function input port. The
engine then calls the mdlSetWorkWidths method, which uses ssGetNumDWork to
determine how many DWork vectors were initialized and then sets the properties for each
DWork vector.
#define MDL_SET_WORK_WIDTHS
static void mdlSetWorkWidths(SimStruct *S) {
int_T numdw = ssGetNumDWork(S);
int_T i;
The mdlOutputs method uses the value stored in the DWork mode vector to determine if
the output signal should be equal to the input signal or the absolute value of the input
signal.
static void mdlOutputs(SimStruct *S, int_T tid)
{
int_T i;
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
real_T *y = ssGetOutputPortRealSignal(S,0);
int_T width = ssGetOutputPortWidth(S,0);
boolean_T *mode = ssGetDWork(S,0);
if (ssIsMajorTimeStep(S)) {
for (i = 0; i < width; i++) {
mode[i] = (boolean_T)(*uPtrs[i] >= 0.0);
}
}
8-19
8 Using Work Vectors
In this section...
“Description of Elementary Work Vector” on page 8-20
“Relationship to DWork Vectors” on page 8-20
“Using Elementary Work Vectors” on page 8-21
“Additional Work Vector Macros” on page 8-22
“Elementary Work Vector Examples” on page 8-23
Work Vector Comparison to DWork Vector How to create equivalent DWork vector
Type
IWork IWork vectors cannot be ssSetNumDWork(S,1);
customized in the generated ssSetDWorkDataType(S, 0, SS_INT8);
code. Also, you are allowed only
one IWork vector.
8-20
Elementary Work Vectors
Work Vector Comparison to DWork Vector How to create equivalent DWork vector
Type
Mode Mode vectors require more ssSetNumDWork(S,1);
memory than DWork vectors ssSetDWorkUsageType(S, 0,
since the mode vector is always sSS_DWORK_USED_AS_MODE);
stored with an integer data ssSetDWorkDataType(S, 0, SS_INT8);
type. Also, you are allowed only
one Mode vector.
PWork Unlike DWork vectors, PWork ssSetNumDWork(S,1);
vectors cannot be named in the ssSetDWorkDataType(S, 0, SS_POINTER);
generated code. Also, you are
The DWork vector then stores a pointer.
allowed only one PWork vector.
RWork RWork vectors cannot be ssSetNumDWork(S,1);
customized in the generated ssSetDWorkDataType(S, 0, SS_DOUBLE);
code. Also, you are allowed only
one RWork vector.
The following steps show how to set up and use elementary work vectors. See “Additional
Work Vector Macros” on page 8-22 for a list of macros related to each step in the
following process.
ssSetNumPWork(S, 2);
This macro indicates how many elements the work vector contains, however, the
Simulink engine does not allocate memory, at this time.
An S-function can defer specifying the length of the work vectors until all information
about the S-function inputs is available by passing the value DYNAMICALLY_SIZED to
8-21
8 Using Work Vectors
the ssSetNumXWork macro. If an S-function defers specifying the length of the work
vectors in mdlInitializeSizes, it must provide a mdlSetWorkWidths method to
set up the work vectors.
The Simulink engine calls the mdlStart method once at the beginning of the
simulation. Before calling this method, the engine allocates memory for the work
vectors. Do not use the mdlStart method for data that needs to be reinitialized over
the course of the simulation, for example, data that needs to be reinitialized when an
enabled subsystem containing the S-function is enabled.
3 In mdlInitializeConditions, initialize the values of any work vectors that might
need to be reinitialized at certain points in the simulation. The engine executes
mdlInitializeConditions at the beginning of the simulation and any time an
enabled subsystem containing the S-function is reenabled.
4 In mdlOutputs, mdlUpdate, etc., use the ssGetXWork macro to retrieve a pointer
to the work vector and use the pointer to access or update the work vector values.
5 Write an mdlRTW method to allow the Target Language Compiler (TLC) to access the
work vector. This step is not necessary if the S-function uses DWork vectors. For
information on writing parameter data in an mdlRTW method, see
ssWriteRTWParamSettings. For more information on generating code using an
mdlRTW method, see “Write Fully Inlined S-Functions with mdlRTW Routine”
(Simulink Coder).
8-22
Elementary Work Vectors
Macro Description
ssGetNumRWork Query the width of the real work vector.
ssSetNumIWork Specify the width of the integer work vector.
ssGetNumIWork Query the width of the integer work vector.
ssSetNumPWork Specify the width of the pointer work vector.
ssGetNumPWork Query the width of the pointer work vector.
ssSetNumModes Specify the width of the mode work vector.
ssGetNumModes Query the width of the mode work vector.
ssGetIWork Get a pointer to the integer work vector.
ssGetIWorkValue Get an element of the integer work vector.
ssGetModeVector Get a pointer to the mode work vector.
ssGetModeVectorValue Get an element of the mode work vector.
ssGetPWork Get a pointer to the pointer work vector.
ssGetPworkValue Get one element from the pointer work vector.
ssGetRWork Get a pointer to the floating-point work vector.
ssGetRWorkValue Get an element of the floating-point work vector.
ssSetIWorkValue Set the value of one element of the integer work vector.
ssSetModeVectorValue Set the value of one element of the mode work vector.
ssSetPWorkValue Set the value of one element of the pointer work vector.
ssSetRWorkValue Set the value of one element of the floating-point work
vector.
This example opens a file and stores the FILE pointer in the pointer work vector.
8-23
8 Using Work Vectors
The following code uses the pointer work vector to store a FILE pointer, returned from
the standard I/O function fopen.
#define MDL_START /* Change to #undef to remove function. */
#if defined(MDL_START)
static void mdlStart(real_T *x0, SimStruct *S)
{
FILE *fPtr;
void **PWork = ssGetPWork(S);
fPtr = fopen("file.data", "r");
PWork[0] = fPtr;
}
#endif /* MDL_START */
The following code retrieves the FILE pointer from the pointer work vector and passes it
to fclose in order to close the file.
static void mdlTerminate(SimStruct *S)
{
if (ssGetPWork(S) != NULL) {
FILE *fPtr;
fPtr = (FILE *) ssGetPWorkValue(S,0);
if (fPtr != NULL) {
fclose(fPtr);
}
ssSetPWorkValue(S,0,NULL);
}
}
Note Although the Simulink engine handles deallocating the PWork vector, the
mdlTerminate method must always free the memory stored in the PWork vector.
The S-function stvctf.c uses RWork and IWork vectors to model a time-varying
continuous transfer function. For a description of this S-function, see the example
“Discontinuities in Continuous States” on page 9-107.
Mode Vector
The following example implements a switch block using a mode work vector. The
mdlInitializeSizes method configures two input ports with direct feedthrough and
one output port. The mode vector element indicates if the signal from the first or second
input port is propagated to the output. The S-function uses one S-function parameter and
a corresponding run-time parameter to store the mode value and allow the switch to be
toggled during simulation.
8-24
Elementary Work Vectors
{
int iParam = 0;
int nParam = ssGetNumSFcnParams(S);
ssSetOptions(S,
SS_OPTION_WORKS_WITH_CODE_REUSE |
SS_OPTION_USE_TLC_WITH_ACCELERATOR |
SS_OPTION_DISALLOW_CONSTANT_SAMPLE_TIME |
SS_OPTION_NONVOLATILE);
}
The mdlInitializeConditions method initializes the mode vector value using the
current value of the S-function dialog parameter.
#define MDL_INITIALIZE_CONDITIONS
/* Function: mdlInitializeConditions =============================
* Abstract:
* Initialize the mode vector value.
*/
static void mdlInitializeConditions(SimStruct *S)
{
int_T *mv = ssGetModeVector(S);
real_T param = mxGetScalar(ssGetSFcnParam(S,0));
8-25
8 Using Work Vectors
mv[0] = (int_T)param;
}
The mdlOutputs method updates the mode vector value with the new run-time
parameter value at every major time step. It then uses the mode vector value to
determine which input signal to pass through to the output.
static void mdlOutputs(SimStruct *S, int_T tid)
{
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
InputRealPtrsType u2Ptrs = ssGetInputPortRealSignalPtrs(S,1);
real_T *y = ssGetOutputPortSignal(S,0);
int_T *mode = ssGetModeVector(S);
real_T param = mxGetScalar(ssGetSFcnParam(S,0));
if (ssIsMajorTimeStep(S)) {
mode[0] = (int_T)param;
}
if (!mode[0]) {
/* first input */
y[0] = (*uPtrs[0]);
}
if (mode[0]) {
/* second input */
y[0] = (*u2Ptrs[0]);
}
}
8-26
Memory Allocation
Memory Allocation
When you create an S-function, you might need to allocate memory for each instance of
your S-function. The standard MATLAB API memory allocation routines mxCalloc and
mxFree should not be used with C MEX S-functions, because these routines are designed
to be used with MEX files that are called from the MATLAB environment and not the
Simulink environment. The correct approach for allocating memory is to use the
stdlib.h library routines calloc and free. In mdlStart, allocate and initialize the
memory
where UD, in this example, is a data structure defined at the beginning of the S-function.
Then, place the pointer to it either in the pointer work vector
ssSetPWorkValue(S, 0, ptr);
ssSetUserData(S,ptr);
In mdlTerminate, free the allocated memory. For example, if the pointer was stored in
the user data
UD *ptr = ssGetUserData(S);
free(ptr);
8-27
9
Note You cannot use the Model Explorer, the S-function Block Parameters dialog box, or
a mask to tune the parameters of a source S-function, i.e., an S-function that has outputs
but no inputs, while a simulation is running. For more information, see “Tune and
Experiment with Block Parameter Values”.
The Simulink engine stores the values of the dialog box parameters in the S-function
SimStruct structure. Use the S-function callback methods and SimStruct macros to
access and check the parameters and use them to compute the S-function output. To use
dialog parameters in your C S-function, perform the following steps when you create the
S-function:
1 Determine the order in which the parameters are to be specified in the block's dialog
box.
2 In the mdlInitializeSizes function, use the ssSetNumSFcnParams macro to tell
the Simulink engine how many parameters the S-function accepts. Specify S as the
first argument and the number of dialog box parameters as the second argument. If
your S-function implements the mdlCheckParameters method, the
mdlInitializeSizes routine should call mdlCheckParameters to check the
validity of the initial values of the parameters. For example, the
mdlInitializeSizes function in sfun_runtime1.c begins with the following
code.
9-2
Pass Dialog Parameters to S-Functions
3 Access the dialog box parameters in the S-function using the ssGetSFcnParam
macro.
Specify S as the first argument and the relative position of the parameter in the list
entered on the dialog box (0 is the first position) as the second argument. The
ssGetSFcnParam macro returns a pointer to the mxArray containing the parameter.
You can use ssGetDTypeIdFromMxArray to get the data type of the parameter.
Alternatively, you can use ssGetSFcnParamDataType to get the data type of the
parameter by specifying the index of the parameter.
#define GAIN_IDX 1
#define GAIN_PARAM(S) ssGetSFcnParam(S,GAIN_IDX) /* Second parameter */
#define OUT_IDX 2
#define OUT_PARAM(S) ssGetSFcnParam(S,OUT_IDX) /* Third parameter */
When running a simulation, you must specify the parameters in the S-Function
parameters field of the S-Function Block Parameters dialog box in the same order that
you defined them in step 1. You can enter any valid MATLAB expression as the value of a
parameter, including literal values, names of workspace variables, function invocations, or
arithmetic expressions. The Simulink engine evaluates the expression and passes its value
to the S-function.
As another example, the following code is part of a device driver S-function. Four input
parameters are used: BASE_ADDRESS_PRM, GAIN_RANGE_PRM, PROG_GAIN_PRM, and
NUM_OF_CHANNELS_PRM. The code uses #define statements at the top of the S-function
to associate particular input arguments with the parameter names.
9-3
9 Implementing Block Features for C/C++ S-Functions
/* Input Parameters */
#define BASE_ADDRESS_PRM(S) ssGetSFcnParam(S, 0)
#define GAIN_RANGE_PRM(S) ssGetSFcnParam(S, 1)
#define PROG_GAIN_PRM(S) ssGetSFcnParam(S, 2)
#define NUM_OF_CHANNELS_PRM(S) ssGetSFcnParam(S, 3)
When running the simulation, enter four variable names or values in the S-function
parameters field of the S-Function Block Parameters dialog box. The first corresponds to
the first expected parameter, BASE_ADDRESS_PRM(S). The second corresponds to the
next expected parameter, and so on.
ssSetNumSFcnParams(S, 4);
Tunable Parameters
Dialog parameters can be either tunable or nontunable. A tunable parameter is a
parameter that a user can change while the simulation is running.
9-4
Pass Dialog Parameters to S-Functions
#if defined(MATLAB_MEX_FILE)
if (ssGetNumSFcnParams(S) == ssGetSFcnParamsCount(S)) {
mdlCheckParameters(S);
if (ssGetErrorStatus(S) != NULL) {
return;
}
} else {
return; /* Parameter mismatch reported by the Simulink engine*/
}
#endif
ssSetSFcnParamTunable(S,GAIN_IDX,true); /* Tunable */
ssSetSFcnParamTunable(S,SIGNS_IDX,false); /* Not tunable */
ssSetSFcnParamTunable(S,OUT_IDX,false); /* Not tunable */
When you tune parameters during simulation, the Simulink engine invokes the S-function
mdlCheckParameters method to validate the changes and then the S-functions'
mdlProcessParameters method to give the S-function a chance to process the
parameters in some way. The engine also invokes these methods when running in external
mode, but it passes the unprocessed changes to the S-function target. Thus, if it is
essential that your S-function process parameter changes, you need to create a Target
Language Compiler (TLC) file that inlines the S-function, including its parameter
processing code, during the code generation process. For information on inlining S-
functions, see “Inlining S-Functions” in the Simulink Coder Target Language Compiler
documentation.
9-5
9 Implementing Block Features for C/C++ S-Functions
See Also
ssGetSFcnParamDataType
More About
• “Create and Update S-Function Run-Time Parameters” on page 10-4
• “SimStruct Macros and Functions Listed by Usage” on page 12-3
9-6
Create and Update S-Function Run-Time Parameters
• Computed parameters
Often the output of a block is a function of the values of several dialog parameters. For
example, suppose a block has two parameters, the volume and density of some object,
and the output of the block is a function of the input signal and the mass of the object.
In this case, the mass can be viewed as a third internal parameter computed from the
two external parameters, volume and density. An S-function can create a run-time
parameter corresponding to the computed weight, thereby eliminating the need to
provide special case handling for weight in the output computation. See “Creating
Run-Time Parameters from Multiple S-Function Parameters” on page 9-10 for more
information.
• Data type conversions
Often a block needs to change the data type of a dialog parameter to facilitate internal
processing. For example, suppose that the output of the block is a function of the input
9-7
9 Implementing Block Features for C/C++ S-Functions
and a dialog parameter and the input and dialog parameter are of different data types.
In this case, the S-function can create a run-time parameter that has the same value
as the dialog parameter but has the data type of the input signal, and use the run-time
parameter in the computation of the output.
• Code generation
During code generation, the Simulink Coder product writes all run-time parameters
automatically to the model.rtw file, eliminating the need for the S-function to
perform this task via an mdlRTW method.
The sfcndemo_runtime Simulink model contains four example S-functions that create
run-time parameters.
9-8
Create and Update S-Function Run-Time Parameters
The next example uses ssSetRunTimeParamInfo and is taken from the S-function
sfun_runtime2.c.
static void mdlSetWorkWidths(SimStruct *S)
{
ssParamRec p; /* Initialize an ssParamRec structure */
int dlgP = GAIN_IDX; /* Index of S-function parameter */
9-9
9 Implementing Block Features for C/C++ S-Functions
#define GAIN_IDX 1
#define GAIN_PARAM(S) ssGetSFcnParam(S,GAIN_IDX)
#define VOL_IDX 0
#define VOL_PARAM(S) ssGetSFcnParam(S,VOL_IDX)
#define DEN_IDX 1
#define DEN_PARAM(S) ssGetSFcnParam(S,DEN_IDX)
9-10
Create and Update S-Function Run-Time Parameters
The mdlOutputs method uses the stored mass to calculate the force.
/* Function: mdlOutputs ==========================================
* Abstract:
9-11
9 Implementing Block Features for C/C++ S-Functions
*
* Output acceleration calculated as input force divided by mass.
*/
static void mdlOutputs(SimStruct *S, int_T tid)
{
real_T *y1 = ssGetOutputPortRealSignal(S,0);
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
RunTimeDataType *mass =
(RunTimeDataType *)((ssGetRunTimeParamInfo(S,0))->data);
/*
* Output acceleration = force / mass
*/
y1[0] = (*uPtrs[0]) / *mass;
}
Lastly, the mdlTerminate method frees the memory allocated for the run-time parameter
in mdlSetWorkWidths.
/* Function: mdlTerminate ==========================================
* Abstract:
* Free the user data.
*/
static void mdlTerminate(SimStruct *S)
{
/* Free memory used to store the run-time parameter data*/
RunTimeDataType *mass = ssGetUserData(S);
if (mass != NULL) {
free(mass);
}
}
In a C S-function, update the run-time parameters using the method appropriate for how
the run-time parameters were created, as described in the following sections.
9-12
Create and Update S-Function Run-Time Parameters
If there is not a one-to-one correspondence between the S-function dialog and run-time
parameters or the run-time parameters are transformed versions of the dialog
parameters, the mdlProcessParameters method must update each parameter
individually. Choose the method used to update the run-time parameter based on how it
was registered.
9-13
9 Implementing Block Features for C/C++ S-Functions
Note that you cannot tune a run-time parameter whose value is a cell array or structure.
K =
1+2i 3+4i
5+6i 7+8i
[1, 2, 5, 6, 3, 4, 7, 8]
9-14
See Also
Note Matrix elements are written out in column-major format. Real and imaginary values
are interleaved.
See Also
ssGetSFcnParamDataType
More About
• “Input and Output Ports” on page 9-16
• “SimStruct Macros and Functions Listed by Usage” on page 12-3
9-15
9 Implementing Block Features for C/C++ S-Functions
• The dimensions of the input port (see “Initializing Input Port Dimensions” on page 9-
17)
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” on page 9-17).
• Whether the input port allows scalar expansion of inputs (see “Scalar Expansion of
Inputs” on page 9-21)
• 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.
9-16
Input and Output Ports
• The numeric type of the input port, if the port accepts complex-valued signals
You can configure additional input port properties using other S-function macros. See
“Input and Output Ports” on page 12-7 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.
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).
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.
9-17
9 Implementing Block Features for C/C++ S-Functions
• Specify some or all of the dimensions of the input port as dynamically sized in
mdlInitializeSizes.
If the input port can accept only vector (1-D) signals but the signals can be of any size,
use
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.
9-18
Input and Output Ports
#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.
9-19
9 Implementing Block Features for C/C++ S-Functions
You can set output port dimensions using one of the following macros:
• ssSetOutputPortDimensionInfo
• ssSetOutputPortMatrixDimensions
• ssSetOutputPortVectorDimension
• ssSetOutputPortWidth
If you want the port's dimensions to depend on block connectivity, set the dimensions
to DYNAMIC_DIMENSIONS when using ssSetOutputPortDimensionInfo or to
DYNAMICALLY_SIZED for all other macros. The S-function must then provide
mdlSetOutputPortDimensionInfo and mdlSetDefaultPortDimensionInfo
methods to ensure that output port dimensions are set to the correct values in code
generation.
• Data type of the output port
Use ssSetOutputPortDataType to set the output port's data type. If you want the
data type of the port to depend on block connectivity, specify the data type as
DYNAMICALLY_TYPED. In this case, you must provide implementations of the
mdlSetOutputPortDataType and mdlSetDefaultPortDataTypes methods to
enable the data type to be set correctly during signal propagation.
• The numeric type of the output port, if the port outputs complex-valued signals
See “Creating Input Ports for C S-Functions” on page 9-16 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.
9-20
Input and Output Ports
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. */
9-21
9 Implementing Block Features for C/C++ S-Functions
int_T port;
real_T sum = 0.0;
for (port = 0; port < nInputPorts; port++) {
/* Get the input signal value */
InputRealPtrsType uPtrs =
ssGetInputPortRealSignalPtrs(S,port);
} else {
/* Use the scalar value to expand the signal */
sum = sum + ((real_T)signs[port] * (*uPtrs[0]));
}
}
}
9-22
Configure Custom Data Types
In this section...
“Custom Data Types in C S-Functions” on page 9-23
“Using Simulink Recognizable Data Types in C S-Functions” on page 9-23
“Using Opaque Data Types in C S-Functions” on page 9-24
• Simulink recognizable custom data types — These are custom data types from a
Simulink.AliasType, Simulink.Bus, Simulink.NumericType, or an
Enumerated data type that can also interact with other Simulink blocks.
• Opaque data types — These are data types for use only with S-Function blocks
programmed to understand them. You might define opaque data types in cases in
which other Simulink blocks do not need to use the data types.
int id1;
ssRegisterTypeFromNamedObject(S, "u8", &id1);
ssSetOutputPortDataType(S, 0, id1);
In addition, you can use the identifier id1 to assign this data type to S-function
parameters, DWork vectors, and input ports.
9-23
9 Implementing Block Features for C/C++ S-Functions
Define the user-defined data type in an external header file to include in the level 2 C S-
Function.
/* Define the structure of the user-defined data type */
typedef struct{
int8_T a;
uint16_T b;
}myStruct;
Place the following code at the beginning of mdlInitializeSizes to set the size and
zero representation of the custom data type myStruct.
/* Define variables */
int_T status;
DTypeId id;
myStruct tmp;
Note If you have Simulink Coder, you cannot use the software to generate code for S-
functions that contain macros to define custom data types. You must use an inline S-
9-24
See Also
function that accesses Target Language Compiler functions to generate code with custom
data types. For more information, see “Inlining S-Functions” (Simulink Coder).
See Also
ssGetNumInputPorts | ssGetNumOutputPorts | ssSetNumInputPorts |
ssSetNumOutputPorts
More About
• “SimStruct Macros and Functions Listed by Usage” on page 12-3
9-25
9 Implementing Block Features for C/C++ S-Functions
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:
• In the block-based method, selecting 0.5 and 0.25 directs the block to execute inputs
and outputs at 0.25 second increments.
9-26
Specify S-Function Sample Times
• In the port-based method, setting the input port to 0.5 and the output port to 0.25
causes the block to process inputs at 2 Hz and outputs at 4 Hz.
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.
• mdlInitializeSizes
• mdlInitializeSampleTimes
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.
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.
9-27
9 Implementing Block Features for C/C++ S-Functions
and offset prior to setting them, for example, by computing the best sample time for
the block based on the S-function dialog parameters obtained using
ssGetSFcnParam.
• Function calls — In mdlInitializeSampleTimes, use ssSetCallSystemOutput to
specify the output elements that are performing function calls. Seesfun_fcncall.c
for an example and “Implement Function-Call Subsystems with S-Functions” on page
9-53 for an explanation of this S-function.
You specify the sample times as pairs [sample_time, offset_time], using these
macros
The valid sample time pairs are (uppercase values are macros defined in simstruc.h):
[CONTINUOUS_SAMPLE_TIME, 0.0 ]
[CONTINUOUS_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET]
[discrete_sample_period, 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” on page 9-39 for more
information.
• A continuous function that changes during minor integration steps should register the
[CONTINUOUS_SAMPLE_TIME, 0.0] sample time.
9-28
Specify S-Function Sample Times
• A continuous function that does not change during minor integration steps should
register the [CONTINUOUS_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET]
sample time.
• A discrete function that changes at a specified rate should register the discrete sample
time pair
[discrete_sample_period, offset]
where
and
If your function has no intrinsic sample time, you must indicate that it is inherited
according to the following guidelines:
• A function that changes as its input changes, even during minor integration steps,
should register the [INHERITED_SAMPLE_TIME, 0.0] sample time.
• A function that changes as its input changes, but doesn't change during minor
integration steps (meaning, is held during minor steps), should register the
[INHERITED_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET] sample time.
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:
if (ssIsContinuousTask(S,tid)) {
}
To determine whether the third (discrete) task has a hit, use the following code fragment:
if (ssIsSampleHit(S,2,tid) {
}
9-29
9 Implementing Block Features for C/C++ S-Functions
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. */
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-function mdlInitializeSizes method:
ssSetNumSampleTimes(S, PORT_BASED_SAMPLE_TIMES)
You must also specify the sample time of each input and output port in the S-function
mdlInitializeSizes method, using the following macros
ssSetInputPortSampleTime(S, idx, period)
ssSetInputPortOffsetTime(S, idx, offset)
ssSetOutputPortSampleTime(S, idx, period)
ssSetOutputPortOffsetTime(S, idx, offset)
The call to ssSetNumSampleTimes can be placed before or after the port-based sample
times are actually specified in mdlInitializeSizes. However, if
ssSetNumSampleTimes does not configure the S-function to use port-based sample
times, any sample times set on the ports will be ignored.
9-30
Specify S-Function Sample Times
For example, the following code sets the sample time of the S-function first input port
to 0.1 and the offset time to 0.
ssSetInputPortSampleTime(S, 0, 0.1);
ssSetInputPortOffsetTime(S, 0, 0);
• Inherited sample time (-1), i.e., the port inherits its sample time from the port to
which it is connected (see “Specifying Inherited Sample Time for a Port” on page 9-
31)
• Constant sample time (Inf), i.e., the signal coming from the port is constant (see
“Specifying Constant Sample Time (Inf) for a Port” on page 9-32)
Note To be usable in a triggered subsystem, all your S-function ports must have
either inherited (–1) or constant sample time (Inf). For more information, see
“Configuring Port-Based Sample Times for Use in Triggered Subsystems” on page 9-
34.
When you specify port-based sample times, the Simulink engine calls
mdlSetInputPortSampleTime and mdlSetOutputPortSampleTime to determine the
rates of inherited signals.
Once all rates have been determined, the engine calls mdlInitializeSampleTimes.
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 and ssGetOutputPortSampleTime in
mdlInitializeSampleTimes to obtain the values of the inherited sample times. For
9-31
9 Implementing Block Features for C/C++ S-Functions
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” on page 9-39 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:
• The output port has a constant value. It uses or inherits a sample time of Inf.
• The S-function is a multirate S-function or uses port-based sample times.
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” on page 9-32.
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.
If your S-function uses port-based sample times, it can set a sample time of Inf on any of
its ports. A port-based sample time of Inf means that the signal entering or leaving the
port stays constant.
Note This option causes the S-function’s ports to support a sample time of Inf,
including ports that inherit their sample times from other blocks. If any S-function
9-32
Specify S-Function Sample Times
ports that inherit sample time cannot have a sample time of Inf, an error occurs. Set
sample times for these ports using the mdlSetInputPortSampleTime and
mdlSetOutputPortSampleTime methods.
• Set the port's sample time to Inf and its offset to 0, e.g.,
ssSetInputPortSampleTime(S,0,mxGetInf());
ssSetInputPortOffsetTime(S,0,0);
• Check in mdlOutputs whether the method's tid argument equals CONSTANT_TID
and if so, set the value of the port's output if it is an output port.
To see an example of how to create ports which output a constant value, see
sfun_port_constant.c, the source file for the sfcndemo_port_constant 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:
• The output port has a constant value. It uses or inherits a sample time of Inf.
• The S-function is a multirate S-function or uses port-based sample times.
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 function
OutputsForTID 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. 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 function Outputs 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 function OutputsForTID, and sets the argument
tid 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.
9-33
9 Implementing Block Features for C/C++ S-Functions
ssSetOptions(S,
SS_OPTION_ALLOW_PORT_SAMPLE_TIME_IN_TRIGSS);
• Set all of its ports to have either inherited (-1) or constant sample time (Inf) in its
mdlInitializeSizes method.
• Handle inheritance of a triggered sample time in mdlSetInputPortSampleTime and
mdlSetOutputPortSampleTime methods as follows.
Since the S-function ports inherit their sample times, the Simulink engine invokes
either mdlSetInputPortSampleTime or mdlSetOutputPortSampleTime during
sample time propagation. The macro ssSampleAndOffsetAreTriggered can be
used in these methods to determine if the S-function resides in a triggered subsystem.
If the S-function does reside in a triggered subsystem, whichever method is called
must set the sample time and offset of the port for which it is called to
INHERITED_SAMPLE_TIME (-1).
9-34
Specify S-Function Sample Times
if (ssSampleAndOffsetAreTriggered(sampleTime,offsetTime)) {
ssSetOutputPortSampleTime(S, 0, INHERITED_SAMPLE_TIME);
ssSetOutputPortOffsetTime(S, 0, INHERITED_SAMPLE_TIME);
Finally, as in the port-based method, you specify the rates for each port, using
ssSetInputPortSampleTime(S, idx, period)
ssSetInputPortOffsetTime(S, idx, offset)
9-35
9 Implementing Block Features for C/C++ S-Functions
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.
where S is the SimStruct, st_index identifies a specific sample time index, and tid 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:
9-36
Specify S-Function Sample Times
if (ssIsContinuousTask(S,tid)) {
}
ssSetNumSampleTimes(S, 1);
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);
9-37
9 Implementing Block Features for C/C++ S-Functions
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).
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. */
...
}
9-38
Specify S-Function Sample Times
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.
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:
• ssGetSampleTime
• ssGetInputPortSampleTime
• ssGetOutputPortSampleTime
• ssGetInputPortOffsetTime
• ssGetOutputPortOffsetTime
• ssGetSampleTimePtr
9-39
9 Implementing Block Features for C/C++ S-Functions
• ssGetInputPortSampleTimeIndex
• ssGetOutputPortSampleTimeIndex
• ssGetSampleTimeTaskID
• ssGetSampleTimeTaskIDPtr
or TLC functions:
• LibBlockSampleTime
• CompiledModel.SampleTime
• LibBlockInputSignalSampleTime
• LibBlockInputSignalOffsetTime
• LibBlockOutputSignalSampleTime
• LibBlockOutputSignalOffsetTime
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.
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
ssGetSampleTime | ssSetInputPortSampleTime | ssSetSampleTime
9-40
See Also
More About
• “SimStruct Macros and Functions Listed by Usage” on page 12-3
9-41
9 Implementing Block Features for C/C++ S-Functions
Zero Crossings
S-functions model zero crossings using the mode work vector (or a DWork vector
configured as a mode vector) and the continuous zero-crossing vector. Whether the S-
function uses mode or DWork vectors, the concept and implementation are the same. For
an example using DWork vectors to model zero crossings, see “DWork Mode Vector” on
page 8-18 in the “Using Work Vectors” section. The remainder of this section uses mode
vectors to model zero crossings.
Elements of the mode vector are integer values. You specify the number of mode vector
elements in mdlInitializeSizes, using ssSetNumModes(S,num). You can then
access the mode vector using ssGetModeVector. The mode vector values determine how
the mdlOutputs routine operates when the solvers are homing in on zero crossings. The
Simulink solvers track the zero crossings or state events (i.e., discontinuities in the first
derivatives) of some signal, usually a function of an input to your S-function, by looking at
the continuous zero crossings. Register the number of continuous zero crossings in
mdlInitializeSizes, using ssSetNumNonsampledZCs(S, num), then include an
mdlZeroCrossings routine to calculate the continuous zero crossings. The S-function
sfun_zc_sat.c contains a zero-crossing example. The remainder of this section
describes the portions of this S-function that pertain to zero-crossing detection. For a full
description of this example, see “Zero-Crossing Detection” on page 9-94.
First, mdlInitializeSizes specifies the sizes for the mode and continuous zero-
crossing vectors using the following lines of code.
ssSetNumModes(S, DYNAMICALLY_SIZED);
ssSetNumNonsampledZCs(S, DYNAMICALLY_SIZED);
Since the number of modes and continuous zero crossings is dynamically sized,
mdlSetWorkWidths must initialize the actual size of these vectors. In this example,
shown below, there is one mode vector for each output element and two continuous zero
crossings for each mode. In general, the number of continuous zero crossings needed for
each mode depends on the number of events that need to be detected. In this case, each
output (mode) needs to detect when it hits the upper or the lower bound, hence two
continuous zero crossings per mode.
static void mdlSetWorkWidths(SimStruct *S)
{
int nModes;
int nNonsampledZCs;
nModes = numOutput;
9-42
Zero Crossings
nNonsampledZCs = 2 * numOutput;
ssSetNumModes(S,nModes);
ssSetNumNonsampledZCs(S,nNonsampledZCs);
}
Next, mdlOutputs determines which mode the simulation is running in at the beginning
of each major time step. The method stores this information in the mode vector so it is
available when calculating outputs at both major and minor time steps.
/* Get the mode vector */
int_T *mode = ssGetModeVector(S);
} else {
/* Output is not limited. */
mode[iOutput] = NonLimitEquation;
}
} /* end IsMajorTimeStep */
Output calculations in mdlOutputs are done based on the values stored in the mode
vector.
9-43
9 Implementing Block Features for C/C++ S-Functions
} else {
/* Output is equal to input */
*y++ = *uPtrs[uIdx];
}
After outputs are calculated, the Simulink engine calls mdlZeroCrossings to determine
if a zero crossing has occurred. A zero crossing is detected if any element of the
continuous zero-crossing vector switches from negative to positive, or positive to
negative. If this occurs, the simulation modifies the step size and recalculates the outputs
to try to locate the exact zero crossing. For this example, the values for the continuous
zero-crossing vectors are calculated as shown below.
static void mdlZeroCrossings(SimStruct *S)
{
int_T iOutput;
int_T numOutput = ssGetOutputPortWidth(S,0);
real_T *zcSignals = ssGetNonsampledZCs(S);
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
/* Set index and increment for the input signal, upper limit, and lower
* limit parameters so that each gives scalar expansion if needed. */
int_T uIdx = 0;
int_T uInc = ( ssGetInputPortWidth(S,0) > 1 );
const real_T *upperLimit = mxGetPr( P_PAR_UPPER_LIMIT );
int_T upperLimitInc = ( mxGetNumberOfElements( P_PAR_UPPER_LIMIT ) > 1 );
const real_T *lowerLimit = mxGetPr( P_PAR_LOWER_LIMIT );
int_T lowerLimitInc = ( mxGetNumberOfElements( P_PAR_LOWER_LIMIT ) > 1 );
See Also
ssGetNumNonsampledZCs
9-44
See Also
More About
• “SimStruct Macros and Functions Listed by Usage” on page 12-3
9-45
9 Implementing Block Features for C/C++ S-Functions
In most cases, specifying the compliance to be default is sufficient to save and restore the
necessary state data. To specify the default compliance, add this line:
ssSetOperatingPointCompliance(S, USE_DEFAULT_OPERATING_POINT).
Setting Result
OPERATING_POINT_COMPLIANCE_ This is the default setting for all S-functions. For S-functions
UNKNOWN that do not use PWorks, Simulink saves and restores the
default simulation operating point (see
USE_DEFAULT_OPERATING_POINT) and issues a warning to
inform the user of this assumption. On the other hand,
Simulink reports an error during the save and restore if it
encounters an S-function that uses PWorks.
USE_DEFAULT_OPERATING_POINT This setting instructs Simulink to treat the S-function like a
built-in block when saving and restoring the
ModelOperatingPoint object. This setting saves continuous
states, non-scratch Dworks, and zero crossing signal
information
9-46
See Also
Setting Result
USE_EMPTY_OPERATING_POINT This setting informs Simulink that the S-function does not
have any simulation state. With this setting, no state
information is saved for this block. This setting is primarily
useful for "sink" blocks (i.e., blocks with no output ports) that
use PWorks or DWorks to store handles to files or figure
windows.
For S-functions that use PWork vectors or static variables to hold data that Simulink
updates during simulation, the S-function must use the custom mdlGetOpeartingPoint
and mdlSetOperatingPoint methods. The following statements demonstrate the
proper format.
mxArray* mdlGetOperatingPoint(SimStruct* S)
void mdlSetOperatingPoint(SimStruct* S, const mxArray* inSS)
For an example of how to implement these methods, see “Custom Code and Hand Coded
Blocks using the S-function API”.
See Also
GetOperatingPoint | SetOperatingPoint | mdlGetOpeartingPoint |
mdlSetOperatingPoint | ssSetOperatingPointCompliance |
ssSetOperatingPointVisibility
9-47
9 Implementing Block Features for C/C++ S-Functions
More About
• “SimStruct Macros and Functions Listed by Usage” on page 12-3
• “Save and Restore Simulation Operating Point”
• “Operating Point Behavior”
9-48
MATLAB Data in C S-Functions
mxArray Manipulation
You can manipulate mxArrays in S-functions using the standard MATLAB API functions.
In general, if your S-function is declared exception free by passing the
SS_OPTION_EXCEPTION_FREE_CODE option to ssSetOptions (see Exception Free Code
on page 9-61 in “Handle Errors in S-Functions” on page 9-60), it should avoid MATLAB
API functions that throw exceptions (i.e., long jump), such as mxCreateDoubleMatrix.
Otherwise, the S-function can use any of the listed functions.
Note S-function parameters are read-only within the S-function algorithm. You can
modify parameter values via the S-function block dialog or mask.
If you have Simulink Coder, it supports a subset of the mxArray manipulation functions
when generating noninlined code for an S-function. For a list of supported functions, see
“Write Noninlined S-Function” (Simulink Coder).
Calls to the macro ssGetSFcnParam return a pointer to an mxArray, which can be used
with the mxArray manipulation functions. If your S-function contains S-function
parameters, use the mxArray manipulation functions in the mdlCheckParameters
method to check the S-function parameter values. See the S-function sfun_runtime3.c
for an example
In this S-function, the following lines check that the first S-function parameter is a
character array with a length greater than or equal to two.
if (!mxIsChar(ssGetSFcnParam(S, 0)) ||
(nu=mxGetNumberOfElements(ssGetSFcnParam(S, 0))) < 2) {
9-49
9 Implementing Block Features for C/C++ S-Functions
To check the use of 32-bit APIs, you can run the S-function upgrade advisor from
Analysis > Model Advisor > Upgrade Advisor.
If you build your code with -largeArrayDims and your code populates the ssParamRec
structure's dimension field with mxArray dimensions, starting R2018a, you can no longer
cast the return value of mxGetDimensions to an int_T pointer because
mxGetDimensions now returns a size_T pointer on 64-bit platforms. As a workaround,
create a temporary copy of type int_T and assign it to the dims field of ssParamRec
structure.
Replace: With:
ssParamRec p; ssParamRec p;
p.dims = (int_T *) mxGetDimensions(ssGetSFcnParam(S,
const mxArray* 0));
mxPrm = ssGetSFcnParam(S, 0);
// Set up other fields of p const mwSize* mxDims = mxGetDimensions(mxPrm);
if (!ssSetRunTimeParamInfo(S, 0, &p)) {const mwSize mxNumDims = mxGetNumberOfDimensions
free(dims); mwSize idx;
return; int_T * dims = malloc(sizeof(int)*mxNumDims);
} for (idx=0; idx < mxNumDims; idx++)
free(dims); // free memory allocated for
{ dimensions
dims[idx] = mxDims[idx];
}
p.dims = dims;
// Set up other fields of p
if (!ssSetRunTimeParamInfo(S, 0, &p)) {
free(dims);
return;
}
free(dims); // free memory allocated for dimensi
9-50
MATLAB Data in C S-Functions
Note To store complex data for input and output signals or DWorks on page 8-2, Simulink
uses interleaved representation.
To automatically check your S-functions on potential interleaved complex data issues, use
Check model for S-function upgrade issues under Analysis > Model Advisor >
Upgrade Advisor.
The following code sample copies a parameter value from an mxArray to the output of
the S-function. In this example, the dimensions, data type, and the complexity of the
parameter and the output argument are ensured to be the same. For example, if the
parameter is complex, the output signal is complex. If the parameter is real, the output
signal is real. For the example below, the data type of both the parameter and the output
is a double (real_T). Before R2018a, you could use mxGetPr and mxGetPr to copy the
real and imaginary parts of a complex data separately. With interleaved complex
representation, you can use memcpy, which is a single copy instruction.
9-51
9 Implementing Block Features for C/C++ S-Functions
Replace: With:
real_T *y = ssGetOutputPortRealSignal(S,0);
real_T *y = ssGetOutputPortRe
boolean_T yIsComplex = ssGetOutputPortComplexSignal(S,
boolean_T yIsComplex
0) === COMPLEX_YES;
ssGetOutputPortComp
int_T yWidth = ssGetOutputPortWidth(S,0);
int_T yWidth = ssGetOutputPortWi
int i; if (yIsComplex) {
a. sizeof(mxComplexDouble)=2*sizeof(mxDouble)=2*sizeof(real_T)
See Also
S-Function | S-Function Builder
More About
• “MATLAB Support for 64-Bit Indexing” (MATLAB)
• “MATLAB Support for Interleaved Complex API in MEX Functions” (MATLAB)
• “Upgrade MEX Files to Use Interleaved Complex API” (MATLAB)
9-52
Implement Function-Call Subsystems with S-Functions
Note Function-call connections can only be performed on the first output port.
Function-call subsystems are not executed directly by the Simulink engine; rather, the S-
function determines when to execute the subsystem. When the subsystem completes
execution, control returns to the S-function. This figure illustrates the interaction
between a function-call subsystem and an S-function.
Function-call subsystems can only be connected to S-functions that have been properly
configured to accept them.
• In mdlInitializeSizes, set the data type of the S-function first output port to
function-call by specifying
9-53
9 Implementing Block Features for C/C++ S-Functions
ssSetOutputPortDataType(S, 0, SS_FCN_CALL);
• Specify the elements that are to execute the function-call subsystem in
mdlInitializeSampleTimes. For example:
ssSetExplicitFCSSCtrl(S, 1);
See sfun_fcncall.c for an example that executes a function-call subsystem on the first
and second elements of the first S-function output. The following Simulink model
(sfcndemo_sfun_fcncall) uses this S-function.
9-54
Implement Function-Call Subsystems with S-Functions
The first function-call subsystem provides a sine wave output. The second function-call
subsystem is a simple feedback loop containing a Unit Delay block.
9-55
9 Implementing Block Features for C/C++ S-Functions
When the Pulse Generator emits its upper value, the function-call subsystem connected to
the first element of the first S-function output port is triggered. Similarly, when the Pulse
Generator emits its lower value, the function-call subsystem connected to the second
element is triggered. The simulation output is shown on the following Scope.
9-56
Implement Function-Call Subsystems with S-Functions
Function-call subsystems are a powerful modeling construct. You can configure Stateflow
blocks to execute function-call subsystems, thereby extending the capabilities of the
blocks. For more information, see the Stateflow documentation.
9-57
9 Implementing Block Features for C/C++ S-Functions
See Also
ssCallSystemWithTid | ssDisableSystemWithTid | ssEnableSystemWithTid
More About
• “SimStruct Macros and Functions Listed by Usage” on page 12-3
9-58
Use C/C++ S-Functions as Sim Viewing Devices in External Mode
ssSetOptions(S, SS_OPTION_SIM_VIEWING_DEVICE);
When simulating a model in Rapid Accelerator mode with signal logging enabled, no data
is logged for antenna elements or To Workspace blocks that are inside of a sim viewing
device.
External mode compatible S-functions are selected, and the trigger is armed, by using the
External Signal & Triggering dialog box. For more information see “External Mode
Simulation with TCP/IP or Serial Communication” (Simulink Coder).
See Also
mdlInitializeSizes
More About
• “SimStruct Macros and Functions Listed by Usage” on page 12-3
9-59
9 Implementing Block Features for C/C++ S-Functions
If your C MEX S-function has parameters whose contents you need to validate, use the
following technique to report errors.
ssSetErrorStatus(S,"Error encountered due to ...");
return;
In most cases, the Simulink engine displays errors in the Diagnostic Viewer. If the error is
encountered in mdlCheckParameters as the S-function parameters are being entered
into the block dialog, the engine opens the error dialog shown below. In either case, the
engine displays the error message along with the name of the S-function and the
associated S-function block that invoked the error.
9-60
Handle Errors in S-Functions
If you do not call mexErrMsgTxt or other API routines that cause exceptions, use the
SS_OPTION_EXCEPTION_FREE_CODE S-function option. You do this by issuing the
following command in the mdlInitializeSizes function.
ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE);
Setting this option increases the performance of your S-function by allowing the Simulink
engine to bypass the exception-handling setup that is usually performed prior to each S-
function invocation. You must take extreme care to verify that your code is exception free
when using SS_OPTION_EXCEPTION_FREE_CODE. If your S-function generates an
exception when this option is set, unpredictable results occur.
All mex* routines have the potential of long-jumping. Several mx* routines also have the
potential of long-jumping. To avoid any difficulties, use only the API routines that retrieve
a pointer or determine the size of parameters. For example, the following API routines
never throw an exception: mxGetPr, mxGetData, mxGetNumberOfDimensions, mxGetM,
mxGetN, and mxGetNumberOfElements.
9-61
9 Implementing Block Features for C/C++ S-Functions
Code in run-time routines can also throw exceptions. Run-time routines refer to certain S-
function routines that the engine calls during the simulation loop (see “Simulink Engine
Interaction with C S-Functions” on page 4-71). The run-time routines include
• mdlGetTimeOfNextVarHit
• mdlOutputs
• mdlUpdate
• mdlDerivatives
If all run-time routines within your S-function are exception free, you can use this option:
ssSetOptions(S, SS_OPTION_RUNTIME_EXCEPTION_FREE_CODE);
To enable array bounds checking, select warning or error from the Array bounds
exceeded options list on the Configuration Parameters dialog box. Alternatively, enter
the following command at the MATLAB command prompt.
9-62
See Also
where modelName is the name of the Simulink model and ValueStr is either 'none',
'warning', or 'error'.
See Also
mdlInitializeSizes | ssSetErrorStatus
More About
• “SimStruct Macros and Functions Listed by Usage” on page 12-3
9-63
9 Implementing Block Features for C/C++ S-Functions
Continuous States
The csfunc.c example shows how to model a continuous system with states using a C
MEX S-function. The following Simulink model uses this S-function.
sfcndemo_csfunc
In continuous state integration, the Simulink solvers integrate a set of continuous states
using the following equations.
9-64
C MEX S-Function Examples
The csfunc.c example specifies that the input port has direct feedthrough. This is
because matrix D is initialized to a nonzero matrix. If D is set equal to a zero matrix in the
state-space representation, the input signal is not used in mdlOutputs. In this case, the
direct feedthrough can be set to 0, which indicates that csfunc.c does not require the
input signal when executing mdlOutputs.
matlabroot/toolbox/simulink/simdemos/simfeatures/src/csfunc.c
The S-function csfunc.c begins with #define statements for the S-function name and
level, and a #include statement for the simstruc.h header. After these statements, the
S-function can include or define any other necessary headers, data, etc. The csfunc.c
example defines the variable U as a pointer to the first input port's signal and initializes
static variables for the state-space matrices.
/* File : csfunc.c
* Abstract:
*
* Example C S-function for defining a continuous system.
*
* x' = Ax + Bu
* y = Cx + Du
*
* For more details about S-functions, see simulink/src/sfuntmpl_doc.c.
*
* Copyright 1990-2013 The MathWorks, Inc.
*/
#include "simstruc.h"
9-65
9 Implementing Block Features for C/C++ S-Functions
};
9-66
C MEX S-Function Examples
ssSetNumContStates(S, 2);
ssSetNumDiscStates(S, 0);
ssSetNumSampleTimes(S, 1);
ssSetNumRWork(S, 0);
ssSetNumIWork(S, 0);
ssSetNumPWork(S, 0);
ssSetNumModes(S, 0);
ssSetNumNonsampledZCs(S, 0);
9-67
9 Implementing Block Features for C/C++ S-Functions
for (lp=0;lp<2;lp++) {
*x0++=0.0;
}
}
The required mdlOutputs function computes the output signal of this S-function. The
beginning of the function obtains pointers to the first output port, continuous states, and
first input port. The S-function uses the data in these arrays to solve the output equation
y=Cx+Du.
/* Function: mdlOutputs =======================================================
* Abstract:
* y = Cx + Du
*/
static void mdlOutputs(SimStruct *S, int_T tid)
{
real_T *y = ssGetOutputPortRealSignal(S,0);
real_T *x = ssGetContStates(S);
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
/* y=Cx+Du */
y[0]=C[0][0]*x[0]+C[0][1]*x[1]+D[0][0]*U(0)+D[0][1]*U(1);
y[1]=C[1][0]*x[0]+C[1][1]*x[1]+D[1][0]*U(0)+D[1][1]*U(1);
}
The mdlDerivatives function calculates the continuous state derivatives. Because this
function is an optional method, a #define statement must precede the function. The
beginning of the function obtains pointers to the S-function continuous states, state
derivatives, and first input port. The S-function uses this data to solve the equation dx=Ax
+Bu.
#define MDL_DERIVATIVES
/* Function: mdlDerivatives =================================================
* Abstract:
9-68
C MEX S-Function Examples
* xdot = Ax + Bu
*/
static void mdlDerivatives(SimStruct *S)
{
real_T *dx = ssGetdX(S);
real_T *x = ssGetContStates(S);
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
/* xdot=Ax+Bu */
dx[0]=A[0][0]*x[0]+A[0][1]*x[1]+B[0][0]*U(0)+B[0][1]*U(1);
dx[1]=A[1][0]*x[0]+A[1][1]*x[1]+B[1][0]*U(0)+B[1][1]*U(1);
}
The required mdlTerminate function performs any actions, such as freeing memory,
necessary at the end of the simulation. In this example, the function is empty.
/* Function: mdlTerminate =====================================================
* Abstract:
* No termination needed, but we are required to have this routine.
*/
static void mdlTerminate(SimStruct *S)
{
UNUSED_ARG(S); /* unused input argument */
}
The required S-function trailer includes the files necessary for simulation or code
generation, as follows.
#ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX file? */
#include "simulink.c" /* MEX file interface mechanism */
#else
#include "cg_sfun.h" /* Code generation registration function */
#endif
Note The mdlOutputs and mdlTerminate functions use the UNUSED_ARG macro to
indicate that an input argument the callback requires is not used. This optional macro is
defined in simstruc_types.h. If used, you must call this macro once for each input
argument that a callback does not use.
Discrete States
The dsfunc.c example shows how to model a discrete system in a C MEX S-function.
The following Simulink model uses this S-function.
sfcndemo_dsfunc
9-69
9 Implementing Block Features for C/C++ S-Functions
matlabroot/toolbox/simulink/simdemos/simfeatures/src/dsfunc.c
The S-function dsfunc.c begins with #define statements for the S-function name and
level, along with a #include statement for the simstruc.h header. After these
statements, the S-function can include or define any other necessary headers, data, etc.
The dsfunc.c example defines U as a pointer to the first input port's signal and initializes
static variables for the state-space matrices.
/* File : dsfunc.c
* Abstract:
*
* Example C S-function for defining a discrete system.
*
* x(n+1) = Ax(n) + Bu(n)
* y(n) = Cx(n) + Du(n)
*
* For more details about S-functions, see simulink/src/sfuntmpl_doc.c.
*
* Copyright 1990-2013 The MathWorks, Inc.
*/
#include "simstruc.h"
9-70
C MEX S-Function Examples
{ 1 , 0 }
};
9-71
9 Implementing Block Features for C/C++ S-Functions
/*====================*
* S-function methods *
*====================*/
ssSetNumContStates(S, 0);
ssSetNumDiscStates(S, 2);
ssSetNumSampleTimes(S, 1);
ssSetNumRWork(S, 0);
ssSetNumIWork(S, 0);
ssSetNumPWork(S, 0);
ssSetNumModes(S, 0);
ssSetNumNonsampledZCs(S, 0);
9-72
C MEX S-Function Examples
ssSetModelReferenceSampleTimeDefaultInheritance(S);
}
for (lp=0;lp<2;lp++) {
*x0++=1.0;
}
}
The required mdlOutputs function computes the output signal of this S-function. The
beginning of the function obtains pointers to the first output port, discrete states, and
first input port. The S-function uses the data in these arrays to solve the output equation
y=Cx+Du.
/* Function: mdlOutputs =======================================================
* Abstract:
* y = Cx + Du
*/
static void mdlOutputs(SimStruct *S, int_T tid)
{
real_T *y = ssGetOutputPortRealSignal(S,0);
real_T *x = ssGetRealDiscStates(S);
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
/* y=Cx+Du */
y[0]=C[0][0]*x[0]+C[0][1]*x[1]+D[0][0]*U(0)+D[0][1]*U(1);
y[1]=C[1][0]*x[0]+C[1][1]*x[1]+D[1][0]*U(0)+D[1][1]*U(1);
}
The Simulink engine calls the mdlUpdate function once every major integration time step
to update the discrete states' values. Because this function is an optional method, a
#define statement must precede the function. The beginning of the function obtains
pointers to the S-function discrete states and first input port. The S-function uses the data
9-73
9 Implementing Block Features for C/C++ S-Functions
in these arrays to solve the equation dx=Ax+Bu, which is stored in the temporary variable
tempX before being assigned into the discrete state vector x.
#define MDL_UPDATE
/* Function: mdlUpdate ======================================================
* Abstract:
* xdot = Ax + Bu
*/
static void mdlUpdate(SimStruct *S, int_T tid)
{
real_T tempX[2] = {0.0, 0.0};
real_T *x = ssGetRealDiscStates(S);
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
/* xdot=Ax+Bu */
tempX[0]=A[0][0]*x[0]+A[0][1]*x[1]+B[0][0]*U(0)+B[0][1]*U(1);
tempX[1]=A[1][0]*x[0]+A[1][1]*x[1]+B[1][0]*U(0)+B[1][1]*U(1);
x[0]=tempX[0];
x[1]=tempX[1];
}
The required mdlTerminate function performs any actions, such as freeing memory,
necessary at the end of the simulation. In this example, the function is empty.
/* Function: mdlTerminate =====================================================
* Abstract:
* No termination needed, but we are required to have this routine.
*/
static void mdlTerminate(SimStruct *S)
{
UNUSED_ARG(S); /* unused input argument */
}
The required S-function trailer includes the files necessary for simulation or code
generation, as follows.
#ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX file? */
#include "simulink.c" /* MEX file interface mechanism */
#else
#include "cg_sfun.h" /* Code generation registration function */
#endif
Note The mdlOutputs and mdlTerminate functions use the UNUSED_ARG macro to
indicate that an input argument the callback requires is not used. This optional macro is
defined in simstruc_types.h. If used, you must call this macro once for each input
argument that a callback does not use.
9-74
C MEX S-Function Examples
sfcndemo_mixedm
If you have a hybrid system, the mdlDerivatives method calculates the derivatives of
the continuous states of the state vector, x, and the mdlUpdate method contains the
equations used to update the discrete state vector, xD. The mdlOutputs method
computes the S-function outputs after checking for sample hits to determine at what point
the S-function is being called.
matlabroot/toolbox/simulink/simdemos/simfeatures/src/mixedm.c
The S-function mixedm.c begins with #define statements for the S-function name and
level, along with a #include statement for the simstruc.h header. After these
statements, the S-function can include or define any other necessary headers, data, etc.
The mixedm.c example defines U as a pointer to the first input port's signal.
/* File : mixedm.c
* Abstract:
*
* An example S-function illustrating multiple sample times by implementing
* integrator -> ZOH(Ts=1second) -> UnitDelay(Ts=1second)
* with an initial condition of 1.
* (e.g. an integrator followed by unit delay operation).
*
* For more details about S-functions, see simulink/src/sfuntmpl_doc.c
*
* Copyright 1990-2007 The MathWorks, Inc.
*/
#include "simstruc.h"
9-75
9 Implementing Block Features for C/C++ S-Functions
9-76
C MEX S-Function Examples
ssSetNumContStates(S, 1);
ssSetNumDiscStates(S, 1);
ssSetNumRWork(S, 1); /* for zoh output feeding the delay operator */
ssSetNumSampleTimes(S, 2);
} /* end mdlInitializeSizes */
ssSetSampleTime(S, 1, 1.0);
9-77
9 Implementing Block Features for C/C++ S-Functions
ssSetOffsetTime(S, 1, 0.0);
ssSetModelReferenceSampleTimeDefaultInheritance(S);
} /* end mdlInitializeSampleTimes */
xC0[0] = 1.0;
xD0[0] = 1.0;
} /* end mdlInitializeConditions */
The required mdlOutputs function performs computations based on the current task.
The macro ssIsContinuousTask checks if the continuous task is executing. If this
macro returns true, ssIsSpecialSampleHit then checks if the discrete sample rate is
also executing. If this macro also returns true, the method sets the value of the floating-
point work vector to the current value of the continuous state, via pointers obtained using
ssGetRWork and ssGetContStates, respectively. The mdlUpdate method later uses
the floating-point work vector as the input to the zero-order hold. Updating the work
vector in mdlOutputs ensures that the correct values are available during subsequent
calls to mdlUpdate. Finally, if the S-function is running at its discrete rate, i.e., the call to
ssIsSampleHit returns true, the method sets the output to the value of the discrete
state.
/* Function: mdlOutputs =======================================================
* Abstract:
* y = xD, and update the zoh internal output.
*/
static void mdlOutputs(SimStruct *S, int_T tid)
{
/* update the internal "zoh" output */
if (ssIsContinuousTask(S, tid)) {
if (ssIsSpecialSampleHit(S, 1, 0, tid)) {
real_T *zoh = ssGetRWork(S);
real_T *xC = ssGetContStates(S);
*zoh = *xC;
}
9-78
C MEX S-Function Examples
/* y=xD */
if (ssIsSampleHit(S, 1, tid)) {
real_T *y = ssGetOutputPortRealSignal(S,0);
real_T *xD = ssGetRealDiscStates(S);
y[0]=xD[0];
}
} /* end mdlOutputs */
The Simulink engine calls the mdlUpdate function once every major integration time step
to update the discrete states' values. Because this function is an optional method, a
#define statement must precede the function. The call to ssIsSampleHit ensures the
body of the method is executed only when the S-function is operating at its discrete rate.
If ssIsSampleHit returns true, the method obtains pointers to the S-function discrete
state and floating-point work vector and updates the discrete state's value using the value
stored in the work vector.
#define MDL_UPDATE
/* Function: mdlUpdate ======================================================
* Abstract:
* xD = xC
*/
static void mdlUpdate(SimStruct *S, int_T tid)
{
UNUSED_ARG(tid); /* not used in single tasking mode */
/* xD=xC */
if (ssIsSampleHit(S, 1, tid)) {
real_T *xD = ssGetRealDiscStates(S);
real_T *zoh = ssGetRWork(S);
xD[0]=*zoh;
}
} /* end mdlUpdate */
The mdlDerivatives function calculates the continuous state derivatives. Because this
function is an optional method, a #define statement must precede the function. The
function obtains pointers to the S-function continuous state derivative and first input port
then sets the continuous state derivative equal to the value of the first input.
#define MDL_DERIVATIVES
/* Function: mdlDerivatives =================================================
* Abstract:
* xdot = U
*/
static void mdlDerivatives(SimStruct *S)
{
real_T *dx = ssGetdX(S);
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
9-79
9 Implementing Block Features for C/C++ S-Functions
/* xdot=U */
dx[0]=U(0);
} /* end mdlDerivatives */
The required mdlTerminate function performs any actions, such as freeing memory,
necessary at the end of the simulation. In this example, the function is empty.
/* Function: mdlTerminate =====================================================
* Abstract:
* No termination needed, but we are required to have this routine.
*/
static void mdlTerminate(SimStruct *S)
{
UNUSED_ARG(S); /* unused input argument */
}
The S-function trailer includes the files necessary for simulation or code generation, as
follows.
#ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX file? */
#include "simulink.c" /* MEX file interface mechanism */
#else
#include "cg_sfun.h" /* Code generation registration function */
#endif
Note The mdlUpdate and mdlTerminate functions use the UNUSED_ARG macro to
indicate that an input argument the callback requires is not used. This optional macro is
defined in simstruc_types.h. If used, you must call this macro once for each input
argument that a callback does not use.
sfcndemo_vsfunc
The vsfunc.c example outputs the input u delayed by a variable amount of time.
mdlOutputs sets the output y equal to state x. mdlUpdate sets the state vector x equal
9-80
C MEX S-Function Examples
to u, the input vector. This example calls mdlGetTimeOfNextVarHit to calculate and set
the time of the next sample hit, that is, the time when vsfunc.c is next called. In
mdlGetTimeOfNextVarHit, the macro ssGetInputPortRealSignalPtrs gets a
pointer to the input u. Then this call is made:
The macro ssGetT gets the simulation time t. The second input to the block, U(1), is
added to t, and the macro ssSetTNext sets the time of the next hit equal to t+U(1),
delaying the output by the amount of time set in (U(1)).
matlabroot/toolbox/simulink/simdemos/simfeatures/src/vsfunc.c
The S-function vsfunc.c begins with #define statements for the S-function name and
level, along with a #include statement for the simstruc.h header. After these
statements, the S-function can include or define any other necessary headers, data, etc.
The vsfunc.c example defines U as a pointer to the first input port's signal.
/* File : vsfunc.c
* Abstract:
*
* Variable step S-function example.
* This example S-function illustrates how to create a variable step
* block. This block implements a variable step delay
* in which the first input is delayed by an amount of time determined
* by the second input:
*
* dt = u(2)
* y(t+dt) = u(t)
*
* For more details about S-functions, see simulink/src/sfuntmpl_doc.c.
*
* Copyright 1990-2007 The MathWorks, Inc.
*/
#include "simstruc.h"
9-81
9 Implementing Block Features for C/C++ S-Functions
ssSetNumContStates(S, 0);
ssSetNumDiscStates(S, 1);
9-82
C MEX S-Function Examples
ssSetNumSampleTimes(S, 1);
ssSetNumRWork(S, 0);
ssSetNumIWork(S, 0);
ssSetNumPWork(S, 0);
ssSetNumModes(S, 0);
ssSetNumNonsampledZCs(S, 0);
9-83
9 Implementing Block Features for C/C++ S-Functions
#define MDL_INITIALIZE_CONDITIONS
/* Function: mdlInitializeConditions ========================================
* Abstract:
* Initialize discrete state to zero.
*/
static void mdlInitializeConditions(SimStruct *S)
{
real_T *x0 = ssGetRealDiscStates(S);
x0[0] = 0.0;
}
The optional mdlGetTimeOfNextVarHit method calculates the time of the next sample
hit. Because this method is optional, a #define statement precedes it. First, this method
obtains a pointer to the first input port's signal using
ssGetInputPortRealSignalPtrs. If the input signal's second element is positive, the
macro ssGetT gets the simulation time t. The macro ssSetTNext sets the time of the
next hit equal to t+(*U[1]), delaying the output by the amount of time specified by the
input's second element (*U[1]).
#define MDL_GET_TIME_OF_NEXT_VAR_HIT
static void mdlGetTimeOfNextVarHit(SimStruct *S)
{
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
The required mdlOutputs function computes the S-function output signal. The function
obtains pointers to the first output port and discrete state and then assigns the state's
current value to the output.
/* Function: mdlOutputs =======================================================
* Abstract:
* y = x
*/
static void mdlOutputs(SimStruct *S, int_T tid)
{
real_T *y = ssGetOutputPortRealSignal(S,0);
real_T *x = ssGetRealDiscStates(S);
9-84
C MEX S-Function Examples
The mdlUpdate function updates the discrete state's value. Because this method is
optional, a #define statement precedes it. The function first obtains pointers to the S-
function discrete state and first input port then assigns the value of the first element of
the first input port signal to the state.
#define MDL_UPDATE
/* Function: mdlUpdate ========================================================
* Abstract:
* This function is called once for every major integration time step.
* Discrete states are typically updated here, but this function is useful
* for performing any tasks that should only take place once per integration
* step.
*/
static void mdlUpdate(SimStruct *S, int_T tid)
{
real_T *x = ssGetRealDiscStates(S);
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
x[0]=U(0);
}
The required mdlTerminate function performs any actions, such as freeing memory,
necessary at the end of the simulation. In this example, the function is empty.
/* Function: mdlTerminate =====================================================
* Abstract:
* No termination needed, but we are required to have this routine.
*/
static void mdlTerminate(SimStruct *S)
{
}
The required S-function trailer includes the files necessary for simulation or code
generation, as follows.
#ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX file? */
#include "simulink.c" /* MEX file interface mechanism */
#else
#include "cg_sfun.h" /* Code generation registration function */
#endif
sfcndemo_matadd
The S-function adds signals of various dimensions to a parameter value entered in the S-
function. The S-function accepts and outputs 2-D or n-D signals.
9-85
9 Implementing Block Features for C/C++ S-Functions
matlabroot/toolbox/simulink/simdemos/simfeatures/src/sfun_matadd.c
The S-function sfun_matadd.c begins with #define statements for the S-function name
and level, along with a #include statement for the simstruc.h header. After these
statements, the S-function includes or defines any other necessary headers, data, etc.
This example defines additional variables for the number of S-function parameters, the S-
function parameter value, and the flag EDIT_OK that indicates if the parameter value can
be edited during simulation.
/* SFUN_MATADD matrix support example.
* C MEX S-function for matrix addition with one input port,
* one output port, and one parameter.
*
* Input Signal: 2-D or n-D array
* Parameter: 2-D or n-D array
* Output Signal: 2-D or n-D array
*
* Input parameter output
* --------------------------------
* scalar scalar scalar
* scalar matrix matrix (input scalar expansion)
* matrix scalar matrix (parameter scalar expansion)
* matrix matrix matrix
*
* Copyright 1990-2007 The MathWorks, Inc.
*/
#define S_FUNCTION_NAME sfun_matadd
#define S_FUNCTION_LEVEL 2
#include "simstruc.h"
9-86
C MEX S-Function Examples
* Abstract:
* Verify parameter settings.
*/
static void mdlCheckParameters(SimStruct *S)
{
if(EDIT_OK(S, PARAM_ARG)){
/* Check that parameter value is not empty*/
if( mxIsEmpty(PARAM_ARG) ) {
ssSetErrorStatus(S, "Invalid parameter specified. The"
"parameter must be non-empty");
return;
}
}
} /* end mdlCheckParameters */
#endif
9-87
9 Implementing Block Features for C/C++ S-Functions
#if defined(MATLAB_MEX_FILE)
if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
return; }
mdlCheckParameters(S);
if (ssGetErrorStatus(S) != NULL) return;
#endif
{
int iParam = 0;
int nParam = ssGetNumSFcnParams(S);
9-88
C MEX S-Function Examples
if( pWidth == 1) {
/* Scalar parameter: output dimensions are unknown. */
if(!ssSetOutputPortDimensionInfo(S,0,DYNAMIC_DIMENSION)){
return; }
}
else{
/*
* Non-scalar parameter: output dimensions are the same
* as the parameter dimensions. To support n-D signals,
* must use a dimsInfo structure to specify dimensions.
*/
DECL_AND_INIT_DIMSINFO(di); /*Initializes structure*/
int_T pSize = mxGetNumberOfDimensions(PARAM_ARG);
const int_T *pDims = mxGetDimensions(PARAM_ARG);
di.width = pWidth;
di.numDims = pSize;
di.dims = pDims;
if(!ssSetOutputPortDimensionInfo(S, 0, &di)) return;
}
}
ssSetInputPortDirectFeedThrough(S, 0, 1);
ssSetNumSampleTimes(S, 1);
ssSetOptions(S,
SS_OPTION_WORKS_WITH_CODE_REUSE |
SS_OPTION_EXCEPTION_FREE_CODE);
} /* end mdlInitializeSizes */
The S-function calls the mdlSetWorkWidths method to register its run-time parameters.
Because mdlSetWorkWidths is an optional method, a #define statement precedes it.
The method first initializes a name for the run-time parameter and then uses
ssRegAllTunableParamsAsRunTimeParams to register the run-time parameter.
9-89
9 Implementing Block Features for C/C++ S-Functions
The S-function mdlOutputs method uses a for loop to calculate the output as the sum of
the input and S-function parameter. The S-function handles n-D arrays of data using a
single index into the array.
/* Function: mdlOutputs ========================================
* Abstract:
* Compute the outputs of the S-function.
*/
static void mdlOutputs(SimStruct *S, int_T tid)
{
InputRealPtrsType uPtr = ssGetInputPortRealSignalPtrs(S,0);
real_T *y = ssGetOutputPortRealSignal(S,0);
const real_T *p = mxGetPr(PARAM_ARG);
/*
* Note1: Matrix signals are stored in column major order.
* Note2: Access each matrix element by one index not two
* indices. For example, if the output signal is a
* [2x2] matrix signal,
* - -
* | y[0] y[2] |
* | y[1] y[3] |
* - -
* Output elements are stored as follows:
* y[0] --> row = 0, col = 0
* y[1] --> row = 1, col = 0
* y[2] --> row = 0, col = 1
* y[3] --> row = 1, col = 1
*/
9-90
C MEX S-Function Examples
int_T numDims;
boolean_T isOk = true;
int iParam = 0;
int_T outWidth = ssGetOutputPortWidth(S, 0);
/*
* The block only accepts 2-D or higher signals. Check
* number of dimensions. If the parameter and the input
* signal are non-scalar, their dimensions must be the same.
*/
9-91
9 Implementing Block Features for C/C++ S-Functions
if(!isOk){
ssSetErrorStatus(S,"Invalid input port dimensions. The "
"input signal must be a 2-D scalar signal, or it must "
"be a matrix with the same dimensions as the parameter "
"dimensions.");
return;
}
During signal propagation, if any output ports have unknown dimensions, the S-function
calls the optional mdlSetOutputPortDimensionInfo method. Because this method is
optional, a #define statement precedes it. In mdlSetOutputPortDimensionInfo, the
S-function uses ssSetOutputPortDimensionInfo to set the dimensions of the output
port to the candidate dimensions dimsInfo. If the call to this macro succeeds, the S-
function further checks the candidate dimensions to ensure that the input signal is either
a 2-D or n-D matrix. If this condition is not met, the S-function errors out with a call to
ssSetErrorStatus. Otherwise, the S-function calls ssSetInputPortDimensionInfo
to set the dimension of the input port to the same candidate dimensions.
# define MDL_SET_OUTPUT_PORT_DIMENSION_INFO
/* Function: mdlSetOutputPortDimensionInfo =====================
* Abstract:
* This routine is called with the candidate dimensions for
* an output port with unknown dimensions. If the proposed
* dimensions are acceptable, the routine should go ahead and
* set the actual port dimensions. If they are unacceptable
* an error should be generated via ssSetErrorStatus.
* Note that any other input or output ports whose dimensions
* are implicitly defined by virtue of knowing the dimensions
* of the given port can also have their dimensions set.
*/
static void mdlSetOutputPortDimensionInfo(SimStruct *S,
int_T port,
const DimsInfo_T *dimsInfo)
{
/*
9-92
C MEX S-Function Examples
Because the S-function has ports that are dynamically sized, it must provide an
mdlSetDefaultPortDimensionInfo method. The Simulink engine invokes this method
during signal propagation when it cannot determine the dimensionality of the signal
connected to the block's input port. This situation can happen, for example, if the input
port is unconnected. In this example, the mdlSetDefaultPortDimensionInfo method
sets the input and output ports dimensions to a scalar.
# define MDL_SET_DEFAULT_PORT_DIMENSION_INFO
/* Function: mdlSetDefaultPortDimensionInfo ====================
* This routine is called when the Simulink engine is not able
* to find dimension candidates for ports with unknown dimensions.
* This function must set the dimensions of all ports with
* unknown dimensions.
*/
static void mdlSetDefaultPortDimensionInfo(SimStruct *S)
{
int_T outWidth = ssGetOutputPortWidth(S, 0);
/* Input port dimension must be unknown. Set it to scalar.*/
if(!ssSetInputPortMatrixDimensions(S, 0, 1, 1)) return;
if(outWidth == DYNAMICALLY_SIZED){
/* Output dimensions are unknown. Set it to scalar. */
if(!ssSetOutputPortMatrixDimensions(S, 0, 1, 1)) return;
}
} /* end mdlSetDefaultPortDimensionInfo */
#endif
The required mdlTerminate function performs any actions, such as freeing memory,
necessary at the end of the simulation. In this example, the function is empty.
/* Function: mdlTerminate ======================================
* Abstract:
* Called when the simulation is terminated.
*/
9-93
9 Implementing Block Features for C/C++ S-Functions
} /* end mdlTerminate */
The required S-function trailer includes the files necessary for simulation or code
generation.
#ifdef MATLAB_MEX_FILE
#include "simulink.c"
#else
#include "cg_sfun.h"
#endif
/* [EOF] sfun_matadd.c */
Note The mdlOutputs and mdlTerminate functions use the UNUSED_ARG macro to
indicate that an input argument the callback requires is not used. This optional macro is
defined in simstruc_types.h. You must call this macro once for each input argument
that a callback does not use.
Zero-Crossing Detection
The example S-function sfun_zc_sat.c demonstrates how to implement a Saturation
block. The following Simulink model uses this S-function.
sfcndemo_sfun_zc_sat
The S-function works with either fixed-step or variable-step solvers. When this S-function
inherits a continuous sample time and uses a variable-step solver, it uses a zero-crossings
algorithm to locate the exact points at which the saturation occurs.
matlabroot/toolbox/simulink/simdemos/simfeatures/src/sfun_zc_sat.c
The S-function sfun_zc_sat.c begins with #define statements for the S-function name
and level, along with a #include statement for the simstruc.h header. After these
statements, the S-function includes or defines any other necessary headers, data, etc.
This example defines various parameters associated with the upper and lower saturation
bounds.
/* File : sfun_zc_sat.c
* Abstract:
*
* Example of an S-function which has nonsampled zero crossings to
9-94
C MEX S-Function Examples
#include "simstruc.h"
/*========================*
* General Defines/macros *
*========================*/
/*
* Make access to mxArray pointers for parameters more readable.
*/
#define P_PAR_UPPER_LIMIT ( ssGetSFcnParam(S,I_PAR_UPPER_LIMIT) )
#define P_PAR_LOWER_LIMIT ( ssGetSFcnParam(S,I_PAR_LOWER_LIMIT) )
This S-function next implements the mdlCheckParameters method to check the validity
of the S-function dialog parameters. Because this method is optional, a #define
statement precedes it. The #if defined statement checks that this function is compiled
as a MEX file, instead of for use with the Simulink Coder product. The body of the
function performs basic checks to ensure that the user entered real vectors of equal
9-95
9 Implementing Block Features for C/C++ S-Functions
length for the upper and lower saturation limits. If the parameter checks fail, the S-
function errors out.
#define MDL_CHECK_PARAMETERS
#if defined(MDL_CHECK_PARAMETERS) && defined(MATLAB_MEX_FILE)
/*
* check parameter basics
*/
for ( i = 0; i < N_PAR; i++ ) {
if ( mxIsEmpty( ssGetSFcnParam(S,i) ) ||
mxIsSparse( ssGetSFcnParam(S,i) ) ||
mxIsComplex( ssGetSFcnParam(S,i) ) ||
!mxIsNumeric( ssGetSFcnParam(S,i) ) ) {
msg = "Parameters must be real vectors.";
goto EXIT_POINT;
}
}
/*
* Check sizes of parameters.
*/
numUpperLimit = mxGetNumberOfElements( P_PAR_UPPER_LIMIT );
numLowerLimit = mxGetNumberOfElements( P_PAR_LOWER_LIMIT );
if ( ( numUpperLimit != 1 ) &&
( numLowerLimit != 1 ) &&
( numUpperLimit != numLowerLimit ) ) {
msg = "Number of input and output values must be equal.";
goto EXIT_POINT;
}
/*
* Error exit point
*/
EXIT_POINT:
if (msg != NULL) {
ssSetErrorStatus(S, msg);
}
}
#endif /* MDL_CHECK_PARAMETERS */
9-96
C MEX S-Function Examples
9-97
9 Implementing Block Features for C/C++ S-Functions
/*
* Set and Check parameter count
*/
ssSetNumSFcnParams(S, N_PAR);
#if defined(MATLAB_MEX_FILE)
if (ssGetNumSFcnParams(S) == ssGetSFcnParamsCount(S)) {
mdlCheckParameters(S);
if (ssGetErrorStatus(S) != NULL) {
return;
}
} else {
return; /* Parameter mismatch reported by the Simulink engine*/
}
#endif
/*
* Get parameter size info.
*/
numUpperLimit = mxGetNumberOfElements( P_PAR_UPPER_LIMIT );
numLowerLimit = mxGetNumberOfElements( P_PAR_LOWER_LIMIT );
/*
* states
*/
ssSetNumContStates(S, 0);
ssSetNumDiscStates(S, 0);
/*
* outputs
* The upper and lower limits are scalar expanded
* so their size determines the size of the output
* only if at least one of them is not scalar.
*/
if (!ssSetNumOutputPorts(S, 1)) return;
if ( maxNumLimit > 1 ) {
ssSetOutputPortWidth(S, 0, maxNumLimit);
} else {
ssSetOutputPortWidth(S, 0, DYNAMICALLY_SIZED);
}
9-98
C MEX S-Function Examples
/*
* inputs
* If the upper or lower limits are not scalar then
* the input is set to the same size. However, the
* ssSetOptions below allows the actual width to
* be reduced to 1 if needed for scalar expansion.
*/
if (!ssSetNumInputPorts(S, 1)) return;
ssSetInputPortDirectFeedThrough(S, 0, 1 );
if ( maxNumLimit > 1 ) {
ssSetInputPortWidth(S, 0, maxNumLimit);
} else {
ssSetInputPortWidth(S, 0, DYNAMICALLY_SIZED);
}
/*
* sample times
*/
ssSetNumSampleTimes(S, 1);
/*
* work
*/
ssSetNumRWork(S, 0);
ssSetNumIWork(S, 0);
ssSetNumPWork(S, 0);
/*
* Modes and zero crossings:
* If we have a variable-step solver and this block has a continuous
* sample time, then
* o One mode element will be needed for each scalar output
* in order to specify which equation is valid (1), (2), or (3).
* o Two ZC elements will be needed for each scalar output
* in order to help the solver find the exact instants
* at which either of the two possible "equation switches"
* One will be for the switch from eq. (1) to (2);
* the other will be for eq. (2) to (3) and vice versa.
* otherwise
* o No modes and nonsampled zero crossings will be used.
*
*/
ssSetNumModes(S, DYNAMICALLY_SIZED);
ssSetNumNonsampledZCs(S, DYNAMICALLY_SIZED);
/*
* options
* o No mexFunctions and no problematic mxFunctions are called
* so the exception free code option safely gives faster simulations.
* o Scalar expansion of the inputs is desired. The option provides
* this without the need to write mdlSetOutputPortWidth and
9-99
9 Implementing Block Features for C/C++ S-Functions
* mdlSetInputPortWidth functions.
*/
ssSetOptions(S, ( SS_OPTION_EXCEPTION_FREE_CODE |
SS_OPTION_ALLOW_INPUT_SCALAR_EXPANSION));
} /* end mdlInitializeSizes */
if (ssIsVariableStepSolver(S) &&
ssGetSampleTime(S,0) == CONTINUOUS_SAMPLE_TIME &&
ssGetOffsetTime(S,0) == 0.0) {
9-100
C MEX S-Function Examples
/*
* modes and zero crossings
* o One mode element will be needed for each scalar output
* in order to specify which equation is valid (1), (2), or (3).
* o Two ZC elements will be needed for each scalar output
* in order to help the solver find the exact instants
* at which either of the two possible "equation switches"
* One will be for the switch from eq. (1) to (2);
* the other will be for eq. (2) to (3) and vice versa.
*/
nModes = numOutput;
nNonsampledZCs = 2 * numOutput;
} else {
nModes = 0;
nNonsampledZCs = 0;
}
ssSetNumModes(S,nModes);
ssSetNumNonsampledZCs(S,nNonsampledZCs);
}
#endif /* MDL_SET_WORK_WIDTHS */
After declaring variables for the input and output signals, the mdlOutputs functions uses
an if-else statement to create blocks of code used to calculate the output signal based
on whether the S-function uses a fixed-step or variable-step solver. The if statement
queries the length of the nonsampled zero-crossing vector. If the length, set in
mdlWorkWidths, is zero, then no zero-crossing detection is done and the output signals
are calculated directly from the input signals. Otherwise, the function uses the mode
work vector to determine how to calculate the output signal. If the simulation is at a
major time step, i.e., ssIsMajorTimeStep returns true, mdlOutputs determines which
mode the simulation is running in, either saturated at the upper limit, saturated at the
lower limit, or not saturated. Then, for both major and minor time steps, the function
calculates an output based on this mode. If the mode changed between the previous and
current time step, then a zero crossing occurred. The mdlZeroCrossings function, not
mdlOutputs, indicates this crossing to the solver.
/* Function: mdlOutputs =======================================================
* Abstract:
*
* A saturation is described by three equations
*
* (1) y = UpperLimit
* (2) y = u
* (3) y = LowerLimit
*
* When this block is used with a fixed-step solver or it has a noncontinuous
* sample time, the equations are used as it
*
* Now consider the case of this block being used with a variable-step solver
9-101
9 Implementing Block Features for C/C++ S-Functions
* and it has a continuous sample time. Solvers work best on smooth problems.
* In order for the solver to work without chattering, limit cycles, or
* similar problems, it is absolutely crucial that the same equation be used
* throughout the duration of a MajorTimeStep. To visualize this, consider
* the case of the Saturation block feeding an Integrator block.
*
* To implement this rule, the mode vector is used to specify the
* valid equation based on the following:
*
* if UpperLimit < u then use (1)
* if LowerLimit <= u <= UpperLimit then use (2)
* if u < LowerLimit then use (3)
*
* The mode vector is changed only at the beginning of a MajorTimeStep.
*
* During a minor time step, the equation specified by the mode vector
* is used without question. Most of the time, the value of u will agree
* with the equation specified by the mode vector. However, sometimes u's
* value will indicate a different equation. Nonetheless, the equation
* specified by the mode vector must be used.
*
* When the mode and u indicate different equations, the corresponding
* calculations are not correct. However, this is not a problem. From
* the ZC function, the solver will know that an equation switch occurred
* in the middle of the last MajorTimeStep. The calculations for that
* time step will be discarded. The ZC function will help the solver
* find the exact instant at which the switch occurred. Using this knowledge,
* the length of the MajorTimeStep will be reduced so that only one equation
* is valid throughout the entire time step.
*/
static void mdlOutputs(SimStruct *S, int_T tid)
{
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
real_T *y = ssGetOutputPortRealSignal(S,0);
int_T numOutput = ssGetOutputPortWidth(S,0);
int_T iOutput;
/*
* Set index and increment for input signal, upper limit, and lower limit
* parameters so that each gives scalar expansion if needed.
*/
int_T uIdx = 0;
int_T uInc = ( ssGetInputPortWidth(S,0) > 1 );
const real_T *upperLimit = mxGetPr( P_PAR_UPPER_LIMIT );
int_T upperLimitInc = ( mxGetNumberOfElements( P_PAR_UPPER_LIMIT ) > 1 );
const real_T *lowerLimit = mxGetPr( P_PAR_LOWER_LIMIT );
int_T lowerLimitInc = ( mxGetNumberOfElements( P_PAR_LOWER_LIMIT ) > 1 );
if (ssGetNumNonsampledZCs(S) == 0) {
/*
* This block is being used with a fixed-step solver or it has
* a noncontinuous sample time, so we always saturate.
*/
9-102
C MEX S-Function Examples
upperLimit += upperLimitInc;
lowerLimit += lowerLimitInc;
uIdx += uInc;
}
} else {
/*
* This block is being used with a variable-step solver.
*/
int_T *mode = ssGetModeVector(S);
/*
* Specify indices for each equation.
*/
enum { UpperLimitEquation, NonLimitEquation, LowerLimitEquation };
/*
* Update the Mode Vector ONLY at the beginning of a MajorTimeStep
*/
if ( ssIsMajorTimeStep(S) ) {
/*
* Specify the mode, ie the valid equation for each output scalar.
*/
for ( iOutput = 0; iOutput < numOutput; iOutput++ ) {
if ( *uPtrs[uIdx] > *upperLimit ) {
/*
* Upper limit eq is valid.
*/
mode[iOutput] = UpperLimitEquation;
} else if ( *uPtrs[uIdx] < *lowerLimit ) {
/*
* Lower limit eq is valid.
*/
mode[iOutput] = LowerLimitEquation;
} else {
/*
* Nonlimit eq is valid.
*/
mode[iOutput] = NonLimitEquation;
}
/*
* Adjust indices to give scalar expansion if needed.
*/
uIdx += uInc;
upperLimit += upperLimitInc;
lowerLimit += lowerLimitInc;
9-103
9 Implementing Block Features for C/C++ S-Functions
/*
* Reset index to input and limits.
*/
uIdx = 0;
upperLimit = mxGetPr( P_PAR_UPPER_LIMIT );
lowerLimit = mxGetPr( P_PAR_LOWER_LIMIT );
} /* end IsMajorTimeStep */
/*
* For both MinorTimeSteps and MajorTimeSteps calculate each scalar
* output using the equation specified by the mode vector.
*/
for ( iOutput = 0; iOutput < numOutput; iOutput++ ) {
if ( mode[iOutput] == UpperLimitEquation ) {
/*
* Upper limit eq.
*/
*y++ = *upperLimit;
} else if ( mode[iOutput] == LowerLimitEquation ) {
/*
* Lower limit eq.
*/
*y++ = *lowerLimit;
} else {
/*
* Nonlimit eq.
*/
*y++ = *uPtrs[uIdx];
}
/*
* Adjust indices to give scalar expansion if needed.
*/
uIdx += uInc;
upperLimit += upperLimitInc;
lowerLimit += lowerLimitInc;
}
}
} /* end mdlOutputs */
9-104
C MEX S-Function Examples
#define MDL_ZERO_CROSSINGS
#if defined(MDL_ZERO_CROSSINGS) && (defined(MATLAB_MEX_FILE) || defined(NRT))
9-105
9 Implementing Block Features for C/C++ S-Functions
/*
* Set index and increment for the input signal, upper limit, and lower
* limit parameters so that each gives scalar expansion if needed.
*/
int_T uIdx = 0;
int_T uInc = ( ssGetInputPortWidth(S,0) > 1 );
real_T *upperLimit = mxGetPr( P_PAR_UPPER_LIMIT );
int_T upperLimitInc = ( mxGetNumberOfElements( P_PAR_UPPER_LIMIT ) > 1 );
real_T *lowerLimit = mxGetPr( P_PAR_LOWER_LIMIT );
int_T lowerLimitInc = ( mxGetNumberOfElements( P_PAR_LOWER_LIMIT ) > 1 );
/*
* For each output scalar, give the solver a measure of "how close things
* are" to an equation switch.
*/
for ( iOutput = 0; iOutput < numOutput; iOutput++ ) {
/*
* Adjust indices to give scalar expansion if needed.
*/
uIdx += uInc;
upperLimit += upperLimitInc;
lowerLimit += lowerLimitInc;
}
}
9-106
C MEX S-Function Examples
The S-function concludes with the required mdlTerminate function. In this example, the
function is empty.
/* Function: mdlTerminate =====================================================
* Abstract:
* No termination needed, but we are required to have this routine.
*/
static void mdlTerminate(SimStruct *S)
{
UNUSED_ARG(S); /* unused input argument */
}
The required S-function trailer includes the files necessary for simulation or code
generation, as follows.
#ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX file? */
#include "simulink.c" /* MEX file interface mechanism */
#else
#include "cg_sfun.h" /* Code generation registration function */
#endif
Note The mdlOutputs and mdlTerminate functions use the UNUSED_ARG macro to
indicate that an input argument the callback requires is not used. This optional macro is
defined in simstruc_types.h. If used, you must call this macro once for each input
argument that a callback does not use.
sfcndemo_stvctf
The S-function demonstrates how to work with the solvers so that the simulation
maintains consistency, which means that the block maintains smooth and consistent
signals for the integrators although the equations that are being integrated are changing.
matlabroot/toolbox/simulink/simdemos/simfeatures/src/stvctf.c
The S-function stvctf.c begins with #define statements for the S-function name and
level, along with a #include statement for the simstruc.h header. After these
statements, the S-function includes or defines any other necessary headers, data, etc.
This example defines parameters for the transfer function's numerator and denominator,
which are entered into the S-function dialog. The comments at the beginning of this S-
9-107
9 Implementing Block Features for C/C++ S-Functions
function provide additional information on the purpose of the work vectors in this
example.
/*
* File : stvctf.c
* Abstract:
* Time Varying Continuous Transfer Function block
*
* This S-function implements a continuous time transfer function
* whose transfer function polynomials are passed in via the input
* vector. This is useful for continuous time adaptive control
* applications.
*
* This S-function is also an example of how to use banks to avoid
* problems with computing derivatives when a continuous output has
* discontinuities. The consistency checker can be used to verify that
* your S-function is correct with respect to always maintaining smooth
* and consistent signals for the integrators. By consistent we mean that
* two mdlOutputs calls at major time t and minor time t are always the
* same. The consistency checker is enabled on the diagnostics page of the
* Configuraion parameters dialog box. The update method of this S-function
* modifies the coefficients of the transfer function, which cause the
* output to "jump." To have the simulation work properly, we need to let
* the solver know of these discontinuities by setting
* ssSetSolverNeedsReset and then we need to use multiple banks of
* coefficients so the coefficients used in the major time step output
* and the minor time step outputs are the same. In the simulation loop
* we have:
* Loop:
* o Output in major time step at time t
* o Update in major time step at time t
* o Integrate (minor time step):
* o Consistency check: recompute outputs at time t and compare
* with current outputs.
* o Derivatives at time t
* o One or more Output,Derivative evaluations at time t+k
* where k <= step_size to be taken.
* o Compute state, x
* o t = t + step_size
* End_Integrate
* End_Loop
* Another purpose of the consistency checker is to verify that when
* the solver needs to try a smaller step_size, the recomputing of
* the output and derivatives at time t doesn't change. Step size
* reduction occurs when tolerances aren't met for the current step size.
* The ideal ordering would be to update after integrate. To achieve
* this we have two banks of coefficients. And the use of the new
* coefficients, which were computed in update, is delayed until after
* the integrate phase is complete.
*
* This block has multiple sample times and will not work correctly
* in a multitasking environment. It is designed to be used in
* a single tasking (or variable step) simulation environment.
* Because this block accesses the input signal in both tasks,
* it cannot specify the sample times of the input and output ports
9-108
C MEX S-Function Examples
* (SS_OPTION_PORT_SAMPLE_TIMES_ASSIGNED).
*
* See simulink/src/sfuntmpl_doc.c.
*
* Copyright 1990-7 The MathWorks, Inc.
*/
#include "simstruc.h"
/*
* Defines for easy access to the numerator and denominator polynomials
* parameters
*/
#define NUM(S) ssGetSFcnParam(S, 0)
#define DEN(S) ssGetSFcnParam(S, 1)
#define TS(S) ssGetSFcnParam(S, 2)
#define NPARAMS 3
9-109
9 Implementing Block Features for C/C++ S-Functions
nEls = mxGetNumberOfElements(ssGetSFcnParam(S,i));
for (el = 0; el < nEls; el++) {
if (!mxIsFinite(pr[el])) {
ssSetErrorStatus(S,"Parameters must be real finite vectors");
return;
}
}
}
9-110
C MEX S-Function Examples
• ssSetNumOutputPorts specifies that the S-function has a single output port. The
method uses ssSetOutputPortWidth to set the width of this output port,
ssSetOutputPortSampleTime to specify that the output port has a continuous
sample time, and ssSetOutputPortOffsetTime to set the offset time to zero.
• ssSetNumSampleTimes then initializes two sample times, which the
mdlInitializeSampleTimes function configures later.
• The method passes a value of four times the number of denominator coefficients to
ssSetNumRWork in order to set the length of the floating-point work vector.
ssSetNumIWork then sets the length of the integer work vector to two. The RWork
vectors store two banks of transfer function coefficients, while the IWork vector
indicates which bank in the RWork vector is currently in use. The S-function sets the
length of all other work vectors to zero. You can omit these lines because zero is the
default value for these macros. However, for clarity, the S-function explicitly sets the
number of work vectors.
• Lastly, ssSetOptions sets any applicable options. In this case,
SS_OPTION_EXCEPTION_FREE_CODE stipulates that the code is exception free.
/*
* Define the characteristics of the block:
*
* Number of continuous states: length of denominator - 1
9-111
9 Implementing Block Features for C/C++ S-Functions
ssSetNumContStates(S, nContStates);
ssSetNumDiscStates(S, 0);
if (!ssSetNumOutputPorts(S,1)) return;
ssSetOutputPortWidth(S, 0, 1);
ssSetOutputPortSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME);
ssSetOutputPortOffsetTime(S, 0, 0);
ssSetNumSampleTimes(S, 2);
ssSetNumRWork(S, 4 * nCoeffs);
ssSetNumIWork(S, 2);
ssSetNumPWork(S, 0);
ssSetNumModes(S, 0);
ssSetNumNonsampledZCs(S, 0);
} /* end mdlInitializeSizes */
9-112
C MEX S-Function Examples
continuous and the subsequent call to ssSetOffsetTime sets the offset to zero. The
second call to this pair of macros sets the second sample time to the value of the third S-
function parameter with an offset of zero. The call to
ssSetModelReferenceSampleTimeDefaultInheritance tells the solver to use the
default rule to determine if referenced models containing this S-function can inherit their
sample times from the parent model.
/* Function: mdlInitializeSampleTimes =========================================
* Abstract:
* This function is used to specify the sample time(s) for the
* S-function. This S-function has two sample times. The
* first, a continuous sample time, is used for the input to the
* transfer function, u. The second, a discrete sample time
* provided by the user, defines the rate at which the transfer
* function coefficients are updated.
*/
static void mdlInitializeSampleTimes(SimStruct *S)
{
/*
* the first sample time, continuous
*/
ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME);
ssSetOffsetTime(S, 0, 0.0);
/*
* the second, discrete sample time, is user provided
*/
ssSetSampleTime(S, 1, mxGetPr(TS(S))[0]);
ssSetOffsetTime(S, 1, 0.0);
ssSetModelReferenceSampleTimeDefaultInheritance(S);
} /* end mdlInitializeSampleTimes */
9-113
9 Implementing Block Features for C/C++ S-Functions
/*
* The continuous states are all initialized to zero.
*/
for (i = 0; i < nContStates; i++) {
x0[i] = 0.0;
numBank0[i] = 0.0;
denBank0[i] = 0.0;
}
numBank0[nContStates] = 0.0;
denBank0[nContStates] = 0.0;
/*
* Set up the initial numerator and denominator.
*/
{
const real_T *numParam = mxGetPr(NUM(S));
int numParamLen = mxGetNumberOfElements(NUM(S));
/*
* Normalize if this transfer function has direct feedthrough.
*/
for (i = 1; i < nCoeffs; i++) {
numBank0[i] -= denBank0[i]*numBank0[0];
}
/*
* Indicate bank0 is active (i.e. bank1 is oldest).
*/
*activeBank = 0;
} /* end mdlInitializeConditions */
The mdlOutputs function calculates the S-function output signals when the S-function is
simulating in a continuous task, i.e., ssIsContinuousTask is true. If the simulation is
9-114
C MEX S-Function Examples
also at a major time step, mdlOutputs checks if the numerator and denominator
coefficients need to be updated, as indicated by a switch in the active bank stored in the
IWork vector. At both major and minor time steps, the S-function calculates the output
using the numerator coefficients stored in the active bank.
/* Function: mdlOutputs =======================================================
* Abstract:
* The outputs for this block are computed by using a controllable state-
* space representation of the transfer function.
*/
static void mdlOutputs(SimStruct *S, int_T tid)
{
if (ssIsContinuousTask(S,tid)) {
int i;
real_T *num;
int nContStates = ssGetNumContStates(S);
real_T *x = ssGetContStates(S);
int_T nCoeffs = nContStates + 1;
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
real_T *y = ssGetOutputPortRealSignal(S,0);
int_T *activeBank = ssGetIWork(S);
/*
* Switch banks because we've updated them in mdlUpdate and we're no
* longer in a minor time step.
*/
if (ssIsMajorTimeStep(S)) {
int_T *banksUpdated = ssGetIWork(S) + 1;
if (*banksUpdated) {
*activeBank = !(*activeBank);
*banksUpdated = 0;
/*
* Need to tell the solvers that the derivatives are no
* longer valid.
*/
ssSetSolverNeedsReset(S);
}
}
num = ssGetRWork(S) + (*activeBank) * (2*nCoeffs);
/*
* The continuous system is evaluated using a controllable state space
* representation of the transfer function. This implies that the
* output of the system is equal to:
*
* y(t) = Cx(t) + Du(t)
* = [ b1 b2 ... bn]x(t) + b0u(t)
*
* where b0, b1, b2, ... are the coefficients of the numerator
* polynomial:
*
* B(s) = b0 s^n + b1 s^n-1 + b2 s^n-2 + ... + bn-1 s + bn
*/
*y = *num++ * (*uPtrs[0]);
9-115
9 Implementing Block Features for C/C++ S-Functions
} /* end mdlOutputs */
Although this example has no discrete states, the method still implements the mdlUpdate
function to update the transfer function coefficients at every major time step. Because
this method is optional, a #define statement precedes it. The method uses
ssGetInputPortRealSignalPtrs to obtain a pointer to the input signal. The input
signal's values become the new transfer function coefficients, which the S-function stores
in the bank of the inactive RWork vector. When the mdlOutputs function is later called at
this major time step, it updates the active bank to be this updated bank of coefficients.
#define MDL_UPDATE
/* Function: mdlUpdate ========================================================
* Abstract:
* Every time through the simulation loop, update the
* transfer function coefficients. Here we update the oldest bank.
*/
static void mdlUpdate(SimStruct *S, int_T tid)
{
if (ssIsSampleHit(S, 1, tid)) {
int_T i;
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
int_T uIdx = 1;/*1st coeff is after signal input*/
int_T nContStates = ssGetNumContStates(S);
int_T nCoeffs = nContStates + 1;
int_T bankToUpdate = !ssGetIWork(S)[0];
real_T *num = ssGetRWork(S)+bankToUpdate*2*nCoeffs;
real_T *den = num + nCoeffs;
real_T den0;
int_T allZero;
/*
* Get the first denominator coefficient. It will be used
* for normalizing the numerator and denominator coefficients.
*
* If all inputs are zero, we probably could have unconnected
* inputs, so use the parameter as the first denominator coefficient.
*/
den0 = *uPtrs[uIdx+nCoeffs];
if (den0 == 0.0) {
den0 = mxGetPr(DEN(S))[0];
}
/*
* Grab the numerator.
*/
allZero = 1;
9-116
C MEX S-Function Examples
/*
* Grab the denominator.
*/
allZero = 1;
for (i = 0; (i < nCoeffs) && allZero; i++) {
allZero &= *uPtrs[uIdx+i] == 0.0;
}
den0 = denParam[0];
for (i = 0; i < denParamLen; i++) {
*den++ = *denParam++ / den0;
}
} else {
for (i = 0; i < nCoeffs; i++) {
*den++ = *uPtrs[uIdx++] / den0;
}
}
/*
* Normalize if this transfer function has direct feedthrough.
*/
num = ssGetRWork(S) + bankToUpdate*2*nCoeffs;
den = num + nCoeffs;
for (i = 1; i < nCoeffs; i++) {
num[i] -= den[i]*num[0];
}
/*
* Indicate oldest bank has been updated.
9-117
9 Implementing Block Features for C/C++ S-Functions
*/
ssGetIWork(S)[1] = 1;
}
} /* end mdlUpdate */
The mdlDerivatives function calculates the continuous state derivatives. The function
uses the coefficients from the active bank to solve a controllable state-space
representation of the transfer function.
#define MDL_DERIVATIVES
/* Function: mdlDerivatives ===================================================
* Abstract:
* The derivatives for this block are computed by using a controllable
* state-space representation of the transfer function.
*/
static void mdlDerivatives(SimStruct *S)
{
int_T i;
int_T nContStates = ssGetNumContStates(S);
real_T *x = ssGetContStates(S);
real_T *dx = ssGetdX(S);
int_T nCoeffs = nContStates + 1;
int_T activeBank = ssGetIWork(S)[0];
const real_T *num = ssGetRWork(S) + activeBank*(2*nCoeffs);
const real_T *den = num + nCoeffs;
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
/*
* The continuous system is evaluated using a controllable state-space
* representation of the transfer function. This implies that the
* next continuous states are computed using:
*
* dx = Ax(t) + Bu(t)
* = [-a1 -a2 ... -an] [x1(t)] + [u(t)]
* [ 1 0 ... 0] [x2(t)] + [0]
* [ 0 1 ... 0] [x3(t)] + [0]
* [ . . ... .] . + .
* [ . . ... .] . + .
* [ . . ... .] . + .
* [ 0 0 ... 1 0] [xn(t)] + [0]
*
* where a1, a2, ... are the coefficients of the numerator polynomial:
*
* A(s) = s^n + a1 s^n-1 + a2 s^n-2 + ... + an-1 s + an
*/
dx[0] = -den[1] * x[0] + *uPtrs[0];
for (i = 1; i < nContStates; i++) {
dx[i] = x[i-1];
dx[0] -= den[i+1] * x[i];
}
} /* end mdlDerivatives */
9-118
See Also
The required mdlTerminate function performs any actions, such as freeing memory,
necessary at the end of the simulation. In this example, the function is empty.
/* Function: mdlTerminate =====================================================
* Abstract:
* Called when the simulation is terminated.
* For this block, there are no end of simulation tasks.
*/
static void mdlTerminate(SimStruct *S)
{
UNUSED_ARG(S); /* unused input argument */
} /* end mdlTerminate */
The required S-function trailer includes the files necessary for simulation or code
generation, as follows.
#ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX file? */
#include "simulink.c" /* MEX file interface mechanism */
#else
#include "cg_sfun.h" /* Code generation registration function */
#endif
Note The mdlTerminate function uses the UNUSED_ARG macro to indicate that an input
argument the callback requires is not used. This optional macro is defined in
simstruc_types.h. If used, you must call this macro once for each input argument that
a callback does not use.
See Also
mdlInitializeSizes | mdlTerminate | mdlUpdate
More About
• “Create a Basic C MEX S-Function” on page 4-2
• “S-Function Callback Methods” on page 1-17
• “SimStruct Macros and Functions Listed by Usage” on page 12-3
9-119
10
In this section...
“Using Level-2 MATLAB S-Function Dialog Parameters” on page 10-2
“Tunable Parameters” on page 10-3
You can pass parameters to an S-function at the start of and during the simulation, using
the S-function parameters field of the Block Parameters dialog box. Such parameters
are called dialog box parameters to distinguish them from run-time parameters created
by the S-function to facilitate code generation (see “Create and Update S-Function Run-
Time Parameters” on page 9-7).
Note You cannot use the Model Explorer, the S-function Block Parameters dialog box, or
a mask to tune the parameters of a source S-function, i.e., an S-function that has outputs
but no inputs, while a simulation is running. For more information, see “Tune and
Experiment with Block Parameter Values”.
1 Determine the order in which the parameters are to be specified in the block's dialog
box.
2 In the setup method, set the run-time object's NumDialogPrms property to indicate
to the engine how many parameters the S-function accepts, for example:
block.NumDialogPrms = 2;
3 Access the dialog box parameters in the S-function using the run-time object's
DialogPrm method. The dialog parameter's Data property stores its current value,
for example:
param1 = block.DialogPrm(1).Data;
param2 = block.DialogPrm(2).Data;
10-2
See Also
When running a simulation, you must specify the parameters in the Parameters field of
the Level-2 MATLAB S-Function Block Parameters dialog in the same order that you
defined them in step 1.
Tunable Parameters
Dialog parameters can be either tunable or nontunable. A tunable parameter is a
parameter that a user can change while the simulation is running.
block.DialogPrmsTunable = {'Tunable','Nontunable','Nontunable'};
See Also
Level-2 MATLAB S-Function | MATLAB Function | S-Function | S-Function Builder
More About
• “S-Function Concepts” on page 1-8
• “Use S-Functions in Models” on page 1-4
10-3
10 Implement Block Features for MATLAB S-Functions
• Computed parameters
Often the output of a block is a function of the values of several dialog parameters. For
example, suppose a block has two parameters, the volume and density of some object,
and the output of the block is a function of the input signal and the mass of the object.
In this case, the mass can be viewed as a third internal parameter computed from the
two external parameters, volume and density. An S-function can create a run-time
parameter corresponding to the computed weight, thereby eliminating the need to
provide special case handling for weight in the output computation. See “Creating
Run-Time Parameters from Multiple S-Function Parameters” on page 9-10 for more
information.
• Data type conversions
Often a block needs to change the data type of a dialog parameter to facilitate internal
processing. For example, suppose that the output of the block is a function of the input
and a dialog parameter and the input and dialog parameter are of different data types.
In this case, the S-function can create a run-time parameter that has the same value
as the dialog parameter but has the data type of the input signal, and use the run-time
parameter in the computation of the output.
• Code generation
During code generation, the Simulink Coder product writes all run-time parameters
automatically to the model.rtw file, eliminating the need for the S-function to
perform this task via an mdlRTW method.
10-4
See Also
block.AutoRegRuntimePrms;
block.AutoUpdateRuntimePrms;
See Also
Level-2 MATLAB S-Function | MATLAB Function | S-Function | S-Function Builder
More About
• “S-Function Concepts” on page 1-8
• “Use S-Functions in Models” on page 1-4
10-5
10 Implement Block Features for MATLAB S-Functions
Then, for each input port, the setup method can specify
To individually specify that an input port's dimensions are dynamically sized, assign a
value of -1 to the dimensions. In this case, you can implement the
SetInputPortDimensions method to set the dimensions during signal propagation.
A port has direct feedthrough if the input is used in the Outputs functions to
calculate either the outputs or the next sample time hit. The direct feedthrough flag
for each input port can be set to either 1=yes or 0=no. Setting the direct feedthrough
flag to 0 tells the Simulink engine that u is not used to calculate the outputs or next
sample time hit. Violating this leads to unpredictable results.
• The data type of the input port, using block.InputPort(n).DatatypeID. See the
explanation for the “DatatypeID” property in the Simulink.BlockData data object
reference page for a list of valid data type IDs.
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 -1. In this case, you can implement the
SetInputPortDataType method to set the data type during signal propagation.
• The numeric type of the input port, if the port accepts complex-valued signals, using
block.InputPort(n).Complexity.
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 'Inherited'. In this case, you can
implement the SetInputPortComplexSignal method to set the numeric type
during signal propagation.
10-6
Create Input and Output Ports
For an example that configures a Level-2 MATLAB S-function with multiple input and
output ports, open the model sldemo_msfcn_lms and inspect the S-function
adapt_lms.m.
block.SetPreCompOutPortInfoToDynamic;
Configure the output ports exactly as you configure input ports. See “Creating Input Ports
for Level-2 MATLAB S-Functions” on page 10-6 for a list of properties you can specify for
each output port, substituting OutputPort for InputPort in each call to the run-time
object.
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
10-7
10 Implement Block Features for MATLAB S-Functions
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.
See Also
Level-2 MATLAB S-Function | MATLAB Function | S-Function | S-Function Builder
More About
• “S-Function Concepts” on page 1-8
• “Use S-Functions in Models” on page 1-4
10-8
Inherit Custom Data Types
The Constant block's Output data type field contains the value MyDouble, which is a
Simulink.AliasType defined in the MATLAB workspace with the following line of code:
MyDouble = Simulink.AliasType('double');
The input and output ports of the Level-2 MATLAB S-function msfcn_inheritdt.m
inherit their data types. When the Simulink engine performs data type propagation, it
assigns the data type MyDouble to these ports.
You can define a fixed-point data type within a Level-2 MATLAB S-function, using one of
the following three methods:
Note If the registered data type is not one of the Simulink built-in data types, you must
have a Fixed-Point Designer™ license.
If you have Fixed-Point Designer, inspect the example models and S-functions provided
with the software for examples using the macros for defining fixed-point data types.
10-9
10 Implement Block Features for MATLAB S-Functions
See Also
Level-2 MATLAB S-Function | MATLAB Function | S-Function | S-Function Builder
More About
• “S-Function Concepts” on page 1-8
• “Use S-Functions in Models” on page 1-4
• “Write Level-2 MATLAB S-Functions” on page 3-2
10-10
Specify S-Function Sample Times
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:
• In the block-based method, selecting 0.5 and 0.25 directs the block to execute inputs
and outputs at 0.25 second increments.
• In the port-based method, setting the input port to 0.5 and the output port to 0.25
causes the block to process inputs at 2 Hz and outputs at 4 Hz.
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.
10-11
10 Implement Block Features for MATLAB S-Functions
to specify the sample time. Use a value of [-1 0] to indicate an inherited sample time.
See “Specify Sample Time” in Using Simulink for a complete list of valid sample times.
• Specify the sample and offset times for each S-function port in the setup method. For
example:
The setup method must not specify a sample time for the block when using port-
based sample times.
• Provide SetInputPortSampleTime and SetOutputPortSampleTime methods,
even if your S-function does not inherit its port-based sample times.
In a Level-2 MATLAB S-function, use a value of [-1 0] for the SampleTime property of
each port to specify that the port inherits its sample time.
If your S-function uses port-based sample times, it can set a sample time of Inf on any of
its ports. A port-based sample time of Inf means that the signal entering or leaving the
port stays constant.
In a Level-2 MATLAB S-function, use this code to specify a sample time of Inf for a port:
10-12
Specify S-Function Sample Times
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 all of these conditions are
true:
• The output port has a constant value. It uses or inherits a sample time of Inf.
• The S-function is a multi-rate S-function.
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” on page 9-32.
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. Note that higher-rate tasks always run before slower-rate tasks. Thus, the
input task always runs before the output task, ensuring that valid data is always present
at the output port.
10-13
10 Implement Block Features for MATLAB S-Functions
See Also
Level-2 MATLAB S-Function | MATLAB Function | S-Function | S-Function Builder
More About
• “S-Function Concepts” on page 1-8
• “Use S-Functions in Models” on page 1-4
10-14
S-Function Compliance with SimState
In order for a Level-2 MATLAB S-function to work with the SimState feature, you must
specify the simStateCompliance of the block using the method,
block.simStateCompliance = setting
Setting Result
'UnknownSimState' This default setting instructs Simulink to use the DefaultSimState to
save and restore the SimState and issues a warning.
'DefaultSimState' This setting instructs Simulink to treat the S-function like a built-in block
when saving and restoring the SimState.
'HasNoSimState' This setting informs Simulink that the S-function does not have any
simulation state. With this setting, no state information is saved for the
block. This setting is primarily useful for "sink" blocks (i.e., blocks with no
output ports) that use PWorks or DWorks to store handles to files or figure
windows.
Note This setting is not allowed if the S-function registers any discrete or
continuous states or zero crossing signals.
'CustomSimState' This setting informs Simulink that the S-function has custom
GetSimState and SetSimState methods.
10-15
10 Implement Block Features for MATLAB S-Functions
Setting Result
'DisallowSimState This setting informs Simulink that the S-function does not allow saving or
' restoring its simulation state. Simulink reports an error if you save and
restore the SimState of the model that contains this S-function.
For an S-function with custom methods ('CustomSimState'), you can use the following
statements to respectively get and set the SimState:
See Also
Level-2 MATLAB S-Function | MATLAB Function | S-Function | S-Function Builder
More About
• “S-Function Concepts” on page 1-8
• “Use S-Functions in Models” on page 1-4
10-16
Use DWork Vectors in S-Functions
You can create an S-function that is reentrant by using DWork vectors that the engine
manages for each particular instance of the S-function.
Note DWork vectors are the most generalized and versatile type of work vector and the
following sections focus on their use. The Simulink product provides additional
elementary types of work vectors that support floating-point, integer, pointer, and mode
data. You can find a discussion of these work vectors in “Elementary Work Vectors” on
page 8-20.
DWork vectors provide the most flexibility for setting data types, names, etc., of the data
in the simulation and during code generation. The following list describes all the
properties that you can set on a DWork vector:
• Data type
10-17
10 Implement Block Features for MATLAB S-Functions
• Size
• Numeric type, either real or complex
• Name
• Usage type (see “Types of DWork Vectors” on page 8-5)
• Simulink Coder identifier
• Simulink Coder storage class
• Simulink Coder C type qualifier
See “How to Use DWork Vectors” on page 8-7 for instructions on how to set these
properties. The three Simulink Coder properties pertain only to code generation and have
no effect during simulation.
The following steps show how to initialize and use DWork vectors in Level-2 MATLAB S-
functions. These steps use the S-function msfcn_unit_delay.m.
function PostPropagationSetup(block)
%% Setup Dwork
block.NumDworks = 1;
block.Dwork(1).Name = 'x0';
block.Dwork(1).Dimensions = 1;
block.Dwork(1).DatatypeID = 0;
block.Dwork(1).Complexity = 'Real';
block.Dwork(1).UsedAsDiscState = true;
10-18
Use DWork Vectors in S-Functions
%% Initialize Dwork
block.Dwork(1).Data = block.DialogPrm(1).Data;
3 In the Outputs, Update, etc. methods, use or update the DWork vector values, as
needed. For example, the following Outputs method sets the S-function output equal
to the value stored in the DWork vector. The Update method then changes the DWork
vector value to the current value of the first S-function input port.
%% Outputs callback method
function Outputs(block)
block.OutputPort(1).Data = block.Dwork(1).Data;
block.Dwork(1).Data = block.InputPort(1).Data;
Note Level-2 MATLAB S-functions do not support MATLAB sparse matrices. Therefore,
you cannot assign a sparse matrix to the value of a DWork vector. For example, the
following line of code produces an error
block.Dwork(1).Data = speye(10);
10-19
10 Implement Block Features for MATLAB S-Functions
The Outputs method uses the handle stored in the second DWork vector to update the
pulse width of the Pulse Generator block.
function Outputs(block)
The Update method then modifies the first DWork vector with the next value for the pulse
width, specified by the input signal to the S-Function block.
function Update(block)
%endfunction
10-20
See Also
See Also
Level-2 MATLAB S-Function | MATLAB Function | S-Function | S-Function Builder
More About
• “S-Function Concepts” on page 1-8
• “Use S-Functions in Models” on page 1-4
10-21
10 Implement Block Features for MATLAB S-Functions
To specify a Level-2 MATLAB S-function as a sim viewing device, call the run-time object's
SetSimViewingDevice method in the S-function setup callback method.
See Also
Level-2 MATLAB S-Function | MATLAB Function | S-Function | S-Function Builder
More About
• “S-Function Concepts” on page 1-8
• “Use S-Functions in Models” on page 1-4
10-22
11
Every user-written S-function must implement a set of methods, called callback methods
or simply callbacks, that the Simulink engine invokes when simulating a model that
contains the S-function. Some callback methods are optional. The engine invokes an
optional callback only if the S-function defines the callback. This topic describes the
purpose and syntax of all callback methods that an S-function can implement. In each
case, the documentation for a callback method indicates whether it is required or
optional. For a list of required callback methods, see “Callback Methods That an S-
Function Must Implement” on page 4-42.
11 S-Function Callback Methods — Alphabetical List
CheckParameters
Check the validity of a MATLAB S-Function's parameters
Required
No
Language
MATLAB
Syntax
CheckParameters(s)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing a Level-2 MATLAB
S-Function block.
Description
Verifies new parameter settings whenever parameters change or are reevaluated during a
simulation.
When a simulation is running, changes to S-function parameters can occur at any time
during the simulation loop, that is, either at the start of a simulation step or during a
simulation step. When the change occurs during a simulation step, the Simulink engine
calls this routine twice to handle the parameter change. The first call during the
simulation step is used to verify that the parameters are correct. After verifying the new
11-2
CheckParameters
parameters, the simulation continues using the original parameter values until the next
simulation step, at which time the new parameter values are used. Redundant calls are
needed to maintain simulation consistency.
Note You cannot access the work, state, input, output, and other vectors in this routine.
Use this routine only to validate the parameters. Additional processing of the parameters
should be done in ProcessParameters.
Example
In a Level-2 MATLAB S-function, the setup method registers the CheckParameters
method as follows
s.RegBlockMethod('CheckParameters', @CheckParam);
The local function CheckParam then verifies the S-function parameters. In this example,
the function checks that the second parameter, an upper limit value, is greater than the
first S-function parameter, a lower limit value.
function CheckParam(s)
See Also
ProcessParameters, Simulink.RunTimeBlock, Simulink.MSFcnRunTimeBlock,
mdlCheckParameters
Introduced in R2012b
11-3
11 S-Function Callback Methods — Alphabetical List
Derivatives
Compute a MATLAB S-Function's derivatives
Required
No
Language
MATLAB
Syntax
Derivatives(s)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block
Description
The Simulink engine invokes this optional method at each time step to compute the
derivatives of the S-function's continuous states. This method should store the derivatives
in the S-function's state derivatives vector. In a Level-2 MATLAB S-function, use the run-
time object's Derivatives method.
Each time the Derivatives routine is called, it must explicitly set the values of all
derivatives. The derivative vector does not maintain the values from the last call to this
routine. The memory allocated to the derivative vector changes during execution.
11-4
Derivatives
Example
For a Level-2 MATLAB S-function example, see msfcn_limintm.m.
See Also
Simulink.RunTimeBlock, Simulink.MSFcnRunTimeBlock, mdlDerivatives
Introduced in R2012b
11-5
11 S-Function Callback Methods — Alphabetical List
Disable
Respond to disabling of an enabled system containing this MATLAB S-Function block
Required
No
Language
MATLAB
Syntax
Disable(s)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
Description
The Simulink engine invokes this optional method if this block resides in an enabled
subsystem and the enabled subsystem changes from an enabled to a disabled state at the
current time step. Your S-function can use this method to perform any actions required by
the disabling of the containing subsystem.
11-6
Disable
See Also
Enable, Simulink.MSFcnRunTimeBlock, mdlDisable
Introduced in R2012b
11-7
11 S-Function Callback Methods — Alphabetical List
Enable
Respond to enabling of an enabled system containing this MATLAB S-Function block
Required
No
Language
MATLAB
Syntax
Enable(s)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
Description
The Simulink engine invokes this optional method if this block resides in an enabled
subsystem and the enabled subsystem changes from a disabled to an enabled state at the
current time step. Your S-function can use this method to perform any actions required by
the enabling of the containing subsystem.
11-8
Enable
See Also
Disable, Simulink.MSFcnRunTimeBlock, mdlEnable
11-9
11 S-Function Callback Methods — Alphabetical List
GetOperatingPoint
Return MATLAB S-function's simulation operating point as a MATLAB data structure
Required
No
Language
MATLAB
Syntax
GetOperatingPoint(s)
Arguments
s
Instance of the Simulink.MSFcnRunTimeBlock class representing the Level-2
MATLAB S-Function block.
Description
The Simulink engine invokes this custom method to get the simulation snapshot
(operating point) of the model containing S. A call to this method should occur after
Start and before Terminate to ensure that all of the S-function data structures (states,
DWork vectors, and outputs) are available.
11-10
GetOperatingPoint
See Also
“Custom Code and Hand Coded Blocks using the S-function API”| SetOperatingPoint |
Simulink.MSFcnRunTimeBlock | mdlGetOpeartingPoint |
ssSetOperatingPointCompliance
Introduced in R2019a
11-11
11 S-Function Callback Methods — Alphabetical List
GetSimState
(Not recommended) Return the MATLAB S-function simulation state as a valid MATLAB
data structure, such as a matrix structure or a cell array.
Required
No
Language
MATLAB
Syntax
GetSimState(s)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
Description
The Simulink engine invokes this custom method to get the simulation state (SimState) of
the model containing S. A call to this method should occur after Start and before
11-12
GetSimState
Terminate to ensure that all of the S-function data structures (e.g., states, DWork
vectors, and outputs) are available.
See Also
SetSimState, Simulink.MSFcnRunTimeBlock, mdlGetSimState
Introduced in R2015b
11-13
11 S-Function Callback Methods — Alphabetical List
InitializeConditions
Initialize the state vectors of this MATLAB S-function
Required
No
Language
MATLAB
Syntax
InitializeConditions(s)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
Description
The Simulink engine invokes this optional method at the beginning of a simulation. It
should initialize the continuous and discrete states, if any, of this S-Function block. In a
Level-2 MATLAB S-function, use the ContStates or Dwork run-time object methods to
access the continuous and discrete states. This method can also perform any other
initialization activities that this S-function requires.
11-14
InitializeConditions
Note If you have Simulink Coder, and you need to ensure that the initialization code in
the InitializeConditions function is run only once, then move this initialization code
into the Start method. MathWorks recommends this code change as a best practice.
If this S-function resides in an enabled subsystem configured to reset states, the Simulink
engine also calls this method when the enabled subsystem restarts execution.
For example, in a C MEX S-function, initializes an IWork vector with one element in the
mdlInitializeSizes method.
ssSetNumIWork(S, 1);
The IWork vector holds a flag indicating if initial values have been specified. Initialize the
flag's value in the mdlInitializeCondition method.
ssSetIWorkValue(S, 0, 1);
}
Check the value of the IWork vector flag in the mdlOutputs method, to determine if
initial values need to be set. Since the engine has calculated input values at this point in
the simulation, the mdlOutputs method can use them to initialize internal values.
11-15
11 S-Function Callback Methods — Alphabetical List
For a Level-2 MATLAB S-function, use a DWork vector instead of an IWork vector in the
previous example.
Example
This example initializes both a continuous and discrete state to 1.0. Level-2 MATLAB S-
functions store discrete states in their DWork vectors.
function InitializeConditions(s)
s.ContStates.Data(1) = 1;
s.Dwork(1).Data = 1;
% endfunction
See Also
Start, Outputs, Simulink.RunTimeBlock, Simulink.MSFcnRunTimeBlock,
mdlInitializeConditions
Introduced in R2012b
11-16
mdlCheckParameters
mdlCheckParameters
Check the validity of a C MEX S-function's parameters
Required
No
Languages
C, C++
Syntax
#define MDL_CHECK_PARAMETERS
Arguments
S
SimStruct representing an S-Function block.
Description
Verifies new parameter settings whenever parameters change or are reevaluated during a
simulation. If you have Simulink Coder, for C MEX S-functions, this method is only valid
for simulation, and must be enclosed in a #if defined(MATLAB_MEX_FILE) statement
to be compatible with code generation targets that support noninlined S-functions.
When a simulation is running, changes to S-function parameters can occur at any time
during the simulation loop, that is, either at the start of a simulation step or during a
simulation step. When the change occurs during a simulation step, the Simulink engine
11-17
11 S-Function Callback Methods — Alphabetical List
calls this routine twice to handle the parameter change. The first call during the
simulation step is used to verify that the parameters are correct. After verifying the new
parameters, the simulation continues using the original parameter values until the next
simulation step, at which time the new parameter values are used. Redundant calls are
needed to maintain simulation consistency.
Note You cannot access the work, state, input, output, and other vectors in this routine.
Use this routine only to validate the parameters. Additional processing of the parameters
should be done in mdlProcessParameters.
Example
This example checks the first S-function parameter to verify that it is a real nonnegative
scalar.
In addition to the preceding routine, you must add a call to this method from
mdlInitializeSizes to check parameters during initialization, because
mdlCheckParameters is only called while the simulation is running. To do this, after
11-18
mdlCheckParameters
See Also
mdlProcessParameters, ssGetSFcnParamsCount, CheckParameters
11-19
11 S-Function Callback Methods — Alphabetical List
mdlDerivatives
Compute the C MEX S-function's derivatives
Required
No
Languages
C, C++
Syntax
#define MDL_DERIVATIVES
Arguments
S
SimStruct representing an S-Function block.
Description
The Simulink engine invokes this optional method at each time step to compute the
derivatives of the S-function's continuous states. This method should store the derivatives
in the S-function's state derivatives vector. In a C MEX S-function, use ssGetdX to get a
pointer to the derivatives vector.
Each time the mdlDerivatives routine is called, it must explicitly set the values of all
derivatives. The derivative vector does not maintain the values from the last call to this
routine. The memory allocated to the derivative vector changes during execution.
11-20
mdlDerivatives
Note If you have Simulink Coder, when generating code for a noninlined C MEX S-
function that contains this method, make sure the method is not wrapped in a #if
defined(MATLAB_MEX_FILE) statement. For example:
#define MDL_DERIVATIVES
#if defined(MDL_DERIVATIVES) && defined(MATLAB_MEX_FILE)
static void mdlDerivatives(SimStruct *S)
{
/* Add mdlDerivatives code here *
}
#endif
The define statement makes the mdlDerivatives method available only to a MATLAB
MEX file. If the S-function is not inlined, the Simulink Coder product cannot use this
method, resulting in link or run-time errors.
Example
For a C MEX S-function example, see csfunc.c.
See Also
ssGetdx, Derivatives
11-21
11 S-Function Callback Methods — Alphabetical List
mdlDisable
Respond to disabling of an enabled system containing this block
Required
No
Languages
C, C++
Syntax
#define MDL_DISABLE
Arguments
S
SimStruct representing an S-Function block.
Description
The Simulink engine invokes this optional method if this block resides in an enabled
subsystem and the enabled subsystem changes from an enabled to a disabled state at the
current time step. Your S-function can use this method to perform any actions required by
the disabling of the containing subsystem.
11-22
mdlDisable
See Also
mdlEnable, Disable
11-23
11 S-Function Callback Methods — Alphabetical List
mdlEnable
Respond to enabling of a enabled system containing this block
Required
No
Languages
C, C++
Syntax
#define MDL_ENABLE
Arguments
S
SimStruct representing an S-Function block.
Description
The Simulink engine invokes this optional method if this block resides in an enabled
subsystem and the enabled subsystem changes from a disabled to an enabled state at the
current time step. Your S-function can use this method to perform any actions required by
the enabling of the containing subsystem.
11-24
mdlEnable
See Also
mdlDisable, Enable
11-25
11 S-Function Callback Methods — Alphabetical List
mdlGetOperatingPoint
Return C MEX S-function's simulation operating point as a MATLAB data structure
Required
No
Languages
C, C++
Syntax
mxArray* mdlGetOperatingPoint(SimStruct* S)
Arguments
S
SimStruct representing an S-Function block.
Description
The Simulink engine invokes this custom method to get the simulation operating point
(snapshot) of the model containing S. A call to this method occurs after mdlStart and
before mdlTerminate to ensure that all of the S-function data structures (states, DWork
vectors, and outputs) are available. mdlGetOperatingPoint is required when the
operating point compliance is custom,
11-26
mdlGetOperatingPoint
Example
/* Function: mdlGetOperatingPoint
* Abstract:
* Package the RunTimeData structure as a MATLAB structure
* and return it.
*/
static mxArray* mdlGetOperatingPoint(SimStruct* S)
{
RunTimeData_T* rtd =
(RunTimeData_T*)ssGetPWorkValue(S, 0);
const char* fieldNames[] = {"Count"};
See Also
“Custom Code and Hand Coded Blocks using the S-function API”|
mdlSetOperatingPoint| GetOperatingPoint
Introduced in R2019a
11-27
11 S-Function Callback Methods — Alphabetical List
mdlGetSimState
(Not recommended) Return the C MEX S-function simulation state as a valid MATLAB
data structure, such as a matrix structure or a cell array.
Required
No
Languages
C, C++
Syntax
#define MDL_SIM_STATE
mxArray* mdlGetSimState(SimStruct* S)
Arguments
S
SimStruct representing an S-Function block.
Description
The Simulink engine invokes this custom method to get the simulation state (SimState) of
the model containing S. A call to this method should occur after mdlStart and before
11-28
mdlGetSimState
mdlTerminate to ensure that all of the S-function data structures (e.g., states, DWork
vectors, and outputs) are available.
Example
/* Function: mdlGetSimState
* Abstract:
* Package the RunTimeData structure as a MATLAB structure
* and return it.
*/
static mxArray* mdlGetSimState(SimStruct* S)
{
RunTimeData_T* rtd =
(RunTimeData_T*)ssGetPWorkValue(S, 0);
const char* fieldNames[] = {"Count"};
See Also
mdlSetSimState, GetSimState
Introduced in R2009a
11-29
11 S-Function Callback Methods — Alphabetical List
mdlGetTimeOfNextVarHit
Specify time of the next sample time hit
Required
No
Languages
C, C++
Syntax
#define MDL_GET_TIME_OF_NEXT_VAR_HIT
Arguments
S
SimStruct representing an S-Function block.
Description
The Simulink engine invokes this optional method at a major time step when the variable
sample time registered by this S-function has a hit. This method is used by the Simulink
engine to determine the time of the next sample hit for variable sample time. The S-
function should set this next sample hit using ssSetTNext macro in this method. The
time of the next hit must be greater than the current simulation time as returned by
ssGetT. The S-function must implement mdlGetTimeOfNextVarHit if it operates at a
variable sample time.
11-30
mdlGetTimeOfNextVarHit
For Level-2 MATLAB S-functions, use a sample time of -2 to specify a variable sample
time. The S-function's output method should then update the NextTimeHit property of
the instance of the Simulink.MSFcnRunTimeBlock class representing the S-Function
block to set the time of the next sample time hit. See /msfcn_vs.m for an example.
For Level-1 MATLAB S-functions, a flag of 4 is passed to the S-function when the next
sample time hit needs to be calculated.
Note The time of the next hit can be a function of the input signals.
Example
static void mdlGetTimeOfNextVarHit(SimStruct *S)
{
time_T offset = getOffset();
time_T timeOfNextHit = ssGetT(S) + offset;
ssSetTNext(S, timeOfNextHit);
}
See Also
mdlInitializeSampleTimes, ssGetT, ssSetTNext
11-31
11 S-Function Callback Methods — Alphabetical List
mdlInitializeConditions
Initialize the state vectors of this C MEX S-function
Required
No
Languages
C, C++
Syntax
#define MDL_INITIALIZE_CONDITIONS
Arguments
S
SimStruct representing an S-Function block.
Description
The Simulink engine invokes this optional method at the beginning of a simulation. It
should initialize the continuous and discrete states, if any, of this S-Function block. In a C
MEX S-function, use ssGetContStates and/or ssGetDiscStates to access the states.
This method can also perform any other initialization activities that this S-function
requires.
Note If you have Simulink Coder and you need to ensure that the initialization code in
the mdlInitializeConditions function is run only once, then move this initialization
11-32
mdlInitializeConditions
code into the mdlStart method. MathWorks recommends this code change as a best
practice.
If this S-function resides in an enabled subsystem configured to reset states, the Simulink
engine also calls this method when the enabled subsystem restarts execution. C MEX S-
functions can use the ssIsFirstInitCond macro to determine whether the time at
which mdlInitializeCondition is called is equal to the simulation start time.
Note If you have Simulink Coder, when generating code for a noninlined C MEX S-
function that contains this method, make sure the method is not wrapped in a #if
defined(MATLAB_MEX_FILE) statement. For example:
#define MDL_INITIALIZE_CONDITIONS
#if defined(MDL_INITIALIZE_CONDITIONS) && defined(MATLAB_MEX_FILE)
static void mdlInitializeConditions(SimStruct *S)
{
/* Add mdlInitializeConditions code here */
}
#endif
For example, in a C MEX S-function, initializes an IWork vector with one element in the
mdlInitializeSizes method.
ssSetNumIWork(S, 1);
The IWork vector holds a flag indicating if initial values have been specified. Initialize the
flag's value in the mdlInitializeCondition method.
11-33
11 S-Function Callback Methods — Alphabetical List
ssSetIWorkValue(S, 0, 1);
}
Check the value of the IWork vector flag in the mdlOutputs method, to determine if
initial values need to be set. Since the engine has calculated input values at this point in
the simulation, the mdlOutputs method can use them to initialize internal values.
static void mdlOutputs(SimStruct *S, int_T tid)
{
// Initialize values if the IWork vector flag is true. //
if (ssGetIWorkValue(S, 0) == 1) {
// Enter initialization code here //
}
For a Level-2 MATLAB S-function, use a DWork vector instead of an IWork vector in the
previous example.
Example
This example initializes both a continuous and discrete state to 1.0.
#define MDL_INITIALIZE_CONDITIONS /*Change to #undef to remove */
/*function*/
#if defined(MDL_INITIALIZE_CONDITIONS)
11-34
mdlInitializeConditions
}
#endif /* MDL_INITIALIZE_CONDITIONS */
For another example that initializes only the continuous states, see resetint.c.
See Also
mdlStart, mdlOutputs, ssIsFirstInitCond, ssGetContStates,
ssGetDiscStates, ssGetTStart, ssGetT, InitializeConditions
11-35
11 S-Function Callback Methods — Alphabetical List
mdlInitializeSampleTimes
Specify the sample rates at which this C MEX S-function operates
Required
Yes
Languages
C, C++
Syntax
#define MDL_INITIALIZE_SAMPLE_TIMES
Arguments
S
SimStruct representing an S-Function block.
Description
This method should specify the sample time and offset time for each sample rate at which
this S-function operates via the following paired macros
where sampleTimeIndex runs from 0 to one less than the number of sample times
specified in mdlInitializeSizes via ssSetNumSampleTimes.
11-36
mdlInitializeSampleTimes
If the S-function operates at one or more sample rates, this method can specify any of the
following sample time and offset values for a given sample time:
• [CONTINUOUS_SAMPLE_TIME, 0.0]
• [CONTINUOUS_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET]
• [discrete_sample_period, offset]
• [VARIABLE_SAMPLE_TIME, 0.0]
If the S-function operates at one rate, this method can alternatively set the sample time to
one of the following sample/offset time pairs.
• [INHERITED_SAMPLE_TIME, 0.0]
• [INHERITED_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET]
If the number of sample times is 0, the Simulink engine assumes that the S-function
inherits its sample time from the block to which it is connected, i.e., that the sample time
is
[INHERITED_SAMPLE_TIME, 0.0]
• A continuous function that changes during minor integration steps should set the
sample time to
[CONTINUOUS_SAMPLE_TIME, 0.0]
• A continuous function that does not change during minor integration steps should set
the sample time to
[CONTINUOUS_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET]
• A discrete function that changes at a specified rate should set the sample time to
[discrete_sample_period, offset]
where
11-37
11 S-Function Callback Methods — Alphabetical List
and
[VARIABLE_SAMPLE_TIME, 0.0]
The Simulink engine invokes the mdlGetTimeOfNextVarHit function to get the time
of the next sample hit for the variable-step discrete task.
[INHERITED_SAMPLE_TIME, 0.0]
• Use ssSetOptions to set the SS_OPTION_DISALLOW_CONSTANT_SAMPLE_TIME
simulation option in mdlInitializeSizes
• Verify that it was assigned a discrete or triggered sample time in
mdlSetWorkWidths:
if (ssGetSampleTime(S, 0) == CONTINUOUS_SAMPLE_TIME) {
ssSetErrorStatus(S,
"This block cannot be assigned a continuous sample
time");
}
After propagating sample times throughout the block diagram, the engine assigns the
sample time
[INHERITED_SAMPLE_TIME, INHERITED_SAMPLE_TIME]
If this function has no intrinsic sample time, it should set its sample time to inherited
according to the following guidelines:
• A function that changes as its input changes, even during minor integration steps,
should set its sample time to
[INHERITED_SAMPLE_TIME, 0.0]
11-38
mdlInitializeSampleTimes
A function that changes as its input changes, but doesn't change during minor
integration steps (i.e., is held during minor steps) should set its sample time to
[INHERITED_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET]
if (ssIsContinuousTask(S,tid)) {
}
If the function wants to determine whether the third (discrete) task has a hit, it can use
the following code fragment.
if (ssIsSampleHit(S,2,tid) {
}
Note If you have Simulink Coder, when generating code for a noninlined S-function that
contains this method, make sure the method is not wrapped in a #if
defined(MATLAB_MEX_FILE) statement. For example:
#if defined(MATLAB_MEX_FILE)
static void mdlInitializeSampleTimes(SimStruct *S)
{
/* Add mdlInitializeSampleTimes code here *
}
#endif
See Also
mdlSetInputPortSampleTime, mdlSetOutputPortSampleTime
11-39
11 S-Function Callback Methods — Alphabetical List
11-40
mdlInitializeSizes
mdlInitializeSizes
Specify the number of inputs, outputs, states, parameters, and other characteristics of the
C MEX S-function
Required
Yes
Languages
C, C++
Syntax
#define MDL_INITIAL_SIZES
Arguments
S
SimStruct representing an S-Function block.
Description
This is the first S-function callback methods that the Simulink engine calls. This method
performs the following tasks:
11-41
11 S-Function Callback Methods — Alphabetical List
as not tunable, the engine issues an error during simulation (or when in external mode
when using the Simulink Coder product) if an attempt is made to change the
parameter.
• Specify the number of states that this function has, using ssSetNumContStates and
ssSetNumDiscStates.
• Configure the block's input ports, including:
• Specify the number of input ports that this S-function has, using
ssSetNumInputPorts.
• Specify the dimensions of the input ports.
A port has direct feedthrough if the input is used in either the mdlOutputs or
mdlGetTimeOfNextVarHit function. 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.
• Configure the block's output ports, including:
• Specify the number of output ports that the block has, using
ssSetNumOutputPorts.
• Specify the dimensions of the output ports.
If your S-function outputs are discrete (for example, the outputs only take specific
values such as 0, 1, and 2), specify SS_OPTION_DISCRETE_VALUED_OUTPUT.
• Set the number of sample times (i.e., sample rates) at which the block operates.
See “Specify S-Function Sample Times” on page 9-26 for a complete discussion of
sample time issues.
11-42
mdlInitializeSizes
For multirate S-functions, the suggested approach to setting sample times is via the
port-based sample times method. When you create a multirate S-function, you must
take care to verify that, when slower tasks are preempted, your S-function correctly
manages data so as to avoid race conditions. When port-based sample times are
specified, the block cannot inherit a sample time of Inf at any port.
• Set the size of the block's work vectors, using ssSetNumRWork, ssSetNumIWork,
ssSetNumPWork, ssSetNumModes, ssSetNumNonsampledZCs.
• Set the simulation options that this block implements, using ssSetOptions.
All options have the form SS_OPTION_<name>. See “Configure C/C++ S-Function
Features” for information on each option. Use a bitwise OR operator to set multiple
options, as in
Note If you have Simulink Coder, when generating code for a noninlined S-function that
contains this method, make sure the method is not wrapped in a #if
defined(MATLAB_MEX_FILE) statement. For example:
#if defined(MATLAB_MEX_FILE)
static void mdlInitializeSizes(SimStruct *S)
{
/* Add mdlInitializeSizes code here *
}
#endif
11-43
11 S-Function Callback Methods — Alphabetical List
• 0 or positive number -- Sets lengths (or widths) to the specified values. The default is
0.
Example
static void mdlInitializeSizes(SimStruct *S)
{
int_T nInputPorts = 1; /* number of input ports */
int_T nOutputPorts = 1; /* number of output ports */
int_T needsInput = 1; /* direct feedthrough */
int_T inputPortIdx = 0;
int_T outputPortIdx = 0;
if (ssGetErrorStatus(S) != NULL)
return;
}
ssSetNumContStates( S, 0);
ssSetNumDiscStates( S, 0);
/*
* Configure the input ports. First set the number of input
11-44
mdlInitializeSizes
* ports.
*/
if (!ssSetNumInputPorts(S, nInputPorts)) return;
/*
* Set input port dimensions for each input port index
* starting at 0.
*/
if(!ssSetInputPortDimensionInfo(S, inputPortIdx,
DYNAMIC_DIMENSION)) return;
/*
* Set direct feedthrough flag (1=yes, 0=no).
*/
ssSetInputPortDirectFeedThrough(S, inputPortIdx, needsInput);
/*
* Configure the output ports. First set the number of
* output ports.
*/
if (!ssSetNumOutputPorts(S, nOutputPorts)) return;
/*
* Set output port dimensions for each output port index
* starting at 0.
*/
if(!ssSetOutputPortDimensionInfo(S,outputPortIdx,
DYNAMIC_DIMENSION)) return;
/*
* Set the number of sample times. */
ssSetNumSampleTimes(S, 1);
/*
* Set size of the work vectors.
*/
ssSetNumRWork(S, 0); /* real vector */
ssSetNumIWork(S, 0); /* integer vector */
ssSetNumPWork(S, 0); /* pointer vector */
ssSetNumModes(S, 0); /* mode vector */
ssSetNumNonsampledZCs(S, 0); /* zero crossings */
ssSetOptions(S, 0);
} /* end mdlInitializeSizes */
11-45
11 S-Function Callback Methods — Alphabetical List
See Also
setup, mdlInitializeSampleTimes
11-46
mdlOutputs
mdlOutputs
Compute the signals that this block emits
Required
Yes
Languages
C, C++
Syntax
#define MDL_OUTPUTS
Arguments
S
SimStruct representing an S-Function block.
tid
Task ID.
Description
The Simulink engine invokes this required method at each simulation time step. The
method should compute the S-function's outputs at the current time step and store the
results in the S-function's output signal arrays.
The tid (task ID) argument specifies the task running when the mdlOutputs routine is
invoked. You can use this argument in the mdlOutputs routine of a multirate S-Function
11-47
11 S-Function Callback Methods — Alphabetical List
Use the UNUSED_ARG macro if the S-function does not contain task-specific blocks of code
to indicate that the tid input argument is required but not used in the body of the
callback. To do this, insert the line
UNUSED_ARG(tid)
Note If you have Simulink Coder, when generating code for a noninlined S-function that
contains this method, make sure the method is not wrapped in a #if
defined(MATLAB_MEX_FILE) statement. For example:
#if defined(MATLAB_MEX_FILE)
static void mdlOutputs(SimStruct *S)
{
/* Add mdlOutputs code here *
}
#endif
The define statement makes the mdlOutputs method available only to a MATLAB MEX
file. If the S-function is not inlined, the Simulink Coder product cannot use this method,
resulting in link or run-time errors.
Example
For an example of an mdlOutputs routine that works with multiple input and output
ports, see sfun_multiport.c.
See Also
ssGetOutputPortComplexSignal, ssGetOutputPortRealSignal,
ssGetOutputPortSignal, Outputs
11-48
mdlProcessParameters
mdlProcessParameters
Process the C MEX S-function's parameters
Required
No
Languages
C, C++
Syntax
#define MDL_PROCESS_PARAMETERS
Arguments
S
SimStruct representing an S-Function block.
Description
This is an optional routine that the Simulink engine calls after mdlCheckParameters
changes and verifies parameters. The processing is done at the top of the simulation loop
when it is safe to process the changed parameters. This function is only valid for
simulation. C MEX S-functions must enclose the method in a #if
defined(MATLAB_MEX_FILE) statement.
11-49
11 S-Function Callback Methods — Alphabetical List
used with the Simulink Coder product. Therefore, if you use this routine in an S-function
designed for use with the Simulink Coder product, you must write your S-function so that
it doesn't rely on this routine. To do this, you must inline your S-function by using the
Target Language Compiler. For information on inlining S-functions, see “Inlining S-
Functions” (Simulink Coder).
Example
This example processes a character vector parameter that mdlCheckParameters has
verified to be of the form '+++' (where there could be any number of '+' or '-'
characters).
}
#endif /* MDL_PROCESS_PARAMETERS */
#define MDL_START
#if defined(MDL_START)
11-50
mdlProcessParameters
See Also
mdlCheckParameters, ProcessParameters
11-51
11 S-Function Callback Methods — Alphabetical List
mdlProjection
Perturb the solver's solution of a system's states to better satisfy time-invariant solution
relationships
Required
No
Languages
C, C++
Syntax
#define MDL_PROJECTION
Arguments
S
SimStruct representing an S-Function block.
Description
This method is intended for use with S-functions that model dynamic systems whose
states satisfy time-invariant relationships, such as those resulting from mass or energy
conservation or other physical laws. The Simulink engine invokes this method at each
time step after the model's solver has computed the S-function's states for that time step.
Typically, slight errors in the numerical solution of the states cause the solutions to fail to
satisfy solution invariants exactly. Your mdlProjection method can compensate for the
11-52
mdlProjection
errors by perturbing the states so that they more closely approximate solution invariants
at the current time step. As a result, the numerical solution adheres more closely to the
ideal solution as the simulation progresses, producing a more accurate overall simulation
of the system modeled by your S-function.
Your mdlProjection method's perturbations of system states must fall within the
solution error tolerances specified by the model in which the S-function is embedded.
Otherwise, the perturbations may invalidate the solver's solution. It is up to your
mdlProjection method to ensure that the perturbations meet the error tolerances
specified by the model. See “Perturbing a System's States Using a Solution Invariant” on
page 11-53 for a simple method for perturbing a system's states. The following articles
describe more sophisticated perturbation methods that your mdlProjection method can
use.
Example
−1
Xn ≅ Xn* + JnT ( Jn JnT ) Rn
where
• Xn is the system's ideal state vector at the solver's current time step
• Xn* is the approximate state vector computed by the solver at the current time step
11-53
11 S-Function Callback Methods — Alphabetical List
• Jn is the Jacobian of the invariant function evaluated at the point in state space
specified by the approximate state vector at the current time step:
∂g
Jn = (X *, t )
∂X n n
• tn is the time at the current time step
• Rn is the residual (difference) between the invariant function evaluated at Xn and Xn* at
the current time step:
Note The value of g(Xn, tn) is the same at each time step and is known by definition.
Given a continuous, differentiable invariant function for the system that your S-function
models, this formula allows your S-function's mdlProjection method to compute a
perturbation
−1
JnT ( Jn JnT ) Rn
of the solver's numerical solution, Xn*, that more closely matches the ideal solution, Xn,
keeping the S-function's solution from drifting from the ideal solution as the simulation
progresses.
MATLAB Example
This example illustrates how the perturbation method outlined in the previous section can
keep a model's numerical solution from drifting from the ideal solution as a simulation
progresses. Consider the following model,mdlProjectionEx1:
The PredPrey block references an S-function, predprey_noproj.m, that uses the Lotka-
Volterra equations
11-54
mdlProjection
ẋ = ax(1 − y)
ẏ = − cy(1 − x)
to model predator-prey population dynamics, where x(t) is the population density of the
predators and y(t) is the population density of prey. The ideal solution to the predator-
prey ODEs satisfies the time-invariant function
x−cecx y−aeay = d
The Invariant Residual block in this model computes the residual between the invariant
function evaluated along the system's ideal trajectory through state space and its
simulated trajectory:
cxn −a ayn
Rn = d − xn−ce yn e
where xnand ynare the values computed by the model's solver for the predator and prey
population densities, respectively, at the current time step. Ideally, the residual should be
zero throughout simulation of the model, but simulating the model reveals that the
residual actually strays considerably from zero:
11-55
11 S-Function Callback Methods — Alphabetical List
This model is the same as the previous model, except that its S-function, predprey.m,
includes a mdlProjection method that uses the perturbation approach outlined in
“Perturbing a System's States Using a Solution Invariant” on page 11-53 to compensate
11-56
mdlProjection
for numerical drift. As a result, the numerical solution more closely tracks the ideal
solution as the simulation progresses as demonstrated by the residual signal, which
remains near or at zero throughout the simulation:
See Also
Projection
Introduced in R2006b
11-57
11 S-Function Callback Methods — Alphabetical List
mdlRTW
Generate code generation data for a C MEX S-function
Required
No
Languages
C, C++
Syntax
#define MDL_RTW
Arguments
S
SimStruct representing an S-Function block.
Description
This function is called when the Simulink Coder product is generating the model.rtw
file. In C MEX S-functions, you can call the following functions that add fields to the
model.rtw file:
• ssWriteRTWParameters
• ssWriteRTWParamSettings
11-58
mdlRTW
• ssWriteRTWWorkVect
• ssWriteRTWStr
• ssWriteRTWStrParam
• ssWriteRTWScalarParam
• ssWriteRTWStrVectParam
• ssWriteRTWVectParam
• ssWriteRTW2dMatParam
• ssWriteRTWMxVectParam
• ssWriteRTWMx2dMatParam
Example
See the S-function sfun_multiport.c in the Simulink model
sfcndemo_sfun_multiport for an example.
See Also
ssSetErrorStatus, WriteRTW
11-59
11 S-Function Callback Methods — Alphabetical List
mdlSetDefaultPortComplexSignals
Set the numeric types (real, complex, or inherited) of ports whose numeric types cannot
be determined from block connectivity
Required
No
Languages
C, C++
Syntax
#define MDL_SET_DEFAULT_PORT_COMPLEX_SIGNALS
Arguments
S
SimStruct representing an S-Function block.
Description
The Simulink engine invokes this method if the block has ports whose numeric types
cannot be determined from connectivity. (This usually happens when the block is
unconnected or is part of a feedback loop.) This method must set the numeric types of all
ports whose numeric types are not set. This method is only valid for simulation, and must
be enclosed in a #if defined(MATLAB_MEX_FILE) statement.
11-60
mdlSetDefaultPortComplexSignals
If the block does not implement this method and at least one port is known to be complex,
the engine sets the unknown ports to COMPLEX_YES; otherwise, it sets the unknown ports
to COMPLEX_NO.
See Also
ssSetOutputPortComplexSignal, ssSetInputPortComplexSignal
11-61
11 S-Function Callback Methods — Alphabetical List
mdlSetDefaultPortDataTypes
Set the data types of ports whose data types cannot be determined from block
connectivity
Required
No
Languages
C, C++
Syntax
#define MDL_SET_DEFAULT_PORT_DATA_TYPES
Arguments
S
SimStruct representing an S-Function block.
Description
The Simulink engine invokes this method if the block has ports whose data types cannot
be determined from block connectivity. (This usually happens when the block is
unconnected or is part of a feedback loop.) This method must set the data types of all
ports whose data types are not set. This method is only valid for simulation, and must be
enclosed in a #if defined(MATLAB_MEX_FILE) statement.
11-62
mdlSetDefaultPortDataTypes
If the block does not implement this method and the engine cannot determine the data
types of any of its ports, the engine sets the data types of all the ports to double. If the
block does not implement this method and the engine cannot determine the data types of
some, but not all, of its ports, the engine sets the unknown ports to the data type of the
port whose data type has the largest size.
if (ssGetInputPortDataType(S, 1) == DYNAMICALLY_TYPED) {
ssSetInputPortDataType(S, 1, SS_UINT8 );
}
See Also
ssSetOutputPortDataType, ssSetInputPortDataType
11-63
11 S-Function Callback Methods — Alphabetical List
mdlSetDefaultPortDimensionInfo
Set the default dimensions of the signals accepted or emitted by a C MEX S-function's
ports
Required
No
Languages
C, C++
Syntax
#define MDL_SET_DEFAULT_PORT_DIMENSION_INFO
Arguments
S
SimStruct representing an S-Function block.
Description
The Simulink engine calls this method during signal dimension propagation when a model
does not supply enough information to determine the dimensionality of signals that can
enter or leave the block represented by S. This method should set the dimensions of any
input and output ports that are dynamically sized to default values. This method is only
valid for simulation, and must be enclosed in a #if defined(MATLAB_MEX_FILE)
statement.
11-64
mdlSetDefaultPortDimensionInfo
If the S-function does not implement this method, the engine tries to find a set of
dimensions that will satisfy the dimension propagation rules implemented using
mdlSetInputPortDimensionInfo and mdlSetOutputPortDimensionInfo. This
process might not be able to produce a valid set of dimensions for S-functions with
special dimension requirements.
if (ssGetOutputPortWidth(S, 0) == DYNAMICALLY_SIZED) {
ssSetOutputPortMatrixDimensions(S, 0, 1, 1 );
}
Example
See sfun_matadd.c for an example of how to use this function.
See Also
ssSetErrorStatus, ssSetOutputPortMatrixDimensions
11-65
11 S-Function Callback Methods — Alphabetical List
mdlSetInputPortComplexSignal
Set the numeric types (real, complex, or inherited) of the signals accepted by an input
port
Required
No
Languages
C, C++
Syntax
#define MDL_SET_INPUT_PORT_COMPLEX_SIGNAL
Arguments
S
SimStruct representing an S-Function block.
port
Index of a port.
csig
Numeric type of signal, either COMPLEX_NO (real) or COMPLEX_YES (complex).
Description
The Simulink engine calls this routine to set the input port numeric type for inputs that
have this attribute set to COMPLEX_INHERITED. The input csig is the proposed numeric
11-66
mdlSetInputPortComplexSignal
type for this input port. This method is only valid for simulation. C MEX S-functions must
enclosed this method in a #if defined(MATLAB_MEX_FILE) statement.
The S-function must check whether the proposed numeric type is a valid type for the
specified port. If it is valid, a C MEX S-function sets the numeric type of the specified
input port using ssSetInputPortComplexSignal. Otherwise, it reports an error using
ssSetErrorStatus.
The S-function can also set the numeric types of other input and output ports with
inherited numeric types. The engine reports an error if the S-function changes the
numeric type of a port whose numeric type is known.
If the S-function does not implement this routine, the engine assumes that the S-function
accepts a real or complex signal and sets the input port numeric type to the specified
value.
The engine calls this method until all input ports with inherited numeric types have their
numeric types specified.
Example
See sdotproduct.c for an example of how to use this function.
See Also
ssSetErrorStatus, ssSetInputPortComplexSignal,
SetInputPortComplexSignal
11-67
11 S-Function Callback Methods — Alphabetical List
mdlSetInputPortDataType
Set the data types of the signals accepted by an input port
Required
No
Languages
C, C++
Syntax
#define MDL_SET_INPUT_PORT_DATA_TYPE
Arguments
S
SimStruct representing an S-Function block.
port
Index of a port.
id
Data type ID.
Description
The Simulink engine calls this routine to set the data type of port when port has an
inherited data type. The data type id is the proposed data type for this port. Data type
11-68
mdlSetInputPortDataType
IDs for the built-in data types can be found in simstruc_types.h. This method is only
valid for simulation. C MEX S-functions must enclose this method in a #if
defined(MATLAB_MEX_FILE) statement.
The S-function must check whether the specified data type is a valid data type for the
specified port. If it is a valid data type, a C MEX S-functions sets the data type of the
input port using ssSetInputPortDataType. Otherwise, it reports an error using
ssSetErrorStatus.
The S-function can also set the data types of other input and output ports if they are
unknown. The engine reports an error if the S-function changes the data type of a port
whose data type has been set.
If the block does not implement this routine, the engine assumes that the block accepts
any data type and sets the input port data type to the specified value.
The engine calls this method until all input ports with inherited data types have their data
types specified.
See Also
ssSetErrorStatus, ssSetInputPortDataType, SetInputPortDataType
11-69
11 S-Function Callback Methods — Alphabetical List
mdlSetInputPortDimensionInfo
Set the dimensions of the signals accepted by an input port
Required
No
Languages
C, C++
Syntax
#define MDL_SET_INPUT_PORT_DIMENSION_INFO
Arguments
S
SimStruct representing an S-Function block.
port
Index of a port.
dimsInfo
Structure that specifies the signal dimensions supported by the port.
11-70
mdlSetInputPortDimensionInfo
Description
The Simulink engine calls this method during dimension propagation with candidate
dimensions dimsInfo for port. In C MEX S-functions, if the proposed dimensions are
acceptable, the method sets the actual port dimensions, using
ssSetInputPortDimensionInfo. If they are unacceptable, the method generates an
error via ssSetErrorStatus.
This method is only valid for simulation. A C MEX S-function must enclose the method in
a #if defined(MATLAB_MEX_FILE) statement.
Note This method can set the dimensions of any other input or output port whose
dimensions derive from the dimensions of port.
By default, the engine calls this method only if it can fully determine the dimensionality of
port from the port to which it is connected. For C MEX S-functions, if the engine cannot
completely determine the dimensionality from port connectivity, it invokes
mdlSetDefaultPortDimensionInfo. If an S-function can fully determine the port
dimensionality from partial information, set the option
SS_OPTION_ALLOW_PARTIAL_DIMENSIONS_CALL in mdlInitializeSizes, using
ssSetOptions. If this option is set, the engine invokes
mdlSetInputPortDimensionInfo even if it can only partially determine the
dimensionality of the input port from connectivity.
The engine calls this method until all input ports with inherited dimensions have their
dimensions specified.
Example
See sfun_matadd.c for an example of how to use this function.
See Also
ssSetErrorStatus, mdlSetOutputPortDimensionInfo,
SetInputPortDimensions
11-71
11 S-Function Callback Methods — Alphabetical List
11-72
mdlSetInputPortDimensionsModeFcn
mdlSetInputPortDimensionsModeFcn
Propagate the dimensions mode
Required
No
Languages
C, C++
Syntax
void mdlSetInputPortDimensionsModeFcn(SimStruct *S, int_T portIdx,
DimensionsMode_T dimsMode)
Arguments
S
SimStruct representing an S-Function block.
portIdx
Index of a port.
dimsMode
Current dimensions mode. Possible values are INHERIT_DIMS_MODE,
FIXED_DIMS_MODE, and VARIABLE_DIMS_MODE
Description
The Simulink engine calls this optional method to enable this S-function to set the
dimensions mode of the input port indexed by portIdx.
11-73
11 S-Function Callback Methods — Alphabetical List
C Example
See sfun_varsize_holdStatesUntilReset.c for an example of how to use this
function.
See Also
mdlSetInputPortDimensionInfo, SetInputPortDimensionsMode
Introduced in R2009b
11-74
mdlSetInputPortSampleTime
mdlSetInputPortSampleTime
Set the sample time of an input port that inherits its sample time from the port to which it
is connected
Required
No
Languages
C, C++
Syntax
#define MDL_SET_INPUT_PORT_SAMPLE_TIME
Arguments
S
SimStruct representing an S-Function block.
port
Index of a port.
sampleTime
Inherited sample time for port.
offsetTime
Inherited offset time for port.
11-75
11 S-Function Callback Methods — Alphabetical List
Description
The Simulink engine invokes this method with the sample time that port inherits from
the port to which it is connected.
For C MEX S-functions, if the inherited sample time is acceptable, this method sets the
sample time of port to the inherited time, using ssSetInputPortSampleTime and
ssSetInputPortOffsetTime. If the sample time is unacceptable, this method
generates an error via ssSetErrorStatus. Note that any other input or output ports
whose sample times are implicitly defined by virtue of knowing the sample time of the
given port can also have their sample times set via calls to
ssSetInputPortSampleTime or ssSetOutputPortSampleTime. This method is only
valid for simulation, and must be enclosed in a #if defined(MATLAB_MEX_FILE)
statement.
The engine calls this method until all input ports with inherited sample times are
specified.
When inherited port-based sample times are specified, the sample time is guaranteed to
be one of the following where 0.0 < period < inf and 0.0 <= offset < period.
Constant, triggered, and variable-step sample times are not propagated to S-functions
with port-based sample times.
Generally mdlSetInputPortSampleTime is called once per port with the input port
sample time. However, there can be cases where this function is called more than once.
This happens when the simulation engine is converting continuous sample times to
continuous but fixed in minor steps sample times. When this occurs, the original values of
the sample times specified in mdlInitializeSizes are restored before this method is
called again.
The final sample time specified at the port can be different from (but equivalent to) the
sample time specified by this method. This occurs when
• The model uses a fixed-step solver and the port has a continuous but fixed in minor
step sample time. In this case, the Simulink engine converts the sample time to the
fundamental sample time for the model.
11-76
mdlSetInputPortSampleTime
• The engine adjusts the sample time to be as numerically sound as possible. For
example, the engine converts [0.2499999999999, 0] to [0.25, 0].
See Also
ssSetInputPortSampleTime, ssSetOutputPortSampleTime,
mdlInitializeSampleTimes, SetInputPortSampleTime
11-77
11 S-Function Callback Methods — Alphabetical List
mdlSetInputPortWidth
Set the width of an input port that accepts 1-D (vector) signals
Required
No
Languages
C, C++
Syntax
#define MDL_SET_INPUT_PORT_WIDTH
Arguments
S
SimStruct representing an S-Function block.
port
Index of a port.
width
Width of signal.
Description
This method is called with the candidate width for a dynamically sized port. If the
proposed width is acceptable, the method should set the actual port width using
11-78
mdlSetInputPortWidth
The Simulink engine invokes this method until all dynamically sized input ports are
configured.
See Also
ssSetInputPortWidth, ssSetOutputPortWidth, ssSetErrorStatus
11-79
11 S-Function Callback Methods — Alphabetical List
mdlSetOperatingPoint
Restore operating point of C MEX S-function
Required
No
Languages
C, C++
Syntax
#define MDL_OPERATING_POINT
Arguments
S
SimStruct representing an S-Function block.
const mxArray* in
Operating point of S-Function created by mdlGetOperatingPoint.
Description
The Simulink engine invokes this custom method at the beginning of a simulation of the
model containing S (SimStruct representing an S-Function block).
mdlSetOperatingPoint sets the initial simulation state of the S-function to the
operating point of the model.
11-80
mdlSetOperatingPoint
Example
/* Function: mdlSetOperatingPoint
* Abstract:
* Unpack the MATLAB structure passed and restore it to
* the RunTimeData structure
*/
static void mdlOperatingPoint(SimStruct* S,
const mxArray* simSnap)
{
RunTimeData_T* rtd =
(RunTimeData_T*)ssGetPWorkValue(S, 0);
See Also
“Custom Code and Hand Coded Blocks using the S-function API”|
mdlInitializeConditions|mdlGetOpeartingPoint |SetOperatingPoint
Introduced in R2019a
11-81
11 S-Function Callback Methods — Alphabetical List
mdlSetOutputPortComplexSignal
Set the numeric types (real, complex, or inherited) of the signals accepted by an output
port
Required
No
Languages
C, C++
Syntax
#define MDL_SET_OUTPUT_PORT_COMPLEX_SIGNAL
Arguments
S
SimStruct representing an S-Function block.
port
Index of a port.
csig
Numeric type of signal, either COMPLEX_NO (real) or COMPLEX_YES (complex).
Description
The Simulink engine calls this routine to set the output port numeric type for outputs that
have this attribute set to COMPLEX_INHERITED. The input argument csig is the
11-82
mdlSetOutputPortComplexSignal
proposed numeric type for this output port. The S-function must check whether the
specified numeric type is a valid type for the specified port.
If it is valid, C MEX S-functions set the numeric type of the specified output port using
ssSetOutputPortComplexSignal. Otherwise, the S-function reports an error, using
ssSetErrorStatus. This method is only valid for simulation. C MEX S-functions must
enclose the method in a #if defined(MATLAB_MEX_FILE) statement.
The S-function can also set the numeric types of other input and output ports with
unknown numeric types. The engine reports an error if the S-function changes the
numeric type of a port whose numeric type is known.
If the S-function does not implement this routine, the engine assumes that the S-function
accepts a real or complex signal and sets the output port numeric type to the specified
value.
The engine calls this method until all output ports with inherited numeric types have their
numeric types specified.
Example
See sdotproduct.c for an example of how to use this function.
See Also
ssSetOutputPortComplexSignal, ssSetErrorStatus,
SetOutputPortComplexSignal
11-83
11 S-Function Callback Methods — Alphabetical List
mdlSetOutputPortDataType
Set the data type of the signals emitted by an output port
Required
No
Languages
C, C++
Syntax
#define MDL_SET_OUTPUT_PORT_DATA_TYPE
Arguments
S
SimStruct representing an S-Function block.
port
Index of an output port.
id
Data type ID.
Description
The Simulink engine calls this routine to set the data type of port when port has an
inherited data type. The data type ID id is the proposed data type for this port. Data type
11-84
mdlSetOutputPortDataType
IDs for the built-in data types can be found in simstruc_types.h. The S-function must
check whether the specified data type is a valid data type for the specified port.
If it is a valid data type, a C MEX S-function sets the data type of port using
ssSetOutputPortDataType. Otherwise, the S-function reports an error, using
ssSetErrorStatus. This method is only valid for simulation. C MEX S-functions must
enclose the method in a #if defined(MATLAB_MEX_FILE) statement.
The S-function can also set the data types of other input and output ports if their data
types have not been set. The engine reports an error if the S-function changes the data
type of a port whose data type has been set.
If the block does not implement this method, the engine assumes that the block supports
any data type and sets the output port data type to the specified value.
The engine calls this method until all output ports with inherited data types have their
data types specified.
See Also
ssSetOutputPortDataType, ssSetErrorStatus, SetOutputPortDataType
11-85
11 S-Function Callback Methods — Alphabetical List
mdlSetOutputPortDimensionInfo
Set the dimensions of the signals accepted by an output port
Required
No
Languages
C, C++
Syntax
#define MDL_SET_OUTPUT_PORT_DIMENSION_INFO
Arguments
S
SimStruct representing an S-Function block.
port
Index of a port.
dimsInfo
Structure that specifies the signal dimensions supported by port.
11-86
mdlSetOutputPortDimensionInfo
Description
The Simulink engine calls this method with candidate dimensions dimsInfo for port. In
C MEX S-functions, if the proposed dimensions are acceptable, the method sets the actual
port dimensions, using ssSetOutputPortDimensionInfo. If they are unacceptable, the
method generates an error via ssSetErrorStatus. This method is only valid for
simulation. C MEX S-functions must enclose the method in a #if
defined(MATLAB_MEX_FILE) statement.
Note This method can set the dimensions of any other input or output port whose
dimensions derive from the dimensions of port.
By default, the engine calls this method only if it can fully determine the dimensionality of
port from the port to which it is connected. In C MEX S-functions, if the engine cannot
completely determine the dimensionality from port connectivity, it invokes
mdlSetDefaultPortDimensionInfo. If an S-function can fully determine the port
dimensionality from partial information, set the option
SS_OPTION_ALLOW_PARTIAL_DIMENSIONS_CALL in mdlInitializeSizes, using
ssSetOptions. If this option is set, the engine invokes
mdlSetOutputPortDimensionInfo even if it can only partially determine the
dimensionality of the output port from connectivity.
The engine calls this method until all output ports with inherited dimensions have their
dimensions specified.
Example
See sfun_matadd.c for an example of how to use this function.
See Also
ssSetErrorStatus, ssSetOutputPortDimensionInfo,
SetOutputPortDimensions
11-87
11 S-Function Callback Methods — Alphabetical List
mdlSetOutputPortSampleTime
Set the sample time of an output port that inherits its sample time from the port to which
it is connected
Required
No
Languages
C, C++
Syntax
#define MDL_SET_OUTPUT_PORT_SAMPLE_TIME
Arguments
S
SimStruct representing an S-Function block.
port
Index of a port.
sampleTime
Inherited sample time for port.
offsetTime
Inherited offset time for port.
11-88
mdlSetOutputPortSampleTime
Description
The Simulink engine calls this method with the sample time that port inherits from the
port to which it is connected.
For C MEX S-functions, if the inherited sample time is acceptable, this method should set
the sample time of port to the inherited sample time and offset time, using
ssSetOutputPortSampleTime and ssSetOutputPortOffsetTime. If the sample time
is unacceptable, this method generates an error via ssSetErrorStatus. This method is
only valid for simulation, and must be enclosed in a #if defined(MATLAB_MEX_FILE)
statement.
This method can set the sample time of any other input or output port whose sample time
derives from the sample time of port, using ssSetInputPortSampleTime or
ssSetOutputPortSampleTime in C MEX S-functions.
Normally, sample times are propagated forward; however, if sources feeding this block
have inherited sample times, the engine might choose to back-propagate known sample
times to this block. When back-propagating sample times, this method is called in
succession for all inherited output port signals.
See Also
ssSetErrorStatus, ssSetInputPortSampleTime, ssSetOutputPortSampleTime,
mdlSetInputPortSampleTime, SetOutputPortSampleTime
11-89
11 S-Function Callback Methods — Alphabetical List
mdlSetOutputPortWidth
Set the width of an output port that outputs 1-D (vector) signals
Required
No
Languages
C, C++
Syntax
#define MDL_SET_OUTPUT_PORT_WIDTH
Arguments
S
SimStruct representing an S-Function block.
port
Index of a port.
width
Width of signal.
Description
This method is called with the candidate width for a dynamically sized port. If the
proposed width is acceptable, the method should go ahead and set the actual port width,
11-90
mdlSetOutputPortWidth
See Also
ssSetInputPortWidth, ssSetOutputPortWidth, ssSetErrorStatus
11-91
11 S-Function Callback Methods — Alphabetical List
mdlSetSimState
(Not recommended) Set the simulation state of the C MEX S-function by restoring the
SimState.
Required
No
Languages
C, C++
Syntax
#define MDL_SIM_STATE
Arguments
S
SimStruct representing an S-Function block.
const mxArray* in
Any valid MATLAB data.
11-92
mdlSetSimState
Description
The Simulink engine invokes this custom method at the beginning of a simulation of the
model containing S . Simulink sets the initial simulation state of the S-function to the
SimState of the model.
Example
/* Function: mdlSetSimState
* Abstract:
* Unpack the MATLAB structure passed and restore it to
* the RunTimeData structure
*/
static void mdlSetSimState(SimStruct* S,
const mxArray* simSnap)
{
RunTimeData_T* rtd =
(RunTimeData_T*)ssGetPWorkValue(S, 0);
See Also
mdlInitializeConditions, mdlGetSimState, SetSimState
11-93
11 S-Function Callback Methods — Alphabetical List
Introduced in R2009a
11-94
mdlSetWorkWidths
mdlSetWorkWidths
Specify the sizes of the work vectors and create the run-time parameters required by this
C MEX S-function
Required
No
Languages
C, C++
Syntax
#define MDL_SET_WORK_WIDTHS
Arguments
S
SimStruct representing an S-Function block.
Description
The Simulink engine calls this optional method to enable this S-function to set the sizes of
state and work vectors that it needs to store global data and to create run-time
parameters (see “Create and Update S-Function Run-Time Parameters” on page 9-7). The
engine invokes this method after it has determined the input port width, output port
width, and sample times of the S-function. This allows the S-function to size the state and
work vectors based on the number and sizes of inputs and outputs and/or the number of
11-95
11 S-Function Callback Methods — Alphabetical List
sample times. This method specifies the state and work vector sizes via the macros
ssGetNumContStates, ssSetNumDiscStates, ssSetNumRWork, ssSetNumIWork,
ssSetNumPWork, ssSetNumModes, and ssSetNumNonsampledZCs.
A C-MEX S-function needs to implement this method only if it does not know the sizes of
all the work vectors it requires when the engine invokes the function's
mdlInitializeSizes method. If this S-function implements mdlSetWorkWidths, it
should initialize the sizes of any work vectors that it needs to DYNAMICALLY_SIZED in
mdlInitializeSizes, even for those whose exact size it knows at that point. The S-
function should then specify the actual size in mdlSetWorkWidths. This method is only
valid for simulation, and must be enclosed in a #if defined(MATLAB_MEX_FILE)
statement.
Example
For a full example of a C MEX S-function using DWork vectors, see the file
sfun_rtwdwork.c used in the Simulink model sfcndemo_sfun_rtwdwork.
See Also
mdlInitializeSizes, PostPropagationSetup
11-96
mdlSimStatusChange
mdlSimStatusChange
Respond to a pause or resumption of the simulation of the model that contains this C MEX
S-function
Required
No
Languages
C, C++
Syntax
#define MDL_SIM_STATUS_CHANGE
Arguments
S
SimStruct representing an S-Function block.
simStatus
Status of the simulation, either SIM_PAUSE or SIM_CONTINUE.
Description
The Simulink engine calls this routine when a simulation of the model containing S
pauses or resumes. This method is only valid for simulation. C MEX S-functions must
enclose the method in a #if defined(MATLAB_MEX_FILE) statement.
11-97
11 S-Function Callback Methods — Alphabetical List
Example
#if defined(MATLAB_MEX_FILE)
#define MDL_SIM_STATUS_CHANGE
static void mdlSimStatusChange(SimStruct *S,
ssSimStatusChangeType simStatus) {
if (simStatus == SIM_PAUSE) {
ssPrintf("Pause has been called! \n");
} else if (simStatus == SIM_CONTINUE) {
ssPrintf("Continue has been called! \n");
}
}
#endif
See Also
SimStatusChange
11-98
mdlStart
mdlStart
Initialize the state vectors of this C MEX S-function
Required
No
Languages
C, C++
Syntax
#define MDL_START
Arguments
S
SimStruct representing an S-Function block.
Description
The Simulink engine invokes this optional method at the beginning of a simulation. The
method performs initialization activities that this S-function requires only once, such as
setting up user data or initializing states.
This method is called at the start of every successive simulation in Fast Restart mode, and
it performs tasks that are required for every run. In contrast,
mdlSetupRuntimeResources performs tasks once in Fast Restart mode and the results
of those tasks done are reused by successive simulations.
11-99
11 S-Function Callback Methods — Alphabetical List
If your S-function resides in an enabled subsystem and needs to reinitialize its states
every whenever the subsystem is enabled, use mdlInitializeConditions to initialize
the state values, instead of mdlStart.
Example
See sfun_directlook.c for an example of how to use this function.
See Also
mdlInitializeConditions, ssGetContStates, ssGetDiscStates, Start
11-100
mdlSetupRuntimeResources
mdlSetupRuntimeResources
Perform any actions required once at the start of the simulation
Required
No
Languages
C, C++
Syntax
#define MDL_SETUP_RUNTIME_RESOURCES
Arguments
S
SimStruct representing an S-Function block.
Description
The Simulink engine invokes this optional method at the end of compilation. The method
performs setup activities that this S-function requires only once irrespective of the
number of simulations that follow (such as in a Fast Restart scenario).
11-101
11 S-Function Callback Methods — Alphabetical List
See Also
mdlInitializeConditions, ssGetContStates, ssGetDiscStates, Start, “Get
Started with Fast Restart”
Introduced in R2016b
11-102
mdlTerminate
mdlTerminate
Perform any actions required at termination of the simulation
Required
Yes
Languages
C, C++
Syntax
void mdlTerminate(SimStruct *S)
Arguments
S
SimStruct representing an S-Function block.
Description
This method performs any actions, such as freeing of memory, that must be performed
when the simulation is terminated or when an S-Function block is destroyed (e.g., when it
is deleted from a model). This method is called at the end of every simulation in Fast
Restart mode.
11-103
11 S-Function Callback Methods — Alphabetical List
In C MEX S-functions, use the UNUSED_ARG macro if the mdlTerminate function does
not perform any actions that require the SimStruct S to indicate that the S input
argument is required, but not used in the body of the callback. To do this, insert the line
UNUSED_ARG(S)
Note If you have Simulink Coder, when generating code for a noninlined C MEX S-
function that contains this method, make sure the method is not wrapped in a #if
defined(MATLAB_MEX_FILE) statement. For example:
#if defined(MATLAB_MEX_FILE)
static void mdlTerminate(SimStruct *S)
{
/* Add mdlTerminate code here *
}
#endif
The define statement makes the mdlTerminate method available only to a MATLAB
MEX file. If the S-function is not inlined, Simulink Coder cannot use this method,
resulting in link or run-time errors.
Example
Suppose your S-function allocates blocks of memory in mdlStart and saves pointers to
the blocks in a PWork vector. The following code fragment would free this memory.
{
int i;
for (i = 0; i<ssGetNumPWork(S); i++) {
if (ssGetPWorkValue(S,i) != NULL) {
free(ssGetPWorkValue(S,i));
11-104
mdlTerminate
}
}
}
See Also
ssSetOptions, Terminate
11-105
11 S-Function Callback Methods — Alphabetical List
mdlCleanupRuntimeResources
Perform any actions required once at termination of the simulation
Required
Yes
Languages
C, C++
Syntax
void mdlCleanupRuntimeResources(SimStruct *S)
Arguments
S
SimStruct representing an S-Function block.
Description
This method performs any actions, such as freeing of memory, that must be performed
when the simulation is terminated or when an S-Function block is destroyed (e.g., when it
is deleted from a model).
11-106
mdlCleanupRuntimeResources
Note If you have Simulink Coder, when generating code for a noninlined C MEX S-
function that contains this method, make sure the method is not wrapped in a #if
defined(MATLAB_MEX_FILE) statement. For example:
#if defined(MATLAB_MEX_FILE)
static void mdlCleanupRuntimeResources(SimStruct *S)
{
/* Add mdlCleanupRuntimeResources code here *
}
#endif
Example
Suppose your S-function allocates blocks of memory in mdlSetupRuntimeResources
and saves pointers to the blocks in a PWork vector. The following code fragment would
free this memory.
#define MDL_CLEANUP_RUNTIME_RESOURCES
static void mdlCleanupRuntimeResources(SimStruct *S)
{
int i;
for (i = 0; i<ssGetNumPWork(S); i++) {
if (ssGetPWorkValue(S,i) != NULL) {
free(ssGetPWorkValue(S,i));
}
}
}
See Also
mdlSetupRuntimeResources,ssSetOptions, Terminate, “Get Started with Fast
Restart”
Introduced in R2016b
11-107
11 S-Function Callback Methods — Alphabetical List
mdlUpdate
Update a block's states
Required
No
Languages
C, C++
Syntax
#define MDL_UPDATE
Arguments
S
SimStruct representing an S-Function block.
tid
Task ID.
Description
The Simulink engine invokes this optional method at each major simulation time step. The
method should compute the S-function's states at the current time step and store the
states in the S-function's state vector. The method can also perform any other tasks that
the S-function needs to perform at each major time step.
11-108
mdlUpdate
Use this code if your S-function has one or more discrete states or does not have direct
feedthrough.
The reason for this is that most S-functions that do not have discrete states but do have
direct feedthrough do not have update functions. Therefore, the engine is able to
eliminate the need for the extra call in these circumstances.
If your C MEX S-function needs to have its mdlUpdate routine called and it does not
satisfy either of the above two conditions, specify that it has a discrete state, using the
ssSetNumDiscStates macro in the mdlInitializeSizes function.
In C MEX S-functions, the tid (task ID) argument specifies the task running when the
mdlOutputs routine is invoked. You can use this argument in the mdlUpdate routine of a
multirate S-Function block to encapsulate task-specific blocks of code (see “Multirate S-
Function Blocks” on page 9-36).
Use the UNUSED_ARG macro if your C MEX S-function does not contain task-specific
blocks of code to indicate that the tid input argument is required but not used in the
body of the callback. To do this, insert the line
UNUSED_ARG(tid)
Note If you have Simulink Coder, when generating code for a noninlined C MEX S-
function that contains this method, make sure the method is not wrapped in a #if
defined(MATLAB_MEX_FILE) statement. For example:
#define MDL_UPDATE
#if defined(MDL_UPDATE) && defined(MATLAB_MEX_FILE)
static void mdlUpdate(SimStruct *S, int_T tid)
{
/* Add mdlUpdate code here *
}
#endif
The define statement makes the mdlUpdate method available only to a MATLAB MEX
file. If the S-function is not inlined, Simulink Coder cannot use this method, resulting in
link or run-time errors.
11-109
11 S-Function Callback Methods — Alphabetical List
Example
For an example that uses this function to update discrete states, see dsfunc.c. For an
example that uses this function to update the transfer function coefficients of a time-
varying continuous transfer function, see stvctf.c.
See Also
mdlDerivatives, ssGetContStates, ssGetDiscStates, Update
11-110
mdlZeroCrossings
mdlZeroCrossings
Update zero-crossing vector
Required
No
Languages
C, C++
Syntax
#define MDL_ZERO_CROSSINGS
Arguments
S
SimStruct representing an S-Function block.
Description
An S-function needs to provide this optional method only if it does zero-crossing
detection. Implementing zero-crossing detection typically requires using the zero-crossing
and mode work vectors to determine when a zero crossing occurs and how the S-
function's outputs should respond to this event. The mdlZeroCrossings method should
update the S-function's zero-crossing vector, using ssGetNonsampledZCs.
You can use the optional mdlZeroCrossings routine when your S-function has
registered the CONTINUOUS_SAMPLE_TIME and has nonsampled zero crossings
11-111
11 S-Function Callback Methods — Alphabetical List
Thus, the zero-crossing signals are used to locate the discontinuities and end the current
time step at the point of the zero crossing. To provide the engine with zero-crossing
signals, mdlZeroCrossings updates the ssGetNonsampleZCs(S) vector.
Example
For an example, see sfun_zc_sat.c. A detailed description of this example can be found
in “Zero Crossings” on page 9-42.
See Also
mdlInitializeSizes, ssGetNonsampledZCs
11-112
Outputs
Outputs
Compute the signals that this MATLAB S-function block emits
Required
Yes
Language
MATLAB
Syntax
Outputs(s)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
Description
The Simulink engine invokes this required method at each simulation time step. In a
Level-2 MATLAB S-function, the Outputs method calculates the S-function's outputs at
the current time step and store the results in the run-time object's
OutputPort(n).Data property. In addition, for S-functions with a variable sample time,
the Outputs method computes the next sample time hit.
Use the run-time object method IsSampleHit to determine if the current simulation time
is one at which a task handled by this block is active. For port-based sample times, use
11-113
11 S-Function Callback Methods — Alphabetical List
Set the run-time object's NextTimeHit property to specify the time of the next sample
hit for variable sample-time S-functions.
See Also
Simulink.RunTimeBlock, Simulink.MSFcnRunTimeBlock, mdlOutputs
Introduced in R2012b
11-114
PostPropagationSetup
PostPropagationSetup
Specify the sizes of the work vectors and create the run-time parameters required by this
MATLAB S-function
Required
No
Language
MATLAB
Syntax
PostPropagationSetup(s)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
Description
The Simulink engine calls this optional method to enable this S-function to set the sizes of
state and work vectors that it needs to store global data and to create run-time
parameters (see “Create and Update S-Function Run-Time Parameters” on page 9-7). The
engine invokes this method after it has determined the input port width, output port
width, and sample times of the S-function. This allows the S-function to size the state and
work vectors based on the number and sizes of inputs and outputs and/or the number of
sample times.
11-115
11 S-Function Callback Methods — Alphabetical List
A Level-2 MATLAB S-function must implement this method if any DWork vectors are used
in the S-function. In the case of MATLAB S-functions, this method sets the number of
DWork vectors and initializes their attributes. For example, the following code in the
PostPropagationSetup method specifies the usage for the first DWork vector:
s.DWork(1).Usage = type;
• DWork
• DState
• Scratch
• Mode
Example
For a full example of a Level-2 MATLAB S-function using DWork vectors, see the file
adapt_lms.m used in the Simulink model sldemo_msfcn_lms.
See Also
setup, Simulink.RunTimeBlock, mdlSetWorkWidths
Introduced in R2012b
11-116
ProcessParameters
ProcessParameters
Process the MATLAB S-function's parameters
Required
No
Language
MATLAB
Syntax
ProcessParameters(s)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
Description
This is an optional routine that the Simulink engine calls after CheckParameters
changes and verifies parameters. The processing is done at the top of the simulation loop
when it is safe to process the changed parameters. This function is only valid for
simulation.
11-117
11 S-Function Callback Methods — Alphabetical List
designed for use with the Simulink Coder product, you must write your S-function so that
it doesn't rely on this routine. To do this, you must inline your S-function by using the
Target Language Compiler. For information on inlining S-functions, see “Inlining S-
Functions” (Simulink Coder).
See Also
CheckParameters, Simulink.MSFcnRunTimeBlock, mdlProcessParameters
Introduced in R2012b
11-118
Projection
Projection
Perturb the solver's solution of a system's states to better satisfy time-invariant solution
relationships
Required
No
Language
MATLAB
Syntax
Projection(s)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
Description
This method is intended for use with S-functions that model dynamic systems whose
states satisfy time-invariant relationships, such as those resulting from mass or energy
conservation or other physical laws. The Simulink engine invokes this method at each
time step after the model's solver has computed the S-function's states for that time step.
Typically, slight errors in the numerical solution of the states cause the solutions to fail to
satisfy solution invariants exactly. Your Projection method can compensate for the
errors by perturbing the states so that they more closely approximate solution invariants
11-119
11 S-Function Callback Methods — Alphabetical List
at the current time step. As a result, the numerical solution adheres more closely to the
ideal solution as the simulation progresses, producing a more accurate overall simulation
of the system modeled by your S-function.
Your Projection method's perturbations of system states must fall within the solution
error tolerances specified by the model in which the S-function is embedded. Otherwise,
the perturbations may invalidate the solver's solution. It is up to your Projection
method to ensure that the perturbations meet the error tolerances specified by the model.
See “Perturb System States Using a Solution Invariant” on page 11-120 for a simple
method for perturbing a system's states. The following articles describe more
sophisticated perturbation methods that your mdlProjection method can use.
Example
−1
Xn ≅ Xn* + JnT ( Jn JnT ) Rn
where
• Xn is the system's ideal state vector at the solver's current time step
• Xn* is the approximate state vector computed by the solver at the current time step
• Jn is the Jacobian of the invariant function evaluated at the point in state space
specified by the approximate state vector at the current time step:
11-120
Projection
∂g
Jn = (X *, t )
∂X n n
• tn is the time at the current time step
• Rn is the residual (difference) between the invariant function evaluated at Xn and Xn* at
the current time step:
Note The value of g(Xn, tn) is the same at each time step and is known by definition.
Given a continuous, differentiable invariant function for the system that your S-function
models, this formula allows your S-function's mdlProjection method to compute a
perturbation
−1
JnT ( Jn JnT ) Rn
of the solver's numerical solution, Xn*, that more closely matches the ideal solution, Xn,
keeping the S-function's solution from drifting from the ideal solution as the simulation
progresses.
MATLAB Example
This example illustrates how the perturbation method outlined in the previous section can
keep a model's numerical solution from drifting from the ideal solution as a simulation
progresses. Consider the following model,mdlProjectionEx1:
The PredPrey block references an S-function, predprey_noproj.m, that uses the Lotka-
Volterra equations
ẋ = ax(1 − y)
ẏ = − cy(1 − x)
11-121
11 S-Function Callback Methods — Alphabetical List
to model predator-prey population dynamics, where x(t) is the population density of the
predators and y(t) is the population density of prey. The ideal solution to the predator-
prey ODEs satisfies the time-invariant function
x−cecx y−aeay = d
The Invariant Residual block in this model computes the residual between the invariant
function evaluated along the system's ideal trajectory through state space and its
simulated trajectory:
cxn −a ayn
Rn = d − xn−ce yn e
where xnand ynare the values computed by the model's solver for the predator and prey
population densities, respectively, at the current time step. Ideally, the residual should be
zero throughout simulation of the model, but simulating the model reveals that the
residual actually strays considerably from zero:
11-122
Projection
This model is the same as the previous model, except that its S-function, predprey.m,
includes a mdlProjection method that uses the perturbation approach outlined in
“Perturb System States Using a Solution Invariant” on page 11-120 to compensate for
numerical drift. As a result, the numerical solution more closely tracks the ideal solution
11-123
11 S-Function Callback Methods — Alphabetical List
as the simulation progresses as demonstrated by the residual signal, which remains near
or at zero throughout the simulation:
See Also
Simulink.MSFcnRunTimeBlock, mdlProjection,
Introduced in R2012b
11-124
SetAllowConstantSampleTime
SetAllowConstantSampleTime
Specify sample time behavior and tunability for S-function blocks with port-based sample
times
Language
MATLAB
Syntax
SetAllowConstantSampleTime(s,flag)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
flag
Logical value to allow a sample time of Inf for ports in the S-function. The default is
False.
Description
Use this macro to specify sample time behavior for your S-function with port-based
sample times. If you set flag to False, the Simulink engine does not allow a sample time
of Inf for this S-function. If you set flag to True, the S-function block is tunable and its
ports can have a sample time of Inf. To set the sample time for ports in the S-function,
use SetInputPortSampleTime and SetOutputPortSampleTime. These ports execute
every time you tune any parameter in your model during simulation.
11-125
11 S-Function Callback Methods — Alphabetical List
See Also
SetOutputPortSampleTime, SetInputPortSampleTime
11-126
SetInputPortComplexSignal
SetInputPortComplexSignal
Set the numeric types (real, complex, or inherited) of the signals accepted by an input
port
Required
No
Language
MATLAB
Syntax
SetInputPortComplexSignal(s, port, csig)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
port
Integer value specifying index of port to be set.
csig
Integer value specifying whether the port accepts real (false or 0) or complex (true
or 1) signals.
11-127
11 S-Function Callback Methods — Alphabetical List
Description
The Simulink engine calls this routine to set the input port numeric type for inputs that
have this attribute set to COMPLEX_INHERITED. The input csig is the proposed numeric
type for this input port. This method is only valid for simulation.
The S-function must check whether the proposed numeric type is a valid type for the
specified port. If it is valid, level-2 MATLAB S-functions set the numeric type of the
specified input port using the line:
s.InputPort(port).Complexity = csig;
The S-function can also set the numeric types of other input and output ports with
inherited numeric types. The engine reports an error if the S-function changes the
numeric type of a port whose numeric type is known.
If the S-function does not implement this routine, the engine assumes that the S-function
accepts a real or complex signal and sets the input port numeric type to the specified
value.
The engine calls this method until all input ports with inherited numeric types have their
numeric types specified.
See Also
Simulink.MSFcnRunTimeBlock, Simulink.BlockPortData,
mdlSetInputPortComplexSignal
Introduced in R2012b
11-128
SetInputPortDataType
SetInputPortDataType
Set the data types of the signals accepted by an input port
Required
No
Language
MATLAB
Syntax
SetInputPortDataType(s, port, id)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
port
Integer value specifying index of port to be set.
id
Integer value specifying ID of port's data type. Use s.getDatatypeName(id) to get
the data type's name.
Description
The Simulink engine calls this routine to set the data type of port when port has an
inherited data type. The data type id is the proposed data type for this port. Data type
11-129
11 S-Function Callback Methods — Alphabetical List
IDs for the built-in data types can be found in simstruc_types.h. This method is only
valid for simulation.
The S-function must check whether the specified data type is a valid data type for the
specified port. If it is a valid data type, Level-2 MATLAB S-functions set the data type of
the input port using the line:
s.InputPort(port).DatatypeID = id;
The S-function can also set the data types of other input and output ports if they are
unknown. The engine reports an error if the S-function changes the data type of a port
whose data type has been set.
If the block does not implement this routine, the engine assumes that the block accepts
any data type and sets the input port data type to the specified value.
The engine calls this method until all input ports with inherited data types have their data
types specified.
See Also
Simulink.MSFcnRunTimeBlock, Simulink.BlockPortData,
mdlSetInputPortDataType
Introduced in R2012b
11-130
SetInputPortDimensions
SetInputPortDimensions
Set the dimensions of the signals accepted by an input port
Required
No
Languages
MATLAB
Syntax
SetInputPortDimensions(s, port, dimsInfo)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
port
Integer value specifying index of port to be set.
dimsInfo
Array that specifies the signal dimensions supported by the port, e.g., [5] for a 5-
element vector signal or [3 3] for a 3-by-3 matrix signal.
Description
The Simulink engine calls this method during dimension propagation with candidate
dimensions dimsInfo for port.
11-131
11 S-Function Callback Methods — Alphabetical List
A Level-2 MATLAB S-function sets the input port dimensions using the line
s.InputPort(port).Dimensions = dimsInfo;
Note This method can set the dimensions of any other input or output port whose
dimensions derive from the dimensions of port.
By default, the engine calls this method only if it can fully determine the dimensionality of
port from the port to which it is connected.
The engine calls this method until all input ports with inherited dimensions have their
dimensions specified.
See Also
SetOutputPortDimensions, Simulink.MSFcnRunTimeBlock,
Simulink.BlockPortData, mdlSetInputPortDimensionInfo
Introduced in R2012b
11-132
SetInputPortDimensionsMode
SetInputPortDimensionsMode
Propagate the dimensions mode
Required
No
Language
MATLAB
Syntax
SetInputPortDimensionsMode(s, port, dm)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
port
Integer value specifying index of port to be set.
dm
Integer value representing the dimensions mode of the port.
Description
The Simulink engine calls this optional method to enable this S-function to set the
dimensions mode of the input port indexed by portIdx.
11-133
11 S-Function Callback Methods — Alphabetical List
See Also
SetInputPortDimensions, Simulink.MSFcnRunTimeBlock,
Simulink.BlockPortData, mdlSetInputPortDimensionsModeFcn
Introduced in R2012b
11-134
SetInputPortSampleTime
SetInputPortSampleTime
Set the sample time of an input port that inherits its sample time from the port to which it
is connected
Required
No
Language
MATLAB
Syntax
SetInputPortSampleTime(s, port, time)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
port
Integer value specifying the index of port whose sampling mode is to be set.
time
Two-element array, [period offset], that specifies the period and offset of the
times that this port samples its input.
11-135
11 S-Function Callback Methods — Alphabetical List
Description
The Simulink engine invokes this method with the sample time that port inherits from
the port to which it is connected.
For Level-2 MATLAB S-functions, if the inherited sample time is acceptable, this method
sets the sample time and offset time using the line
s.InputPort(port).SampleTime = time;
The engine calls this method until all input ports with inherited sample times are
specified.
When inherited port-based sample times are specified, the sample time is guaranteed to
be one of the following where 0.0 < period < inf and 0.0 <= offset < period.
Constant, triggered, and variable-step sample times are not propagated to S-functions
with port-based sample times.
Generally SetInputPortSampleTime is called once per port with the input port sample
time. However, there can be cases where this function is called more than once. This
happens when the simulation engine is converting continuous sample times to continuous
but fixed in minor steps sample times. When this occurs, the original values of the sample
times specified in setup are restored before this method is called again.
The final sample time specified at the port can be different from (but equivalent to) the
sample time specified by this method. This occurs when
• The model uses a fixed-step solver and the port has a continuous but fixed in minor
step sample time. In this case, the Simulink engine converts the sample time to the
fundamental sample time for the model.
• The engine adjusts the sample time to be as numerically sound as possible. For
example, the engine converts [0.2499999999999, 0] to [0.25, 0].
11-136
SetInputPortSampleTime
See Also
setup, Simulink.MSFcnRunTimeBlock , mdlSetInputPortSampleTime
Introduced in R2012b
11-137
11 S-Function Callback Methods — Alphabetical List
SetOperatingPoint
Restore operating point of MATLAB S-function
Required
No
Language
MATLAB
Syntax
SetOperatingPoint(s, in)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
in
The MATLAB data of type returned by GetOperatingPoint.
Description
The Simulink engine invokes this custom method at the beginning of a simulation of the
model containing S. Simulink sets the initial simulation state of the S-function to the
operating point of the model.
11-138
SetOperatingPoint
See Also
“Custom Code and Hand Coded Blocks using the S-function API”|
InitializeConditions|GetOperatingPoint|mdlGetOpeartingPoint
Introduced in R2019a
11-139
11 S-Function Callback Methods — Alphabetical List
SetOutputPortComplexSignal
Set the numeric types (real, complex, or inherited) of the signals accepted by an output
port
Required
No
Language
MATLAB
Syntax
SetOutputPortComplexSignal(s, port, csig)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
port
Integer value specifying the index of port to be set.
csig
Integer value specifying whether the port produces real (0) or complex (1) signals.
Description
The Simulink engine calls this routine to set the output port numeric type for outputs that
have this attribute set to COMPLEX_INHERITED. The input argument csig is the
11-140
SetOutputPortComplexSignal
proposed numeric type for this output port. The S-function must check whether the
specified numeric type is a valid type for the specified port.
If it is valid, Level-2 MATLAB S-functions set the numeric type of the specified output port
using the line
s.OutputPort(port).Complexity = csig;
The S-function can also set the numeric types of other input and output ports with
unknown numeric types. The engine reports an error if the S-function changes the
numeric type of a port whose numeric type is known.
If the S-function does not implement this routine, the engine assumes that the S-function
accepts a real or complex signal and sets the output port numeric type to the specified
value.
The engine calls this method until all output ports with inherited numeric types have their
numeric types specified.
Example
See sdotproduct.c for an example of how to use this function.
See Also
Simulink.MSFcnRunTimeBlock , Simulink.BlockPortData,
mdlSetOutputPortComplexSignal
Introduced in R2012b
11-141
11 S-Function Callback Methods — Alphabetical List
SetOutputPortDataType
Set the data type of the signals emitted by an output port
Required
No
Language
MATLAB
Syntax
SetOutputPortDataType(s, port, id)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
port
Integer value specifying index of port to be set.
id
Integer value specifying ID of port's data type. Use s.getDatatypeName(id) to get
the data type's name.
Description
The Simulink engine calls this routine to set the data type of port when port has an
inherited data type. The data type ID id is the proposed data type for this port. Data type
11-142
SetOutputPortDataType
IDs for the built-in data types can be found in simstruc_types.h. The S-function must
check whether the specified data type is a valid data type for the specified port.
If it is a valid data type, Level-2 MATLAB S-functions set the data type of the output port
using the line
s.OutputPort(port).DatatypeID = id;
The S-function can also set the data types of other input and output ports if their data
types have not been set. The engine reports an error if the S-function changes the data
type of a port whose data type has been set.
If the block does not implement this method, the engine assumes that the block supports
any data type and sets the output port data type to the specified value.
The engine calls this method until all output ports with inherited data types have their
data types specified.
See Also
Simulink.MSFcnRunTimeBlock , Simulink.BlockPortData,
mdlSetOutputPortDataType
Introduced in R2012b
11-143
11 S-Function Callback Methods — Alphabetical List
SetOutputPortDimensions
Set the dimensions of the signals accepted by an output port
Required
No
Language
MATLAB
Syntax
SetOutputPortDimensions(s, port, dimsInfo)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
port
Integer value specifying the index of the port to be set.
dimsInfo
Array that specifies the signal dimensions supported by the port, e.g., [5] for a 5-
element vector signal or [3 3] for a 3-by-3 matrix signal.
Description
The Simulink engine calls this method with candidate dimensions dimsInfo for port.
11-144
SetOutputPortDimensions
A Level-2 MATLAB S-function sets the output port dimensions using the line
s.OutputPort(port).Dimensions = dimsInfo;
Note This method can set the dimensions of any other input or output port whose
dimensions derive from the dimensions of port.
By default, the engine calls this method only if it can fully determine the dimensionality of
port from the port to which it is connected.
The engine calls this method until all output ports with inherited dimensions have their
dimensions specified.
Example
See sfun_matadd.c for an example of how to use this function.
See Also
SetInputPortDimensions, Simulink.MSFcnRunTimeBlock ,
Simulink.BlockPortData, mdlSetOutputPortDimensionInfo
Introduced in R2012b
11-145
11 S-Function Callback Methods — Alphabetical List
SetOutputPortSampleTime
Set the sample time of an output port that inherits its sample time from the port to which
it is connected
Required
No
Language
MATLAB
Syntax
SetOutputPortSampleTime(s, port, time)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the S-Function
block.
port
Integer value specifying the index of port whose sampling mode is to be set.
time
Two-element array, [period offset], that specifies the period and offset of the
times that this port produces output.
11-146
SetOutputPortSampleTime
Description
The Simulink engine calls this method with the sample time that port inherits from the
port to which it is connected.
For Level-2 MATLAB S-functions, if the inherited sample time is acceptable, this method
sets the sample time and offset time using the line
s.OutputPort(port).SampleTime = time;
This method can set the sample time of any other input or output port whose sample time
derives from the sample time of port, setting the SampleTime property of the
Simulink.BlockPortData object associated with the port in Level-2 MATLAB S-
functions.
Normally, sample times are propagated forward; however, if sources feeding this block
have inherited sample times, the engine might choose to back-propagate known sample
times to this block. When back-propagating sample times, this method is called in
succession for all inherited output port signals.
See SetInputPortSampleTime for more information about when this method is called.
See Also
SetInputPortSampleTime, Simulink.MSFcnRunTimeBlock,
Simulink.BlockPortData, mdlSetOutputPortSampleTime
Introduced in R2012b
11-147
11 S-Function Callback Methods — Alphabetical List
SetSimState
(Not recommended) Set the simulation state of the MATLAB S-function by restoring the
SimState.
Required
No
Language
MATLAB
Syntax
SetSimState(s, in)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
in
The MATLAB data of type returned by GetSimState.
11-148
SetSimState
Description
The Simulink engine invokes this custom method at the beginning of a simulation of the
model containing S . Simulink sets the initial simulation state of the S-function to the
SimState of the model.
See Also
InitializeConditions, GetSimState, mdlSetSimState
Introduced in R2012b
11-149
11 S-Function Callback Methods — Alphabetical List
setup
Specify the number of inputs, outputs, states, parameters, and other characteristics of the
MATLAB S-function
Required
Yes
Language
MATLAB
Syntax
setup(s)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
Description
This is the first S-function callback methods that the Simulink engine calls.
The Level-2 MATLAB S-function setup method performs nearly the same tasks as the C
MEX S-function mdlInitializeSizes method, with two significant differences. The
setup method does not initialize discrete state information, but it does specify the block
sample times, eliminating the need for an mdlInitializeSampleTimes method. Use
the following properties and methods of the run-time object s to configure the S-function:
11-150
setup
• Specify the number of input ports that this S-function has, using
s.NumInputPorts.
• Specify the dimensions of the ith input port, using
s.InputPort(i).Dimensions.
• If using port-based sample times, specify the sample time of the ith input port,
using s.InputPort(i).SampleTime.
• For each input port, specify whether it has direct feedthrough, using
s.InputPort(i).DirectFeedthrough.
A port has direct feedthrough if the input is used in the Outputs method to
calculate the output or the next sample time, for an S-function with a variable
sample time. 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 Outputs method.
Setting the direct feedthrough flag to 0 tells the engine that u is not used in this S-
function method. Violating this leads to unpredictable results.
See Simulink.BlockData and its parent and children classes for a list of all the
properties and methods associated with a Level-2 MATLAB S-function input port.
• Configure the block's output ports, including:
• Specify the number of output ports that the block has, using s.NumOutputPorts.
• Specify the dimensions of the ith output port, using
s.OutputPort(i).Dimensions.
• If using port-based sample times, specify the sample time of the ith output port,
using s.OutputPort(i).SampleTime.
• Set the block-based sample times (i.e., sample rates), using s.SampleTimes.
11-151
11 S-Function Callback Methods — Alphabetical List
See “Specify S-Function Sample Times” on page 9-26 for a complete discussion of
sample time issues.
For multirate S-functions, the suggested approach to setting sample times is via the
port-based sample times method. When you create a multirate S-function, you must
take care to verify that, when slower tasks are preempted, your S-function correctly
manages data so as to avoid race conditions. When port-based sample times are
specified, the block cannot inherit a sample time of Inf at any port.
See “Using the setup Method” on page 3-5 for additional information and examples using
the setup method.
See Also
Simulink.BlockData, Simulink.MSFcnRunTimeBlock, mdlInitializeSizes,
mdlInitializeSampleTimes
Introduced in R2012b
11-152
SimStatusChange
SimStatusChange
Respond to a pause or resumption of the simulation of the model that contains this
MATLAB S-function
Required
No
Languages
MATLAB
Syntax
SimStatusChange(s, status)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
status
Status of the simulation, either 0 when paused or 1 when continued.
Description
The Simulink engine calls this routine when a simulation of the model containing S
pauses or resumes. This method is only valid for simulation.
11-153
11 S-Function Callback Methods — Alphabetical List
See Also
Simulink.MSFcnRunTimeBlock, mdlSimStatusChange
Introduced in R2012b
11-154
Start
Start
Initialize the state vectors of this MATLAB S-function
Required
No
Language
MATLAB
Syntax
Start(s)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
Description
The Simulink engine invokes this optional method at the beginning of a simulation. The
method performs initialization activities that this S-function requires only once, such as
allocating memory and setting up user data. Use InitializeConditions to initialize
state values
If your S-function resides in an enabled subsystem and needs to reinitialize its states
whenever the subsystem is enabled, use InitializeConditions to initialize the state
values, instead of Start.
11-155
11 S-Function Callback Methods — Alphabetical List
Example
See msfcn_varpulse.m for an example of how to use this function.
See Also
InitializeConditions, Simulink.RunTimeBlock, mdlStart
Introduced in R2012b
11-156
Terminate
Terminate
Perform any actions required at termination of the simulation
Required
Yes
Language
MATLAB
Syntax
Terminate(s)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
Description
This method performs any actions, such as freeing of memory, that must be performed
when the simulation is terminated or when an S-Function block is destroyed (e.g., when it
is deleted from a model).
See Also
mdlTerminate
11-157
11 S-Function Callback Methods — Alphabetical List
Introduced in R2012b
11-158
Update
Update
Update a block's states
Required
No
Language
MATLAB
Syntax
Update(s)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
Description
The Simulink engine invokes this optional method at each major simulation time step. The
method should compute the S-function's states at the current time step and store the
states in the S-function's state vector. The method can also perform any other tasks that
the S-function needs to perform at each major time step.
Use this code if your S-function has one or more discrete states or does not have direct
feedthrough.
11-159
11 S-Function Callback Methods — Alphabetical List
The reason for this is that most S-functions that do not have discrete states but do have
direct feedthrough do not have update functions. Therefore, the engine is able to
eliminate the need for the extra call in these circumstances.
Example
For an example that uses this function to update discrete states, see
msfcn_unit_delay.m.
See Also
Derivatives, Simulink.RunTimeBlock, Simulink.MSFcnRunTimeBlock,
mdlUpdate
Introduced in R2012b
11-160
WriteRTW
WriteRTW
Generate code generation data for the MATLAB S-function
Required
No
Language
MATLAB
Syntax
WriteRTW(s)
Arguments
s
Instance of Simulink.MSFcnRunTimeBlock class representing the Level-2 MATLAB
S-Function block.
Description
This function is called when the Simulink Coder product is generating the model.rtw
file.
11-161
11 S-Function Callback Methods — Alphabetical List
Example
See the S-function adapt_lms.m in the Simulink model sldemo_msfcn_lms for an
example.
See Also
Simulink.MSFcnRunTimeBlock, mdlRTW
Introduced in R2012b
11-162
12
Language Support
Some SimStruct functions are available only in some of the languages supported by the
Simulink software. The reference page for each SimStruct macro or function lists the
languages in which it is available and gives the syntax for these languages.
The SimStruct
The file simstruc.h is a C language header file that defines the Simulink data structure
and the SimStruct access macros. It encapsulates all the data relating to the model or
S-function, including block parameters and outputs.
There is one SimStruct data structure allocated for the Simulink model. Each S-function
in the model has its own SimStruct associated with it. The organization of these
SimStructs is much like a directory tree. The SimStruct associated with the model is
the root SimStruct. The SimStructs associated with the S-functions are the child
SimStructs.
12-2
S-Function SimStruct Functions
Buses
Macro Description
ssGetBusElementComplexSignal Get the signal complexity for a bus element.
ssGetBusElementDataType Get the data type identifier for a bus
element.
ssGetBusElementDimensions Get the dimensions of a bus element.
ssGetBusElementName Get the name of a bus element.
ssGetBusElementNumDimensions Get the number of dimensions for a bus
element.
ssGetBusElementOffset Get the offset from the start of the bus data
type to a bus element.
ssGetNumBusElements Get the number of elements in a bus signal.
ssGetSFcnParamName Get the value of a block parameter for an S-
function block.
12-3
12 S-Function SimStruct Functions Reference
Macro Description
ssIsDataTypeABus Determine whether a data type identifier
represents a bus signal.
ssRegisterTypeFromParameter Register a data type that a parameter in the
Simulink data type table specifies.
ssSetBusInputAsStruct Specify whether to convert the input bus
signal for an S-function from virtual to
nonvirtual.
ssSetBusOutputAsStruct Specify whether the output bus signal from
an S-function must be virtual or nonvirtual.
ssSetBusOutputObjectName Specify the name of the bus object that
defines the structure and type of the output
bus signal.
Data Type
Macro Description
ssGetDataTypeId Get the ID for a data type.
ssGetDataTypeIdAliasedThruTo Get the ID for the built-in data type
associated with a data type alias.
ssGetDataTypeName Get a data type's name.
ssGetDataTypeSize Get a data type's size.
ssGetDataTypeZero Get the zero representation of a data type.
ssGetInputPortDataType Get the data type of an input port.
ssGetNumDataTypes Get the number of data types defined by an
S-function or the model.
ssGetOutputPortDataType Get the data type of an output port.
ssGetOutputPortSignal Get an output signal of any type except
double.
ssGetSFcnParamDataType Get the data type of a parameter.
ssRegisterDataType Register a data type.
ssSetDataTypeSize Specify the size of a data type.
12-4
S-Function SimStruct Functions
Macro Description
ssSetDataTypeZero Specify the zero representation of a data
type.
ssSetInputPortDataType Specify the data type of signals accepted by
an input port.
ssSetOutputPortDataType Specify the data type of an output port.
Macro Description
ssGetDTypeIdFromMxArray Get the Simulink data type of a dialog
parameter.
ssGetNumSFcnParams Get the number of parameters that an S-
function expects.
ssGetSFcnParam Get a parameter entered by a user in the S-
Function block dialog box.
ssGetSFcnParamsCount Get the actual number of parameters
specified by the user.
ssSetNumSFcnParams Set the number of parameters that an S-
function expects.
ssSetSFcnParamTunable Specify the tunability of a dialog box
parameter.
Macro Description
ssGetErrorStatus Get a character vector that identifies the
last error.
ssGetLocalErrorStatus Get a character vector that identifies the
last error in a thread-safe manner.
ssPrintf Print a variable-content msg.
ssSetErrorStatus Report errors.
ssSetLocalErrorStatus Report errors in a thread-safe manner.
ssWarning Display a warning message.
12-5
12 S-Function SimStruct Functions Reference
Function Call
Macro Description
ssCallSystemWithTid Execute a function-call subsystem
connected to an S-function.
ssDisableSystemWithTid Disable a function-call subsystem
connected to this S-function block.
ssEnableSystemWithTid Enable a function-call subsystem connected
to this S-function.
ssGetCallSystemNumFcnCall- Get the number of function-call
Destinations destinations.
ssGetExplicitFCSSCtrl Determine whether this S-function
explicitly enables and disables the function-
call subsystem that it invokes.
ssSetCallSystemOutput Specify that an output port element issues a
function call.
ssSetExplicitFCSSCtrl Specify whether an S-function explicitly
enables and disables the function-call
subsystem that it calls.
12-6
S-Function SimStruct Functions
Macro Description
ssAllowSignalsWithMoreThan2D Enable S-function to work with
multidimensional input and output
signals.
ssGetInputPortComplexSignal Get the numeric type (complex or real)
of an input port.
ssGetInputPortDataType Get the data type of an input port.
ssGetInputPortDirectFeedThrough Determine whether an input port has
direct feedthrough.
ssGetInputPortFrameData Determine whether a port accepts
signal frames.
ssGetInputPortOffsetTime Determine the offset time of an input
port.
ssGetInputPortRequiredContiguous Determine whether the signal elements
entering a port must be contiguous.
ssGetInputPortSampleTime Determine the sample time of an input
port.
ssGetInputPortSampleTimeIndex Get the sample time index of an input
port.
ssGetInputPortUnit Get unit of input port
ssGetOutputPortComplexSignal Get the numeric type (complex or real)
of an output port.
ssGetOutputPortDataType Get the data type of an output port.
ssGetOutputPortFrameData Determine whether a port outputs
signal frames.
ssGetOutputPortOffsetTime Determine the offset time of an output
port.
ssGetOutputPortSampleTime Determine the sample time of an
output port.
ssGetOutputPortUnit Get unit of output port
12-7
12 S-Function SimStruct Functions Reference
Macro Description
ssRegisterUnitFromExpr Register unit from unit expression
ssSetInputPortComplexSignal Set the numeric type (real or complex)
of an input port.
ssSetInputPortDataType Set the data type of an input port.
ssSetInputPortDirectFeedThrough Specify that an input port is a direct-
feedthrough port.
ssSetInputPortOffsetTime Specify the sample time offset for an
input port.
ssSetInputPortRequiredContiguous Specify that the signal elements
entering a port must be contiguous.
ssSetInputPortSampleTime Set the sample time of an input port.
ssSetInputPortUnit Specify unit of input port
ssSetNumInputPorts Set the number of input ports on an S-
Function block.
ssSetNumOutputPorts Specify the number of output ports on
an S-Function block.
ssSetOneBasedIndexInputPort Specify that an input port expects one-
based indices.
ssSetOneBasedIndexOutputPort Specify that an output port emits one-
based indices.
ssSetOutputPortComplexSignal Specify the numeric type (real or
complex) of this port.
ssSetOutputPortDataType Specify the data type of an output port.
ssSetOutputPortOffsetTime Specify the sample time offset value of
an output port.
ssSetOutputPortSampleTime Specify the sample time of an output
port.
ssSetOutputPortUnit Specify unit of output port
ssSetZeroBasedIndexInputPort Specify that an input port expects zero-
based indices.
12-8
S-Function SimStruct Functions
Macro Description
ssSetZeroBasedIndexOutputPort Specify that an output port emits zero-
based indices.
12-9
12 S-Function SimStruct Functions Reference
Macro Description
ssAddOutputDimsDependencyRule Register a method to handle current
dimensions update.
ssAddVariableSizeSignalsRuntimeChecke Register a method to check the current
r input dimensions.
ssAllowSignalsWithMoreThan2D Enable S-function to work with
multidimensional signals.
ssGetCurrentInputPortDimensions Gets the current size of dimension dIdx
of input port pIdx.
ssGetCurrentInputPortWidth Gets the total width (total number of
elements) of the signal at input port
pIdx
ssGetCurrentOutputPortDimensions Gets the current size of dimension dIdx
of the signal at output port pIdx.
ssGetCurrentOutputPortWidth Gets the total width (total number of
elements) of the signal at output port
pIdx.
ssGetInputPortDimensions Get the dimensions of the signal
accepted by an input port.
ssGetInputPortDimensionSize Get the size of one dimension of the
signal entering an input port.
ssGetInputPortDimensionsMode Gets the dimensions mode of the input
port indexed by pIdx,
ssGetInputPortNumDimensions Get the dimensionality of the signals
accepted by an input port.
ssGetInputPortWidth Determine the width of an input port.
ssGetOutputPortDimensions Get the dimensions of the signal
leaving an output port.
ssGetOutputPortDimensionSize Get the size of one dimension of the
signal leaving an output port.
ssGetOutputPortDimensionsMode Sets the dimensions mode of the output
port indexed by pIdx.
12-10
S-Function SimStruct Functions
Macro Description
ssGetOutputPortNumDimensions Get the number of dimensions of an
output port.
ssGetOutputPortWidth Determine the width of an output port.
ssSetCurrentOutputPortDimensions Sets the current size corresponding to
dimension dIdx of the output signal at
port pIdx.
ssSetDWorkRequireResetForSignalSize Set the block flag for resetting the
dIndex DWork size upon subsystem
reset.
ssSetInputPortDimensionInfo Set the dimensionality of an input port.
ssSetInputPortDimensionsMode Sets the dimensions mode of the input
port indexed by pIdx.
ssSetInputPortDimsSameAsOutputPortDim Set the dimensions of output port
s outIdx to be equal than the dimensions
of input port inpIdx.
ssSetInputPortMatrixDimensions Specify dimension information for an
input port that accepts matrix signals.
ssSetInputPortVectorDimension Specify dimension information for an
input port that accepts vector signals.
ssSetInputPortWidth Set the width of a 1-D (vector) input
port.
ssSetOutputPortDimensionInfo Specify the dimensionality of an output
port.
ssSetOutputPortDimensionsMode Sets the dimensions mode of the output
port indexed by pIdx.
ssSetOutputPortMatrixDimensions Specify dimension information for an
output port that emits matrix signals.
ssSetOutputPortVectorDimension Specify dimension information for an
output port that emits vector signals.
ssSetOutputPortWidth Specify the width of a 1-D (vector)
output port.
12-11
12 S-Function SimStruct Functions Reference
Macro Description
ssSetOutputPortMatrixDimensions Specify the dimensions of a 2-D
(matrix) signal.
ssRegMdlSetInputPortDimensionsModeFcn Register the method to handle
dimensions mode propagation for each
input port.
ssSetSignalSizesComputeType Set the type of output dependency on
the input signal.
ssSetVectorMode Specify the vector mode that an S-
function supports.
12-12
S-Function SimStruct Functions
Macro Description
ssGetInputPortBufferDstPort Determine the output port that is
overwriting an input port's memory
buffer.
ssGetInputPortConnected Determine whether an S-Function
block port is connected to a nonvirtual
block.
ssGetInputPortOptimOpts Determine the reusability setting of the
memory allocated to the input port of
an S-function.
ssGetInputPortOverWritable Determine whether an input port can
be overwritten.
ssGetInputPortRealSignal Get the address of a real, contiguous
signal entering an input port.
ssGetInputPortRealSignalPtrs Access the signal elements connected
to an input port.
ssGetInputPortSignal Get the address of a contiguous signal
entering an input port.
ssGetInputPortSignalPtrs Get pointers to input signal elements of
type other than double.
ssGetNumInputPorts Can be used in any routine (except
mdlInitializeSizes) to determine
how many input ports a block has.
ssGetNumOutputPorts Can be used in any routine (except
mdlInitializeSizes) to determine
how many output ports a block has.
ssGetOutputPortConnected Determine whether an output port is
connected to a nonvirtual block.
ssGetOutputPortBeingMerged Determine whether the output of this
block is connected to a Merge block.
ssGetOutputPortOptimOpts Determine the reusability of the
memory allocated to the output port of
an S-function.
12-13
12 S-Function SimStruct Functions Reference
Macro Description
ssGetOutputPortRealSignal Access the elements of a signal
connected to an output port.
ssGetOutputPortSignal Get the vector of signal elements
emitted by an output port.
ssSetInputPortOptimOpts Specify the reusability of the memory
allocated to the input port of an S-
function.
ssSetInputPortOverWritable Specify whether an input port is
overwritable by an output port.
ssSetOutputPortOptimOpts Specify the reusability of the memory
allocated to the output port of an S-
function.
ssSetOutputPortOverwritesInputPort Specify whether an output port can
share its memory buffer with an input
port.
Model Reference
Macro Description
ssRTWGenIsModelReferenceRTW- Determine if the model reference Simulink
Target Coder target is generating.
ssRTWGenIsModelReferenceSIM- Determine if the model reference
Target simulation target is generating.
ssSetModelReferenceNormalMode- Specify if S-function can be used in
Support referenced model simulating in normal
mode.
ssSetModelReferenceSampleTime- Specify that a referenced model containing
DefaultInheritance this S-function can inherit its sample time
from its parent model.
ssSetModelReferenceSampleTime- Specify that the use of this S-function in a
DisallowInheritance referenced model prevents the referenced
model from inheriting its sample time from
its parent model.
12-14
S-Function SimStruct Functions
Macro Description
ssSetModelReferenceSampleTime- Specify whether use of an S-function in a
InheritanceRule referenced model prevents the referenced
model from inheriting its sample time from
the parent model.
Run-Time Parameters
These macros allow you to create, update, and access run-time parameters corresponding
to a block's dialog parameters.
Macro Description
ssGetNumRunTimeParams Get the number of run-time parameters
created by this S-function.
ssGetRunTimeParamInfo Get the attributes of a specified run-time
parameter.
Register all tunable dialog parameters as
run-time parameters.
ssRegDlgParamAsRunTimeParam Register a run-time parameter.
ssSetNumRunTimeParams Specify the number of run-time parameters
to be created by this S-function.
ssSetRunTimeParamInfo Specify the attributes of a specified run-
time parameter.
Update all run-time parameters
corresponding to tunable dialog
parameters.
ssUpdateDlgParamAsRunTimeParam Update a run-time parameter.
ssUpdateRunTimeParamData Update the value of a specified run-time
parameter.
ssUpdateRunTimeParamInfo Update the attributes of a specified run-
time parameter from the attributes of the
corresponding dialog parameters.
12-15
12 S-Function SimStruct Functions Reference
Sample Time
Macro Description
ssGetInputPortSampleTime Determine the sample time of an input port.
ssGetInputPortSampleTimeIndex Get the sample time index of an input port.
ssGetNumSampleTimes Get the number of sample times an S-
function has.
ssGetOffsetTime Determine one of an S-function's sample
time offsets.
ssGetOutputPortSampleTime Determine the sample time of an output
port.
ssGetPortBasedSampleTimeBlock- Determine whether a block that uses port-
IsTriggered based sample times resides in a triggered
subsystem.
ssGetSampleTime Determine one of an S-function's sample
times.
ssGetTNext Get the time of the next sample hit in a
discrete S-function with a variable sample
time.
ssIsContinuousTask Determine whether a specified rate is the
continuous rate.
ssIsSampleHit Determine the sample rate at which an S-
function is operating.
ssIsSpecialSampleHit Determine whether the current sample time
hits two specified rates.
ssSampleAndOffsetAreTriggered Determine whether a sample time and
offset value pair indicate a triggered
sample time.
ssSetInputPortSampleTime Set the sample time of an input port.
ssSetModelReferenceSampleTime- Specify that a referenced model containing
DefaultInheritance this S-function can inherit its sample time
from its parent model.
12-16
S-Function SimStruct Functions
Macro Description
ssSetModelReferenceSampleTime- Specify that the use of this S-function in a
DisallowInheritance referenced model prevents the referenced
model from inheriting its sample time from
its parent model.
ssSetModelReferenceSampleTime- Specify whether use of an S-function in a
InheritanceRule referenced model prevents the referenced
model from inheriting its sample time from
the parent model.
ssSetNumSampleTimes Set the number of sample times an S-
function has.
ssSetOffsetTime Specify the offset of a sample time.
ssSetSampleTime Specify a sample time for an S-function.
ssSetTNext Specify the time of the next sample hit in an
S-function.
Simulation Information
Macro Description
ssGetBlockReduction Determine whether a block has requested
block reduction before the simulation has
begun and whether it has actually been
reduced after the simulation loop has
begun.
ssGetErrorStatus Get a character vector that identifies the
last error.
ssGetFixedStepSize Get the fixed step size of the model
containing the S-function.
ssGetMaxStepSize Get the maximum step size of the model
containing the S-function.
ssGetMinStepSize Get the minimum step size of the model
containing the S-function.
12-17
12 S-Function SimStruct Functions Reference
Macro Description
ssGetSimMode Determine the context in which an S-
function is being invoked: normal
simulation, external-mode simulation,
model editor, etc.
ssGetSimStatus Determine the current simulation status.
ssGetSolverMode Get the solver mode being used to solve the
S-function.
ssGetSolverName Get the name of the solver being used for
the simulation.
ssGetStateAbsTol Get the absolute tolerance used by the
model's variable-step solver for a specified
state.
ssGetStopRequested Get the value of the simulation stop
requested flag.
ssGetT Get the current base simulation time.
ssGetTaskTime Get the current time for a task.
ssGetTFinal Get the end time of the current simulation.
ssGetTNext Get the time of the next sample hit.
ssGetTStart Get the start time of the current simulation.
ssIsExternalSim Determine if the model is running in
external mode.
ssIsFirstInitCond Determine whether the current simulation
time is equal to the simulation start time.
ssIsMajorTimeStep Determine whether the current time step is
a major time step.
ssIsMinorTimeStep Determine whether the current time step is
a minor time step.
ssIsVariableStepSolver Determine whether the current solver is a
variable-step solver.
ssRTWGenIsAccelerator Determine if the model is running in
Accelerator mode.
12-18
S-Function SimStruct Functions
Macro Description
ssSetStateAbsTol Set the values of the absolute tolerances
that the variable-step solver will apply to
the S-function states.
ssSetBlockReduction Request that Simulink attempt to reduce a
block.
ssSetOperatingPointCompliance Specify how Simulink treats an S-function
when saving and restoring the simulation
state of a model containing the S-function.
ssSetOperatingPointVisibility Specify whether or not the simulation state
of the S-function is visible (accessible) in
the simulation state of the model.
ssSetSolverNeedsReset Ask Simulink to reset the solver.
ssSetStopRequested Ask Simulink to terminate the simulation at
the end of the current time step.
Macro Description
ssGetContStates Get an S-function's continuous states.
ssGetDiscStates Get an S-function's discrete states.
ssGetDWork Get a DWork vector.
ssGetDWorkComplexSignal Determine whether the elements of a
DWork vector are real or complex numbers.
ssGetDWorkDataType Get the data type of a DWork vector.
ssGetDWorkName Get the name of a DWork vector.
ssGetDWorkUsageType Determine how the DWork vector is used in
S-function.
ssGetDWorkUsedAsDState Determine whether a DWork vector is used
as a discrete state vector.
ssGetDWorkWidth Get the size of a DWork vector.
ssGetdX Get the derivatives of the continuous states
of an S-function.
12-19
12 S-Function SimStruct Functions Reference
Macro Description
ssGetIWork Get an S-function's integer-valued (int_T)
work vector.
ssGetIWorkValue Get a value from a block's integer work
vector.
ssGetModeVector Get an S-function's mode work vector.
ssGetModeVectorValue Get an element of a block's mode vector.
ssGetNonsampledZCs Get an S-function's zero-crossing signals
vector.
ssGetNumContStates Determine the number of continuous states
that an S-function has.
ssGetNumDiscStates Determine the number of discrete states
that an S-function has.
ssGetNumDWork Get the number of data type work vectors
used by a block.
ssGetNumIWork Get the size of an S-function's integer work
vector.
ssGetNumModes Determine the size of an S-function's mode
vector.
ssGetNumNonsampledZCs Determine the number of nonsampled zero
crossings that an S-function detects.
ssGetNumPWork Determine the size of an S-function's
pointer work vector.
ssGetNumRWork Determine the size of an S-function's real-
valued (real_T) work vector.
ssGetPWork Get an S-function's pointer (void *) work
vector.
ssGetPWorkValue Get a pointer from a pointer work vector.
ssGetRealDiscStates Get the real (real_T) values of an S-
function's discrete state vector.
ssGetRWork Get an S-function's real-valued (real_T)
work vector.
12-20
S-Function SimStruct Functions
Macro Description
ssGetRWorkValue Get an element of an S-function's real-
valued work vector.
ssSetDWorkComplexSignal Specify whether the elements of a data type
work vector are real or complex.
ssSetDWorkDataType Specify the data type of a data type work
vector.
ssSetDWorkName Specify the name of a data type work
vector.
ssSetDWorkUsageType Specify how the DWork vector is used in S-
function.
ssSetDWorkUsedAsDState Specify that a data type work vector is used
as a discrete state vector.
ssSetDWorkWidth Specify the width of a data type work
vector.
ssSetIWorkValue Set an element of a block's integer work
vector.
ssSetModeVectorValue Set an element of a block's mode vector.
ssSetNumContStates Specify the number of continuous states
that an S-function has.
ssSetNumDiscStates Specify the number of discrete states that
an S-function has.
ssSetNumDWork Specify the number of data type work
vectors used by a block.
ssSetNumIWork Specify the size of an S-function's integer
(int_T) work vector.
ssSetNumModes Specify the number of operating modes that
an S-function has.
ssSetNumNonsampledZCs Specify the number of zero crossings that
an S-function detects.
ssSetNumPWork Specify the size of an S-function's pointer
(void *) work vector.
12-21
12 S-Function SimStruct Functions Reference
Macro Description
ssSetNumRWork Specify the size of an S-function's real
(real_T) work vector.
ssSetPWorkValue Set an element of a block's pointer work
vector.
ssSetRWorkValue Set an element of a block's floating-point
work vector.
Code Generation
Macro Description
ssGetDWorkRTWIdentifier Get the identifier used to declare a DWork
vector in code generated from the
associated S-function.
ssGetDWorkRTWIdentifierMust- Get a flag indicating if a DWork vector
ResolveToSignalObject resolves to a Simulink.Signal object.
ssGetDWorkRTWStorageClass Get the storage class of a DWork vector in
code generated from the associated S-
function.
ssGetDWorkRTWTypeQualifier Get the C type qualifier (e.g., const) used
to declare a DWork vector in code
generated from the associated S-function.
ssGetNumInputPorts Get the number of input ports that a block
has
ssGetNumOutputPorts Get the number of output ports that a block
has
ssGetPlacementGroup Get the name of the placement group of a
block.
ssRTWGenIsCodeGen Identify any code generation that is not
used by the Accelerator.
ssSetArrayLayoutForCodeGen Specify array layout of the S-function.
ssSetDWorkRTWIdentifier Set the identifier used to declare a DWork
vector in code generated from the
associated S-function.
12-22
S-Function SimStruct Functions
Macro Description
ssSetDWorkRTWIdentifierMust- Specify if a DWork vector resolves to a
ResolveToSignalObject Simulink.Signal object.
ssSetDWorkRTWStorageClass Set the storage class of a DWork vector in
code generated from the associated S-
function.
ssSetDWorkRTWTypeQualifier Set the C type qualifier (e.g., const) used
to declare a DWork vector in code
generated from the associated S-function.
ssSetPlacementGroup Specify the name of the placement group of
a block.
ssWriteRTW2dMatParam Write a Simulink matrix parameter to the S-
function's model.rtw file.
ssWriteRTWMx2dMatParam Write a MATLAB matrix parameter to the S-
function's model.rtw file.
ssWriteRTWMxVectParam Write a MATLAB vector parameter to the S-
function's model.rtw file.
ssWriteRTWParameters Write tunable parameters to the S-
function's model.rtw file.
ssWriteRTWParamSettings Write settings for the S-function's
parameters to the model.rtw file.
ssWriteRTWScalarParam Write a scalar parameter to the S-function's
model.rtw file.
ssWriteRTWStr Write a character vector to the S-function's
model.rtw file.
ssWriteRTWStrParam Write a character vector parameter to the
S-function's model.rtw file.
ssWriteRTWStrVectParam Write a character vector vector parameter
to the S-function's model.rtw file.
ssWriteRTWVectParam Write a Simulink vector parameter to the S-
function's model.rtw file.
ssWriteRTWWorkVect Write the S-function's work vectors to the
model.rtw file.
12-23
12 S-Function SimStruct Functions Reference
Miscellaneous
Macro Description
ssCallExternalModeFcn Invoke the external mode function for an S-
function.
ssGetModelName Get the name of an S-Function block or
model containing the S-function.
ssGetParentSS Get the parent of an S-function.
ssGetPath Get the path of an S-function or the model
containing the S-function.
ssGetRootSS Return the root (model) SimStruct.
ssGetUserData Access user data.
ssSetExternalModeFcn Specify the external mode function for an S-
function.
ssSetOptions Set various simulation options.
ssSetPlacementGroup Specify the execution order of a sink or
source S-function.
ssSetUserData Specify user data.
ssSupportsMultipleExecInstances Allow an S-function to operate within a For
Each Subsystem.
12-24
13
This section describes the S-function options available through ssSetOptions. Each S-
function sets its applicable options at the end of its mdlInitializeSizes method. Use
the OR operator (|) to set multiple options. For example:
ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE |
SS_OPTION_DISCRETE_VALUED_OUTPUT);
13 S-Function Options — Alphabetical List
SS_OPTION_ALLOW_CONSTANT_PORT_SAMPL
E_TIME
Allow a sample time of Inf for a port
Description
Allows an S-function with port-based sample times to specify or inherit a sample time of
Inf. This setting allows the port to have a constant value, and tells the Simulink engine
that all input and output ports support a sample time of Inf. See “Specifying Constant
Sample Time (Inf) for a Port” on page 9-32 for more information.
Example
See sfun_port_constant.c, the source file for the sfcndemo_port_constant
example, for an example.
See Also
SS_OPTION_DISALLOW_CONSTANT_SAMPLE_TIME
Introduced in R2007b
13-2
SS_OPTION_ALLOW_INPUT_SCALAR_EXPANSION
SS_OPTION_ALLOW_INPUT_SCALAR_EXPANSI
ON
Allow scalar expansion of input ports
Description
Specifies that the input to your S-function input ports can have a width of either 1 or the
size specified by the port, usually referred to as the block width. The S-function expands
scalar inputs to the same dimensions as the block width. See “Scalar Expansion of Inputs”
on page 9-21 for more information.
Example
See sfun_multiport.c, the source file for the sfcndemo_sfun_multiport example,
for an example.
Introduced in R2007b
13-3
13 S-Function Options — Alphabetical List
SS_OPTION_ALLOW_PARTIAL_DIMENSIONS_CA
LL
Allow calls to mdlSetInputPortDimensionInfo and
mdlSetOutputPortDimensionInfo with partial dimension information
Description
Indicates the S-function can handle dynamically dimensioned signals. By default, the
Simulink engine calls the mdlSetInputPortDimensionInfo or
mdlSetOutputPortDimensionInfo methods if the number of dimensions and size of
each dimension for the candidate port are fully known. If
SS_OPTION_ALLOW_PARTIAL_DIMENSIONS_CALLS is set, the engine may also call these
methods with partial dimension information. For example, the methods may be called
when the port width is known, but the actual 2-D dimensions are unknown. See
mdlSetDefaultPortDimensionInfo for more information.
See Also
mdlSetDefaultPortDimensionInfo
Introduced in R2007b
13-4
SS_OPTION_ALLOW_PORT_SAMPLE_TIME_IN_TRIGSS
SS_OPTION_ALLOW_PORT_SAMPLE_TIME_IN_T
RIGSS
Allow an S-function with port-based sample times to operate in a triggered subsystem
Description
Allows an S-function that uses port-based sample times to operate in a triggered
subsystem. During sample time propagation, use the macro
ssSampleAndOffsetAreTriggered to determine if the sample and offset times
correspond to the block being in a triggered subsystem. If the block is triggered, all port
sample times must be either triggered or constant. See “Configuring Port-Based Sample
Times for Use in Triggered Subsystems” on page 9-34 for more information.
Example
See sfun_port_triggered.c, the source file for the sfcndemo_port_triggered
example, for an example.
See Also
ssSampleAndOffsetAreTriggered
Introduced in R2007b
13-5
13 S-Function Options — Alphabetical List
SS_OPTION_ASYNC_RATE_TRANSITION
Create a read-write pair of blocks that ensure correct data transfer
Description
Creates a read-write pair of blocks intended to guarantee correct data transfers between
a synchronously (periodic) and an asynchronously executing subsystem or between two
asynchronously executing subsystems. Both the read S-function and write S-function
should set this option.
• Read-write pairs. In this class, two blocks, using a technique such as double buffering,
ensure data integrity in a multitasking environment. When creating the read-write pair
of blocks, the S-functions for these blocks should set the
SS_OPTION_ASYNC_RATE_TRANSITION option. Furthermore, the MaskType property
of the read block, must include the character vector read and the MaskType property
of write block must include the character vector write.
• A single protected or unprotected block. To create a single Protected Rate Transition
block, create a subsystem that contains the following
and set the Tag value of the Outport block to AsyncRateTransition. The S-function
then provides the code for the protected transition. Note, this S-function does not set
the SS_OPTION_ASYNC_RATE_TRANSITION option.
See Also
SS_OPTION_ASYNCHRONOUS
13-6
SS_OPTION_ASYNC_RATE_TRANSITION
Introduced in R2007b
13-7
13 S-Function Options — Alphabetical List
SS_OPTION_ASYNCHRONOUS
Specify this S-function drives a function-call subsystem attached to interrupt service
routines
Description
Specifies that the S-function is driving function-call subsystems attached to interrupt
service routines. This option applies only to S-functions that have no input ports during
code generation and 1 output port. During simulation, the S-function may have an input
port to provide a condition on which to execute. The output port must be configured to
perform function calls on every element. If any of these requirements is not met, the
SS_OPTION_ASYNCHRONOUS option is ignored. Specifying this option
• Informs the Simulink engine that there is no implied data dependency involving the
data sources or destinations of the function-call subsystem called by the S-function.
• Causes the function-call subsystem attached to the S-function to be colored purple,
indicating that it does not execute at a periodic rate.
• Enables additional checks to verify that the model is constructed correctly.
1 The engine validates that the appropriate asynchronous rate transition blocks
reside between the purple function-call subsystem. The engine also checks that
period tasks exists. You can directly read and write from the function-call
subsystem by using a block that has no computational overhead. To ensure safe
task transitions between period and asynchronous tasks, use the
SS_OPTION_ASYNC_RATE_TRANSITION option.
2 For data transfers between two asynchronously executed (purple) function-call
subsystem, the engine validates that the appropriate asynchronous task transition
blocks exits.
See Also
SS_OPTION_ASYNC_RATE_TRANSITION
Introduced in R2007b
13-8
SS_OPTION_CALL_TERMINATE_ON_EXIT
SS_OPTION_CALL_TERMINATE_ON_EXIT
Force call to mdlTerminate
Description
Guarantees the Simulink engine calls the S-function's mdlTerminate method before
destroying a block that references the S-function. Calling mdlTerminate allows your S-
function to clean up after itself, for example, by freeing memory it allocated during a
simulation. The engine destroys an S-function block under the following circumstances.
If this option is not set, the engine calls your S-function's mdlTerminate method only if
the mdlStart method of at least one block in the model containing the S-function
executed without error.
Example
See the S-function sfun_runtime3.c for an example.
See Also
mdlTerminate
Introduced in R2007b
13-9
13 S-Function Options — Alphabetical List
SS_OPTION_CAN_BE_CALLED_CONDITIONALLY
Specify this S-function can be called conditionally
Description
Specifies that the S-function can be called conditionally by other blocks. The Simulink
engine uses this option to determine if the S-Function block can be moved into the
execution context of the conditionally executed subsystem in which the S-function
resides.
Example
See the S-function sdotproduct.c used in the Simulink model
sfcndemo_sdotproduct for an example.
Introduced in R2007b
13-10
SS_OPTION_DISALLOW_CONSTANT_SAMPLE_TIME
SS_OPTION_DISALLOW_CONSTANT_SAMPLE_T
IME
Disallow inheritance of Inf sample time
Description
Prohibits the S-Function block that references this S-function from inheriting a sample
time of Inf. The SS_OPTION_DISALLOW_CONSTANT_SAMPLE_TIME option applies only
to S-functions that use block-based sample times.
Note If you have Simulink Coder, and the S-function declares the number of sample
times as PORT_BASED_SAMPLE_TIMES, it will not inherit a sample time of Inf unless it
specifies the SS_OPTION_ALLOW_CONSTANT_PORT_SAMPLE_TIME option.
• If the S-function specifies this option and inherits a sample time of Inf, the Simulink
Coder product determines how to generate code for the block based on if the block is
invariant.
• A block is invariant if all of its ports' signals are invariant. A signal is invariant if it has
a constant value during the entire simulation. A constant block sample time does not
guarantee all the ports' signals are invariant. For more information, see “Inline
Invariant Signals” (Simulink Coder).
• If the block is not invariant, the Simulink Coder product generates code only in the
model_initialize function. If the block is invariant, the Simulink Coder product
eliminates the block’s code altogether.
Example
See sfix_fir.cpp for an example.
13-11
13 S-Function Options — Alphabetical List
See Also
SS_OPTION_ALLOW_CONSTANT_PORT_SAMPLE_TIME
Introduced in R2007b
13-12
SS_OPTION_DISCRETE_VALUED_OUTPUT
SS_OPTION_DISCRETE_VALUED_OUTPUT
Specify this S-function has discrete valued output
Description
Specifies this S-function has discrete valued outputs. With this option set, the Simulink
engine does not assign algebraic variables to this S-function when it appears in an
algebraic loop.
Introduced in R2007b
13-13
13 S-Function Options — Alphabetical List
SS_OPTION_EXCEPTION_FREE_CODE
Improve performance of exception-free S-functions
Description
Improves performance of S-functions that do not use mexErrMsgTxt, mxCalloc, or any
other routines that can throw an exception. An S-function is not exception free if it
contains any routine that, when called, has the potential of long-jumping out of a block of
code and into another scope. See “Exception Free Code” on page 9-61 for more
information.
Example
See vsfunc.c for an example.
See Also
SS_OPTION_RUNTIME_EXCEPTION_FREE_CODE
Introduced in R2007b
13-14
SS_OPTION_FORCE_NONINLINED_FCNCALL
SS_OPTION_FORCE_NONINLINED_FCNCALL
Specify generated code format for function-call subsystems called by this S-function
Description
If you have Simulink Coder, indicates that the software should generate procedures for all
function-call subsystems called by this S-function, instead of possibly inlining the
subsystem code. If an S-function sets this option, Simulink Coder ignores the Inline
setting for the Code generation function packaging option in the Subsystem
Parameters dialog box for the Subsystem block. For more information, see “About
Nonvirtual Subsystem Code Generation” (Embedded Coder).
Introduced in R2007b
13-15
13 S-Function Options — Alphabetical List
SS_OPTION_NONVOLATILE
Enable the Simulink engine to remove unnecessary S-Function blocks
Description
Specifies this S-function has no side effects. Setting this option enables the Simulink
engine to remove the S-Function block referencing this S-function during dead branch
elimination, if it is not needed.
Example
See the S-function sdotproduct.c used in the Simulink model
sfcndemo_sdotproduct for an example.
Introduced in R2007b
13-16
SS_OPTION_PLACE_ASAP
SS_OPTION_PLACE_ASAP
Specify this S-function should be placed as soon as possible
Description
Specifies that this S-function should be placed as soon as possible in the block sorted
order. The SS_OPTION_PLACE_ASAP option uses a hierarchical sorted order such as that
used by blocks (“Rules for Block Priorities”). Within a subsystem, the Simulink engine
places an S-function block using this option as far up in the sorted order as possible
without changing the model's semantics. If the S-function's Priority block property is set,
and other blocks in the same subsystem have the same priority, the engine places S-
functions with this option before the other blocks in the same subsystem with the same
priority. This option is typically used by devices connecting to hardware when you want to
ensure the hardware connection is completed first.
Note Simulink honors the SS_OPTION_PLACE_ASAP option, relative to other blocks, only
if this block and the other blocks are in the same subsystem. As a result, Simulink does
not compare two blocks set with SS_OPTION_PLACE_ASAP if they exist in different
subsystems. In addition, Simulink might not place blocks with SS_OPTION_PLACE_ASAP
set before blocks without SS_OPTION_PLACE_ASAP set if they are in different
subsystems.
For more information on block sorted orders, see “What Is Sorted Order?”.
Introduced in R2007b
13-17
13 S-Function Options — Alphabetical List
SS_OPTION_PORT_SAMPLE_TIMES_ASSIGNED
Specify this S-function uses port-based sample times
Description
Indicates the S-function registers multiple sample times (ssSetNumSampleTimes > 1) to
specify the rate at which each input and output port is running. The simulation engine
needs this information when checking for illegal rate transitions. If an S-function uses this
option, it cannot inherit its sample times. See “Hybrid Block-Based and Port-Based
Sample Times” on page 9-35 for more information.
Example
See mixedm.c for an example.
Introduced in R2007b
13-18
SS_OPTION_REQ_INPUT_SAMPLE_TIME_MATCH
SS_OPTION_REQ_INPUT_SAMPLE_TIME_MATC
H
Specify sample times of input signal and port must match
Description
Specifies that the input signal sample times must match the sample time assigned to the
block input port. For example:
generates an error if this option is set. The Simulink engine does not generate an error if
the block or input port sample time is inherited.
Introduced in R2007b
13-19
13 S-Function Options — Alphabetical List
SS_OPTION_RUNTIME_EXCEPTION_FREE_COD
E
Improve performance of run-time exception-free S-functions
Description
Improves performance of S-functions that do not use mexErrMsgTxt, mxCalloc, or any
other routines that can throw an exception inside of a run-time routines. Applicable run-
time routines include mdlGetTimeOfNextVarHit, mdlOutputs, mdlUpdate, and
mdlDerivatives.
See Also
SS_OPTION_EXCEPTION_FREE_CODE
Introduced in R2007b
13-20
SS_OPTION_SIM_VIEWING_DEVICE
SS_OPTION_SIM_VIEWING_DEVICE
Indicate S-Function block is a SimViewingDevice
Description
Indicates the S-Function block referencing this S-function is a SimViewingDevice. As
long as the block meets the other requirements for a SimViewingDevice, i.e., no states,
no outputs, etc., the Simulink engine considers the block to be an external mode block. As
an external mode block, the block appears in the external mode user interface and the
Simulink Coder product does not generate code for it. During an external mode
simulation, the engine runs the block only on the host. See “Use C/C++ S-Functions as
Sim Viewing Devices in External Mode” on page 9-59 in Writing S-Functions for more
information.
Introduced in R2007b
13-21
13 S-Function Options — Alphabetical List
SS_OPTION_SFUNCTION_INLINED_FOR_RTW
Specify use of TLC file during code generation
Description
Indicates the S-function has an associated TLC file and does not contain an mdlRTW
method. Setting this option has no effect if the S-function contains an mdlRTW method.
During code generation, if SS_OPTION_SFUNCTION_INLINED_FOR_RTW is set and the
Simulink Coder product cannot locate the S-function's TLC file, the Simulink Coder
product generates an error. If SS_OPTION_SFUNCTION_INLINED_FOR_RTW is not set but
the Simulink Coder product does locate a TLC file for the S-function, it uses the TLC file.
Introduced in R2007b
13-22
SS_OPTION_SUPPORTS_ALIAS_DATA_TYPES
SS_OPTION_SUPPORTS_ALIAS_DATA_TYPES
Support data type aliases
Description
Specifies how the S-function handles signals whose data types are aliases (see
Simulink.AliasType for more information about data type aliases). If this option is set
and the S-function's inputs and outputs use data type aliases, SimStruct macros such as
ssGetInputPortDataType and ssGetOutputPortDataType return the data type IDs
of those aliases. However, if this option is not set, the SimStruct macros return the data
type IDs associated with the equivalent built-in data types instead. For a list of built-in
values for the data type ID, see ssGetInputPortDataType.
Note If you have Simulink Coder, and this option is not set and the S-function's inputs
use data type aliases, the Simulink engine attempts to propagate the aliases to the S-
function's outputs. However, this process can fail, in which case the engine propagates
the equivalent built-in data types instead. To explicitly control the propagation of data
type aliases through an S-function, enable the
SS_OPTION_SUPPORTS_ALIAS_DATA_TYPES option.
Introduced in R2007b
13-23
13 S-Function Options — Alphabetical List
SS_OPTION_USE_TLC_WITH_ACCELERATOR
Use TLC file when simulating in accelerated mode
Description
Forces the Simulink Accelerator mode to use the Target Language Compiler (TLC)
inlining code for the S-function, which speeds up execution of the S-function. If this
option is not set, the Simulink Accelerator mode uses the MEX version of the S-function
even if a TLC file for the S-function exists. This option should not be set for device driver
blocks (A/D) or when there is an incompatibility between running the MEX mdlStart or
mdlInitializeConditions functions together with the TLC Outputs, Update, or
Derivatives functions. Also, this option indicates that the TLC inlining code should be
used when generating a simulation target for a referenced model that contains this S-
function.
Note The Simulink Accelerator mode does not require the Simulink Coder product to run
an inlined S-function. However, to ensure that the inlined S-function can run in
accelerated mode in current and future Simulink releases, the TLC file for the S-function
must use documented TLC functions to access the CompiledModel structure.
Example
See the S-function timestwo.c used in the Simulink model sfcndemo_timestwo for an
example.
Introduced in R2007b
13-24
SS_OPTION_WORKS_WITH_CODE_REUSE
SS_OPTION_WORKS_WITH_CODE_REUSE
Specify this S-function supports code reuse
Description
Signifies that this S-function is compatible with the Simulink Coder product subsystem
code reuse feature. See “S-Functions That Support Code Reuse” (Simulink Coder) in the
"Simulink Coder User's Guide" for more information. If this option is not set, the Simulink
Coder product will not reuse any subsystem containing this S-Function.
Example
See timestwo.c for an example.
Introduced in R2007b
13-25