How to end the experiment

In general, the easiest way to code the stimulus is to have it continue indefinitely until the scanner stops scanning. After the scan is finished and you want to stop the stimulus you hit the ESC key. This way you never have the stimulus stop before the scanner does, and it doesn't hurt to keep having the stimulus go past the end of the scan.

If instead you want to only collect a specific number of blocks of trials and stop, then you would set:

task{1}.numBlocks = 4;

say, to run for 4 blocks of trials and then stop. Or if you want to run for a specific number of trials and stop, then you can do:

task{1}.numTrials = 17;

which would run for 17 trials and stop. These variables default to inf so that the experiment only stops when the user hits ESC.

How to use 10-bit contrast

If you want to use 10-bits so as to be able to display finer contrast gradations, you need to remap the usual 8-bit contrast steps (0:255) into a subset of the larger 10-bit (1024) contrast table. This can be done using a piece of code called setGammaTable that can be included in your code as a subfunction (written by JG and FP and found at ~shani/matlab/MGLexpts/setGammaTable.m), but there are some details to be careful of.

First, you will want to ‘reserve’ some colors that you will want to be able to use and leave unaffected by the resetting of the gamma table. This allows you to show, for example, a high-contrast fixation cross at the same time that you’re showing a low-contrast target. If you don’t reserve some colors, you won’t be able to have anything high-contrast at the same time as you use the 10-bit capacity. See example code taskTemplateContrast10bit.m where four colors are saved, and a low-contrast target is shown (written by SO and found at mgl/task/taskTemplateContrast10bit.m).

How to run a dual task

If you want to run two tasks at once, for example, an RSVP task at fixation and a detection task in the periphery, you will create two tasks and call one from within the other. You should construct it so one task (e.g. detection) is the main task and the other task (e.g. fixation-RSVP) is the subsidiary task.

The subsidiary task needs to be constructed like a regular task, with its own initialization and callbacks, but without the updateTask loop. It will be updated from within the main task.

The main task will be constructed as usual, but an extra line will appear to set the subsidiary task and to update it. For example, to set the fixation task as the subsidiary, you will add a line in the main task like this:

task{2} = fixationTask(myscreen);

Then, the update loop of the main task will look like this:

phaseNum = 1;
while (phaseNum <= length(task{1})) && ~myscreen.userHitEsc
 % update the task
 [task{1} myscreen phaseNum] = updateTask(task{1},myscreen,phaseNum);
 [task{2} myscreen] = updateTask(task{2},myscreen,1);
 % flip screen
 myscreen = tickScreen(myscreen,task);
% if we got here, we are at the end of the experiment
myscreen = endTask(myscreen,task);

The key to getting this to work is to control the timing. One way to do this is to have the main task set some variables which tell the subsidiary task whether or not to run. In order to do this, have the stimulus variable set as a global variable in both tasks. Set two stimulus subfields as flags, e.g. stimulus.startSubsidiary and stimulus.endSubsidiary, in order to control the subsidiary task. Then have the subsidiary task check the status of these flags, and start or stop accordingly.

In order to get the subsidiary task to start and stop when the appropriate flags are set, you will need to do the following:

Set the first segment of the subsidiary task to have infinite length. That makes the subsidiary wait in the first segment until the main task calls it. When the main task wants to start the subsidiary task, it will set the stimulus.startSubsidary flag to 1, and this will cause the subsidiary to jump to the next segment as follows:

In the screenUpdate callback of the subsidiary task, have a loop that checks to see whether the stimulus.startSubsidiary flag is set to 1. (This should be done in screenUpdate so that it can check all the time.) Have an if-loop that tells the task to skip ahead to the next segment as soon as the flag == 1. (It’s a good idea to reset the flag to 0):

if(stimulus.startSubsidiary == 1)
 stimulus.startSubsidiary = 0;
 task = jumpSegment(task);

When you’re ready to end the subsidiary task, have the main task set the stimulus.endSubsidiary flag to 1, and have the following if-loop in the subsidiary’s screenUpdate callback:

if(stimulus.endSubsidiary == 1)
 stimulus.endSubsidiary = 0;
 task = jumpSegment(task,inf);

The ‘inf’ argument in the jumpSegment function call tells the task to jump to the end of all the segments and start the next trial. This puts the subsidiary task back into the state of being in the infinite first segment, waiting for the start flag to be reset to 1 by the main task.

Example code can be found in taskTemplateDualMain.m and taskTemplateDualSubsidiary.m

How to calibrate the monitor


