Matlab S-Function使用方法總結
目錄
S-Function也就是System-Function的縮寫,是一種強大的對Simulink模塊庫進行擴展的工具,利用它可以實現自己的Simulink模塊。S-Function就是MATLAB由於內置模型不能完全滿足用戶需求,而提供給用戶自己編寫程序來滿足自己模型需求的接口。S函數是一個動態系統的計算機語言描述,可以用Matlab、C、C++、Fortran、Ada等語言來寫,本文只介紹怎樣用Matlab語言來實現S-Function功能。
1 S-Function示例程序分析
在Matlab的workspace裏輸入命令:
edit sfuntmpl
打開Matlab提供的S函數的模板文件sfuntmpl.m
,這是matlab自己提供的s函數模板,我們通過它來具體分析s函數的結構。
概括說來, 建立S-Function可以分成兩個分離的任務:第一,初始化模塊特性包括輸入輸出信號的寬度,離散連續狀態的初始條件和採樣時間,等。第二,將算法放到合適的S-Function子函數中。下面結合示例程序進行詳細分析。
1.1 輸入輸出分析
它的第一行是這樣的:
function [sys,x0,str,ts,simStateCompliance] = sfuntmpl(t,x,u,flag)
其遵循Matlab S-Function語法的通用格式:
[SYS,X0,STR,TS,SIMSTATECOMPLIANCE] = SFUNC(T,X,U,FLAG,P1,...,Pn)
上述通用格式表明,SFUNC
函數在給定時間T
返回的內容取決於標誌量FLAG
、當前狀態向量X
、以及當前輸入向量U
。其中,FLAG
是仿真過程中的狀態標誌(以它來判斷當前是初始化還是運行等),其完整定義如下:
% FLAG RESULT DESCRIPTION
% ----- ------ --------------------------------------------
% 0 [SIZES,X0,STR,TS] Initialization, return system sizes in SYS,
% initial state in X0, state ordering strings
% in STR, and sample times in TS.
% 1 DX Return continuous state derivatives in SYS.
% 2 DS Update discrete states SYS = X(n+1)
% 3 Y Return outputs in SYS.
% 4 TNEXT Return next time hit for variable step sample
% time in SYS.
% 5 Reserved for future (root finding).
% 9 [] Termination, perform any cleanup SYS=[].
狀態向量X
和X0
包含離散狀態下的連續狀態。
可選參數P1,...,Pn
可以提供給S-Function並且可以在任意FLAG
操作時使用。
輸出量的含義:SYS
輸出根據FLAG
的不同而不同(下面將結合FLAG
來講SYS
的含義),X0
是狀態變量的初始值,STR
是保留參數(一般在初始化中將它置空就可以了,如設str=[]
),TS
是一個1×2
的向量,TS(1)
是採樣週期,TS(2)
是偏移量。
當SFUNC
函數在FLAG=0
時被調用,將會返回下列信息:
SYS(1) = Number of continuous states.
SYS(2) = Number of discrete states.
SYS(3) = Number of outputs.
SYS(4) = Number of inputs.
Any of the first four elements in SYS can be specified
as -1 indicating that they are dynamically sized. The
actual length for all other flags will be equal to the
length of the input, U.
SYS(5) = Reserved for root finding. Must be zero.
SYS(6) = Direct feedthrough flag (1=yes, 0=no). The s-function
has direct feedthrough if U is used during the FLAG=3
call. Setting this to 0 is akin to making a promise that
U will not be used during FLAG=3. If you break the promise
then unpredictable results will occur.
SYS(7) = Number of sample times. This is the number of rows in TS.
X0 = Initial state conditions or [] if no states.
STR = State ordering strings which is generally specified as [].
TS = An m-by-2 matrix containing the sample time
(period, offset) information. Where m = number of sample
times. The ordering of the sample times must be:
TS = [0 0, : Continuous sample time.
0 1, : Continuous, but fixed in minor step
sample time.
PERIOD OFFSET, : Discrete sample time where
PERIOD > 0 & OFFSET < PERIOD.
-2 0]; : Variable step discrete sample time
where FLAG=4 is used to get time of
next hit.
There can be more than one sample time providing
they are ordered such that they are monotonically
increasing. Only the needed sample times should be
specified in TS. When specifying more than one
sample time, you must check for sample hits explicitly by
seeing if
abs(round((T-OFFSET)/PERIOD) - (T-OFFSET)/PERIOD)
is within a specified tolerance, generally 1e-8. This
tolerance is dependent upon your model's sampling times
and simulation time.
You can also specify that the sample time of the S-function
is inherited from the driving block. For functions which
change during minor steps, this is done by
specifying SYS(7) = 1 and TS = [-1 0]. For functions which
are held during minor steps, this is done by specifying
SYS(7) = 1 and TS = [-1 1].
SIMSTATECOMPLIANCE = Specifices how to handle this block when saving and
restoring the complete simulation state of the
model. The allowed values are: 'DefaultSimState',
'HasNoSimState' or 'DisallowSimState'. If this value
is not speficified, then the block's compliance with
simState feature is set to 'UknownSimState'.
下面結合sfuntmpl.m中的代碼來講具體的結構:
1.2 函數分析
下面結合sfuntmpl.m
文件中的代碼來講具體的結構。
1.2.1 flag爲0的情況
%
% The following outlines the general structure of an S-function.
%
switch flag, %判斷flag,看當前處於哪個狀態
%%%%%%%%%%%%%%%%%%
% Initialization %
%%%%%%%%%%%%%%%%%%
case 0,
[sys,x0,str,ts,simStateCompliance]=mdlInitializeSizes;
解釋說明:
flag=0
表示當前處於初始化狀態,此時調用函數mdlInitializeSizes
進行初始化,此函數在該文件中定義。內容如下:
%
%===========================================================================
% mdlInitializeSizes
% Return the sizes, initial conditions, and sample times for the S-function.
%===========================================================================
%
function [sys,x0,str,ts,simStateCompliance]=mdlInitializeSizes
%
% call simsizes for a sizes structure, fill it in and convert it to a
% sizes array.
%
% Note that in this example, the values are hard coded. This is not a
% recommended practice as the characteristics of the block are typically
% defined by the S-function parameters.
%
sizes = simsizes;
sizes.NumContStates = 0;
sizes.NumDiscStates = 0;
sizes.NumOutputs = 0;
sizes.NumInputs = 0;
sizes.DirFeedthrough = 1;
sizes.NumSampleTimes = 1; % at least one sample time is needed
sys = simsizes(sizes);
% initialize the initial conditions
x0 = [];
% str is always an empty matrix
str = [];
% initialize the array of sample times
ts = [0 0];
simStateCompliance = 'UnknownSimState';
其中的返回值sys
是一個Simulink所需的結構體,它用來設置模塊的一些參數,各個參數詳細說明如下:
size = simsizes;%用於設置模塊參數的結構體用工具函數simsizes來生成
sizes.NumContStates = 0; %模塊連續狀態變量的個數
sizes.NumDiscStates = 0; %模塊離散狀態變量的個數
sizes.NumOutputs = 0; %模塊輸出變量的個數
sizes.NumInputs = 0; %模塊輸入變量的個數
sizes.DirFeedthrough = 1; %模塊是否存在直接貫通
sizes.NumSampleTimes = 1; %模塊的採樣時間個數, 至少是一個
sys = simsizes(sizes); %設置完後賦給sys輸出
舉個例子,考慮如下模型:
dx/dt=fc(t,x,u)
也可以用連續狀態方程描述:dx/dt=A*x+B*u
x(k+1)=fd(t,x,u)
也可以用離散狀態方程描述:x(k+1)=H*x(k)+G*u(k)
y=fo(t,x,u)
也可以用輸出狀態方程描述:y=C*x+D*u
設上述模型連續狀態變量、離散狀態變量、輸入變量、輸出變量均爲1個,我們就只需改上面那一段代碼爲(一般連續狀態與離散狀態不會一塊用, 此處是爲了方便說明):
sizes.NumContStates=1;
sizes.NumDiscStates=1;
sizes.NumOutputs=1;
sizes.NumInputs=1;
程序中其他的部分可以保持不變, 繼續在mdlInitializeSizes函數中往下看:
x0 = []; %初始狀態變量設置爲空,表示沒有狀態變量,以我們上面的假設,
%可改爲x0=[0,0](離散和連續的狀態變量我們都設它初值爲0)
str = []; %保留參數, 置[]即可。
ts = [0 0]; %採樣週期設爲0表示是連續系統, 如果是離散系統,
%在下面的mdlGetTimeOfNextVarHit函數中具體介紹
1.2.2 flag爲1的情況
%%%%%%%%%%%%%%%
% Derivatives %
%%%%%%%%%%%%%%%
case 1,
sys=mdlDerivatives(t,x,u);
flag=1
表示此時要計算連續狀態的微分,即上面提到的dx/dt=fc(t,x,u)
中的dx/dt
,找到函數mdlDerivatives
的定義,如果設置連續狀態變量個數爲0,則此處只需sys=[]
就可以了,按我們上述討論的那個模型, 此處需要改成 sys=fc(t,x(1),u)
或sys=A*x(1)+B*u
,此處的x(1)
是連續狀態變量,而x(2)
是離散的,這裏只用到了連續的。此時的輸出sys就是微分結果。
1.2.3 flag爲2的情況
%%%%%%%%%%
% Update %
%%%%%%%%%%
case 2,
sys=mdlUpdate(t,x,u);
flag=2
表示此時要計算下一個離散狀態,即上面提到的x(k+1)=fd(t,x,u)
,在文件中找到mdlUpdate
函數, 其中的sys=[]
表示沒有離散狀態,我們可以改成sys=fd(t,x(2),u)
或sys=H*x(2)+G*u
;sys
即爲x(k+1)
。
1.2.4 flag爲3的情況
%%%%%%%%%%%
% Outputs %
%%%%%%%%%%%
case 3,
sys=mdlOutputs(t,x,u);
flag=3
表示此時要計算輸出狀態,即y=fo(t,x,u)
。找到文件中定義的mdlOutputs
函數。sys=[]
則表示沒有輸出狀態,我們可以改成sys=fo(t,x,u)
或sys=C*x+D*u
,sys
此時表示輸出狀態y
。
1.2.5 flag爲4的情況
%%%%%%%%%%%
% GetTimeOfNextVarHit %
%%%%%%%%%%%
case 4,
sys=mdlGetTimeOfNextVarHit(t,x,u);
flag=4
表示此時要計算下一次採樣的時間,只在離散採樣系統中才有用(即上文的mdlInitializeSizes
中提到的設置ts(1)
不爲0)。連續系統中只需在mdlGetTimeOfNextVarHit
函數中設置sys=[]
。該函數主要用於變步長的設置,具體實現可以通過輸入命令edit vsfunc
查看vsfunc.m文件中的示例。
1.2.6 flag爲9的情況
%%%%%%%%%%%
% Terminate %
%%%%%%%%%%%
case 9,
sys=mdlTerminate(t,x,u);
flag=9
表示此時系統即將結束,通常,在mdlTerminate
函數中設置sys=[]
即可,除非想要在系統結束之前還需要進行一些操作。
1.3 輸入參數設置
利用上文提到的可選參數P1,...,Pn
,S-Function可以設置輸入參數。下面的例子通過S-Function的可選參數實現simulink下的gain模塊一樣的功能。
function [sys,x0,str,ts,simStateCompliance] = sfungain(t,x,u,flag,gain)
switch flag,
case 0,
sizes = simsizes;
sizes.NumContStates = 0;
sizes.NumDiscStates = 0;
sizes.NumOutputs = 1;
sizes.NumInputs = 1;
sizes.DirFeedthrough = 1;
sizes.NumSampleTimes = 1;
sys = simsizes(sizes);
x0=[];
str=[];
ts=[0,0];
case 3,
sys=gain*u;
case {1,2,4,9},
sys = [];
end
2 S-Function模型生成
S-Function模型生成的步驟說明如下所示:
- 首先將上文介紹的模板文件
sfuntmpl.m
複製到自己Matlab的WorkSpace中,並將其重命名爲自己自定義模型的名稱。 - 根據自定義模型需要修改文件中的函數。
- 在Simulink程序界面打開Simulink library Browser,在其左側導航欄中的
simulink --> user-defined function
中拖一個S-Function模型到自己的模型設計界面中。 - 雙擊添加的S-Function,設置
S-function name
參數爲自定義模型的名稱(和.m
文件名一致);點擊Edit
按鈕,即可跳轉到第2步完成的.m
文件進行編輯。 - 如果模型存在自定義的輸入參數,還需要設置
S-function modules
參數。 - 點擊
OK
按鈕完成S-Function模塊的配置。
在simulink --> user-defined function
中還有個s-Function Builder
,它可以生成用需要的S函數。具體操作示例可參考百度經驗(來源於網絡,僅供參考):https://jingyan.baidu.com/article/ae97a646727476fbfd461d85.html。
在Matlab的workspace下輸入命令
sfundemos
,可以看到很多演示S函數的程序。
3 S-Function的簡單設計示例
本節以1.3節提到的自定義gain模塊爲示例,具體展示S-Function的設計流程。
下面我們將利用S-Function設計一個和simulink下gain模塊類似的自定義模塊"Gain",該模塊可以設置增益參數。
- Matlab命令行輸入命令
edit sfuntmpl
打開S-Function示例函數,並將其複製到自己的Matlab工作空間下,重命名爲Gain.m
,並修改其內容如下:
function [sys,x0,str,ts,simStateCompliance] = Gain(t,x,u,flag,gain)
switch flag,
%%%%%%%%%%%%%%%%%%
% Initialization %
%%%%%%%%%%%%%%%%%%
case 0,
[sys,x0,str,ts,simStateCompliance]=mdlInitializeSizes;
%%%%%%%%%%%%%%%
% Derivatives %
%%%%%%%%%%%%%%%
case 1,
sys=mdlDerivatives(t,x,u);
%%%%%%%%%%
% Update %
%%%%%%%%%%
case 2,
sys=mdlUpdate(t,x,u);
%%%%%%%%%%%
% Outputs %
%%%%%%%%%%%
case 3,
sys=mdlOutputs(t,x,u,gain);
%%%%%%%%%%%%%%%%%%%%%%%
% GetTimeOfNextVarHit %
%%%%%%%%%%%%%%%%%%%%%%%
case 4,
sys=mdlGetTimeOfNextVarHit(t,x,u);
%%%%%%%%%%%%%
% Terminate %
%%%%%%%%%%%%%
case 9,
sys=mdlTerminate(t,x,u);
%%%%%%%%%%%%%%%%%%%%
% Unexpected flags %
%%%%%%%%%%%%%%%%%%%%
otherwise
DAStudio.error('Simulink:blocks:unhandledFlag', num2str(flag));
end
% end sfuntmpl
%
%===========================================================================
% mdlInitializeSizes
% Return the sizes, initial conditions, and sample times for the S-function.
%===========================================================================
%
function [sys,x0,str,ts,simStateCompliance]=mdlInitializeSizes
sizes = simsizes;
sizes.NumContStates = 0;
sizes.NumDiscStates = 0;
sizes.NumOutputs = 1;
sizes.NumInputs = 1;
sizes.DirFeedthrough = 1;
sizes.NumSampleTimes = 1; % at least one sample time is needed
sys = simsizes(sizes);
%
% initialize the initial conditions
%
x0 = [];
%
% str is always an empty matrix
%
str = [];
%
% initialize the array of sample times
%
ts = [0 0];
simStateCompliance = 'UnknownSimState';
% end mdlInitializeSizes
%
%===========================================================================
% mdlDerivatives
% Return the derivatives for the continuous states.
%===========================================================================
%
function sys=mdlDerivatives(t,x,u)
sys = [];
% end mdlDerivatives
%
%===========================================================================
% mdlUpdate
% Handle discrete state updates, sample time hits, and major time step
% requirements.
%===========================================================================
%
function sys=mdlUpdate(t,x,u)
sys = [];
% end mdlUpdate
%
%===========================================================================
% mdlOutputs
% Return the block outputs.
%===========================================================================
%
function sys=mdlOutputs(t,x,u,gain)
sys=gain*u;
%sys = [];
% end mdlOutputs
%
%===========================================================================
% mdlGetTimeOfNextVarHit
% Return the time of the next hit for this block. Note that the result is
% absolute time. Note that this function is only used when you specify a
% variable discrete-time sample time [-2 0] in the sample time array in
% mdlInitializeSizes.
%===========================================================================
%
function sys=mdlGetTimeOfNextVarHit(t,x,u)
sampleTime = 1; % Example, set the next hit to be one second later.
sys = t + sampleTime;
% end mdlGetTimeOfNextVarHit
%
%===========================================================================
% mdlTerminate
% Perform any end of simulation tasks.
%===========================================================================
%
function sys=mdlTerminate(t,x,u)
sys = [];
% end mdlTerminate
- 新建Simulink模型,並添加
Sine Wave
模塊、S-Function
模塊和Scope
模塊,如下圖所示。其中Sine Wave
模塊的Amplitude
參數設置爲1
,Scope
模塊的輸入參數個數設置爲2
。
- 雙擊S-Function模塊進行如下圖所示參數設置。注意此處設置S-Function的增益參數爲
5
。
- 單擊Simulink界面中的"Run"按鈕運行此模型,雙擊
Scope
模塊可以得到如下圖所示結果。
上圖中,黃色曲線爲S-Function模塊的輸入信號,藍色曲線爲輸出信號,輸出信號相對輸入信號增益爲5,和第3步中S-function parameters
的設置相吻合。