Create and Implement a Basic C MEX S-Function
This topic explains how to create basic C MEX S-Functions (system-functions), how C MEX S-functions interact with Simulink®, and a simple example of creating a C MEX S-Function and implementing it in a Simulink model.
S-functions provide a powerful mechanism for extending the capabilities of the Simulink environment. An S-function is a computer language
description of a Simulink block written in MATLAB®, C, C++, or Fortran. For blocks written in C, C++, or Fortran, use C Mex
S-functions. C, C++, and Fortran® S-functions are compiled as MEX files using the mex
utility
(see Build C MEX Function). As with other MEX files,
S-functions are dynamically linked subroutines that the MATLAB execution engine can automatically load and execute.
How to Create C MEX S-Functions
You can create C MEX S-functions using any of the following approaches:
Handwritten S-function — You can write a C MEX S-function from scratch. (Create and Implement a Basic C MEX S-Function provides a step-by-step example.) See Templates for C S-Functions for a complete skeleton implementation of a C MEX S-function that you can use as a starting point for creating your own S-functions. Although handwritten S-functions support the widest range of features, they can be difficult to write.
S-Function Builder — This block integrates a C/C++ code and builds a C MEX S-function from specifications and code fragments that you supply using a graphical user interface. This eliminates the need for you to write S-functions from scratch. The S-Function Builder block simplifies the task of writing C MEX S-functions but supports fewer features. See Use a Bus with S-Function Builder to Create an S-Function for more information about the S-Function Builder block.
Simulink Coder™— Simulink Coder product provides a method for generating a C MEX S-function from a graphical subsystem. If you are new to writing C MEX S-functions, you can build portions of your application in a Simulink subsystem and use the S-function target to convert it to an S-function. The generated files provide insight on how particular blocks can be implemented within an S-function. For details and limitations on using the S-function target, see Use S-Function Target for Model or Subsystem (Simulink Coder). You can develop an S-function to represent external code using an API that interacts with the Simulink engine. Use this S-function with the code generator to produce code. For details regarding different types of S-functions in code generation, see S-Functions and Code Generation (Simulink Coder).
See Available S-Function Implementations for more information on the features and limitations of each of these approaches to writing a C MEX S-function.
How C MEX S-Function Interacts with Simulink
A C MEX S-function must provide information about the function to the Simulink engine during the simulation. As the simulation proceeds, the engine, the ODE solver, and the C MEX S-function interact to perform specific tasks. These tasks include defining initial conditions and block characteristics, and computing derivatives, discrete states, and outputs.
As with MATLAB S-functions, the Simulink engine interacts with a C MEX S-function by invoking callback methods that the S-function implements.
Each method performs a predefined task, such as computing block outputs, required to
simulate the block whose functionality the S-function defines. However, the S-function is
free to perform the task in each method according to the functionality the S-function
implements. For example, the mdlOutputs
method must compute the block
outputs at the current simulation time. However, the S-function can calculate these outputs
in any way that is appropriate for the function. This callback-based API allows you to
create S-functions, and hence custom blocks, of any desired functionality.
The set of callback methods that C MEX S-functions can implement is larger than that available for MATLAB S-functions. C MEX S-functions are required to implement only a small subset of the callback methods in the S-function API. If your block does not implement a particular feature, such as matrix signals, you are free to omit the callback methods needed to implement a feature. This allows you to create simple blocks very quickly.
The general format of a C MEX S-function is shown below:
#define S_FUNCTION_NAME /* your_sfunction_name_here */ #define S_FUNCTION_LEVEL 2 #include "simstruc.h" static void mdlInitializeSizes(SimStruct *S) { } /* <additional S-function routines/code> */ static void mdlTerminate(SimStruct *S) { } #ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file? */ #include "simulink.c" /* MEX-file interface mechanism */ #else #include "cg_sfun.h" /* Code generation registration function */ #endif
mdlInitializeSizes
is the first routine the Simulink engine calls when interacting with the S-function. The engine subsequently
invokes other S-function methods (all starting with mdl
). At the end of a
simulation, the engine calls mdlTerminate
.
Introducing an Example of a Basic C MEX S-Function
This section presents an example of a C MEX S-function that you can use as a model for
creating simple C S-functions. The example S-function timestwo.c
outputs
twice its input.
The following model uses the timestwo
S-function to double the
amplitude of a sine wave and plot it in a scope.
The block dialog for the S-function specifies timestwo
as the
S-function name; the parameters field is empty.
The timestwo
S-function contains the S-function callback methods
shown in this figure. At the end of S-function, include the code snippet as described in
Simulink/Simulink Coder Interfaces.
The contents of timestwo.c
are shown below. A description of the code
is provided after the example.
#define S_FUNCTION_NAME timestwo #define S_FUNCTION_LEVEL 2 #include "simstruc.h"
static void mdlInitializeSizes(SimStruct *S) { ssSetNumSFcnParams(S, 0); if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) { return; /* Parameter mismatch reported by the Simulink engine*/ } if (!ssSetNumInputPorts(S, 1)) return; ssSetInputPortWidth(S, 0, DYNAMICALLY_SIZED); ssSetInputPortDirectFeedThrough(S, 0, 1); if (!ssSetNumOutputPorts(S,1)) return; ssSetOutputPortWidth(S, 0, DYNAMICALLY_SIZED); ssSetNumSampleTimes(S, 1); /* Take care when specifying exception free code - see sfuntmpl.doc */ ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE); }
static void mdlInitializeSizes(SimStruct *S) { ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME); ssSetOffsetTime(S, 0, 0.0); }
static void mdlOutputs(SimStruct *S, int_T tid) { int_T i; InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0); real_T *y = ssGetOutputPortRealSignal(S,0); int_T width = ssGetOutputPortWidth(S,0); for (i=0; i<width; i++) { *y++ = 2.0 *(*uPtrs[i]); } }
static void mdlTerminate(SimStruct *S){}
#ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file? */ #include "simulink.c" /* MEX-file interface mechanism */ #else #include "cg_sfun.h" /* Code generation registration function */ #endif
This example has three parts:
Defines and includes
Callback method implementations
Simulink (or Simulink Coder) product interfaces
Defines and Includes
The example starts with the following define
statements.
#define S_FUNCTION_NAME timestwo #define S_FUNCTION_LEVEL 2
The first define
statement specifies the name of the S-function
(timestwo
). The second define
statement specifies
that the S-function is in the Level 2 format (for more information
about Level 1 and Level 2 S-functions, see Convert Level-1 C MEX S-Functions).
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.
#define S_FUNCTION_NAME timestwo #define S_FUNCTION_LEVEL 2 #include "simstruc.h"
The simstruc.h
file defines a data structure, called the
SimStruct
, that the Simulink engine uses to maintain information about the S-function. The
simstruc.h
file also defines macros that enable your MEX file to set
values in and get values (such as the input and output signal to the block) from the
SimStruct
(see About SimStruct Functions).
Callback Method Implementations
The next part of the timestwo
S-function contains implementations of
required callback methods.
mdlInitializeSizes
The Simulink engine calls mdlInitializeSizes
to inquire about the
number of input and output ports, sizes of the ports, and any other information (such as
the number of states) needed by the S-function.
The timestwo
implementation of
mdlInitializeSizes
specifies the following size information:
Zero parameters
Therefore, the S-function parameters field of the S-Function Block Parameters dialog box must be empty. If it contains any parameters, the engine reports a parameter mismatch.
One input port and one output port
The widths of the input and output ports are dynamically sized. This tells the engine that the S-function can accept an input signal of any width. By default, the widths of dynamically sized input and output port are equal when the S-function has only one input and output port.
One sample time
The
mdlInitializeSampleTimes
callback method specifies the actual value of the sample time.Exception free code
Specifying exception-free code speeds up execution of your S-function. You must take care when specifying this option. In general, if your S-function is not interacting with the MATLAB environment, you can safely specify this option. For more details, see Simulink Engine Interaction with C S-Functions.
mdlInitializeSampleTimes
The Simulink engine calls mdlInitializeSampleTimes
to set the sample
times of the S-function. A timestwo
block executes whenever the driving
block executes. Therefore, it has a single inherited sample time,
INHERITED_SAMPLE_TIME
.
mdlOutputs
The engine calls mdlOutputs
at each time step to calculate
the block outputs. The timestwo
implementation of
mdlOutputs
multiplies the input signal by 2 and writes the answer to
the output.
The line:
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
accesses the input signal. The ssGetInputPortRealSignalPtrs
macro
returns a vector of pointers, which you must access using
*uPtrs[i]
For more details on accessing input signals, see Accessing Signals Using Pointers.
The line:
real_T *y = ssGetOutputPortRealSignal(S,0);
accesses the output signal. The ssGetOutputPortRealSignal
macro
returns a pointer to an array containing the block outputs.
The line:
int_T width = ssGetOutputPortWidth(S,0);
obtains the width of the signal passing through the block. The S-function loops over the inputs to compute the outputs.
mdlTerminate
The engine calls mdlTerminate
to provide the S-function with an
opportunity to perform tasks at the end of the simulation. This is a mandatory S-function
routine. The timestwo
S-function does not perform any termination
actions, and this routine is empty.
Simulink/Simulink Coder Interfaces
At the end of the S-function, include the following code to attach your S-function to either the Simulink or Simulink Coder products.
#ifdef MATLAB_MEX_FILE #include "simulink.c" #else #include "cg_sfun.h" #endif
This trailer is required at the end of every S-function. If it is omitted, any attempt
to compile your S-function will abort with a failure during build of exports
file
error message.
Building the Timestwo Example
To compile this S-function, enter
mex timestwo.c
at the command line. The mex
command compiles and links the
timestwo.c
file using the default compiler. The mex
command creates a dynamically loadable executable for the Simulink software to use. If you have multiple MATLAB-supported compilers, you can change the default using the mex
-setup
command. See Change Default Compiler and the list of
Supported Compilers.
The resulting executable is referred to as a MEX S-function, where MEX stands for
“ MATLAB Executable. ” The MEX file extension varies from platform to platform.
For example, on a 32–bit Microsoft®
Windows® system, the MEX file extension is .mexw32
.