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,參數裏面填入要設定的參數,然後仿真即可。