Skip to content

Commit 9606375

Browse files
committed
update to use textures for aperture and dots
also includes - some refactoring - specifying dot density in number per visual angle square and total number - using new CPP_PTB sub-functions
1 parent 52bc2d0 commit 9606375

File tree

4 files changed

+115
-129
lines changed

4 files changed

+115
-129
lines changed

initEnv.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686
function addDependencies()
8787

8888
pth = fileparts(mfilename('fullpath'));
89-
addpath(fullfile(pth, 'lib', 'CPP_BIDS'));
89+
addpath(fullfile(pth, 'lib', 'CPP_BIDS', 'src'));
9090
addpath(fullfile(pth, 'lib', 'CPP_PTB'));
9191
addpath(fullfile(pth, 'subfun'));
9292

setParameters.m

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
% Time between events in secs
4141
cfg.ISI = 0.1;
4242
% Number of seconds before the motion stimuli are presented
43-
cfg.onsetDelay = 5;
43+
cfg.onsetDelay = 1;
4444
% Number of seconds after the end all the stimuli before ending the run
4545
cfg.endDelay = 1;
4646

@@ -51,20 +51,21 @@
5151
cfg.eventDuration = 1; % second
5252

5353
% speed in visual angles
54-
cfg.dot.speed = 8;
54+
cfg.dot.speed = 1;
5555
% Coherence Level (0-1)
56-
cfg.dot.coh = 1;
57-
% Maximum number dots per frame
58-
cfg.dot.maxNbPerFrame = 300;
56+
cfg.dot.coh = .7;
57+
% nb dots per visual angle square.
58+
cfg.dot.density = 5;
59+
5960
% Dot life time in seconds
6061
cfg.dot.lifeTime = 1;
6162
% Dot Size (dot width) in visual angles.
6263
cfg.dot.size = 0.1;
6364
cfg.dot.color = cfg.color.white;
64-
cfg.dot.dontClear = 0;
6565

6666
% Diameter/length of side of aperture in Visual angles
67-
cfg.diameterAperture = 8;
67+
cfg.aperture.type = 'circle';
68+
cfg.aperture.width = []; % if left empty it will take the screen height
6869

6970
%% Task(s)
7071

@@ -74,14 +75,11 @@
7475
cfg.task.instruction = '1-Detect the RED fixation cross\n \n\n';
7576

7677
% Fixation cross (in pixels)
77-
% Set the length of the lines of the fixation cross
78-
cfg.fixation.dimensionPix = 10;
79-
% Set the line width for our fixation cross
80-
cfg.fixation.lineWidthPix = 4;
81-
cfg.fixation.xDisplacement = 0; % Manual displacement of the fixation cross
82-
cfg.fixation.yDisplacement = 0; % Manual displacement of the fixation cross
83-
cfg.fixation.color = cfg.color.white;
78+
cfg.fixation.type = 'cross';
8479
cfg.fixation.colorTarget = cfg.color.red;
80+
cfg.fixation.color = cfg.color.white;
81+
cfg.fixation.width = .15;
82+
cfg.fixation.lineWidthPix = 2;
8583

8684
cfg.target.maxNbPerBlock = 2;
8785
cfg.target.duration = 0.15; % In secs

subfun/doDotMo.m

