Prompt user input, time 4 seconds and prompt again - matlab

I have a matrix testNumbers = [1, 3, 8, 6, 9, 7].
What I want to do now is to make the user prompt a input and check if that input is equal to testNumbers(1), if it is do something (for later, %do something) and after 4 seconds continue to make the user input a number again but this time check if testNumbers(2) is equal to the user prompt. This will then continue until the length(testNumbers) has ended.
Can this be done? I assume a for loop has to be used, but I am totally new and therefore a example would be great. Then I can continue building this.
A example:
testNumbers = [1, 3, 8, 6, 9, 7]
A timer starts (4sec)
User inputs 1 within t <= 4 sec
Do something like disp('Correct')
User inputs 3 within t <= 4 sec
Do something like disp('Correct')
User should input 8 but time runs out
Do something like disp('time run out')
User inputs 5 within t <= 4 sec but is wrong, shall be 6
Do something like disp('Wrong')
Continue like this until the matrix ends...

You can use tic and toc to measure the elapsed time between two points. You can place the tic before the user input (to start the timer), and then use a toc wherever you want to check the time that has elapsed since that point. You can use multilple toc's and they will all refer to the closest tic.
% Start the timer
tic
% Prompt the user for input
value = input('Enter a number:');
elapsed_time = toc;
% If the response took more than 4 seconds
if elapsed_time > 4
disp('took too long')
end
If instead (as your title states) you want to wait 4 seconds, you can use pause to pause execution of your program for a given amount of time
input('Enter a number:');
pause(4) % Pause for 4 seconds
% Do something else

Related

MatLab Why won't my random walker break in a capture zone?

Hi I programmed a 1d random walker and I am trying to implement a capture zone, where the program will stop if the walker remains in a specific range of values for a certain amount of time. The code I have looks like this:
steps = 1000; %sets the number of steps to 1000
rw = cumsum(-1 + 2 * round(rand(steps,1)),1); %Set up our random walk with cumsum
%Now we will set up our capture zone between 13-18 for fun
if rw >= 13 & rw <= 18
dwc = dwc + 1 %Dwelling counted ticks up every time walker is in 13-18
else dwc = 0; %Once it leaves, it returns to 0
end
while dwc >= 5
fprintf('5 steps or more within range after %d steps, so so breaking out.\n', rw);
break
end
figure(7)
comet(rw); %This will plot our random walk
grid on; %Just to see the capture zone better
hold on;
line(xlim, [13, 13], 'Color', 'r');
line(xlim, [18, 18], 'Color', 'r');
hold off;
title('1d Random Walk with Capture Zone');
xlabel('Steps');
ylabel('Position');
It will run through the walk, but it will never break in the capture zone. I am sure it has been in the capture zone for longer than 5 steps on multiple occasions but it keeps running anyway. Any help is appreciated.
You code isn't doing what you think. There is no loop to step through to count steps & check for capture (... you don't need a loop for that anyway)
First this issue: rw is a 1000x1 array. So you if statement condition rw >= 13 & rw <= 18 will likewise return an 1000x1 logical. Which won't make a lot of since.
Second issue is you never modify the condition of the while inside the loop so it will either pass over it or get stuck in and endless loop.
while dwc >= 5
...
break
end
Edit linear version with now loops:
steps = 1000; %sets the number of steps to 1000
rw = cumsum(-1 + 2 * round(rand(steps,1)),1); %Set up our random walk with cumsum
%Now we will set up our capture zone between 13-18 for fun
captureCheck = rw >= 13 & rw <= 18;
%Counts the number of consecutive steps within the capture zone.
consecStepsInZone = diff([0 (find( ~(captureCheck(:).' > 0))) numel(captureCheck) + 1])- 1;
fprintf('The max number of consecutive steps in the zone is: %d\n',max(consecStepsInZone));

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.

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)

How to terminate a task based on time, regardless of trial number (Psychtoolbox)

I need to make a timer that starts counting at the beginning of a multi-phase delay task, and that ends the delay task after a certain period of time has passed, moving on to the next part of the experiment. For now, I'd like to end the task after 2 seconds have passed.
In the code below, I included an example that can be paste into an editor. I used a part of a Stroop task for this delay task that consists of one phase (in my actual code there are 3 phases, but I simplified the task for this question)-- press the 1 key for red, the 2 key for green, and the 3 key for blue. Each phase currently runs for six trials. (just one set of 6 trials for my one phase for now).
I'd like the task itself (all phases together) to last a period of time, and then terminate at the time I set regardless of the trial number. So if the 2 seconds have passed, the task should end even if we are only on phase 1, trial number 3 of 6.
The code below that is commented out (while loop with NumSecondsStart and NumSecondsEnd) is my current attempt. I'm not sure where such a loop would go (around the phase for loop, around the trial loop?) Thanks!
CODE:
clear all
close all
KbName('UnifyKeyNames');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%
[window, rect]=Screen('OpenWindow',0);
RED=KbName('1'); GREEN=KbName('2'); BLUE=KbName('3');
keysOfInterest=zeros(1,256);
keysOfInterest([RED, GREEN, BLUE])=1;
KbQueueCreate(-1, keysOfInterest);
KbQueueStart;
WORDCOLORS = {'red', 'green', 'blue'};
rgbColors = [1000 0 0; 0 1000 0; 0 0 1000];
starttime=Screen('Flip',window);
KbQueueFlush;
% NumSecondsStart = GetSecs;
% while (NumSecondsEnd-NumSecondsStart) == 1
for phase = 1
design=repmat([1 2 3], 2, 2)';
if phase == 1
designRand=design(randperm(length(design)),:);
Word=WORDCOLORS(designRand(1:6));
Color=rgbColors(designRand(:,2),:);
end
for trial=1:6
if phase == 1
DrawFormattedText(window, Word{trial}, 'center' ,'center', Color(trial,:));
WaitSecs(rand+.5)
starttime=Screen('Flip',window);
[pressed, firstPress]=KbQueueCheck;
endtime=KbQueueWait();
RTtext=sprintf('Response Time =%1.2f secs',endtime-starttime);
DrawFormattedText(window,RTtext,'center' ,'center',[255 0 255]);
vbl=Screen('Flip',window);
Screen('Flip',window,vbl+1);
NumSecondsEnd =GetSecs;
end
end
end
% break;
% end
ListenChar(0);
ShowCursor();
Screen('CloseAll');
I think tic and toc will be your friends here...
I would also not use while in favour of the following:
(Assuming an iteration which has started will be allowed to finish)
Add tic; where you want the timing to start, not inside the loop or else it will reset the timer each iteration.
Add the following within the for loop, either at the beginning or end
if toc >= 2
break
end
This will break out of the for loop the first time it reaches this and 2 seconds or more have passed

Accept only one keypress for a certain period of time in 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