PsychtoolboxVersion Output:
‘3.0.18 – Flavor: Manual Install, 26-Oct-2021 18:56:38.
I am running this on Windows 10.
I am using Psychtoolbox for a method of constant stimuli task that involves displaying images. A floating adapter image is displayed first for 30 seconds, and then the participant goes through 90 trials. Each trial involves the following: a 2 second blank period showing a black screen and small fixation cross. Then an image (the fixation cross is constantly present) is shown for 0.2 seconds. Then the image disappears, the participant responds with a keypress, and finally, there is a 5 second adaptation period with the same floating adapter image each time. Once the 90th trial is finished, an exit screen is shown, and when the participant presses any key, the Psychtoolbox window closes.
Sometimes the experiment works fine, with all 90 trials completed with no issue. Sometimes, though, unpredictably, MATLAB or Psychtoolbox seems to freeze on one of the last trials. Sometimes it’s the 88th trial, sometimes the 89th, sometimes the 87th; there is no pattern I can discern. Anyway, what happens is that after the participant responds with a keypress, the floating adapter image never appears. The screen just remains black, with the fixation cross in the middle of the screen. The only way to exit that I’ve found is by hitting the “Window” key to bring up the Start Menu and then attempting to close the Psychtoolbox window from the Taskbar. MATLAB itself then quits and has to be restarted. Because of that, there’s no error message left behind.
This problem happens both on my laptop running Windows 10, and a desktop computer running Windows 10.
I saw a very similar issue on this forum that was solved by ensuring that each texture was cleared before a new one was created. I modified my code accordingly, and the experiment actually ran successfully three times in a row (this was remarkable), but then I tried running it a fourth time, and the experiment froze on the 87th trial.
Here is the main function that runs the experiment, along with a couple of smaller functions I wrote that may possibly be relevant.
function drawImage
arguments
image {mustBeNumeric};
location (1,4) double;
window(1,1) double;
end
Screen(‘Close’);
image_texture = Screen(‘MakeTexture’,window,image);
Screen(‘DrawTexture’,window,image_texture,[],location,0);
end
function drawFixationCross
arguments
window (1,1) double;
window_rect (1,4) double;
color double;
arm_length (1,1) double;
line_width (1,1) double;
end
[x_center,y_center] = RectCenter(window_rect);
x_coordinates = [-arm_length arm_length 0 0];
y_coordinates = [0 0 -arm_length arm_length];
coordinates = [x_coordinates;y_coordinates];
Screen(‘DrawLines’,window,coordinates,line_width,color,…
[x_center y_center],0);
end
function RunExperiment
arguments
participant (1,1) string;
object_number (1,1) double;
adapter_view (1,1) string;
end
%% Sync tests
%{
NOTE: The third argument of Screen(‘Preference’,‘SkipSyncTests’,[]) must
be either 0 or 1 (0 = don’t skip; 1 = skip).
If possible, this argument should be set to 0, since doing the sync tests
will ensure that stimulus presentation timing is super accurate and
precise.
However, sometimes sync tests fail on certain computers, and if they
fail, Psychtoolbox can’t run at all (the function will terminate
immediately and an error message titled “PTB - Error: Synchronization
Failure!” will be displayed). If this happens, and you’re in a situation
where extremely accurate and precise timing is not required (experimenting
with or revising the code, debugging, etc.), then the argument can be set
to 1.
%}
Screen(‘Preference’,‘SkipSyncTests’,0);
%% Load the experiment stimuli and other variables from file
load Variables.mat; %#ok
clear tutorial_text;
%% Extra input argument validation
if participant == “”
error(‘participant cannot be an empty string!’);
elseif object_number < 1 || object_number > length(objects) - 1
error(‘object_number must be a number from 1 to %d!’,…
length(objects) - 1);
elseif adapter_view == “”
error(‘adapter_view cannot be an empty string!’);
end
%% Set the raw data filename
timestamp = sprintf(’%04d-%02d-%02d_%02d-%02d-%02d’,round(clock));
raw_data_filename = sprintf(‘RAW_%s_obj-%d_%s_%s.mat’,…
participant,object_number,adapter_view,timestamp);
%% Get the object’s adapter images and test images
adapter_images = objects(object_number).adapters;
test_images = objects(object_number).test;
if isempty(adapter_images)
error(‘No adapter images found for this object!’);
elseif isempty(test_images)
error(‘No test images found for this object!’);
end
clear objects;
%% Get the size (in pixels) of the images
%{
NOTE: The size function’s output has the dimensions in the wrong order,
so the dimensions have to be switched around.
%}
image_size = size(adapter_images{1});
image_size = [image_size(2) image_size(1)];
%% Calculate the number of times each test image must be presented
max_image_presentations = trial_number / length(test_images);
%% Preallocate arrays to track test image presentations and hold data
tracker = zeros(1,length(test_images));
test_view_data = strings(1,trial_number);
response_data = zeros(1,trial_number);
reaction_time_data = zeros(1,trial_number);
%% Set up Psychtoolbox to display images and text
%{
NOTE: This also involves establishing the boundaries of the floating area
that the adapter and test images will be restricted to.
%}
PsychDefaultSetup(2);
screens = Screen(‘Screens’);
screen_number = min(screens);
black = BlackIndex(screen_number);
white = WhiteIndex(screen_number);
[window,window_rect] = PsychImaging(‘OpenWindow’,screen_number,black);
try
image_rect = [0 0 image_size(1) image_size(2)];
[x_range,y_range] = calculateLocationRange(window_rect,…
floating_area_size,image_size);
Screen(‘TextSize’,window,text_size);
Screen(‘TextFont’,window,‘Courier’);
HideCursor(window);
clear screens screen_number floating_area_size image_size text_size black;
%% Display the start screen
%{
NOTE: 65 and 186 are the key codes for the ‘a’ and ‘;’ keys. These key
codes must be modified if and when the input method is changed.
%}
DrawFormattedText(window,start_screen_text,‘center’,‘center’,white);
Screen(‘Flip’,window);
KbStrokeWait;
clear start_screen_text;
RestrictKeysForKbCheck([65 186]);
%% Initial adaptation period
adapter_index = strcmp(adapter_view,adapter_views);
adapter = adapter_images{adapter_index};
clear adapter_views adapter_images adapter_index;
[location,current_edge] = chooseRandomLocation(image_rect,x_range,y_range);
[target_edge,target_location] = chooseTargetEdge(location,x_range,…
y_range,current_edge);
drawImage(adapter,location,window);
drawFixationCross(window,window_rect,fixation_cross_color,arm_length,…
line_width);
Screen(‘Flip’,window);
seconds_passed = 0;
tic;
while seconds_passed < initial_adaptation_period
[location,arrived] = moveTowardLocation(location,target_location,1);
if arrived
[target_edge,target_location] = chooseTargetEdge(location,…
x_range,y_range,target_edge);
end
drawImage(adapter,location,window);
drawFixationCross(window,window_rect,fixation_cross_color,…
arm_length,line_width);
Screen(‘Flip’,window);
WaitSecs(time_to_travel_one_pixel);
seconds_passed = toc;
end
for i = 1:trial_number
%% Blank period
drawFixationCross(window,window_rect,fixation_cross_color,...
arm_length,line_width);
Screen('Flip',window);
WaitSecs(blank_period);
%% Test period
%{
NOTE: Keeping track of the image that was presented during the previous
trial (previous_test_index) is necessary to prevent the same image
being displayed twice in succession.
%}
image_chosen = false;
while image_chosen == false
test_index = randi(length(test_images));
if i == 1
image_chosen = true;
elseif test_index ~= previous_test_index &&...
tracker(test_index) < max_image_presentations
image_chosen = true;
end
end
previous_test_index = test_index;
tracker(test_index) = tracker(test_index) + 1;
test_view_data(i) = test_views(test_index);
current_test = test_images{test_index};
[location,~] = chooseRandomLocation(image_rect,x_range,y_range);
drawImage(current_test,location,window);
drawFixationCross(window,window_rect,fixation_cross_color,...
arm_length,line_width);
Screen('Flip',window);
WaitSecs(test_period);
%% Response period
%{
NOTE: I inserted a pause of 0.2 seconds because without it, the top_up
adaptation period would start the instant I made my response, and the
speed was actually a little unnerving.
%}
drawFixationCross(window,window_rect,fixation_cross_color,...
arm_length,line_width);
Screen('Flip',window);
response_made = false;
start_time = GetSecs;
while response_made == false
[key_is_pressed,~,key_code] = KbCheck;
if key_is_pressed
response_made = true;
end
end
end_time = GetSecs;
WaitSecs(0.2);
response_data(i) = find(key_code);
reaction_time_data(i) = end_time - start_time;
clc;
%% Save the raw data
saveData(raw_data_filename,participant,object_number,adapter_view,...
timestamp,test_view_data,response_data,reaction_time_data);
%% Top-up adaptation period
if i == trial_number
break;
else
[location,current_edge] = chooseRandomLocation(image_rect,...
x_range,y_range);
[target_edge,target_location] = chooseTargetEdge(location,...
x_range,y_range,current_edge);
drawImage(adapter,location,window);
drawFixationCross(window,window_rect,fixation_cross_color,...
arm_length,line_width);
Screen('Flip',window);
seconds_passed = 0;
tic;
while seconds_passed < top_up_adaptation_period
[location,arrived] = moveTowardLocation(location,...
target_location,1);
if arrived
[target_edge,target_location] = ...
chooseTargetEdge(location,x_range,y_range,target_edge);
end
drawImage(adapter,location,window);
drawFixationCross(window,window_rect,fixation_cross_color,...
arm_length,line_width);
Screen('Flip',window);
WaitSecs(time_to_travel_one_pixel);
seconds_passed = toc;
end
end
Screen('Close');
end
%% Display the exit screen
RestrictKeysForKbCheck([]);
DrawFormattedText(window,exit_screen_text,‘center’,‘center’,white);
Screen(‘Flip’,window);
KbStrokeWait;
Screen(‘Close’);
sca;
sca;
%% Save the raw data
saveData(raw_data_filename,participant,object_number,adapter_view,…
timestamp,test_view_data,response_data,reaction_time_data);
fprintf(‘Filename: %s\n’,raw_data_filename);
clear;
%% Handle errors
catch the_error
save([‘ERROR_’ raw_data_filename])
sca;
sca;
rethrow(the_error);
end
end