基于MATLAB和S函数的复杂系统设计
(1)初始化阶段。它是仿真的第一步,先于第一个仿真循环,它初始化S函数,在这个阶段,Simulink完成下面的工作:
? 初始化SimStruct包含S函数信息的数据结构; ? 确定输入、输出端口的数目和大小; ? 确定模块的采样时间; ? 分配内存给sizes数组。
(2)计算下一个采样点的时间。如果模型使用变步长解法器,那么需要在当前仿真确定下一个采样点的时刻,也即下一个仿真和大小。
(3)计算当前主仿真步的输出。在这个调用完成后,模块的所有输出端口都对当前的仿真步有效,也即是说只有在一个模块被更新之后,它才能作为其他模块的有效输入,去影响那些模块的行为。
(4)更新模块当前主时间步的离散状态。在这个仿真阶段中,所有的模型块都要进行每个时间步一次的活动为当前时间的仿真循环更新离散状态。
在仿真模型建立的同时我们要用到MATLAB当中的S函数。它是一种用程序描述而非控制模块图描述的动态系统,可以使用MATLAB语言来编写,并编译成MATLAB的.m文件格式的文件。
S-function运行时由sys参数控制的,所以第一步是先写程序。在MATLAB命令窗口中键入命令edit sfuntempl即可调用模块板程序编辑S函数。第二步就是到非线性模块库中将S-function的系统功能模块复制进来,然后输入程序文件名,以供调用。S-function的设计步骤很简单,只有两步,但是可以实现非常复杂的功能。
2.2 S函数的基本结构及封装
2.2.1 S函数的概述
S函数是 System function 系统函数的简称,是指采用非图形化(即计算机语言,而非 Simulink系统模块)的方式描述的功能模块。在MATLAB中,用户除了可以使用 MATLAB代码编写S函数以外,还可以使用C、C++、FORTRAN 或Ada 语言编写S函数,只不过用这些语言编写程序时需要用编译器生成动态连接库(DLL)文件,然后在 Simulink 中直接调用。
S函数是由一种特殊的语法构成的,用来描述并实现动态系统的。它采用一种特殊的调用语法,使函数和Simulink求解器进行交互。这种交互与求解器和Simulink仿真模型间的交互相类似:S函数接受来自Simulink求解器的相关信息,并对求解器发出的命令做出适当的响应。S函数作为与其它语言结合的接口,可以使用这个语言所提供的强大功能。例如,使用MATLAB语言编写的S函数称为M文件S函数,它可以充分利
6
基于MATLAB和S函数的复杂系统设计
用MATLAB所提供的丰富资源,方便地调用各种工具箱函数和图形函数;而使用C 语言编写的S函数被称为C-MEX 文件S函数,则可以实现对操作系统和外部设备等的访问,也可以提供与操作系统的接口。另外,S函数可以使用其他多种语言编写,因此可以实现代码的移植,即将已有的代码结合进来,而不需在Simulink中重新实现算法。
S函数中采用非图形化的方式描述系统,其内部采用文本方式输入描述系统的公式、方程,这种方式非常适合复杂动态系统的数学描述,且可以在仿真过程中对仿真进行精确的控制。
2.2.2 S函数的基本结构
S函数[10]是有固定格式的,MATLAB语言和C语言编写的S函数的格式是不同的。用MATLAB语言编写的S函数的引导语句为:
function [sys,x0,str,ts]=fun(t,x,u,flag,p1,p2,?)
其中fun为S函数的函数名,t,x,u分别为时间、状态和输入信号,flag为标志位,标志位的取值不同,S函数执行的任务与返回数据也是不同的:
(1)若flag的值为0时,将启动S函数所描述系统的初始化过程,这时将调用一个名为mdlInitializeSizes()子函数,该函数应该对一些参数进行初始设置,如离散状态变量的个数、连续状态变量的个数,模块输入和输出的路数,模块的采样周期个数和采样周期的值、模块状态变量的初值向量x0等。首先通过sizes=simsizes语句获得默认的系统参数变量sizes。得出的sizes实际上是一个结构体变量,其常用成员为:
? NumContStates表示S函数描述的模块中连续状态的个数; ? NumDiscStates表示离散状态的个数;
? NumInputs和NumOutputs分别表示模块输入和输出的个数;
? DirFeedthrough为输入信号是否直接在输出端出现,取值可以为0,1; ? NumSampleTimes为模块采样周期的个数。
按照要求设置好的结构体sizes应该在通过sys=simsizes(sizes)语句赋给sys参数。除了sys外,还应该设置系统的初始状态变量x0、说明变量str和采样周期变量ts,其中ts变量应该为双列的矩阵,其中每一行对应一个采样周期。对连续系统和有单个采样周期的系统来说,该变量为[t1,t2],其中t1为采样周期,如果取t1=-1则将继承输入信号的采样周期参数t2为偏移量,一般取为0。
(2)若flag的值为1时,将作连续状态变量的更新,将调用mdlDerivatives函数,更新后连续状态变量将由sys变量返回。
(3)若flag的值为2时,将作离散状态变量的更新,将调用mdlUpdate()函数,更新后的离散状态变量将由sys变量返回。
(4)若flag的值为3时,将求取系统的输出信号,将调用mdlOutputs()函数,
7
基于MATLAB和S函数的复杂系统设计
将计算得出的输出信号由sys变量返回。
(5)若flag的值为4时,将调用mdlGetTimeOfNextVarHit()函数,计算下一步的仿真时刻,并将计算得出的下一步仿真时间由sys变量返回。
(6)若flag的值为9时,将终止仿真过程,将调用mdlTerminate()函数,这时不返回任何变量。
S函数中目前不支持其他的flag选择。形成S函数的模块后,就可以将其嵌入到系统的仿真模型中进行仿真了。在实际仿真过程中,Simulink会自动将flag设置成0,进行初始化过程,然后将flag的设置为3,计算该模块的输出。一个仿真周期后,Simulink先将flag的值分别设置为1和2,更新系统的连续和离散状态,再将其设置成3来计算模块的输出值,如此一个周期接一个周期地计算,直至仿真结束条件满足,Simulink将把flag的值设置成9,终止仿真过程。 2.2.3 S函数模块的封装
右键点击S函数模块,选择MASK选项,弹出封装编辑框,在这里有四个栏,分别为图标、参数、初始化、文档。其中参数最为重要。图标即模块上显示的图形,可以编辑自己需要的文字,也可以用图片包装模块。初始化可以对模块参数进行默认设置,文档中可以编写模块说明和帮助链接。而最重要的参数栏中,要把模块对应的S函数的参数列出来,每一个参数有三种形式:编辑、下拉框、复选框。如果是下拉框形式,要编辑对应的选项。如果S函数需要响应不同操作,可以对每一个参数选择编写对应的回调函数。
封装编辑好后,右键点击S函数模块选择LOOK UNDER MASK选项,在弹出的对话框中,首先填写原文件,把编译过的文件放置在当前目录下,在对话框中正确填写文件名(不写后缀),然后再把封装时定义的参数变量按顺序写在参数框中,每个参数用逗号隔开,注意变量名必须与封装填写的名称一致,且数目相同。最有一个框不用填写。点击OK。则完成了对S函数的模块封装。
2.3 S函数工作原理
了解S函数的工作原理对于用户掌握S函数的编写方法是非常有用的,对用户对于 Simulink 的仿真原理的理解也是很有帮助的。本节介绍S函数的工作原理。
在具体介绍S函数的工作原理之前,首先需要回顾一下Simulink模块的工作原理。 Simulink 中的每个模块都有三个基本元素:输入向量、状态向量和输出向量,分别表示为u,x和 y。图1反映了它们之间的关系。在Simulink模块的三个元素中,状态向量是最重要的,也是最灵活的概念。在Simulink中状态向量可以分为连续状态、离散状态或两者的结合。输入、输出及状态的关系可以用状态方程描述:
8
基于MATLAB和S函数的复杂系统设计
输出方程:y=f0 t ,x ,u (1) 连续状态方程:dx=fd t ,x ,u (2) 离散状态方程:xk+1=fu t ,x ,u (3) 其中x= dx xk+1 ,如图1所示。
输入 状态(x) ?? 模块
?? 输出
图1 Simulink模块的基本模型
Simulink在仿真时将上述方程对应不同的仿真阶段,它们分别是计算模块的输出、更新离散状态、计算连续状态的微分。在仿真开始和结束,还包括初始化和结束仿真两个阶段。在每个阶段,Simulink都反复地调用模块。
由于积分时,对仿真步长有要求,所以此时需要将仿真步长细化。完成一个仿真循环就进入下一个仿真步长,如此循环直至仿真结束。
在调用模型中的S函数时,Simulink会调用用户定义的S函数的例程来实现每个仿真阶段要完成的任务。这些任务包括:
(1)初始化:仿真开始前,Simulink在这个阶段初始化S函数,完成的主要工作包括:
? 初始化包含S函数所有信息的结构体SimStruct; ? 确定输入输出端口的数目和大小; ? 确定模块的采样时间; ? 分配内存和Sizes数组。
(2)计算下一个采样时刻:如果模型使用变步长求解器,那么就需要在当前仿真步长内确定下一个采样点的时间,也即下一个仿真步长的大小。
(3)计算输出:计算所有输出端口的输出值。
(4)更新离散状态:此例程在每个仿真步长处都要执行一次,为当前时间的仿真循环更新离散状态。
(5)数值积分:这个阶段只有模块具有连续状态和非采样过零点时才会存在。如果 S函数存在连续状态,Simulink 就在细化的小时间步长中调用S函数的输出(mdlOutputs)和微分(mdlDerivatives)例程。如果存在非采样过零点,Simulink将调用S函数中的输出(mdlOutputs)和过零检测(mdlZeroCrossngs)例程,以定位过零点。
关于仿真的概念:仿真步长(Simulation step)、仿真阶段(Simulation stage)。为了深入了解S函数的工作原理,还需了解一个概念:仿真循环(Simulation loop)。
9
基于MATLAB和S函数的复杂系统设计
一个仿真循环就是由仿真阶段按一定顺序组成的执行序列。对于每个模块,经过一次仿真循环就是一个仿真步长,而在同一个仿真步长中,模型中各模块的仿真按照事先排好的顺序依次执行。这个过程可以用图 2表示。
从图2中可以看出,在仿真开始时,Simulink首先对模型进行初始化,此阶段不属于仿真循环。在所有模块都初始化后,模块进入仿真循环,在仿真循环的每个阶段,Simulink都要调用模块或者S函数。
初始化模块 计算下一个采样时间点 (仅适用变采样速率模块) 计算输出 更新离散状态 数值积分 计算导数 计算输出 计算导数 检测过零事件 仿真结束 图2 S函数仿真流程
3两关节机械手仿真模型
为了验证机械手模型的稳定性,选两关节机器人系统(不考虑摩擦力)进行仿真,其动力学模型为:
?? ?? ??+?? ??,?? ??+?? ?? +??=?? (4)
10