matlab 中的 S-Function的用法(C語言)

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章