Writing S-Functions | ![]() ![]() |
Example - Variable Step S-Function
The example S-function, vsfunc.c
uses a variable step sample time. Variable step-size functions require a call to mdlGetTimeOfNextVarHit
, which is an S-function routine that calculates the time of the next sample hit. S-functions that use the variable step sample time can only be used with variable step solvers. vsfunc
is a discrete S-function that delays its first input by an amount of time determined by the second input.
This example demonstrates how to correctly work with the fixed and variable step solvers when the equations (functions) that are being integrated change 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. This example calls mdlGetTimeOfNextVarHit
, an S-function routine that calculates and sets the "time of next hit," that is, the time when is vsfunc
is next called. In mdlGetTimeOfNextVarHit
the macro ssGetU
is used to get a pointer to the input u
. Then this call is made.
ssSetTNext(S, ssGetT(S)(*u[1]));
The macro ssGetT
gets the simulation time t
. The second input to the block, (*u[1])
, is added to t
, and the macro ssSetTNext
sets the time of next hit equal to t+(*u[1])
, delaying the output by the amount of time set in (*u[1])
.
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. This block implements a variable step delay * in which the first input is delayed by an amount of time determined * by the second input: * * dt = u(2) * y(t+dt) = u(t) * * For more details about S-functions, see simulink/src/sfuntmpl_doc.c. * * Copyright 1990-2000 The MathWorks, Inc. * $Revision: 1.1 $ */ #define S_FUNCTION_NAME vsfunc #define S_FUNCTION_LEVEL 2 #include "simstruc.h" #define U(element) (*uPtrs[element]) /* Pointer to Input Port0 */ /* Function: mdlInitializeSizes =============================================== * Abstract: * The sizes information is used by Simulink to determine the S-function * block's characteristics (number of inputs, outputs, states, etc.). */ static void mdlInitializeSizes(SimStruct *S) { ssSetNumSFcnParams(S, 0); /* Number of expected parameters */ if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) { return; /* Parameter mismatch will be reported by Simulink */ } ssSetNumContStates(S, 0); ssSetNumDiscStates(S, 1); if (!ssSetNumInputPorts(S, 1)) return; ssSetInputPortWidth(S, 0, 2); ssSetInputPortDirectFeedThrough(S, 0, 1); if (!ssSetNumOutputPorts(S, 1)) return; ssSetOutputPortWidth(S, 0, 1); ssSetNumSampleTimes(S, 1); ssSetNumRWork(S, 0); ssSetNumIWork(S, 0); ssSetNumPWork(S, 0); ssSetNumModes(S, 0); ssSetNumNonsampledZCs(S, 0); if (ssGetSimMode(S) == SS_SIMMODE_RTWGEN && !ssIsVariableStepSolver(S)) { ssSetErrorStatus(S, "S-function vsfunc.c cannot be used with RTW " "and Fixed-Step Solvers because it contains variable" " sample time"); } /* Take care when specifying exception free code - see sfuntmpl_doc.c */ ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE); } /* Function: mdlInitializeSampleTimes ========================================= * Abstract: * Variable-Step S-function */ static void mdlInitializeSampleTimes(SimStruct *S) { ssSetSampleTime(S, 0, VARIABLE_SAMPLE_TIME); ssSetOffsetTime(S, 0, 0.0); } #define MDL_INITIALIZE_CONDITIONS /* Function: mdlInitializeConditions ======================================== * Abstract: * Initialize discrete state to zero. */ static void mdlInitializeConditions(SimStruct *S) { real_T *x0 = ssGetRealDiscStates(S); x0[0] = 0.0; } #define MDL_GET_TIME_OF_NEXT_VAR_HIT static void mdlGetTimeOfNextVarHit(SimStruct *S) { InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0); /* Make sure input will increase time */ if (U(1) <= 0.0) { /* If not, abort simulation */ ssSetErrorStatus(S,"Variable step control input must be " "greater than zero"); return; } ssSetTNext(S, ssGetT(S)+U(1)); } /* 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. * Discrete states are typically updated here, but this function is useful * for performing any tasks that should only take place once per integration * step. */ static void mdlUpdate(SimStruct *S, int_T tid) { real_T *x = ssGetRealDiscStates(S); InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0); x[0]=U(0); } /* Function: mdlTerminate ===================================================== * Abstract: * No termination needed, but we are required to have this routine. */ 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
![]() | Example - Hybrid System S-Functions | Example - Zero Crossing S-Function | ![]() |