Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions ensemblesWrapper.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
function ensemblesWrapper(subjCode)

if nargin<1,
% Subject info
prompt={'Participant code:'};
def={'999'};
title='Input Participant Code';
lineNo=1;
userinput=inputdlg(prompt,title,lineNo,def);
subjCode=userinput{1};
end

assert(length(subjCode)==3,'subjCode must be 3 characters long.')
assert(ischar(subjCode),'Put that subjCode in single quotes!')

% focus to the command window
commandwindow;

% get into the correct folder
cd 'C:\Users\Seated4\Desktop\Matt Experiments\ensembles\tasks'

% make sure helper files are in the path
addpath(['..' filesep 'helpers' filesep]);

%% practice
% terminated by experimenter
pracCode = ['9' subjCode(2:3)];
runHet('m',pracCode);

%% experiment
% 408 equal count trials across 10 blocks
for i=1:10,
runHet('s',subjCode);

[keyIsDown,~,keyCode]=KbCheck;
if keyIsDown
if strcmpi(KbName(keyCode),'q'),
return;
end
end
end

% 408 unequal count trials across 10 blocks
for i=1:10,
runHet('d',subjCode);

[keyIsDown,~,keyCode]=KbCheck;
if keyIsDown
if strcmpi(KbName(keyCode),'q'),
return;
end
end
end

% 816 mixed trials across 20 blocks
for i=1:20,
runHet('m',subjCode);

[keyIsDown,~,keyCode]=KbCheck;
if keyIsDown
if strcmpi(KbName(keyCode),'q'),
return;
end
end
end

