walkerDirectionsDemo.m

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;