Lines changed: 84 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -16,146 +16,143 @@
1616
% dots outside of the aperture is turned into a NaN so effectively the
1717
% actual number of dots on the screen at any given time is not the one that you input but a
1818
% smaller number (nDots / Area of aperture) on average.
19-
19+
2020
%% Get parameters
21-
dontClear = cfg.dot.dontClear;
22-
2321
direction = thisEvent.direction(1);
2422
isTarget = thisEvent.target(1);
25-
speed = thisEvent.speed(1);
26-
27-
coh = cfg.dot.coh;
28-
ndots = cfg.dot.maxNbPerFrame;
29-
dotSizePix = cfg.dot.sizePix;
23+
24+
3025
dotLifeTime = cfg.dot.lifeTime;
31-
dotColor = cfg.dot.color;
32-
26+
3327
targetDuration = cfg.target.duration;
34-
28+
3529
% thisEvent = deg2Pix('speed', thisEvent, cfg);
3630
% dotSpeedPix = logFile.iEventSpeedPix;
37-
38-
diamAperturePix = cfg.diameterAperturePix;
39-
diamAperture = cfg.diameterAperture;
40-
31+
32+
coh = cfg.dot.coh;
33+
speed = thisEvent.speed(1);
4134
% Check if it is a static or motion block
4235
if direction == -1
43-
44-
% dotSpeedPix = 0;
45-
36+
4637
speed = 0;
47-
38+
coh = 1;
39+
4840
dotLifeTime = cfg.eventDuration;
4941
end
50-
42+
5143
%% initialize variables
52-
44+
5345
% Set an array of dot positions [xposition, yposition]
5446
% These can never be bigger than 1 or lower than 0
55-
% [0,0] is the top / left of the square that contains the square aperture
56-
% [1,1] is the bottom / right of the square that contains the square aperture
57-
xy = rand(ndots, 2);
58-
47+
% [0,0] is the top / left of the square
48+
% [1,1] is the bottom / right of the square
49+
dotPositions = rand(cfg.dot.number, 2);
50+
5951
% Set a N x 2 matrix that gives jump size in pixels
6052
% pix/sec * sec/frame = pix / frame
6153
dxdy = repmat( ...
62-
speed * 10 / (diamAperture * 10) * (3 / cfg.screen.monitorRefresh) * ...
63-
[cos(pi * direction / 180.0) -sin(pi * direction / 180.0)], ndots, 1);
64-
54+
speed * 10 / (cfg.aperture.width * 10) * (3 / cfg.screen.monitorRefresh) * ...
55+
[cos(pi * direction / 180.0) -sin(pi * direction / 180.0)], cfg.dot.number, 1);
56+
6557
% dxdy = repmat(...
6658
% dotSpeedPix / Cfg.ifi ...
6759
% * (cos(pi*direction/180) - sin(pi*direction/180)), ...
6860
% ndots, 1);
69-
61+
7062
% Create a ones vector to update to dotlife time of each dot
71-
dotTime = ones(size(xy, 1), 1);
72-
73-
% Set for how many frames to show the dots
74-
continueShow = floor(cfg.eventDuration / cfg.screen.ifi);
75-
63+
dotTime = ones(size(dotPositions, 1), 1);
64+
7665
% Covert the dotLifeTime from seconds to frames
7766
dotLifeTime = ceil(dotLifeTime / cfg.screen.ifi);
67+
68+
% Set for how many frames this event will last
69+
framesLeft = floor(cfg.eventDuration / cfg.screen.ifi);
7870

