Simple Port Codes & Pulse Trains

 

Background

The recording facilities at MMIL, NYU, and MGH all make use of different technology to send triggers during stimulus presentation.  The MEG system at MMIL and the intracranial recordings at NYU both use digital triggers through the 8 Data pins (pins 2-9) of the parallel port.  Intracranial recordings at MGH, by contrast, uses analog triggers, through a single line cable whose voltage fluctuation are recorded on an EEG channel. The signal in this cable is also controlled through the parallel port.

This difference has practical implications when you’re coding a Presentation script, and so the purpose of this document is to teach you to customize your code for each type of system.

The Presentation software was optimized to work with a setup similar to the one at MMIL/NYU.  These systems can lean on the software’s internal port codes without modification.  That is, you can send unique numeric codes (port_code = 1 to 255) to your data acquisition equipment by setting the appropriate port_code parameter. This document will refer to this practice as Simple Port Codes.

 

MGH, by contrast, can send only one numeric code to the port (due to hardware restrictions, this code must be a 7).  There are a number of ways to circumvent this limitation, but MGH uses pulse trains by convention.  Pulse trains code numbers as brief bursts of a single code.  So to encode a “3” in a MEG data file, you can send three 20 ms codes over the course of 100 ms, which leaves a 20 ms gap to separate the codes.

 

MGH Also accommodates an alternate coding scheme that simulates binary numeric coding. To use this coding, first send a “trigger” pulse, and then alternate pulses of 1 and 0 corresponding to an appropriate binary code. By convention, this coding scheme requires 20ms pulses with a 100ms pulse SOA, so it isn’t ideal for fast tasks. An example :

 

time   0    100   200   300   400   500

pulse  7     7     7     0     0     7

value  Trig  1     2     4     8     16

 

This sequence of pulses would mean 1+2+16=19

A Simple Task

To see how this difference works in practice, let’s take a passive viewing task as an example. Imagine you want to present the numbers 1-3 in order for one second each. The code for this basic task would look something like this

begin;

 

picture {

text { caption = “+”; }txt1;

x = 0; y = 0;

} pic1;

 

trial {

trial_duration = 1000;

     stimulus_event {

           picture pic1;

     }event1;

}mytrial;

 

begin_pcl;

 

loop

int i = 1

until

i > 3

begin

     txt1.set_caption( string( i ) );

     txt1.redraw();

     mytrial.present();

     i = i + 1

end;

 

This script doesn’t send any port codes yet, but the bold sections are the places where differences will emerge between Simple Port Codes and Pulse Trains: event declaration and the execution loop. Let’s assume that you’d like to see distinct codes for each stimulus onset. With Simple Port Codes, that means sending a 1, 2, or a 3, for the relevant stimulus. With Pulse Trains, you’ll need to send a 1 once, twice, or thrice for the relevant stimulus.  The schematic would look like this:

The pulse trains obviously have a more complex event structure.  This fact bears out in the script as well.

 

Event Declaration

The SDL section of a presentation script is often conceptually similar to variable declaration in other scripting languages.  So while we’re creating the events that make up the trials, we’ll need to declare some port codes so that the PCL section will have some codes to modify. See the SDL table for the actual code.

For Simple Port Codes, this declaration is as simple as adding a port_code parameter to your picture stimulus event. This parameter gets added at the same level as the picture declaration, that is to say it is nested inside the event declaration, but not inside the picture declaration. For simple events, you do not even need to add a time parameter, because, the Presentation Default is to start events at the beginning of a trial.

Because you can only declare one port code per event, Pulse Trains require more events than Simple Port Codes. For this task, we’ll need to fire as many as three codes for a given stimulus display, so we’ll have to declare three events per trial (one for the picture and first event code, and two more for additional codes).

The data acquisition device can’t distinguish between repeated identical codes without a delimiter.  Leaving a code-less gap of the same duration as the pulse_width ($pw in the example below) satisfies this need. So the first event happens at 0 ms, the second happens at $pw*2 ms, and so on.  Note that event2 and event3 use the special token nothing{}; as their stimulus declarations. This prevents the code-only events from overwriting the picture stimulus declared in event1.

 

SDL

Simple Port Codes Pulse Trains
 

 

 

 

 

stimulus_event {

picture pic1;

port_code = 3;

}event1;

stimulus_event {

picture pic1;

time = 0;

port_code = 1;

}event1;

stimulus_event {

nothing{};

time = ‘$pw*2’;

port_code = 1;

}event2;

stimulus_event {

nothing{};

time = ‘$pw*4’;

port_code = 1;

}event3;

 

Modifications in PCL

In this script structure, the single trial declaration in SDL is modified for the stimulus parameters in PCL in an execution loop. You can already see this at work in the text declaration (txt1.set_caption( string( i ) );), and the same principle applies to the port codes four the three stimuli.

For the Simple Port Codes case, we can send distinct numerical codes for each event.  Accomplishing this therefore only requires that we modify the port code in event1 using the set_port_code() function.

Things are more complex with pulse trains because each execution loop has three events and corresponding codes to manage. Sending a zero is equivalent to sending no code, so it’s possible to simulate firing one, two, or three successive codes by zeroing out the port codes in events 2 and 3. With a simple task like this one, the loop variable i will be sufficient for the necessary flow control.

The pseudocode for the pulse trains port_codes would read:

IFF i exceeds 1, event2 sends a code.

IFF i exceeds 2, event3 sends a code.

Your flow control logic will vary with your experimental design.

 

PCL

Simple Port Codes Pulse Trains
 

 

 

 

event1.set_port_code( i );

if i > 1 then

event2.set_port_code( 1 );

else

event2.set_port_code( 0 );

end;

 

if i > 2 then

event3.set_port_code( 1 );

else

event3.set_port_code( 0 );

end;

 

Summary

When it comes to sending port codes, there are two principal differences between the MMIL/NYU hardware and the MGH hardware.  The first occurs at event declaration.  Simple Port Codes require that there be one event and one unique code to denote a stimulus event.  Pulse Trains require as many events and port codes as there are possible event types.

The second occurs during PCL execution.  Simple Port Codes require only require that the correct port code be set for any given stimulus event. Pulse trains require that every port code in a train be set correctly for a single stimulus event. The latter case may require the use of flow control statements (e.g. conditionals and loops) to efficiently assign long pulse trains.

It’s worth noting that this is one of many ways to code this particular task.  The important thing to learn from this document is to plan your trial and stimulus events to accommodate your hardware, and do good bookkeeping if you choose to modify those templates in PCL.

If you’d like to see the final versions of these different scripts (they include some headers and other modifications that exceed the scope of this document), you may find them below.

 

codetask.sce

simplecodes.sce

pulsetrains.sce

 

Happy Coding!