Main Content

Create a Basic C MEX S-Function

About 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 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.

  • S-Function Builder — This block integrates a C/C++ code and builds a C MEX S-function from specifications and code fragments that you supply using a graphical user interface. This eliminates the need for you to write S-functions from scratch. See Use a Bus with S-Function Builder to Create an S-Function for more information about the S-Function Builder.

  • Legacy Code Tool — This utility builds a C MEX S-function from existing C code and specifications that you supply using MATLAB® code. See Integrate C Functions Using Legacy Code Tool for more information about integrating legacy C code into Simulink® models.

Each of these approaches involves a tradeoff between the ease of writing an S-function and the features supported by the S-function. Although handwritten S-functions support the widest range of features, they can be difficult to write. The S-Function Builder block simplifies the task of writing C MEX S-functions but supports fewer features. The Legacy Code Tool provides the easiest approach to creating C MEX S-functions from existing C code but supports the fewest features. See Available S-Function Implementations for more information on the features and limitations of each of these approaches to writing a C MEX S-function.

If you have Simulink Coder™, in addition to the previous three approaches, the Simulink Coder product provides a method for generating a C MEX S-function from a graphical subsystem. If you are new to writing C MEX S-functions, you can build portions of your application in a Simulink subsystem and use the S-function target to convert it to an S-function. The generated files provides insight on how particular blocks can be implemented within an S-function. For details and limitations on using the S-function target, see 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).

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 /* Defines and Includes */
#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 mdlInitializeSampleTimes(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.