Writing S-Functions | ![]() ![]() |
Example of a Hybrid System S-Function
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 mdlDerivatives
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.
In Simulink block diagram form, the S-function mixedm.c
looks like
which implements a continuous integrator followed by a discrete unit delay.
Because there are no tasks to complete at termination, mdlTerminate
is an empty function. mdlDerivatives
calculates the derivatives of the continuous states of the state vector, x
, and mdlUpdate
contains the equations used to update the discrete state vector, x
.
matlabroot/simulink/src/mixedm.c
/* File : mixedm.c * Abstract: * * An example S-function illustrating multiple sample times by implementing * integrator -> ZOH(Ts=1second) -> UnitDelay(Ts=1second) * with an initial condition of 1. * (e.g. an integrator followed by unit delay operation). * * For more details about S-functions, see simulink/src/sfuntmpl_doc.c * * Copyright 1990-2000 The MathWorks, Inc. */ #define S_FUNCTION_NAME mixedm #define S_FUNCTION_LEVEL 2 #include "simstruc.h" #define U(element) (*uPtrs[element]) /* Pointer to Input Port0 */ /*====================* * S-function methods * *====================*/ /* 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, 1); ssSetNumDiscStates(S, 1); ssSetNumRWork(S, 1); /* for zoh output feeding the delay operator */ if (!ssSetNumInputPorts(S, 1)) return; ssSetInputPortWidth(S, 0, 1); ssSetInputPortDirectFeedThrough(S, 0, 1); ssSetInputPortSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME); ssSetInputPortOffsetTime(S, 0, 0.0); if (!ssSetNumOutputPorts(S, 1)) return; ssSetOutputPortWidth(S, 0, 1); ssSetOutputPortSampleTime(S, 0, 1.0); ssSetOutputPortOffsetTime(S, 0, 0.0); ssSetNumSampleTimes(S, 2); /* Take care when specifying exception free code - see sfuntmpl_doc.c. */ ssSetOptions(S, (SS_OPTION_EXCEPTION_FREE_CODE | SS_OPTION_PORT_SAMPLE_TIMES_ASSIGNED)); } /* end mdlInitializeSizes */ /* 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); ssSetOffsetTime(S, 0, 0.0); ssSetSampleTime(S, 1, 1.0); ssSetOffsetTime(S, 1, 0.0); } /* end mdlInitializeSampleTimes */ #define MDL_INITIALIZE_CONDITIONS /* Function: mdlInitializeConditions ========================================== * Abstract: * Initialize both continuous states to one. */ static void mdlInitializeConditions(SimStruct *S) { real_T *xC0 = ssGetContStates(S); real_T *xD0 = ssGetRealDiscStates(S); xC0[0] = 1.0; xD0[0] = 1.0; } /* end mdlInitializeConditions */ /* Function: mdlOutputs ======================================================= * Abstract: * y = xD, and update the zoh internal output. */ static void mdlOutputs(SimStruct *S, int_T tid) { /* update the internal "zoh" output */ if (ssIsContinuousTask(S, tid)) { if (ssIsSpecialSampleHit(S, 1, 0, tid)) { real_T *zoh = ssGetRWork(S); real_T *xC = ssGetContStates(S); *zoh = *xC; } } /* y=xD */ if (ssIsSampleHit(S, 1, tid)) { real_T *y = ssGetOutputPortRealSignal(S,0); real_T *xD = ssGetRealDiscStates(S); y[0]=xD[0]; } } /* end mdlOutputs */ #define MDL_UPDATE /* Function: mdlUpdate ====================================================== * Abstract: * xD = xC */ static void mdlUpdate(SimStruct *S, int_T tid) { UNUSED_ARG(tid); /* not used in single tasking mode */ /* xD=xC */ if (ssIsSampleHit(S, 1, tid)) { real_T *xD = ssGetRealDiscStates(S); real_T *zoh = ssGetRWork(S); xD[0]=*zoh; } } /* end mdlUpdate */ #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); } /* end mdlDerivatives */ /* Function: mdlTerminate ===================================================== * Abstract: * No termination needed, but we are required to have this routine. */ static void mdlTerminate(SimStruct *S) { UNUSED_ARG(S); /* unused input argument */ } #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 Discrete State S-Function | Example of a Variable-Step S-Function | ![]() |