Accept only one keypress for a certain period of time in Matlab - matlab

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

Related

How can I check mouse events as a background process in Matlab?

I am using Matlab to develop an application which performs several mathematical operations, whose parameters can be changed when the mouse is clicked, as in the example below.
while time<endtime
calculate_manythings;
if ~mod(time,checkmouse)
mouseinput_timeout(timemouse, gca);
change_calculation_parameters;
end
time=time+1;
end
At the moment, I am pausing the operations periodically to check for mouse events, but this is slow and unpractical. How can I monitor these continually and run the code at the same time? Could I make the mouse event checks a background process using parfeval, for example?
Many thanks,
Marta
you can use callback functions. here I used 'ButtonDownFcn':
timeinterval = 1; % seconds between mouse clicks
% generate axes with callback function
h = plot(rand(1,2),'LineWidth',6);
set(gca,'ButtonDownFcn',#callback);
% reset Tag and time
h.Tag = '';
tic;
while true
drawnow;
if strcmp(h.Tag,'Pressed') % if pressed
t = toc; % check time passed
if t >= timeinterval
% change parameters
disp('Pressed');
h.Color = rand(1,3);
% reset timer
tic;
end
% reset Tag
h.Tag = '';
end
end
and the callback function is:
function callback(src,~)
src.Children(1).Tag = 'Pressed';
end

Creating Continuous Output in Matlab

I have a script that is something like this:
i = 1;
while i <10000
a = input('enter a ');
c(i) = a;
i = i + 1;
end
I am trying to have 'a' be saved in 'c' about every second regardless of how long the user takes to input the value or anything else going on in the loop. So for example, lets say the user inputs 3 for 'a' waits 2 secs, then inputs 6 for 'a' then waits 3 secs then inputs 12 then nothing for a while, 'c' would look like this:
c = 3 3 6 6 6 12 12 12 12 12...
Right now, 'c' looks like this:
c = 3 6 12...
which is NOT what I want. Any suggestions? it doesn't have to be a second on the dot but i want continuous output.
Your question is interesting, but is not very well specified. I'm assuming the following:
Each input should be immediately appended to c, and repeatedly appended again every second until a new value is entered, which resets the time count. It's not clear from your question if you want that initial, fixed "commit" of the new input to c or not.
You want the updated c to be automatically displayed, according to your comment to a now deleted question. You should have stated that in your question to begin with.
Then, you can use a timer object that is stopped and restarted when each new input value has been entered. The timer is configured to wake up every second. When it wakes, it appends the latest input value a to vector c and displays it. Care should be taken to stop and delete the timer when no longer needed. In addition,
I'm considering empty input as an exit signal; that is, empty input indicates that the user wants to finish even if the iterations have not been exhausted. Using Ctrl-C to abort input is not viable, because the timer would keep running. I don't know anmy way to intercept Ctrl-C.
I'm removing the prompt string from the input function input as it interferes with the automatic display of the updated c vector.
User input blocks execution of the program. If you want other operations done with c as it's being updated by the timer, include them in its 'TimerFcn' function. Currently that function is just 'c = [c a]; disp(c)' (append the input and display it).
Code
c = []; % initiallize
t = timer('ExecutionMode', 'fixedRate', ... % Work periodically
'Period', 1, ... % Every 1 second...
'TimerFcn', 'c = [c a]; disp(c)', ... % ... append latest value to c
'ErrorFcn', 'delete(t)'); % If user ends with Ctrl-C, delete the timer
i = 1;
done = false;
clc % clear screen
while i < 10 & ~done
a = input(''); % Input new value. No prompt string
stop(t) % stop appending previous a
if isempty(a)
done = true; % no more iterations will not be run
else
start(t) % start timer: appends current a, and repeats every second
end
i = i + 1;
end
delete(t) % stop and delete timer
clear t % remove timer from workspace
Example
Here's a gif with an example run, where I'm inputting values 10, 20, 30, 40 with different pause times, and exiting with an empty input.

Matlab gui with pause function

I am using the GUIDE for matlab gui.
The gui built in order to communicate with keithley current measurement device through GPIB.
When using a toggle button for Current measurement while loop, i am using a pause() function inside the while loop for each iteration and a ytranspose on the y array reading results.
function Measure_Callback(hObject, eventdata, handles)
global GPIB1
global filename
global timeStep
disp('Measurement in progress \n stopwatch starts!');
tic
x=0;
n=0;
while get(hObject,'Value')
fprintf(GPIB1, 'printnumber(smua.measure.i(smua.nvbuffer1))');
fprintf(GPIB1, 'printbuffer(1,1,nvbuffer1)');
A = fscanf(GPIB1);
if length(A)<20
x = x+1;
n = n+1;
t(n) = toc ;
y(x) = str2double(A);
plot(t,y,'-bo',...
'LineWidth',2,...
'MarkerEdgeColor','k',...
'MarkerFaceColor',[.49 1 .63],...
'MarkerSize',10);
grid on
hold on
end
title('Current vs Time','FontSize', 15)
xlabel('Time [s]','FontSize', 15)
ylabel('Current [A]','FontSize', 15)
a = timeStep;
pause(a)
end
disp('Measurement terminated');
disp('Elapsed time: ');
elapsedtime = toc;
elapsedtime_string = num2str(elapsedtime);
disp(elapsedtime_string);
ytrans = transpose(y);
csvwrite(filename,ytrans);
fprintf(GPIB1, 'smua.source.output = smua.OUTPUT_OFF');
For the pause function i'm geting error:
?? Error using ==> pause Error while evaluating uicontrol Callback
For the transpose(y) function i'm also getting a error:
its undefined y.
Cant understand why are those errors and could use some help.
Thank you!
First off, as people say, post the errors and the code. Do you know if length(A) is smaller than 20 in the first time you run the loop? Because if not, A is not defined and you can't transpose something that is not there. Initialize A before the loop to something and see if the error persists (or print out length(A) to make sure the loop gets entered the first run).
As for the pause error, make sure pause is an int or double, not a string. If you get your global timeStep from the GUI field, it is probably a string and you need to covert it to double first.

MATLAB: How to run function until the key is released?

I have a GUI and I want to repeat some process from the time the given key is pressed until the key is released.
I know how to do some process once when the key is pressed. But is there any way how to for example display random number every second until the key is released?
Thank you for your answers.
Jaja
You can attach a timer to your figure, start it with the KeyPressFcn and stop it with the KeyReleaseFcn.
The example below will create a figure, and display a random number in the console as long as the key f is pressed.
function h=keypressdemo
h.fig = figure ;
%// set up the timer
h.t = timer ;
h.t.Period = 1 ;
h.t.ExecutionMode = 'fixedRate' ;
h.t.TimerFcn = #timer_calback ;
%// set up the Key functions
set( h.fig , 'keyPressFcn' , #keyPressFcn_calback ) ;
set( h.fig , 'keyReleaseFcn' , #keyReleaseFcn_calback ) ;
guidata( h.fig ,h)
function timer_calback(~,~)
disp( rand(1) )
function keyPressFcn_calback(hobj,evt)
if strcmp(evt.Key,'f')
h = guidata(hobj) ;
%// necessary to check if the timer is already running
%// otherwise the automatic key repetition tries to start
%// the timer multiple time, which produces an error
if strcmp(h.t.Running,'off')
start(h.t)
end
end
function keyReleaseFcn_calback(hobj,evt)
if strcmp(evt.Key,'f')
h = guidata(hobj) ;
stop(h.t)
end
This is a simple timer mode and the callback function take a lot less time than the interval so no problem to expect here. If you want whatever function to re-execute itself right after it's finished (kind of infinite loop), you can set that up by changing the executionmode of the timer (read the timer documentation for examples.
However, be aware that if your callback execute permanently and consume all the (matlab unique) thread ressource, your GUI might become less responsive.

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)