Matlab S-Function使用方法总结
目录
- Matlab S-Function使用方法总结
- 1 S-Function示例程序分析
- 1.1 输入输出分析
- 1.2 函数分析
- 1.2.1 flag为0的情况
- 1.2.2 flag为1的情况
- 1.2.3 flag为2的情况
- 1.2.4 flag为3的情况
- 1.2.5 flag为4的情况
- 1.2.6 flag为9的情况
- 1.3 输入参数设置
- 2 S-Function模型生成
- 3 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
的设置相吻合。