点击显示 收起
【摘要】 首先介绍了S函数的工作原理及仿真流程,然后通过举例说明了三种S函数的编写方法。根据不同的对象,通过对S函数的灵活运用,可在实际应用当中轻松实现所需要的功能模块。
【关键词】 Matlab Simulink S函数 模块封装
The Application of S Function in Simulink
LUO Ting
(Department of Basics of Computer Science,Chengdu Medical College,Chengdu 610083,China)
Abstract:The principle and simulation processes of the S function were introduced firstly.Then three ways to write the S function were explained through examples.It could be concluded that necessary functional modules could be easily obtained through flexible manipulation of the S function in practical applications.
Key words:Matlab;Simulink;S function;module mask
1 引言
S函数是System Function的简称。在很多情况下,Simulink现有的模块已经不能满足用户的需要,这时可以自己编写相应的代码来完成对模块功能的需求。S函数则提供了一个代码和Simulink模块之间的接口,用来实现对模块的编程。其中S函数的代码可以用Matlab语言编写,也可以是C、C++、Ada、Fortran等语言编写。而非Matlab语言在应用当中须先被编写成MEX文件,即Matlab Executable文件[3][6]。
2 S函数工作机理[1]
每个Simulink模块都可用输入信号u,输出信号y和当前模块的状态x等三个变量描述。如下图所示:
在simulink当中,对于连续和离散的系统,它的处理方式是不一样的。在t时刻模块内部的状态是由两个状态构成,连续状态xc和离散状态xd,则这个时刻对应的状态为
图1 simulink模块的工作原理示意图
Fig.1 Operating principle of Simulink module
x=xc+xd,y=f(t,x,u),系统输出为。对于连续系统来说,更新系统状态是通过对目标函数进行求导以及积分来实现的,而对于离散系统来说,则没有求导以及积分的处理,直接在当前时刻更新其状态,得到系统的输出。
此时系统可用以下方程进行描述
连续状态方程:x′=fd(t,x,u)
离散状态方程:xk+1=fu(t,x,u)
系统输出方程:y=f0(t,x,u)3 Simulink的仿真流程
simulink的仿真过程可分为三个阶段:初始化阶段;仿真循环阶段;仿真结束阶段。
在仿真过程当中,Simulink会调用相应的仿真例程来完成相应的功能。首先,在初始化阶段,Simulink将对整个系统模块的参数进行初始化,检查各个模块的数据长度和类型,制订仿真模块的执行顺序,设置相应的仿真时间间隔以及内存的分配等等;接下来,在仿真循环阶段,按照初始化制订的仿真顺序依次执行每一个模块。对于离散状态,会更新当前时刻的离散状态并进行输出,而对于连续时间则处理起来相对复杂,它会计算两次输出,这两次输出会在求解器当中进行一致性检查,当超过求解器设置的容限时,求解器会以一个更小的步长进行计算输出,而且在连续时间状态情况下存在一个过零检测的问题,即在仿真循环当中如果检测到过零点,simulink系统会自动在此过零点周围进行插值。
仿真过程是由求解器和simulink系统交互控制的,它们之间的交互关系可由下面一个图进行说明[4]:
图2 求解器和simulink系统的交互行为示意图
Fig.2 Interactive behavior of the solution implement and simulink system
4 M文件S函数
M文件的S函数分为两种, level 1和level 2。它们互有缺点,前者运行速度快,但无法处理复数以及基于帧数据的处理,后者运行速度稍慢,但能处理复数数据和基于帧的数据[5]。下面分别对两种M文件S函数的编写进行描述。
4.1 Level1级S函数
在大多数情况下,运用level 1的S函数即可满足用户的需要。下面针对Simulink给的level 1的S函数模块介绍S函数的具体编写方法,此文件名为sfuntmpl.m(在Matlabroot/toolbox/simulink/blocks下),或者直接在命令行输入>>edit sfuntmp1,即打开该函数,因为在Matlab下已将此路径设置为搜索路径。
function [sys,x0,str,ts] = sfuntmpl(t,x,u,flag)
此函数有4个输入参数:
①t:采样时间
②x:系统状态
③u:输入
④flag:仿真流程控制标志
函数的输出有4个:
①sys:各子函数返回值,随调用子函数不同意义不同
②x0:各状态的初始值
③str:保留参数,设置为[]
④ts:系统采样时间,为一个n×2的矩阵,第一列表示抽样时间,第二列表示时间偏移量下面举例说明M文件S函数的编写过程。
例:实现一个具有信号增益效果的模块(单输入、单输出),且增益可调。
首先需要修改的是函数名称(自定)以及添加一个系统输入参数gain,添加的方式为: function[sys,x0,str,ts]=VariableGain_Level1(t,x,u,flag,gain)
除了基本的初始设置以外,只需对VariableGain_Level1中的mdlOutputs子函数进行配置即可实现对输入信号增益的功能,如下
sys=gainu
这里gain是增益参数,u是输入的数据,sys在mdlOutputs子函数当中
接下来就是需要用Simulink模块的S函数模块与此VariableGain_Level1函数相关联。此模块在Simulink\User-Defined Functions里:
双击此模块,会弹出以下这个对话框:
现在需要将上面编辑的S函数名VariableGain_Level1放写在“S-function name”栏,且将需要用到的参数gain写在“S-function parameters”栏(当出现多个参数时,各个参数之间需用逗号隔开),如果不出现错误,此时已经将Simulink下S-Function模块与编写的VariableGain_Level1函数关联在一起。
此时模块中将显示关联的S函数名,且已经完成该模块应有的功能。
4.2 Level2级S函数
下面介绍level 2级的S函数的编写。首先level 2级的S函数的结构与level 1级的S函数不一样,但其基本处理流程一样。它的处理方式是基于模块的描述,比如对模块进行初始化,对模块内部参数的描述,对内部工作空间的使用等等。level 2级的S函数模版是放在Matlabroot/toolbox/simulink/blocks下,文件名为msfuntmpl.m。
下面给出一个用Level 2的M文件编写的一个S函数的例子,同样用来实现前面用Level 1级书写的增益函数。为了完成该功能,需要在Output函数当中添加如下语句进行实现:
gain=block.DialogPrm(1).Data;(4-2-1)
block.OutputPort(1).Data=gainblock.InputPort(1).Data;(4-2-2)
(4-2-1)句是将需要设置的增益参数传递给变量gain,(4-2-2)句是将输入端口1的数据乘以增益变量gain,并将得到的数据输出到输出端口1。
下面将此S函数进行模块封装,该模块在Simulink\User-Defined Functions里:
双击此模块,将弹出的对话框如下
其中第一栏的'M-file name'中填入S函数的名称VariableGain_Level2,第二栏的'Parameters'中填入需用到的参数gain(当出现多个参数时,各个参数之间需用逗号隔开)。完成此操作之后,模块将可以实现和level 1级的S函数一样的功能:
此时模块中将显示关联的S函数名。
5 C Mex S函数[2]
C语言S函数采用通用的C语言规范,它比M文件S函数具有更强的处理能力,更快的执行速度,并且可以生成独立可执行的C-Mex文件。
C语言的S函数的编写方式与M文件S函数比较相似,都是采用回调函数的方式。根据Simulink的不同指令调用不同的函数,然后返回相应的结果。与M文件S函数相比,C语言S函数提供了更多的回调函数。对于仿真过程中的每一个模块,Simulink都建立了一个SimStruct的数据结构,用于保存该模块的相关信息。在M文件S函数中,这个数据结构是不能被读取的,但在C语言S函数中,我们能够读取和修改SimStruct结构中的内容,因此能够实现对仿真过程更强的控制功能。另外,C语言的S函数能够处理更多类型的数据类型,比如矩阵信号等。为此,Simulink为C语言S函数定义了更多的回调函数,用于实现更多的数据处理功能。
与M文件S函数类似,C语言S函数也有与之对应的模版,不同的是它有两个版本,一个为基本的模版sfuntmpl_basic.c,其中包含了必要的几个回调函数,可以满足用户基本的需求,另一个则是比较详尽的模版Sfuntempl_doc.c,它们都在Matlabroot\simulink\src目录下。
下面给出一个用C语言编写的一个S函数的实例,同样用来实现前面用M文件S函数写的增益函数,此时只需用到C语言的基本模版。与M文件S函数的编写类似,C Mex的S函数主要完成功能也是在子函数mdlOutputs当中,不同的是C语言是通过指针对数据进行访问,首先应该给该函数命名:
#define S_FUNCTION_NAME VariableGain_C
而mdlOutputs中的关键代码如下:
int_T i;
InputRealPtrsType uPTRS=ssGetInputPortRealSignalPtrs(S,0);(5-1)
real_T y=ssGetOutputPortRealSignal(S,0);(5-2)
int_T width=ssGetOutputPortWidth(S,0);(5-3)
const real_T G=mxGetPr(ssGetSFcnParam(S,0));(5-4)
for(i=0;i
{
y++=(G)(uPTRS[i]);(5-5) }
(5-1)句是获得输入信号的指针;(5-2)句是获得输出信号的指针;(5-3)句是获得输出端口的宽度;(5-4)句是获得输入参数的指针,(5-5)句是完成信号增益的功能。
至此,完成了对带有一个输入参数的C语言S函数的编写,如要实现在Simulink下调用此S函数,还需要将该C文件转换成MEX,即Matlab可执行文件。只需要在Matlab命令窗口中执行如下命令即可:
mex VariableGain_C.c
系统会自动生成一个VariableGain_C.mexw32的文件,此文件即可在Matlab下进行调用。接下来的操作与处理Level 1级的M文件S函数一样。生成的S函数模块如下:
该模块已经能够完成对输入的增益参数进行相应的功能,模块中即显示为C Mex文件名。
6 结束语
在实际应用当中,通过对三种S函数模块的比较,Level1级的M文件S函数能处理的对象较少,只能应付普通的基于点数据的操作;Level2级的M文件S函数则功能相对完备,只是运行速度不及前者,当然也不及C Mex的S函数;而C Mex的S函数在运行速度上为最优,功能最强大,但其缺点是对矩阵的处理略显复杂。所以根据不同的对象,应选取不同的S函数编写方式。
【参考文献】
[1]The Math Works Inc.Using SIMULINK,Natick,MA.July 2002.
[2]The Math Works Inc.Writing S-Functions,Natick,MA.July 2002.
[3]Tomas Co.Short Tutorial on Matlab.2004.
[4]姚俊,马松辉.Simulink建模与仿真[M].西安:西安电子科技大学出版社, 2002.
[5]陈永春.从Matlab/Simulink模型到代码实现[M].北京:清华大学出版社,2002.
[6]邓华.MATLAB通信仿真及应用实例详解[M].北京: 人民邮电出版社, 2003.