How to extract the elapsed time from a timer object in MATLAB? - matlab

Is there any way to extract the elapsed time from the beginning of each period from a timer object in MATLAB?
Say we have a timer object like this:
t=timer('ExecutionMode', 'fixedRate', ...
'Period', 15, ...
'TimerFcn',#(x,y)disp('Hello World!'))

The y contains the absolute timestamp. Store it when the timer is stated and take the difference:
function my_callback(m,x,y)
persistent starttime
switch m
case 'start'
starttime=y.Data.time;
case 'timer'
disp(datenum(y.Data.time-starttime)*24*60*60);
otherwise
error('unknown argument');
end
end
With a timer:
t=timer('ExecutionMode', 'fixedRate','Period', 15,'StartFcn',#(x,y)my_callback('start',x,y),'TimerFcn',#(x,y)my_callback('timer',x,y))
start(t)
Alternative solution using userdata:
t=timer('ExecutionMode', 'fixedRate','Period', 15,'StartFcn',#(x,y)set(x,'UserData',y.Data.time),'TimerFcn',#(x,y)disp(datenum(y.Data.time-get(x,'UserData'))*24*60*60))

Approach using tic, toc and 'UserData'
There is no direct method on the timer-object to read the elapsed time since its last call. It is possible to use a construct with tic and toc to achieve what you want.
The generic field 'UserData' can be used to add user-data to the timer object. We can write this value with set() and read it with get(). So we set this value with tic in the callback-function and get it back later to compute the time difference using toc.
More specifically, here is the callback-function:
function timerCallback(timerObj,event) %#ok<INUSD>
disp('Hello World!');
set(timerObj,'UserData',tic);
Now we can write a wrapper-function to get the elapsed time:
function retval = getElapsedTime(timerObj)
retval = toc(get(timerObj,'UserData'));
Example usage of proposed approach
To see if this approach works, we use pause to wait in a for loop and read the elapsed time approximately every second. Here is a complete example:
function timer_example
t = timer('ExecutionMode', 'fixedRate', ...
'Period', 5, ...
'TimerFcn', #timerCallback); % create timer
start(t); % start timer
pause on; % make sure pause can be used
for i = 1:10
pause(1); % wait a second
disp(getElapsedTime(t)); % display the elapsed time
end
stop(t); % stop timer
delete(t); % delete timer
function timerCallback(timerObj,event) %#ok<INUSD>
disp('Hello World!');
set(timerObj,'UserData',tic);
function retval = getElapsedTime(timerObj)
retval = toc(get(timerObj,'UserData'));
This gives the following output:
>> timer_example
Hello World!
1.0163
2.0173
3.0235
4.0285
Hello World!
0.0366
1.0390
2.0427
3.0461
4.0470
Hello World!
0.0515

Use tic as StartFcn of your timer and then use toc to elicit elapsed time, so:
timerObj = timer; %create timer object
timerObj.ExecutionMode = 'fixedSpacing';
timerObj.Period = 15;
timerObj.StartFcn = #(~,~)tic; % start ticking when timer starts
timerObj.TimerFcn = #myTimerFunc;
myTimerFunc is:
function [] = myTimerFunc(timerObj,event)
% use toc
disp(toc);
end

Related

How to know elapsed time during execution of system command in Matlab?

I have a Matlab code that runs a system script. The script may be stopped due to the command runs. I want to know if there is a way that the program knows if it has taken a long time and do something else. Here is the code:
tic;
[status,cmdout]=system(iperfcmd); % The program can be blocked here
toc; % I want to know if it has taken a long time (like 5 seconds) for the system call and kill it.
How about performing the system call asynchronously (https://uk.mathworks.com/help/parallel-computing/parallel.pool.parfeval.html) and polling from the main thread, something like this:
% Setup
tMax = 5; % Maximum time to wait for system call
pollDelay = 1; % Time between polls
timeOut = false;
% Run system call asynchronously
F = parfeval(#timeSystem,3,'iperfcmd');
tic
% Poll at regular intervals, break out if it finishes or exceeds time limit
while strcmp(F.State,'running') && ~timeOut
t = toc;
pause(pollDelay)
if t>tMax
timeOut = true; % This terminates the loop (alternatively use break)
end
end
if strcmp(F.State,'finished')
[status,cmdout,runTime]=fetchOutputs(F);
else
% Handle hanging system call here
cancel(F) % Cancelling the FutureEvent might terminate the system call?
end
function [status,cmdout,runTime] = timeSystem(command)
tStart = tic;
[status,cmdout] = system(command)
runTime = toc;
end
Hopefully that works for you. It's untested tested due to not having iperfcmd
Assign toc to a variable and then do logic on that value
tic
[status,cmdout]=system(iperfcmd);
elapsedTime = toc;
elapsedTime > 5

Edit the Timer Function once it has started

I'm trying to figure out how to have a timer add time once it has begun. The idea is if a person clicks certain buttons in a GUI the timer increases by a given amount of time that is determined by a different variable. When I couldn't figure that out, I decided to just make a second timer that starts on a button click but the second timer won't display even though the code is the exact same so now I'm really at a loss.
enter image description here
enter image description here
As far as I know, there's no way to adjust a running timer. I would recommend trying to use tic/toc. Put your time limit in some variable (tLimit), get the start time with tic, and then compute the elapsed time with toc and compare to tLimit.
tLimit = <some number>;
tStart = tic;
Then later in the code you check how much time has elapsed:
if toc(tStart) > tLimit
% done
end
If you need to add time:
tLimit = tLimit + tExtra
If you really want to run your check in a timer object, you could create a function which does the time comparison, and have your timer run that:
function timeCheck(timerObj,~)
global tStart
global tLimit
if toc(tStart) > tLimit
fprintf('Time''s up! %0.1f seconds elapsed\n', toc(tStart));
stop(timerObj);
end
end
Then:
global tStart
global tLimit
tLimit = <some number>;
t = timer;
t.TimerFcn = #timeCheck;
t.ExecutionMode = 'fixedRate';
tStart = tic;
start(t);

MATLAB tic/toc in called function

In MATLAB, I want to time a function written by someone else, and their function might use tic/toc internally. I want my own tic/toc. But if the inner function calls tic, then the outer timer gets reset.
How can I avoid this? I don't want to use timeit because timeit will call the inner function multiple times, which I don't want.
MWE:
Outer script:
tic
inner_function()
elapsed_time = toc;
fprintf('Function took %f seconds\n', elapsed_time)
Inner function:
function [] = inner_function()
pause(2)
tic
toc
end
Then:
>> outer_script
Elapsed time is 0.000024 seconds.
Function took 0.000232 seconds
If you comment out the tic/toc in inner_function() you get this, which is what I want:
>> outer_script
Function took 2.000362 seconds
Just for a little more context, the outer script is mine, and I use it to test functions written by my students. I want to allow them to use tic/toc however they want in their code, but I also want to be able to time their code independently.
You can do this by assigning your tic calls to a variable. Give your desired timer to toc later on as an argument.
function [] = inner_function()
pause(2)
tic
toc
end
Rerunning a modified example,
clock2 = tic;
inner_function()
elapsed_time = toc(clock2);
fprintf('Function took %f seconds\n', elapsed_time)
Elapsed time is 0.000009 seconds.
Function took 2.009997 seconds

Is there any alternative for pause function in MATLAB?

I want to pause a timer function (for like 5 seconds) in the middle of its execution in MATLAB GUI. Pause(5) can do it but the problem is that it pauses all other callback functions to execute (including other timer functions I am using in the MATLAB GUI, for example).
I was thinkink maybe I can write a dummy loop that could be executed for 5 sec but it might not be accurate and efficient. Do you have any suggestion?
Additional info:
handles.maintmr = timer(...
'ExecutionMode', 'fixedRate', ...
'TasksToExecute',1,'StartDelay',299, 'Period', 1,...
'TimerFcn', {#ttl_timer, hObject});
handles.et_tmr = timer(...
'ExecutionMode', 'fixedRate', ...
'Period', 0.5, ...
'TimerFcn', {#timer_ET_rec, hObject});
handles.tmr = timer(...
'ExecutionMode', 'fixedRate', ...
'Period', 9.85, ...
'TimerFcn', {#timer_update_display, hObject});
These are the defined three timer functions I am using in MATLAB GUI
And these are how I call the callback timer functions:
function timer_ET_rec(obj,event,hObject,eventdata)
handles = guidata(hObject);
function timer_update_display(obj,event,hObject,eventdata)
handles = guidata(hObject);
function ttl_timer(obj,event,hObject,eventdata)
handles= guidata(hObject);
I would try something like
t = tic();
while toc(t) < 5
pause(0.1);
drawnow('limitrate');
end
I like Edric's solution. Other options:
Option 1
The waitfor(obj) function (interrupts execution until object 'obj' is deleted).
eg.
%Pop-up msg;
h1 = errordlg({'This message interrupts the code. Close me to continue'},...
'Hi! I'm a pop-up')
% interrupt until closed
waitfor(h1)
Option 2
The timer() function doesn't run off the wallclock (ie. actual real world time) so I'm not sure it can do what you seem to what --- maintaining regular execution of code every x minutes regardless of interrupts and pauses in the code. But some methods can get close to it.
a) use the timer function to regularly TEST if you have passed a particular period according to wallclock time or not (if statement with clock()). If so, execute some other code.
b) Change the timer 'BusyMode' from the assumed default 'drop' to 'queue'and it will insert code to run as close as possible to the desired time.
Best solution will depend on what exactly you are trying to achieve.

Execute for loop with time

I have a for loop like this
for t = 0: 1: 60
// my code
end
I want to execute my code in 1st, 2nd, 3rd, ..., 60th seconds. How to do this? Also how can I run my code at arbitrary times? For example in 1st, 3rd and 10th seconds?
What you can do is use the pause command and place how many seconds you want your code to pause for. Once you do that, you execute the code that you want. As an example:
times = 1:60;
for t = [times(1), diff(times)]
pause(t); % // Pause for t seconds
%// Place your code here...
...
...
end
As noted by #CST-Link, we should not take elapsed time into account, which is why we take the difference in neighbouring times of when you want to start your loop so that we can start your code as quickly as we can.
Also, if you want arbitrary times, place all of your times in an array, then loop through the array.
times = [1 3 10];
for t = [times(1), diff(times)]
pause(t); %// Pause for t seconds
%// Place your code here...
...
...
end
Polling is bad, but Matlab is by default single-threaded, so...
For the first case:
tic;
for t = 1:60
while toc < t, pause(0.01); end;
% your code
end;
For the second case:
tic;
for t = [1,3,10]
while toc < t, pause(0.01); end;
% your code
end;
The pause calls were added following the judicious observation of Amro about busy waiting. 0.01 seconds sounds like a good trade between timing precision and "amount" of spinning...
while pause is most of the time good enough, if you want better accuracy use java.lang.Thread.sleep.
For example the code below will display the minutes and seconds of your computer clock, exactly on the second (the function clock is accurate to ~ 1 microsecond), you can add your code instead of the disp command, the java.lang.Thread.sleep is just to illustrate it's accuracy (see after the code for an explanation)
while true
c=clock;
if mod(c(6),1)<1e-6
disp([c(5) c(6)])
java.lang.Thread.sleep(100); % Note: sleep() accepts [mSecs] duration
end
end
To see the difference in accuracy you can replace the above with java.lang.Thread.sleep(999); vs pause(0.999) and see how you sometimes skip an iteration.
For more info see here.
EDIT:
you can use tic\ toc instead of clock, this is probably more accurate because they take less time...
You can use a timer object. Here's an example that prints the numbers from 1 to 10 with 1 second between consecutive numbers. The timer is started, and it stops itself when a predefined number of executions is reached:
n = 1;
timerFcn = 'disp(n), n=n+1; if n>10, stop(t), end'; %// timer's callback
t = timer('TimerFcn' ,timerFcn, 'period', 1, 'ExecutionMode', 'fixedRate');
start(t) %// start the timer. Note that it will stop itself (within the callback)
A better version, with thanks to #Amro: specify the number of executions directly as a timer's property. Don't forget to stop the timer when done. But don't stop it too soon or it will not get executed the expected number of times!
n = 1;
timerFcn = 'disp(n), n=n+1;'; %// this will be the timer's callback
t = timer('TimerFcn', timerFcn, 'period', 1, 'ExecutionMode', 'fixedRate', ...
'TasksToExecute', 10);
start(t) %// start the timer.
%// do stuff. *This should last long enough* to avoid stopping the timer too soon
stop(t)