How to move to next iteration in for loop in Matlab - matlab

I get users to do the following to adjust the luminance of grey squares through Psychtoolbox (allowing both big and small changes and registering these values).
while exitDemo == false
[keyIsDown,secs, keyCode] = KbCheck;
if keyCode(escapeKey)
exitDemo = true;
elseif keyCode(more_lum_small)
rectColor = rectColor + smallcolorchange;
elseif keyCode(less_lum_small)
rectColor = rectColor - smallcolorchange;
elseif keyCode(more_lum_large)
rectColor = rectColor + bigcolorchange;
elseif keyCode(less_lum_large)
rectColor = rectColor - bigcolorchange;
end
if keyCode(more_lum_small)
colorcounter = colorcounter + 0.001;
elseif keyCode(less_lum_small)
colorcounter = colorcounter - 0.001;
elseif keyCode(less_lum_large)
colorcounter = colorcounter - 0.1;
elseif keyCode(more_lum_large)
colorcounter = colorcounter + 0.1;
end
centeredRect = CenterRectOnPointd(baseRect, squareX, squareY);
centeredRect2 = CenterRectOnPointd(baseRect2, square2X, square2Y);
banner_break = CenterRectOnPointd(banner, bannerX, bannerY);
% Draw the rect to the screen
Screen('FillRect', window, rectColor, centeredRect);
Screen('FillRect', window, rect2Color, centeredRect2);
Screen('FillRect', window, bannerColor, banner_break);
% Flip to the screen
vbl = Screen('Flip', window, vbl + (waitframes - 0.5) * ifi);
end
I now would like to put this in a for loop. Ideally, the user would move to the next iteration by pressing a key or the mouse button.
I am somehow stuck. Should I use a continue function?

If I understand you right, you want to run this type of test on your users multiple times in a for-loop. I don’t want to install Psychtoolbox just to answer one question so I thought I'll mock up my own example with 3 question quiz. You can stop said quiz by answering q (quit) to any of the questions. I presume that this would be your application.
%% Initialise questions and answers
prompts = {...
'What instrument did Sherlock Holmes play?';
'How do we get rid of the pigeons form the roof?';
'What did you bring me this time minion!?!'};
answers = {...
'trumpet';
'bazooka';
'window'};
no_responses = {...
'Hmm, interesting... "%s" you say...?\n';
'Madness! "%s" will never work!\n';
'Yes! Now that the "%s" is complete, people will tremble at my masters plan!\n'};
yes_responses = {...
'Splendid! That''s correct\n';
'Yes... This might work\n';
'Nooo...!!! The light! It burns!\n'};
completion_message = 'Level up!';
%% Ask questions
exitDemo = false;
for j = 1:numel(no_responses)
fprintf('--- Question %d ---\n',j);
response = no_responses{j};
prompt = sprintf('%s\n>',prompts{j});
% Loop while has not gotten a correct answer yet
gotCorrectAnswer = false;
while ~gotCorrectAnswer
answer = input(prompt,'s');
answer = lower(answer);
if strcmp(answer,'q') % Check for exit condition
exitDemo = true;
break
elseif strcmp(answer,answers{j}) % Check for the correct answer
fprintf(yes_responses{j});
gotCorrectAnswer = true;
else
fprintf(no_responses{j},answer);
end
end
% Check whether broke out of the for loop due to exit condition
if exitDemo
break
end
end
if ~exitDemo
fprintf(completion_message);
end
Note that you could achieve the same effect by pressing Ctrl+C on your keyboard while the code is executing. You can e.g. stop code like while true; pause(1); end with this. You don't need to program in any explicit stop conditions. Having said that, that is a bit of a hacky solution and it will abort every part of code which is running. The explicit exit condition allows you to handle exit a bit more gracefully (e.q. close up files, write to log, display a message etc.). Also; you should be aware that your users could possibly do that if they're malicious (unless Psychtoolbox protects against that which I doubt).

answer for keypress:
https://stackoverflow.com/a/9311250/5841680; based on input()
answer for mouseclick:
https://de.mathworks.com/help/matlab/ref/waitforbuttonpress.html; based on waitforbuttonpress
you don't need a for loop, works in a while loop all the same.
hope I did understand the question properly...

Related

How to make for loops run faster - Psychtoolbox in matlab

