1+ function [cfg ] = expDesignMtMst(cfg )
2+ % Creates the sequence of blocks and the events in them
3+ %
4+ % The conditions are consecutive static and motion blocks
5+ % (Gives better results than randomised).
6+ %
7+ % Style guide: constants are in SNAKE_UPPER_CASE
8+ %
9+ % EVENTS
10+ % The numEventsPerBlock should be a multiple of the number of "base"
11+ % listed in the MOTION_DIRECTIONS and STATIC_DIRECTIONS (4 at the moment).
12+ % MOTION_DIRECTIONS = [0 90 180 270];
13+ %
14+ % Pseudorandomization rules:
15+ % (1) Directions are all present in random orders in `numEventsPerBlock/nDirections`
16+ % consecutive chunks. This evenly distribute the directions across the
17+ % block.
18+ % (2) No same consecutive direction
19+ %
20+ %
21+ % TARGETS
22+ %
23+ % Pseudorandomization rules:
24+ % (1) If there are more than 1 target per block we make sure that they are at least 2
25+ % events apart.
26+ % (2) Targets cannot be on the first or last event of a block.
27+ % (3) Targets can not be present more than NB_REPETITIONS - 1 times in the same event
28+ % position across blocks.
29+ %
30+ % Input:
31+ % - cfg: parameters returned by setParameters
32+ % - displayFigs: a boolean to decide whether to show the basic design
33+ % matrix of the design
34+ %
35+ % Output:
36+ % - ExpParameters.designBlockNames = cell array (nr_blocks, 1) with the
37+ % name for each block
38+ %
39+ % - cfg.designDirections = array (nr_blocks, numEventsPerBlock)
40+ % with the direction to present in a given block
41+ % - 0 90 180 270 indicate the angle
42+ % - -1 indicates static
43+ %
44+ % - cfg.designSpeeds = array (nr_blocks, numEventsPerBlock) * speedEvent;
45+ %
46+ % - cfg.designFixationTargets = array (nr_blocks, numEventsPerBlock)
47+ % showing for each event if it should be accompanied by a target
48+ %
49+
50+ %% Check inputs
51+
52+ % Set variables here for a dummy test of this function
53+ if nargin < 1 || isempty(cfg )
54+ error(' give me something to work with' );
55+ end
56+
57+ fprintf(' \n\n Creating design.\n\n ' );
58+
59+ [NB_BLOCKS , NB_REPETITIONS , NB_EVENTS_PER_BLOCK , MAX_TARGET_PER_BLOCK ] = ...
60+ getDesignInput(cfg );
61+ [~ , FIX_RIGHT_INDEX , FIX_LEFT_INDEX ] = assignConditions(cfg );
62+
63+ if mod(NB_REPETITIONS , MAX_TARGET_PER_BLOCK ) ~= 0
64+ error(' number of repetitions must be a multiple of max number of targets' );
65+ end
66+
67+ RANGE_TARGETS = 1 : MAX_TARGET_PER_BLOCK ;
68+ targetPerCondition = repmat(RANGE_TARGETS , 1 , NB_REPETITIONS / MAX_TARGET_PER_BLOCK );
69+
70+ numTargetsForEachBlock = zeros(1 , NB_BLOCKS );
71+ numTargetsForEachBlock(FIX_RIGHT_INDEX ) = shuffle(targetPerCondition );
72+ numTargetsForEachBlock(FIX_LEFT_INDEX ) = shuffle(targetPerCondition );
73+
74+ %% Give the blocks the names with condition and design the task in each event
75+ while 1
76+
77+ fixationTargets = zeros(NB_BLOCKS , NB_EVENTS_PER_BLOCK );
78+
79+ for iBlock = 1 : NB_BLOCKS
80+
81+ % Set target
82+ % - if there are 2 targets per block we make sure that they are at least
83+ % 2 events apart
84+ % - targets cannot be on the first or last event of a block
85+ % - no more than 2 target in the same event order
86+
87+ nbTarget = numTargetsForEachBlock(iBlock );
88+
89+ chosenPosition = setTargetPositionInSequence( ...
90+ NB_EVENTS_PER_BLOCK , ...
91+ nbTarget , ...
92+ [1 NB_EVENTS_PER_BLOCK ]);
93+
94+ fixationTargets(iBlock , chosenPosition ) = 1 ;
95+
96+ end
97+
98+ % Check rule 3
99+ if max(sum(fixationTargets )) < NB_REPETITIONS - 1
100+ break
101+ end
102+
103+ end
104+
105+ %% Now we do the easy stuff
106+ cfg.design.blockNames = assignConditions(cfg );
107+
108+ cfg.design.nbBlocks = NB_BLOCKS ;
109+
110+ cfg = setDirections(cfg );
111+
112+ speeds = ones(NB_BLOCKS , NB_EVENTS_PER_BLOCK ) * cfg .dot .speedPixPerFrame ;
113+ cfg.design.speeds = speeds ;
114+
115+ cfg.design.fixationTargets = fixationTargets ;
116+
117+ end
118+
119+ function cfg = setDirections(cfg )
120+
121+ [FIX_RIGHT_DIRECTIONS , FIX_LEFT_DIRECTIONS ] = getDirectionBaseVectors(cfg );
122+
123+ [NB_BLOCKS , NB_REPETITIONS , NB_EVENTS_PER_BLOCK ] = getDesignInput(cfg );
124+
125+ [~ , FIX_RIGHT_INDEX , FIX_LEFT_INDEX ] = assignConditions(cfg );
126+
127+ if mod(NB_EVENTS_PER_BLOCK , length(FIX_RIGHT_DIRECTIONS )) ~= 0
128+ error(' Number of events/block not a multiple of number of motion/static direction' );
129+ end
130+
131+ % initialize
132+ directions = zeros(NB_BLOCKS , NB_EVENTS_PER_BLOCK );
133+
134+ % Create a vector for the static condition
135+ NB_REPEATS_BASE_VECTOR = NB_EVENTS_PER_BLOCK / length(FIX_LEFT_DIRECTIONS );
136+
137+ for iMotionBlock = 1 : NB_REPETITIONS
138+
139+ % Set motion direction and static order
140+ directions(FIX_LEFT_INDEX(iMotionBlock ), : ) = ...
141+ repeatShuffleConditions(FIX_LEFT_DIRECTIONS , NB_REPEATS_BASE_VECTOR );
142+
143+ directions(FIX_RIGHT_INDEX(iMotionBlock ), : ) = ...
144+ repeatShuffleConditions(FIX_RIGHT_DIRECTIONS , NB_REPEATS_BASE_VECTOR );
145+
146+ end
147+
148+ cfg.design.directions = directions ;
149+
150+ end
151+
152+ function [FIX_RIGHT_DIRECTIONS , FIX_LEFT_DIRECTIONS ] = getDirectionBaseVectors(cfg )
153+
154+ % CONSTANTS
155+ % Set directions for both blocks condition
156+
157+ FIX_RIGHT_DIRECTIONS = cfg .design .motionDirections ;
158+ FIX_LEFT_DIRECTIONS = cfg .design .motionDirections ;
159+
160+ end
161+
162+ function [conditionNamesVector , FIX_RIGHT_INDEX , FIX_LEFT_INDEX ] = assignConditions(cfg )
163+
164+ [~ , nbRepet ] = getDesignInput(cfg );
165+
166+ conditionNamesVector = repmat(cfg .design .names , nbRepet , 1 );
167+
168+ % Get the index of each condition
169+ FIX_RIGHT_INDEX = find(strcmp(conditionNamesVector , ' fixation_right' ));
170+ FIX_LEFT_INDEX = find(strcmp(conditionNamesVector , ' fixation_left' ));
171+
172+ end
0 commit comments