Matlab S-Function使用方法總結

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=[].

狀態向量XX0包含離散狀態下的連續狀態。
可選參數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*usys此時表示輸出狀態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模型生成的步驟說明如下所示:

  1. 首先將上文介紹的模板文件sfuntmpl.m複製到自己Matlab的WorkSpace中,並將其重命名爲自己自定義模型的名稱。
  2. 根據自定義模型需要修改文件中的函數。
  3. 在Simulink程序界面打開Simulink library Browser,在其左側導航欄中的simulink --> user-defined function中拖一個S-Function模型到自己的模型設計界面中。
  4. 雙擊添加的S-Function,設置S-function name參數爲自定義模型的名稱(和.m文件名一致);點擊Edit按鈕,即可跳轉到第2步完成的.m文件進行編輯。
  5. 如果模型存在自定義的輸入參數,還需要設置S-function modules參數。
  6. 點擊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",該模塊可以設置增益參數。

  1. 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

  1. 新建Simulink模型,並添加Sine Wave模塊、S-Function模塊和Scope模塊,如下圖所示。其中Sine Wave模塊的Amplitude參數設置爲1Scope模塊的輸入參數個數設置爲2
    在這裏插入圖片描述
  2. 雙擊S-Function模塊進行如下圖所示參數設置。注意此處設置S-Function的增益參數爲5
    在這裏插入圖片描述
  3. 單擊Simulink界面中的"Run"按鈕運行此模型,雙擊Scope模塊可以得到如下圖所示結果。
    在這裏插入圖片描述
    上圖中,黃色曲線爲S-Function模塊的輸入信號,藍色曲線爲輸出信號,輸出信號相對輸入信號增益爲5,和第3步S-function parameters的設置相吻合。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章