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的设置相吻合。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章