%% End of experiment notice
WhichScreen=max(Screen('Screens'));
shutdown.oldVDLevel = Screen('Preference', 'VisualDebugLevel', 2);
shutdown.oldVerbosity = Screen('Preference', 'Verbosity', 1);
shutdown.oldSkipSyncValue = Screen('Preference', 'SkipSyncTests', 1);
[w, ~] = Screen('OpenWindow',WhichScreen,[0 0 0]);
Screen('BlendFunction', w, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


instText = ['You have reached the end of this part of the experiment!\n\n',...
'Please tell the experimenter that you have finished'];
Screen('FillRect', w, [0 0 0]); % instruction screen background black
Screen('TextSize', w, 25);
DrawFormattedText(w, instText, 'Center', 'Center', [255 255 255]);
Screen('Flip', w); % display instructions

WaitSecs(2);
KbWait([],2);

ShutdownNicely(shutdown);
5 changes: 4 additions & 1 deletion helpers/DrawFixation.m
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@
rgb = [255 255 255]; % default to white cross
end

[~, windowHeight]=Screen('WindowSize', window);


%Screen('DrawLine', window, rgb, x - armLength, y, x + armLength, y);
Screen('DrawLine', window, rgb, x - armLength, y+armLength, x + armLength, y-armLength);
%Screen('DrawLine', window, rgb, x, y - armLength, x, y + armLength);
Screen('DrawLine', window, rgb, x-armLength, y - armLength, x+armLength, y + armLength);
Screen('DrawLine', window, rgb, x, 1, x, 800);
Screen('DrawLine', window, rgb, x, 1, x, windowHeight);
Empty file modified helpers/MakeTone.m
100644 → 100755
Empty file.
15 changes: 13 additions & 2 deletions helpers/PlaceHalfWindowsLR.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,16 @@
% See also: DrawMirrored, in the whac repository.

assert(nargin==4,'PlaceHalfWindowsLR: Need 4 arguments, got %d.\n',nargin)
Screen('DrawTexture',window,onehalf,[], [0 0 ScrRes(1)/2 ScrRes(2)], 0);
Screen('DrawTexture',window,otherhalf,[], [ScrRes(1)/2 0 ScrRes(1) ScrRes(2)], 0);

ScaleFactor = 0.93; % Stimuli generated assuming 48px/deg, actual setup is 44.65 px/deg
[stimWidth, stimHeight] = Screen('WindowSize',onehalf);
origHalfRect = [0 0 stimWidth stimHeight];
targetRect = round(origHalfRect .* ScaleFactor);
leftRect = CenterRect(targetRect, [0 0 ScrRes(1)/2 ScrRes(2)]);
rightRect = CenterRect(targetRect, [ScrRes(1)/2 0 ScrRes(1) ScrRes(2)]);

% Screen('Resolution',window)
% Screen('DrawTexture',window,onehalf,[], [0 0 ScrRes(1)/2 ScrRes(2)], 0);
% Screen('DrawTexture',window,otherhalf,[], [ScrRes(1)/2 0 ScrRes(1) ScrRes(2)], 0);
Screen('DrawTexture',window,onehalf,[], leftRect, 0);
Screen('DrawTexture',window,otherhalf,[], rightRect, 0);
Empty file modified helpers/ShutdownNicely.m
100644 → 100755
Empty file.
Empty file modified helpers/convert2VisAngle.m
100644 → 100755
Empty file.
18 changes: 7 additions & 11 deletions helpers/equneq_instructions.m
Original file line number Diff line number Diff line change
@@ -1,28 +1,24 @@
function equneq_instructions(w,keyl,keyr,BGCol,TxtCol)
function equneq_instructions(w,keyl,keyr)
% EQUNEQ_INSTRUCTIONS Display instructions for ensembles task
% equneq_instructions(w,keyl,keyr,BGCol,TxtCol)
% w (int): usable PsychToolbox window
% keyl, keyr (char): left/right key, eg 'h' and 'k'
% BGCol (int(3)): background color in [r g b] 0-255
% TxtCol: same idea, for text color

% blank screen
Screen('FillRect', w, BGCol);
Screen('FillRect', w, [0 0 0]);
Screen('Flip', w);

instText = ['Choose which side has LARGER mean size.\n\n' ...
sprintf('Press %s for left. Press %s for right.\n\n',keyl,keyr) ...
'Press h for left. Press k for right.\n\n' ...
'Look at the cross in the midddle.\n\n\n\n' ...
'If you respond correctly, you will hear a HIGH beep. \n\n'...
'If you respond incorrectly, you will hear a LOW beep. \n\n\n'...
'If you do not respond in time, you will hear DOUBLE LOW beeps.\n\n' ...
sprintf('If you press anything than %s or %s, you will hear DOUBLE LOW beeps.\n\n\n\n',keyl,keyr) ...
'If you press anything than h or k, you will hear DOUBLE LOW beeps.\n\n\n\n' ...
'Each block takes a few minutes, and contains about 40 trials.\n' ...
sprintf('To begin, press %s, and then press %s.',keyl,keyr) ];
'To begin, press h, and then press k.' ];

Screen('FillRect', w, BGCol); % instruction screen background
Screen('FillRect', w, [0 0 0]); % instruction screen background black
Screen('TextSize', w, 25);
DrawFormattedText(w, instText, 'Center', 'Center', TxtCol);
DrawFormattedText(w, instText, 'Center', 'Center', [255 255 255]);
Screen('Flip', w); % display instructions

