A copy is also included in PsychBench in <PsychBench folder>/demos, so you can run it from there.
<cdcm>% RETINOTOPY DEMO<cdcm>
<cdcm>% Coding method<cdcm>
<cdcm>% --------------------------------------------------<cdcm>
<cdcm>% Each trial shows a retinotopic mapping stimulus for use in fMRI. Stimuli are<cdcm>
<cdcm>% based on a black & white dartboard pattern on a 50% gray background. The<cdcm>
<cdcm>% dartboard is positioned at screen center and spans 12.2 deg (6.1 deg<cdcm>
<cdcm>% eccentricity from center) with the middle 0.8 deg cut out and a white fixation<cdcm>
<cdcm>% dot placed at center. Each trial shows one of two types of stimuli: (1) an<cdcm>
<cdcm>% isolated wedge segment of the dartboard moving angularly in steps either<cdcm>
<cdcm>% clockwise or counterclockwise, and (2) an isolated "ring" segment of the<cdcm>
<cdcm>% dartboard moving radially in steps either outward from the center or inward<cdcm>
<cdcm>% toward the center. See property settings below for parameters. The stimulus<cdcm>
<cdcm>% starts 1 sec from sync trigger from scanner, received a short time after trial<cdcm>
<cdcm>% start, and runs for 2 loops of the stimulus (rotations around the dartboard or<cdcm>
<cdcm>% expansions/contractions through the dartboard). Here sync trigger is simulated<cdcm>
<cdcm>% as any key press from the default keyboard device. We run 2 repetitions of the<cdcm>
<cdcm>% sequence clockwise wedges, outward rings, counterclockwise wedges, inward<cdcm>
<cdcm>% rings.<cdcm>
<cdcm>%<cdcm>
<cdcm>% This scanner demo syncs in each trial and element timing is relative to sync.<cdcm>
<cdcm>% Syncing in blocks with trial timing relative to sync is also possible--see<cdcm>
<cdcm>% trial object property .start and scannerSyncInBlocksDemo.m.<cdcm>
<cdcm>%<cdcm>
<cdcm>% NOTE: In a real life you would want to modify this experiment to use more<cdcm>
<cdcm>% loops (longer stimuli) and more repetitions, in addition to listening for only<cdcm>
<cdcm>% the expected trigger signal from the specific scanner device.<cdcm>
<cdcm>%<cdcm>
<cdcm>% Similar to https://www.jneurosci.org/content/26/51/13128.<cdcm>
<cdcm>%<cdcm>
<cdcm>% http://www.scholarpedia.org/article/Visual_map<cdcm>
<cdcm>% Mark start of experiment script<cdcm>
newExperiment
<cdcm>% WEDGE TRIALS<cdcm>
<cdcm>% ==========<cdcm>
<cdcm>% 2 trial definitions numbered 1, 2 corresponding to clockwise, counterclockwise wedge steps<cdcm>
<cdkm>for<cdkm> direction = [1 -1]
<cdcm>% Sync with scanner<cdcm>
<cdcm>% ---<cdcm>
<cdcm>% Simulate trigger by key press for this tutorial.<cdcm>
<cdcm>% Many scanners send triggers as key presses, in which case would use a keyPress object in a real experiment too.<cdcm>
<cdcm>% By default listens for any key (could be changed in property .listenKeyNames).<cdcm>
syncer = keyPressObject;
<cdcm>% Listen for key press from default keyboard just for this demo.<cdcm>
<cdcm>% In a real experiment would need to set this to point to whatever device the trigger is coming from.<cdcm>
syncer.n_device = [];
<cdcm>% Register input as a trigger instead of response from subject<cdcm>
syncer.registerTrigger = true;
<cdcm>% Sync experiment at trigger so can set subsequent trials to start at times from sync<cdcm>
syncer.syncExperiment = true;
<cdcm>% Default start at trial start.<cdcm>
<cdcm>% By default keyPress elements end when they record a trigger/response -> don't need to set .end.<cdcm>
<cdcm>% Report sync time ( = trigger time)<cdcm>
syncer.report = <cdsm>"syncTime"<cdsm>;
<cdcm>% ---<cdcm>
<cdcm>% Dartboard wedges<cdcm>
<cdcm>% ---<cdcm>
stimulus = dartboardRetinotopyObject;
<cdcm>% Basic dartboard parameters:<cdcm>
<cdcm>% size (deg), center cut-out size (deg), numbers of angular and radial checks<cdcm>
stimulus.diameter = 12.2;
stimulus.centerDiameter = 0.8;
stimulus.numAngularChecks = 48;
stimulus.numRadialChecks = 4.75;
<cdcm>% Set alternating radial strips to move inward/outward at specific speed (radial cycles/sec), like an internally balanced phase shift.<cdcm>
<cdcm>% Sign here effectively sets which strips go in which direction -> modulate by wedge direction +/-1 so clockwise/counterclockwise wedge stimuli are opposites.<cdcm>
stimulus.radialTemporalFrequencyBalanced = direction*5/6;
<cdcm>% Show wedges<cdcm>
stimulus.showWedges = true;
<cdcm>% Set wedge parameters, all based on units of angular checks in the dartboard:<cdcm>
<cdcm>% size (checks), movement increment (checks), movement time interval (sec)<cdcm>
stimulus.apertureSize = 6;
stimulus.apertureStep = direction*2;
stimulus.apertureInterval = 1;
<cdcm>% Number of loops around the dartboard to show before object ends on its own<cdcm>
stimulus.maxNumLoops = 2;
<cdcm>% Start 1 sec from experiment sync (done by syncer object above).<cdcm>
<cdcm>% Don't need to set .end cause ends on its own based on .maxNumLoops above.<cdcm>
stimulus.start.t_sync = 1;
<cdcm>% See start time, duration in experiment results output<cdcm>
stimulus.report = [<cdsm>"startTime"<cdsm> <cdsm>"duration"<cdsm>];
<cdcm>% ---<cdcm>
<cdcm>% Fixation dot<cdcm>
<cdcm>% ---<cdcm>
<cdcm>% Default dots object = 1 round white dot, diameter = 0.2 deg<cdcm>
fixation = dotsObject;
<cdcm>% Make sure it displays in front of the dartboard<cdcm>
fixation.depth = <cdsm>"front"<cdsm>;
<cdcm>% Start at start of dartboard; End at end of dartboard<cdcm>
fixation.start.startOf = <cdsm>"stimulus"<cdsm>;
fixation.end.endOf = <cdsm>"stimulus"<cdsm>;
<cdcm>% ---<cdcm>
<cdcm>% Add trial definition with default numbering (1, 2, ...)<cdcm>
addTrial(syncer, wedges, fixation);
<cdkm>end<cdkm>
<cdcm>% ==========<cdcm>
<cdcm>% RING TRIALS<cdcm>
<cdcm>% ==========<cdcm>
<cdcm>% 2 trial definitions numbered 3, 4 corresponding to outward, inward ring steps.<cdcm>
<cdcm>% Same as wedge trials above except for wedge/ring parameters in the dartboardRetinotopy object.<cdcm>
<cdkm>for<cdkm> direction = [1 -1]
<cdcm>% Sync with scanner<cdcm>
<cdcm>% ---<cdcm>
syncer = keyPressObject;
syncer.n_device = [];
syncer.registerTrigger = true;
syncer.syncExperiment = true;
syncer.report = <cdsm>"syncTime"<cdsm>;
<cdcm>% ---<cdcm>
<cdcm>% Dartboard rings<cdcm>
<cdcm>% ---<cdcm>
stimulus = dartboardRetinotopyObject;
stimulus.diameter = 12.2;
stimulus.centerDiameter = 0.8;
stimulus.numAngularChecks = 48;
stimulus.numRadialChecks = 4.75;
stimulus.radialTemporalFrequencyBalanced = direction*5/6;
<cdcm>% Show rings<cdcm>
stimulus.showRings = true;
<cdcm>% Set ring parameters, all based on units of radial checks in the dartboard:<cdcm>
<cdcm>% size (checks), movement increment (checks), movement time interval (sec).<cdcm>
stimulus.apertureSize = 1;
stimulus.apertureStep = direction*0.3125;
stimulus.apertureInterval = 1;
stimulus.maxNumLoops = 2;
stimulus.start.t_sync = 1;
stimulus.report = [<cdsm>"startTime"<cdsm> <cdsm>"duration"<cdsm>];
<cdcm>% ---<cdcm>
<cdcm>% Fixation dot<cdcm>
<cdcm>% ---<cdcm>
fixation = dotsObject;
fixation.depth = <cdsm>"front"<cdsm>;
fixation.start.startOf = <cdsm>"stimulus"<cdsm>;
fixation.end.endOf = <cdsm>"stimulus"<cdsm>;
<cdcm>% ---<cdcm>
<cdcm>% Add trial definition with default numbering (adds 3, 4 after 1, 2 defined above)<cdcm>
addTrial(syncer, rings, fixation);
<cdkm>end<cdkm>
<cdcm>% ==========<cdcm>
<cdcm>% Make experiment object and set background color for the experiment to 50% gray.<cdcm>
<cdcm>% You can also just do this as a preference in pb_prefs(), but good to do it like this in case script runs on different computers.<cdcm>
experiment = experimentObject;
experiment.backColor = [0.5 0.5 0.5];
<cdcm>% Use addToExperiment() to add objects not specific to trial (don't need to use otherwise)<cdcm>
addToExperiment(experiment)
<cdcm>% Set trial list: 2 repetitions of the sequence clockwise, outward, counterclockwise, inward<cdcm>
nn = rep([1 3 2 4], 2);
setTrialList(nn)
<cdcm>% You can call "viewExperiment" and "viewExperiment -d" to visualize trials<cdcm>
<cdcm>% Run<cdcm>
[results, resultsMatrix] = runExperiment;