To calibrate a monitor, you can use the program moncalib.m in the utils directory. It is set up to work with the PhotoResearch PR650 photometer/colorimeter (which the Lennie lab has) and a serial port adaptor (use the one from the Carrasco lab it is a white Keyspan USA-28 and says Carrasco Lab on it–the one that is in the bag with the photometer is a white translucent Keyspan USA-28X B and doesn't seem to work properly). The serial port interface for matlab is included in the mgl distribution but can also be found on the Mathworks website [1]. To use the Keyspan USA-28 adaptor you will need to download a driver from [2].

  • Tricky–When using the automated calibration via the serial port, the program will ask you to turn on the PR650 and then press 'return' within 5 secs. You might not want to press 'return' right away, or you may get something like this on the photometer:
(XFER) s/w ver 1.02 

This indicates that you pressed the return while the photometer is waiting for a transfer signal (not sure what it is), and hence entered the XFER mode. If you wait another 2 secs or so it will enter the control mode, now press 'return' you should see this:

(CTRL) s/w ver 1.19 

Basically there is about 2-3 secs time window you should press 'return' to get to this state.

  • Tricky2–When doing the automated calibration, turn off screensavers and energysaver, otherwise the screen will go blank after a while and you'll be measuring luminance of blank sreens.

If you cannot install the serial port interface or don't want to automatically calibrate using the USB cable you can also use the program to run manually with any photometer by typing in the luminance measurements yourself.

The program moncalib will save a calibration file in the local directory. For you to use this calibration file, you can store it in one of two places. Either in your own program directory under a directory called displays:


Or you can store it in the general displays directory


InitScreen should automatically find the correct table by checking your computer name and looking for the file in these two places. If you do not use the standard filename, or have multiple calibrations for the same computer (like if you have multiple monitors calibrated), you can use a specific file by setting myscreen.calibFilename

myscreen.calibFilename = 'mycalibrationfile.mat';
myscreen = initScreen(myscreen);

Note that the calibFilename can be a literal filename as in the above, or you can specify a portion of the name that will get matched in a file from the displays directory (e.g. computername_displayname would matcha any file in the displays directory that looks like *computername_displayname*.mat).

The name of the file usually created by moncalib will be:


Where xxxx is a sequential number starting at 0001 and yymmdd is the date of the calibration. This stores a variable called calib which contains all the information about the calibration. You can quickly plot the data in calib by doing:

load 0001_stimulus-g5_LCD_061004

The most important field of calib is the table field which holds the inverse lookup table to linearize the monitor.

10 bit gamma tables

The NVIDIA GeForce series of video cards have 10 bit gamma tables (these are the only ones we have tested):

  • NVIDIA GeForce FX 6600 (In the G5 in the magnet room)
  • NVIDIA GeForce FX 7300 GT (brownie Mike Landy's psychophysics room)
  • NVIDIA GeForce FX ????? (Jackson the G5 in the psychophysics room)

ATI 10 bit cards:

  • any Randeon card for desktop computers above series 7000 has 10-bits DAC resolution (laptop cards don't have it necessarely or drivers do not access it)
  • some more information about this can be found on Denis Pelli webpage [3] and on the discussion group [4].

It is always the best to use the bit test in moncalib because some drivers do not allow 10-bit control on 10-bit DAC cards. You can also query the display card to see if it says that it supports a 10 bit gamma:

displayInfo = mglDescribeDisplays

Check the field gammaTableWidth to see if it is 10.

Calibration devices

Note that there are some commercially available devices to calibrate monitor screens which create color profiling information (e.g. [5] [6] [7]. We have tested one of these called Spyder2Pro which allows you to linearize the monitor output but found that is not yet suitable for psychophysics purposes. The calibration program crashes when you use the default settings to linearize the monitor (an email to the tech support confirmed this is a bug in their software). Using advanced settings it worked but it could only test luminance at 5 output levels. The linearization that it achieved was not accurate enough when tested with the PR650 (it looked like they are doing some sort of spline fit of the points and the luminance as a function of monitor output level looked like a wavy line around the ideal).

How to run an experiment with the same random sequence as a previous one

You can do this by calling initScreen with the randstate of the previous experiment


This will insure that all the parameters, randVars and segment times are generated with the same random sequence as the previous experiment.

Alternatively, you can run both experiments starting with the same randstate (which can be an integer value). For example


Will run the experiment with exactly the same randomization sequence every time.

software/mgl/taskreferencehowtos.txt · Last modified: 2009/05/01 13:32 (external edit) Creative Commons License Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0