1. S-Function簡(jiǎn)介S-Function是system-function的縮寫。說(shuō)得簡(jiǎn)單,S-Function就是用MATLAB所提供的模型不能完全滿足用戶,而提供給用戶自己編寫程序來(lái)滿足自己要求模型的接口。
2. MEX函數(shù)與M文件的區(qū)別第一, MEX 函數(shù)能實(shí)現(xiàn)的回調(diào)函數(shù)比M-文件能實(shí)現(xiàn)的回調(diào)函數(shù)要多得多; 第二, MEX 函數(shù)直接訪問(wèn)內(nèi)部數(shù)據(jù)結(jié)構(gòu)SimStruct,SimStruct 是Simulink 用來(lái)保存關(guān)于S-function 信息的一個(gè)數(shù)據(jù)結(jié)構(gòu); 第三, MEX 函數(shù)也可使用MATLAB MEX 文件API 直接來(lái)訪問(wèn)MATLAB 的工作空間。 如果一個(gè)C MEX文件與一個(gè)M文件具有相同的名字,則C MEX文件被優(yōu)先使用,即在S-Function塊中使用的是C MEX文件。
3. 基礎(chǔ)知識(shí)3.1 直接饋通(direct feedthrough)直接饋通表示系統(tǒng)的輸出或可變采樣時(shí)間是否受到輸入的控制。 a. 輸出函數(shù)(mdlOutputs或flag==3)是輸入u的函數(shù)。即,如果輸入u在mdlOutputs中被訪問(wèn),則存在直接饋通。 b. 對(duì)于一個(gè)變步長(zhǎng)S-Function的“下一個(gè)采樣時(shí)間”函數(shù)(mdlGetTimeOfNextVarHit或flag==4)中可以訪問(wèn)輸入u。 例如,一個(gè)需要其輸入的系統(tǒng)(也就是具有直接饋通)是運(yùn)算y=kXu,其中,u是輸入,k是增益,y是輸出。 又如,一個(gè)不需要其輸入的系統(tǒng)(也就是沒(méi)有直饋通)是一種簡(jiǎn)單的積分運(yùn)算: 輸出:y=x; 導(dǎo)數(shù):dx/dt=u 其中,x是狀態(tài),dx/dt是狀態(tài)對(duì)時(shí)間的導(dǎo)數(shù),u是輸入,y是輸出。 正確設(shè)置直接饋通標(biāo)志是十分重要的,因?yàn)樗绊懩P椭袎K的執(zhí)行順序,并可用檢測(cè)代數(shù)環(huán)。 3.2 dynamically sized inputs主要是給出:輸入連續(xù)狀態(tài)數(shù)目(size.NumContStates),離散狀態(tài)數(shù)目(size.NumDiscStates) ,輸出數(shù)目(size.NumOutputs),輸入數(shù)目(size.NumInputs),Direct Feedthrough(size.Dir Feedthrough)。 3.3 setting sample times and offsetssetting smaple times and offsets主要設(shè)置采樣時(shí)間. 3.4 Level-1 和Level-2Level 1 提供一個(gè)簡(jiǎn)單的接口,可與少部分的S函數(shù)API交互。Matlab對(duì)于這種方式的支持更多的是為了保持與以前版本的兼容,現(xiàn)在推薦采用的是Level 2 S函數(shù)。
4. S-Function實(shí)例S-Function的仿真流程 例如要?jiǎng)?chuàng)建一個(gè)有1輸入(2維),2輸出(1維),3個(gè)參數(shù),還有全局變量的S-Function。 過(guò)程如下: a. 新建sfunction的C語(yǔ)言文件打開(kāi)simulink,點(diǎn)擊User-Defined Functions里面的S-Function Examples。這個(gè)里面有多個(gè)語(yǔ)言版本的模板,有C,C++,Ada,F(xiàn)ortran和M語(yǔ)言的版本,其實(shí)都大同小異,只要了解幾個(gè)函數(shù)就很容易使用了。 選擇C語(yǔ)言的版本:從S-function模塊中選擇C-file S-functions里面的Basic C-MEX template。打開(kāi)后,另存為自己的模塊名字,如test.c 。下面我們來(lái)分析代碼: #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) { //這個(gè)函數(shù)用來(lái)設(shè)置輸入、輸出和參數(shù)的。 ssSetNumSFcnParams(S, 3); /*設(shè)置參數(shù)個(gè)數(shù),這里為3 */ if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) { return; } ssSetNumContStates(S, 0);//設(shè)置連續(xù)狀態(tài)的個(gè)數(shù),缺省為0; ssSetNumDiscStates(S, 0);//設(shè)置離散狀態(tài)的個(gè)數(shù),缺省為0; if (!ssSetNumInputPorts(S, 1)) return;//設(shè)置輸入變量的個(gè)數(shù),這里為1 ssSetInputPortWidth(S, 0, 2); //設(shè)置輸入變量0的維數(shù)為2 ssSetInputPortRequiredContiguous(S, 0, true); //設(shè)置input0的訪問(wèn)方式,true就是臨近訪問(wèn),這樣指針的增量后就可以直接訪問(wèn)下個(gè)input端口了。 ssSetInputPortDirectFeedThrough(S, 0, 1);// 設(shè)置輸入端口的信號(hào)是否mdlOutputs函數(shù)中使用,這兒設(shè)置為true。 if (!ssSetNumOutputPorts(S, 2)) return;//設(shè)置輸出變量的個(gè)數(shù) ssSetOutputPortWidth(S, 0, 1);//設(shè)置輸出變量0的維數(shù)為1維 ssSetOutputPortWidth(S, 1, 1);//設(shè)置輸出變量1的維數(shù)為1維 ssSetNumSampleTimes(S, 1); //設(shè)置采樣時(shí)間,此處為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)//暫時(shí)不管 { 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)//暫時(shí)不管 { } #endif /* MDL_INITIALIZE_CONDITIONS */ #define MDL_START /* Change to #undef to remove function */ #if defined(MDL_START) static void mdlStart(SimStruct *S)//暫時(shí)不管 { } #endif /* MDL_START */ static void mdlOutputs(SimStruct *S, int_T tid)//這里填入相關(guān)的運(yùn)算、算法等 { 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變量全部初始化,否則下次運(yùn)行程序時(shí),全局變量還是之前的值。 { } #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.調(diào)用sfunction在simulink空間里面拉入sfunction,在s-function name里面填入test,參數(shù)里面填入要設(shè)定的參數(shù),然后仿真即可。
|
|