7971
%% Start the dots presentation
80-
vbl = Screen('Flip', cfg.screen.win, 0, dontClear);
72+
vbl = Screen('Flip', cfg.screen.win);
8173
onset = vbl;
82-
83-
while continueShow
84-
74+
75+
while framesLeft
76+
8577
% L are the dots that will be moved
86-
L = rand(ndots, 1) < coh;
87-
78+
L = rand(cfg.dot.number, 1) < coh;
79+
8880
% Move the selected dots
89-
xy(L, :) = xy(L, :) + dxdy(L, :);
90-
81+
dotPositions(L, :) = dotPositions(L, :) + dxdy(L, :);
82+
9183
% If not 100% coherence, we get new random locations for the other dots
9284
if sum(~L) > 0
93-
xy(~L, :) = rand(sum(~L), 2);
85+
dotPositions(~L, :) = rand(sum(~L), 2);
9486
end
95-
87+
9688
% Create a logical vector to detect any dot that has:
9789
% - an xy position inferior to 0
9890
% - an xy position superior to 1
9991
% - has exceeded its liftime
100-
N = any([xy > 1, xy < 0, dotTime > dotLifeTime], 2) ;
101-
92+
N = any([dotPositions > 1, dotPositions < 0, dotTime > dotLifeTime], 2) ;
93+
10294
% If there is any such dot we relocate it to a new random position
10395
% and change its lifetime to 1
10496
if any(N)
105-
xy(N, :) = rand(sum(N), 2);
97+
dotPositions(N, :) = rand(sum(N), 2);
10698
dotTime(N, 1) = 1;
10799
end
108-
109-
% Convert the dot position to pixels
110-
xy_pix = floor(xy * diamAperturePix);
111-
100+
101+
%% Convert the dot position to pixels
102+
% We expand that square so that its side is equal to the whole
103+
% screen width.
104+
% With no aperture the whole screen is filled with dots.
105+
dotPositionsPix = floor(dotPositions * cfg.screen.winRect(3));
106+
112107
% This assumes that zero is at the top left, but we want it to be
113108
% in the center, so shift the dots up and left, which just means
114109
% adding half of the aperture size to both the x and y direction.
115-
xy_pix = (xy_pix - diamAperturePix / 2)';
116-
117-
% NaN out-of-circle dots
118-
% We use Pythagore's theorem to figure out which dots are out of the
119-
% circle
120-
outCircle = sqrt(xy_pix(1, :).^2 + xy_pix(2, :).^2) + ...
121-
dotSizePix / 2 > (diamAperturePix / 2);
122-
xy_pix(:, outCircle) = NaN;
123-
124-
%% PTB draws the dots stimulation
125-
126-
% Draw the fixation cross
127-
color = cfg.fixation.color;
110+
dotPositionsPix = (dotPositionsPix - cfg.screen.winRect(3) / 2)';
111+
112+
thisEvent.dot.positions = dotPositionsPix;
113+
114+
%% make textures
115+
dotTexture('make', cfg, thisEvent);
116+
117+
apertureTexture('make', cfg, thisEvent);
118+
119+
%% draw evetything and flip screen
120+
121+
dotTexture('draw', cfg, thisEvent);
122+
123+
apertureTexture('draw', cfg, thisEvent);
124+
128125
% If this frame shows a target we change the color
126+
thisFixation.fixation = cfg.fixation;
127+
thisFixation.screen = cfg.screen;
129128
if GetSecs < (onset + targetDuration) && isTarget == 1
130-
color = cfg.fixation.colorTarget;
129+
thisFixation.fixation.color = cfg.fixation.colorTarget;
131130
end
132-
drawFixationCross(cfg, color);
133-
134-
% Draw the dots
135-
Screen('DrawDots', cfg.screen.win, xy_pix, dotSizePix, dotColor, cfg.screen.center, 2);
136-
137-
Screen('DrawingFinished', cfg.screen.win, dontClear);
138-
139-
vbl = Screen('Flip', cfg.screen.win, vbl + cfg.screen.ifi, dontClear);
140-
131+
drawFixation(thisFixation);
132+
133+
Screen('DrawingFinished', cfg.screen.win);
134+
135+
vbl = Screen('Flip', cfg.screen.win, vbl + cfg.screen.ifi);
136+
141137
%% Update counters
142-
138+
143139
% Check for end of loop
144-
continueShow = continueShow - 1;
145-
140+
framesLeft = framesLeft - 1;
141+
146142
% Add one frame to the dot lifetime to each dot
147143
dotTime = dotTime + 1;
148-
144+
149145
end
150-
146+
151147
%% Erase last dots
152-
153-
drawFixationCross(cfg, cfg.fixation.color);
154-
155-
Screen('DrawingFinished', cfg.screen.win, dontClear);
156-
157-
vbl = Screen('Flip', cfg.screen.win, vbl + cfg.screen.ifi, dontClear);
158-
148+
149+
drawFixation(cfg);
150+
151+
Screen('DrawingFinished', cfg.screen.win);
152+
153+
vbl = Screen('Flip', cfg.screen.win, vbl + cfg.screen.ifi);
154+
159155
duration = vbl - onset;
160-
156+
161157
end
158+

