Programming Reference:StimulusTask Class
Location
BCI2000/src/shared/modules/application
Synopsis
The StimulusTask class is a base class for application modules that present a sequence of stimuli. You do not use objects of type StimulusTask directly; rather, you implement your own class that inherits from it, and implements specialized behavior building on the base functionality provided by the StimulusTask class.
The StimulusTask class performs sequencing, and dispatches GenericFilter::Process() calls to its virtual member functions. Child classes (descendants) of StimulusTask implement event handlers by overriding its virtual functions, and populate the stimulus-target association map, thereby associating stimulus codes with sets of stimuli, and possible selection targets.
In the BCI2000 core distribution, both the P3SpellerTask and the StimulusPresentationTask are based on the StimulusTask base class, and implement their own specialized behavior on top of it.
Events
Events Summary
The following table indicates which events exist, and the temporal sequence in which they occur. Stimulus presentation proceeds in "phases", which are distinct parts of the stimulus presentation: Each presentation sequence is preceded by a "PreSequence" interval; the sequence itself consists of alternating "Stimulus" and "Inter Stimulus Intervals (ISIs)"; a "PostSequence" follows after the sequence.
Events marked with * may occur multiple times in a row. Events given in square brackets depend on the signal processing module, and may not occur at all; however, when they occur, their place in the temporal sequence will be as specified in the table.
Progress from one application state to the next will occur according to the sequencing parameters, or if requested by a handler via its doProgress output argument (see Input events below).
| Sequence of events | Phase | Typical application behavior | ||
|---|---|---|---|---|
| OnPreflight | ||||
| OnInitialize | ||||
| OnStartRun | display initial message | |||
| DoPreRun* | PreRun | |||
| Loop { | ||||
| OnNextStimulusCode | provide a stimulus code, or 0 to finish run | |||
| OnPreSequence | ||||
| DoPreSequence* | PreSequence | |||
| OnSequenceBegin | determine attended target | |||
| Loop { | ||||
| OnStimulusBegin | present stimulus | |||
| DoStimulus* | Stimulus | |||
| OnStimulusEnd | hide visual stimulus | |||
| OnNextStimulusCode | provide a stimulus code, or 0 to finish sequence | |||
| DoISI* | ISI | |||
| [OnClassInput]* | store classification input (copy/free modes only) -- this event may occur any time during the sequence, and during the post sequence phase | |||
| } | ||||
| OnSequenceEnd | ||||
| DoPostSequence* | PostSequence | |||
| [OnClassResult] | determine selected target (copy/free modes only) | |||
| } | ||||
| OnPostRun | ||||
| DoPostRun* | PostRun | |||
| OnStopRun | display final message | |||
| OnHalt |
Stimulus Code Event
int OnNextStimulusCode
By returning a sequence of stimulus codes, this event handler determines the sequence in which stimuli (or associations thereof) are presented. This handler should return the next element of the current sequence of stimulus codes, or zero to indicate the end of the sequence. A null sequence indicates the end of a run, i.e. the current run will end when OnNextStimulusCode returns two zeros in a row.
The OnNextStimulusCode event handler is mandatory for a StimulusPresentation descendant to implement. Thus, a minimal stimulus presentation application consists of a StimulusPresentation descendant that
- declares its own additional parameters from its constructor,
- checks those parameters for consistency in its OnPreflight handler,
- populates the Association Map in its OnInitialize handler, and
- provides a sequence of stimulus codes in its OnNextStimulusCode event handler.
Events forwarded from the GenericFilter interface
OnPreflight(SignalProperties (r))
OnInitialize(SignalProperties (r))
These events are forwarded from the inherited GenericFilter::Preflight and GenericFilter::Initialize events, with input signal properties as an argument. Within the BCI2000 filter chain, the StimulusTask class always writes its input signal through to its output signal, so no output signal properties are provided to these event handlers.
OnStartRun
OnStopRun
OnHalt
These events are forwarded from GenericFilter's StartRun, StopRun, and Halt events.
Phase transition Events
OnPreSequence
OnSequenceBegin
OnSequenceEnd
OnStimulusBegin(int stimulusCode (r))
OnStimulusEnd(int stimulusCode (r))
OnPostRun
These events are triggered by phase transitions during a run, e.g., the OnPreSequence event handler is called whenever the phase changes from PreRun to PreSequence.
The stimulusCode arguments to the OnStimulusBegin and OnStimulusEnd event handlers contain the stimulus code present in the StimulusCode state variable; the default behavior of these handlers is to present and conceal the respective stimuli. For the remaining event handlers of this category, the default behavior is to do nothing.
Input Events
DoPreRun(GenericSignal (r), bool doProgress (rw))
DoPreSequence(GenericSignal (r), bool doProgress (rw))
DoStimulus(GenericSignal (r), bool doProgress (rw))
DoISI(GenericSignal (r), bool doProgress (rw))
DoPostSequence(GenericSignal (r), bool doProgress (rw))
DoPostRun(GenericSignal (r), bool doProgress (rw))
Each call to GenericFilter::Process() is dispatched to one of these event handlers, depending on the phase in the sequence, with each handler function corresponding to a phase.
These event handlers will typically not be used by a task class that inherits from StimulusTask, unless it needs to modify the standard sequencing behavior, such that it progresses faster or slower from one phase to the next, or subdivides a phase into two or more sub-phases.
Modifying sequencing behavior is possible through the handlers' doProgress argument. doProgress will typically be set to false, except for the last call to the handler during the current phase in the sequence. A handler may modify the application's sequencing behavior by setting the doProgress argument: setting it from false to true will proceed to the next phase earlier than prescribed by the sequencing parameters, and setting it to false from true will defer progressing, such that the handler will be called again, until its doProgress argument is actually true on exit.
Classification Events
Target classification is based on the behavior of the P3TemporalFilter signal processing filter. This filter performs per-stimulus averaging over EEG epochs; once it has acquired the desired amount of epochs, it sets its output to the average wave form, and the StimulusCodeRes state to the respective stimulus code. In conjunction with the LinearClassifier (or other classification filter), this implies that the application module receives, in its input signal, a single classification value for stimulus whenever StimulusCodeRes equals .
OnClassInput(stimulusCode (r), GenericSignal (r))
The OnClassInput event handler is called each time a classification value has been received from the signal processing module. Classification values are stored in a ClassResult object. A StimulusPresentation descendant class may take additional action by implementing its own OnClassInput event handler.
Target* OnClassResult(ClassResult (r))
The StimulusPresentationTask' accumulates classification values in a ClassResult class, and then calls the OnClassResult event handler once classification input has been received for all stimulus codes.
The OnClassResult event handler is supposed to determine a selection target from these classification values. Classification values are provided in a ClassResult object; the OnClassResult handler returns a pointer to a Target object representing the chosen selection target, or a null pointer to indicate that no target has been chosen. On return from the OnClassResult event handler, and in case of a non-null pointer, the target object's Select() method is then called, which typically results in some action associated with the target object in question, such as entering a letter into a speller.
The default OnClassResult handler calls AssociationMap::ClassifyTargets() to translate classification values into selection targets; you may override this behavior by providing your own handler.
Properties
All properties are protected, i.e. intended for use from descendant classes only.
AssociationMap Associations (rw)
An object of type AssociationMap, representing sets of stimuli and selection targets associated with a given stimulus code.
Typically, a stimulus presentation application populates the Associations object with stimuli and targets in its OnInitialize event handler, and relies on the StimulusPresentationTask default mechanisms for stimulus presentation, and target classification.
Often, but not always, there is a 1-to-1-to-1 correspondence between stimuli, stimulus codes, and selection targets; for a detailed discussion of these terms, and how to use the related objects in your own application, refer to Programming Reference:AssociationMap Class.
Target* AttendedTarget (rw)
A pointer that refers to a selection target object, or a null pointer. When non-null, the StimulusType state variable is set based on the AttendedTarget property such that StimulusType is set to 1 whenever the current StimulusCode state variable refers to an Association that contains the specified target.
For a discussion of how stimuli, stimulus codes, and selection targets are related to each other via Association objects, refer to Programming Reference:AssociationMap Class.
GUI::GraphDisplay Display (r)
The Display property provides access to the GUI::GraphDisplay object representing the application module's output window.
ostream AppLog, AppLog.File, AppLog.Screen (w)
Inheriting from ApplicationBase, descendants of StimulusTask have access to the AppLog, AppLog.File, and AppLog.Screen streams which are members of ApplicationBase. These streams allow convenient output into an application log file (AppLog.File), an application log window (AppLog.Screen), and both simultaneously (AppLog).
RandomGenerator RandomNumberGenerator (rw)
An object of type RandomGenerator which behaves according to the user setting in the RandomSeed parameter.
Methods
Methods are declared protected, i.e. for use by descendants only.
DisplayMessage(string)
Displays a text message in the application window. This function is provided for convenience and consistency of appearance; for detailed control over appearance of text messages, add your own TextField object to the GUI::GraphDisplay represented by the Display property.
Parameters
WindowBackgroundColor
The window's background color, given as an RGB value. For convenience, RGB values may be entered in hexadecimal notation, e.g. 0xff0000 for red.
PreRunDuration
The duration of the pause preceding the first sequence. Given in sample blocks, or in time units when immediately followed with 's', 'ms', or similar.
PostRunDuration
Duration of the pause following last sequence. Given in sample blocks, or in time units when immediately followed with 's', 'ms', or similar.
PreSequenceDuration
Duration of the pause preceding sequences (or sets of intensifications). Given in sample blocks, or in time units when immediately followed with 's', 'ms', or similar.
In free or copy mode, the PreSequenceDuration and PostSequenceDuration parameters may not go below twice the value of the StimulusDuration parameters, in order to allow for presentation of FocusOn and Result announcement stimuli.
PostSequenceDuration
Duration of the pause following sequences (or sets of intensifications). Given in sample blocks, or in time units when immediately followed with 's', 'ms', or similar.
When used in conjunction with the P3TemporalFilter, this value needs to be larger than the EpochLength parameter. This allows classification to complete before the next sequence of stimuli is presented.
StimulusDuration
For visual stimuli, the duration of stimulus presentation. For auditory stimuli, the maximum duration, i.e. playback of audio extending above the specified duration will be muted. Given in sample blocks, or in time units when immediately followed with 's', 'ms', or similar.
EarlyOffsetExpression
Allows the specification of an Expression that is constantly monitored during stimulus presentation. When the value of the Expression transitions from zero to non-zero, the stimulus is aborted early, even if the StimulusDuration has not yet elapsed. For example, set this Expression to KeyDown==32 and start your source module with the --LogKeyboard=1 flag: then the subject will be able to advance the stimulus sequence manually by pressing the space key.
ISIMinDuration, ISIMaxDuration
Minimum and maximum duration of the inter-stimulus interval. During the inter-stimulus interval, the screen is blank, and audio is muted.
Actual inter-stimulus intervals vary randomly between minimum and maximum value, with uniform probability for all intermediate values. Given in sample blocks, or in time units when immediately followed with 's', 'ms', or similar. Note that temporal resolution is limited to a single sample block.
InterpretMode
An enumerated value selecting on-line classification of evoked responses:
- 0: no target is announced "attended", and no classification is performed;
- 1: online or free mode: classification is performed, but no "attended target" is defined;
- 2: copy mode: "attended" targets are defined, classification is performed.
DisplayResults
Switches result display of copy/free spelling on or off. In the P3Speller, setting DisplayResults to 'off' will disable execution of all speller commands (such as switching matrices) as well.
MinimumEvidence
NOTE: If you are using your own classifier, this feature will not work properly unless your classifier's output matches certain criteria. Make sure to read these notes on how to use a different classifier.
By default, target selection is performed without considering the actual amount of evidence that favors the selected target over other targets. Although the selected target will always be a target with maximum classification score (i.e., evidence), other targets may have the same or a similar score. It may be useful to omit classification in such situations altogether, by specifying a minimum amount of evidence that must exist in favor of the selected target, when compared to the next-best target. When used together with the AccumulateEvidence option, this allows to dynamically control the number of stimulus presentations, by simply repeating stimulus sequences until a sufficient amount of evidence has been collected.
Setting MinimumEvidence to 0 or to a negative number will result in default behavior, i.e. there will be a target selection each time classification scores are received from the SignalProcessing module. For values greater 0, the amount of selection errors will become smaller as the value of MinimumEvidence is increased; this increases the amount of information contained in each selection. At the same time, it becomes more and more unlikely that a selection will occur at all within a certain amount of time; this decreases the amount of information transmitted per time (information flow, or bitrate). In between, a certain value will correspond to an optimal compromise between selection errors, and selection duration. At this point, the flow of information is maximized.
The meaning of the actual number entered into the MinimumEvidence parameter is relative to the amount of within-class variance present in the classification score. An evidence of 0 means a 50:50 chance for correct classification. Increasing the evidence value by two standard deviations corresponds to an improvement by a factor of roughly 88:12, four standard deviations correspond to (88:12)^2=(98:2) ... etc, approaching perfect classification as evidence increases towards infinity.
In classifier training, classifier weights may be normalized such that within-class variance is 1 (this is done by BCI2000Analysis, and recent versions of the P300Classifier tool). In this case, you may use the following equations to convert between the MinimumEvidence parameter , and the correct classification chance :
.
For large , this relationship may be approximated and expressed in terms of error probability :
.
Thus, the evidence value roughly corresponds to twice the number of leading zeros in the desired error probability, if classifier weights are normalized. Some values are provided in the following table:
| Selection Error | Evidence |
|---|---|
| 5% | 3 |
| 1% | 4.6 |
| 0.5% | 5.3 |
| 0.1% | 6.9 |
| 0.05% | 7.6 |
| 0.01% | 9.2 |
AccumulateEvidence
By default, only those classification scores are used which have been received from the signal processing module immediately prior to classification. When AccumulateEvidence is set, classification scores are accumulated until a selection is actually performed. Typically, accumulated classification scores will have higher evidence values, such that a selection threshold set with MinimumEvidence will be eventually crossed after scores have been accumulated for some time.
This allows for dynamically choosing the number of stimulus repetitions in a P300 paradigm, by setting the number of stimulus repetitions to 1, and setting the MinimumEvidence parameter to a value greater zero.
In addition, accumulated overall evidence will not increase if there is no consistent evidence in favor of a certain target. Thus, it is possible to operate a P300 BCI in a quasi-asynchronous mode by using AccumulateEvidence, and choosing a MinimumEvidence value that is large enough to make accidental selection unlikely. In this configuration, no selection will be made unless the BCI user is actually concentrating on a target for a number of stimulus presentations, resulting in consistently accumulating evidence for that target.
NOTE: If you are using your own classifier, this feature will not work properly unless your classifier's output matches certain criteria. Make sure to read these notes on how to use a different classifier.
PhotoDiodePatch
Display a photo diode patch on the stimulus window. Recording from a photo diode located on that patch will allow triggering on actual stimulus delivery (see User_Reference:P3TemporalFilter#OnsetExpression).
PhotoDiodePatchHeight
Photo diode patch height in relative coordinates (between 0 and 1).
PhotoDiodePatchWidth
Photo diode patch width in relative coordinates (between 0 and 1).
PhotoDiodePatchLeft
Photo diode patch left position in relative coordinates (between 0 and 1).
PhotoDiodePatchTop
Photo diode patch top position in relative coordinates (between 0 and 1).
PhotoDiodePatchShape
Photo diode patch shape: 0 rectangle, 1 ellipse.
PhotoDiodePatchActiveColor
Photo diode patch color when active (RGB color in format 0xrrggbb).
PhotoDiodePatchInactiveColor
Photo diode patch color when inactive, (RGB color in format 0xrrggbb, use 0xff000000 for transparent).
PhotoDiodePatchExpression
Photo diode patch expression, determines active state by evaluating to nonnull. Defaults to StimulusBegin>0.
States
StimulusCode
The numerical ID of the stimulus being presented (16 bit).
StimulusType
This state is 1 during presentation of an attended stimulus, and 0 otherwise. The notion of an "attended" stimulus requires data recording in copy mode.
StimulusBegin
This state is 1 during the first block of stimulus presentation, and 0 otherwise.
PhaseInSequence
This state is 1 during pre-sequence, 2 during sequence and 3 during post-sequence (see Timeline).
PauseApplication
While this state is set to 1, no task processing occurs, i.e. the task is paused, and may be resumed by setting PauseApplication to 0.
Timeline
See also
User Reference:P3TemporalFilter, User Reference:P3SpellerTask, User Reference:StimulusPresentationTask;
Programming Reference:Association Class, Programming Reference:AssociationMap Class, Programming Reference:Stimulus Class, Programming Reference:Target Class, Programming Reference:ClassResult Class