I created a MATLAB code using Psychtoolbox to make an experiment.
Everything works as I intended but it seems the initial loading of the experiment takes too long. The task is a simple yes/no response task whether the target word('probe') appeared in the previous set of word stimuli.
I put basic intro text as an image and then wait for any keypress to start the experiment but it will take about 40 seconds to actually begin the first trial after any keystroke. I want to make it work without any delay. It should start its first trial immediately after any keystroke.
I checked the timestops with GetSecs() on numerous positions in the code and it was not anything to do with loading stimuli or initial setting of the experiment before the for loop I attached below.
To make things look simpler, I changed some of the variables into actual numbers I used. I can gurantee that it is not due to large stimuli size since it is only 1500 words. Once the for loop starts, it goes smoothly but it takes 40 seconds to actually start the first trial so I think it is something to do with a specific function in the for loop or the way I built it.
Please let me know if anything is too vague or unclear. I will do my best to make things read better.
Edit: I minimalized the code leaving only the function names used in Psychtoolbox. I left the functions I used in between loops to let you know if they could cause any delay. It will not be possible to run this without Psychtoolbox installed so I guess you can briefly examine the structure of the code.
for trial = 1:250
for i = 1:6
DrawFormattedText();
Screen();
WaitSecs(0.5);
end
DrawFormattedText();
flipTime = Screen();
WaitSecs(0.5);
DrawFormattedText();
flipTime = Screen();
rt = 0;
resp = 0;
while GetSecs - flipTime < 3
clear keyCode;
RestrictKeysForKbCheck();
[keyIsDown,secs,keyCode] = KbCheck;
respTime = GetSecs;
pressedKeys = find(keyCode);
% ESC key quits the experiment
if keyCode(KbName('ESCAPE')) == 1
clear all
close all
sca
return
end
% Check for response keys
if ~isempty(pressedKeys)
for i = 1:2
if KbName(i) == pressedKeys(1)
resp = i;
rt = respTime - flipTime;
end
end
end
% Exit loop once a response is recorded
if rt > 0
break;
end
end
if rt == 0 || rt > 3 % 3 second limit for subjects to react to the probe stimuli
DrawFormattedText();
Screen();
WaitSecs(1);
end
Screen();
vbl = Screen();
WaitSecs(1);
% Record the trial data into output data matrix
respMat{1, trial} = trial;
respMat{2, trial} = resp;
respMat{3, trial} = rt;
end

Using KbCheck and GetSecs to record reaction time in a conflict task in MATLAB (Psychtoolbox)

I created a Stroop-like reaction time task in MATLAB and looking at pilot results suggests there might be something wrong with my code (the congruency effect is much bigger than expected). I suspect I may be recording RTs wrong, so could anyone help me out with whether the following setup is okay?
On any given trial, two events happen (following a fixation cross): first, the target stimulus is presented for a max of 3 seconds (or until response), then the participant has to press a button to start the next trial. RT for both buttonpresses (target and trial-start button) is recorded. Here's my code:
Screen('DrawTexture', mainwin, Target);
Screen('Flip', mainwin);
timeStart = GetSecs;keyIsDown=0; correct=0; rt=0;
while 1 & (GetSecs - timeStart) < 3
[keyIsDown, secs, keyCode] = KbCheck;
FlushEvents('keyDown');
if keyIsDown
nKeys = sum(keyCode);
if nKeys==1
if keyCode(Left)||keyCode(Right)||keyCode(Down)||keyCode(Up)
rt = 1000.*(GetSecs-timeStart);
keypressed=find(keyCode);
Screen('Flip', mainwin);
if ... [I removed some irrelevant ERROR feedback related code here]...
elseif keyCode(escKey)
ShowCursor; fclose(outfile); Screen('CloseAll'); return
end
keyIsDown=0; keyCode=0;
end
else
keypressed = 0; %the resp column in output is 0 if no button is pressed
end
end
if keypressed == 0 %indicates timeout errors
DrawFormattedText(mainwin, 'TOO SLOW', 'center', 'center', errorcol);
Screen('Flip', mainwin);
WaitSecs(1);
end
Screen('DrawTexture', mainwin, press5);
Screen('Flip', mainwin);
keyIsDown=0; timeSt = GetSecs;
while 1
[keyIsDown, secs, keyCode] = KbCheck;
if keyIsDown
if keyCode(MoveOn)
pause_rt = 1000.*(secs - timeSt);
break ;
elseif keyCode(escKey)
ShowCursor;
fclose(outfile);
Screen('CloseAll');
return;
end
end
end
My questions: the command GetSecs gets the time whenever it's called, right? So GetSecs - timeStart is an okay way of calculating RT - but so is secs - timeSt (as seen for the second stimulus), as secs is the time KbCheck returns for the buttonpress. The two methods are largely equivalent (with GetSecs - timeStart maybe slightly overestimating RT), is that correct?
My worry here is that RT estimates for the target on the NEXT trial might be influenced by the second button press RT of the PREVIOUS trial. Do you see any evidence of that?
You are correct that GetSecs returns the time whenever it is called. But, although not the cause of your error, calling GetSecs after each window Flip isn't necessary, because the Flip function returns the estimate of stimulus onset, as the second output of the function. So for example, instead of:
Screen('Flip', mainwin);
timeStart = GetSecs;
You can just use
[~, timeStart] = Screen('Flip', mainwin);
I don't notice anything obviously wrong in the code, when you say the RTs seem incorrect, do they seem too fast, or too slow? Personally I would use KbReleaseWait after collecting RT to wait until the Key has been released, but perhaps FlushEvents is doing a similar thing here.

