个人使用MATLAB timer 心得

来源:互联网 发布:累计参与人数js效果 编辑:程序博客网 时间:2024/04/28 21:01

背景:

最近由于项目的需求,需要使用matlab实时处理数据,在网上查了一些资料,决定使用了matlab的timer,尽管matlab的帮助文档里明确写出尽量不要用timer处理实时性的任务,原文:The timer object is subject to the limitations of your hardware, operating system, and software. Avoid using timer objects for real-time applications.不过经过试验,感觉效果还不错,所以写下这篇心得以防自己忘记timer的用法。这是结合matlab帮助文 档和我自己的理解写的,具体以matlab帮助文档为准。


基本用法:

t = timer;
建立一个空的timer对象,名字是t,可以详见matlab的帮助文档,这里我只说我自认为比较普遍的用法。
建立了一个定时器后,接下来就要设置t的一些参数以及回调函数(callback)了。接下来介绍一下可设置的timer的参数,主要有:'BusyMode'、'ErrorFcn'、'ExecutionMode'、'Name'、'ObjectVisibility'、'Period'、'StartDelay'、'StartFcn'、'StopFcn'、'Tag'、'TimerFcn'、'TasksToExecute'、'UserData'。这里主要介绍几个有用的:'BusyMode'、'ExecutionMode'、'Period'、'StartDelay'、'StartFcn'、'StopFcn'、'TimerFcn'、'TasksToExecute'、'UserData'。先介绍没怎么用的以及为什么我没有用它。

'ErrorFcn':我理解的是程序在发生错误时执行的代码。应该是为了增加程序的鲁棒性而设置的,对
我本次的任务而言没什么用处,因此没有使用。
'Name'ObjectVisibility'':给新建的timer起一个名字,默认的是timer-1、timer-2……timer-n,起
名字太费脑子,没有用。
'ObjectVisibility':对我这个项目没用
'Tag':和name差不多,没什么用


接下来重点介绍用到的相关设置
'BusyMode':因为timer在执行时,会送入matlab的执行队列,这里是选择执行队列的操作。有三个
选择:drop、error和queue。默认的是drop,三者相同的是:当任务队列空时,将当前任务添加至任务队列,
不同的是:
drop:当发生冲突时丢掉当前的任务,好处是可以保证timerFcn的鲁棒性,坏处是可能会丢失数据。
error:当前的任务执行完后停止timer
queue:调整'Period'的值以适应当前的任务执行时间
说一说使用心得,在使用timerFcn时,最好使用matlab的tic toc测量一下tinerFcn的执行时间和Period
的关系,尽量让Period的时间大于timerFcn的执行时间,这样可以减少matlab执行队列发生冲突的几率。
关于timer队列的详细使用和安排,matlab有专门的帮助文档说明,我也会在下一部分说明。


'ExecutionMode':有四个选项可以选择:'singleShot'、'fixedRate'、'fixedDelay'、'fixedSpacing'
'singleShot':默认值。timer的回调函数只执行一次,如果选择这个选项,那么Period的值就没有意义
'fixedRate':timer开始后立即开始执行,具体执行次数,看'TasksToExecute'的值
'fixedDelay':延迟一段时间后执行
'fixedSpacing':当任务队列空时执行
这次项目使用的是fixedRate,一方面是复合要求,一方面是好整体把控timerFcn的时间,尽量避免任务
队列发生冲突


'Period':默认位1(秒)。指明程序执行/延迟时间,以秒为单位,如果设置为2,则指明timerFcn执行2秒
的时间,如果timerFcn执行时间少于2秒,那么会执行stopFcn。‘period’得配合ExecutionMode和
TasksToExecute使用。


'StartDelay':默认为0,不delay。以秒为单位,在timer执行时和第一次执行timerFcn回调函数时执行,
延迟一定时间。一开始不知道为什么要有这个“无用”的选项,timerFcn第一次执行时,任务队列不应该是空
的吗,为什么要延迟,后来我使用多个timer并存时,总是第一个timer得不到userdata,后面的都可以,设置了
这个值以后就可以了,其实也是起到任务队列调度的作用


'StartFcn'、'StopFcn'、'TimerFcn':timer的回调函数,也基本是timer你想干点儿啥的重要体现部分,
这里重点说一下参数调用的部分。如果你的timerFcn需要传入参数,那么使用一下形式:
t.TimerFcn = {@getRealTimeData,ch,Fs,Period};
其中ch、Fs、Period是我传入的参数,回调函数的形式是:
function myfunction(obj,event,arg1,arg2),具体详情可以见timer_callback
_function帮助文档


'TasksToExecute':默认的是inf,无限次,就是指定timerFcn执行次数


'UserData':用户数据的传出,我用它主要是用来获取数据用的,这个也很重要

