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)
Related
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);
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.
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
I run a lot of long simulations in Matlab, typically taking from a couple of minutes to a couple of hours, so to speed things up I decided to run the simulations simultaneously using a parfor loop.
arglist = [arg1, arg2, arg3, arg4];
parfor ii = 1:size(arglist, 2)
myfun(arglist(ii));
end
Everything worked just fine, except for one thing: the progress printing. Since each simulation takes a lot of time, I usually print progress using something like
prevlength = 0;
for ii = 1:tot_iter
% Some calculations here
msg = sprintf('Working on %d of %d, %.2f percent done', ii, tot_iter, ii/tot_iter);
fprintf(repmat('\b', 1, prevlength))
fprintf(msg);
prevlength = numel(msg);
end
but, as could be expected, when doing this inside a parfor loop, you get chaos.
I have googled a lot in search of a solution and have found a bunch of "parfor progress printers" like this one. However, all of them print the progress of the entire parfor loop instead of showing how far each of the individual iterations have come. Since I only have about 4-8 iterations in the parfor loop, but each iteration takes about an hour, this approach isn't very helpful to me.
The ideal solution for me would be something that looks like this
Working on 127 of 10000, 1.27 percent done
Working on 259 of 10000, 2.59 percent done
Working on 3895 of 10000, 38.95 percent done
Working on 1347 of 10000, 13.47 percent done
that is, each simulation gets one line showing how far it has run. I'm not sure though if this is possible at all, I can at least not imagine any way to do this.
Another way would be to do something like this
Sim 1: 1.27% Sim 2: 2.59% Sim 3: 38.95% Sim 4: 13.47%
that is, show all the progresses on the same line. To do this, you would need to keep track of what position on the line each simulation is to write on and write there, without erasing the other progresses. I can't figure out how this would be done, is this possible to do?
If there is some other solution to my problem (showing the progress of each individual iteration) that I haven't thought of, I'd be happy to hear about it.
Since this is the first time I ask a question here on SO it is quite possible that there is something that I have missed; if so, please feel free to comment below.
Edit
After receiving this answer, I thought that I should share how I used it to solve my problem since I didn't use it exactly as in the answer, in case someone else encounters the same problem.
Here is a small test program with basically the same structure as my program, making use of the progress bar (parfor_progress) mentioned in the answer:
function parfor_progress_test()
cpus = feature('numCores');
matlabpool('open', cpus);
cleaner = onCleanup(#mycleaner);
args = [1000, 1000, 1000, 1000];
m = sum(args);
parfor_progress(m);
parfor ii = 1:size(args,2)
my_fun(args(ii));
end
parfor_progress(0);
end
function my_fun(N)
for ii = 1:N
pause(rand*0.01);
parfor_progress;
end
end
function mycleaner
matlabpool close;
fclose all;
end
Simple Progress Bar
Something like a progress bar could be done similar to this...
Before the parfor loop :
fprintf('Progress:\n');
fprintf(['\n' repmat('.',1,m) '\n\n']);
And during the loop:
fprintf('\b|\n');
Here we have m is the total number of iterations, the . shows the total number of iterations and | shows the number of iterations completed. The \n makes sure the characters are printed in the parfor loop.
Progress Bar and Percentage Completion
Otherwise you could try this: http://www.mathworks.com/matlabcentral/fileexchange/32101-progress-monitor--progress-bar--that-works-with-parfor
It will display a progress bar and percentage completion but can be easily modified to just include the percentage completion or progress bar.
This function amends a character to a file on every iteration and then reads the number of characters written to that file which indicates the number of iterations completed. This file accessing method is allowed in parfor's.
Assuming you correctly add the above to your MATLAB path somehow, you can then use the following:
arglist = [arg1, arg2, arg3, arg4];
parfor_progress(size(arglist, 2)); % Set the total number of iterations
parfor ii = 1:size(arglist, 2)
myfun(arglist(ii));
parfor_progress; % Increment the progress counter
end
parfor_progress(0); % Reset the progress counter
Time to Completion and Percentage Completion
There is also a function called showTimeToCompletion() which is available from: https://www.soundzones.com/software/sound-zone-tools/
and works alongside parfor_progress. This function allows you to print a detailed summary of the progress of a parfor loop (or any loop for that matter) which contains the start time, length of time running, estimated finish time and percentage completion. It makes smart use of the \b (backspace) character so that the command window isn't flooded with text. Although not strictly a progress 'bar' it is perhaps more informative.
The third example in the header of the function file,
fprintf('\t Completion: ');
showTimeToCompletion; startTime=tic;
len=1e2;
p = parfor_progress( len );
parfor i = 1:len
pause(1);
p = parfor_progress;
showTimeToCompletion( p/100, [], [], startTime );
end
outputs the following to the command window:
Completion: 31.00%
Remaining: 00:00:23
Total: 00:00:33
Expected Finish: 3:30:07PM 14-Nov-2017
Useful for estimating the completion of a running simulation, especially one that may take hours or days.
Starting in R2013b, you can use PARFEVAL to evaluate your function asynchronously and have the client display progress updates. (Obviously this approach is not quite as simple as adding stuff to your PARFOR loop). There's an example here.
The Diary property of the Future returned by PARFEVAL is updated continuously while processing, so that might also be useful if you have a small number of large tasks.
Starting in R2017a, you can use parallel.pool.DataQueue and afterEach to implement a waitbar for parfor, like so:
if isempty(gcp('nocreate'))
parpool('local', 3);
end
dq = parallel.pool.DataQueue;
N = 10;
wb = waitbar(0, 'Please wait...');
% Use the waitbar's UserData to track progress
wb.UserData = [0 N];
afterEach(dq, #(varargin) iIncrementWaitbar(wb));
afterEach(dq, #(idx) fprintf('Completed iteration: %d\n', idx));
parfor idx = 1:N
pause(rand());
send(dq, idx);
end
close(wb);
function iIncrementWaitbar(wb)
ud = wb.UserData;
ud(1) = ud(1) + 1;
waitbar(ud(1) / ud(2), wb);
wb.UserData = ud;
end
after exploring #Edric answer I found that there is an example in the Matlab documentation that exactly implements a waitbar for a pareval loop. Check help FetchNext
N = 100;
for idx = N:-1:1
% Compute the rank of N magic squares
F(idx) = parfeval(#rank, 1, magic(idx));
end
% Build a waitbar to track progress
h = waitbar(0, 'Waiting for FevalFutures to complete...');
results = zeros(1, N);
for idx = 1:N
[completedIdx, thisResult] = fetchNext(F);
% store the result
results(completedIdx) = thisResult;
% update waitbar
waitbar(idx/N, h, sprintf('Latest result: %d', thisResult));
end
% Clean up
delete(h)
I have a simple, sort of GUI code shown below.
This "test_keypress" function creates a figure, and it responses to the keypress (space).
Now, I want to add a constraint so that Matlab accepts only one keypress for a certain period of time (say, 1 second).
In other words, I want to reject a keypress if it happens within 1 sec after the previous keypress occurred.
How can I do that?
function test_keypress
f = figure;
set(f,'KeyPressFcn',#figInput);
imshow(ones(200,200,3));
end
function figInput(src,evnt)
if strcmp(evnt.Key,'space')
imshow(rand(200,200,3));
end
end
You can store the current time, and only evaluate the imshow command if the key-press occurs at least 100 seconds after the last one.
function test_keypress
f = figure;
set(f,'KeyPressFcn',#figInput);
imshow(ones(200,200,3));
%# initialize time to "now"
set(f,'userData',clock);
end
function figInput(src,evnt)
currentTime = clock;
%# get last time
lastTime = get(src,'UserData');
%# show new figure if the right key has been pressed and at least
%# 100 seconds have elapsed
if strcmp(evnt.Key,'space') && etime(lastTime,currentTime) > 100
imshow(rand(200,200,3));
%# also update time
set(src,'UserData',currentTime)
end
end