《武汉工程大学学报》 2014年11期
70-74
出版日期:2014-11-30
ISSN:1674-2869
CN:42-1779/TQ
矩阵实验室的仿真工具TrueTime设计
0引言仿真开始前,要初始化各个内核模块以及网络模块,创建一些计时器、任务、事件和监控器等[1].初始化代码和仿真时需要执行的代码可写成C++函数,也可以写成矩阵实验室(Matrix Laboratory,以下简称:Matlab)中的.m文件,前者的效率较高,后者更方便.1TrueTime的代码书写通过一个比例控制器(PIcontroller)的实现来说明如何书写Matlab或C++代码.1.1书写Matlab代码比例控制的Matlab代码实现如下:Function\[exectime,data\]=pcontroller(segment,data)Switch segment,Case 1,r=ttAnalogIn(1);y=ttAnalogIn(2);data.u=data.K*(r-y);exectime=0.002;Case 2,ttAnalogOut(1,data.u); exectime= -1;%finishedend变量segment用来决定执行哪一部分,data是用户定义的数据结构,该数据结构是在执行ttCreateTask或ttCreatePeriodicTask时创建的,在这个函数里被更新并返回.ttAnalogIn表示读,ttAnalogOut表示写.第一段代码的执行时间是2 s,这表示该任务的输入到输出的延时至少为2 s.第二段代码返回一个负的执行时间,用以表示代码执行已经结束,即没有其他的代码段需要执行了.1.2书写C++代码比例控制的C++代码实现如下所示,其中数据结构Task_Data已知,包含了控制信号u和控制器放大倍数K. Double Pcontroller(int segment,void*data){Task_Data*d=(Task_Data*) data;Swich(segment) {Case 1:double r=ttAnalogIn(1);double y=ttAnalogIn(2);d->u=d->K*(r-y);return 0.002;Case 2:ttAnalogOut(1, d->u);return FINISHED;//end of execution } }1.3调用仿真模块框图不论是通过C++实现还是通过Matlab实现,都可以在代码里调用仿真模块框图,这是实现控制器的一个简便方法,其代码实现如下:Function\[exectime,data\]=Picode(segment,data)Switch (segment),Case 1,inp(1)=ttAnalogIn(1);inp(2)=ttAnalogIn(2);outp=ttCallBlockSystem(2,inp,‘PI_Controller’);data.u=outp(1);exectime=outp(2);Case 2,ttAnalogOut(1,data.u);exectime= -1;%finishedend第11期何莹,等:矩阵实验室的仿真工具TrueTime设计武汉工程大学学报第36卷2初始化TrueTime TrueTime内核模块初始化有[2]:定义调度策略;指定输入和输出的个数;创建任务、事件、监测器等.这些都是由初始化脚本函数来完成的.它的内核模块带有一个参数,不论是在Matlab还是在C++里,此参数都是初始化脚本的文件名,例如下面例子中的参数就是:example_init.一个TT仿真在初始化时需要的最少代码如下所示,通过ttInitKernel函数定义输入、输出个数和调度政策;通过如下所示的函数创建一个周期任务,此任务调用比例控制Matlab代码实现程序中所给的Pcontroller函数. Function example_initTtInitKernel(2,1,‘PrioFP’);data.u=0;data.K=2;offset=0;period=0.005;prio=5;TtCreatePeriodicTask(‘ctrl’,offset,period,prio,‘Pcontroll’,data);初始化脚本的C++实现下面程序所示,文件ttkernel.cpp包含了用以实现TrueTime内核的仿真回调函数,这个初始化脚本实际上是一个完整的Matlab S-函数.变量filename是指源文件的名字,即如果源文件是example_init.cpp,那么就把S_FUNCTION_NAME定义为example_init.#define S_FUNCTION_NAME filename#include “ttkernel.cpp”//insert your code functions herevoid init() //perform the initialization }void cleanup() {//free dynamic memory allocated in this script} Init()函数完成所有的初始化工作,由它动态分配的内存都可以通过cleanup()函数收回[3].TT初始化脚本的Matlab实现的C++版本如下所示. #define S_FUNCTION_NAME example_init#include “ttkernel.cpp”#include“Pcontroller.cpp” //P-controller code functionclass Task_Data { public: double u; double K; };Task_Data*data;//pointer to local memory for the taskvoid init() { ttInitKernel(2,1,FP);data=new Task_Data; data->u=0.0; data->K=2.0; double offset=0.0; double period=0.005; double prio=5.0;ttCreatePeriodicTask("ctrl",offset,period,prio,Pcontroller,data); }void cleanup() { delete data; }3TrueTime的编译在Matlab中编译只要执行make_truetime.m就行了,这个脚本会编译TT的内核以及网络S-函数,还有MEX文件.对于C++就不同了,初始化脚本(比如example_init.cpp)需要先编译产生一个Matlab mex文件,一般采用下面这个命令:>>ttmex example_init.cpp 每次改变代码函数或者初始化脚本时,都需要重新编译一次.注意:ttmex命令与普通的mex命令具有相同的功能,只是前者会自动找到内核文件的路径.在Matlab情况下,即使对代码函数或者初始化脚本作了改动,但是仿真结果却没有任何变化,此时用下指令>>clean function 来迫使Matlab在仿真前重新加载所有的函数.4TrueTime中的网络设置TrueTime的网络模块模拟了在一个局域网中的介质访问和分组传输过程[4].当一个节点需要发送消息(使用ttSendMsg)时,一个触发信号会被送到相应的输入通道的网络模块中;当这个信息的仿真传输过程完成时,网络模块就会通过相应的输出通道发送一个新的触发信号到目的节点;最后这个被传输的信息放在了目的计算机的缓冲区里.此消息包含:用户数据(例如控制信号以及测量信号)、发送以及接收节点的信息、信息的长度、优先级以及最终期限.TrueTime支持6种网络:CSMA/CD(e.g.Ethernet)、CSMA/AMP(e.g.CAN)、Round Robin(e.g.令牌总线网)、FDMA、TDMA(e.g.TTP)和分组Ethernet.TT中忽略了传播时延,因为在LAN中这类时延很小.可以通过blockmask对话框来设置网络模块[5].以Ethernet为例来说明如何设置这个对话框.首先介绍一些涉及到的网络参数:Network number,表示网络模块的数量,有上限;Number of nodes,表示与网络连接的节点个数,这个数字将决定Snd、Rcv的大小以及输入、输出量的个数;Data rate(bits/s)表示网络速率;Minimum frame size(bytes),对于不同的协议,这个数值是不一样的,在Ethernet中是64 bytes,它包括14byte的头信息以及4byte的CRC;Preprocessing delay(s),是指数据在发送端由于网络接口而造成的延迟;Postprocessing delay(s):是指数据在接收端由于网络接口而造成的延迟;丢包率(0-1),是指数据在传输过程中可能丢失的概率,丢失的数据会占用网络带宽,但永远到不了目的节点.Ethernet采用的MAC机制是CSMA/CD,如果网络忙,发送端会等待一段时间间隔后重发.一旦出现数据发送冲突,发送端将会等待一段时间tbackoff,定义如下:tbakoff=frame sizemin/data rate×R,其中R=rand(0,2K-1),K是发生冲突的节点数.等待一段时间后,发送端会尝试复发.用一个例子说明如下,有两个节点正在等待第三个节点的传输结束,它们之间发生冲突的概率为1,1/2(K=1),1/4(K=2),….实现网络模块的S-函数在$DIR/truetime/kernel下面,这个文件只要编译一次就可以了,其编译指令为:>>mex ttnetwork.cpp.5TrueTime应用示例笔者主要给出2个应用示例[6],例1是对直流伺服电机(DCservo)实现简单的PID控制,例2则通过网络实现对直流伺服电机的控制.直流伺服电机的传递函数可以描述为:G(s)=1 000s(s+1),PID控制器的实现为:P(k)=K·(r(k)-y(k)),J(k+1)=I(k)+KhTd(r(k)-y(k)),D(k)=adD(k-1)+bd(y(k-1)-y(k)),u(k)=P(k)+I(k)+D(k),其中ad=TdNh+Td,ωc=20 rad/s.选择合适的控制器参数使闭环带宽为ωc=20 rad/s,衰减率为ξ=0.7.[例1] DCservo的实时控制通过这个例子,可以对TrueTime的仿真环境有个基本认识.这个过程的控制任务是在一个TT内核模块里实现的,既可以使用标准的PID实现方法,也可以调用Simulink模块框图来计算每个采样时刻的控制信号.下面仅给出几个主要的函数代码,其他代码从略.用Matlab代码实现控制器任务:function\[exectime,data\]=picode(seg,data)switch seg,case 1,r=ttAnalogIn(data.rChan);y=ttAnalogIn(data.yChan);data=pidcaIc(data,r,y);exectime=0.002;Case 2,ttAnalogOut(data.uChan,data.u);exectime= -1;end初始化脚本如下:Function singleservo_initttInitKernel(2,1,’prioFP’);%nbrOfInputus,nbrOfOutputs,FPdata.K=0.96; data.Ti=0.12; data.Td=0.049; data.N=10;data.h=0.006; data.u=0; data.Iold=0; data.Dold=0;data.yold=0; data.rChan=1;data.yChan=2; data.uChan=1;ttCreatePeriodicTask(’pid_task’,0.0,0.006,2,’pidcode’,data);通过仿真模型,可以很好地分析DCservo的PID控制效果.比如,通过改变第一段代码的执行时间来仿真不同输入-输出延时的效果;通过改变采样周期来研究采样周期对控制性能的影响.[例2]DCservo的网络控制在这个实验里,一共有4个计算机节点,每一个都代表一个TT内核模块,传感器采用时间驱动,采样周期设为h,通过网络将采样后的数据传输给控制节点,计算控制信号是控制器的任务,并将其传输给执行器节点,执行器采用事件驱动方式,所以一旦有控制信号到达,便立即响应.下面分别给出控制器、传感器和执行器的实现代码,其他代码从略.Matlab代码实现传感器:function\[exectime,data\]=sescode(seg,data)switch seg,case 1,data.y=ttAnalogIn(1);exectime=0.0005;case 2,ttSendMsg(4,data.y,10);%Send message to mode 4 (controller)exectime=0.0004;case 3,exectime= -1;%finishedendMatlab代码实现控制器:function\[exectime,data\]=ctrlcode(seg,data);switch seg,case 1,r=ttAnalogIn(1);%Read reference value;y=ttGetMsg;%Obtain sensor value;D=data.ad*data_Dold+data.bd*(data.yoldy);P=data.K*(r-y);data.u=P+D; data.yold=y; data.Dold=D; exectime=0.0005;case 2,ttSendMsg(2,data.u,10);%Send 10 bytes to node2 (actuator)exectime= -1; %finishedendMatlab代码实现执行器:function\[exectime,data\]=actcode(seg,data);switch seg,case 1,data.u=ttGetMsg; exectime=0.0005;case 2,ttAnalogOut(1,data.u); exectime=-1; %finishedend6结语应用TrueTime做网络控制体系的仿真能够较好的再现系统的特征,例如可以设置节点的驱动方式、采样周期,可以设定网络时延的特性,可以设置所采用的网络类型等等.因为TrueTime基于MatlabSimulink,所以控制算法的实现很方便,既可以使用标准的传递函数方法,也可以调用系统自带的内核模块框图.致谢感谢泰州学院提供的试验平台!