matlab/simulink中帶參數的S-Function(S函數)的寫法

S函數的相關概念與寫法,直接在幫助文件中搜:【MATLAB S-Functions Create custom blocks defined】、【S-Function Concepts】等

 

S函數模塊可以從下圖中拖出來:

圖 1

其中S-Function是正宗的S函數模塊,旁邊還有一個S-Function builder是給新手用的,只要學會了S函數模塊,S builder模塊自然一看就懂。

使用S函數模塊的步驟:①寫S函數的.m文件, 並把m文件所在的文件夾加入搜索路徑,如下圖2所示。②在simulink中拖出S函數,並填上m文件的名字,如果有參數(下文會講到),也把參數名填上,如下圖3所示。然後就可以執行仿真了

圖2

圖3

 

下面是最關鍵的部分,如何寫S函數:

寫S函數的本質就是寫一堆回調函數,C/C++程序員對回調函數應該很熟悉了,既然是回調函數,那寫之前必須要知道形參和返回值的格式,這個格式從哪查?直接在matlab命令行執行: edit sfuntmpl,就直接打開了官方提供的模板,連格式都不用查了,直接仿照官方模板把函數體改改蓋就行了,方便。

(1)S函數的總函數

把官方模板的代碼拷到一個新文件裏,並命名爲自定義名稱,我取的名字是oneOrderModule.m,然後把函數名也改成和文件名相同,我的是這樣的:function [sys,x0,str,ts,simStateCompliance] = oneOrderModule(t,x,u,flag, T)

我與官方版不同的是,自己加了一個參數T,如果你還想添加更多參數,直接在形參表裏添加就行了。添加的形參的實參值,來自於圖3的第二個輸入框,這個輸入框可填常量,也可以填工作區變量名。

形參:①當前的仿真時間t,單位爲秒,該參數可以用來描述變參數系統,例如你想實現【在t>2S時,把系統增益給改掉】這一功能,就可以通過判定t的值來實現;②x爲狀態列向量;③輸入列向量u;④flag爲當前狀態機的第幾步,例如實參送進來的flag=0代表S函數需要初始化,flag=1代表要更新連續狀態

返回值:在不同的狀態步下(也即flag不同時),返回值的意義是不同的,在模板文件的註釋中都講到了:

例如flag=0時,需要返回:輸入輸出狀態變量等的大小SIZES、狀態變量的初值X0等。。。
又如flag=3時,返回值sys代表輸出向量Y,也即狀態空間表達式第2式,Y=CX+DU

不同flag下返回值得寫法,將在下面的各個函數中依次講解

(2)系統初始化

當我麼在函數中檢測到flag=0時,意味着simulnk需要我們返回系統初始化的一些信息。
實際上,我們可以直接把flag=0時需要執行的代碼直接寫在switch-case中,但是爲了使程序更清晰,我們也仿照官方模板,在case中調用初始化函數mdlInitializeSizes,我們把代碼寫在初始化函數中。

function [sys,x0,str,ts,simStateCompliance]=mdlInitializeSizes

sizes = simsizes;

sizes.NumContStates  = 1;%連續狀態向量的元素數目
sizes.NumDiscStates  = 0;%離散狀態向量的元素數目
sizes.NumOutputs     = 2;%輸出向量的元素數目
sizes.NumInputs      = 1;%輸入向量的元素數目
sizes.DirFeedthrough = 1;%輸入是否直接饋通到輸出
sizes.NumSampleTimes = 1;   % 採樣時間矩陣的行數(必須設爲>=1),另外列數固定爲2,無需設置

sys = simsizes(sizes);%把以上賦值好的結構賦給返回值
x0  = [0];%設置狀態向量的初值
str = [];%保留參數,不用管
ts  = [0 0];%採樣時間設置,必須爲mx2維度,其中m爲上面sizes.NumSampleTimes的值
simStateCompliance = 'UnknownSimState';

此函數中,按照回調函數的要求,sys的返回要返回一些成員的尺寸大小,我們可以一個個爲sys(1)、sys(2)。。等依次賦值,但我們不會這麼做,因爲官方模板爲我們提供了一個輔助數據結構的實體simsizes,直接把他複製出來把成員值改好,再賦值給返回值sys即可。simsizes的成員有6個,其中有2個需要單獨講一下:

①直接饋通標誌DirFeedthrough,這個東西實際上就是看看狀態空間表達式第2式Y=CX+DU中的D矩陣是否爲0矩陣,如果不是,那我們必須把饋通標誌設爲1。從回調函數來看,只要我們把DirFeedthrough設成了1,那麼當flag=3時,系統會把t、u兩個參數傳進總函數oneOrderModule中,如果DirFeedthrough設成了0,那麼當flag=3時,我們在oneOrderModule函數或者mdlOutputs函數中中將無法讀到t的值(實際讀出來總是0),也無法讀到u的值(實際讀出來總是一個只含Nan元素的向量)。

②採樣時間矩陣的行數NumSampleTimes
這個東西有些複雜,從直觀上看,它決定了【採樣時間矩陣ts】的行數,ts矩陣是NumSampleTimes行2列的矩陣。ts的每一行均包含一個數據對:[ 採樣時間   偏移量 ],這些數據對不是亂填的,可選就這麼幾種形式:

採樣時間可以理解爲採樣週期,真正的採樣時刻=n*週期+偏移量。
對於連續系統,採樣時間應設爲0,matlab也提供宏CONTINUOUS_SAMPLE_TIME,該宏的值=0。
對於固定步長的離散系統,可以直接設置採樣間隔和偏移,形如:[ 0.1   0.02 ]
對於變步長的離散系統,可以設置爲:[VARIABLE_SAMPLE_TIME,  0.0],這種參數需要同時把simulink求解器solver設置成變步長的。
繼承前一模塊的採樣點,可以設置爲:[INHERITED_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET或0]。

更多知識點,可以搜索這幾個宏名來學習。

 

(3)連續系統更新、離散系統更新

這兩個函數分別爲mdlDerivatives和mdlUpdate,如果需要支持自定義的參數,那麼直接修改函數的形參表即可,在我的例子中,我附加了一個T參數,那麼我的連續系統更新函數是這樣的:

function sys=mdlDerivatives(t,x,u, T)
A = [-1/T];
B = [1/T];
sys = A*x+B*u;

原理是這樣的,典型一階系統的微分方程:

如果系統中存在離散狀態,那麼就在mdlUpdate中寫出離散狀態空間表達式即可,如果沒有離散狀態,就直接sys返回空矩陣。

(4)輸出函數

function sys=mdlOutputs(t,x,u)
C = [1 
    1];
D = [0
    1];
 sys = C * x + D * u;
%sys = [x t];

這個也沒啥好說的,描述一下輸出向量即可。不過提醒一下,如果使用了 u或t 參數,不要忘記把饋通標誌置1,否則在本函數中收不到t和u的實參值。

這個函數描述了兩個輸出: y(1)=x,y(2)=x+u

 

 

下面看一下仿真結果:

和預想的一樣,沒毛病。

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