The S-Function Builder is a Simulink® block that integrates C/C++ code to build an S-function from specifications and C code that you supply. The S-Function Builder also serves as a wrapper for the generated S-function in models that use the S-function.
To use the S-Function Builder, click the Simulink canvas and type S-Function Builder or drag a S-Function Builder block from Simulink Library > User-Defined. To open the S-Function Builder editor, double-click the S-Function Builder block icon or select the block. Then select Open Block from the Edit menu on the model editor or the block's context menu.
S-Function Builder editor is composed of four user interface components:
S-Function Builder toolstrip
Settings pane
Ports and Parameters Table
Libraries table
Specify a name for your S-function to start constructing your S-Function Builder block. Note that when you name an S-function, all functions in the S-Function Builder editor changes and the S-function name becomes a prefix to all wrapper functions.
Use the S-Function Builder toolstrip to specify a target language for the S-function that you would like to generate:
C — Generate C S-functions.
C++ — Generate C++ S-functions.
Inherit from model — Inherit the language settings from the Language setting of the model. See Language (Simulink Coder) for more information.
Customize the basic features your S-function, such as initial conditions, and number of
states, by using the Settings pane on the right of the
S-Function Builder editor. The S-Function Builder uses the information that
you enter on this pane to generate the mdlInitializeSizes
callback method. The Simulink engine invokes this method during the model initialization phase of the
simulation to obtain basic information about the S-function.
Using the Settings table, you can specify the number of discrete and continuous states and their initial conditions.
You can enter the values of initial conditions as a comma-seperated list, (for
example, 1,1,1
) or as a vector (for example, [1 1
1]
). The number of initial conditions must be equal to the number of states
indicated.
Set the array layout of your C/C++ code. You can select one of the options listed in the table.
Option | Array Layout of C/C++ Function | Action |
---|---|---|
Column-major | Column-major | The S-Function Builder block adds the SimStruct function |
Row-major | Row-major | The S-Function Builder block adds the SimStruct function During simulation, if your C/C++ code involves matrices or multidimensional inputs, outputs, or parameters, transposes are added to these S-function callback methods:
Simulink also applies the these transposes when running simulation in Accelerator and Rapid Accelerator modes. The S-function is not inlined by using TLC. Instead, the MEX S-function with transposes is compiled directly. |
Any | C/C++ function is not affected by array layout | The S-Function Builder block adds the SimStruct function |
Select the sample mode of your 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. When inherited sample time is selected, note that
the Sample time value field of the Settings
table is inactive.
Continuous
— The block updates its outputs at each simulation
step. When continuous sample time is selected, note that the Sample time
value field of the Settings table is
inactive.
Discrete
— The S-function updates its outputs at the rate
specified in the Sample time value field of the
Settings table.
PWorks
Set PWorks
, the number of data pointers used by the S-function.
PWorks
points to the memory over the lifecycle of the block. If you
enter any other value than 0
for Number of PWorks,
it adds a pointer, void **PW
, to all functions in S-Function Builder.
For example, you can declare and initialize a pointer to a file or memory at the
Start_wrapper
, access it in Outputs_wrapper
,
Update_wrapper
, and Derivatives_wrapper
functions,
and deallocate it at the Terminate_wrapper
function. The code written
in these functions is called by the mdlStart
,
mdlOutputs
, mdlUpdate
,
mdlDerivatives
, and mdlTerminate
methods. See the
examples Moving Average
with Start and Terminate and Permutation using Cpp
Classes in S-Function
Demos.
Note
Use of PWorks
affects the SimState compliance. If you declare
PWorks
, the use of SimState save and restore is not allowed.
Otherwise, the default SimState compliance setting,
USE_DEFAULT_SIM_STATE
, is used.
Make the SimStruct
(S
) accessible to the wrapper
functions that the S-Function Builder is using. This selection enables you to use the
SimStruct
macros and functions with your code in the
Outputs_wrapper
, Derivatives_wrapper
, and the
Update_wrapper
functions. When you turn this setting on,
SimStruct *S
is added to the list of parameters.
For example, with this option enabled, you can use macros such as ssGetT
in code that computes the S-function outputs:
double t = ssGetT(S); if(t < 2) { y0[0] = u0[0]; } else { y0[0]= 0.0; } |
Select the Direct Feedthrough check box on the Settings table if the values from the current time step of the S-function inputs are used to compute its outputs. The Simulink engine uses this information to detect algebraic loops created by directly or indirectly connecting the S-function output to the S-function input.
Use the Ports and Parameters table on the bottom of the editor to specify input and output ports and parameters for the S-function. To add a port or parameter:
Select the Ports and Parameters table, and from the
S-Function Builder toolstrip, select your choice under Insert
Port
.
Select the Ports and Parameters table and right-click on one of the headers on the table.
To delete a port or parameter in the table, select the port or parameter you would like to delete, right-click to open the menu and click Delete.
The order of the ports and parameters in the table is the order of ports and parameters
on the block. For example, the first input port on the table is the input port with the
index 0
, and the first parameter is the parameter with index
0
.
In the Ports and Parameters, table you can define the following:
Name — Name of the port or parameter. To change the name of a port or parameter, double-click on the name.
Scope — Scope of the port or parameter. The variable could be an input or output port or a parameter. Click on the scope value to change scope of the port or parameter.
Data type — Data type of the port or parameter. You can specify all Simulink built-in data types as well as fixdt data types and buses as ports.
Dimensions — Dimension of the port or parameter.
For ports, specify the dimension to -1 to inherit the dimensions from another block.
For parameters, the dimension is set to -1
and is inherited from
the block parameters on the block interface.
To specify a 1-D dimension, only enter the number of rows for the dimension, for
example, [2]
. To enter a 2-D dimension, enter the dimension as
number of row and columns, for example, [2,1]
.
Complexity — You can specify the complexity of the port or parameter as real or complex.
The Libraries table allows you to specify the location of external code files referenced by custom code that you enter in other the wrapper methods of the S-Function Builder editor.
To enter a new path or an entry, select the Libraries table and
select one of the options under Insert Paths
on the S-Function
Builder toolstrip. Alternatively, click on one of the tags or values on the
Libraries table. Once you select path or entry, you can change your
selection by clicking on the tag on the table. You can enter paths or entries to the
external libraries, object codes and source files referenced by custom code on the
S-Function Builder editor.
Tag to choose | Purpose |
---|---|
LIB_PATH | Specify object and library paths. . |
INC_PATH | Specify the include search paths for header files and source files. |
SRC_PATH | Specify search paths for object files and source files. |
ENV_PATH | Specify environment variables. |
ENTRY | Specify the object, source, and library file names. You can also enter
preprocessor directives in this field, for example, |
Enclose the names of the header files on the top of the code editor. If you are using
custom header files that are not on the same path, make sure to include the directory with
the INC_PATH
tag. Similarly, use the top of the editor to declare of
external functions that are not declared in the header files. Include each declaration on a
separate line.
You can enter paths or entries for to the external libraries, object codes, and source files referenced by custom code on the S-Function Builder editor.
For example, consider an S-Function Builder project in C:\Program
Files\MATLAB\work
. The table shows on how to link to external
files:
File Locations | Entries to the Libraries Table |
---|---|
|
|
C:\Program
Files\MATLAB\work\customobjs\userfunctions.obj |
|
|
|
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. List multiple LIB_PATH
entries on separate
lines. The paths are searched in the order you specify.
Each directive must be listed on a separate line.
Note
Do not put quotation marks around the library path, even if the path name has spaces in it. If you add quotation marks, the compiler will not find the library.
S-Function Builder uses wrapper methods to specify the S-function code and properties that generate the corresponding S-function. Use the appropriate wrapper methods to construct the S-function body. Click Apply on the toolstrip to generate the S-function code.
This table provides a summary of S-Function Builder methods:
S-Function Method | Wrapper Method | Purpose |
---|---|---|
Start and Terminate |
| Allocate and deallocate memory at the start and the end of simulation.
Allocated memory is referenced using PWorks for use throughout
the S-Function. |
Outputs |
| Enter the code that computes the outputs of the S-function at each simulation time step. |
Update |
| Enter the code that computes the value of discrete states at the next time step using the values at the current time step. This method only exists when you specify Number of Discrete States on the Settings table. |
Derivatives |
| Enter the code to compute state derivatives. This method only exists when you specify Number of Continuous States on the Settings table. |
Now, you can investigate these methods in more detail.
In the S-Function Builder, use the Outputs_wrapper
method to enter
the code that computes the outputs of the S-function at each simulation time step. Note
that when generating the S-function code, S-Function Builder generates a
wrapper method using the name of your model and a wrapper function in the form of
<system_name>_<function_name>_wrapper
. For example, if your
model's name is dsfunc_builder
, the output method appears as
dsfunc_builder_Output_wrapper
in the S-Function
Builder editor. If you do not have a name for your S-Function
Builder block yet, it appears as system_Output_wrapper
.
See the following code for an example of the Outputs
method:
void sfun_Outputs_wrapper(const real_T *u, real_T *y, const real_T *xD, /* optional */ const real_T *xC, /* optional */ const real_T *param0, /* optional */ int_T p_width0 /* optional */ real_T *param1 /* optional */ int_t p_width1 /* optional */ int_T y_width, /* optional */ int_T u_width) /* optional */ { /* Your code inserted here */ } |
where sfun
is the name of the S-function. The S-Function Builder
inserts a call to this wrapper function in the mdlOutputs
callback method that it generates for your S-function. The
Simulink engine invokes the mdlOutputs
method at each simulation
or sample time step to compute the S-function output. The mdlOutputs
method in turn invokes the wrapper function containing your output code. Your output code
then computes and returns the S-function output.
The mdlOutputs
method passes some or all of the following arguments
to the outputs wrapper function.
Argument | Description |
---|---|
u0, u1, ... uN | Pointers to arrays containing the inputs to the S-function, where
N is the number of input ports specified on the
Input scope found on the Ports and
Parameters table. The names of the arguments that appear in the
outputs wrapper function are the same as the names found on the
Input scope of the Ports and
Parameters table. The width of each array is the same as the input
width specified for each input on the Dimensions pane. If the
input is a matrix, the width equals the product of the dimensions of the arrays.
If you specify -1 as an input width, the width of the array is specified by the
wrapper function's u_width argument. |
y0, y1, ... yN | Pointer to arrays containing the outputs of the S-function, where
N is the number of output ports specified on the
Scope pane on the Ports and Parameters
table. The names of the arguments that appear in the outputs wrapper function are
the same as the names found on the Output scope of
Ports and Parameters table. The width of each array is the
same as the output width specified for each output on the
Dimensions pane. If an output is a matrix, the width equals
the product of the dimensions of the arrays. If you specified -1 as the output
width, the width of the array is specified by the wrapper function's
y_width argument. Use this array to pass the outputs that
your code computes back to the Simulink engine. |
xD | Pointer to an array containing the discrete states of the S-function. This argument appears only if you specify discrete states on the Number of discrete states in the Settings menu. At the first simulation time step, the discrete states have the initial values that you specify on the Discrete states IC. At subsequent sample-time steps, the states are obtained from the values that the S-function computes at the preceding time step. |
xC | Pointer to an array containing the continuous states of the S-function. This argument appears only if you specify number of continuous states on the Number of continuous states row of the Settings menu. At the first simulation time step, the continuous states have the initial values that you specify on the Continuous states IC row. At subsequent time steps, the states are obtained by numerically integrating the derivatives of the states at the preceding time step. |
param0 , p_width0 ,
param1 , p_width1 , ...
paramN , p_widthN | param0 , param1 ,
...paramN are pointers to arrays containing the S-function
parameters, where N is the number of parameters specify on the
Ports and Parameters table. 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. |
y_width | Width of the array containing the S-function outputs. This argument appears
in the generated code only if you specify -1 as the width of
the S-function output. If the output is a matrix, y_width is
the product of the dimensions of the matrix. |
u_width | Width of the array containing the S-function inputs. This argument appears in
the generated code only if you specify -1 as the width of the
S-function input. If the input is a matrix, u_width is the
product of the dimensions of the matrix. |
These arguments permit you to compute the output of the block as a function of its inputs and, optionally, its states and parameters. The code that you enter in this field can invoke external functions declared in the header files or external declarations on the Libraries table, which allows you to use existing code to compute the outputs of the S-function.
Use the Update_wrapper
function to enter code that computes the
values of the discrete states at the next time step according to the values at the current
time step. See the following code:
void sfun_Update_wrapper(const real_T *u, const real_T *y, real_T *xD, const real_T *param0, /* optional */ int_T p_width0, /* optional */ real_T *param1,/* optional */ int_T p_width1, /* optional */ int_T y_width, /* optional */ int_T u_width) /* optional */ { /* Your code inserted here. */ }
where sfun
is the name of the S-function. The S-Function Builder
inserts a call to this wrapper function in the mdlUpdate
callback method that it generates for the S-function. The
Simulink engine calls the mdlUpdate
method at the end of each time
step to obtain the values of the discrete states at the next time step (see Simulink Engine Interaction with C S-Functions). At the next
time step, the engine passes the updated states back to the mdlOutputs
method.
The mdlUpdate
callback method generated for the S-function passes
the following arguments to the Update_wrapper
function:
u
y
xD
param0
, p_width0
, param1
,
p_width1
, ... paramN
,
p_widthN
y_width
u_width
See Compute Outputs Using Outputs Method for the meanings and
usage of these arguments. Your code should use the discrete states variable,
xD
, to return the values of the discrete states that it computes. The
arguments allow your code to compute the discrete states as functions of the S-function
inputs, outputs, and, optionally, parameters. Your code can invoke external functions
declared in the code editor.
If the S-function has continuous states, use the
Derivatives_wrapper
function to enter the code required to compute
the state derivatives. Enter code for the mdlDerivatives
function to
compute the derivatives of the continuous states editor under this field. An example
declaration of the function may look like the following:
void system_Derivatives_wrapper(const real_T *u, const real_T *y, real_T *dx, real_T *xC, const real_T *param0, /* optional */ int_T p_width0, /* optional */ real_T *param1,/* optional */ int_T p_width1, /* optional */ int_T y_width, /* optional */ int_T u_width) /* optional */ { /* Your code inserted here. */ } |
where system
is the name of the S-function.
The S-Function Builder inserts a call to this wrapper function in the mdlDerivatives
method that it generates for the S-function. The Simulink engine calls the mdlDerivatives
method at the end of each
time step to obtain the derivatives of the continuous states (see Simulink Engine Interaction with C S-Functions). The Simulink solver numerically integrates the derivatives to determine the continuous
states at the next time step. At the next time step, the engine passes the updated states
back to the mdlOutputs
method. For more information on how
Simulink engine interacts with S-functions, see Simulink Engine Interaction with C S-Functions.
The mdlDerivatives
method generated for the S-function passes the
following arguments to the derivatives wrapper function:
u
y
dx
xC
param0
, p_width0
, param1
,
p_width1
, ... paramN
,
p_widthN
y_width
u_width
The dx
argument is a pointer to an array whose width is the same as
the number of continuous derivatives specified on the Settings pane.
Your code should use this array to return the values of the derivatives that it computes.
See the explanation under Compute Outputs Using Outputs Method method for the
meanings and usage of the other arguments. The arguments allow your code to compute
derivatives as a function of the S-function inputs, outputs, and, optionally, parameters.
Your code can invoke external functions declared in the code editor.
Use the Start_wrapper
method to write code to allocate memory at
the start of simulation. The allocated is referenced by Pworks
for use
throughout the S-function. Similarly, use the Terminate_wrapper
method
to write code to free up the memory allocated at the Start_wrapper
method. Memory referenced by PWorks
can also be seen by
Terminate, and should be deallocated here.
See the Set the Number of PWorks to learn more about
PWorks
.
After entering the code in the S-Function Builder editor, investigate the options under Build menu to build your S-function.
The build menu contains the following selections:
Show compile steps — Log each build step in the Build Log field.
Create a debuggable MEX-file — Include debugging information in the generated MEX file.
Generate wrapper TLC — Selecting this option allows you to generate a TLC file. You need to generate a TLC file if you are running your model in Rapid Accelerator mode or generating Simulink Coder™ code from your model. Also, while it is not necessary for Accelerator mode simulations, the TLC file generates code for the S-function and thus makes your model run faster in Accelerator mode.
Enable support for coverage — Make an S-Function compatible with model coverage. For more information, see Coverage for Custom C/C++ Code in Simulink Models (Simulink Coverage) in the Simulink Coverage™ documentation.
Enable support for design verifier — Generate an S-function for use with the Simulink Design Verifier™. For more information, see Support Limitations for S-Functions and C/C++ Code (Simulink Design Verifier).
When you make your selection, click Build to build your S-function and build a MEX-file. To exclude building of a MEX-file from the generated source code, select Generate Code Only.
S-Function | S-Function Builder