|
1 | 1 | function [cfg] = expDesign(cfg, displayFigs) |
2 | 2 | % Creates the sequence of blocks and the events in them |
3 | 3 | % |
4 | | - % The conditions are consecutive static and motion blocks (Gives better results than randomised). |
| 4 | + % The conditions are consecutive static and motion blocks |
| 5 | + % (Gives better results than randomised). |
5 | 6 | % |
6 | 7 | % EVENTS |
7 | 8 | % The numEventsPerBlock should be a multiple of the number of "base" |
8 | | - % listed in the motionDirections and staticDirections (4 at the moment). |
| 9 | + % listed in the MOTION_DIRECTIONS and STATIC_DIRECTIONS (4 at the moment). |
| 10 | + % MOTION_DIRECTIONS = [0 90 180 270]; |
| 11 | + % STATIC_DIRECTIONS = [-1 -1 -1 -1]; |
9 | 12 | % |
10 | 13 | % Pseudorandomization rules: |
11 | 14 | % (1) Directions are all present in random orders in `numEventsPerBlock/nDirections` |
|
42 | 45 | % - cfg.designFixationTargets = array (nr_blocks, numEventsPerBlock) |
43 | 46 | % showing for each event if it should be accompanied by a target |
44 | 47 | % |
45 | | - |
46 | | - |
| 48 | + |
47 | 49 | %% Check inputs |
48 | | - |
| 50 | + |
49 | 51 | % Set to 1 for a visualtion of the trials design order |
50 | 52 | if nargin < 2 || isempty(displayFigs) |
51 | 53 | displayFigs = 0; |
52 | 54 | end |
53 | | - |
| 55 | + |
54 | 56 | % Set variables here for a dummy test of this function |
55 | 57 | if nargin < 1 || isempty(cfg) |
56 | 58 | cfg.design.names = {'static'; 'motion'}; |
|
60 | 62 | cfg.target.maxNbPerBlock = 2; |
61 | 63 | displayFigs = 1; |
62 | 64 | end |
63 | | - |
| 65 | + |
64 | 66 | [NB_BLOCKS, NB_REPETITIONS, NB_EVENTS_PER_BLOCK, MAX_TARGET_PER_BLOCK] = getInput(cfg); |
65 | | - [~, staticIndex, motionIndex] = assignConditions(cfg); |
66 | | - |
| 67 | + [~, STATIC_INDEX, motionIndex] = assignConditions(cfg); |
| 68 | + |
67 | 69 | RANGE_TARGETS = [1 MAX_TARGET_PER_BLOCK]; |
68 | | - targetPerCondition = repmat(RANGE_TARGETS, 1, NB_REPETITIONS/2); |
69 | | - |
| 70 | + targetPerCondition = repmat(RANGE_TARGETS, 1, NB_REPETITIONS / 2); |
| 71 | + |
70 | 72 | numTargetsForEachBlock = zeros(1, NB_BLOCKS); |
71 | | - numTargetsForEachBlock(staticIndex) = shuffle(targetPerCondition); |
72 | | - numTargetsForEachBlock(motionIndex) = shuffle(targetPerCondition); |
73 | | - |
| 73 | + numTargetsForEachBlock(STATIC_INDEX) = shuffle(targetPerCondition); |
| 74 | + numTargetsForEachBlock(MOTION_INDEX) = shuffle(targetPerCondition); |
| 75 | + |
74 | 76 | %% Give the blocks the names with condition and design the task in each event |
75 | 77 | while 1 |
76 | | - |
| 78 | + |
77 | 79 | fixationTargets = zeros(NB_BLOCKS, NB_EVENTS_PER_BLOCK); |
78 | | - |
| 80 | + |
79 | 81 | for iBlock = 1:NB_BLOCKS |
80 | | - |
| 82 | + |
81 | 83 | % Set target |
82 | 84 | % - if there are 2 targets per block we make sure that they are at least |
83 | 85 | % 2 events apart |
84 | 86 | % - targets cannot be on the first or last event of a block |
85 | 87 | % - no more than 2 target in the same event order |
86 | | - |
| 88 | + |
87 | 89 | chosenTarget = []; |
88 | | - |
| 90 | + |
89 | 91 | tmpTarget = numTargetsForEachBlock(iBlock); |
90 | | - |
| 92 | + |
91 | 93 | switch tmpTarget |
92 | | - |
| 94 | + |
93 | 95 | case 1 |
94 | | - |
| 96 | + |
95 | 97 | chosenTarget = randsample(2:NB_EVENTS_PER_BLOCK - 1, tmpTarget, false); |
96 | | - |
| 98 | + |
97 | 99 | case 2 |
98 | | - |
| 100 | + |
99 | 101 | targetDifference = 0; |
100 | | - |
| 102 | + |
101 | 103 | while any(targetDifference <= 2) |
102 | 104 | chosenTarget = randsample(2:NB_EVENTS_PER_BLOCK - 1, tmpTarget, false); |
103 | 105 | targetDifference = diff(chosenTarget); |
104 | 106 | end |
105 | | - |
| 107 | + |
106 | 108 | end |
107 | | - |
| 109 | + |
108 | 110 | fixationTargets(iBlock, chosenTarget) = 1; |
109 | | - |
| 111 | + |
110 | 112 | end |
111 | | - |
| 113 | + |
112 | 114 | % Check rule 3 |
113 | 115 | if max(sum(fixationTargets)) < 3 |
114 | 116 | break |
115 | 117 | end |
116 | | - |
| 118 | + |
117 | 119 | end |
118 | | - |
| 120 | + |
119 | 121 | %% Now we do the easy stuff |
120 | 122 | cfg.design.blockNames = assignConditions(cfg); |
121 | | - |
| 123 | + |
122 | 124 | cfg.design.nbBlocks = NB_BLOCKS; |
123 | | - |
| 125 | + |
124 | 126 | cfg = setDirections(cfg); |
125 | | - |
| 127 | + |
126 | 128 | speeds = ones(NB_BLOCKS, NB_EVENTS_PER_BLOCK) * cfg.dot.speedPixPerFrame; |
127 | 129 | cfg.design.speeds = speeds; |
128 | | - |
| 130 | + |
129 | 131 | cfg.design.fixationTargets = fixationTargets; |
130 | 132 |
|
131 | | - |
132 | 133 | %% Plot |
133 | | - diplayDesign(cfg, displayFigs) |
134 | | - |
| 134 | + diplayDesign(cfg, displayFigs); |
| 135 | + |
135 | 136 | end |
136 | 137 |
|
137 | 138 | function cfg = setDirections(cfg) |
138 | | - |
| 139 | + |
139 | 140 | % CONSTANTS |
140 | 141 | % Set directions for static and motion condition |
141 | 142 | MOTION_DIRECTIONS = [0 90 180 270]; |
142 | 143 | STATIC_DIRECTIONS = [-1 -1 -1 -1]; |
143 | | - |
| 144 | + |
144 | 145 | [NB_BLOCKS, NB_REPETITIONS, NB_EVENTS_PER_BLOCK] = getInput(cfg); |
145 | | - |
146 | | - [~, staticIndex, motionIndex] = assignConditions(cfg); |
147 | | - |
| 146 | + |
| 147 | + [~, STATIC_INDEX, MOTION_INDEX] = assignConditions(cfg); |
| 148 | + |
148 | 149 | if mod(NB_EVENTS_PER_BLOCK, length(MOTION_DIRECTIONS)) ~= 0 |
149 | 150 | error('Number of events/block not a multiple of number of motion/static direction'); |
150 | 151 | end |
151 | | - |
| 152 | + |
152 | 153 | % initialize |
153 | 154 | directions = zeros(NB_BLOCKS, NB_EVENTS_PER_BLOCK); |
154 | | - |
| 155 | + |
155 | 156 | % Create a vector for the static condition |
156 | 157 | static_directions = repmat( ... |
157 | 158 | STATIC_DIRECTIONS, ... |
158 | 159 | 1, NB_EVENTS_PER_BLOCK / length(STATIC_DIRECTIONS)); |
159 | | - |
| 160 | + |
160 | 161 | for iMotionBlock = 1:NB_REPETITIONS |
161 | | - |
| 162 | + |
162 | 163 | % Check that we never have twice the same direction |
163 | 164 | while 1 |
164 | 165 | tmp = [ ... |
165 | 166 | shuffle(MOTION_DIRECTIONS), ... |
166 | 167 | shuffle(MOTION_DIRECTIONS), ... |
167 | 168 | shuffle(MOTION_DIRECTIONS)]; |
168 | | - |
169 | | - if ~any(diff(tmp,[],2)==0) |
| 169 | + |
| 170 | + if ~any(diff(tmp, [], 2) == 0) |
170 | 171 | break |
171 | 172 | end |
172 | 173 | end |
173 | | - |
| 174 | + |
174 | 175 | % Set motion direction and static order |
175 | | - directions(motionIndex(iMotionBlock), :) = tmp; |
176 | | - directions(staticIndex(iMotionBlock), :) = static_directions; |
177 | | - |
| 176 | + directions(MOTION_INDEX(iMotionBlock), :) = tmp; |
| 177 | + directions(STATIC_INDEX(iMotionBlock), :) = static_directions; |
| 178 | + |
178 | 179 | end |
179 | | - |
| 180 | + |
180 | 181 | cfg.design.directions = directions; |
181 | | - |
| 182 | + |
182 | 183 | end |
183 | 184 |
|
184 | 185 | function [nbBlocks, nbRepet, nbEventsBlock, maxTargBlock] = getInput(cfg) |
|
188 | 189 | nbBlocks = length(cfg.design.names) * nbRepet; |
189 | 190 | end |
190 | 191 |
|
191 | | -function [condition, staticIndex, motionIndex] = assignConditions(cfg) |
192 | | - |
| 192 | +function [condition, STATIC_INDEX, MOTION_INDEX] = assignConditions(cfg) |
| 193 | + |
193 | 194 | [~, nbRepet] = getInput(cfg); |
194 | | - |
| 195 | + |
195 | 196 | condition = repmat(cfg.design.names, nbRepet, 1); |
196 | | - |
| 197 | + |
197 | 198 | % Get the index of each condition |
198 | | - staticIndex = find(strcmp(condition, 'static')); |
199 | | - motionIndex = find(strcmp(condition, 'motion')); |
200 | | - |
| 199 | + STATIC_INDEX = find(strcmp(condition, 'static')); |
| 200 | + MOTION_INDEX = find(strcmp(condition, 'motion')); |
| 201 | + |
201 | 202 | end |
202 | 203 |
|
203 | 204 | function shuffled = shuffle(unshuffled) |
|
210 | 211 | end |
211 | 212 |
|
212 | 213 | function diplayDesign(cfg, displayFigs) |
213 | | - |
| 214 | + |
214 | 215 | %% Visualize the design matrix |
215 | 216 | if displayFigs |
216 | | - |
217 | | - close all |
| 217 | + |
| 218 | + close all; |
218 | 219 |
|
219 | 220 | figure(1); |
220 | | - |
| 221 | + |
221 | 222 | % Shows blocks (static and motion) and events (motion direction) order |
222 | 223 | directions = cfg.design.directions; |
223 | 224 | directions(directions == -1) = -90; |
224 | | - |
| 225 | + |
225 | 226 | subplot(3, 1, 1); |
226 | 227 | imagesc(directions); |
227 | | - |
| 228 | + |
228 | 229 | labelAxesBlock(); |
229 | | - |
| 230 | + |
230 | 231 | caxis([-90 - 37, 270 + 37]); |
231 | 232 | myColorMap = lines(5); |
232 | 233 | colormap(myColorMap); |
233 | | - |
| 234 | + |
234 | 235 | title('Block (static and motion) & Events (motion direction)'); |
235 | | - |
| 236 | + |
236 | 237 | % Shows the fixation targets design in each event (1 or 0) |
237 | 238 | fixationTargets = cfg.design.fixationTargets; |
238 | | - |
| 239 | + |
239 | 240 | subplot(3, 1, 2); |
240 | 241 | imagesc(fixationTargets); |
241 | 242 | labelAxesBlock(); |
242 | 243 | title('Fixation Targets design'); |
243 | 244 | colormap(gray); |
244 | | - |
| 245 | + |
245 | 246 | % Shows the fixation targets position distribution in the block across |
246 | 247 | % the experimet |
247 | 248 | [~, itargetPosition] = find(fixationTargets == 1); |
248 | | - |
| 249 | + |
249 | 250 | subplot(3, 1, 3); |
250 | 251 | hist(itargetPosition); |
251 | 252 | labelAxesFreq(); |
252 | 253 | title('Fixation Targets position distribution'); |
253 | | - |
254 | | - |
| 254 | + |
255 | 255 | figure(2); |
256 | | - |
| 256 | + |
257 | 257 | MOTION_DIRECTIONS = [0 90 180 270]; |
258 | | - |
| 258 | + |
259 | 259 | for iMotion = 1:length(MOTION_DIRECTIONS) |
260 | | - |
| 260 | + |
261 | 261 | [~, position] = find(directions == MOTION_DIRECTIONS(iMotion)); |
262 | | - |
| 262 | + |
263 | 263 | subplot(2, 2, iMotion); |
264 | 264 | hist(position); |
265 | 265 | scaleAxes(); |
266 | 266 | labelAxesFreq(); |
267 | 267 | title(num2str(MOTION_DIRECTIONS(iMotion))); |
268 | | - |
| 268 | + |
269 | 269 | end |
270 | | - |
271 | 270 |
|
272 | 271 | end |
273 | | - |
| 272 | + |
274 | 273 | end |
275 | 274 |
|
276 | 275 | function labelAxesBlock() |
|
0 commit comments