4.6 实验十 S函数的编写及应用
一、实验目的
1、学习S函数的编写方法。
2、利用S函数在Simulink环境中实现复杂模块。
二、相关知识
Simulink是提供了一个十分易用的仿真平台,但在使用过程中会发现有些过程或对象用现成的Simulink模块不易搭建,远不如m文件和函数灵活和强大。事实上,Simulink也提供了一个解决方案——S函数,类似于普通函数的功能,这大大扩展了Simulink的仿真能力。
1、 用MATLAB语句编写S函数
S函数还可以用C、C++、Fortran等语言编写。用MATLAB语句编写S函数引导语句为:
function [sys,x0,str,ts]=funname(t,x,u,flag,p1,p2,?)
其中funname 为函数名,t、x、u分别为时间、状态和输入信号,flag为标志位,这四个参数是固定的,后面几个参数为输入参数。flag的值为0、1、2、3、4和9,分别对应一个内部过程,其关系如下表所示: Flag取值 0 1 2 3 4 9 在仿真过程中,flag=0(初始化过程)仅出现一次,其他值(过程)在每个采样周期循环出现,在每个过程中要完成一些功能,只要在这个过程中写上适当的程序代码即可。函数主程序通常如下(参见Simulink自带文件sfuntmpl.mdl):
Switch flag Case 0,
[sys,x0,str,ts]=mdlInitializeSizes; case 1,
sys=mdlDerivatives(t,x,u); case 2,
sys=mdlUpdate(t,x,u); case 3,
sys=mdlOutputs(t,x,u);
过程 初始化 连续状态计算 离散状态计算 输出信号计算 调用函数名 mdlInitializeSizes mdlDerivatives mdlUpdate mdlOutputs 返回参数 sys为初始化参数,x0, str, ts如其定义 sys返回连续状态 sys返回离散状态 sys返回系统输出 下一步仿真时刻 mdlGetTimeOfNextVarHit sys返回下一步仿真的时间 终止仿真设定 mdlTerminate 无 33
case 4,
sys=mdlGetTimeOfNextVarHit(t,x,u); case 9,
sys=mdlTerminate(t,x,u); otherwise
error(['Unhandled flag = ',num2str(flag)]); end
调用的各函数写在主程序之后,函数名是Simulin推荐的函数名,不是强制性的,我们也可以用其他函数名,更简单地,不用函数,把过程直接写在主程序中。其中flag为0和3的过程必须编写程序,其他过程根据实际需要可忽略。初始化过程的编写有一定的规范,如下所示:
function [sys,x0,str,ts]=mdlInitializeSizes
sizes = simsizes;
sizes.NumContStates = 1; sizes.NumDiscStates = 0; sizes.NumOutputs = 1; sizes.NumInputs = 2; sizes.DirFeedthrough = 1;
sys = simsizes(sizes);
x0 = []; str = [];
初始化需提供S函数的一些特定信息,包括输入/输出变量和状态的个数等,这通过一个结构变量实现。第一句sizes = simsizes通过simsizes函数定义一个结构变量,该变量有6个结构元素,如上所示,按具体要求设置完成后,通过sys = simsizes(sizes)语句赋给sys参数。除了sys外,还应设置系统的初始状态变量x0、说明变量str和采样周期变量ts,其中ts为双列矩阵,每一行对应一个采样周期。对连续系统和有单个采样周期的系统来说,该变量为[t1,t2],其中t1为采样周期,t1=-1则将继承输入信号的采样周期,t2为偏移量,一般取0。
2、S函数的调用
建立Simulink仿真框图时,选择S-Function模块(MATLAB6.5/Simulink5在User-Defined Function模块库),双击S-Function模块,会弹出一个参数设置对话框,如下图所示,在S-Function name栏内填写S函数文件名,就可以建立起该模块和我们编写的S函数
%初始化状态
%说明字符串变量,通常为空串 %采样周期初始化
%连续状态的个数 %离散状态的个数 %输出变量个数 %输入变量个数
%输入是否直接至输出端,通常为1
%采样周期个数,通常为1。S函数支持多采样周期系统
sizes.NumSampleTimes = 1;
ts = [-1 0];
34
文件之间的联系,在S-Function parameters栏内给出S函数的输入参数,参数可以是常数,也可以是变量名,如果是变量名,仿真前须在命令窗口中赋值。
三、实验内容
1.编写S函数,实现下图死区非线性模块功能
编写S函数如下:
function [sys,x0,str,ts] = sqnl(t,x,u,flag,s1) %死区非线性
y h -s-h -s s -h s+h x 35
% s1为死区环值
switch flag, case 0,
[sys,x0,str,ts]=mdlInitializeSizes; case 1 sys=x; case 3,
sys=mdlOutputs(t,x,u,s1); case {1,2,4,9} sys=[]; otherwise
error(['Unhandled flag = ',num2str(flag)]); end
function [sys,x0,str,ts]=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); x0=[]; str=[]; ts=[-1 0];
function sys=mdlOutputs(t,x,u,s1) if abs(u)>=s1,
if u>0,sys=u-s1; else sys=u+s1; end
else sys=0; end
按上面介绍的方法,建立Simulink模块,运行验证。
2.编写S函数,实现积分分离PID控制功能
36