11function [cfg ] = expDesign(cfg , displayFigs )
22 % Creates the sequence of blocks and the events in them
33 %
4- % The conditions are consecutive static and motion blocks
5- % Gives better results than randomised.
6- %
7- % It can be run as a stand alone without inputs to display a visual example of possible design.
4+ % The conditions are consecutive static and motion blocks (Gives better results than randomised).
85 %
96 % EVENTS
107 % The numEventsPerBlock should be a multiple of the number of "base"
118 % listed in the motionDirections and staticDirections (4 at the moment).
9+ % Pseudorandomization rules:
10+ % (1) Directions are all present in random orders in `numEventsPerBlock/nDirections`
11+ % consecutive chunks. This evenly distribute the directions across the
12+ % block.
13+ % (2) No same consecutive direction (TO IMPLEMENT)
1214 %
13- %
14- % TARGETS:
15- % If there are 2 targets per block we make sure that they are at least 2
16- % events apart.
17- % Targets cannot be on the first or last event of a block
15+ % TARGETS
16+ % Pseudorandomization rules:
17+ % (1) If there are 2 targets per block we make sure that they are at least 2
18+ % events apart.
19+ % (2) Targets cannot be on the first or last event of a block.
20+ % (3) Targets can not be present more than 2 times in the same event
21+ % position across blocks.
1822 %
1923 % Input:
2024 % - ExpParameters: parameters returned by SetParameters
3034 % - 0 90 180 270 indicate the angle
3135 % - -1 indicates static
3236 %
33- % - ExpParameters.designSpeeds = array (nr_blocks, numEventsPerBlock) * speedEvent
37+ % - ExpParameters.designSpeeds = array (nr_blocks, numEventsPerBlock) * speedEvent;
3438 %
3539 % - ExpParameters.designFixationTargets = array (nr_blocks, numEventsPerBlock)
3640 % showing for each event if it should be accompanied by a target
3741 %
3842
3943 % Set directions for static and motion condition
4044 motionDirections = [0 90 180 270 ];
41- % staticDirections = [0 90 180 270 ];
42- staticDirections = [- 1 - 1 - 1 - 1 ];
43-
45+ staticDirections = [- 1 - 1 - 1 - 1 ];
46+
47+
4448 %% Check inputs
45-
49+
4650 % Set variables here for a dummy test of this function
4751 if nargin < 1 || isempty(cfg )
4852 cfg.names = {' static' , ' motion' };
6771 if mod(numEventsPerBlock , length(motionDirections )) ~= 0
6872 warning(' Number of events/block not a multiple of number of motion/static direction' );
6973 end
70-
74+
75+
7176 %% Adapt some variables according to input
72-
73- % Set directions for static and motion condition
74- motionDirections = repmat(motionDirections , 1 , numEventsPerBlock / length(motionDirections ));
75- staticDirections = repmat(staticDirections , 1 , numEventsPerBlock / length(staticDirections ));
76-
77+
7778 % Assign the conditions
7879 condition = repmat(names , 1 , numRepetitions );
7980 nrBlocks = length(condition );
81+
82+ % Assigne design parameters to be exported
83+ cfg.designBlockNames = cell(nrBlocks , 1 );
84+ cfg.designDirections = zeros(nrBlocks , numEventsPerBlock );
85+ cfg.designSpeeds = ones(nrBlocks , numEventsPerBlock ) * speedEvent ;
86+ cfg.designFixationTargets = zeros(nrBlocks , numEventsPerBlock );
87+
88+ % Create a vector for the static condition
89+ staticDirections = repmat(staticDirections , 1 , numEventsPerBlock / length(staticDirections ));
90+
8091 % Get the index of each condition
81- staticIndex = find(strcmp(condition , ' static' ));
82- motionIndex = find(strcmp(condition , ' motion' ));
83-
92+ staticIndex = find( strcmp(condition , ' static' ) );
93+ motionIndex = find( strcmp(condition , ' motion' ) );
94+
95+ for iMotionBlock = 1 : numRepetitions
96+
97+ % Shuffle and set motion direction order
98+ cfg .designDirections(motionIndex(iMotionBlock ),: ) = ...
99+ [ Shuffle(motionDirections ), Shuffle(motionDirections ), Shuffle(motionDirections )];
100+
101+ % Set static condition
102+ cfg .designDirections(staticIndex(iMotionBlock ),: ) = staticDirections ;
103+
104+ end
105+
84106 % Assign the targets for each condition
85107 rangeTargets = [1 maxNumFixTargPerBlock ];
108+
109+ % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
110+
111+ % % % IT COULD BE A PROBLEM IF WE SET THE N OF TARGETS RANDOMLY (TOO CHOOSE
112+ % % % RANDOMLY B/W 1 AND 2 FOR N TIMES) BECAUSE AT THE END EACH PARTICIPANT
113+ % % % HAS A DIFFERENET NUMBER OF TARKETS TO GET, LMK
114+
86115 % Get random number of targets for one condition
87116 targetPerCondition = randi(rangeTargets , 1 , numRepetitions );
88117 % Assign the number of targets for each condition after shuffling
89118 numTargets = zeros(1 , nrBlocks );
90119 numTargets(staticIndex ) = Shuffle(targetPerCondition );
91120 numTargets(motionIndex ) = Shuffle(targetPerCondition );
92-
93- %% Give the blocks the names with condition
94-
95- cfg.design.blockNames = cell(nrBlocks , 1 );
96- cfg.design.directions = zeros(nrBlocks , numEventsPerBlock );
97- cfg.design.speeds = ones(nrBlocks , numEventsPerBlock ) * dotsSpeed ;
98- cfg.design.fixationTargets = zeros(nrBlocks , numEventsPerBlock );
99-
100- for iMotionBlock = 1 : numRepetitions
101-
102- cfg .design .directions(motionIndex(iMotionBlock ), : ) = Shuffle(motionDirections );
103- cfg .design .directions(staticIndex(iMotionBlock ), : ) = Shuffle(staticDirections );
104-
105- end
106-
107- for iBlock = 1 : nrBlocks
108-
109- % Set block name
110- switch condition{iBlock }
111- case ' static'
112- thisBlockName = {' static' };
113- case ' motion'
114- thisBlockName = {' motion' };
121+
122+ % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
123+
124+ %% Give the blocks the names with condition and design the task in each event
125+
126+ while 1
127+
128+ for iBlock = 1 : nrBlocks
129+
130+
131+ % Set block name
132+ switch condition{iBlock }
133+ case ' static'
134+ thisBlockName = {' static' };
135+ case ' motion'
136+ thisBlockName = {' motion' };
137+ end
138+
139+ cfg .designBlockNames(iBlock ) = thisBlockName ;
140+
141+ % Set target
142+ % - if there are 2 targets per block we make sure that they are at least
143+ % 2 events apart
144+ % - targets cannot be on the first or last event of a block
145+ % - no more than 2 target in the same event order
146+
147+ chosenTarget = [];
148+
149+ tmpTarget = numTargets(iBlock );
150+
151+ switch tmpTarget
152+
153+ case 1
154+
155+ chosenTarget = randsample(2 : numEventsPerBlock - 1 , tmpTarget , false );
156+
157+ case 2
158+
159+ targetDifference = 0 ;
160+
161+
162+ while targetDifference <= 2
163+ chosenTarget = randsample(2 : numEventsPerBlock - 1 , tmpTarget , false );
164+ targetDifference = (max(chosenTarget ) - min(chosenTarget ));
165+ end
166+
167+ end
168+
169+ cfg .designFixationTargets(iBlock , chosenTarget ) = 1 ;
170+
115171 end
116- cfg .design .blockNames(iBlock ) = thisBlockName ;
117-
118- % set target
119- % if there are 2 targets per block we make sure that they are at least
120- % 2 events apart
121- % targets cannot be on the first or last event of a block
122-
123- chosenTarget = [];
124-
125- tmpTarget = numTargets(iBlock );
126-
127- switch tmpTarget
128-
129- case 1
130-
131- chosenTarget = randsample(2 : numEventsPerBlock - 1 , tmpTarget , false );
132-
133- case 2
134-
135- targetDifference = 0 ;
136-
137- while targetDifference <= 2
138- chosenTarget = randsample(2 : numEventsPerBlock - 1 , tmpTarget , false );
139- targetDifference = (max(chosenTarget ) - min(chosenTarget ));
140- end
141-
172+
173+ % Check rule 3
174+ if max(sum(cfg .designFixationTargets )) < 3
175+ break
176+ else
177+ cfg.designBlockNames = cell(nrBlocks , 1 );
178+ cfg.designFixationTargets = zeros(nrBlocks , numEventsPerBlock );
142179 end
143-
144- cfg .design .fixationTargets(iBlock , chosenTarget ) = 1 ;
145-
180+
146181 end
147-
182+
183+
184+ designSpeeds = cfg .designSpeeds ' ;
185+ designDirections = cfg .designDirections ' ;
186+ designFixationTargets = cfg .designFixationTargets ' ;
187+
188+ cfg.trialList = [designDirections(: ) designSpeeds(: ) designFixationTargets(: )];
189+
190+
191+ % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
192+
148193 %% Visualize the design matrix
149194 if displayFigs
150-
151- uniqueNames = unique(cfg .design .blockNames ) ;
152-
153- Ind = zeros(length(cfg .design .blockNames ), length(uniqueNames )) ;
154-
155- for i = 1 : length(uniqueNames )
156- CondInd(: , i ) = find( ...
157- strcmp(cfg .design .blockNames , uniqueNames{i })) ; % #ok<*AGROW>
158- Ind(CondInd(: , i ), i ) = 1 ;
195+
196+ figure(1 );
197+
198+
199+ % Shows blocks (static and motion) and events (motion direction) order
200+ subplot(3 ,3 ,1 )
201+
202+ designDirection = cfg .designDirections ;
203+ designDirection(designDirection ==-1 ) = - 90 ;
204+
205+ imagesc(designDirection )
206+
207+ labelAxesBlock()
208+
209+ caxis([-90 - 37 , 270 + 37 ])
210+ myColorMap = lines(5 );
211+ colormap(myColorMap );
212+
213+ title(' Block (static and motion) & Events (motion direction)' )
214+
215+
216+ % Shows the direction position distribution in the motion blocks
217+ % across the experiment
218+ subplot(3 ,3 ,2 )
219+
220+ leftPosition = [];
221+ for i= 1 : nrBlocks
222+ leftPosition = [ leftPosition find(cfg .designDirections(i ,: )==0 ) ];
159223 end
160-
161- imagesc(Ind );
162-
163- set(gca , ...
164- ' XTick' , 1 : length(uniqueNames ), ...
165- ' XTickLabel' , uniqueNames );
166-
224+ hist(leftPosition )
225+ scaleAxes()
226+ labelAxesFreq()
227+ title(' 0' )
228+
229+ subplot(3 ,3 ,3 )
230+
231+ rightPosition = [];
232+ for i= 1 : nrBlocks
233+ rightPosition = [ rightPosition find(cfg .designDirections(i ,: )==90 ) ];
234+ end
235+ hist(rightPosition )
236+ scaleAxes()
237+ labelAxesFreq()
238+ title(' 90' )
239+
240+ subplot(3 ,3 ,5 )
241+
242+ upPosition = [];
243+ for i= 1 : nrBlocks
244+ upPosition = [ upPosition find(cfg .designDirections(i ,: )==180 ) ];
245+ end
246+ hist(upPosition )
247+ scaleAxes()
248+ labelAxesFreq()
249+ title(' 180' )
250+
251+ subplot(3 ,3 ,6 )
252+
253+ downPosition = [];
254+ for i= 1 : nrBlocks
255+ downPosition = [ downPosition find(cfg .designDirections(i ,: )==270 ) ];
256+ end
257+ hist(downPosition )
258+ scaleAxes()
259+ labelAxesFreq()
260+ title(' 270' )
261+
262+
263+ % Shows the fixation targets design in each event (1 or 0)
264+ subplot(3 ,3 ,7 )
265+
266+ imagesc(cfg .designFixationTargets )
267+ labelAxesBlock()
268+ title(' Fixation Targets design' )
269+
270+
271+ % Shows the fixation targets position distribution in the block across
272+ % the experimet
273+ subplot(3 ,3 ,8 )
274+
275+ itargetPosition = [];
276+ for i= 1 : nrBlocks
277+ itargetPosition = [ itargetPosition find(cfg .designFixationTargets(i ,: )==1 ) ];
278+ end
279+ hist(itargetPosition )
280+ labelAxesFreq()
281+ title(' Fixation Targets position distribution' )
282+
167283 end
284+
285+ end
286+
287+ function labelAxesBlock()
288+ % an old viking saying because they really cared about their axes
289+ ylabel(' Block seq.' , ' Fontsize' , 8 );
290+ xlabel(' Events' , ' Fontsize' , 8 );
291+ end
292+
293+ function labelAxesFreq()
294+ % an old viking saying because they really cared about their axes
295+ ylabel(' freq.' , ' Fontsize' , 8 );
296+ xlabel(' Events' , ' Fontsize' , 8 );
297+ end
298+
299+ function scaleAxes()
300+ xlim([1 12 ])
301+ ylim([0 5 ])
302+ end
0 commit comments