说了这么多,看一个例子:
% 测试timerfunction tTimerFcn(t,ch,Fs,Period)% t是传入的timer对象t.StartDelay = Period;t.BusyMode = 'queue';t.ExecutionMode = 'fixedRate';t.Period = Period;% t.StartFcn = @(~,thisEvent)disp(['t ',thisEvent.Type ' executed '...%         datestr(thisEvent.Data.time,'dd-mmm-yyyy HH:MM:SS.FFF')]);  %显示开始时间t.TimerFcn = {@getRealTimeData,ch,Fs,Period};% t.StopFcn = @(~,thisEvent)disp(['t ',thisEvent.Type ' executed '...%         datestr(thisEvent.Data.time,'dd-mmm-yyyy HH:MM:SS.FFF')]);  %显示结束时间t.TasksToExecute = 1;start(t);end


大概的设置就这些,如果想使用userdata,那么在timerFcn里一定要加上一句代码:
function getRealTimeData(mTimer,~,ch,Fs,Period)大段代码……% tmp=get(mTimer);% set(mTimer,'UserData',[tmp.UserData;values.pvData]);set(mTimer,'UserData',values.pvData);end
注意我注释的两行和没有注释的一行的区别,注释掉的可以实现userdata的数据全部存储,而没有注释的只能获取当前的数据,在最开始创建timer出使用timer_Data = t.UserData;就可以使用userdata了。

最后记得要stop(t)和delete(t)。

2注意事项:

1、在使用timer时一定要注意Period和timerFcn执行时间的关系,如果period设置的太小,就会使得matlab
的任务队列产生冲突,那么会对后续的程序执行产生影响

2、多个timer之间的关系:matlab没有什么并行执行,多个timer之间是顺序执行,不过执行的顺序有所区别,测试如下:
% 测试timerclear all;clc;t = timer;t1 = timer;t2 = timer;t.StartFcn = @(~,thisEvent)disp(['t ',thisEvent.Type ' executed '...    datestr(thisEvent.Data.time,'dd-mmm-yyyy HH:MM:SS.FFF')]);t.TimerFcn = @(~,thisEvent)disp(['t ',thisEvent.Type ' executed '...    datestr(thisEvent.Data.time,'dd-mmm-yyyy HH:MM:SS.FFF')]);t.StopFcn = @(~,thisEvent)disp(['t ',thisEvent.Type ' executed '...    datestr(thisEvent.Data.time,'dd-mmm-yyyy HH:MM:SS.FFF')]);t.Period = 2;t.TasksToExecute = 3;t.ExecutionMode = 'fixedRate';start(t)t1.StartFcn = @(~,thisEvent)disp(['t1 ',thisEvent.Type ' executed '...    datestr(thisEvent.Data.time,'dd-mmm-yyyy HH:MM:SS.FFF')]);t1.TimerFcn = @(~,thisEvent)disp(['t1 ',thisEvent.Type ' executed '...    datestr(thisEvent.Data.time,'dd-mmm-yyyy HH:MM:SS.FFF')]);t1.StopFcn = @(~,thisEvent)disp(['t1 ',thisEvent.Type ' executed '...    datestr(thisEvent.Data.time,'dd-mmm-yyyy HH:MM:SS.FFF')]);t1.Period = 2;t1.TasksToExecute = 3;t1.ExecutionMode = 'fixedRate';start(t1)t2.StartFcn = @(~,thisEvent)disp(['t2 ',thisEvent.Type ' executed '...    datestr(thisEvent.Data.time,'dd-mmm-yyyy HH:MM:SS.FFF')]);t2.TimerFcn = @(~,thisEvent)disp(['t2 ',thisEvent.Type ' executed '...    datestr(thisEvent.Data.time,'dd-mmm-yyyy HH:MM:SS.FFF')]);t2.StopFcn = @(~,thisEvent)disp(['t2 ',thisEvent.Type ' executed '...    datestr(thisEvent.Data.time,'dd-mmm-yyyy HH:MM:SS.FFF')]);t2.Period = 2;t2.TasksToExecute = 3;t2.ExecutionMode = 'fixedRate';start(t2)

程序结果:


上面是运行程序的结果,可以看出三个timerFcn其实是顺序执行,因为程序简单,就一行代码,所以时间差
的不是很大,如果是比较复杂的程序,或者是对实时性要求比较高的,那么可以考虑适当的优化matlab代码
和算法以满足实时性的要求

3、最后想强调一点:matlab预分配数组的问题。
因为matlab的语法不像c语言那么严谨,这里我主要是指变量预定义的问题,有时候matlab可以直接使用
变量而不用再前面提前声明,如:a = 2*3;,或者a = []; a = [a [1 2 3] [2 3 4]];这种使用时matlab编译器会给出
一个警告,或者说连警告都算不上,只是提醒你a可能会随着程序的运行而增大,为了提高运行速率,a最好
提前预定义。之前我也没怎么注意这个事儿,知道这次用timer,把程序中的变量都规范预定义了之后,程序运行
速度调高了很多,大概能有10几秒吧,也可能是我编程太菜的原因