KbCheck (?) unreliable in Psychtoolbox RT paradigm

I am trying to create a simple RT experiment in MATLAB R2014b, using Psychtoolbox. Participants will have to categorize faces, pressing one of two buttons as fast as they can. I created the paradigm on one computer, and it is working fine on that, but when I moved it to another (the one I want to be testing on), there was a weird error: even though the program seemed to be logging keypresses on the majority of trials, sometimes it wouldn't respond, and I had to press the key a number of times before it proceeded to the next trial. I am unsure what's going in, but I assume there could be something wrong with the computer itself (what might that be?), or with this particular bit of the code:
Screen('Flip', mainwin);
timeStart = GetSecs;keyIsDown=0; correct=0; rt=0;
while 1
bf = 0; %this variable is irrelevant here, I use it later to break
out of a loop
while (GetSecs - timeStart) < 0.2 %faces are presented briefly, but
%I'm recording responses here anyway, just in case there are some
%fast anticipatory responses - after this loop is over, I keep
%recording RT and button press the exact same way, but with no
%stimulus present
[keyIsDown, secs, keyCode] = KbCheck;
FlushEvents('keyDown');
if keyIsDown
nKeys = sum(keyCode);
if nKeys==1
if keyCode(Key1)||keyCode(Key2)
rt = 1000.*(GetSecs-timeStart);
keypressed=find(keyCode);
Screen('Flip', mainwin);
type = 'T';
bf = 1;
if keyCode(Key1) & targ_pic == 1
correct = 1;
elseif keyCode(Key2) & targ_pic == 0
correct = 1;
end
break;
elseif keyCode(escKey)
ShowCursor; fclose(outfile); Screen('CloseAll');
return
end
keyIsDown=0; keyCode=0;
end
else
keypressed = 0;
end
end
Can anyone maybe spot something that may be wrong with this?
Incidentally: is this the correct way to get RT out of PTB? I found that bit of code online, but I'm a little uncertain about why the "secs" variable is not used.
Both computers run Windows 10.
A few suggestions:
The Flip command will return the estimate of stimulus onset time, currently you are calling GetSecs after the Flip command, which is not necessary and will always return a value that is slightly later than the actual screen Flip. Likewise, you can use the time of key press returned by KbCheck, rather than calling GetSecs after identifying a key press.
I don't think you need the FlushEvents command, and it might be causing some timing variability.
It is also sometimes useful to pause for a short amount of time (for example 1 millisecond) between KbCheck events.
Below is a version of your code snippet with a few of these changes. It may also be more concise to have a single response checking loop, in which you Flip off the stimulus after 200 ms, rather than separate pre 200 ms and post 200 ms response checking loops, though I haven't made that change here.
keyIsDown=0; correct=0; rt=0;
[~, timeStart] = Screen('Flip', mainwin);
while 1
bf = 0; %this variable is irrelevant here, I use it later to break
%out of a loop
while (GetSecs - timeStart) < 0.2 %faces are presented briefly, but
%I'm recording responses here anyway, just in case there are some
%fast anticipatory responses - after this loop is over, I keep
%recording RT and button press the exact same way, but with no
%stimulus present
[keyIsDown, secs, keyCode] = KbCheck;
if keyIsDown
nKeys = sum(keyCode);
if nKeys==1
if keyCode(Key1)||keyCode(Key2)
rt = 1000.*(secs-timeStart);
keypressed=find(keyCode);
Screen('Flip', mainwin);
type = 'T';
bf = 1;
if keyCode(Key1) & targ_pic == 1
correct = 1;
elseif keyCode(Key2) & targ_pic == 0
correct = 1;
end
break;
elseif keyCode(escKey)
ShowCursor; fclose(outfile); Screen('CloseAll');
return
end
keyIsDown=0; keyCode=0;
end
else
keypressed = 0;
end
WaitSecs(.001);
end
end

Matlab assignin('base',...) Resets