nextKey = keyl; % first make them press left key
Expand Down
Empty file modified helpers/fixedPositions.m
100644 → 100755
Empty file.
Empty file modified helpers/generateSet.m
100644 → 100755
Empty file.
Empty file modified helpers/getPos.m
100644 → 100755
Empty file.
Empty file modified helpers/makeAll.m
100644 → 100755
Empty file.
Empty file modified helpers/makeDiff.m
100644 → 100755
Empty file.
Empty file modified helpers/makeEqual.m
100644 → 100755
Empty file.
Empty file modified helpers/makeMix.m
100644 → 100755
Empty file.
Empty file modified helpers/makeSame.m
100644 → 100755
Empty file.
Empty file modified helpers/makeStim.m
100644 → 100755
Empty file.
Empty file modified helpers/makeUnequal.m
100644 → 100755
Empty file.
Empty file modified helpers/mean2tot.m
100644 → 100755
Empty file.
Empty file modified helpers/pairSpacing.m
100644 → 100755
Empty file.
Empty file modified helpers/psyPoints.m
100644 → 100755
Empty file.
Empty file modified helpers/setSpacing.m
100644 → 100755
Empty file.
Empty file modified helpers/totOfSet.m
100644 → 100755
Empty file.
138 changes: 68 additions & 70 deletions tasks/runHet.m
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
function datafile = runHet(cond,subjCode)
% RUNHET Run heterogeneous ensembles experiment
% Initially released Spring 2015 // Comments to Sasen Cain sasen@ucsd.edu
% Updates & task variations at https://github.com/sasen/equneq/
% datafile = runHet(cond,subjCode)
% Spring 2015 // Comments to Sasen Cain sasen@ucsd.edu
% cond (char) : condition 's', 'd', 'm' for same, different, or mixed trials
% subjCode (char(3)) : 3-character code for the subject, in quotes. 'dbg'-> debug mode
% datafile (str) : full path to textfile containing subject's saved results for this block
% Experiment description
%% Experiment description
%
% Two ensembles of filled circles, to L and R of fixation.
% Two ensembles of filled circles, to L and R of fixation.
% Keypress 2-AFC on which side has greater mean diameter.
% Sets may have equal or unequal numbers of circles.
assert(nargin==2,'Two arguments, the condition code, and subject code, are required.')
Expand All @@ -17,7 +13,7 @@

stimfile = 'allStimuli123_6.mat';
load(stimfile)
if ~exist('trials')
if ~exist('trials','var')
switch cond
case 's'
trials = sTr;
Expand All @@ -40,12 +36,12 @@
subjFiles = what(pathdata);
fIndex = find(strncmp(cond,subjFiles.mat,1)); % find the index for this condition
else
fprintf(1,'Starting new subject. Stimulus file is: %s',stimfile)
sanityCheck = input('\n Are you happy with this? [y/n]:','s');
if strcmp(sanityCheck,'n')
disp('OK, maybe you should fix that.')
return
end
% fprintf(1,'Starting new subject. Stimulus file is: %s',stimfile)
% sanityCheck = input('\n Are you happy with this? [y/n]:','s');
% if strcmp(sanityCheck,'n')
% disp('OK, maybe you should fix that.')
% return
% end
mkdir(pathdata);
fIndex = [];
end
Expand Down Expand Up @@ -93,7 +89,6 @@
% Stimulus parameters %
%%%%%%%%%%%%%%%%%%%%%%%
black = [ 0 0 0];
gray = [128 128 128];
white = [255 255 255];
fixationLength = 10; % length of lines in fixation cross
tFixation = 0.500; % 500 ms fixation cross display
Expand All @@ -110,7 +105,7 @@
maxTrials = 42; % upto 42 trials per block!
numTrials = min([ (length(trials)-doneTrials), maxTrials]); % trials to do this time
if numTrials==0
fprintf(1,'\nDone with condition %s.\nPlease inform the experimenter.\n',cond)
fprintf(1,'\nDone with condition %s.\nPlease inform the experimenter.\n',cond) %#ok<PRTCAL>
return
end

Expand Down Expand Up @@ -147,13 +142,16 @@
[xCen, yCen] = RectCenter(winRect);

%% Open a half-size offscreen window for pre-drawing Left & Right stimuli
HalfScrRes = [ScrRes(1)/2 ScrRes(2)]; % half-screens split along horizontal side
woff1 = Screen('OpenOffScreenWindow',w,[BGCol 0], [0 0 HalfScrRes]);
woff2 = Screen('OpenOffScreenWindow',w,[BGCol 0], [0 0 HalfScrRes]);
% HalfScrRes = [ScrRes(1)/2 ScrRes(2)]; % half-screens split along horizontal side
% woff1 = Screen('OpenOffScreenWindow',w,[0 0 0 0], [0 0 HalfScrRes]);
% woff2 = Screen('OpenOffScreenWindow',w,[0 0 0 0], [0 0 HalfScrRes]);
originalHSR = [1280/2 800]; % Half of Sasen's original screen size
woff1 = Screen('OpenOffScreenWindow',w,[0 0 0 0], [0 0 originalHSR]);
woff2 = Screen('OpenOffScreenWindow',w,[0 0 0 0], [0 0 originalHSR]);

