A copy is also included in PsychBench in <PsychBench folder>/demos, so you can run it from there.
<cdcm>% WALKER DIRECTIONS EXPERIMENT DEMO<cdcm>
<cdcm>% Coding method<cdcm>
<cdcm>% --------------------------------------------------<cdcm>
<cdcm>% Each trial shows a 15-dot point light human walking display at a height of 10<cdcm>
<cdcm>% deg, rotated to face either left or right. The walker is in a mask of dots<cdcm>
<cdcm>% taken from the same motion data. Number of mask dots is randomized between<cdcm>
<cdcm>% 15-155. Mask dot mean positions are randomized within a cylinder with width 12<cdcm>
<cdcm>% deg, and dot phases (time offsets in the walking cycle) are randomized. Each<cdcm>
<cdcm>% mask dot is rotated left or right such that total numbers of dots in the mask<cdcm>
<cdcm>% + walker display in each direction are equal (e.g. 20 mask dots left + 15<cdcm>
<cdcm>% walker dots left + 35 mask dots right). Within each direction, mask dots are<cdcm>
<cdcm>% taken evenly from the motion data with the remainders taken randomly.<cdcm>
<cdcm>%<cdcm>
<cdcm>% The subject responds by left/right arrow key press with whether the walker is<cdcm>
<cdcm>% facing left or right.<cdcm>
<cdcm>%<cdcm>
<cdcm>% Two factors: walker direction (1/2 = left/right), number of mask dots. We run<cdcm>
<cdcm>% 40 left trials + 40 right trials = 80 trials total, all in random order. The<cdcm>
<cdcm>% experiment begins with 6 training trials showing just the walker, and another<cdcm>
<cdcm>% 6 training trials showing the walker with a minimal mask of 15 dots.<cdcm>
newExperiment
<cdcm>% TASK TRIALS<cdcm>
<cdcm>% 80 trial definitions numbered 1-80: 2 directions x 40 random numbers of dots each.<cdcm>
<cdcm>% Each random number of dots is potentially a different value for masks property<cdcm>
<cdcm>% .numScrambleDots (see below), so each is a DISTINCT TRIAL which needs a<cdcm>
<cdcm>% separate trial definition.<cdcm>
<cdcm>% ==========<cdcm>
<cdkm>for<cdkm> d = [1 2]
<cdkm>for<cdkm> n_rep = 1:40
<cdcm>% Walker<cdcm>
<cdcm>% ---<cdcm>
walker = bmlWalkerObject;
<cdcm>% bmlWalkerData.mat comes with the bmlWalker element type.<cdcm>
<cdcm>% Contains cell array "bmlWalkerData".<cdcm>
<cdcm>% {2} contains the motion data we want to use.<cdcm>
walker.fileName = <cdsm>"bmlWalkerData.mat"<cdsm>;
walker.dataExpr = <cdsm>"bmlWalkerData{2}"<cdsm>;
<cdkm>if<cdkm> d == 1
<cdcm>% Facing left<cdcm>
walker.azimuth = -90;
<cdkm>else<cdkm>
<cdcm>% Facing right<cdcm>
walker.azimuth = +90;
<cdkm>end<cdkm>
<cdcm>% Default start at trial start; End at response<cdcm>
walker.end.response = true;
<cdcm>% See direction # in results<cdcm>
walker.info.direction = d;
<cdcm>% ---<cdcm>
<cdcm>% Walker mask<cdcm>
<cdcm>% ---<cdcm>
<cdcm>% Use two bmlWalker objects superimposed: one for dots facing left, one for<cdcm>
<cdcm>% facing right<cdcm>
masks = bmlWalkerObject(2);
<cdcm>% Mask 1 = same direction as walker, 2 = opposite<cdcm>
masks(1).azimuth = walker.azimuth;
masks(2).azimuth = -walker.azimuth;
<cdcm>% Random number of dots across both masks between 15-155.<cdcm>
<cdcm>% Mask 1 (same direction) = random number between 0-70<cdcm>
<cdcm>% Mask 2 (opposite direction) = same number + 15<cdcm>
masks(1).numScrambleDots = randomNum(0, 70, [], <cdsm>"-i"<cdsm>);
masks(2).numScrambleDots = masks(1).numScrambleDots+15;
<cdcm>% All other properties same for both objects...<cdcm>
<cdkm>for<cdkm> n = 1:2
<cdcm>% Same motion data as walker<cdcm>
masks(n).fileName = <cdsm>"bmlWalkerData.mat"<cdsm>;
masks(n).dataExpr = <cdsm>"bmlWalkerData{2}"<cdsm>;
<cdcm>% .scramble = true makes it a random dot mask<cdcm>
masks(n).scramble = true;
<cdcm>% 12 deg square mask area<cdcm>
masks(n).scrambleAreaSize = [12 12];
<cdcm>% Random motion phase across dots<cdcm>
masks(n).scramblePhases = true;
<cdcm>% Start/End same as walker<cdcm>
masks(n).end.response = true;
<cdcm>% See number of dots in results.<cdcm>
<cdcm>% Total number of mask dots = sum of them.<cdcm>
masks(n).report = <cdsm>"numScrambleDots"<cdsm>;
<cdkm>end<cdkm>
<cdcm>%---<cdcm>
<cdcm>% Key press response<cdcm>
<cdcm>% ---<cdcm>
response = keyPressObject;
<cdcm>% Listen for left/right arrow keys.<cdcm>
<cdcm>% You can get these key names using showKey() at the MATLAB command line.<cdcm>
<cdcm>% Response value recorded in record property .response will be number of the name in this list, i.e. 1 = left, 2 = right.<cdcm>
response.listenKeyNames = [<cdsm>"left"<cdsm> <cdsm>"right"<cdsm>];
<cdcm>% Score correct/incorrect.<cdcm>
<cdcm>% Response values 1 = left, 2 = right conveniently match our loop variable "d", so we can just set correct response = that.<cdcm>
response.scoreResponse = true;
response.correctResponse = d;
<cdcm>% Default start at trial start.<cdcm>
<cdcm>% By default keyPress elements end when they record a response -> don't need to set .end.<cdcm>
<cdcm>% See response, score, latency in results<cdcm>
response.report = [<cdsm>"response"<cdsm> <cdsm>"responseScore"<cdsm> <cdsm>"responseLatency"<cdsm>];
<cdcm>% ---<cdcm>
<cdcm>% Add trial definition with default numbering (1, 2, 3, ...)<cdcm>
addTrial(walker, masks, response);
<cdkm>end<cdkm>
<cdkm>end<cdkm>
<cdcm>% ==========<cdcm>
<cdcm>% TRAINING TRIALS<cdcm>
<cdcm>% ==========<cdcm>
<cdcm>% WALKER WITH NO MASK<cdcm>
<cdcm>% 2 trial definitions numbered 101, 102: 2 directions, no mask<cdcm>
<cdkm>for<cdkm> d = [1 2]
walker = bmlWalkerObject;
walker.fileName = <cdsm>"bmlWalkerData.mat"<cdsm>;
walker.dataExpr = <cdsm>"bmlWalkerData{2}"<cdsm>;
<cdkm>if<cdkm> d == 1
walker.azimuth = -90;
<cdkm>else<cdkm>
walker.azimuth = +90;
<cdkm>end<cdkm>
walker.end.response = true;
response = keyPressObject;
response.listenKeyNames = [<cdsm>"left"<cdsm> <cdsm>"right"<cdsm>];
response.scoreResponse = true;
response.correctResponse = d;
<cdcm>% Add trial definition to group 100 (101, 102, ...)<cdcm>
addTrial(walker, response, 100);
<cdkm>end<cdkm>
<cdcm>% WALKER WITH MINIMAL MASK<cdcm>
<cdcm>% 2 trial definitions numbered 201, 202: 2 directions, same number of mask dots in each<cdcm>
<cdkm>for<cdkm> d = [1 2]
walker = bmlWalkerObject;
walker.fileName = <cdsm>"bmlWalkerData.mat"<cdsm>;
walker.dataExpr = <cdsm>"bmlWalkerData{2}"<cdsm>;
<cdkm>if<cdkm> d == 1
walker.azimuth = -90;
<cdkm>else<cdkm>
walker.azimuth = +90;
<cdkm>end<cdkm>
walker.end.response = true;
<cdcm>%Mask = 15 dots facing opposite direction 15-dot walker<cdcm>
mask = bmlWalkerObject;
mask.azimuth = -walker.azimuth;
mask.numScrambleDots = 15;
mask.fileName = <cdsm>"bmlWalkerData.mat"<cdsm>;
mask.dataExpr = <cdsm>"bmlWalkerData{2}"<cdsm>;
mask.scramble = true;
mask.scrambleAreaSize = [12 12];
mask.scramblePhases = true;
mask.end.response = true;
response = keyPressObject;
response.listenKeyNames = [<cdsm>"left"<cdsm> <cdsm>"right"<cdsm>];
response.scoreResponse = true;
response.correctResponse = d;
<cdcm>% Add trial definition to group 200 (201, 202, ...)<cdcm>
addTrial(walker, mask, response, 200);
<cdkm>end<cdkm>
<cdcm>% PAUSE TRIAL<cdcm>
<cdcm>% ---<cdcm>
<cdcm>% dialogue object to show text until subject presses any key.<cdcm>
<cdcm>% Can just set text and leave all properties at default.<cdcm>
pauseText = dialogueObject;
pauseText.text = <cdsm>"Press any key to continue..."<cdsm>;
<cdcm>% Add trial definition with name "pause"<cdcm>
addTrial(pauseText, <cdsm>"pause"<cdsm>);
<cdcm>% ---<cdcm>
<cdcm>% ==========<cdcm>
<cdcm>% Set trial list:<cdcm>
<cdcm>%<cdcm>
<cdcm>% - 3 x 2 walker only training trial definitions in random order<cdcm>
<cdcm>% - pause<cdcm>
<cdcm>% - 3 x 2 walker + mask training trial definitions in random order<cdcm>
<cdcm>% - pause<cdcm>
<cdcm>% - task trial definitions in random order<cdcm>
<cdcm>%<cdcm>
<cdcm>% Random order just to randomize left/right<cdcm>
nn = {randomOrder(rep(101:102, 3)) <cdsm>"pause"<cdsm> randomOrder(rep(201:202, 3)) <cdsm>"pause"<cdsm> randomOrder(1:80)};
setTrialList(nn)
<cdcm>% You can call "viewExperiment" and "viewExperiment -d" to visualize trials<cdcm>
[results, resultsMatrix] = runExperiment;