1. S-Function簡介
S-Function是system-function的縮寫。說得簡單,S-Function就是用MATLAB所提供的模型不能完全滿足用戶,而提供給用戶自己編寫程序來滿足自己要求模型的接口。
2. MEX函數與M文件的區別
第一, MEX 函數能實現的回調函數比M-文件能實現的回調函數要多得多;
第二, MEX 函數直接訪問內部數據結構SimStruct,SimStruct 是Simulink 用來保存關於S-function 信息的一個數據結構;
第三, MEX 函數也可使用MATLAB MEX 文件API 直接來訪問MATLAB 的工作空間。
如果一個C MEX文件與一個M文件具有相同的名字,則C MEX文件被優先使用,即在S-Function塊中使用的是C MEX文件。
3. 基礎知識
3.1 直接饋通(direct feedthrough)
直接饋通表示系統的輸出或可變采樣時間是否受到輸入的控制。
a. 輸出函數(mdlOutputs或flag==3)是輸入u的函數。即,如果輸入u在mdlOutputs中被訪問,則存在直接饋通。
b. 對於一個變步長S-Function的“下一個采樣時間”函數(mdlGetTimeOfNextVarHit或flag==4)中可以訪問輸入u。
例如,一個需要其輸入的系統(也就是具有直接饋通)是運算y=kXu,其中,u是輸入,k是增益,y是輸出。
又如,一個不需要其輸入的系統(也就是沒有直饋通)是一種簡單的積分運算:
輸出:y=x;
導數:dx/dt=u
其中,x是狀態,dx/dt是狀態對時間的導數,u是輸入,y是輸出。
正確設置直接饋通標志是十分重要的,因為它影響模型中塊的執行順序,並可用檢測代數環。
3.2 dynamically sized inputs
主要是給出:輸入連續狀態數目(size.NumContStates),離散狀態數目(size.NumDiscStates) ,輸出數目(size.NumOutputs),輸入數目(size.NumInputs),Direct Feedthrough(size.Dir Feedthrough)。
3.3 setting sample times and offsets
setting smaple times and offsets主要設置采樣時間.
3.4 Level-1 和Level-2
Level 1 提供一個簡單的接口,可與少部分的S函數API交互。Matlab對於這種方式的支持更多的是為了保持與以前版本的兼容,現在推薦采用的是Level 2 S函數。
4. S-Function實例
S-Function的仿真流程
例如要創建一個有1輸入(2維),2輸出(1維),3個參數,還有全局變量的S-Function。 過程如下:
a. 新建sfunction的C語言文件
打開simulink,點擊User-Defined Functions里面的S-Function Examples。這個里面有多個語言版本的模板,有C,C++,Ada,Fortran和M語言的版本,其實都大同小異,只要了解幾個函數就很容易使用了。 選擇C語言的版本:從S-function模塊中選擇C-file S-functions里面的Basic C-MEX template。打開后,另存為自己的模塊名字,如test.c 。下面我們來分析代碼:
#define S_FUNCTION_NAME test//這里把文件名sfuntmpl_basic修改為test #define S_FUNCTION_LEVEL 2 #include "simstruc.h" //程序里面要用到的頭文件在這里引用,如“math.h”等。 float global_var; //定義全局變量 static void mdlInitializeSizes(SimStruct *S) { //這個函數用來設置輸入、輸出和參數的。 ssSetNumSFcnParams(S, 3); /*設置參數個數,這里為3 */ if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) { return; } ssSetNumContStates(S, 0);//設置連續狀態的個數,缺省為0; ssSetNumDiscStates(S, 0);//設置離散狀態的個數,缺省為0; if (!ssSetNumInputPorts(S, 1)) return;//設置輸入變量的個數,這里為1 ssSetInputPortWidth(S, 0, 2); //設置輸入變量0的維數為2 ssSetInputPortRequiredContiguous(S, 0, true); //設置input0的訪問方式,true就是臨近訪問,這樣指針的增量后就可以直接訪問下個input端口了。 ssSetInputPortDirectFeedThrough(S, 0, 1);// 設置輸入端口的信號是否mdlOutputs函數中使用,這兒設置為true。 if (!ssSetNumOutputPorts(S, 2)) return;//設置輸出變量的個數 ssSetOutputPortWidth(S, 0, 1);//設置輸出變量0的維數為1維 ssSetOutputPortWidth(S, 1, 1);//設置輸出變量1的維數為1維 ssSetNumSampleTimes(S, 1); //設置采樣時間,此處為1s。 ssSetNumRWork(S, 0);//不管 ssSetNumIWork(S, 0); ssSetNumPWork(S, 0); ssSetNumModes(S, 0); ssSetNumNonsampledZCs(S, 0); ssSetOptions(S, 0); //下面可以寫全局變量的初始化程序 global_var=1; } static void mdlInitializeSampleTimes(SimStruct *S)//暫時不管 { ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME); ssSetOffsetTime(S, 0, 0.0); } #define MDL_INITIALIZE_CONDITIONS /* Change to #undef to remove function */ #if defined(MDL_INITIALIZE_CONDITIONS) static void mdlInitializeConditions(SimStruct *S)//暫時不管 { } #endif /* MDL_INITIALIZE_CONDITIONS */ #define MDL_START /* Change to #undef to remove function */ #if defined(MDL_START) static void mdlStart(SimStruct *S)//暫時不管 { } #endif /* MDL_START */ static void mdlOutputs(SimStruct *S, int_T tid)//這里填入相關的運算、算法等 { real_T *para1 = mxGetPr(ssGetSFcnParam(S,0)); real_T *para2 = mxGetPr(ssGetSFcnParam(S,1)); real_T *para3 = mxGetPr(ssGetSFcnParam(S,2)); const real_T *u = (const real_T*) ssGetInputPortSignal(S,0); real_T *y1 = ssGetOutputPortSignal(S,0); real_T *y2 = ssGetOutputPortSignal(S,1); y1[0]=u[0]*para1[0]+u[1]*para2[0]; y2[0]=u[1]*para3[0]+u[0]*para1[0]; } #define MDL_UPDATE /* Change to #undef to remove function */ #if defined(MDL_UPDATE) static void mdlUpdate(SimStruct *S, int_T tid) { } #endif /* MDL_UPDATE */ #define MDL_DERIVATIVES /* Change to #undef to remove function */ #if defined(MDL_DERIVATIVES) static void mdlDerivatives(SimStruct *S) { } #endif /* MDL_DERIVATIVES */ static void mdlTerminate(SimStruct *S)//這里需要把global變量全部初始化,否則下次運行程序時,全局變量還是之前的值。 { } #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
b. 編譯
在matlab的command window 里面輸入“mex test.c”,即可將test.c編譯為mex文件。
c.調用sfunction
在simulink空間里面拉入sfunction,在s-function name里面填入test,參數里面填入要設定的參數,然后仿真即可。