Writing S-Functions | ![]() ![]() |
Example of a 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.
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 the next hit, that is, the time when vsfunc
is next called. In mdlGetTimeOfNextVarHit
, the macro ssGetU
is used to get a pointer to the input u
. Then this call is made.
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 the 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. */ #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 of a Hybrid System S-Function | Example of a Zero Crossing S-Function | ![]() |