Sfunctions DISC
Sfunctions DISC
Writing S-Functions
How to Contact The MathWorks
www.mathworks.com Web
comp.soft-sys.matlab Newsgroup
www.mathworks.com/contact_TS.html Technical Support
508-647-7000 (Phone)
508-647-7001 (Fax)
Trademarks
MATLAB, Simulink, Stateflow, Handle Graphics, Real-Time Workshop, and xPC TargetBox
are registered trademarks, and SimBiology, SimEvents, and SimHydraulics are trademarks of
The MathWorks, Inc.
Other product or brand names are trademarks or registered trademarks of their respective
holders.
Patents
The MathWorks products are protected by one or more U.S. patents. Please see
www.mathworks.com/patents for more information.
Revision History
October 1998 First printing Revised for Simulink 3.0 (Release R11)
November 2000 Second printing Revised for Simulink 4.0 (Release R12)
July 2002 Third printing Revised for Simulink 5.0 Release R13)
April 2003 Online only Revised for Simulink 5.1 (Release R13SP1)
April 2004 Online only Revised for Simulink 5.1.1 (Release R13SP1+)
June 2004 Online only Revised for Simulink 6.0 (Release R14)
October 2004 Online only Revised for Simulink 6.1 (Release R14SP1)
March 2005 Online only Revised for Simulink 6.2 (Release R14SP2)
September 2005 Online Only Revised for Simulink 6.3 (Release R14SP3)
March 2006 Online only Revised for Simulink 6.4 (Release 2006a)
September 2006 Online only Revised for Simulink 6.5 (Release 2006b)
March 2007 Online only Revised for Simulink 6.6 (Release 2007a)
Contents
Overview of S-Functions
1
What Is an S-Function? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-2
v
Writing S-Functions in M
2
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-2
Writing S-Functions in C
3
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-3
Creating C MEX S-Functions . . . . . . . . . . . . . . . . . . . . . . . . 3-4
vi Contents
Input Ports Pane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-18
Output Ports Pane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-19
Parameters Pane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-21
Data Type Attributes Pane . . . . . . . . . . . . . . . . . . . . . . . . . . 3-22
Libraries Pane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-23
Outputs Pane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-25
Continuous Derivatives Pane . . . . . . . . . . . . . . . . . . . . . . . . 3-29
Discrete Update Pane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-31
Build Info Pane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-33
Example: Modeling a Two-Input/Two-Output System . . . . 3-35
vii
Writing Callback Methods . . . . . . . . . . . . . . . . . . . . . . . . . . 3-81
viii Contents
Building an Ada S-Function . . . . . . . . . . . . . . . . . . . . . . . . 5-10
Ada Compiler Requirements . . . . . . . . . . . . . . . . . . . . . . . . 5-10
ix
Implementing Block Features
7
Dialog Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-3
Tunable Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-5
x Contents
Exception Free Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-57
ssSetErrorStatus Termination Criteria . . . . . . . . . . . . . . . . 7-58
Checking Array Bounds . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-58
Examples
A
S-Function Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-2
xi
S-Function Examples .............................. A-2
Index
xii Contents
1
Overview of S-Functions
What Is an S-Function?
An S-function is a computer language description of a Simulink block.
S-functions can be written in MATLAB®, C, C++, Ada, or Fortran. C, C++,
Ada, and Fortran S-functions are compiled as MEX-files using the mex utility
(see “Building MEX-Files” in the External Interfaces User’s Guide). As with
other MEX-files, they are dynamically linked into MATLAB when needed.
S-functions use a special calling syntax that enables you to interact with
Simulink equation solvers. This interaction is very similar to the interaction
that takes place between the solvers and built-in Simulink blocks. The form
of an S-function is very general and can accommodate continuous, discrete,
and hybrid systems.
S-functions allow you to add your own blocks to Simulink models. You can
create your blocks in MATLAB, C, C++, Fortran, or Ada. By following a set of
simple rules, you can implement your algorithms in an S-function. 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 by using masking.
You can use S-functions with Real-Time Workshop®. You can also customize
the code generated by Real-Time Workshop for S-functions by writing a
Target Language Compiler (TLC) file. See “Writing S-Functions for Real-Time
Workshop” in the Real-Time Workshop User’s Guide for more information.
1-2
Using S-Functions in Models
1 timestwo 2
/*
* File : timestwo.c
* Abstract:
* An example C-file S-function for
* multiplying an input by 2:
* y = 2*u
*/
1-3
1 Overview of S-Functions
Note If the MATLAB path includes a C MEX-file and an M-file having the
same root name referenced by an S-function block, the S-function block uses
the C MEX-file.
1-4
Using S-Functions in Models
You can use the Simulink 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 discussions of additional
1-5
1 Overview of S-Functions
parameters and masking, see “Creating Block Masks” in the Using Simulink
documentation.
1-6
How S-Functions Work
Simulation Stages
Execution of a Simulink model proceeds in stages. First comes the
initialization phase. In this phase, Simulink incorporates library blocks
into the model, propagates widths, data types, and sample times, evaluates
1-7
1 Overview of S-Functions
1-8
How S-Functions Work
1-9
1 Overview of S-Functions
1-10
Implementing S-Functions
Implementing S-Functions
You can implement an S-function as either an M-file or a MEX-file. The
following sections describe these alternative implementations and discuss
the advantages of each.
M-File S-Functions
An M-file S-function consists of a MATLAB function of the following form:
[sys,x0,str,ts]=f(t,x,u,flag,p1,p2,...)
where f is the S-function’s name, t is the current time, x is the state vector
of the corresponding S-function block, u is the block’s inputs, flag indicates
a task to be performed, and p1, p2, ... are the block’s parameters. During
simulation of a model, Simulink repeatedly invokes f, using flag to indicate
the task to be performed for a particular invocation. Each time the S-function
performs the task, it returns the result in a structure having the format
shown in the syntax example.
1-11
1 Overview of S-Functions
We recommend that you follow the structure and naming conventions of the
template when creating M-file S-functions. This makes it easier for others to
understand and maintain M-file S-functions that you create. See Chapter 2,
“Writing S-Functions in M” for information on creating M-file S-functions.
MEX-File S-Functions
Like an M-file S-function, a MEX-file function consists of a set of callback
routines that Simulink invokes to perform various block-related tasks during
a simulation. Significant differences exist, however. For one, MEX-file
functions are implemented in a different programming language: C, C++,
Ada, or Fortran. Also, Simulink invokes MEX S-function routines directly
instead of via a flag value as with M-file S-functions. Because Simulink
invokes the functions directly, MEX-file functions must follow standard
naming conventions specified by Simulink.
Other key differences exist. For one, the set of callback functions that
MEX functions can implement is much larger than can be implemented by
M-file functions. A MEX function also has direct access to the internal data
structure, called the SimStruct, that Simulink uses to maintain information
about the S-function. MEX-file functions can also use the MATLAB MEX-file
API to access the MATLAB workspace directly.
1-12
Implementing S-Functions
1-13
1 Overview of S-Functions
S-Function Concepts
Understanding these key concepts should enable you to build S-functions
correctly:
Direct Feedthrough
Direct feedthrough means that the output (or the variable sample time
for variable sample time blocks) is controlled directly by the value of an
input port. A good rule of thumb is that an S-function input port has direct
feedthrough if
An example of a system that requires its inputs (i.e., has direct feedthrough) is
the operation , where u is the input, k is the gain, and y is the output.
An example of a system that does not require its inputs (i.e., does not have
direct feedthrough) is this simple integration algorithm
Outputs:
Derivative:
1-14
S-Function Concepts
M-file S-functions can have only one input port and that input port can
accept only one-dimensional (vector) signals. However, the signals can be of
varying widths. Within an M-file S-function, to indicate that the input width
is dynamically sized, specify a value of -1 for the appropriate fields in the
sizes structure, which is returned during the mdlInitializeSizes call.
You can determine the actual input width when your S-function is called by
using length(u). If you specify a width of 0, the input port is removed from
the S-function block.
A C S-function can have multiple I/O ports and the ports can have different
dimensions. The number of dimensions and the size of each dimension can
be determined dynamically.
For example, the following illustration shows two instances of the same
S-Function block in a model.
1-15
1 Overview of S-Functions
C S-functions give you more flexibility in specifying the widths of input and
output ports. See “Creating Input and Output Ports” on page 7-13.
1-16
S-Function Concepts
specify that the block’s sample time is inherited. A simple example of this
is a Gain block that inherits its sample time from the block driving it.
A block can inherit its sample time from
- The driving block
- The destination block
- The fastest sample time in the system
To set a block’s sample time as inherited, use -1 in M-file S-functions and
INHERITED_SAMPLE_TIME in C S-functions as the sample time. For more
information on the propagation of sample times, see “Displaying Sample
Time Colors” in Using Simulink.
[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 S-function can have only one sample time pair
[INHERITED_SAMPLE_TIME, 0.0]
or
[INHERITED_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET]
1-17
1 Overview of S-Functions
where
INHERITED_SAMPLE_TIME = -1.0
and
[VARIABLE_SAMPLE_TIME, 0.0]
If your S-function has no intrinsic sample time, you must indicate that your
sample time is inherited. There are two cases:
1-18
S-Function Concepts
1-19
1 Overview of S-Functions
S-Function Examples
Simulink comes with a library of S-function examples, including:
To run an example:
1-20
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 these subdirectories under the
MATLAB root directory:
M-files toolbox/simulink/blocks
C, C++, and Fortran simulink/src
Ada simulink/ada/examples
1-21
1 Overview of S-Functions
Filename Description
csfunc.m Define a continuous system in
state-space format.
dsfunc.m Define a discrete system in
state-space format.
vsfunc.m Illustrates how to create a variable
sample time 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.
mixedm.m Implement a hybrid system
consisting of a continuous integrator
in series with a unit delay.
vdpm.m Implement the Van der Pol equation
(similar to the demo model, vdp).
simom.m Example state-space M-file
S-function with internal A, B, C,
and D matrices. This S-function
implements
dx/dt = Ax + By
y = Cx + Du
where x is the state vector, u is the
input vector, and y is the output
vector. The A, B, C, and D matrices
are embedded in the M-file.
1-22
S-Function Examples
Filename Description
simom2.m Example state-space M-file
S-function with external A, B, C,
and D matrices. The state-space
structure is the same as in simom.m,
but the A, B, C, and D matrices are
provided externally as parameters
to this file.
limintm.m Implement a continuous limited
integrator where the output is
bounded by lower and upper bounds
and includes initial conditions.
sfun_varargm.m Example M-file S-function showing
how to use the MATLAB vararg
facility.
vlimintm.m Example of a continuous limited
integrator S-function. This
illustrates how to use the size entry
of -1 to build an S-function that can
accommodate a dynamic input/state
width.
vdlmintm.m Example of a discrete limited
integrator S-function. This example
is identical to vlimint.m, except that
the limited integrator is discrete.
1-23
1 Overview of S-Functions
C S-Function Examples
The simulink/src directory also contains examples of C MEX S-functions,
many of which have an M-file S-function counterpart. These C MEX
S-functions are listed in this table.
Filename Description
barplot.c Access Simulink signals without
using the standard block inputs.
csfunc.c Example C MEX S-function for
defining a continuous system.
dlimintc.c Implement a discrete-time limited
integrator.
dsfunc.c Example C MEX S-function for
defining a discrete system.
fcncallgen.c Execute function-call subsystems n
times at the designated rate (sample
time).
limintc.c Implement a limited integrator.
mixedm.c Implement a hybrid dynamic system
consisting of a continuous integrator
(1/s) in series with a unit delay (1/z).
mixedmex.c Implement a hybrid dynamic system
with a single output and two inputs.
quantize.c Example MEX-file for a vectorized
quantizer block. Quantizes the
input into steps as specified by the
quantization interval parameter, q.
sdotproduct Compute dot product
(multiply-accumulate) of two
real or complex vectors.
sftable2.c Two-dimensional table lookup in
S-function form.
1-24
S-Function Examples
Filename Description
sfun_atol.c Set different absolute tolerances for
each continuous state.
sfun_cplx.c Complex signal add with one input
port and one parameter.
sfun_directlook.c Direct 1-D lookup.
sfun_dtype_io.c Example of the use of Simulink data
types for inputs and outputs.
sfun_dtype_param.c Example of the use of Simulink data
types for parameters.
sfun_dynsize.c Simple example of how to size
outputs of an S-function dynamically.
sfun_errhdl.c Simple example of how to
check parameters using the
mdlCheckParams S-function routine.
sfun_fcncall.c Example of an S-function that is
configured to execute function-call
subsystems on the first and second
output elements.
sfun_frmad.c Frame-based A/D converter.
sfun_frmda.c Frame-based D/A converter.
sfun_frmdft.c Multichannel frame-based
Discrete-Fourier transformation
(and its inverse).
sfun_frmunbuff.c Frame-based unbuffer block.
sfun_multiport.c S-function that has multiple input
and output ports.
sfun_manswitch.c Manual switch.
sfun_matadd.c Matrix add with one input port, one
output port, and one parameter.
sfun_multirate.c Demonstrate how to specify
port-based sample times.
1-25
1 Overview of S-Functions
Filename Description
sfun_psbbreaker.c Implement the logic for the Breaker
block in the SimPowerSystems
Blockset.
sfun_psbcontc.c Continuous implementation of
state-space system.
sfun_psbdiscc.c Discrete implementation of
state-space system.
sfun_runtime1.c Run-time parameter example.
sfun_runtime2.c Run-time parameter example.
sfun_zc.c Demonstrate use of nonsampled zero
crossings to implement abs(u). This
S-function is designed to be used
with a variable-step solver.
sfun_zc_sat.c Saturation example that uses zero
crossings.
sfunmem.c A one-integration-step delay and
hold memory function.
simomex.c Implements a single-input,
two-output state-space dynamic
system described by these
state-space equations
dx/dt = Ax + Bu
y = Cx + Du
1-26
S-Function Examples
Filename Description
stspace.c Implement a set of state-space
equations. You can turn this
into a new block by using the
S-Function block and mask facility.
This example MEX-file performs
the same function as the built-in
State-Space block. This is an
example of a MEX-file where the
number of inputs, outputs, and states
is dependent on the parameters
passed in from the workspace. Use
this as a template for other MEX-file
systems.
stvctf.c Implement 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.
stvdtf.c Implement a discrete-time transfer
function whose transfer function
polynomials are passed in via
the input vector. This is useful
for discrete-time adaptive control
applications.
stvmgain.c Time-varying matrix gain.
table3.c 3-D lookup table.
timestwo.c Basic C MEX S-function that doubles
its input.
vdlmintc.c Implement a discrete-time vectorized
limited integrator.
vdpmex.c Implement the Van der Pol equation.
1-27
1 Overview of S-Functions
Filename Description
vlimintc.c Implement a vectorized limited
integrator.
vsfunc.c Illustrate how to create a variable
sample time block in Simulink. This
block implements a variable-step
delay in which the first input is
delayed by an amount of time
determined by the second input.
Filename Description
sfun_timestwo_for.F Sample Level 1 Fortran
representation of a C timestwo
S-function.
sfun_atmos.c Calculation of the 1976 standard
sfun_atmos_sub.F atmosphere to 86 km using a Fortran
subroutine.
simomexf.F Sample Level 1 Fortran
representation of the C simomex
S-function.
vdpmexf.F Sample Level 1 Fortran
representation of the C vdpmex
S-function.
1-28
S-Function Examples
Filename Description
sfun_counter_cpp.cpp Store a C++ object in the pointers
vector PWork.
1-29
1 Overview of S-Functions
1-30
2
Writing S-Functions in M
Introduction
Simulink provides an application programming interface (API) that lets you
create custom blocks whose properties and behavior are defined by M-file
programs called M-file S-functions. The Level-2 M-file S-function API allows
you to create blocks that have all of the features and capabilities of Simulink
built-in blocks, including multiple input and output ports, the ability to accept
vector or matrix signals of any data type supported by Simulink, real or
complex signals, signal frames, and the ability to operate at multiple sample
rates. For information on how to use the API to create custom blocks, see
“Writing Level-2 M-File S-Functions” on page 2-3.
Note This version of Simulink also supports a predecessor API, called Level
1, for writing M-file S-functions. This is done to ensure that Simulink can
simulate models that use M-file S-function blocks developed for use with
earlier Simulink releases (see “Maintaining Level-1 M-File S-Functions”
on page 2-9). You should not use the Level-1 API to develop new M-file
S-functions. Instead, you should use the Level-2 API.
Simulink allows you to generate code for M-file S-functions if they are inlined.
See “Inlining S-Functions” in the Target Language Compiler documentation
for more information.
2-2
Writing Level-2 M-File S-Functions
2-3
2 Writing S-Functions in M
S-Function Template
To give you a head start on creating Level-2 M-file S-functions, Simulink
provides an annotated M-file template containing skeleton implementation
of the callbacks defined by the Level-2 M-File S-function API. The template
resides at
matlabroot/toolbox/simulink/blocks/msfuntmpl.m
To create an M-file 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 comments in the template explain how to do this.
2-4
Writing Level-2 M-File S-Functions
Callback Methods
The Level-2 M-file S-function API specifies a set of callback methods that an
M-file S-function must implement (see “Callback Methods That an S-Function
Must Implement” on page 3-50) and others that it may choose to omit,
depending on the requirements of the block that the S-function defines. The
methods defined by the Level-2 M-file S-function API generally correspond to
that of similarly named methods defined by the C MEX-file S-function API. For
information on what each method does, see “How Simulink Works” in Using
Simulink and Chapter 8, “S-Function Callback Methods — Alphabetical List”.
The following table lists the Level-2 M-file S-function callback methods and
their C MEX-file counterparts.
2-5
2 Writing S-Functions in M
Update mdlUpdate
WriteRTW mdlRTW
ZeroCrossings mdlZeroCrossings
Setup Method
The body of the setup method of a Level-2 M-file S-function initializes
instances of the corresponding Level-2 M-File S-Function block in a model.
In this respect, the main function is similar to the mdlInitializeSizes
callback method implemented by C MEX S-functions. Setup tasks that the
main function performs include:
2-6
Writing Level-2 M-File S-Functions
• Setting up the number of parameters and checking for the validity of these
parameters.
• Registering the various block methods using the handles for other
local functions in the M-file, using the RegBlockMethod method of the
S-function block’s run-time object passed to it. See the documentation for
Simulink.MSFcnRunTimeBlock for information on using this method.
function setup(block)
block.OutputPort(1).Dimensions = 1;
%% Register methods
2-7
2 Writing S-Functions in M
block.RegBlockMethod('PostPropagationSetup',@DoPostPropSetup);
block.RegBlockMethod('InitializeConditions',@InitConditions);
block.RegBlockMethod('Outputs', @Output);
block.RegBlockMethod('Update', @Update);
Run-time Object
When Simulink invokes a Level-2 M-file S-function callback method, it passes
an instance of Simulink.MSFcnRunTimeBlock class to the method as an
argument. This instance, known as the S-function block’s run-time object,
serves the same purpose for Level-2 M-file S-function callback methods as the
SimStruct structure serves for C MEX-file S-function callback methods. It
enables the method to provide and obtain information about various elements
of the block: ports, parameters, states, and work vectors. The method does
this by getting or setting properties or invoking methods of the block run-time
object. See the documentation for Simulink.MSFcnRunTimeBlock class for
information on getting and setting the run-time object’s properties and
invoking its methods.
Note Other M-file programs besides M-file S-functions can use run-time
objects to obtain information about an M-file S-function or other blocks in a
model that is simulating. See “Accessing Block Data During Simulation” in
Using Simulink for more information.
2-8
Maintaining Level-1 M-File S-Functions
Note The information provided in this section is intended only for use in
maintaining existing M-file S-functions based on Level-1 API. You should use
the more capable Level-2 API to develop new M-file S-functions (see “Writing
Level-2 M-File S-Functions” on page 2-3). Level-1 M-file S-functions do not
support multidimensional signals.
[sys,x0,str,ts]=f(t,x,u,flag,p1,p2,...)
S-Function Arguments
Simulink passes the following arguments to an S-function:
2-9
2 Writing S-Functions in M
t Current time
x State vector
u Input vector
The following table describes the values that flag can assume and lists the
corresponding S-function method for each value.
Flag Argument
2-10
Maintaining Level-1 M-File S-Functions
S-Function Outputs
An M-file returns an output vector containing the following elements:
• 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, reserved for future use. M-file S-functions must set this to the empty
matrix, [].
• ts, a two-column matrix containing the sample times and offsets of the
block (see “Specifying Sample Time” in the Using Simulink for information
on how to specify a block’s sample time and offset).
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
2-11
2 Writing S-Functions in M
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
Simulink 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 give Simulink this information, call the simsizes function at the beginning
of mdlInitializeSizes.
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.
sys = simsizes(sizes);
2-12
Maintaining Level-1 M-File S-Functions
This passes the information in the sizes structure to sys, a vector that holds
the information for use by Simulink.
Compare the code in the Level-1 and Level-2 S-functions sfundsc2.m and
msfcn_unit_delay.m for an example.
2-13
2 Writing S-Functions in M
2-14
3
Writing S-Functions in C
3-2
Introduction
Introduction
A C MEX-file that defines an S-Function block must provide information
about the model to Simulink during the simulation. As the simulation
proceeds, Simulink, the ODE solver, and the C MEX-file interact to perform
specific tasks. These tasks include defining initial conditions and block
characteristics, and computing derivatives, discrete states, and outputs.
3-3
3 Writing S-Functions in C
#include "simstruc.h"
3-4
Introduction
• Legacy Code Tool — This utility builds a C MEX S-function from existing
C code and specifications that you supply using MATLAB M-code. See
“Integrating Existing C Functions into Simulink Models with the Legacy
Code Tool” on page 3-53 for more information about integrating legacy C
code with Simulink.
3-5
3 Writing S-Functions in C
1 Set the MATLAB current directory to the directory in which you want to
create the S-function.
3-6
Building S-Functions Automatically
4 Double-click the block to open the S-Function Builder dialog box (see
“S-Function Builder Dialog Box” on page 3-11).
3-7
3 Writing S-Functions in C
5 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 3-11).
6 If you have not already done so, configure the MATLAB mex command to
work on your system.
3-8
Building S-Functions Automatically
To configure the mex command, type mex -setup at the MATLAB command
line.
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:
4 In the dialog box that opens, enter the name of the executable file generated
by the S-Function Builder into the S-Function name edit field.
3-9
3 Writing S-Functions in C
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 specified in the
S-function name field of the S-Function Builder’s dialog box. This file
contains the C source code representation of the standard portions of the
generated S-function.
• sfun_wrapper.c
This file contains the custom code that you entered in the S-Function
Builder dialog box.
• sfun.tlc
This file permits Simulink to run the generated S-function in accelerated
mode and Real-Time Workshop to include this S-function in the code it
generates.
After generating the S-function source code, the S-Function Builder uses the
MATLAB 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.
3-10
S-Function Builder Dialog Box
3-11
3 Writing S-Functions in C
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.
Note The following sections use the term target S-function to refer to the
S-function specified by the S-Function Builder dialog box.
3-12
S-Function Builder Dialog Box
S-function name
Specifies the name of the target S-function.
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 3-21.
• Data type — Lists the data type of the parameter. Define and modify this
property from the “Parameters Pane” on page 3-21.
• Value — Specifies the value of the parameter. Enter a valid MATLAB
expression in this field.
Port/Parameter Pane
This pane displays the ports and parameters that the dialog box specifies for
the target S-function.
3-13
3 Writing S-Functions in C
The pane contains a tree control whose top nodes correspond to the
target S-function’s 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.
3-14
S-Function Builder Dialog Box
The S-Function Builder uses the information that you enter on this pane to
generate the S-function’s mdlInitializeSizes callback method. Simulink
invokes this method during the model initialization phase of the simulation
to obtain basic information about the S-function. (See “How Simulink
Interacts with C S-Functions” on page 3-73 for more information on the model
initialization phase.)
Discrete states IC
Initial conditions of the S-function’s discrete states. 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.
3-15
3 Writing S-Functions in C
Continuous states IC
Initial conditions of the S-function’s continuous states. 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 block updates its outputs at each simulation step.
• Discrete
The S-function updates its outputs at the rate specified in the Sample
time value field of the S-Function Builder dialog box.
3-16
S-Function Builder Dialog Box
The column of buttons to the left of the panes allows you to add, delete, or
reorder ports or parameters, depending on the currently selected pane.
• To add a port or parameter, click the Add button (the top button in the
column of buttons).
• To delete the currently selected port/parameter, click the Delete button
(located beneath the Add button).
• To move the currently selected port/parameter up one position in the
corresponding S-Function port/parameter list, click the Up button (beneath
the Delete button).
• To move the currently selected port/parameter down one position in the
corresponding S-function port/parameter list, click the Down button
(beneath the Up button).
This pane also contains tabbed panes that enable you to specify the attributes
of the ports and parameters that you create. See the following topics for more
information.
3-17
3 Writing S-Functions in C
The pane comprises an editable table that lists the properties of the input
ports in the order in which the ports appear on the S-function block. Each row
of the table corresponds to a port. Each entry in the row displays a property
of the port as follows.
Port name
Name of the port. Edit this field to change the port name.
Dimensions
Lists the number of dimensions of input signals accepted by the port. To
display a list of supported dimensions, click the adjacent button. To change
the port’s dimensionality, select a new value from the list. Specify 1-D to size
the signal dynamically, regardless of the signal’s actual dimensionality.
3-18
S-Function Builder Dialog Box
Rows
Specifies the size of the input signal’s first (or only) dimension. Specify -1 to
size the signal dynamically.
Columns
Specifies the size of the input signal’s second dimension (only if the input port
accepts 2-D signals).
Note For input signals with two dimensions, if the row dimensions is
dynamically sized, the column dimension must also be dynamically sized or
set to 1. If the column 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
Specifies whether the input port accepts real or complex-valued signals.
Frame
Specifies whether this port accepts frame-based signals generated by Signal
Processing Blockset or Communications Blockset. For more information, see
the documentation for these blocksets.
3-19
3 Writing S-Functions in C
The pane comprises an editable table that lists the properties of the output
ports in the order in which the ports appear on the S-function block. Each row
of the table corresponds to a port. Each entry in the row displays a property
of the port as follows.
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’s
dimensionality, select a new value from the list. Specify 1-D to size the signal
dynamically, regardless of the signal’s actual dimensionality.
Rows
Specifies the size of the output signal’s first (or only) dimension. Specify -1 to
size the signal dynamically.
3-20
S-Function Builder Dialog Box
Columns
Specifies the size of the output signal’s second dimension (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 default Simulink methods
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
Specifies whether the port outputs real or complex-valued signals.
Frame
Specifies whether this port outputs frame-based signals generated by Signal
Processing Blockset or Communications Blockset. For more information, see
the documentation for these blocksets.
Parameters Pane
The Parameters pane allows you to inspect and modify the properties of
the S-function’s parameters.
3-21
3 Writing S-Functions in C
The pane comprises an editable table that lists the properties of the
S-function’s 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. Each entry in the row displays a property of the
parameter as follows.
Parameter name
Name of the parameter. Edit this field to change the name.
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’s data type, select a
new type from the list.
Complexity
Specifies whether the parameter has real or complex values.
The pane contains a table listing the data type attributes of each of
the S-functions ports. Only some of the fields in the table are editable.
Non-editable fields are grayed out. Each row corresponds to a port of the
3-22
S-Function Builder Dialog Box
Port
Name of the port. This field is not editable.
Data Type
Data type of the port. To display a list of specifiable data types, select the
adjacent pulldown list control. 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 “Fixed-Point Data” 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.
3-23
3 Writing S-Functions in C
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 directory, you need specify
only the file’s name. If the file resides in another directory, you must specify
the full path of the file.
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, e.g.,
3-24
S-Function Builder Dialog Box
-DDEBUG
Includes
Header files containing declarations of functions, variables, and macros
referenced by custom code that you enter elsewhere on the S-Function Builder
dialog box. Specify each file on a separate line as #include statements. Use
brackets to enclose the names of 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 directory, you must use the INC_PATH tag in the
Library/Object/Source files field to set the S-Function Builder’s include
path to the directories containing the include files (see “Library/Object/Source
files” on page 3-24).
Outputs Pane
Use the Outputs pane to enter code that computes the outputs of the
S-function at each simulation time step.
3-25
3 Writing S-Functions in C
3-26
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. Simulink 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’s output. The S-function’s mdlOutputs
method in turn invokes the wrapper function containing your output code.
Your output code then actually computes and returns the S-function’s output.
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).
3-27
3 Writing S-Functions in C
Argument Description
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 Simulink.
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 3-31 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 3-29 for
more information).
3-28
S-Function Builder Dialog Box
Argument Description
param0, p_width0, param0, param1, ...paramN are pointers to arrays
param1, p_width1, containing the S-function’s parameters, where N is the
... paramN, number of parameters specified on the Parameters
p_widthN 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’s outputs.
This argument appears in the generated code only
if you specified -1 as the width of the S-function’s
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’s inputs.
This argument appears in the generated code only if
you specified -1 as the width of the S-function’s 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 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.
3-29
3 Writing S-Functions in C
3-30
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 mdlDerivatives callback method that it
generates for the S-function. Simulink calls the mdlDerivatives method
at the end of each time step to obtain the derivatives of the S-function’s
continuous states (see “How Simulink Interacts with C S-Functions” on
page 3-73). The Simulink solver numerically integrates the derivatives to
determine the continuous states at the next time step. At the next time step,
Simulink passes the updated states back to the S-function’s mdlOutputs
method (see “Outputs Pane” on page 3-25).
• u
• y
• dx
• xC
• param0, p_width0, param1, p_width1, ... paramN, p_widthN
• y_width
• u_width
3-31
3 Writing S-Functions in C
Enter code to compute the values of the S-function’s discrete states in the
Code for the mdlUpdate function 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
3-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. Simulink calls the mdlUpdate method at the end
of each time step to obtain the values of the S-function’s discrete states at the
next time step (see “How Simulink Interacts with C S-Functions” on page
3-73). At the next time step, Simulink passes the updated states back to the
S-function’s mdlOutputs method (see “Outputs Pane” on page 3-25).
• u
• y
• xD
• param0, p_width0, param1, p_width1, ... paramN, p_widthN
• y_width
• u_width
See “Outputs Pane” on page 3-25 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’s inputs,
outputs, and, optionally, parameters. Your code can invoke external functions
declared on the Libraries pane.
3-33
3 Writing S-Functions in C
3-34
S-Function Builder Dialog Box
double t = ssGetT(S);
if(t < 2 ) {
y0[0] = u0[0];
} else {
y0[0]= 0.0;
}
For a complete listing of SimStruct macros and functions, see in the online
documentation.
Additional methods
Click this button to include TLC methods in your S-function. The following
dialog box appears.
Check the methods you want to add and click the Close button to include
the methods in your S-function. See “Block Target File Methods” for more
information.
3-35
3 Writing S-Functions in C
In the example, the state-space matrices are parameters to the S-function and
the S-function input and output are vectors. You can find a manually written
version of the S-function in dsfunc.c.
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.
3-36
S-Function Builder Dialog Box
The Input ports pane defines the one S-function input port as a 1-D vector
with two rows.
The Output ports pane similarly defines the one S-function output port as
a 1-D vector with two rows.
3-37
3 Writing S-Functions in C
The Parameters pane defines four parameters, one for each of the four
state-space matrices.
3-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.
3-39
3 Writing S-Functions in C
3-40
Example of a Basic C MEX S-Function
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.
3-41
3 Writing S-Functions in C
#include simstruc.h
if (!ssSetNumOutputPorts(S,1)) return;
ssSetOutputPortWidth(S, 0, DYNAMICALLY_SIZED);
ssSetNumSampleTimes(S, 1);
3-42
Example of a Basic C MEX S-Function
}
}
The following sections explain the three parts example, and also describes
how to build the example:
The first specifies the name of the S-function (timestwo). The second specifies
that the S-function is in the level 2 format (for more information about level
3-43
3 Writing S-Functions in C
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.
The simstruc.h file defines a data structure, called the SimStruct, that
Simulink 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 Chapter 9, “SimStruct Functions — By Category”).
Callback Implementations
The next part of the timestwo S-function contains implementations of
callback methods required by Simulink.
mdlInitializeSizes
Simulink calls mdlInitializeSizes to inquire about the number of input and
output ports, sizes of the ports, and any other objects (such as the number
of states) needed by the S-function.
• Zero parameters
This means that the S-function parameters field of the S-functions’s
dialog box must be empty. If it contains any parameters, Simulink reports
a parameter mismatch.
• One input port and one output port
The widths of the input and output ports are dynamically sized. This tells
Simulink that the S-function can accept an input signal of any width. Note
3-44
Example of a Basic C MEX S-Function
that the default handling for dynamically sized S-functions for this case
(one input and one output) is that the input and output widths are equal.
• One sample time
The timestwo example specifies the actual value of the sample time in the
mdlInitializeSampleTimes routine.
• The code is exception free.
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
isn’t interacting with MATLAB, it is safe to specify this option. For more
details, see “How Simulink Interacts with C S-Functions” on page 3-73.
mdlInitializeSampleTimes
Simulink 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
Simulink calls mdlOutputs at each time step to calculate a block’s outputs.
The timestwo implementation of mdlOutputs takes the input, multiplies it by
2, and writes the answer to the output.
to access the input signal. The macro returns a vector of pointers, which
you must access using
*uPtrs[i]
real_T *y = ssGetOutputPortRealSignal(S,0);
3-45
3 Writing S-Functions in C
to get the width of the signal passing through the block. Finally, the S-function
loops over the inputs to compute the outputs. ()
mdlTerminate
Perform tasks at the end of the simulation. This is a mandatory S-function
routine. However, the timestwo S-function doesn’t need to perform any
termination actions, so this routine is empty.
#ifdef MATLAB_MEX_FILE
#include "simulink.c"
#else
#include "cg_sfun.h"
#endif
mex timestwo.c
at the command line. The mex command compiles and links the timestwo.c
file to create a dynamically loadable executable for Simulink to use.
3-46
Example of a Basic C MEX S-Function
3-47
3 Writing S-Functions in C
Note We recommend that you use the C MEX-file template when developing
MEX S-functions.
3-48
Templates for C S-Functions
Note All S-functions from Simulink 1.3 through 2.1 are considered to be Level
1 S-functions. They are compatible with Simulink 3.0, but we recommend that
you write new S-functions in the Level 2 format.
3-49
3 Writing S-Functions in C
These statements select the appropriate code for your particular application:
3-50
Templates for C S-Functions
Note This trailer code must not be in the body of any S-function routine.
The SimStruct
The file matlabroot/simulink/include/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.
Simulink provides a set of macros that S-functions can use to access the fields
of the SimStruct. See Chapter 9, “SimStruct Functions — By Category” for
more information.
S-functions are not required to use these data types. For example, you can
edit the Simulink example matlabroot/simulink/src/csfunc.c on a PC
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
S-functions can be compiled in one of three modes identified by the presence
of one of the following defines:
3-51
3 Writing S-Functions in C
These define statements do not appear in the S-function. The mode definition
are made by either the mex command or by Real-Time Workshop when the
S-function is built.
3-52
Integrating Existing C Functions into Simulink Models with the Legacy Code Tool
Overview
You can integrate existing C (or C++) functions—for example, device
drivers, lookup tables, and general functions and interfaces—into Simulink
simulations by using the Legacy Code Tool. Using specifications that
you supply as M-code, the tool transforms existing functions into C MEX
S-functions that you can include in Simulink models. If you use Real-Time
Workshop to generate code from a model, the Legacy Code Tool can insert an
appropriate call to your C function into the generated code (for details, see
“Using the Legacy Code Tool to Automate the Generation of Files for Fully
Inlined S-Functions” in the Real-Time Workshop documentation).
3-53
3 Writing S-Functions in C
Note Before you can use legacy_code, you must ensure that a C compiler is
set up for your MATLAB installation. If you need to set up a compiler, enter
the command mex -setup in the MATLAB Command Window.
The following diagram illustrates a general procedure for using the Legacy
Code Tool. “Example of Integrating Existing C Functions into Simulink
Models with the Legacy Code Tool” on page 3-56 provides an example that
uses the Legacy Code Tool to transform an existing C function into a Simulink
C MEX S-function.
3-54
Integrating Existing C Functions into Simulink Models with the Legacy Code Tool
3-55
3 Writing S-Functions in C
To use the Legacy Code Tool to incorporate this C function into a Simulink
model as a C MEX S-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: {}
3-56
Integrating Existing C Functions into Simulink Models with the Legacy Code Tool
SourceFiles: {}
HostLibFiles: {}
TargetLibFiles: {}
IncPaths: {}
SrcPaths: {}
LibPaths: {}
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 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)';
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
directory.
3-57
3 Writing S-Functions in C
5 Use the legacy_code function to compile and link the S-function source
file into a dynamically loadable executable that Simulink can use. At the
MATLAB prompt, type:
legacy_code('compile', def);
legacy_code('slblock_generate', def);
3-58
Integrating Existing C Functions into Simulink Models with the Legacy Code Tool
3-59
3 Writing S-Functions in C
• Placing all required header and source files in the current working
directory or in a hierarchical directory structure
• Generating and placing one or more S-functions in the current working
directory
3-60
Integrating Existing C Functions into Simulink Models with the Legacy Code Tool
lct_spec = legacy_code('initialize')
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)
3-61
3 Writing S-Functions in C
For a complete list of the structure’s fields with descriptions, 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:
General syntax
return-spec = function-name(argument-spec)
For example, the following string specifies a function named doubleIt with
return specification double y1 and input argument specification double u1.
3-62
Integrating Existing C Functions into Simulink Models with the Legacy Code Tool
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
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.
3-63
3 Writing S-Functions in C
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 1 to ensure that the generated code remains safe in the
event that 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 state arguments of the existing C
function. The function’s input and output arguments map to Simulink input
and output ports, parameters map to Simulink workspace parameters, and
states map to Simulink Dwork vectors.
argument-type argument-token
If the function has no arguments, you can omit the argument specification
or specify it as void.
3-64
Integrating Existing C Functions into Simulink Models with the Legacy Code Tool
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.
3-65
3 Writing S-Functions in C
3-66
Integrating Existing C Functions into Simulink Models with the Legacy Code Tool
2 You must supply the header file that defines the data type only if the
numeric data type is also an alias.
4 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 complex (for example, complex<double>). For an example, see
sldemo_lct_cplxgain.
3-67
3 Writing S-Functions in C
6 For a multidimensional signal, you can use the size function to determine
the number of elements in the signal. For examples, see sldemo_lct_lut
and sldemo_lct_ndarray.
def.OutputFcnSpec=
'void foo(double p1[][], double u1[size(p1,2)], double y1[size(u1,1)], ...
3-68
Integrating Existing C Functions into Simulink Models with the Legacy Code Tool
legacy_code('sfcn_cmex_generate', lct_spec);
3 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);
3-69
3 Writing S-Functions in C
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:
3-70
Integrating Existing C Functions into Simulink Models with the Legacy Code Tool
defs1 = lct_register_1;
defs2 = lct_register_2;
defs3 = lct_register_3;
defs = [desfs1(:);defs2(:);defs3(:)];
You can then use the following sequence of calls to legacy_code 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);
3-71
3 Writing S-Functions in C
legacy_code('sfcn_tlc_generate', defs3);
3-72
How Simulink Interacts with C S-Functions
Process View
The following figures show the order in which Simulink invokes an
S-function’s callback methods. Solid rectangles indicate callbacks that always
occur during model initialization and/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 in Chapter 8, “S-Function Callback Methods — Alphabetical
List” to determine the exact circumstances under which Simulink invokes
the callback.
3-73
3 Writing S-Functions in C
3-74
How Simulink Interacts with C S-Functions
3-75
3 Writing S-Functions in C
For more information about Real-Time Workshop and how it interacts with
S-functions, see the Real-Time Workshop documentation and the “Real-Time
Workshop Target Language Compiler Reference Guide”.
Simulink calls mdlRTW once when it enters external mode and again each
time a parameter changes or when you select Update Diagram under your
model’s Edit menu.
3-76
How Simulink Interacts with C S-Functions
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
The following figure shows the general mapping between these various types
of data.
3-77
3 Writing S-Functions in C
• Via pointers
• Using contiguous inputs
InputRealPtrsType uPtrs =
ssGetInputPortRealSignalPtrs(S,portIndex)
*uPtrs[element]
3-78
How Simulink Interacts with C S-Functions
Note that input array pointers can point at noncontiguous places in memory.
You can retrieve the output signal by using this code.
real_T *y = ssGetOutputPortSignal(S,outputPortIndex);
3-79
3 Writing S-Functions in C
correct way to access input elements and write them to the output elements
(assuming the input and output ports have equal widths) is to use this code.
int_T element;
int_T portWidth = ssGetInputPortWidth(S,inputPortIndex);
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 Simulink. This is because it
is possible to access invalid memory (which depends on how you build your
model). When accessing the input signals incorrectly, a crash 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 you are correctly accessing wide input signals, pass a replicated
signal to each input port of your S-function. You do this by creating a Mux
block with the number of input ports equal to the width of the desired signal
entering your S-function. Then the driving source should be connected to each
input port as shown in this figure.
3-80
Writing Callback Methods
3-81
3 Writing S-Functions in C
mex -g timestwo.c
4 From the Microsoft Development Environment menu bar, select Tools >
Debug Processes.
3-82
Debugging C MEX S-Functions
b Click Attach.
b Click OK.
You should now be attached to the MATLAB process.
8 From the Microsoft Development Environment’s File menu, select Open >
File. Select the timestwo.c source files from the file browser that opens.
mex -g timestwo.c
3-83
3 Writing S-Functions in C
3 Exit MATLAB.
matlab -D<nameOfDebugger>
The -D flag starts MATLAB within the specified debugger. For example, to
use the dbx debugging tool on Solaris, enter the following command.
matlab -Ddbx
5 Once the debugger has loaded, continue loading MATLAB by typing run at
the debugger prompt.
(dbx) run
Running: matlab
(process id 9375)
dbmex on
(dbx) cont
3-84
Converting Level 1 C MEX S-Functions to Level 2
#define S_FUNCTION_LEVEL 2
3-85
3 Writing S-Functions in C
#define MDL_INITIALIZE_CONDITIONS
static void mdlInitializeConditions(SimStruct *S)
{
}
to
to
3-86
Converting Level 1 C MEX S-Functions to Level 2
#define MDL_UPDATE
static void mdlUpdate(SimStruct *S, int_T tid)
{
}
#define MDL_DERIVATIVES
static void mdlDerivatives(SimStruct *S, int_T tid)
{
}
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
3-87
3 Writing S-Functions in C
Obsolete Macros
The following macros are obsolete. Each obsolete macro should be replaced
with the specified macro.
ssGetY(S) ssGetOutputPortRealSignal(S,port)
ssGetSampleTimeEvent(S,sti) ssGetSampleTime(S,sti)
ssSetSampleTimeEvent(S,t) ssSetSampleTime(S,sti,t)
ssGetOffsetTimeEvent(S,sti) ssGetOffsetTime(S,sti)
ssSetOffsetTimeEvent(S,sti,t) ssSetOffsetTime(S,sti,t)
ssIsSampleHitEvent(S,sti,tid) ssIsSampleHit(S,sti,tid)
ssGetNumInputArgs(S) ssGetNumSFcnParams(S)
ssGetNumArgs(S) ssGetSFcnParamsCount(S)
ssGetArg(S,argNum) ssGetSFcnParam(S,argNum)
3-88
Converting Level 1 C MEX S-Functions to Level 2
3-89
3 Writing S-Functions in C
3-90
4
The procedure for creating C++ S-functions is nearly the same as that for
creating C S-functions (see Chapter 3, “Writing S-Functions in C”). The
following sections explain the differences.
To tell the compiler to use C calling conventions when compiling the callback
methods, wrap the C++ source for the S-function callback methods in an
extern "C" statement. The C++ version of the sfun_counter S-function
example (matlabroot/simulink/src/sfun_counter_cpp.cpp) illustrates
usage of the extern "C" directive to ensure that the compiler generates
Simulink-compatible callback methods:
/* File : sfun_counter_cpp.cpp
* Abstract:
*
* Example of an C++ S-function which stores an C++ object in
* the pointers vector PWork.
*
* Copyright 1990-2005 The MathWorks, Inc.
*
*/
#include "iostream.h"
class counter {
double x;
public:
counter() {
x = 0.0;
}
double output(void) {
x = x + 1.0;
return x;
}
};
#ifdef __cplusplus
4-2
Source File Format
#define S_FUNCTION_LEVEL 2
#define S_FUNCTION_NAME sfun_counter_cpp
/*
* Need to include simstruc.h for the definition of the SimStruct and
* its associated macro definitions.
*/
#include "simstruc.h"
/*====================*
* S-function methods *
*====================*/
ssSetNumContStates(S, 0);
ssSetNumDiscStates(S, 0);
ssSetNumSampleTimes(S, 1);
4-3
4 Creating C++ S-Functions
ssSetNumRWork(S, 0);
ssSetNumIWork(S, 0);
ssSetNumPWork(S, 1); // reserve element in the pointers vector
ssSetNumModes(S, 0); // to store a C++ object
ssSetNumNonsampledZCs(S, 0);
ssSetOptions(S, 0);
}
4-4
Source File Format
*/
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 use
y[0] = c->output(); // member functions of the
} // object
/*=============================*
* Required S-function trailer *
*=============================*/
#ifdef __cplusplus
} // end of extern "C" scope
#endif
4-5
4 Creating C++ S-Functions
2 Store a pointer to each object that you want to be persistent in the pointer
work vector:
4-6
Making C++ Objects Persistent
4-7
4 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 file’s contents as C++ code.
4-8
5
The following sections explain how to use the Ada programming language
to create S-functions.
Introduction
Simulink allows you to use the Ada programming language to create
S-functions. Simulink supports Ada S-functions on the following 32-bit
platforms.
• Windows (WIN32)
• Linux (GLNX86)
5-2
Ada S-Function Source File Format
The specification should also specify each callback method that the S-function
implements as an Ada procedure exported to C. The following is an example of
an Ada S-function specification that meets these requirements.
package Times_Two is
5-3
5 Creating Ada S-Functions
end Times_Two;
begin
-- Set the input port attributes
--
ssSetNumInputPorts( S, 1);
ssSetInputPortWidth( S, 0, DYNAMICALLY_SIZED);
ssSetInputPortDataType( S, 0, SS_DOUBLE);
ssSetInputPortDirectFeedThrough(S, 0, TRUE);
ssSetInputPortOverWritable( S, 0, FALSE);
ssSetInputPortOptimizationLevel(S, 0, 3);
5-4
Ada S-Function Source File Format
exception
when E : others =>
if ssGetErrorStatus(S) = "" then
ssSetErrorStatus(S,
"Exception occured in mdlInitializeSizes. " &
"Name: " & Exception_Name(E) & ", " &
"Message: " & Exception_Message(E) &
" and " & "Information: " &
Exception_Information(E));
end if;
end mdlInitializeSizes;
begin
if uWidth = 1 then
for Idx in 0 .. yWidth-1 loop
Y(Idx) := 2.0 * U(0);
end loop;
else
for Idx in 0 .. yWidth-1 loop
Y(Idx) := 2.0 * U(Idx);
end loop;
end if;
exception
5-5
5 Creating Ada S-Functions
end Times_Two;
5-6
Writing Callback Methods in Ada
5-7
5 Creating Ada S-Functions
Note When interacting with Ada S-functions, Simulink invokes only a subset
of the callback methods that it invokes for C S-functions. The “Languages
Supported” section of the reference page for each callback method specifies
whether Simulink invokes that callback when interacting with an Ada
S-function.
5-8
Writing Callback Methods in Ada
Implementing Callbacks
Simulink defines in a general way the task of each callback. The S-function
is free to perform the task according to the functionality it implements. For
example, Simulink specifies that the S-function’s mdlOutputs method must
compute that block’s outputs at the current simulation time. It does not
specify what those outputs must be. This callback-based API allows you to
create S-functions, and hence custom blocks, that meet your requirements.
SimStruct Functions
Simulink provides a set of functions that enable an Ada S-function to access
the internal data structure (SimStruct) that Simulink maintains for the
S-function. These functions consist of Ada wrappers around the SimStruct
macros used to access the SimStruct from a C S-function (see Chapter 9,
“SimStruct Functions — By Category”). Simulink provides Ada wrappers for
a substantial subset of the SimStruct macros. The “Languages Supported”
section of the reference page for a macro specifies whether it has an Ada
wrapper.
5-9
5 Creating Ada S-Functions
For example, to build the times_two S-function example that comes with
Simulink, enter the command
5-10
Example of an Ada S-Function
The following model uses the times_two S-function to double the amplitude
of a sine wave and plot it in a scope.
The block dialog for the S-function specifies times_two as the S-function
name; the parameters field is empty.
5-11
5 Creating Ada S-Functions
The source code for the times_two S-function comprises two parts:
• Package specification
• Package body
package Times_Two is
5-12
Example of an Ada S-Function
end Times_Two;
The package specification begins by specifying that the S-function uses the
Simulink package.
The Simulink package defines Ada procedures for accessing the internal
data structure (SimStruct) that Simulink maintains for each S-function (see
Chapter 9, “SimStruct Functions — By Category”).
The specification specifies that the Ada compiler should compile each method
as a C-callable function. This is because the Simulink engine assumes that
callback methods are C functions.
5-13
5 Creating Ada S-Functions
Note When building an Ada S-function, the MATLAB mex tool uses the
package specification to determine the callbacks that the S-function does not
implement. It then generates stubs for the nonimplemented methods.
5-14
Example of an Ada S-Function
begin
-- Set the input port attributes
--
ssSetNumInputPorts( S, 1);
ssSetInputPortWidth( S, 0, DYNAMICALLY_SIZED);
ssSetInputPortDataType( S, 0, SS_DOUBLE);
ssSetInputPortDirectFeedThrough(S, 0, TRUE);
ssSetInputPortOverWritable( S, 0, FALSE);
ssSetInputPortOptimizationLevel(S, 0, 3);
exception
when E : others =>
if ssGetErrorStatus(S) = "" then
ssSetErrorStatus(S,
"Exception occured in mdlInitializeSizes. " &
"Name: " & Exception_Name(E) & ", " &
5-15
5 Creating Ada S-Functions
begin
if uWidth = 1 then
for Idx in 0 .. yWidth-1 loop
Y(Idx) := 2.0 * U(0);
end loop;
else
for Idx in 0 .. yWidth-1 loop
Y(Idx) := 2.0 * U(Idx);
end loop;
end if;
exception
when E : others =>
if ssGetErrorStatus(S) = "" then
ssSetErrorStatus(S,
"Exception occured in mdlOutputs. " &
"Name: " & Exception_Name(E) & ", " &
"Message: " & Exception_Message(E) & " and " &
"Information: " & Exception_Information(E));
end if;
5-16
Example of an Ada S-Function
end mdlOutputs;
end Times_Two;
mdlInitializeSizes
Simulink calls mdlInitializeSizes to inquire about the number of input and
output ports, the sizes of the ports, and any other objects (such as the number
of states) needed by the S-function.
Finally the method provides an exception handler to handle any errors that
occur in invoking the SimStruct functions.
mdlOutputs
Simulink calls mdlOutputs at each time step to calculate a block’s outputs.
The times_two implementation of mdlOutputs takes the input, multiplies it
by 2, and writes the answer to the output.
5-17
5 Creating Ada S-Functions
Finally the method loops over the inputs to compute the outputs.
5-18
6
Creating Fortran
S-Functions
The following sections explain how to use the Fortran programming language
to create S-functions.
Introduction
There are two main strategies to executing Fortran code from Simulink. One
is from a Level 1 Fortran-MEX (F-MEX) S-function, the other is from a Level
2 gateway S-function written in C. Each has its advantages and both can be
incorporated into code generated by Real-Time Workshop. To have complete
code generation with Real-Time Workshop, you must inline the Fortran
S-function. See “Inlining S-Functions” in the Target Language Compiler
documentation for more information.
6-2
Creating Level 1 Fortran S-Functions
3 Compile the edited file into a MEX-file, using the mex command.
C
C File: SFUN_TIMESTWO_FOR.F
C
C Abstract:
C A sample Level 1 FORTRAN representation of a
C timestwo S-function.
C
C The basic mex command for this example is:
C
C >> mex sfun_timestwo_for.F simulink.F
C
6-3
6 Creating Fortran S-Functions
SIZE(1) = 0
SIZE(2) = 0
SIZE(3) = 1
SIZE(4) = 1
SIZE(5) = 0
SIZE(6) = 1
6-4
Creating Level 1 Fortran S-Functions
RETURN
END
C
C=====================================================
C
C Function: OUTPUT
C
C Abstract:
C Perform output calculations for continuous
C signals.
C
C=====================================================
C .. Parameters ..
SUBROUTINE OUTPUT(T, X, U, Y)
REAL*8 T
REAL*8 X(*), U(*), Y(*)
RETURN
END
C
C=====================================================
C
C Stubs for unused functions.
C
C=====================================================
SUBROUTINE INITCOND(X0)
REAL*8 X0(*)
C --- Nothing to do.
RETURN
END
6-5
6 Creating Fortran S-Functions
END
SUBROUTINE DOUTPUT(T, X, U, Y)
REAL*8 T, X(*), U(*), Y(*)
C --- Nothing to do.
RETURN
END
sfcndemo_timestwo_for
6-6
Creating Level 1 Fortran S-Functions
6-7
6 Creating Fortran S-Functions
Using the C MEX S-function as a gateway is quite simple if you are writing
the Fortran code from scratch. If instead your Fortran code already exists as a
stand-alone simulation, there is some work to be done to identify parts of the
code that need to be registered with Simulink, 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
“Porting Legacy Code” on page 6-19).
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.
MEX Environment
Remember that mex -setup needs to find both the MATLAB C and the
Fortran compilers, but it can work with only one of these compilers at a time.
If you install or change compilers, you must run mex -setup between other
mex commands.
6-8
Creating Level 2 Fortran S-Functions
Test the installation and setup using sample MEX-files from the MATLAB C
and Fortran MEX examples in matlabroot/extern/examples/mex, as well as
Simulink examples, which are located in matlabroot/simulink/src.
cd([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([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. Compaq Visual Fortran (formerly known as Digital
Fortran) is one compiler whose default stack cleanup is the callee. However,
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
6-9
6 Creating Fortran S-Functions
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 Windows as well. MKS is one
company that has commercial versions of powerful UNIX utilities, although
most 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 Linux.
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/Linux
0001522 .symtab
0001532 .strtab
0001542 .shstrtab
0001554 .text
0001562 .rel.text
0001574 .data
0001602 .bss
0001607 .note
0001615 .comment
6-10
Creating Level 2 Fortran S-Functions
0003071 sfun_atmos_for.for
0003101 gcc2_compiled.
0003120 rearth.0
0003131 gmr.1
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 Compaq Visual Fortran and Intel Visual Fortran on 32-bit Windows
machines, the symbol is suppressed, so that Atmos becomes ATMOS (no
underscore).
Note On UNIX, 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.
6-11
6 Creating Fortran S-Functions
The f2c package can be obtained for 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/C++ and Intel® Visual
Fortran 9.0 (formerly known as Compaq Visual Fortran), this example can be
compiled using the following mex commands (each command is on one line).
On 64-bit Windows machines, using Microsoft Visual C/C++ and Intel® Visual
Fortran 9.0 (formerly known as Compaq Visual Fortran), this example can be
compiled using the following mex commands (each command is on one line).
6-12
Creating Level 2 Fortran S-Functions
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.
For Sun (Solaris) and other commercial UNIX platforms, you can purchase
the computer vendor’s Fortran compiler, a third-party Fortran such as Absoft,
or even use the Gnu Fortran port for that platform (if available).
As long as the compiler can output the same object (.o) format as the
platform’s C compiler, the Fortran compiler will work with the gateway C
MEX S-function technique.
Gnu Fortran (g77) can be obtained free for several platforms from many
download sites, including tap://www.redhat.com in the download area. A
useful keyword on search engines is g77.
6-13
6 Creating 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 instead the code needs to have continuous time states with support for
variable-step solvers, the states must be registered and stored with Simulink
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-14
Creating Level 2 Fortran S-Functions
consists of three steps. The first is trivial; the second and third can take
a bit of examination.
2 Identify variables that need to be inputs and outputs and put them in the
SUBROUTINE argument list or in a COMMON block.
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.
6-15
6 Creating Fortran S-Functions
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
6-16
Creating Level 2 Fortran S-Functions
sfcndemo_atmos
If the linker finds multiple C libraries, you might need to add the option
/NODEFAULTLIB:libc.lib to the command to avoid an error. For example:
6-17
6 Creating Fortran S-Functions
On some UNIX systems where the C and Fortran compilers were installed
separately (or aren’t 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-18
Porting Legacy Code
If it is impractical to find all the implicit states and to separate out the
derivative calculations for Simulink, 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 Simulink major 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
matlabroot/simulink/src/sfuntmpl_gate_fortran.c for an example that
uses DWork vectors.
6-19
6 Creating Fortran S-Functions
Sample Times
If the code has an implicit step size in its algorithm, coefficients,
etc., ensure that you register the proper discrete sample time in the
mdlInitializeSampleTimes() S-function method and only change the block’s
output values from the mdlUpdate() method.
Multiple Instances
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 matlabroot/simulink/include/simstruc.h and
matlabroot/simulink/src/sfuntmpl_doc.c for details on allocating
data-typed work vectors.
DOUBLE PRECISION F
:
:
F = F + 1.0
TIME = 0.003 * F
6-20
Porting Legacy Code
6-21
6 Creating Fortran S-Functions
6-22
7
Implementing Block
Features
7-2
Dialog Parameters
Dialog Parameters
A user can pass parameters to an S-function at the start of and, optionally,
during the simulation, using the S-Function parameters field of the
block’s 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 “Run-Time Parameters” on page 7-8). Simulink
stores the values of the dialog box parameters in the S-function’s SimStruct
structure. Simulink provides callback methods and SimStruct macros that
allow the S-function to access and check the parameters and use them in
the computation of the block’s output.
If you want your S-function to be able to use dialog parameters, you must
perform the following steps when you create the S-function:
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.
#define SIGNS_IDX 0
#define SIGNS_PARAM(S) ssGetSFcnParam(S,SIGNS_IDX) /* First 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 */
7-3
7 Implementing Block Features
When running a simulation, the user must specify the parameters in the
S-Function parameters field of the block’s dialog box in the same order that
you defined them in step 1. The user can enter any valid MATLAB expression
as the value of a parameter, including literal values, names of workspace
variables, function invocations, or arithmetic expressions. Simulink evaluates
the expression and passes its value to the S-function.
Note You cannot use the Model Explorer, the S-Function block 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. See “Changing
Source Block Parameters During Simulation” for more information.
7-4
Dialog Parameters
/* 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, a user enters four variable names or values
in the S-Function parameters field of the block’s 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. Use
the macro ssSetSFcnParamTunable in mdlInitializeSizes to specify the
tunability of each dialog parameter used by the macro.
7-5
7 Implementing Block Features
#if defined(MATLAB_MEX_FILE)
if (ssGetNumSFcnParams(S) == ssGetSFcnParamsCount(S)) {
mdlCheckParameters(S);
if (ssGetErrorStatus(S) != NULL) {
return;
}
} else {
return; /* Parameter mismatch will be reported by Simulink */
}
#endif
ssSetSFcnParamTunable(S,GAIN_IDX,true); /* Tunable */
ssSetSFcnParamTunable(S,SIGNS_IDX,false); /* Not tunable */
ssSetSFcnParamTunable(S,OUT_IDX,false); /* Not tunable */
7-6
Dialog Parameters
(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 Target Language Compiler Reference Guide.
7-7
7 Implementing Block Features
Run-Time Parameters
Simulink allows an S-function to create internal representations of external
dialog parameters called run-time parameters. Every run-time parameter
corresponds to one or more dialog parameters and can have the same value
and data type as its corresponding external parameters or a different value
or data type. If a run-time parameter differs in value or data type from its
external counterpart, the dialog parameter is said to have been transformed
to create the run-time parameter. The value of a run-time parameter that
corresponds to multiple dialog parameters is typically a function of the values
of the dialog parameters. Simulink allocates and frees storage for run-time
parameters and provides functions for updating and accessing them, thus
eliminating the need for S-functions to perform these tasks.
• 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 weight of the object. In this case, the weight 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.
• 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 parameter and the input and
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, Real-Time Workshop 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.
7-8
Run-Time Parameters
The following Simulink model contains three example S-functions that create
run-time parameters:
matlabroot/toolbox/simulink/simdemos/simfeatures/sfcndemo_runtime.mdl
Note The first four characters of the names of a block’s run-time parameters
must be unique. If they are not, Simulink signals an error. For example, trying
to register a parameter named param2 triggers an error if a parameter named
param1 already exists. This restriction allows Real-time Workshop to generate
variable names that are unique within a pre-specified number of characters.
7-9
7 Implementing Block Features
7-10
Run-Time Parameters
p.nDimensions = 2;
p.dimensions = (int_T *) mxGetDimensions(GAIN_PARAM(S));
p.dataTypeId = SS_DOUBLE;
p.complexSignal = COMPLEX_NO;
p.data = (void *)mxGetPr(GAIN_PARAM(S));
p.dataAttributes = NULL;
p.nDlgParamIndices = 1;
p.dlgParamIndices = &dlgP
p.transformed = false;
p.outputAsMatrix = false;
7-11
7 Implementing Block Features
Note that you cannot tune a runtime parameter whose value is a cell array
or structure.
7-12
Creating Input and Output Ports
• The dimensions of the input port (see “Initializing Input Port Dimensions”
on page 7-14)
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 7-15).
• Whether the input port allows scalar expansion of inputs (see “Scalar
Expansion of Inputs” on page 7-18)
• 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 Simulink 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
7-13
7 Implementing Block Features
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.
• The numeric type of the input port, if the port accepts complex-valued
signals
Use ssSetInputPortComplexSignal to set the input port’s numeric type.
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 must provide implementations of the
mdlSetInputPortComplexSignal and mdlSetDefaultPortComplexSignals
methods to enable the numeric type to be set correctly during signal
propagation.
You can configure additional input port properties using other S-function
macros. See “Input and Output Ports” on page 9-6 in the “SimStruct Macros
and Functions Listed by Usage” section for more information.
• If the input signal must be one-dimensional and the input port width
is w, use
ssSetInputPortWidth(S, inputPortIdx, w)
ssSetInputPortMatrixDimensions(S, inputPortIdx, m, n)
7-14
Creating Input and Output Ports
• Otherwise, if the input signal can have either one or two dimensions, use
You can use this function to fully or partially initialize the port dimensions
(see next section).
• Specify some or all of the dimensions of the input port as dynamically sized
in mdlInitializeSizes.
If the input port can accept a signal of any dimensionality, use
ssSetInputPortMatrixDimensions(S, inputPortIdx, m, n)
7-15
7 Implementing Block Features
7-16
Creating 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
- ssSetOutputPortMatrixDimensions
- ssSetOutputPortVectorDimension
- ssSetOutputPortWidth
If you want the port’s dimensions to depend on block connectivity, set the
dimensions to DYNAMICALLY_SIZED. 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. For more detail on how to set up output port
dimensions, see “Initializing Input Port Dimensions” on page 7-14. The
process you use to set up output ports is identical to the process shown in
that section for initializing and dimensioning input ports, but using macros
appropriate to output ports.
7-17
7 Implementing Block Features
See “Creating Input Ports” on page 7-13 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.
7-18
Creating Input and Output Ports
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, Simulink 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 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, Simulink ignores the scalar expansion
option.
int_T port;
real_T sum = 0.0;
for (port = 0; port < nInputPorts; port++) {
/* Get the input signal value */
InputRealPtrsType uPtrs =
7-19
7 Implementing Block Features
ssGetInputPortRealSignalPtrs(S,port);
} else {
/* Use the scalar value to expand the signal */
sum = sum + ((real_T)signs[port] * (*uPtrs[0]));
}
}
}
set_param(blockname,'MaskSelfModifiable','on')
at the MATLAB 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 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.
7-20
Custom Data Types
3 Specify the value that represents zero for the data type, using
ssSetDataTypeZero.
/* Define variables
int_T status;
DTypeId id;
myStruct tmp;
7-21
7 Implementing Block Features
Note If a signal with an aliased data type is passed to the S-function and
the S-function creates a data type ID for it using ssRegisterDataType, the
S-function should not set the size or zero representation for that data type.
See Simulink.AliasType for a discussion on aliased data types.
Note You cannot generate Real-Time Workshop code for S-functions that
contain macros to define custom data types. You must use an inlined
S-function that accesses Target Language Compiler functions to generate
code with custom data types. See “Inlining S-Functions” in the Real-Time
Workshop Target Language Compiler documentation.)
7-22
Sample Times
Sample Times
This section explains how to specify the sample-time behavior of your function,
e.g., whether it inherits its rates from the blocks that drive it or defines its
own rates and, if it defines its own rates, what the rates are.
For example, consider two sample rates, 0.5 and 0.25 seconds, respectively:
• In the block-based method, selecting 0.5 and 0.25 would direct the block to
execute inputs and outputs at 0.25 second increments.
• In the port-based method, you could set the input port to 0.5 and the output
port to 0.25, and the block would 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 don’t want the overhead
associated with running input and output ports at the highest sample rate
of your block.
7-23
7 Implementing Block Features
• mdlInitializeSizes
• mdlInitializeSampleTimes
ssSetNumSampleTimes(S,numSampleTimes);
where numSampleTimes > 0. This tells Simulink that your S-function has
block-based sample times. Simulink calls mdlInitializeSampleTimes, which
in turn sets the sample times.
7-24
Sample Times
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
7-25
7 Implementing Block Features
[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 submodel, i.e., a model referenced by
another model. See “Specifying Model Reference Sample Time Inheritance”
on page 7-37 for more information.
[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:
7-26
Sample Times
• 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 (that is, 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, if your
first sample time is continuous, then you use the following code fragment
to check for a sample hit. Note that you get incorrect results if you use
ssIsSampleHit(S,0,tid).
if (ssIsContinuousTask(S,tid)) {
}
If, for example, you wanted to determine whether the third (discrete) task has
a hit, you would use the following code fragment:
if (ssIsSampleHit(S,2,tid) {
}
Example: mdlInitializeSampleTimes
This example specifies that there are two discrete sample times with periods
of 0.01 and 0.5 seconds.
7-27
7 Implementing Block Features
ssSetNumSampleTimes(S, PORT_BASED_SAMPLE_TIMES)
You must also specify the sample time of each input and output port in the
S-function’s mdlInitializeSizes method, using the following macros
ssSetInputPortSampleTime(S, 0, 0.1);
ssSetInputPortOffsetTime(S, 0, 0);
• Inherited sample time, 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 7-29)
• Constant sample time, i.e., the port’s input or output never changes (see
“Specifying Constant Sample Time for a Port” on page 7-30)
7-28
Sample Times
Port-based sample times cannot be used with S-functions that have neither
input ports nor output ports. If an S-function uses port-based sample times
and has no ports, the S-function produces errors when the Simulink model
is updated or run. If the number of input or output ports on an S-function is
variable, extra protection should be added into the S-function to ensure the
total number of ports does not go to zero.
The setup method should not specify a sample time for the block when using
port-based sample times.
ssSetInputPortSampleTime(S, 0, -1);
ssSetInputPortOffsetTime(S, 0, 0);
7-29
7 Implementing Block Features
if (!ssGetInputPortSampleTime(S,0) {
ssSetErrorStatus(S,"Cannot inherit a continuous sample time.");
}
Note If you specify that your S-function’s ports inherit their sample time, you
should also specify whether it is safe to use the S-function in a submodel,
i.e., a model referenced by another model. See “Specifying Model Reference
Sample Time Inheritance” on page 7-37 for more information.
Before specifying constant sample time for an output port whose output
depends on the S-function’s parameters, the S-function should use
ssGetInlineParameters to check whether the user has specified the Inline
parameters option on the Optimization pane of the Configuration
parameters dialog box. If the user has not checked this option, it is possible
for the user to change the values the S-function’s parameters and hence
its outputs during the simulation. In this case, the S-function should not
specify a constant sample time for any ports whose outputs depend on the
S-function’s parameters.
To specify constant sample time for a port, the S-function must perform the
following tasks
7-30
Sample Times
ssSetOptions(S, SS_OPTION_ALLOW_CONSTANT_PORT_SAMPLE_TIME);
ssSetInputPortSampleTime(S, 0, mxGetInf());
ssSetInputPortOffsetTime(S, 0, 0);
ssSetOptions(S,
SS_OPTION_ALLOW_PORTh_SAMPLE_TIME_IN_TRIGSS);
7-31
7 Implementing Block Features
• Set all of its ports to have either inherited or constant sample time in its
mdlInitializeSizes method.
• Handle inheritance of a triggered sample time in
mdlSetInputPortSampleTime and mdlSetOutputPortSampleTime methods
as follows.
Since the S-function’s ports inherit their sample times,
Simulink 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).
Setting a port’s sample time and offset both to INHERITED_SAMPLE_TIME
indicates that the sample time of the port is triggered, i.e., it produces an
output or accepts an input only when the subsystem in which it resides is
triggered. The method must then also set the sample times and offsets of
all of the S-function’s other input and output ports to have either triggered
or constant sample time, whichever is appropriate, e.g.,
if (ssSampleAndOffsetAreTriggered(sampleTime,offsetTime)) {
ssSetOutputPortSampleTime(S, 0, INHERITED_SAMPLE_TIME);
ssSetOutputPortOffsetTime(S, 0, INHERITED_SAMPLE_TIME);
7-32
Sample Times
ssSetSampleTime
ssSetOffsetTime
Finally, as in the port-based method, you specify the rates for each port, using
7-33
7 Implementing Block Features
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
matlabroot/simulink/src/mixedm.c.
For example, these statements 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)) {
}
7-34
Sample Times
The second argument, 1, corresponds to the second sample time, 0.75 second.
ssSetNumSampleTimes(S, 1);
In the second sample time, the offset causes Simulink 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.
7-35
7 Implementing Block Features
ssSetNumSampleTimes(S, 2);
Suppose, for example, that your model has an input port operating at one rate,
0, and an output port operating at a slower rate, 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 (ssISampleHit(S, 0, tid) {
if (ssIsSpecialSampleHit(S, 0, 1, tid) {
/* Transfer input to output memory. */
...
}
}
if (ssIsSampleHit(S, 1, tid) {
/* Emit output. */
...
}
In this example, the first block runs when a sample hit occurs at the input
rate. If the hit also occurs at the output rate, the block transfers the input to
the output memory. The second block runs when a sample hit occurs at the
output rate. It transfers the output in its memory area to the block’s output.
Note that higher-rate tasks always run before slower-rate tasks. Thus, the
input task in the preceding example always runs before the output task,
ensuring that valid data is always present at the output port.
7-36
Sample Times
Note If your S-function does not set this flag, Simulink assumes that it
does not preclude a submodel containing it from inheriting a sample time.
However, Simulink optionally warns the user that the submodel contains
S-functions that do not specify a sample-time inheritance rule (see “Blocks
That Preclude Sample-Time Inheritance” in the online Simulink help).
• ssGetSampleTime
• ssGetInputPortSampleTime
• ssGetOutputPortSampleTime
• ssGetInputPortOffsetTime
• ssGetOutputPortOffsetTime
• ssGetSampleTimePtr
• ssGetInputPortSampleTimeIndex
• ssGetOutputPortSampleTimeIndex
• ssGetSampleTimeTaskID
• ssGetSampleTimeTaskIDPtr
7-37
7 Implementing Block Features
or TLC functions:
• LibBlockSampleTime
• CompiledModel.SampleTime
• LibBlockInputSignalSampleTime
• LibBlockInputSignalOffsetTime
• LibBlockOutputSignalSampleTime
• LibBlockOutputSignalOffsetTime
If the 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
submodels that inherit their sample time.
This 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
submodel. For this reason, this S-function should specify its model reference
inheritance rule as follows:
ssSetModelReferenceSampleTimeInheritanceRule
(S, DISALLOW_SAMPLE_TIME_INHERITANCE);
7-38
Work Vectors
Work Vectors
Work vectors are blocks of memory that an S-function can ask Simulink to
allocate to each instance of the S-function in a model. If multiple instances
of your S-function can occur in a model, your S-function must use work
vectors instead of global or static memory to store instance-specific values of
S-function variables. Otherwise, your S-function runs the risk of one instance
overwriting data needed by another instance, causing a simulation to fail or
produce incorrect results.The ability to keep track of multiple instances of
an S-function is called reentrancy.
You can create an S-function that is reentrant by using work vectors that
Simulink manages for each particular instance of the S-function. Integer,
floating-point (real), pointer, and general data types are supported. The
number of elements in each vector can be specified dynamically as a function
of the number of inputs to the S-function.
For example, suppose you’d like to track the previous value of each input signal
element entering input port 1 of your S-function. Either the discrete-state
vector or the real-work vector could be used for this, depending upon whether
the previous value is considered a discrete state (that is, compare the unit
delay and the memory block). If you do not want the previous value to
be logged when states are saved, use the real-work vector, rwork. To do
this, in mdlInitializeSizes specify the length of this vector by using
ssSetNumRWork. Then in either mdlStart or mdlInitializeConditions,
initialize the rwork vector using ssSetRWorkValue. In mdlOutputs, you can
retrieve the previous inputs by using ssGetRWork. In mdlUpdate, update the
previous value of the rwork vector by using ssGetInputPortRealSignalPtrs.
See matlabroot/simulink/src/sfunmem.c for an example using the rwork
vector.
7-39
7 Implementing Block Features
Use the macros in this table to specify the length of the work vectors for each
instance of your S-function in mdlInitializeSizes.
Macro Description
ssSetNumContStates Width of the continuous-state vector
ssSetNumDiscStates Width of the discrete-state vector
ssSetNumDWork Width of the data type work vector
ssSetNumRWork Width of the real-work vector
ssSetNumIWork Width of the integer-work vector
ssSetNumPWork Width of the pointer-work vector
ssSetNumModes Width of the mode-work vector
ssSetNumNonsampledZCs Width of the nonsampled zero-crossing
vector
• 0 (the default). This indicates that the vector is not used by your S-function.
• A positive nonzero integer. This is the width of the vector that is available
for use by mdlStart, mdlInitializeConditions, and S-function routines
called in the simulation loop.
• The DYNAMICALLY_SIZED define. The default behavior for dynamically
sized vectors is to set them to the overall block width. Simulink does this
after propagating line widths and sample times. The block width is the
width of the signal passing through your block. In general this is equal to
the output port width.
If the default behavior of dynamically sized vectors does not meet your
needs, use mdlSetWorkWidths and the macros listed in Macros Used in
Specifying Vector Widths on page 7-40, to set the sizes of the work vectors
explicitly. mdlSetWorkWidths also allows you to set your work vector lengths
as functions of the block sample time and/or port widths.
7-40
Work Vectors
The continuous states are used when you have a state that needs to be
integrated by one of the Simulink solvers. When you specify continuous states,
you must return the states’ derivatives in mdlDerivatives. The discrete state
vector is used to maintain state information that changes at fixed intervals.
Typically the discrete state vector is updated in place in mdlUpdate.
The integer, real, and pointer work vectors are storage locations that are
not logged by Simulink during simulations. They maintain persistent data
between calls to your S-function.
First, mdlInitializeSizes specifies the sizes for the mode and nonsampled
zero-crossing vectors using the following lines of code.
ssSetNumModes(S, DYNAMICALLY_SIZED);
ssSetNumNonsampledZCs(S, DYNAMICALLY_SIZED);
7-41
7 Implementing Block Features
nModes = numOutput;
nNonsampledZCs = 2 * numOutput;
ssSetNumModes(S,nModes);
ssSetNumNonsampledZCs(S,nNonsampledZCs);
}
7-42
Work Vectors
mode[iOutput] = LowerLimitEquation;
} else {
/* Output is not limited. */
mode[iOutput] = NonLimitEquation;
}
} /* end IsMajorTimeStep */
Output calculations in mdlOutputs are finally done based on the values stored
in the mode vector.
} else {
/* Output is equal to input */
*y++ = *uPtrs[uIdx];
}
7-43
7 Implementing Block Features
and recalculates the outputs to try to locate the exact zero crossing. For this
example, the values for the nonsampled zero-crossing vectors are calculated
as shown below.
/* 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 );
7-44
Work Vectors
The following code uses the pointer-work vector to store a FILE pointer,
returned from the standard I/O function fopen.
This code retrieves the FILE pointer from the pointer-work vector and passes
it to fclose to close the file.
Note If you are using mdlSetWorkWidths, any work vectors you use in your
S-function should be set to DYNAMICALLY_SIZED in mdlInitializeSizes, even
if the exact value is known before mdlInitializeSizes is called. The size to
be used by the S-function should be specified in mdlSetWorkWidths.
The synopsis is
7-45
7 Implementing Block Features
Memory Allocation
When you are creating an S-function, the available work vectors might not
provide enough capability. In this case, you 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 MATLAB and not Simulink. 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 pointer-work vector elements
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 *prt = ssGetUserData(S);
free(prt);
7-46
Function-Call Subsystems
Function-Call Subsystems
You can create a triggered subsystem whose execution is determined by logic
internal to an S-function instead of by the value of a signal. A subsystem so
configured is called a function-call subsystem. To implement a function-call
subsystem:
7-47
7 Implementing Block Features
ssSetExplicitFCSSCtrl(S, 1);
7-48
Function-Call Subsystems
7-49
7 Implementing Block Features
When the Pulse Generator emits its upper value, the function-call subsystem
connected to the first element of the S-function’s first 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 Scope, below.
7-50
Function-Call Subsystems
7-51
7 Implementing Block Features
You can use your S-function as a sim viewing device in external mode if it
satisfies the following conditions.
ssSetOptions(S, SS_OPTION_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”in the Real-Time Workshop documentation.
7-52
Processing Frame-Based Signals
Note Simulating a model containing the S-function that you develop requires
a Signal Processing Blockset license.
ssSetNumInputPorts(S, 1);
ssSetInputPortFrameData(S, 0, FRAME_YES);
ssSetNumOutputPorts(S,1);
ssSetOutputPortFrameData(S, 0, FRAME_NO);
• The S-function should specify the dimensions of the signals that its
frame-based ports accept or produce in its mdlInitializeSizes or
mdlSetInputPortDimensionInfo and mdlSetOutputPortDimensionInfo
callback methods. Note that frame-based signals must be dimensioned as
2-D arrays. For example, the following code in mdlInitializeSizes specifies
that the first frame-based input port is dynamically sized. This S-function
must then also have an mdlSetInputPortDimensionInfo callback that sets
the specific dimensions of this input port.
7-53
7 Implementing Block Features
ssSetNumInputPorts(S, 1);
ssSetInputPortFrameData(S, 0, FRAME_YES);
ssSetInputPortMatrixDimensions(S, 0, DYNAMICALLY_SIZED, DYNAMICALLY_SIZED);
• If the frame status of any of the S-function’s input ports is inherited, the
S-function should define a mdlSetInputPortFrameData callback method.
Simulink passes the frame status that it assigns to the port, based on frame
signal propagation rules, as an argument to this callback method. The
callback method should in turn use the ssSetInputPortFrameData function
to set the port to the assigned status if it is acceptable or signal an error
using ssSetErrorStatus if it is not. If the frame status of other ports of the
S-function depend on the status inherited by one of its input ports, the
callback method can also use ssSetInputPortFrameData to set the frame
status of the other ports based on the status that the input port inherits. A
template for the mdlSetInputPortFrameData callback is shown below.
#if defined(MATLAB_MEX_FILE)
#define MDL_SET_INPUT_PORT_FRAME_DATA
static void mdlSetInputPortFrameData(SimStruct *S,
int_T portIndex,
Frame_T frameData)
{
if(!frameData==FRAME_YES) {
ssSetErrorStatus(S, "Incorrect frame status");
return;
}
ssSetInputPortFrameData(S, portIndex, frameData); /* Sets frame status */
} /* end mdlSetInputPortFrameData */
#endif
7-54
Processing Frame-Based Signals
7-55
7 Implementing Block Features
Handling Errors
When working with S-functions, it is important to handle unexpected events
such as invalid parameter values correctly.
If your S-function has parameters whose contents you need to validate, use
the following technique to report errors encountered.
mdlOutputs()
{
char msg[256]; /* ILLEGAL: should be "static char */
/*msg[256];"*/
sprintf(msg,"Error due to %s", string);
ssSetErrorStatus(S,msg);
return;
}
7-56
Handling Errors
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);
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
7-57
7 Implementing Block Features
Code in run-time routines can also throw exceptions. Run-time routines refer
to certain S-function routines that Simulink calls during the simulation
loop (see “How Simulink Interacts with C S-Functions” on page 3-73). 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);
7-58
Handling Errors
To enable array bounds checking, select warning or error from the Array
bounds exceeded options list in the Debugging group on the Diagnostics
-Data Validity pane of the Configuration Parameters dialog box or enter
the following command at the MATLAB command line.
where modelName is the name of the Simulink model and ValueStr is either
'none', 'warning', or 'error'.
7-59
7 Implementing Block Features
S-Function Examples
Most S-Function blocks require the handling of states, continuous or discrete.
The following sections discuss common types of systems that you can model in
Simulink with S-functions:
7-60
S-Function Examples
Note that csfunc.c 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 isn’t 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/simulink/src/csfunc.c
The beginning of each S-function must include #define statements for
the S-function’s name and level, along with a #include statement for the
simstruc.h header. Following these statements, the S-function can include
or define any other necessary headers, data, etc. In the csfunc.c example
shown below, in addition to the required statements, U is defined as elements
in the pointer to the first input port’s signal and static variables containing
the state-space matrices are initialized.
/* File : csfunc.c
* Abstract:
*
* Example C-file 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-2007 The MathWorks, Inc.
*/
7-61
7 Implementing Block Features
#include "simstruc.h"
7-62
S-Function Examples
• Next, the method configures the S-function to have a single input and
output port, each with a width of two to match the dimensions of the
state-space matrices. Note that the input port is also set to have direct
feedthrough by passing a value of 1 to ssSetInputPortDirectFeedThrough.
• ssSetNumSampleTimes then specifies that there is one sample time, which
will be configured later in the mdlInitializeSampleTimes function.
• A value of 0 is passed to ssSetNumRWork, ssSetNumIWork, etc., to indicate that
none of the work vectors are used by this S-function. Note that these lines
could be omitted since zero is the default value for all of these macros. For
clarity, it is preferable to explicitly set the number of work vectors.
• Lastly, any applicable options are set using ssSetOptions. In this case, the
only option is SS_OPTION_EXCEPTION_FREE_CODE, which stipulates that
the code is exception free.
/*====================*
* S-function methods *
*====================*/
ssSetNumContStates(S, 2);
ssSetNumDiscStates(S, 0);
7-63
7 Implementing Block Features
ssSetNumSampleTimes(S, 1);
ssSetNumRWork(S, 0);
ssSetNumIWork(S, 0);
ssSetNumPWork(S, 0);
ssSetNumModes(S, 0);
ssSetNumNonsampledZCs(S, 0);
7-64
S-Function Examples
#define MDL_INITIALIZE_CONDITIONS
/* Function: mdlInitializeConditions ========================================
* Abstract:
* Initialize both continuous states to zero.
*/
static void mdlInitializeConditions(SimStruct *S)
{
real_T *x0 = ssGetContStates(S);
int_T lp;
for (lp=0;lp<2;lp++) {
*x0++=0.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);
}
7-65
7 Implementing Block Features
continuous states, state derivatives, and first input port. The data in these
arrays is then used to solve the equation dx=Ax+Bu.
#define MDL_DERIVATIVES
/* Function: mdlDerivatives =================================================
* Abstract:
* 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 trailer of this S-function must include the files necessary for simulation
or code generation, as follows.
7-66
S-Function Examples
matlabroot/simulink/src/dsfunc.c
The beginning of each S-function must include #define statements for
the S-function’s name and level, along with a #include statement for the
simstruc.h header. Following these statements, the S-function can include
or define any other necessary headers, data, etc. In the dsfunc.c example
shown below, in addition to the required statements, U is defined as elements
7-67
7 Implementing Block Features
in the pointer to the first input port’s signal and static variables containing
the state-space matrices are initialized.
/* File : dsfunc.c
* Abstract:
*
* Example C-file 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-2007 The MathWorks, Inc.
*/
#include "simstruc.h"
7-68
S-Function Examples
/*====================*
* S-function methods *
*====================*/
7-69
7 Implementing Block Features
*/
static void mdlInitializeSizes(SimStruct *S)
{
ssSetNumSFcnParams(S, 0); /* Number of expected parameters */
if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
return; /* Parameter mismatch will be reported by Simulink */
}
ssSetNumContStates(S, 0);
ssSetNumDiscStates(S, 2);
ssSetNumSampleTimes(S, 1);
ssSetNumRWork(S, 0);
ssSetNumIWork(S, 0);
ssSetNumPWork(S, 0);
ssSetNumModes(S, 0);
ssSetNumNonsampledZCs(S, 0);
7-70
S-Function Examples
*/
static void mdlInitializeSampleTimes(SimStruct *S)
{
ssSetSampleTime(S, 0, 1.0);
ssSetOffsetTime(S, 0, 0.0);
ssSetModelReferenceSampleTimeDefaultInheritance(S);
}
#define MDL_INITIALIZE_CONDITIONS
/* Function: mdlInitializeConditions ========================================
* Abstract:
* Initialize both discrete states to one.
*/
static void mdlInitializeConditions(SimStruct *S)
{
real_T *x0 = ssGetRealDiscStates(S);
int_T lp;
for (lp=0;lp<2;lp++) {
*x0++=1.0;
}
}
7-71
7 Implementing Block Features
{
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 mdlUpdate function is called once every major integration time step to
update the discrete states’ values. Since this is an optional method, it must
be proceeded by a #define statement. The beginning of the function obtains
pointers to the S-function’s discrete states and first input port. The data in
these arrays is then used 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];
}
7-72
S-Function Examples
The trailer of this S-function must include the files necessary for simulation
or code generation, as follows.
7-73
7 Implementing Block Features
you need to check for sample hits to determine at what point your
S-function is being called.
matlabroot/simulink/src/mixedm.c
The beginning of each S-function must include #define statements for
the S-function’s name and level, along with a #include statement for the
simstruc.h header. Following these statements, the S-function can include
or define any other necessary headers, data, etc. In the mixedm.c example
shown below, in addition to the required statements, U is defined as elements
in the 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.
*/
7-74
S-Function Examples
#include "simstruc.h"
7-75
7 Implementing Block Features
*====================*
* S-function methods *
*====================*/
ssSetNumContStates(S, 1);
ssSetNumDiscStates(S, 1);
ssSetNumRWork(S, 1); /* for zoh output feeding the delay operator */
ssSetNumSampleTimes(S, 2);
7-76
S-Function Examples
SS_OPTION_PORT_SAMPLE_TIMES_ASSIGNED));
} /* end mdlInitializeSizes */
ssSetSampleTime(S, 1, 1.0);
ssSetOffsetTime(S, 1, 0.0);
ssSetModelReferenceSampleTimeDefaultInheritance(S);
} /* end mdlInitializeSampleTimes */
#define MDL_INITIALIZE_CONDITIONS
/* Function: mdlInitializeConditions ==========================================
* Abstract:
* Initialize both continuous states to one.
7-77
7 Implementing Block Features
*/
static void mdlInitializeConditions(SimStruct *S)
{
real_T *xC0 = ssGetContStates(S);
real_T *xD0 = ssGetRealDiscStates(S);
xC0[0] = 1.0;
xD0[0] = 1.0;
} /* end mdlInitializeConditions */
/* y=xD */
7-78
S-Function Examples
if (ssIsSampleHit(S, 1, tid)) {
real_T *y = ssGetOutputPortRealSignal(S,0);
real_T *xD = ssGetRealDiscStates(S);
y[0]=xD[0];
}
} /* end mdlOutputs */
The mdlUpdate function is called once every major integration time step to
update the discrete states’ values. Since this is an optional method, it must be
proceeded by a #define statement. The heart of the function is wrapped in a
call to ssIsSampleHit to ensure the code is called only when the S-function
is operating at its discrete rate. The function then obtains pointers to the
S-function’s discrete states and floating-point work vector. The value of the
discrete state is updated 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 */
7-79
7 Implementing Block Features
#define MDL_DERIVATIVES
/* Function: mdlDerivatives =================================================
* Abstract:
* xdot = U
*/
static void mdlDerivatives(SimStruct *S)
{
real_T *dx = ssGetdX(S);
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
/* xdot=U */
dx[0]=U(0);
} /* end mdlDerivatives */
The trailer of this S-function must include the files necessary for simulation
or code generation, as follows.
7-80
S-Function Examples
ssSetTNext(S, ssGetT(S)(*u[1]));
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/simulink/src/vsfunc.c
The beginning of each S-function must include #define statements for
the S-function’s name and level, along with a #include statement for the
simstruc.h header. Following these statements, the S-function can include
or define any other necessary headers, data, etc. . In the vsfunc.c example
shown below, in addition to the required statements, U is defined as elements
in the pointer to the first input port’s signal
7-81
7 Implementing Block Features
/* File : vsfunc.c
* Abstract:
*
* Variable step S-function example.
* This example S-function illustrates how to create a variable step
* block in Simulink. 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"
7-82
S-Function Examples
• Lastly, any applicable options are set using ssSetOptions. In this case, the
only option is SS_OPTION_EXCEPTION_FREE_CODE, which stipulates that
the code is exception free.
ssSetNumContStates(S, 0);
ssSetNumDiscStates(S, 1);
7-83
7 Implementing Block Features
ssSetNumSampleTimes(S, 1);
ssSetNumRWork(S, 0);
ssSetNumIWork(S, 0);
ssSetNumPWork(S, 0);
ssSetNumModes(S, 0);
ssSetNumNonsampledZCs(S, 0);
7-84
S-Function Examples
ssSetSampleTime(S, 0, VARIABLE_SAMPLE_TIME);
ssSetOffsetTime(S, 0, 0.0);
ssSetModelReferenceSampleTimeDefaultInheritance(S);
}
#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;
}
#define MDL_GET_TIME_OF_NEXT_VAR_HIT
static void mdlGetTimeOfNextVarHit(SimStruct *S)
{
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
7-85
7 Implementing Block Features
The mdlUpdate function updates the discrete state’s value. Since this is an
optional method, it must be proceeded by a #define statement. The beginning
of the function obtains pointers to the S-function’s discrete state and first
input port. The value of the first element of the first input port signal is
then assigned 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.
*/
7-86
S-Function Examples
x[0]=U(0);
}
The trailer of this S-function must include the files necessary for simulation
or code generation, as follows.
7-87
7 Implementing Block Features
matlabroot/simulink/src/sfun_zc_sat.c
The beginning of each S-function must include #define statements for
the S-function’s name and level, along with a #include statement for the
simstruc.h header. Following these statements, the S-function can include or
define 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
* implement a saturation function. This S-function is designed to be
* used with a variable or fixed step solver.
*
* A saturation is described by three equations
*
* (1) y = UpperLimit
* (2) y = u
* (3) y = LowerLimit
*
* and a set of inequalities that specify which equation to use
*
* if UpperLimit < u then use (1)
* if LowerLimit <= u <= UpperLimit then use (2)
* if u < LowerLimit then use (3)
*
* A key fact is that the valid equation 1, 2, or 3, can change at
* any instant. Nonsampled zero crossing support helps the variable step
* solvers locate the exact instants when behavior switches from one equation
* to another.
*
* Copyright 1990-2007 The MathWorks, Inc.
*/
#include "simstruc.h"
7-88
S-Function Examples
/*========================*
* 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) )
#define MDL_CHECK_PARAMETERS
#if defined(MDL_CHECK_PARAMETERS) && defined(MATLAB_MEX_FILE)
7-89
7 Implementing Block Features
/*
* 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 */
7-90
S-Function Examples
7-91
7 Implementing Block Features
/*
* 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 will be reported by Simulink */
}
#endif
/*
* Get parameter size info.
*/
numUpperLimit = mxGetNumberOfElements( P_PAR_UPPER_LIMIT );
numLowerLimit = mxGetNumberOfElements( P_PAR_LOWER_LIMIT );
/*
* states
*/
ssSetNumContStates(S, 0);
7-92
S-Function Examples
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);
}
/*
* 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
7-93
7 Implementing Block Features
*/
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
* mdlSetInputPortWidth functions.
*/
ssSetOptions(S, ( SS_OPTION_EXCEPTION_FREE_CODE |
SS_OPTION_ALLOW_INPUT_SCALAR_EXPANSION));
} /* end mdlInitializeSizes */
7-94
S-Function Examples
S-function inherits its sample time from its driving block. The call to
ssSetModelReferenceSampleTimeDefaultInheritance tells the solver to
use the default rule to determine if submodels containing this S-function can
inherit their sample times from the parent model.
#define MDL_SET_WORK_WIDTHS
#if defined(MDL_SET_WORK_WIDTHS) && defined(MATLAB_MEX_FILE)
/* Function: mdlSetWorkWidths ===============================================
* The width of the Modes and the ZCs depends on the width of the output.
* This width is not always known in mdlInitializeSizes so it is handled
* here.
*/
static void mdlSetWorkWidths(SimStruct *S)
{
int nModes;
int nNonsampledZCs;
if (ssIsVariableStepSolver(S) &&
7-95
7 Implementing Block Features
/*
* 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 crossings work 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. Note, if the mode changed between the previous and current time
7-96
S-Function Examples
7-97
7 Implementing Block Features
/*
* 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.
*/
for (iOutput = 0; iOutput < numOutput; iOutput++) {
if (*uPtrs[uIdx] >= *upperLimit) {
*y++ = *upperLimit;
} else if (*uPtrs[uIdx] > *lowerLimit) {
*y++ = *uPtrs[uIdx];
} else {
*y++ = *lowerLimit;
}
7-98
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;
}
7-99
7 Implementing Block Features
/*
* Adjust indices to give scalar expansion if needed.
*/
uIdx += uInc;
upperLimit += upperLimitInc;
lowerLimit += lowerLimitInc;
}
/*
* 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];
}
/*
7-100
S-Function Examples
#define MDL_ZERO_CROSSINGS
#if defined(MDL_ZERO_CROSSINGS) && (defined(MATLAB_MEX_FILE) || defined(NRT))
7-101
7 Implementing Block Features
* There is generally one ZC signal for each pair of signals that can
* switch. The three equations above would break into two pairs (1)&(2)
* and (2)&(3). The possibility of a "long jump" from (1) to (3) does
* not need to be handled as a separate case. It is implicitly handled.
*
* When ZCs are calculated, the value is normally used twice. When it is
* first calculated, it is used as the end of the current time step. Later,
* it will be used as the beginning of the following step.
*
* The sign of the ZC signal always indicates an equation from the pair. For
* S-functions, which equation is associated with a positive ZC and which is
* associated with a negative ZC doesn't really matter. If the ZC is positive
* at the beginning and at the end of the time step, this implies that the
* "positive" equation was valid throughout the time step. Likewise, if the
* ZC is negative at the beginning and at the end of the time step, this
* implies that the "negative" equation was valid throughout the time step.
* Like any other nonlinear solver, this is not foolproof, but it is an
* excellent indicator. If the ZC has a different sign at the beginning and
* at the end of the time step, then a equation switch definitely occurred
* during the time step.
*
* Ideally, the ZC signal gives an estimate of when an equation switch
* occurred. For example, if the ZC signal is -2 at the beginning and +6 at
* the end, then this suggests that the switch occurred
* 25% = 100%*(-2)/(-2-(+6)) of the way into the time step. It will almost
* never be true that 25% is perfectly correct. There is no perfect choice
* for a ZC signal, but there are some good rules. First, choose the ZC
* signal to be continuous. Second, choose the ZC signal to give a monotonic
* measure of the "distance" to a signal switch; strictly monotonic is ideal.
*/
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.
7-102
S-Function Examples
*/
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.
*/
7-103
7 Implementing Block Features
uIdx += uInc;
upperLimit += upperLimitInc;
lowerLimit += lowerLimitInc;
}
}
The trailer of this S-function includes the files necessary for simulation or
code generation, as follows.
7-104
S-Function Examples
matlabroot/simulink/src/stvctf.c
The beginning of each S-function must include #define statements for
the S-function’s name and level, along with a #include statement for the
simstruc.h header. Following these statements, the S-function can include
or define 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’s dialog. Note, the comments at the beginning of
this S-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
7-105
7 Implementing Block Features
7-106
S-Function Examples
#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
#define MDL_CHECK_PARAMETERS
#if defined(MDL_CHECK_PARAMETERS) && defined(MATLAB_MEX_FILE)
/* Function: mdlCheckParameters =============================================
* Abstract:
* Validate our parameters to verify:
* o The numerator must be of a lower order than the denominator.
* o The sample time must be a real positive nonzero value.
*/
static void mdlCheckParameters(SimStruct *S)
{
int_T i;
7-107
7 Implementing Block Features
if (mxIsEmpty( ssGetSFcnParam(S,i)) ||
mxIsSparse( ssGetSFcnParam(S,i)) ||
mxIsComplex( ssGetSFcnParam(S,i)) ||
!mxIsNumeric( ssGetSFcnParam(S,i)) ) {
ssSetErrorStatus(S,"Parameters must be real finite vectors");
return;
}
pr = mxGetPr(ssGetSFcnParam(S,i));
nEls = mxGetNumberOfElements(ssGetSFcnParam(S,i));
for (el = 0; el < nEls; el++) {
if (!mxIsFinite(pr[el])) {
ssSetErrorStatus(S,"Parameters must be real finite vectors");
return;
}
}
}
7-108
S-Function Examples
7-109
7 Implementing Block Features
/*
* Define the characteristics of the block:
*
* Number of continuous states: length of denominator - 1
* Inputs port width 2 * (NumContStates+1) + 1
* Output port width 1
* DirectFeedThrough: 0 (Although this should be computed.
* We'll assume coefficients entered
* are strictly proper).
* Number of sample times: 2 (continuous and discrete)
* Number of Real work elements: 4*NumCoeffs
* (Two banks for num and den coeff's:
* NumBank0Coeffs
7-110
S-Function Examples
* DenBank0Coeffs
* NumBank1Coeffs
* DenBank1Coeffs)
* Number of Integer work elements: 2 (indicator of active bank 0 or 1
* and flag to indicate when banks
* have been updated).
*
* The number of inputs arises from the following:
* o 1 input (u)
* o the numerator and denominator polynomials each have NumContStates+1
* coefficients
*/
nCoeffs = mxGetNumberOfElements(DEN(S));
nContStates = nCoeffs - 1;
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);
7-111
7 Implementing Block Features
} /* end mdlInitializeSizes */
/*
* the second, discrete sample time, is user provided
*/
ssSetSampleTime(S, 1, mxGetPr(TS(S))[0]);
ssSetOffsetTime(S, 1, 0.0);
ssSetModelReferenceSampleTimeDefaultInheritance(S);
} /* end mdlInitializeSampleTimes */
7-112
S-Function Examples
#define MDL_INITIALIZE_CONDITIONS
/* Function: mdlInitializeConditions ==========================================
* Abstract:
* Initalize the states, numerator and denominator coefficients.
*/
static void mdlInitializeConditions(SimStruct *S)
{
int_T i;
int_T nContStates = ssGetNumContStates(S);
real_T *x0 = ssGetContStates(S);
int_T nCoeffs = nContStates + 1;
real_T *numBank0 = ssGetRWork(S);
real_T *denBank0 = numBank0 + nCoeffs;
int_T *activeBank = ssGetIWork(S);
/*
* 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.
*/
{
7-113
7 Implementing Block Features
/*
* 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 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 output is calculated using the numerator coefficients
stored in the active bank.
7-114
S-Function Examples
* 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)
7-115
7 Implementing Block Features
*
* 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]);
for (i = 0; i < nContStates; i++) {
*y += *num++ * *x++;
}
}
} /* end mdlOutputs */
#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;
7-116
S-Function Examples
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;
for (i = 0; (i < nCoeffs) && allZero; i++) {
allZero &= *uPtrs[uIdx+i] == 0.0;
}
7-117
7 Implementing Block Features
/*
* 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.
*/
ssGetIWork(S)[1] = 1;
}
7-118
S-Function Examples
} /* end mdlUpdate */
#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:
7-119
7 Implementing Block Features
*
* 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 */
The trailer of this S-function must include the files necessary for simulation
or code generation, as follows.
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 matlabroot/simulink/include/simstruc_types.h . If used, you
must call this macro once for each input argument that a callback does not use.
7-120
8
S-Function Callback
Methods — Alphabetical
List
Required No
C S
Arguments SimStruct representing an S-Function block.
M Syntax CheckParameters(s)
M s
Arguments Instance of Simulink.MSFcnRunTimeBlock class representing an
S-Function block.
8-2
mdlCheckParameters
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 setting the number of parameters you expect
in your S-function by using ssSetNumSFcnParams, use this code in
mdlInitializeSizes:
8-3
mdlCheckParameters
Languages Ada, C, M
8-4
mdlDerivatives
Required No
C S
Arguments SimStruct representing an S-Function block.
M Syntax Derivatives(s)
M s
Arguments Instance of Simulink.MSFcnRunTimeBlock class representing the
S-Function block
Description Simulink 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. This
method can 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.
8-5
mdlDerivatives
#define MDL_DERIVATIVES
#if defined(MDL_DERIVATIVES) && defined(MATLAB_MEX_FILE)
static void mdlDerivatives(SimStruct *S)
{
/* Add mdlDerivatives code here *
}
#endif
Languages Ada, C, M
8-6
mdlDisable
Required No
C S
Arguments SimStruct representing an S-Function block.
M Syntax Disable(s)
M s
Arguments Instance of Simulink.MSFcnRunTimeBlock class representing the
S-Function block.
Languages Ada, C, M
8-7
mdlEnable
Required No
C S
Arguments SimStruct representing an S-Function block.
M Syntax Enable(s)
M s
Arguments Instance of Simulink.MSFcnRunTimeBlock class representing the
S-Function block.
Languages Ada, C, M
8-8
mdlGetTimeOfNextVarHit
Required No
C S
Arguments SimStruct representing an S-Function block.
Description Simulink invokes this optional method at every major integration step
to get the time of the next sample time hit. This method should set the
time of next hit, using ssSetTNext. The time of the next hit must be
greater than the current simulation time as returned by ssGetT. The
S-function must implement this method if it operates at a discrete,
variable-step sample time.
For Level-2 M-file 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
matlabroot/toolbox/simulink/blocks/msfcn_vs.m for an example.
For Level-1 M-file 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.
8-9
mdlGetTimeOfNextVarHit
Languages C, M
8-10
mdlInitializeConditions
Required No
C S
Arguments SimStruct representing an S-Function block.
M Syntax InitializeConditions(s)
M s
Arguments Instance of Simulink.MSFcnRunTimeBlock class representing the
S-Function block.
8-11
mdlInitializeConditions
#define MDL_INITIALIZE_CONDITIONS
#if defined(MDL_INITIALIZE_CONDITIONS) && defined(MATLAB_MEX_FILE)
static void mdlInitializeConditions(SimStruct *S)
{
/* Add mdlInitializeConditions code here *
}
#endif
Example This example is an S-function with both continuous and discrete states.
It initializes both sets of states to 1.0.
8-12
mdlInitializeConditions
}
#endif /* MDL_INITIALIZE_CONDITIONS */
For another example that initializes only the continuous states, see
matlabroot/simulink/src/resetint.c.
Languages C, C++, M
8-13
mdlInitializeSampleTimes
Required Yes
C S
Arguments 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
• [CONTINUOUS_SAMPLE_TIME, 0.0]
• [CONTINUOUS_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET]
• [discrete_sample_period, offset]
• [VARIABLE_SAMPLE_TIME, 0.0]
• [INHERITED_SAMPLE_TIME, 0.0]
8-14
mdlInitializeSampleTimes
• [INHERITED_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET]
[INHERITED_SAMPLE_TIME, 0.0]
[CONTINUOUS_SAMPLE_TIME, 0.0]
[CONTINUOUS_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET]
[discrete_sample_period, offset]
where
and
[VARIABLE_SAMPLE_TIME, 0.0]
8-15
mdlInitializeSampleTimes
[INHERITED_SAMPLE_TIME, 0.0]
if (ssGetSampleTime(S, 0) == CONTINUOUS_SAMPLE_TIME) {
ssSetErrorStatus(S,
"This block cannot be assigned a continuous 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:
[INHERITED_SAMPLE_TIME, 0.0]
8-16
mdlInitializeSampleTimes
[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) {
}
8-17
mdlInitializeSampleTimes
#if defined(MATLAB_MEX_FILE)
static void mdlInitializeSampleTimes(SimStruct *S)
{
/* Add mdlInitializeSampleTimes code here *
}
#endif
Languages C
8-18
mdlInitializeSizes
Purpose Specify the number of inputs, outputs, states, parameters, and other
characteristics of the S-function
Required Yes
C S
Arguments SimStruct representing an S-Function block.
M Syntax setup(s)
M s
Arguments Instance of Simulink.MSFcnRunTimeBlock class representing the
S-Function block.
Description This is the first of the S-function’s callback methods that Simulink calls.
This method should perform the following tasks:
8-19
mdlInitializeSizes
- Specify the number of input ports that this S-function has, using
ssSetNumInputPorts.
- Specify the dimensions of the input ports.
See ssSetInputPortDimensionInfo for more information.
- For each input port, specify whether it has direct feedthrough,
using ssSetInputPortDirectFeedThrough.
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 Simulink that u is not used
in either of these S-function routines. Violating this leads to
unpredictable results.
• Configure the block’s output ports.
This entails the following tasks:
- Specify the number of output ports that the block has, using
ssSetNumOutputPorts.
- Specify the dimensions of the output ports.
See mdlSetOutputPortDimensionInfo for more information.
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.
There are two ways of specifying sample times:
- Port-based sample times
- Block-based sample times
8-20
mdlInitializeSizes
8-21
mdlInitializeSizes
#if defined(MATLAB_MEX_FILE)
static void mdlInitializeSizes(SimStruct *S)
{
/* Add mdlInitializeSizes code here *
}
#endif
8-22
mdlInitializeSizes
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
* 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;
/*
8-23
mdlInitializeSizes
/*
* 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 */
Languages Ada, C, M
8-24
mdlOutputs
Required Yes
C S
Arguments SimStruct representing an S-Function block.
tid
Task ID.
M Syntax Outputs(s)
M s
Arguments Instance of Simulink.MSFcnRunTimeBlock class representing the
S-Function block.
Description Simulink 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
mdlOutports routine of a multirate S-Function block to encapsulate
task-specific blocks of code (see “Multirate S-Function Blocks” on page
7-34).
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)
8-25
mdlOutputs
#if defined(MATLAB_MEX_FILE)
static void mdlOutputs(SimStruct *S)
{
/* Add mdlOutputs code here *
}
#endif
8-26
mdlProcessParameters
Required No
C S
Arguments SimStruct representing an S-Function block.
M Syntax ProcessParameters(s)
M s
Arguments Instance of Simulink.MSFcnRunTimeBlock class representing the
S-Function block.
8-27
mdlProcessParameters
}
#endif /* MDL_PROCESS_PARAMETERS */
}
#endif /* MDL_PROCESS_PARAMETERS */
#define MDL_START
#if defined(MDL_START)
8-28
mdlProcessParameters
Languages Ada, C, M
8-29
mdlProjection
Required No
C S
Arguments SimStruct representing an S-Function block.
M Syntax Projection(s)
M s
Arguments Instance of Simulink.MSFcnRunTimeBlock class representing the
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.
Simulink 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 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
8-30
mdlProjection
8-31 for a simple method for perturbing a system’s states. The following
articles describe more sophisticated perturbation methods that your
mdlProjection method can use.
X n ≅ X n* + J nT ( J n J nT )−1 Rn
where
• X n is the system’s ideal state vector at the solver’s current time step
8-31
mdlProjection
∂g
Jn = ( X n* , tn )
∂X
Rn = g( X n , tn ) − g( X n* , tn )
J nT ( J n J nT )−1 Rn
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 (open):
8-32
mdlProjection
x& = ax(1 − y)
y& = − cy(1 − x)
x − c ecx y− a eay = d
where xn and yn are 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:
8-33
mdlProjection
This model is the same as the previous model, except that its
S-function, predprey.m, includes a mdlProjection method that uses
8-34
mdlProjection
Languages C, M
8-35
mdlRTW
Required No
C S
Arguments SimStruct representing an S-Function block.
M Syntax WriteRTW(s)
M s
Arguments Instance of Simulink.MSFcnRunTimeBlock class representing the
S-Function block.
• ssWriteRTWParameters
• ssWriteRTWParamSettings
• ssWriteRTWWorkVect
• ssWriteRTWStr
• ssWriteRTWStrParam
• ssWriteRTWScalarParam
• ssWriteRTWStrVectParam
• ssWriteRTWVectParam
• ssWriteRTW2dMatParam
• ssWriteRTWMxVectParam
8-36
mdlRTW
• ssWriteRTWMx2dMatParam
Languages C, C++, M
8-37
mdlSetDefaultPortComplexSignals
Purpose Set the numeric types (real, complex, or inherited) of ports whose
numeric types cannot be determined from block connectivity
Required No
C S
Arguments SimStruct representing an S-Function block.
Description Simulink 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.
If the block does not implement this method and at least one port is
known to be complex, Simulink sets the unknown ports to COMPLEX_YES;
otherwise, it sets the unknown ports to COMPLEX_NO.
Languages C
8-38
mdlSetDefaultPortDataTypes
Purpose Set the data types of ports whose data types cannot be determined from
block connectivity
Required No
C S
Arguments SimStruct representing an S-Function block.
Description Simulink 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.
If the block does not implement this method and Simulink cannot
determine the data types of any of its ports, Simulink sets the data
types of all the ports to double. If the block does not implement this
method and Simulink cannot determine the data types of some, but not
all, of its ports, Simulink sets the unknown ports to the data type of the
port whose data type has the largest size.
Languages C
8-39
mdlSetDefaultPortDimensionInfo
Required No
C S
Arguments SimStruct representing an S-Function block.
Languages C
8-40
mdlSetInputPortComplexSignal
Purpose Set the numeric types (real, complex, or inherited) of the signals
accepted by an input port
Required No
C S
Arguments SimStruct representing an S-Function block.
port
Index of a port.
csig
Numeric type of signal, either COMPLEX_NO (real) or COMPLEX_YES
(complex).
M s
Arguments Instance of Simulink.MSFcnRunTimeBlock class representing the
S-Function block.
port
Integer value specifying index of port to be set.
typeId
Integer value specifying whether the port accepts real (0) or
complex (1) signals.
Description Simulink 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. The S-function must
check whether the proposed numeric type is a valid type for the specified
port. If it is valid, the S-function must set the numeric type of the
8-41
mdlSetInputPortComplexSignal
Languages C, C++, M
8-42
mdlSetInputPortDataType
Purpose Set the data types of the signals accepted by an input port
Required No
C S
Arguments SimStruct representing an S-Function block.
port
Index of a port.
id
Data type ID.
M s
Arguments Instance of Simulink.MSFcnRunTimeBlock class representing the
S-Function block.
port
Integer value specifying index of port to be set.
typeId
Integer value specifying ID of port’s data type. Use
s.getDatatypeName(typeId) to get the data type’s name.
Description Simulink 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 IDs for the built-in data types can be found in
matlabroot/simulink/include/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, it must set the data type of the
input port using ssSetInputPortDataType. Otherwise, it must report
an error using ssSetErrorStatus.
8-43
mdlSetInputPortDataType
The S-function can also set the data types of other input and output
ports if they are unknown. Simulink 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, Simulink assumes that
the block accepts any data type and sets the input port data type to
the specified value.
Simulink will call this method until all input ports with inherited data
types have their data types specified.
Languages C, M
8-44
mdlSetInputPortDimensionInfo
Required No
C S
Arguments SimStruct representing an S-Function block.
port
Index of a port.
dimsInfo
Structure that specifies the signal dimensions supported by the
port.
M s
Arguments Instance of Simulink.MSFcnRunTimeBlock class representing the
S-Function block.
port
Integer value specifying index of port to be set.
dims
1-D 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.
8-45
mdlSetInputPortDimensionInfo
Note This method can set the dimensions of any other input or output
port whose dimensions derive from the dimensions of port.
By default, Simulink calls this method only if it can fully determine the
dimensionality of port from the port to which it is connected. If it cannot
completely determine the dimensionality from port connectivity, it
invokes mdlSetDefaultPortDimensionInfo. If an S-function can fully
determine the port dimensionality from partial information, the function
should set the option SS_OPTION_ALLOW_PARTIAL_DIMENSIONS_CALL
in mdlInitializeSizes, using ssSetOptions. If this option is set,
Simulink invokes mdlSetInputPortDimensionInfo even if it can
only partially determine the dimensionality of the input port from
connectivity.
Simulink will call this method until all input ports with inherited
dimensions have their dimensions specified.
Languages C, C++, M
8-46
mdlSetInputPortFrameData
Required No
C S
Arguments SimStruct representing an S-Function block.
port
Index of a port.
frameData
Frame data.
M s
Arguments 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.
mode
Integer value specifying the sampling mode of the port (0 =
sample, 1 = frame).
Description This method is called with the candidate frame setting (FRAME_YES
or FRAME_NO) for an input port. If the proposed setting is acceptable,
the method should go ahead and set the actual frame data setting
using ssSetInputPortFrameData. If the setting is unacceptable, an error
should be generated via ssSetErrorStatus. Note that any other input
or output ports whose frame data settings are implicitly defined by
8-47
mdlSetInputPortFrameData
virtue of knowing the frame data setting of the given port can also have
their frame data settings configured.
Simulink will call this method until all input ports with inherited frame
settings have their frame settings specified.
The use of frame-based signals (mode has a value of 1) requires a Signal
Processing Blockset license.
Languages C, C++, M
8-48
mdlSetInputPortSampleTime
Purpose Set the sample time of an input port that inherits its sample time from
the port to which it is connected
Required No
C S
Arguments SimStruct representing an S-Function block.
port
Index of a port.
sampleTime
Inherited sample time for port.
offsetTime
Inherited offset time for port.
M s
Arguments 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 samples its input.
Description Simulink invokes this method with the sample time that port
inherits from the port to which it is connected. If the inherited
sample time is acceptable, this method should set the sample time of
8-49
mdlSetInputPortSampleTime
Simulink invokes 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.
• The model uses a fixed-step solver and the port has a continuous but
fixed in minor step sample time. In this case, Simulink converts the
sample time to the fundamental sample time for the model.
8-50
mdlSetInputPortSampleTime
Languages C, C++, M
8-51
mdlSetInputPortWidth
Purpose Set the width of an input port that accepts 1-D (vector) signals
Required No
C S
Arguments 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 using ssSetInputPortWidth. If the size is
unacceptable, an error should be generated via ssSetErrorStatus. Note
that any other dynamically sized input or output ports whose widths
are implicitly defined by virtue of knowing the width of the given port
can also have their widths set via calls to ssSetInputPortWidth or
ssSetOutputPortWidth.
Simulink invokes this method until all dynamically sized input ports
are configured.
Languages C
8-52
mdlSetOutputPortComplexSignal
Purpose Set the numeric types (real, complex, or inherited) of the signals
accepted by an output port
Required No
C S
Arguments SimStruct representing an S-Function block.
port
Index of a port.
csig
Numeric type of signal, either COMPLEX_NO (real) or COMPLEX_YES
(complex).
M s
Arguments Instance of Simulink.MSFcnRunTimeBlock class representing the
S-Function block.
port
Integer value specifying the index of port to be set.
typeId
Integer value specifying whether the port produces real (0) or
complex (1) signals.
Description Simulink 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 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, the S-function
8-53
mdlSetOutputPortComplexSignal
must set the numeric type of the specified output port using
ssSetOutputPortComplexSignal. Otherwise, it must report an error,
using ssSetErrorStatus. The S-function can also set the numeric types
of other input and output ports with unknown numeric types. Simulink
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, Simulink assumes
that the S-function accepts a real or complex signal and sets the output
port numeric type to the specified value.
Simulink will call this method until all output ports with inherited
numeric types have their numeric types specified.
Languages C, C++, M
8-54
mdlSetOutputPortDataType
Purpose Set the data type of the signals emitted by an output port
Required No
C S
Arguments SimStruct representing an S-Function block.
port
Index of an output port.
id
Data type ID.
M s
Arguments Instance of Simulink.MSFcnRunTimeBlock class representing the
S-Function block.
port
Integer value specifying index of port to be set.
typeId
Integer value specifying ID of port’s data type. Use
s.getDatatypeName(typeId) to get the data type’s name.
Description Simulink calls this routine to set the data type of port when port has
an inherited data type. The data type IDid is the proposed data type
for this port. Data type IDs for the built-in data types can be found in
matlabroot/simulink/include/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, it must set the data type of
port using ssSetOutputPortDataType. Otherwise, it must report an
error, using ssSetErrorStatus.
8-55
mdlSetOutputPortDataType
The S-function can also set the data types of other input and output
ports if their data types have not been set. Simulink 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, Simulink assumes that
the block supports any data type and sets the output port data type to
the specified value.
Simulink will call this method until all output ports with inherited data
types have their data types specified.
Languages C, C++, M
8-56
mdlSetOutputPortDimensionInfo
Required No
C S
Arguments SimStruct representing an S-Function block or a Simulink model.
port
Index of a port.
dimsInfo
Structure that specifies the signal dimensions supported by port.
M s
Arguments Instance of Simulink.MSFcnRunTimeBlock class representing the
S-Function block.
port
Integer value specifying the index of the port to be set.
dims
1-D 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.
8-57
mdlSetOutputPortDimensionInfo
Note This method can set the dimensions of any other input or output
port whose dimensions derive from the dimensions of port.
By default, Simulink calls this method only if it can fully determine the
dimensionality of port from the port to which it is connected. If it cannot
completely determine the dimensionality from port connectivity, it
invokes mdlSetDefaultPortDimensionInfo. If an S-function can fully
determine the port dimensionality from partial information, the function
should set the option SS_OPTION_ALLOW_PARTIAL_DIMENSIONS_CALL
in mdlInitializeSizes, using ssSetOptions. If this option is set,
Simulink invokes mdlSetOutputPortDimensionInfo even if it can
only partially determine the dimensionality of the output port from
connectivity. Simulink will call this method until all output ports with
inherited dimensions have their dimensions specified.
Languages C, C++, M
8-58
mdlSetOutputPortSampleTime
Purpose Set the sample time of an output port that inherits its sample time from
the port to which it is connected
Required No
C S
Arguments SimStruct representing an S-Function block.
port
Index of a port.
sampleTime
Inherited sample time for port.
offsetTime
Inherited offset time for port.
M s
Arguments 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.
Description Simulink calls this method with the sample time that port inherits
from the port to which it is connected. If the inherited sample time
is acceptable, this method should set the sample time of port to the
8-59
mdlSetOutputPortSampleTime
pd = s.OutputPort(port);
pd.SampleTime = time;
Languages C, M
8-60
mdlSetOutputPortWidth
Purpose Set the width of an output port that outputs 1-D (vector) signals
Required No
C S
Arguments 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, using ssSetOutputPortWidth. If the size
is unacceptable, an error should be generated via ssSetErrorStatus.
Note that any other dynamically sized input or output ports whose
widths are implicitly defined by virtue of knowing the width of the given
port can also have their widths set via calls to ssSetInputPortWidth or
ssSetOutputPortWidth.
Languages C
8-61
mdlSetWorkWidths
Purpose Specify the sizes of the work vectors and create the run-time parameters
required by this S-function
Required No
C S
Arguments SimStruct representing an S-Function block.
M Syntax PostPropagationSetup(s)
M s
Arguments Instance of Simulink.MSFcnRunTimeBlock class representing the
S-Function block.
Description Simulink 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 “Run-Time Parameters” on page
7-8). Simulink 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. 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 Simulink
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,
8-62
mdlSetWorkWidths
even for those whose exact size it knows at that point. The S-function
should then specify the actual size in mdlSetWorkWidths.
A Level-2 M-file S-function must implement this method if any Dwork
vectors are used in the S-function. In the case of M-file 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 type for the Dwork vector:
block.DWork(1).UsageType = type;
• DWork
• DState
• Scratch
• Mode
Languages Ada, C, M
8-63
mdlSimStatusChange
Required No
C S
Arguments SimStruct representing an S-Function block.
simStatus
Status of the simulation, either SIM_PAUSE or SIM_CONTINUE.
M s
Arguments Instance of Simulink.MSFcnRunTimeBlock class representing the
S-Function block.
status
Status of the simulation, either 0 when paused or 1 when
continued.
Description Simulink calls this routine when a simulation of the model containing S
pauses or resumes.
8-64
mdlSimStatusChange
}
}
#endif
Languages C
8-65
mdlStart
Required No
C S
Arguments SimStruct representing an S-Function block.
M Syntax Start(s)
M s
Arguments Instance of Simulink.MSFcnRunTimeBlock class representing the
S-Function block.
Languages Ada, C, M
8-66
mdlTerminate
Required Yes
C S
Arguments SimStruct representing an S-Function block.
M Syntax Terminate(s)
M s
Arguments Instance of Simulink.MSFcnRunTimeBlock class representing the
S-Function block.
Description This method should perform any actions, such as freeing memory, that
must be performed at the end of simulation or when an S-Function
block is destroyed (e.g., when it is deleted from a model). The option
SS_OPTION_CALL_TERMINATE_ON_EXIT (see ssSetOptions) determines
whether Simulink invokes this method. If this option is not set,
Simulink invokes mdlTerminate at the end of the simulation only if
the mdlStart method of at least one block in the model has executed
without error during the simulation. If this option is set, Simulink
always invokes the mdlTerminate method at the end of a simulation
run and whenever it destroys a block.
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)
8-67
mdlTerminate
#if defined(MATLAB_MEX_FILE)
static void mdlTerminate(SimStruct *S)
{
/* Add mdlTerminate code here *
}
#endif
{
int i;
for (i = 0; i<ssGetNumPWork(S); i++) {
if (ssGetPWorkValue(S,i) != NULL) {
free(ssGetPWorkValue(S,i));
}
}
}
Languages Ada, C, M
8-68
mdlUpdate
Required No
C S
Arguments SimStruct representing an S-Function block.
tid
Task ID.
M Syntax Update(s)
M s
Arguments Instance of Simulink.MSFcnRunTimeBlock class representing the
S-Function block.
Description Simulink 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.
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, Simulink is able to eliminate the need for the extra call in
these circumstances.
If your 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.
8-69
mdlUpdate
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
7-34).
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)
#define MDL_UPDATE
#if defined(MDL_UPDATE) && defined(MATLAB_MEX_FILE)
static void mdlUpdate(SimStruct *S)
{
/* Add mdlUpdate code here *
}
#endif
Example For an example that uses this function to update discrete states, see
matlabroot/simulink/src/dsfunc.c. For an example that uses this
function to update the transfer function coefficients of a time-varying
continuous transfer function, see matlabroot/simulink/src/stvctf.c.
8-70
mdlUpdate
8-71
mdlZeroCrossings
Required No
C S
Arguments SimStruct representing an S-Function block.
M Syntax ProcessParameters(s)
M s
Arguments Instance of Simulink.MSFcnRunTimeBlock class representing the
S-Function block.
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
8-72
mdlZeroCrossings
Languages C, C++, M
8-73
9
SimStruct Functions — By
Category
Introduction
Simulink provides a set of functions for accessing the fields of an S-function’s
simulation data structure (SimStruct). S-function callback methods use these
functions to store and retrieve information about an S-function.
This reference describes the syntax and usage of each SimStruct function.
The descriptions appear alphabetically by name to facilitate location of a
particular function. This section also provides listings of functions by usage
to speed location of macros and functions for specific purposes, such as
implementing data type support.
Language Support
Some SimStruct functions are available only in some of the languages
supported by Simulink. The reference page for each SimStruct macro or
function lists the languages in which it is available. If the SimStruct function
is available in C, the reference page gives its C syntax. Otherwise, it gives
its syntax in the language in which it is available.
The SimStruct
The file matlabroot/simulink/include/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.
9-2
SimStruct Macros and Functions Listed by Usage
Data Type
Dialog Box Parameters
Error Handling and Status
Function Call
I/O Port — Signal Specification
I/O Port — Signal Dimensions
I/O Port — Signal Access on page 9-10
Run-Time Parameters on page 9-12
Sample Time on page 9-13
Simulation Information on page 9-15
State and Work Vector on page 9-17
Miscellaneous
Real-Time Workshop
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.
9-3
9 SimStruct Functions — By Category
Macro Description
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.
ssRegisterDataType Register a data type.
ssSetDataTypeSize Specify the size of a data type.
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.
ssGetNumParameters Get the number of parameters that this
block has (Ada only).
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.
ssSetParameterName Set the name of a parameter (Ada only).
9-4
SimStruct Macros and Functions Listed by Usage
Macro Description
ssSetParameterTunable Set the tunability of a parameter (Ada only).
ssSetSFcnParamNotTunable Obsolete.
ssSetSFcnParamTunable Specify the tunability of a dialog box
parameter.
Macro Description
ssGetErrorStatus Get a string that identifies the last error.
ssPrintf Print a variable-content msg.
ssSetErrorStatus Report errors.
ssWarning Display a warning message.
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.
ssGetExplicitFCSSCtrl Determine whether this S-function explicitly
enables and disables the function-call
subsystem that it invokes.
9-5
9 SimStruct Functions — By Category
Macro Description
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.
Macro Description
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.
ssGetOutputPortComplexSignal Get the numeric type (complex
or real) of an output port.
9-6
SimStruct Macros and Functions Listed by Usage
Macro Description
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.
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.
ssSetInputPortFrameData Specify whether a port accepts
signal frames.
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.
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.
9-7
9 SimStruct Functions — By Category
Macro Description
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.
ssSetOutputPortFrameData Specify whether a port outputs
framed data.
ssSetOutputPortOffsetTime Specify the sample time offset
value of an output port.
ssSetOutputPortSampleTime Specify the sample time of an
output port.
ssSetZeroBasedIndexInputPort Specify that an input port
expects zero-based indices.
ssSetZeroBasedIndexOutputPort Specify that an output port emits
zero-based indices.
Macro Description
ssAllowSignalsWithMoreThan2D Enable S-function to work with
multidimensional signals.
ssGetInputPortDimensions Get the dimensions of the signal
accepted by an input port.
ssGetInputPortNumDimensions Get the dimensionality of the
signals accepted by an input
port.
ssGetInputPortWidth Determine the width of an input
port.
9-8
SimStruct Macros and Functions Listed by Usage
Macro Description
ssGetOutputPortDimensions Get the dimensions of the signal
leaving an output port.
ssGetOutputPortNumDimensions Get the number of dimensions of
an output port.
ssGetOutputPortWidth Determine the width of an
output port.
ssSetInputPortDimensionInfo Set the dimensionality of an
input port.
9-9
9 SimStruct Functions — By Category
Macro Description
ssSetOutputPortMatrixDimensions Specify the dimensions of a 2-D
(matrix) signal.
ssSetVectorMode Specify the vector mode that an
S-function supports.
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.
ssGetInputPortSignalAddress Get the address of an input port’s
signal (Ada only).
ssGetInputPortSignalPtrs Get pointers to input signal
elements of type other than
double.
9-10
SimStruct Macros and Functions Listed by Usage
Macro Description
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.
ssGetOutputPortRealSignal Access the elements of a signal
connected to an output port.
ssGetOutputPortSignal Get the vector of signal elements
emitted by an output port.
ssGetOutputPortSignalAddress Get the address of an output
port’s signal (Ada only).
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.
9-11
9 SimStruct Functions — By Category
Macro Description
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.
Run-Time Parameters
These macros allow you to create, update, and access run-time parameters
corresponding to a block’s dialog parameters.
Run-Time 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.
ssRegAllTunableParamsAsRunTimeParams 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.
9-12
SimStruct Macros and Functions Listed by Usage
Macro Description
ssSetRunTimeParamInfo Specify the attributes
of a specified run-time
parameter.
ssUpdateAllTunableParamsAsRunTimeParams 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.
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.
9-13
9 SimStruct Functions — By Category
Macro Description
ssGetOutputPortSampleTime Determine the sample time of an
output port.
ssGetPortBasedSampleTimeBlockIs- Determine whether a block that
Triggered uses port-based sample times
resides in a triggered subsystem.
ssGetSampleTime Determine one of an S-function’s
sample times.
ssGetSampleTimeOffset Get the offset of the current sample
time (Ada only).
ssGetSampleTimePeriod Get the period of the current sample
time (Ada only).
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 whether use of an
InheritanceRule S-function in a submodel prevents
the submodel from inheriting its
sample time from the parent model.
9-14
SimStruct Macros and Functions Listed by Usage
Macro Description
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
ssGetAbsTol Get the absolute tolerances used by a model’s
variable-step solver.
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 string that identifies the last error.
ssGetInlineParameters Determine whether the user has set the
inline parameters option for the model
containing this S-function.
ssGetSimMode Determine the context in which an
S-function is being invoked: normal
simulation, external-mode simulation,
model editor, etc.
ssGetSolverMode Get the solver mode being used to solve the
S-function.
ssGetSolverName Get the name of the solver being used for
the simulation.
9-15
9 SimStruct Functions — By Category
Macro Description
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.
ssIsFirstInitCond Determine whether this is the first call to
mdlInitializeConditions.
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.
ssSetBlockReduction Request that Simulink attempt to reduce a
block.
ssSetSolverNeedsReset Ask Simulink to reset the solver.
ssSetStopRequested Ask Simulink to terminate the simulation at
the end of the current time step.
9-16
SimStruct Macros and Functions Listed by Usage
Macro Description
ssGetContStateAddress Get the address of a block’s continuous state
vector.
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
data type work vector are real or complex
numbers.
ssGetDWorkDataType Get the data type of a data type work vector.
ssGetDWorkName Get the name of a data type work vector.
ssGetDWorkUsedAsDState Determine whether a data type work vector
is used as a discrete state vector.
ssGetDWorkWidth Get the size of a data type work vector.
ssGetdX Get the derivatives of the continuous states
of an S-function.
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.
9-17
9 SimStruct Functions — By Category
Macro Description
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.
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.
9-18
SimStruct Macros and Functions Listed by Usage
Macro Description
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.
ssSetNumRWork Specify the size of an S-function’s real
(real_T) work vector.
9-19
9 SimStruct Functions — By Category
Macro Description
ssSetPWorkValue Set an element of a block’s pointer work
vector.
ssSetRWorkValue Set an element of a block’s floating-point
work vector.
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.
9-20
SimStruct Macros and Functions Listed by Usage
Miscellaneous (Continued)
Macro Description
ssSetPlacementGroup Specify the execution order of a sink or source
S-function.
ssSetUserData Specify user data.
Real-Time Workshop
Macro Description
ssGetDWorkRTWIdentifier Get the identifier used to declare a
DWork vector in code generated from
the associated S-function.
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.
ssGetPlacementGroup Get the name of the placement group
of a block.
ssSetDWorkRTWIdentifier Set the identifier used to declare a
DWork vector in code generated from
the associated S-function.
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.
9-21
9 SimStruct Functions — By Category
Macro Description
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 string to the S-function’s
model.rtw file.
ssWriteRTWStrParam Write a string parameter to the
S-function’s model.rtw file.
ssWriteRTWStrVectParam Write a string 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.
9-22
A
Examples
S-Function Features
“Passing Parameters to S-Functions” on page 1-4
“Multirate S-Function Blocks” on page 7-34
“Example Involving a Pointer Work Vector” on page 7-44
S-Function Examples
“S-Function Examples” on page 1-20
“Example of a Continuous State S-Function” on page 7-60
“Example of a Discrete State S-Function” on page 7-67
“Example of a Hybrid System S-Function” on page 7-73
“Example of a Variable-Step S-Function” on page 7-81
“Example of a Zero Crossing S-Function” on page 7-87
“Example of a Time-Varying Continuous Transfer Function” on page 7-105
S-Function Builder
“Building S-Functions Automatically” on page 3-6
“Library/Object/Source files” on page 3-24
“Enable access to SimStruct” on page 3-35
Writing S-Functions in C
“Example of a Basic C MEX S-Function” on page 3-41
“Example of Integrating Existing C Functions into Simulink Models with
the Legacy Code Tool” on page 3-56
A-2
Creating Ada S-Functions
A-3
A Examples
A-4
Index
A
Index C++ objects
Ada S-functions making persistent 4-6
creating 5-3 C++ S-functions
example 5-11 building 4-8
GNAT Ada95 compiler 5-10 mex command 4-8
mex syntax 5-10 C-to-Fortran gateway S-function 6-8
source file format 5-3 callback methods 1-11
specification 5-3 CFortran 6-13
additional parameters for M-file S-functions 2-13 cg_sfun.h 3-50
array bounds checking array bounds 7-58
checking 7-58 compile option
for legacy_code function 3-69
compiler compatibility
B Fortran 6-9
block I/O ports 7-13 continuous blocks
block-based sample times 7-24 setting sample time 7-35
specifying 7-24 Continuous Derivatives pane
Build Info pane S-Function Builder 3-29
S-Function Builder 3-33 continuous state S-function example (C
MEX) 7-60
Converting Level-1 M-file S-functions 2-13
C
creating persistent C++ objects 4-6
C functions
integrating into Simulink models 3-53
example 3-56 D
C language header file data structures
matlabroot/simulink/include/- Legacy Code Tool
simstruc.h 9-2 registering 3-60
C MEX S-functions registering multiple 3-71
advantages 3-3 data types
converting from level 1 to level 2 3-85 supported by Legacy Code Tool 3-67
creating 3-4 using user-defined 7-21
definition 1-2 demos
deploying S-functions generated with 3-72 Legacy Code Tool 3-72
example 3-41 device drivers
generating and compiling with Legacy Code integrating into Simulink models 3-53
Tool 3-69 direct feedthrough 1-14
modes for compiling 3-51 discrete state S-function example (C MEX) 7-67
S-Function Builder 3-6 Discrete Update pane
Simulink interaction 3-73 S-Function Builder 3-31
Index-1
Index
Index-2
Index
Index-3
Index
Index-4
Index
Index-5