visualLocTanslational.m

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,6 @@
2525
cfg = userInputs(cfg);
2626
cfg = createFilename(cfg);
2727

28-
disp(cfg);
29-
30-
% REFACTOR
31-
% Prepare for fixation Cross
32-
cfg.xCoords = [-cfg.fixation.dimensionPix cfg.fixation.dimensionPix 0 0] + ...
33-
cfg.fixation.xDisplacement;
34-
cfg.yCoords = [0 0 -cfg.fixation.dimensionPix cfg.fixation.dimensionPix] + ...
35-
cfg.fixation.yDisplacement;
36-
cfg.allCoords = [cfg.xCoords; cfg.yCoords];
37-
3828
%% Experiment
3929

4030
% Safety loop: close the screen if code crashes
@@ -44,8 +34,11 @@
4434
[cfg] = initPTB(cfg);
4535

4636
% Convert some values from degrees to pixels
47-
cfg = degToPix('diameterAperture', cfg, cfg);
4837
cfg.dot = degToPix('size', cfg.dot, cfg);
38+
39+
% dots are displayed on a square with a length in visual angle equal to the
40+
% field of view
41+
cfg.dot.number = cfg.dot.density * cfg.screen.FOV^2;
4942

5043
[el] = eyeTracker('Calibration', cfg);
5144

@@ -56,28 +49,24 @@
5649
% Prepare for the output logfiles with all
5750
logFile.extraColumns = cfg.extraColumns;
5851
logFile = saveEventsFile('open', cfg, logFile);
59-
60-
% Wait for space key to be pressed
61-
pressSpaceForMe();
62-
52+
53+
% prepare textures
54+
cfg = apertureTexture('init', cfg);
55+
cfg = dotTexture('init', cfg);
56+
57+
disp(cfg);
58+
59+
standByScreen(cfg);
60+
6361
% prepare the KbQueue to collect responses
6462
getResponse('init', cfg.keyboard.responseBox, cfg);
6563
getResponse('start', cfg.keyboard.responseBox);
6664

67-
% Show instructions
68-
DrawFormattedText(cfg.screen.win, cfg.task.instruction, ...
69-
'center', 'center', cfg.text.color);
70-
Screen('Flip', cfg.screen.win);
71-
7265
% Wait for Trigger from Scanner
7366
waitForTrigger(cfg);
7467

75-
% Show the fixation cross
76-
drawFixationCross(cfg, cfg.fixation.color);
77-
Screen('Flip', cfg.screen.win);
78-
7968
%% Experiment Start
80-
cfg.experimentStart = GetSecs;
69+
cfg = getExperimentStart(cfg);
8170

8271
WaitSecs(cfg.onsetDelay);
8372

@@ -152,14 +141,14 @@
152141
% End of the run for the BOLD to go down
153142
WaitSecs(cfg.endDelay);
154143

144+
cfg = getExperimentEnd(cfg);
145+
155146
% Close the logfiles
156147
saveEventsFile('close', cfg, logFile);
157148

158149
getResponse('stop', cfg.keyboard.responseBox);
159150
getResponse('release', cfg.keyboard.responseBox);
160151

161-
totalExperimentTime = GetSecs - cfg.experimentStart;
162-
163152
eyeTracker('Shutdown', cfg);
164153

165154
% save the whole workspace
@@ -171,6 +160,8 @@
171160
else
172161
save(matFile, '-v7.3');
173162
end
163+
164+
farewellScreen(cfg);
174165

175166
cleanUp();
176167

0 commit comments

Comments
 (0)