I am attempting to write a function that, if called before any animation, will handle the close events without extra code in the animation file.
function matlabStopFunction(varargin)
persistent runs
if runs==2
runs = [];
end
if isempty(runs)
evalin('base','figure(''DeleteFcn'',#matlabStopFunction);');
runs = 1;
else
assignin('base','play',false);
pause(1);
runs = 2;
end
end
Here's a sample animation code that I've been using:
function sampleAnimation
matlabStopFunction;
r = 5;
th = 0;
play = true;
while play
x = r * cosd(th);
y = r * -sind(th);
plot(x,y,'r*');
axis([-10 10 -10 10]);
th = th + 45;
pause(0.25);
end
end
The stop function works fine creating the figure, and when I close the figure, it calls the same function as expected (including the assignin on line 10). However, when stepping through, when I first get back to the base function (sampleAnimation), play is false as would be expected:
But when I step one more line, play is reset to true
Am I incorrectly assigning the value of play to false in the stop function, and if so, how could I correct this so that the animation stops when the figure is closed while keeping the code inside the animation to a minimum? I am trying to replicate the method on this blog except with all the code contained in a separate file.
I am running Matlab 2014b on Windows 8.1.
To answer your question - you are modifying the value play in the base workspace - where as the loop is in the workspace of the sampleAnimation function -> so you are not changing the required value to stop the animation. To verify this clear your variables in the base workspace clear before you run your code and you will see that the variable play is created and set to false.
By the way there is a much simpler way to do this, you animation can create a figure and then you can stop when it is deleted:
function sampleAnimation
h = figure;
r = 5;
th = 0;
while ishandle ( h )
x = r * cosd(th);
y = r * -sind(th);
plot(x,y,'r*');
axis([-10 10 -10 10]);
th = th + 45;
pause(0.25);
end
end

Program an iteration which will be stopped when the mentioned circumstance is met

Hi everyone I have encountered a problem in writing a programming code for the algorithm as shown below
This program is going to be terminated when the approximate error which is defined as (current approximation-previous approximation)/current approximation is less than 0.01. It can be simplified as (f(xr)i+1 - f(xr)i)/f(xr)i+1. Below are the code that I have written and I would really like to know how can I program an iteration which will be stopped when the mentioned circumstance is met.
xl = input('Enter lower limit : ');
xu = input('Enter upper limit : ');
xr = (xl+xu)/2;
R = 3; V = 30;
fl = (pi*R*xl^2)-(pi*(xl^3)/3)-V; % between is there anyway can call these functions
fu = (pi*R*xu^2)-(pi*(xu^3)/3)-V; other than typing 3 times
fh = (pi*R*xr^2)-(pi*(xr^3)/3)-V;
while relative error is less than 0.01 then display value of xr
if fl*fu<0
xu = xr;
elseif fl*fu>0
xl = xr;
end
end
I updated the code now that I could run it. I tested it with f(x)=x^2-2. It converges to 1.4141 in 6 iterations. I suggest you compare that code with what you had to understand what was not working for you before. This will be a good learning experience.
>> example(1,2);
Crossing found after 6 iterations: 1.414062
where example.m is the following:
function xr = root(xl,xu)
MAX_NUMBER_ITERATIONS = 1000;
MAX_DELTA=.01;
numberIterations=0;
xr_old=xu;
xr = (xl+xu)/2;
while ((numberIterations<MAX_NUMBER_ITERATIONS) & (abs(xr_old-xr)>=MAX_DELTA))
numberIterations=numberIterations+1;
xr_old = xr;;
product=f(xl)*f(xr);
if product<0
xu = xr;
xr = (xl+xu)/2;
continue;
elseif product>0
xl = xr;
xr = (xl+xu)/2;
continue;
else
break;
end
end
fprintf('Crossing found after %d iterations: %f\n',numberIterations,xr)
end
function y = f(x)
y=x^2-2;
end
You forgot to implement Step 3(c).
You also didn't "return to step 2" in steps 3(a) and 3(b) as the instructions state. To do that, you will need to create a while loop as described here; put in your while loop the condition that will keep it looping. If that condition evaluates to false, it should drop out of the loop in accordance with step 3(c).
Use CONTINUE to fulfill the "Return to Step 2" part in steps 3(a) and 3(b); that moves execution back to the top of the loop. See also Jump command in MATLAB
Good luck.
you can put calculation in a function:
function f = some_function(x)
R = 3;
V = 30;
f = (pi*R*x^2)-(pi*(x^3)/3)-V;
You can try with 100 passes (for safety):
for i=1:100
xr_old = xr
fr_old = fr
xr = (xl+xu)/2;
fr = some_function(xr);
if abs((xr - xr_old)/xr) < MIN_STEP
break
end
temp = fl*fr
if temp < 0:
xu = xr
fu = fr
else if temp > 0:
xl = xr
fl = fr
end
end