Modeling Simulation Implementation Writing S-Functions Version 3
How to Contact The MathWorks: ☎ 508-647-7000 Phone 508-647-7001 Fax The MathWorks, Inc. 24 Prime Park Way Natick, MA 01760-1500 Mail http://www.mathworks.com Web Anonymous FTP server Newsgroup PHONE FAX ✉ MAIL INTERNET ftp.mathworks.com comp.soft-sys.matlab @ support@mathworks.com suggest@mathworks.com bugs@mathworks.com doc@mathworks.com subscribe@mathworks.com service@mathworks.com info@mathworks.
Contents Overview of S-Functions 1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-2 What Is an S-Function? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-2 When to Use an S-Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-4 How S-Functions Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-4 Overview of M-File and C MEX S-Functions . . . . . . . . . . . . . . . 1-7 S-Function Concepts . . . . . . . .
Writing S-Functions As C-MEX files 3 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-2 Writing Basic C MEX S-Functions . . . . . . . . . . . . . . . . . . . . . . 3-4 ii Contents Creating More Complex C MEX S-Functions . . . . . . . . . . . . Statements Required at the Top of S-Functions . . . . . . . . . . . Statements Required at the Bottom of S-Functions . . . . . . . . Conditionally Compiling S-Functions . . . . . . . . . . . . . . . . . . . .
Function-Call Subsystems . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-95 The C MEX S-Function SimStruct . . . . . . . . . . . . . . . . . . . . . 3-97 Converting Level 1 C MEX S-Functions to Level 2 . . . . . . 3-118 Guidelines for Writing C MEX S-Functions 4 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Classes of Problems Solved by S-Functions . . . . . . . . . . . . . . . . Types of S-Functions . . . . . . . . . . . . . . . . . . . . . . .
iv Contents
1 Overview of S-Functions Introduction . . . . . . . . . . . . What Is an S-Function? . . . . . . . . When to Use an S-Function . . . . . . How S-Functions Work . . . . . . . . Overview of M-File and C MEX S-Functions S-Function Concepts . . . . . . . . . Sample S-Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-2 . 1-2 . 1-4 . 1-4 . 1-7 . 1-9 .
1 Overview of S-Functions Introduction S-functions (system-functions) provide a powerful mechanism for extending the capabilities of Simulink®. The introductory sections of this chapter describe what an S-function is and when and why you might use one. This chapter then presents a comprehensive description of how to write your own S-functions. S-functions allow you to add your own algorithms to Simulink models. You can write your algorithms in MATLAB® or C.
Introduction S-Function dialog box S-function source file /* * MYSFUN * */ /* The follo #define S_FU . . . A model that includes two S-Function blocks S-Function1 dialog box C MEX-file or function[sys % mysfun M-file % switch(flag) . . . M-file Figure 1-1: The Relationship Between an S-Function Block, Its Dialog Box, and the Source File That Defines the Block’s Behavior In this example, the model contains two instances of an S-Function block.
1 Overview of S-Functions When to Use an S-Function The most common use of S-functions is to create custom Simulink blocks.
Introduction blocks with no states, x is an empty vector. In MEX-file S-functions, there are two separate state vectors for the continuous and discrete states. Simulation Stages and S-Function Routines Simulink makes repeated calls during specific stages of simulation to each block in the model, directing it to perform tasks such as computing its outputs, updating its discrete states, or computing its derivatives.
1 Overview of S-Functions Initialize model Calculate time of next sample hit (only for variable sample time blocks) Simulation loop Calculate outputs in major time step Update discrete states in major time step Calculate derivatives Calculate derivatives Calculate outputs Calculate derivatives Locate zero crossings At termination perform any required tasks.
Introduction Simulink makes repeated calls to S-functions in your model. During these calls, Simulink calls S-function routines (also called methods), which perform tasks required at each stage. These tasks include: • Initialization — Prior to the first simulation loop, Simulink initializes the S-function. During this stage, Simulink: - Initializes the SimStruct, a simulation structure that contains information about the S-function. - Sets the number and size of input and output ports.
1 Overview of S-Functions calls the appropriate functions for each flag value. For a C MEX S-function, Simulink calls the S-function routines directly. This table lists the simulation stages, the corresponding S-function routines, and the associated flag value for M-file S-functions.
Introduction S-Function Concepts Understanding these key concepts should enable you to build S-functions correctly: • Direct feedthrough • Dynamically sized inputs • Setting sample times and offsets Direct Feedthrough Direct feedthrough means that the output or the variable sample time 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: • The output function (mdlOutputs or flag==3) is a function of the input u.
1 Overview of S-Functions width can also be used to determine the number of continuous states, the number of discrete states, and the number of outputs. 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).
Introduction • Continuous sample time — For S-functions that have continuous states and/ or nonsampled zero crossings. For this type of S-function, the output changes in minor time steps. • Continuous but fixed in minor time step sample time — For S-functions that need to execute at every major simulation step, but do not change value during minor time steps.
1 Overview of S-Functions S-functions can be either single or multirate; a multirate S-function has multiple sample times. Sample times are specified in pairs in this format: [sample_time, offset_time]. The valid sample time pairs are [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.
Introduction • A discrete S-function that changes at a specified rate should register the discrete sample time pair, [discrete_sample_time_period, offset], where discrete_sample_period > 0.0 and 0.0 ≤ offset < discrete_sample_period • A discrete S-function that changes at a variable rate should register the variable step discrete sample time: [VARIABLE_SAMPLE_TIME, 0.0] The mdlGetTimeOfNextVarHit routine is called to get the time of the next sample hit for the variable step discrete task.
1 Overview of S-Functions The simulink/blocks directory contains many M-file S-functions. Consider starting off by looking at these files. Table 1-2: Example M-File S-Functions Filename Description csfunc.m Defines a continuous system in state-space format. dsfunc.m Defines a discrete system in state-space format. vsfunc.m Illustrates how to create a variable step block.
Introduction Table 1-2: Example M-File S-Functions (Continued) Filename Description sfun_varargm.m This is an example M-file S-function showing how to use the MATLAB vararg facility. vlimintm.m An 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. vdlimintm.m An example of a discrete limited integrator S-function. This example is identical to vlimint.
1 Overview of S-Functions Table 1-3: Example C MEX S-Functions (Continued) 1-16 Filename Description mixedmex.c Implements a hybrid dynamical system with a single output and two inputs. quantize.c An example MEX-file for a vectorized quantizer block. Quantizes the input into steps as specified by the quantization interval parameter, q. resetint.c A reset integrator. sftable2.c A two-dimensional table lookup in S-function form. sfun_dynsize.
Introduction Table 1-3: Example C MEX S-Functions (Continued) Filename Description simomex.c Implements a single output, two input state-space dynamical system described by these state-space equations dx/dt = Ax + Bu y = Cx + Du where x is the state vector, u is vector of inputs, and y is the vector of outputs. stspace.c Implements a set of state-space equations. You can turn this into a new block by using the S-Function block and mask facility.
1 Overview of S-Functions 1-18
2 Writing S-Functions As M-Files Introduction . . . . . . . . . . . . . . . . . . . . 2-2 Defining S-Function Block Characteristics . . . . . . . . 2-3 A Simple M-File S-Function Example . . . . . . . . . . 2-4 Examples of M-File S-Functions . . Example - Continuous State S-Function Example - Discrete State S-Function . . Example - Hybrid System S-Functions . Example - Variable Step S-Functions . Passing Additional Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2 Writing S-Functions As M-Files Introduction An M-file that defines an S-Function block must provide information about the model; Simulink needs this information during simulation. As the simulation proceeds, Simulink, the ODE solver, and the M-file interact to perform specific tasks. These tasks include defining initial conditions and block characteristics, and computing derivatives, discrete states, and outputs.
Introduction Building S-functions can be thought of as two separate tasks: • Initializing block characteristics, including number of inputs, outputs, initial conditions of continuous and discrete states, and sample times • Placing your algorithms in the appropriate S-function routine Defining S-Function Block Characteristics For Simulink to recognize an M-file S-function, you must provide it with specific information about the S-function.
2 Writing S-Functions As M-Files A Simple M-File S-Function Example The easiest way to understand how S-functions work is to look at a simple example. This block takes an input scalar signal, doubles it, and plots it to a scope: The M-file code that contains the S-function is modeled on an S-function template called sfuntmpl.m, which is included with Simulink. By using this template, you can create an M-file S-function that is very close in appearance to a C MEX S-function.
Introduction The first four input arguments, which Simulink passes to the S-function, must be the variables t, x, u, and flag: • t, the time • x, the state vector (required even if, as in this case, there are no states) • u, the input vector • flag, the parameter that controls the S-function subroutine calls at each simulation stage Simulink also requires that the output parameters, sys, x0, str, and ts be placed in the order given. These parameters are: • sys, a generic return argument.
2 Writing S-Functions As M-Files Below are the S-function subroutines that timestwo.m calls: %============================================================== % Function mdlInitializeSizes initializes the states, sample % times, state ordering strings (str), and sizes structure. %============================================================== function [sys,x0,str,ts] = mdlInitializeSizes % Call function simsizes to create the sizes structure.
Introduction To test this S-function in Simulink, connect a sine wave generator to the input of an S-Function block. Connect the output of the S-Function block to a Scope. Double-click on the S-Function block to open the dialog box: Enter the function name here. In this example, type timestwo. If you have additional parameters to pass to the block, enter their names here, separating them with commas. In this example, there are no additional parameters. You can now run this simulation.
2 Writing S-Functions As M-Files Examples of M-File S-Functions The simple example discussed above (timestwo) has no states. Most S-Function blocks require the handling of states, whether continuous or discrete. The sections that follow discuss four common types of systems you can model in Simulink using S-functions: • Continuous • Discrete • Hybrid • Variable-step All examples are based on the M-file S-function template found in sfuntmpl.m.
Examples of M-File S-Functions Example - Continuous State S-Function Simulink includes a function called csfunc.m, which is an example of a continuous state system modeled in an S-function. Here is the code for the M-file S-function: function [sys,x0,str,ts] = csfunc(t,x,u,flag) % CSFUNC An example M-file S-function for defining a system of % continuous state equations: % x' = Ax + Bu % y = Cx + Du % % Generate a continuous linear system: A=[−0.09 −0.
2 Writing S-Functions As M-Files %============================================================== % mdlInitializeSizes % Return the sizes, initial conditions, and sample times for the % S-function. %============================================================== % function [sys,x0,str,ts] = mdlInitializeSizes(A,B,C,D) % % Call simsizes for a sizes structure, fill it in and convert it % to a sizes array. % sizes = simsizes; sizes.NumContStates = 2; sizes.NumDiscStates = 0; sizes.NumOutputs = 2; sizes.
Examples of M-File S-Functions % End of mdlDerivatives. % %============================================================== % mdlOutputs % Return the block outputs. %============================================================== % function sys = mdlOutputs(t,x,u,A,B,C,D) sys = C*x + D*u; % End of mdlOutputs. The above example conforms to the simulation stages discussed earlier in this chapter. Unlike timestwo.
2 Writing S-Functions As M-Files function [sys,x0,str,ts] = dsfunc(t,x,u,flag) % An example M-file S-function for defining a discrete system. % This S-function implements discrete equations in this form: % x(n+1) = Ax(n) + Bu(n) % y(n) = Cx(n) + Du(n) % % Generate a discrete linear system: A=[–1.3839 –0.5097 1.0000 0]; B=[–2.5559 0 0 4.2382]; C=[ 0 2.0761 0 7.7891]; D=[ –0.8141 –2.9334 1.
Examples of M-File S-Functions % Call simsizes for a sizes structure, fill it in, and convert it % to a sizes array. sizes = simsizes; sizes.NumContStates = 0; sizes.NumDiscStates = 2; sizes.NumOutputs = 2; sizes.NumInputs = 2; sizes.DirFeedthrough = 1; % Matrix D is non-empty. sizes.NumSampleTimes = 1; sys = simsizes(sizes); x0 = ones(2,1); % Initialize the discrete states. str = []; % Set str to an empty matrix. ts = [1 0]; % sample time: [period, offset] % End of mdlInitializeSizes.
2 Writing S-Functions As M-Files Example - Hybrid System S-Functions Simulink includes a function called mixedm.m, which is an example of a hybrid system (a combination of continuous and discrete states) modeled in an S-function. Handling hybrid systems is fairly straightforward; the flag parameter forces the calls to the correct S-function subroutine for the continuous and discrete parts of the system.
Examples of M-File S-Functions Here is the code for the M-file S-function: function [sys,x0,str,ts] = mixedm(t,x,u,flag) % A hybrid system example that implements a hybrid system % consisting of a continuous integrator (1/s) in series with a % unit delay (1/z). % % Set the sampling period and offset for unit delay.
2 Writing S-Functions As M-Files sizes.NumOutputs = 1; sizes.NumInputs = 1; sizes.DirFeedthrough = 0; sizes.NumSampleTimes = 2; sys = simsizes(sizes); x0 = ones(2,1); str = []; ts = [0, 0 % sample time dperiod, doffset]; % End of mdlInitializeSizes. % %============================================================== % mdlDerivatives % Compute derivatives for continuous states.
Examples of M-File S-Functions % End of mdlUpdate. % %============================================================== % mdlOutputs % Return the output vector for the S-function. %============================================================== % function sys = mdlOutputs(t,x,u,doffset,dperiod) % Return output of the unit delay if we have a % sample hit within a tolerance of 1e-8. If we % don't have a sample hit then return [] indicating % that the output shouldn't change.
2 Writing S-Functions As M-Files function [sys,x0,str,ts] = vsfunc(t,x,u,flag) % This example S-function illustrates how to create a variable % step block in Simulink.
Examples of M-File S-Functions sizes = simsizes; sizes.NumContStates sizes.NumDiscStates sizes.NumOutputs sizes.NumInputs sizes.DirFeedthrough = = = = = 0; 1; 1; 2; 1; % % % % flag=4 requires direct feedthrough if input u is involved in calculating the next sample time hit. sizes.NumSampleTimes = 1; sys = simsizes(sizes); % % Initialize the initial conditions. % x0 = [0]; % % Set str to an empty matrix. % str = []; % % Initialize the array of sample times.
2 Writing S-Functions As M-Files function sys = mdlOutputs(t,x,u) sys = x(1); % end mdlOutputs % %============================================================== % mdlGetTimeOfNextVarHit % Return the time of the next hit for this block. Note that the % result is absolute time. %============================================================== % function sys = mdlGetTimeOfNextVarHit(t,x,u) sys = t + u(2); % End of mdlGetTimeOfNextVarHit.
3 Writing S-Functions As C-MEX files Introduction . . . . . . . . . . . . . . . . . . . . 3-2 Writing Basic C MEX S-Functions . . . . . . . . . . 3-4 Creating More Complex C MEX S-Functions . . . . . 3-10 Overview of the C MEX S-Function Routines . . . . . 3-15 Examples of C MEX-File S-Function Blocks . . . . . . 3-56 Function-Call Subsystems . . . . . . . . . . . . . . 3-95 The C MEX S-Function SimStruct . . . . . . . . . . 3-97 Converting Level 1 C MEX S-Functions to Level 2 . .
3 Writing S-Functions As C-MEX files 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 MEX-file interact to perform specific tasks. These tasks include defining initial conditions and block characteristics, and computing derivatives, discrete states, and outputs.
Introduction contents. After Simulink calls mdlInitializeSizes, it then interacts with the S-function through various other routines (all starting with mdl). At the end of a simulation, mdlTerminate is called. Unlike M-file S-functions, there is not an explicit flag parameter associated with each C MEX S-function routine. This is because Simulink automatically calls each S-function routine at the appropriate time during its interaction with the S-function.
3 Writing S-Functions As C-MEX files Writing Basic C MEX S-Functions This section discusses basic C MEX S-functions, where basic means an S-function that contains only the required S-function routines. However, the contents of the routines can be as complex as you like. You have the freedom to place any logic in S-function routines as long as the routines conform to their required formats.
Writing Basic C MEX S-Functions To incorporate this S-function into Simulink, create a source file called timestwo.c and place the S-function routines of the above figure in it. Typing mex timestwo.c at the command line directs MATLAB to compile and link the timestwo.c file. This creates a dynamically loadable executable for Simulink’s use. 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.
3 Writing S-Functions As C-MEX files Table 3-1: S-Function Routines Called During Simulation of the timestwo Example (Continued) 3-6 S-Function Routine Description mdlOutputs Calculation of outputs. For our timestwo S-function, mdlOutputs takes the input, multiplies it by two, and writes the answer to the output. This routine is called during the simulation loop each time the output of timestwo needs to be updated. For the above block diagram, it is called at every time step.
Writing Basic C MEX S-Functions The contents of timestwo.c are shown below. #define S_FUNCTION_NAME timestwo #define S_FUNCTION_LEVEL 2 #include “simstruc.
3 Writing S-Functions As C-MEX files There is more information that the timestwo.c example requires: • Defines and includes — The example specifies the name of the S-function (timestwo) and that the S-function is in the level 2 format (for more information about level 1 and level 2 S-functions, see “Converting Level 1 C MEX S-Functions to Level 2” on page 3-118). After defining these two items, the example includes simstruc.
Writing Basic C MEX S-Functions • mdlOutput: - The numerical calculation. mdlOutputs tells Simulink to multiply the input signal by 2.0 and place the result in the output signal. - To access the input signal, use: InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0); where uPtrs is a vector of pointers and must be accessed using: *uPtrs[i] For more details, see “Data View of S-Functions” on page 3–19.
3 Writing S-Functions As C-MEX files Creating More Complex C MEX S-Functions There are numerous S-function routines available for use in C MEX S-functions. Simulink provides template C MEX-file S-functions that include statements that define the necessary functions, as well as comments that should help you write the code needed for your S-function block. The template file, sfuntmpl.
Creating More Complex C MEX S-Functions The following headers are included by matlabroot/simulink/include/ simstruc.h when compiling as a MEX-file. Table 3-2: Header Files Included by Simstruc.h When Compiling as a MEX-File Header File Description matlabroot/extern/include/tmwtypes.h General data types, e.g., real_T matlabroot/extern/include/mex.h MATLAB MEX-file API routines matlabroot/extern/include/matrix.
3 Writing S-Functions As C-MEX files • simulink.c is included if the file is being compiled into a MEX-file. • cg_sfun.h is included if the file is being used in conjunction with the Real-Time Workshop to produce a stand-alone or real-time executable. Note This trailer code must not be in the body of any S-function routine. Conditionally Compiling S-Functions S-functions can be compiled in one of three modes identified by the presence of one of the following defines.
Creating More Complex C MEX S-Functions Note that the second argument to ssSetErrorStatus must be persistent memory. It cannot be a local variable in your procedure. For example, the following will cause unpredictable errors: mdlOutputs() { char msg[256]; {ILLEGAL: to fix use "static char msg[256];"} sprintf(msg,"Error due to %s", string); ssSetErrorStatus(S,msg); return; } The ssSetErrorStatus error handling approach is the suggested alternative to using the mexErrMsgTxt function.
3 Writing S-Functions As C-MEX files your S-function generates an exception when this option is set, unpredictable results will occur. All mex* routines have the potential of long jumping. In addition several mx* routines have the potential of long jumping. To avoid any difficulties, use only the API routines that retrieve a pointer or determine the size of parameters.
Overview of the C MEX S-Function Routines Overview of the C MEX S-Function Routines The following figure shows the calling structure, including optional S-function routines (methods), of a C MEX S-function: 3-15
3 Writing S-Functions As C-MEX files mdlInitializeSizes p. 3-28 mdlSetInputPortWidth/mdlSetOutputPortWidth p. 3-35 Initialization mdlSetInputPortSampleTime/mdlSetOutputPortSampleTime p. 3-33 mdlInitializeSampleTimes p. 3-36 mdlSetWorkWidths p. 3-46 mdlStart p. 3-48 Called during the simulation loop when parameters to your S-function change. mdlCheckParameters Simulation loop p. 3-24 mdlInitializeConditions p. 3-48 mdlProcessParameters p.
Overview of the C MEX S-Function Routines The following sections discuss each of these routines and give an overview of the more common macros used to access the SimStruct data structure. A full list of the macros is given in “The C MEX S-Function SimStruct” on page 3–97. Alternate Calling Structure for the Real Time Workshop If you use the Real-Time Workshop to generate code for a model that contains S-functions, Simulink does not go through the entire calling sequence outlined above.
3 Writing S-Functions As C-MEX files Alternate Calling Structure for External Mode When running Simulink in external mode, the calling sequence for S-function routines changes. This picture shows the correct sequence for external mode: mdlInitializeSizes p. 3-28 mdlSetInputPortWidth/mdlSetOutputPortWidth p. 3-35 mdlSetInputPortSampleTime/mdlSetOutputPortSampleTime p. 3-33 mdlInitializeSampleTimes p. 3-36 mdlSetWorkWidths p. 3-46 p.
Overview of the C MEX S-Function Routines Data View of S-Functions S-function blocks have input and output signals, parameters, 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 • External inputs via the root inport blocks • Ground if the input signal is unconnected or grounded Block outputs can also go to the external outputs via the root outport blocks.
3 Writing S-Functions As C-MEX files The length of the various signals and vectors is configured in the mdlInitializeSizes routine. The signals as well as their length can be accessed in S-function routines that are called during the simulation loop. During the simulation loop, accessing the input signals is performed using: InputRealPtrs uPtrs = ssGetInputPortRealSignalPtrs(S,portIndex) This is an array of pointers, where portIndex starts at 0. There is one for each input port.
Overview of the C MEX S-Function Routines Accessing Input Signals of Individual Ports This section describes how to access all input signals of a particular port and write them to the output port. The figure above shows that the input array of pointers may point to noncontiguous entries in the block I/O vector. The output signals of a particular port form a contiguous vector.
3 Writing S-Functions As C-MEX files entering your S-function. Then the driving source should be connected to each input port as shown in this figure: Source signal Mux S-function Checking and Processing S-Function Parameters You can provide parameters to S-functions that can be changed interactively using the S-Function parameters field of the block’s dialog box.
Overview of the C MEX S-Function Routines and NUM_OF_CHANNELS_PRM. The code uses #define statements to associate particular input arguments with the parameter names.
3 Writing S-Functions As C-MEX files Typically, it is safe to have an mdlCheckParameters in your S-function when it is used with the Real-Time Workshop, providing that when parameter tuning is performed, it is done using Simulink external mode. If you have an mdlProcessParameters routine in your S-function code, you may need to inline the S-function for it to work correctly in external mode. This is necessary because only changes to the tunable parameters are passed to the generated code.
Overview of the C MEX S-Function Routines 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: mdlCheckParameters.
3 Writing S-Functions As C-MEX files mdlProcessParameters mdlProcessParameters is an optional routine that Simulink calls after mdlCheckParameters changes and verifies parameters. The processing is done at the top of the simulation loop when it is safe to process the changed parameters. This routine can only be used in a C MEX S-function. The purpose of this routine is to process newly changed parameters. An example is to cache parameter changes in work vectors.
Overview of the C MEX S-Function Routines Example: mdlProcessParameters. This example processes a string parameter that mdlCheckParameters has verified to be of the form '+++' (where there could be any number of '+' or '-' characters).
3 Writing S-Functions As C-MEX files mdlInitializeSizes function. Supplied macros set values for the structure fields. If a value is not specified, it is initialized to zero. There are additional macros that get various values. For a complete list of built-in macros that work with C language S-functions, see “The C MEX S-Function SimStruct” on page 3–97. mdlInitializeSizes mdlInitializeSizes is the first routine Simulink calls when interacting with an S-function.
Overview of the C MEX S-Function Routines simulation (or the Real-Time Workshop external mode) if an attempt is made to change the parameter. • If your S-function outputs are discrete (e.g., can only take on the values, 1 and 2), then specify SS_OPTION_DISCRETE_VALUED_OUTPUT. • The ssGetPath (the Simulink full model path to the block) and ssGetModelName (here model refers to the S-function name) are available for use.
3 Writing S-Functions As C-MEX files The synopsis is /* Function: mdlInitializeSizes ===============================================* Abstract: * The sizes information is used by Simulink to determine the S-function * block's characteristics (number of inputs, outputs, states, etc.). * * The direct feedthrough flag can be either 1=yes or 0=no. It should be * set to 1 if the input, "u", is used in the mdlOutput function.
Overview of the C MEX S-Function Routines * of the output port which can be DYNAMICALLY_SIZE or greater than zero. */ if (!ssSetNumOutputPorts(S, nOutputPorts)) return; ssSetOutputPortWidth(S, outputPortIdx, width); /* * Set the number of sample times. This must be a positive, nonzero * integer indicating the number of sample times or it can be * PORT_BASED_SAMPLE_TIMES. For multi-rate S-functions, the * suggested approach to setting sample times is via the port * based sample times routine.
3 Writing S-Functions As C-MEX files * the size specified by the port which is usually referred to as * the block width. * * SS_OPTION_DISALLOW_CONSTANT_SAMPLE_TIME - This is used to disable * your S-function block from inheriting a constant sample time. * * SS_OPTION_ASYNCHRONOUS - This option applies only to S-functions that * have no input ports and 1 output port. The output port must be * configured to perform function calls on every element.
Overview of the C MEX S-Function Routines either 1 or N. You can use ssGetInputPortWidth in the routines called during the simulation loop to determine the actual port width being used. You can also specify that input and/or output signals are dynamically sized (via the DYNAMICALLY_SIZED define). Simulink determines the corresponding widths when it propagates vector widths throughout your model. You can influence the vector width propagation via the mdlSetInputPortWidth and mdlSetOutputPort width routines.
3 Writing S-Functions As C-MEX files When inherited port based sample times are specified, the sample time will be one of the following: • continuous: [0.0, 0.0] • discrete: [period, offset] where 0.0 < period < inf and 0.0 <= offset < period Constant, triggered, and variable step sample times will not be propagated to S-functions with port based sample times.
Overview of the C MEX S-Function Routines This is the code synopsis for mdSetOutputPortSampleTime: #if defined(MDL_SET_OUTPUT_PORT_SAMPLE_TIME) && defined(MATLAB_MEX_FILE) static void mdlSetOutputPortSampleTime(SimStruct *S, int_T portIdx, real_T sampleTime, real_T offsetTime) { } #endif /* MDL_SET_OUTPUT_PORT_SAMPLE_TIME */ See matlabrooot/simulink/src/sfun_multirate.c for an example.
3 Writing S-Functions As C-MEX files Setting Sample Times for C MEX S-Functions Simulink supports blocks that execute at different rates. There are two methods by which you can specify the rates (i.e., sample times): • Block-based sample times • Port-based sample times In the case of block-based sample times, your S-function specifies all the sample rates of the block and processes inputs and outputs at the fastest rate specified if all the sample times are integer multiples of the fastest sample time.
Overview of the C MEX S-Function Routines Specifying the Number of Sample Times in mdlInitializeSizes. To configure your S-function block for block-based sample times, use 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. Setting Sample Times and Specifying Function Calls in mdlInitializeSampleTimes.
3 Writing S-Functions As C-MEX files 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 ] [INHERITED_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET] or The following guidelines may help aid in specifying sample times: • A continuous function that changes during minor integration steps should register the [CONTINUOUS_SAMPLE_TIME, 0.0] sample time.
Overview of the C MEX S-Function Routines 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 used the following code fragment to check for a sample hit. Note that you would get incorrect results if you used ssIsSampleHit(S,0,tid).
3 Writing S-Functions As C-MEX files Specifying the Number of Sample Times in mdlInitializeSizes. To specify port-based sample times, use ssSetNumSampleTimes(S, PORT_BASED_SAMPLE_TIMES) with: ssSetInputPortSampleTime(S, idx, period) ssSetInputPortOffsetTime(S, idx, offset) ssSetOutputPortSampleTime(S, idx, period) ssSetOutputPortOffsetTime(S, idx, offset) The inputPortIndex and outputPortIndex range from 0 to the number of input (output) ports minus 1.
Overview of the C MEX S-Function Routines Constant, triggered, and variable step sample times will not be propagated to S-functions with port based sample times. This is the code synopsis for mdlSetInputPortSampleTime: #if defined(MDL_SET_INPUT_PORT_SAMPLE_TIME) && defined(MATLAB_MEX_FILE) static void mdlSetInputPortSampleTime(SimStruct int_T real_T real_T { } #endif /* MDL_SET_INPUT_PORT_SAMPLE_TIME */ *S, portIdx, sampleTime, offsetTime) See matlabrooot/simulink/src/sfun_multirate.c for an example.
3 Writing S-Functions As C-MEX files Multirate S-Function Blocks In a multirate S-Function block, you can encapsulate the code that defines each behavior in the mdlOutput and mdlUpdate functions with a statement that determines whether a sample hit has occurred. The ssIsSampleHit macro determines whether the current time is a sample hit for a specified sample time.
Overview of the C MEX S-Function Routines Example - Defining a Sample Time for a Hybrid Block. This example defines sample times for a hybrid S-Function block. /* Initialize the sample time and offset. */ static void mdlInitializeSampleTimes(SimStruct *S) { /* Continuous state sample time and offset. */ ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME); ssSetOffsetTime(S, 0, 0.0); /* Discrete state sample time and offset. */ ssSetSampleTime(S, 1, 0.1); ssSetOffsetTime(S, 1, 0.
3 Writing S-Functions As C-MEX files Work vectors have several advantages: • Instance specific storage for block variables • Integer, real, pointer, and general data types • Elimination of static and global variables and the associated multiple instance problems For example, suppose you’d like to track the previous value of each input signal element entering input port 1 of your S-function.
Overview of the C MEX S-Function Routines Specify vector widths in mdlInitializeSizes. There are three choices: • 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 will be 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.
3 Writing S-Functions As C-MEX files the mdlZeroCrossings routine to return the nonsampled zero crossings. See matlabroot/simulink/src/sfun_zc.c for an example. mdlSetWorkWidths The optional simulation only routine, mdlSetWorkWidths, is called after input port width, output port width, and sample times of the S-function have been determined to set any state- and work-vector sizes that are a function of the input, output, and/or sample times.
Overview of the C MEX S-Function Routines This code retrieves the FILE pointer from the pointer-work vector and passes it to fclose to close the file: static void mdlTerminate(SimStruct *S) { if (ssGetPWork(S) != NULL) { FILE *fPtr; fPtr = (FILE *) ssGetPWorkValue(S,0); if (fPtr != NULL) { fclose(fPtr); } ssSetPWorkValue(S,0,NULL); } } Note If you are using mdlSetWorkWidths, then any work vectors you use in your S-function should be set to DYNAMICALLY_SIZED in mdlInitializeSizes, even if the exact value i
3 Writing S-Functions As C-MEX files routines. In mdlStart allocate and initialize the memory and place the pointer to it either in pointer-work vector elements ssGetPWork(S)[i] = ptr; or attach it as user data: ssSetUserData(S,ptr); In mdlTerminate, free the allocated memory. S-Function Initialization The S-function routines discussed so far have dealt with defining the S-function characteristics, such as the number of input and output ports and their widths.
Overview of the C MEX S-Function Routines Simulink will call this routine in two places: • At the start of simulation • If it is present in an enabled subsystem configured to reset states. In this case, Simulink will call mdlInitializeConditions when the enabled subsystem restarts execution to reset the states. You can use the ssIsFirstInitCond(S) macro to determine whether the current call is the first to mdlInitializeConditions.
3 Writing S-Functions As C-MEX files S-Function Routines Called During Simulation Conceptually, the way Simulink performs a simulation is that it executes the blocks in your model in the order dictated by their connections. After executing this list of blocks, the process is repeated until the end of simulation is reached. This repeated execution of the blocks is referred to as the simulation loop.
Overview of the C MEX S-Function Routines For an example of an mdlOutputs routine that works with multiple input and output ports, see matlabroot/simulink/src/sfun_multiport.c. mdlUpdate The optional routine mdlUpdate 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.
3 Writing S-Functions As C-MEX files last call to this routine. The memory allocated to the derivative vector changes during execution. The synopsis is: #define MDL_DERIVATIVES /* Change to #undef to remove function. */ #if defined(MDL_DERIVATIVES) static void mdlDerivatives(SimStruct *S) { } #endif /* MDL_DERIVATIVES */ For an example, see matlabroot/simulink/src/csfunc.c.
Overview of the C MEX S-Function Routines mdlTerminate In the mdlTerminate routine, perform any actions that are necessary at the termination of a simulation. For example, if memory was allocated in mdlInitializeSizes or mdlStart, this is the place to free it. Suppose your S-function allocates a few chunks of memory and saves them in PWork.
3 Writing S-Functions As C-MEX files The parameter can also be a variable as in modules = 'sfun_module1 sfun_module2' set_param(sfun_block,'SFunctionModules','modules') or a string to be evaluated (this is needed when the modules are valid identifiers): set_param(sfun_block,'SFunctionModules','''sfun_module1 sfun_module2''') S-Function RTWdata for Generating Code with RTW There is a property of blocks called RTWdata, which can be used by the Target Language Compiler when inlining an S-function.
Overview of the C MEX S-Function Routines routine or your S-function has a “simulation mode” and a “real-time mode” such as a hardware I/O S-function that simulates the I/O device in Simulink and interacts with the I/O device in real-time. To inline an S-function in the generated code, you must use the Target Language Compiler. Details on this can be found in the Real-Time Workshop User’s Guide and Target Language Compiler Reference Guide.
3 Writing S-Functions As C-MEX files Examples of C MEX-File S-Function Blocks 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: • Continuous state • Discrete state • Hybrid • Variable step sample time • Zero crossings • Time varying continuous transfer function All examples are based on the C MEX-file S-function template, sfuntmpl.c, and sfuntmpl.
Examples of C MEX-File S-Function Blocks during which it calls mdlOutputs and mdlDerivatives. Each of these pairs of calls is referred to as an integration stage. The integration returns with the continuous states updated and the simulation time moved forward. Time is moved forward as far as possible, providing that error tolerances in the state are met. The maximum time step is subject to constraints of discrete events such as the actual simulation stop time and the user-imposed limit. Note that csfunc.
3 Writing S-Functions As C-MEX files matlabroot/simulink/src/csfunc.c /* * * * * * * * * * * * */ File : csfunc.c Abstract: Example C-MEX S-function for defining a continuous system. x' = Ax + Bu y = Cx + Du For more details about S-functions, see simulink/src/sfuntmpl.doc. Copyright (c) 1990-1998 by The MathWorks, Inc. All Rights Reserved. $Revision: 1.2 $ #define S_FUNCTION_NAME csfunc #define S_FUNCTION_LEVEL 2 #include "simstruc.
Examples of C MEX-File S-Function Blocks return; /* Parameter mismatch will be reported by Simulink.
3 Writing S-Functions As C-MEX files static void mdlOutputs(SimStruct *S, int_T tid) { real_T *y = ssGetOutputPortRealSignal(S,0); real_T *x = ssGetContStates(S); InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0); /* y=Cx+Du */ y[0]=C[0][0]*x[0]+C[0][1]*x[1]+D[0][0]*U(0)+D[0][1]*U(1); y[1]=C[1][0]*x[0]+C[1][1]*x[1]+D[1][0]*U(0)+D[1][1]*U(1); } #define MDL_DERIVATIVES /* Function: mdlDerivatives ================================================= * Abstract: * xdot = Ax + Bu */ static void mdlDeriv
Examples of C MEX-File S-Function Blocks Example - Discrete State S-Function The matlabroot/simulink/src/dsfunc.c example shows how to model a discrete system in a C MEX S-function. Discrete systems can be modeled by the following set of equations: u (input) y (output) xd (states) y = f 0 ( t, x d, u ) (output) x d + 1 = fu ( t, x d, u ) (update) dsfunc.c implements a discrete state-space equation. The output portion is placed in mdlOutputs and the update portion in mdlUpdate.
3 Writing S-Functions As C-MEX files matlabroot/simulink/src/dsfunc.c /* * * * * * * * * * * * */ File : dsfunc.c Abstract: Example C MEX 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. Copyright (c) 1990-1998 by The MathWorks, Inc. All Rights Reserved. $Revision: 1.3 $ #define S_FUNCTION_NAME dsfunc #define S_FUNCTION_LEVEL 2 #include "simstruc.
Examples of C MEX-File S-Function Blocks return; /* Parameter mismatch will be reported by Simulink */ } ssSetNumContStates(S, 0); ssSetNumDiscStates(S, 2); if (!ssSetNumInputPorts(S, 1)) return; ssSetInputPortWidth(S, 0, 2); ssSetInputPortDirectFeedThrough(S, 0, 1); if (!ssSetNumOutputPorts(S, 1)) return; ssSetOutputPortWidth(S, 0, 2); ssSetNumSampleTimes(S, 1); ssSetNumRWork(S, 0); ssSetNumIWork(S, 0); ssSetNumPWork(S, 0); ssSetNumModes(S, 0); ssSetNumNonsampledZCs(S, 0); /* Take care when specifying exc
3 Writing S-Functions As C-MEX files /* Function: mdlOutputs ======================================================= * Abstract: * y = Cx + Du */ static void mdlOutputs(SimStruct *S, int_T tid) { real_T *y = ssGetOutputPortRealSignal(S,0); real_T *x = ssGetRealDiscStates(S); InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0); /* y=Cx+Du */ y[0]=C[0][0]*x[0]+C[0][1]*x[1]+D[0][0]*U(0)+D[0][1]*U(1); y[1]=C[1][0]*x[0]+C[1][1]*x[1]+D[1][0]*U(0)+D[1][1]*U(1); } #define MDL_UPDATE /* Function: mdlUpdat
Examples of C MEX-File S-Function Blocks Example - Hybrid System S-Functions The S-function, matlabroot/simulink/src/mixedm.c, is an example of a hybrid (a combination of continuous and discrete states) system. mixedm.c combines elements of csfunc.c and dsfunc.c. If you have a hybrid system, place your continuous equations in mdlDerivative and your discrete equations in mdlUpdate. In addition, you need to check for sample hits to determine at what point your S-function is being called.
3 Writing S-Functions As C-MEX files matlabroot/simulink/src/mixedm.c /* File : mixedm.c * Abstract: * * An example C MEX S-function that implements a continuous integrator (1/s) * in series with a unit delay (1/z) * * For more details about S-functions, see simulink/src/sfuntmpl.doc. * * Copyright (c) 1990-1998 by The MathWorks, Inc. All Rights Reserved. * $Revision: 1.4 $ */ #define S_FUNCTION_NAME mixedm #define S_FUNCTION_LEVEL 2 #include "simstruc.
Examples of C MEX-File S-Function Blocks /* Take care when specifying exception free code - see sfuntmpl.doc. */ ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE); } /* Function: mdlInitializeSampleTimes ========================================= * Abstract: * Two tasks: One continuous, one with discrete sample time of 1.0 */ static void mdlInitializeSampleTimes(SimStruct *S) { ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME); ssSetSampleTime(S, 1, 1.0); ssSetOffsetTime(S, 0, 0.0); ssSetOffsetTime(S, 1, 0.
3 Writing S-Functions As C-MEX files real_T *xD = ssGetRealDiscStates(S); real_T *xC = ssGetContStates(S); /* xD=xC */ if (ssIsSampleHit(S, 1, tid)) { xD[0]=xC[0]; } } #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); } /* Function: mdlTerminate ================================
Examples of C MEX-File S-Function Blocks during the simulation. In the transfer function used in this example, the parameters of the transfer function vary with time. The output of vsfunc is simply the input u delayed by a variable amount of time. mdlOutputs sets the output y equal to state x. mdlUpdate sets the state vector x equal to u, the input vector.
3 Writing S-Functions As C-MEX files matlabroot/simulink/src/vsfunc.c /* * * * * * * * * * * * * * * * * * */ File : vsfunc.c Abstract: Example C-file S-function for defining a continuous system. Variable step S-function example. This example S-function illustrates how to create a variable step block in Simulink.
Examples of C MEX-File S-Function Blocks ssSetNumSampleTimes(S, 1); ssSetNumRWork(S, 0); ssSetNumIWork(S, 0); ssSetNumPWork(S, 0); ssSetNumModes(S, 0); ssSetNumNonsampledZCs(S, 0); /* Take care when specifying exception free code - see sfuntmpl.
3 Writing S-Functions As C-MEX files /* Function: mdlOutputs ======================================================= * Abstract: * y = x */ static void mdlOutputs(SimStruct *S, int_T tid) { real_T *y = ssGetOutputPortRealSignal(S,0); real_T *x = ssGetRealDiscStates(S); /* Return the current state as the output */ y[0] = x[0]; } #define MDL_UPDATE /* Function: mdlUpdate ======================================================== * Abstract: * This function is called once for every major integration time step
Examples of C MEX-File S-Function Blocks Example - Zero Crossing S-Function The example S-function, sfun_zc_sat demonstrates how to implement a saturation block. This S-function is designed to work with either fixed or variable step solvers. When this S-function inherits a continuous sample time, and a variable step solver is being used, a zero crossings algorithm is used to locate the exact points at which the saturation occurs. matlabroot/simulink/src/sfun_zc_sat.
3 Writing S-Functions As C-MEX files /*========================* * General Defines/macros * *========================*/ /* index to Upper Limit */ #define I_PAR_UPPER_LIMIT 0 /* index to Upper Limit */ #define I_PAR_LOWER_LIMIT 1 /* total number of block parameters */ #define N_PAR 2 /* * Make access to mxArray pointers for parameters more readable.
Examples of C MEX-File S-Function Blocks 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 */ /* Function: mdlInitializeSizes =============================================== * Abstract: * Initialize the sizes array.
3 Writing S-Functions As C-MEX files /* * states */ ssSetNumContStates(S, 0); ssSetNumDiscStates(S, 0); /* * outputs * The upper and lower limits are scalar expanded * so their size determines the size of the output * only if at least one of them is not scalar.
Examples of C MEX-File S-Function Blocks /* * 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.
3 Writing S-Functions As C-MEX files #define MDL_SET_WORK_WIDTHS #if defined(MDL_SET_WORK_WIDTHS) && defined(MATLAB_MEX_FILE) /* Function: mdlSetWorkWidths =================================================== * The width of the modes and the zero crossings depends on the width of the * output. This width is not always known in mdlInitializeSizes so it is handled * here.
Examples of C MEX-File S-Function Blocks * and having a continuous sample time. Solvers work best on smooth problems. * In order for the solver to work without chattering, limit cycles, or * similar problems, it is absolutely crucial that the same equation be used * throughout the duration of a MajorTimeStep. To visualize this, consider * the case of the Saturation block feeding an Integrator block.
3 Writing S-Functions As C-MEX files for (iOutput = 0; iOutput < numOutput; iOutput++) { if (*uPtrs[uIdx] >= *upperLimit) { *y++ = *upperLimit; } else if (*uPtrs[uIdx] > *lowerLimit) { *y++ = *uPtrs[uIdx]; } else { *y++ = *lowerLimit; } 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.
Examples of C MEX-File S-Function Blocks 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.
3 Writing S-Functions As C-MEX files #define MDL_ZERO_CROSSINGS #if defined(MDL_ZERO_CROSSINGS) && (defined(MATLAB_MEX_FILE) || defined(NRT)) /* Function: mdlZeroCrossings ================================================= * Abstract: * This will only be called if the number of nonsampled zero crossings is * greater than 0, which means this block has a continuous sample time and the * the model is using a variable step solver.
Examples of C MEX-File S-Function Blocks 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.
3 Writing S-Functions As C-MEX files } } #endif /* end mdlZeroCrossings */ /* Function: mdlTerminate ===================================================== * Abstract: * No termination needed, but we are required to have this routine. */ static void mdlTerminate(SimStruct *S) { } #ifdef MATLAB_MEX_FILE #include "simulink.c" #else #include "cg_sfun.
Examples of C MEX-File S-Function Blocks matlabroot/simulink/src/stvctf.c /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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.
3 Writing S-Functions As C-MEX files */ #define S_FUNCTION_NAME stvctf #define S_FUNCTION_LEVEL 2 #include "simstruc.
Examples of C MEX-File S-Function Blocks "the numerator, nonempty and with first " "element nonzero"); return; } /* xxx verify finite */ if (mxGetNumberOfElements(TS(S)) != 1 || mxGetPr(TS(S))[0] <= 0.
3 Writing S-Functions As C-MEX files * NumBank1Coeffs * DenBank1Coeffs) * Number of Integer work elements: 2 (indicator of active bank 0 or 1 * and flag to indicate when banks * have been updated).
Examples of C MEX-File S-Function Blocks ssSetOffsetTime(S, 0, 0.0); /* * the second, discrete sample time, is user provided */ ssSetSampleTime(S, 1, mxGetPr(TS(S))[0]); ssSetOffsetTime(S, 1, 0.0); } /* end mdlInitializeSampleTimes */ #define MDL_INITIALIZE_CONDITIONS /* Function: mdlInitializeConditions ========================================== * Abstract: * Initialize the states, numerator and denominator coefficients.
3 Writing S-Functions As C-MEX files } } /* * 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 */ /* Function: mdlOutputs ======================================================= * Abstract: * The outputs for this block are computed by using a controllable state* space representation of the transfer function.
Examples of C MEX-File S-Function Blocks /* * The continuous system is evaluated using a controllable state space * representation of the transfer function. This implies that the * output of the system is equal to: * * y(t) = Cx(t) + Du(t) * = [ b1 b2 ... bn]x(t) + b0u(t) * * where b0, b1, b2, ... are the coefficients of the numerator * polynomial: * * B(s) = b0 s^n + b1 s^n-1 + b2 s^n-2 + ...
3 Writing S-Functions As C-MEX files 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; } if (allZero) { /* if numerator is all zero */ const real_T *numParam = mxGetPr(NUM(S)); int_T numParamLen = mxGetNumberOfElements(NUM(S)); /* * Move the input to the denominator input and * get the denominator from the input parameter.
Examples of C MEX-File S-Function Blocks * 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.
3 Writing S-Functions As C-MEX files */ 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 */ /* Function: mdlTerminate ===================================================== * Abstract: * Called when the simulation is terminated. * For this block, there are no end of simulation tasks. */ static void mdlTerminate(SimStruct *S) { } /* end mdlTerminate */ #ifdef MATLAB_MEX_FILE #include "simulink.
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: • In the Trigger block, select function-call as the Trigger type parameter. • In the S-function, use the ssCallSystemWithTid macro to call the triggered subsystem.
3 Writing S-Functions As C-MEX files To configure an S-function to call a function-call subsystem: 1 Specify which elements are to execute the function-call system in mdlInitializeSampleTimes. For example: ssSetCallSystemOutput(S,0); ssSetCallSystemOutput(S,2); /* call on 1st element */ /* call on 3rd element */ 2 Execute the subsystem in the appropriate mdlOutputs or mdlUpdates S-function routines. For example: static void mdlOutputs(...
The C MEX S-Function SimStruct The C MEX S-Function 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.
3 Writing S-Functions As C-MEX files Table 3-5: General SimStruct Macros (Continued) 3-98 Macro Description ssGetParentSS(S) This is typically not used in S-functions. It returns the parent SimStruct or NULL if the S is the root SimStruct. ssGetRootSS(s) This is typically not used in S-functions. It returns the root SimStruct of the tree of SimStruct’s. ssSetPlacementGroup (S,groupName) This is an advanced feature typically used for Real-Time Workshop device driver blocks.
The C MEX S-Function SimStruct Table 3-5: General SimStruct Macros (Continued) Macro Description ssSetOptions (S,options) Used in mdlInitializeSizes to set any of the following options. These options must be joined using the OR operator.
3 Writing S-Functions As C-MEX files Table 3-5: General SimStruct Macros (Continued) Macro Description ssSetOptions (S,options) SS_OPTION_ASYNCHRONOUS — This option applies only to S-functions that have 0 or 1 input ports and 1 output port. The output port must be configured to perform function calls on every element. If any of these requirements are not met, the SS_OPTION_ASYNCHRONOUS is ignored. Use this option when driving function-call subsystems that will be attached to interrupt service routines.
The C MEX S-Function SimStruct Table 3-6: Error Handling and Status SimStruct Macros Macros Description ssSetErrorStatus (S,"string") For improved performance and error handling, your S-function should report errors using: ssSetErrorStatus(S, "error message"); return; Be careful when using ssSetErrorStatus in your S-function. Error string must be persistent memory; it cannot be a local variable. ssGetSimMode(S) This macro can be used to determine the context in which your S-function is executing.
3 Writing S-Functions As C-MEX files Table 3-7: Input and Output Port Signal SimStruct Macros Macro Description ssSetNumInputPorts (S,nInputPorts) Used in mdlInitializeSizes to set to the number of input ports to a nonnegative integer. It should be invoked using: if (!ssSetNumInputPorts(S,nInputPorts)) return; where ssSetNumInputPorts returns a 0 if nInputPorts is negative or an error occurred while creating the ports.
The C MEX S-Function SimStruct Table 3-7: Input and Output Port Signal SimStruct Macros (Continued) Macro Description ssSetInputPortOffsetTime (S,inputPortIdx,offset) Used in mdlInitializeSizes (after ssSetNumInputPorts) to specify the sample time offset for each input port index. You can use this macro in conjunction with ssSetInputPortSampleTime if you have specified port-based sample times for your S-function.
3 Writing S-Functions As C-MEX files Table 3-7: Input and Output Port Signal SimStruct Macros (Continued) Macro Description ssSetInputPortReusable (S,inputPortIdx,value) Used in mdlInitializeSizes (after ssSetNumInputPorts) to specify whether the input port memory buffer can be reused by other signals in the model. This macro can take on two values: • Off (value=0) — specifies that the input port is not reusable. This is the default. • On (value=1) — specifies that the input port is reusable.
The C MEX S-Function SimStruct Table 3-7: Input and Output Port Signal SimStruct Macros (Continued) Macro Description ssSetInputPortReusable (S,inputPortIdx,value) Note that this is a suggestion and not a requirement for the Simulink engine. If Simulink cannot resolve buffer reuse in local memory, it resets value=0 and places the input port signals into global memory.
3 Writing S-Functions As C-MEX files Table 3-7: Input and Output Port Signal SimStruct Macros (Continued) Macro Description ssSetOutputPortReusable (S,outputPortIdx,value) Used in mdlInitializeSizes (after ssSetNumOutputPorts) to specify whether output ports have a test point. This macro can take on two values: • Off (value=0) — specifies that the output port is not reusable. This is the default. • On (value=1) — specifies that the output port is reusable.
The C MEX S-Function SimStruct Table 3-7: Input and Output Port Signal SimStruct Macros (Continued) Macro Description ssGetInputPortRealSignalPtrs (S,inputPortIdx) Can be used in any simulation loop (see p. 3-16) S-function routine to access an input port signal. The input port index starts at 0 and ends at the number of input ports minus 1. This macro returns a pointer to an array of pointers to the real_T input signal elements.
3 Writing S-Functions As C-MEX files Table 3-7: Input and Output Port Signal SimStruct Macros (Continued) Macro Description ssGetInputPortBufferDstPort (S,inputPortIdx) Can be used in any run-time (see p. 3-14) S-function routine to determine the index number of an output port when the specified input port has been overwritten by the output port.
The C MEX S-Function SimStruct Table 3-7: Input and Output Port Signal SimStruct Macros (Continued) Macro Description ssGetOutputPortOffsetTime (S,outputPortIdx) Can be used in any routine (except mdlInitializeSizes) to determine the offset time of an output port. This should only be used if you have specified port-based sample times.
3 Writing S-Functions As C-MEX files Table 3-8: Parameter SimStruct Macros (Continued) Macros Description ssGetSFcnParam(S,index) Used in any routine to access a parameter entered by in the S-function block dialog box where index starts at 0 and is less than ssGetSFcnParamsCount(S). ssSetSFcnParamNotTunable (S,index) Used in mdlInitializeSizes to specify that a parameter doesn’t change during the simulation, where index starts at 0 and is less than ssGetSFcnParamsCount(S).
The C MEX S-Function SimStruct Table 3-9: Sample Time SimStruct Macros (Continued) Macro Description ssIsSampleHit(S,st_index, tid) Used in mdlOutputs or mdlUpdate when your S-function has multiple sample times to determine what task your S-function is executing in. This should not be used in single rate S-functions or for the st_index corresponding to a continuous task.
3 Writing S-Functions As C-MEX files Table 3-10: State and Work Vector SimStruct Macros 3-112 Macro Description ssSetNumContStates (S,nContStates) Used in mdlInitializeSizes to specify the number of continuous states as 0, a positive integer, or DYNAMICALLY_SIZED. If you specify DYNAMICALLY_SIZED, then you can optionally specify the true (positive integer) width in mdlSetWorkWidths, otherwise the width to be used will be the width of the signal passing through the block.
The C MEX S-Function SimStruct Table 3-10: State and Work Vector SimStruct Macros (Continued) Macro Description ssSetNumPWork(S,nPWork) Used in mdlInitializeSizes to specify the number of pointer (void *) work vector elements as 0, a positive integer, or DYNAMICALLY_SIZED. If you specify DYNAMICALLY_SIZED, then you can optionally specify the true (positive integer) width in mdlSetWorkWidths, otherwise the width to be used will be the width of the signal passing through the block.
3 Writing S-Functions As C-MEX files Table 3-10: State and Work Vector SimStruct Macros (Continued) 3-114 Macro Description ssGetNumDiscStates(S) Can be used in any routine (except mdlInitializeSizes)to determine the number of discrete states your S-function is using. ssGetRealDiscStates(S) Can be used in the simulation loop, mdlInitializeConditions, or mdlStart routines to get the real_T discrete state vector. This vector has length ssGetNumDiscStates(S).
The C MEX S-Function SimStruct Table 3-10: State and Work Vector SimStruct Macros (Continued) Macro Description ssGetPWork(S) Can be used in the simulation loop, mdlInitializeConditions, or mdlStart routines to get the pointer (void *) work vector. This vector has length ssGetNumPWork(S). Typically, this vector and its pointer contents are initialized in mdlStart or mdlInitializeConditions. Its contents are updated in mdlUpdate, and used in mdlOutputs.
3 Writing S-Functions As C-MEX files Table 3-11: Simulation Information SimStruct Macros 3-116 Macro Description ssGetT(S) Used in mdlOutputs and mdlUpdate to get the “base” simulation time. If your S-function doesn’t have a single rate continuous sample time, then this time may not be the “correct task time” and your S-function will run deterministically in a multitasking environment.
The C MEX S-Function SimStruct Table 3-12: Function-Call SimStruct Macros Macro Description ssSetCallSystemOutput (S,index) Used in mdlInitializeSampleTimes to specify that the a the specified output port element index is issuing a function call by using ssCallSystemWithTid(S,index,tid). The index specified starts at 0 and must be less than ssGetOutputPortWidth(S,0). ssCallSystemWithTid (S,index,tid) Used in mdlOutputs to execute a function-call subsystem connected to the S-function.
3 Writing S-Functions As C-MEX files Converting Level 1 C MEX S-Functions to Level 2 Level 2 S-functions were introduced with Simulink 2.2. Level 1 S-functions refer to S-functions that were written to work with Simulink 2.1 and previous releases. Level 1 S-functions are compatible with Simulink 2.2; you can use them in new models without making any code changes. However, to take advantage of new features in S-functions, level 1 S-functions must be updated to level 2 S-functions.
Converting Level 1 C MEX S-Functions to Level 2 • If your S-function has a nonempty mdlInitializeConditions, then update it to the following form #define MDL_INITIALIZE_CONDITIONS static void mdlInitializeConditions(SimStruct *S) { } otherwise, delete the function. - The continuous states are accessed using ssGetContStates. The ssGetX macro has been removed. - The discrete states are accessed using ssGetRealDiscStates(S). The ssGetX macro has been removed.
3 Writing S-Functions As C-MEX files • If your S-function has a nonempty mdlUpdate, then update it to this form: #define MDL_UPDATE static void mdlUpdate(SimStruct *S, int_T tid) { } otherwise, delete the function. • If your S-function has a nonempty mdlDerivatives, then update it to this form: #define MDL_DERIVATIVES static void mdlDerivatives(SimStruct *S, int_T tid) { } otherwise, delete the function. • Replace all obsolete SimStruct macros. See Table 3-13 for a complete list of obsolete macros.
Converting Level 1 C MEX S-Functions to Level 2 Table 3-13: Obsolete SimStruct Macros Obsolete Macro Replace With ssGetU(S), ssGetUPtrs(S) ssGetInputPortSignalPtrs(S,port) ssGetY(S) ssGetOutputPortRealSignal(S,port) ssGetX(S) ssGetContStates(S), ssGetRealDiscStates(S) ssGetStatus(S) Normally not used, but ssGetErrorStatus(S) is available. ssSetStatus(S,msg) ssSetErrorStatus(S,msg) ssGetSizes(S) Specific call the desired item (i.e., ssGetNumContStates(S)).
3 Writing S-Functions As C-MEX files Table 3-13: Obsolete SimStruct Macros (Continued) 3-122 Obsolete Macro Replace With ssGetNumOutputs ssGetNumOutputPorts(S) and ssGetOutputPortWidth(S,port) ssSetNumOutputs ssSetNumOutputPorts(S,nOutputPorts) and ssSetOutputPortWidth(S,port,val)
4 Guidelines for Writing C MEX S-Functions Introduction . . . . . . . . . . . . Classes of Problems Solved by S-Functions Types of S-Functions . . . . . . . . . Basic Files Required for Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-2 4-2 4-3 4-5 Noninlined S-Functions . . . . . . . . . . . . . . . 4-7 Writing Wrapper S-Functions The MEX S-Function Wrapper . The TLC S-Function Wrapper . The Inlined Code . . . . . . . . . . . . . . . . . . . . . . . . . . .
4 Guidelines for Writing C MEX S-Functions Introduction This chapter describes how to create S-functions that work seamlessly with both Simulink and the Real-Time Workshop. It begins with basic concepts and concludes with an example of how to create a highly optimized direct-index lookup table S-function block.
Introduction environment with a great deal of flexibility. This flexibility cannot always be maintained when you use S-functions with the Real-Time Workshop. For example, it is not possible to access the MATLAB workspace from an S-function that is used with the Real-Time Workshop. However, using the techniques presented in this chapter, you can create S-functions for most applications that work with the generated code from the Real-Time Workshop.
4 Guidelines for Writing C MEX S-Functions The MathWorks has adopted terminology for these different requirements. Respectively, the situations described above map to this terminology: 1 Noninlined S-function 2 Wrapper S-function 3 Fully inlined S-function Noninlined S-Functions A noninlined S-function is a C-MEX S-function that is treated identically by Simulink and the Real-Time Workshop. In general, you implement your algorithm once according to the S-function API.
Introduction Fully Inlined S-Functions A fully inlined S-function builds your algorithm (block) into Simulink and the Real-Time Workshop in a manner that is indistinguishable from a built-in block. Typically, a fully inlined S-function requires you to implement your algorithm twice: once for Simulink (C-MEX S-function) and once for the Real-Time Workshop (TLC file).
4 Guidelines for Writing C MEX S-Functions files), it embeds some of this overhead code in the generated C code. If you want to optimize your real-time code and eliminate some of the overhead code, you must inline (or embed) your S-functions. This involves writing a TLC (sfunction.tlc) file that directs the Real-Time Workshop to eliminate all overhead code from the generated code. The Target Language Compiler, which is part of the Real-Time Workshop, processes sfunction.
Noninlined S-Functions Noninlined S-Functions Noninlined S-functions are identified by the absence of an sfunction.tlc file for your S-function (sfunction.mex). When placing a noninlined S-function in a model that is to be used with the Real-Time Workshop, the following MATLAB API functions are supported: • mxGetEps • mxGetInf • mxGetM • mxGetN • mxGetNaN • mxGetPr — Note: using mxGetPr on an empty matrix does not return NULL; rather, it returns a random value.
4 Guidelines for Writing C MEX S-Functions Writing Wrapper S-Functions This section describes how to create S-functions that work seamlessly with Simulink and the Real-time Workshop using the wrapper concept. This section begins by describing how to interface your algorithms in Simulink by writing MEX S-function wrappers (sfunction.mex). It finishes with a description of how to direct the Real-Time Workshop to insert your algorithm into the generated code by creating a TLC S-function wrapper (sfunction.
Writing Wrapper S-Functions Wrapper S-functions are useful when creating new algorithms that are procedural in nature or when integrating legacy code into Simulink. However, if you want to create code that is • interpretive in nature in Simulink (i.e., highly-parameterized by operating modes) • heavily optimized in the Real-Time Workshop (i.e., no extra tests to decide what mode the code is operating in) then you must create a fully inlined TLC file for your S-function.
4 Guidelines for Writing C MEX S-Functions This figure illustrates the wrapper S-function concept: Simulink Place the name of your S-function in the S-function block’s dialog box. Real-Time Workshop wrapper.c, the generated code, calls MdlOutputs, which then calls my_alg. wrapper.mdl wrapsfcn *see note below S-function In Simulink, the S-function calls mdlOutputs, which in turn calls my_alg. wrapsfcn.c ... mdlOutputs(...) { ... my_alg(); } mdlOutputs in wrapsfcn.mex calls external function my_alg.
Writing Wrapper S-Functions Using an S-function wrapper to import algorithms in your Simulink model means that the S-function serves as an interface that calls your C code algorithms from mdlOutputs. S-function wrappers have the advantage that you can quickly integrate large stand-alone C code into your model without having to make changes to the code. This is an example of a model that includes an S-function wrapper.
4 Guidelines for Writing C MEX S-Functions /* * mdlInitializeSampleTimes - indicate that this S-function runs *at the rate of the source (driving block) */ static void mdlInitializeSampleTimes(SimStruct *S) { ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME); ssSetOffsetTime(S, 0, 0.0); } Place the call to my_alg in mdlOutputs. /* * mdlOutputs - compute the outputs by calling my_alg, which *resides in another module, my_alg.
Writing Wrapper S-Functions The TLC S-Function Wrapper This section describes how to inline the call to my_alg in the MdlOutputs section of the generated code. In the above example, the call to my_alg is embedded in the mdlOutputs section as: *y = my_alg(*uPtrs[0]); When creating a TLC S-function wrapper, the goal is to have the Real-Time Workshop embed the same type of call in the generated code. It is instructive to look at how the Real-Time Workshop executes S-functions that are not inlined.
4 Guidelines for Writing C MEX S-Functions /* Level2 S-Function Block: /S-Function (wrapsfcn) */ { SimStruct *rts = ssGetSFunction(rtS, 0); sfcnOutputs(rts, tid); } Noninlined S-functions create a SimStruct object and generate a call to the S-function routine mdlOutputs. /* Outport Block: /Out */ rtY.Out = rtB.
Writing Wrapper S-Functions to your C algorithm (my_alg), you can eliminate both the SimStruct and the extra function call, thereby improving the efficiency and reducing the size of the generated code. Inlining a wrapper S-function requires an sfunction.tlc file for the S-function; this file must contain the function call to my_alg. This picture shows the relationships between the algorithm, the wrapper S-function, and the sfunction.tlc file: wrapper.c my_alg.c ... MdlOutputs { ... y = my_alg(); ... } ...
4 Guidelines for Writing C MEX S-Functions placing calls to your S-function in the generated code. This is the wrapsfcn.tlc file that inlines wrapsfcn.c: %% File : wrapsfcn.tlc %% Abstract: %% Example inlined tlc file for S-function wrapsfcn.c %% %implements “wrapsfcn” “C” This line is placed in wrapper.h. This line is expanded and placed in MdlOutputs within wrapper.c. %% Function: BlockTypeSetup ==================================================== %% Abstract: %% Create function prototype in model.
Writing Wrapper S-Functions The final step is the actual inlining of the call to the function my_alg. This is done by the Outputs function. In this function, you load the input and output and call place a direct call to my_alg. The call is embedded in wrapper.c. The Inlined Code The code generated when you inline your wrapper S-function is similar to the default generated code.
4 Guidelines for Writing C MEX S-Functions Fully Inlined S-Functions Continuing the example of the previous section, you could eliminate the call to my_alg entirely by specifying the explicit code (i.e., 2.0*u) in wrapsfcn.tlc. This is referred to as a fully inlined S-function. While this can improve performance, if your C code is large this may be a lengthy task. In addition, you now have to maintain your algorithm in two places, the C S-function itself and the corresponding TLC file.
Fully Inlined S-Functions that contains multiple ports. You may find that looking at this example will aid in the understanding of fully inlined TLC files.
4 Guidelines for Writing C MEX S-Functions Fully Inlined S-Function with the mdlRTW Routine You can make a more fully inlined S-function that uses the S-function mdlRTW routine. The purpose of the mdlRTW routine is to provide the code generation process with more information about how the S-function is to be inlined, including: • Renaming of tunable parameters in the generated code. This improves readability of the code by replacing p1, p2, etc., by names of your choice.
Fully Inlined S-Function with the mdlRTW Routine • How to use the mdlRTW routine to customize the Real-Time Workshop generated code to produce the optimal code for a given set of block parameters • How to generate an inlined TLC file for an S-function in a combination of the fully-inlined form and/or the wrapper form The Direct-Index Lookup Table Algorithm The 1-D lookup table block provided in the Simulink library uses interpolation or extrapolation when computing outputs.
4 Guidelines for Writing C MEX S-Functions The following graph illustrates how the parameters XData=[1:6], YData=[1,2,7,4,5,9] are handled. For example, if the input (x-value) to the S-function block is 3, then the output (y-value) is 7. 9 8 7 6 5 4 3 2 1 1 1.5 2 2.5 3 3.5 4 4.5 5 5.5 6 Figure 4-3: Typical Output from a Lookup Table Example The Direct-Index Lookup Table Example This section shows how to improve the lookup table by inlining a direct-index S-function with a TLC file.
Fully Inlined S-Function with the mdlRTW Routine index in the XData for the current x input value when the XData is unevenly spaced. The GetDirectLookupIndex routine is called from both the S-function and the generated code. Here the example uses the wrapper concept for sharing C code between Simulink MEX-files and the generated code.
4 Guidelines for Writing C MEX S-Functions mxGetPr MATLAB API function. This results in a slight increase in performance. mdlRTW Usage The Real-Time Workshop calls the mdlRTW routine while it (the Real-Time Workshop) generates the model.rtw file. You can add information to the model.rtw file about the mode in which your S-function block is operating to produce optimal code for your Simulink model. This example adds the following information to the model.
Fully Inlined S-Function with the mdlRTW Routine When creating this model, you need to specify the following for each S-function block: set_param(‘sfun_directlook_ex/S-Function’,’SFunctionModules’,’lookup_index’) set_param(‘sfun_directlook_ex/S-Function1’,’SFunctionModules’,’lookup_index’) This informs the Real-Time Workshop build process that the module lookup_index.c is needed when creating the executable.
4 Guidelines for Writing C MEX S-Functions rtY.Out1 = rtb_buffer2; /* S-Function Block: /S-Function1 */ { real_T *xData = &rtP.S_Function1.XData[0]; real_T *yData = &rtP.S_Function1.YData[0]; int_T idx; idx = GetDirectLookupIndex(xData, 5, rtb_Sine_Wave); rtb_buffer2 = yData[idx]; } /* Outport Block: /Out2 */ rtY.Out2 = rtb_buffer2; This is the code that is inlined for the bottom S-function block in the sfun_directlook_ex model.
Fully Inlined S-Function with the mdlRTW Routine matlabroot/simulink/src/sfun_directlook.c /* * File : sfun_directlook.c * Abstract: * * Direct 1-D lookup. Here we are trying to compute an approximate * solution, p(x) to an unknown function f(x) at x=x0, given data point * pairs (x,y) in the form of a x data vector and a y data vector. For a * given data pair (say the i’th pair), we have y_i = f(x_i). It is * assumed that the x data values are monotonically increasing.
4 Guidelines for Writing C MEX S-Functions /*==============* * misc defines * *==============*/ #if !defined(TRUE) #define TRUE 1 #endif #if !defined(FALSE) #define FALSE 0 #endif /*===========* * typedef’s * *===========*/ typedef struct SFcnCache_tag { boolean_T evenlySpaced; } SFcnCache; /*===================================================================* * Prototype define for the function in separate file lookup_index.
Fully Inlined S-Function with the mdlRTW Routine } return(TRUE); } else { return(FALSE); } } /* end IsRealVect */ /*====================* * S-function routines * *====================*/ #define MDL_CHECK_PARAMETERS /* Change to #undef to remove function */ #if defined(MDL_CHECK_PARAMETERS) && defined(MATLAB_MEX_FILE) /* Function: mdlCheckParameters ================================================ * Abstract: * This routine will be called after mdlInitializeSizes, whenever * parameters change or get re-ev
4 Guidelines for Writing C MEX S-Functions /* * Verify we have a valid XDataEvenlySpaced parameter. */ if (!mxIsNumeric(XDATAEVENLYSPACED(S)) || !(mxIsDouble(XDATAEVENLYSPACED(S)) || mxIsLogical(XDATAEVENLYSPACED(S))) || mxIsComplex(XDATAEVENLYSPACED(S)) || mxGetNumberOfElements(XDATAEVENLYSPACED(S)) != 1) { ssSetErrorStatus(S,”3rd, X-evenly-spaced parameter must be scalar “ “(0.0=false, 1.0=true)”); return; } /* * Verify x-data is correctly spaced.
Fully Inlined S-Function with the mdlRTW Routine } else { /* XData is ‘unevenly-spaced’ */ for (i = 1; i < numEl; i++) { if (xData[i] <= xData[i-1]) { ssSetErrorStatus(S,”X-vector must be a strictly “ “monotonically increasing vector”); return; } } } } } #endif /* MDL_CHECK_PARAMETERS */ /* Function: mdlInitializeSizes ================================================ * Abstract: * The sizes information is used by Simulink to determine the S-function * block’s characteristics (number of inputs, outputs, st
4 Guidelines for Writing C MEX S-Functions ssSetInputPortOverWritable(S, 0, TRUE); if (!ssSetNumOutputPorts(S, 1)) return; ssSetOutputPortWidth(S, 0, DYNAMICALLY_SIZED); ssSetOutputPortTestPoint(S, 0, FALSE); ssSetNumSampleTimes(S, 1); ssSetSFcnParamNotTunable(S, XDATAEVENLYSPACED_PIDX); ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE); } /* mdlInitializeSizes */ /* Function: mdlInitializeSampleTimes ========================================== * Abstract: * The lookup inherits its sample time from the drivi
Fully Inlined S-Function with the mdlRTW Routine cache->evenlySpaced = FALSE; } } #endif /* MDL_START */ /* Function: mdlOutputs ======================================================== * Abstract: * In this function, we compute the outputs of our S-function * block. Generally outputs are placed in the output vector, ssGetY(S).
4 Guidelines for Writing C MEX S-Functions } /* end mdlOutputs */ /* Function: mdlTerminate ====================================================== * Abstract: * Free the cache that was allocated in mdlStart.
Fully Inlined S-Function with the mdlRTW Routine boolean_T even = (mxGetScalar(XDATAEVENLYSPACED(S)) != 0.0); if (!ssWriteRTWParamSettings(S, 1, SSWRITE_VALUE_QSTR, “XSpacing”, even ? “EvenlySpaced” : “UnEvenlySpaced”)){ return;/* An error occurred which will be reported by Simulink */ } } } #endif /* MDL_RTW */ /*=============================* * Required S-function trailer * *=============================*/ #ifdef MATLAB_MEX_FILE #include “simulink.c” #else #include “cg_sfun.
4 Guidelines for Writing C MEX S-Functions matlabroot/simulink/src/lookup_index.c /* File : lookup_index.c * Abstract: * * Contains a routine used by the S-function sfun_directlookup.c to * compute the index in a vector for a given data value. * * Copyright (c) 1990-1998 by The MathWorks, Inc. All Rights Reserved. * $Revision: 1.3 $ */ #include “tmwtypes.
Fully Inlined S-Function with the mdlRTW Routine */ for (;;) { idx = (bottom + top)/2; if (u < x[idx]) { top = idx; } else if (u > x[idx+1]) { bottom = idx + 1; } else { /* * We have: x[idx] <= u <= x[idx+1], only need * to do two more checks and we have the answer. */ if (u < 0) { /* * We want right continuity, i.e., * if u == x[idx+1] * then x[idx+1] <= u < x[idx+2] * else x[idx ] <= u < x[idx+1] */ return( (u == x[idx+1]) ? (idx+1) : idx); } else { /* * We want left continuity, i.e.
4 Guidelines for Writing C MEX S-Functions matlabroot/toolbox/simulink/blocks/sfun_directlook.tlc %% %% %% %% %% %% %% File : sfun_directlook.tlc Abstract: Level-2 S-function sfun_directlook block target file. It is using direct lookup algorithm without interpolation. Copyright (c) 1994-1998 by The MathWorks, Inc. All Rights Reserved. $Revision: 1.
Fully Inlined S-Function with the mdlRTW Routine %function Outputs(block, system) Output /* % Block: % */ { %assign rollVars = [“U”, “Y”] %% %% Load XData and YData as local variables %% real_T *xData = %; real_T *yData = %; %assign xDataLen = SIZE(XData.Value, 1) %% %% When the XData is evenly spaced, we use the direct lookup algorithm %% to locate the lookup index. %% %if SFcnParamSettings.
4 Guidelines for Writing C MEX S-Functions %endif %endroll %endif } %endfunction %% EOF: sfun_directlook.
Index A additional parameters for S-functions 2-20 block width 3-33 block-based sample times 3-36 pointer work vector 3-46 sample time for continuous block 3-42 sample time for hybrid block 3-43 variable step S-function (C MEX) 3-68 variable step S-function (M-file) 2-17 exception free code 3-13 C F B C MEX S-function routines 3-3 C MEX S-functions 1-2, 3-1, 3-4 configuring port widths 3-32 continuous block, setting sample time 3-42 continuous state S-function example (C MEX) 3-56 continuous state S-f
Index mdlSetOutputPortSampleTime 3-34, 3-41 mdlSetOutputPortWidth function 3-35 mdlSetWorkWidths 3-46 mdlStart 3-48 mdlUpdate 3-42, 3-51 memory and work vectors 3-43 mex utility 1-2 mex.h 3-11 M-file S-function routines 2-2 mixedm.
Index error handling and status 3-101 function call 3-117 general 3-97 input and output port signal 3-102 parameter 3-109 sample time 3-110 simulation information 3-116 state and work vector 3-112 simulation loop 1-5 simulation stages 1-5 simulink.
Index ssSetNumSampleTimes 3-110 ssSetNumSFcnParams 3-109 ssSetOffsetTime 3-110 ssSetOptions 3-99 ssSetOutputPortOffsetTime 3-105 ssSetOutputPortReusable 3-106 ssSetOutputPortSampleTime 3-105 ssSetOutputPortWidth 3-105 ssSetPlacementGroup 3-98 ssSetSampleTime 3-110 ssSetSFcnParamNotTunable 3-110 ssSetSolverNeedsReset 3-116 ssSetStopRequested 3-116 T tmwtypes.