% Display reminder of instructions (need to have shown demo already)
% Make them press left key, then right key; that will call the KbCheck/KbName MEX files!
equneq_instructions(w, keymap.l, keymap.r, BGCol, TextColors{1});
equneq_instructions(w, keymap.l, keymap.r);



Expand All @@ -162,17 +160,17 @@
for i = doneTrials+1 : doneTrials+numTrials

% Draw fixation to indicate the start of the trial
Screen('FillRect', w, BGCol);
DrawFixation(w, fixationLength, xCen, yCen, TextColors{1});
Screen('FillRect', w, black);
DrawFixation(w, fixationLength, xCen, yCen);
[~, tFixOnset] = Screen('Flip', w,[], 1); % dontClear =1 %% Show fixation, mark its onset time

% Prepare stimuli on our offscreen half-windows
Screen('FillRect', woff1, BGCol);
Screen('FillRect', woff2, BGCol);
Screen('DrawDots',woff1,trials(i).Lcirs(:,1:2)',trials(i).Lcirs(:,3),TextColors{1},[],1); % 1=cir, 2=circ++
Screen('DrawDots',woff2,trials(i).Rcirs(:,1:2)',trials(i).Rcirs(:,3),TextColors{1},[],1);
Screen('FillRect', woff1, black);
Screen('FillRect', woff2, black);
Screen('DrawDots',woff1,trials(i).Lcirs(:,1:2)',trials(i).Lcirs(:,3),white,[],1); % 1=cir, 2=circ++
Screen('DrawDots',woff2,trials(i).Rcirs(:,1:2)',trials(i).Rcirs(:,3),white,[],1);
PlaceHalfWindowsLR(w,woff1,woff2,ScrRes); % Put the stimuli on the window
DrawFixation(w, fixationLength, xCen, yCen, TextColors{1}); % Add fixation cross last
DrawFixation(w, fixationLength, xCen, yCen); % Add fixation cross last
% Wait til the end of fixation period; then display stimuli. Mark stimulus onset time.
[~, tStimulusOnset] = Screen('Flip', w, tFixOnset+tFixation); %%%%%%%%% <========== show stimuli!

Expand All @@ -181,7 +179,7 @@
% imwrite(curImage,fname,'jpg');

%%% Stimulus offset: Blank screen until response
Screen('FillRect', w, BGCol);
Screen('FillRect', w, black);
[~, tStimulusOffset] = Screen('Flip', w, tStimulusOnset+tDisplay, 1); % dontClear =1

% Get 2AFC response keypress. Keep this clean to have tight confidence on RT
Expand Down Expand Up @@ -220,47 +218,47 @@
end % if keyisdown ITI

if ~postTrialStuffDoneYet
% 1. Give real-time feedback in the form of sounds, record accuracy data
if isnan(RTs(i)) % didn't respond in time [we're characterizing response]
PsychPortAudio('FillBuffer', audiohandle,toneToolate);
elseif strcmp( trials(i).trialRightAnswers, meanEqualCode ); % trial has no right/wrong ans
% the means are actually equal. flip a coin to call it right or wrong
% note: accuracy is a lie here, but it saves WHAT WE TOLD THE SUBJECT!!
% FIXME: ideally, this would be standard for all subjects!!
if round(rand) % coinflip = 1; call it right
PsychPortAudio('FillBuffer', audiohandle,toneCorrect);
ACCs(i) = 1;
else % call it wrong
PsychPortAudio('FillBuffer', audiohandle,toneIncorrect);
ACCs(i) = 0;
end % if coin flip
elseif strcmp(choices{i}, keymap.l) || strcmp(choices{i}, keymap.r) % hit a valid key
if strcmp(choices{i}, keymap.(trials(i).trialRightAnswers)) % response was right
PsychPortAudio('FillBuffer', audiohandle,toneCorrect);
ACCs(i) = 1;
else % response was the wrong side
PsychPortAudio('FillBuffer', audiohandle,toneIncorrect);
ACCs(i) = 0;
end %-- if response was right
else % hit an invalid key. Note: ACCs(i) should stay NaN as initialized
PsychPortAudio('FillBuffer', audiohandle,toneToolate); % FIXME: giving too-late feedback ok?
end %-- isnan (characterize response)
PsychPortAudio('Start',audiohandle); % play feedback (program keeps going, i think)

% 3. Record data for experimental parameters in .mat
expdata.trial(i) = i;
expdata.veridical(i) = trials(i).trialRightAnswers;
expdata.RTs(i) = RTs(i);
expdata.choices{i} = choices{i};
expdata.afcL(i) = afcL(i);
expdata.ACCs(i) = ACCs(i);
expdata.trialType(i) = trials(i).trialType;
expdata.Lmean(i) = trials(i).Lmean;
expdata.Rmean(i) = trials(i).Rmean;
save(datafile, 'expdata');

postTrialStuffDoneYet = 1; % all intertrial business is finished
end %% doing post-trial stuff
% 1. Give real-time feedback in the form of sounds, record accuracy data
if isnan(RTs(i)) % didn't respond in time [we're characterizing response]
PsychPortAudio('FillBuffer', audiohandle,toneToolate);
elseif strcmp( trials(i).trialRightAnswers, meanEqualCode ); % trial has no right/wrong ans
% the means are actually equal. flip a coin to call it right or wrong
% note: accuracy is a lie here, but it saves WHAT WE TOLD THE SUBJECT!!
% FIXME: ideally, this would be standard for all subjects!!
if round(rand) % coinflip = 1; call it right
PsychPortAudio('FillBuffer', audiohandle,toneCorrect);
ACCs(i) = 1;
else % call it wrong
PsychPortAudio('FillBuffer', audiohandle,toneIncorrect);
ACCs(i) = 0;
end % if coin flip
elseif strcmp(choices{i}, keymap.l) || strcmp(choices{i}, keymap.r) % hit a valid key
if strcmp(choices{i}, keymap.(trials(i).trialRightAnswers)) % response was right
PsychPortAudio('FillBuffer', audiohandle,toneCorrect);
ACCs(i) = 1;
else % response was the wrong side
PsychPortAudio('FillBuffer', audiohandle,toneIncorrect);
ACCs(i) = 0;
end %-- if response was right
else % hit an invalid key. Note: ACCs(i) should stay NaN as initialized
PsychPortAudio('FillBuffer', audiohandle,toneToolate); % FIXME: giving too-late feedback ok?
end %-- isnan (characterize response)
PsychPortAudio('Start',audiohandle); % play feedback (program keeps going, i think)
% 3. Record data for experimental parameters in .mat
expdata.trial(i) = i;
expdata.veridical(i) = trials(i).trialRightAnswers;
expdata.RTs(i) = RTs(i);
expdata.choices{i} = choices{i};
expdata.afcL(i) = afcL(i);
expdata.ACCs(i) = ACCs(i);
expdata.trialType(i) = trials(i).trialType;
expdata.Lmean(i) = trials(i).Lmean;
expdata.Rmean(i) = trials(i).Rmean;
save(datafile, 'expdata');
postTrialStuffDoneYet = 1; % all intertrial business is finished
end %% doing post-trial stuff

end %% waiting in ITI
end %% main trial loop
Expand All @@ -269,7 +267,7 @@
% Inform subjects that experiment is over, shutdown everything
endDisplay = ['The block is over.\n\n'...
'Please rest now, and restart when ready.'];
DrawFormattedText(w, endDisplay, 'center', 'center', TextColors{1});
DrawFormattedText(w, endDisplay, 'center', 'center', white);
Screen('Flip', w);
WaitSecs(2);
ShutdownNicely(shutdown); % Close the program
Expand Down