FEP VisuomotorJoystickTask: Difference between revisions
Created page with "==Synopsis== '''FEP_VisuomotorJoystickTask''' is a BCI2000 application module that implements a center-out visuomotor reaching task controlled with a USB HID joystick. The task presents hidden changes in the relationship between joystick movement and cursor movement while recording behavioral responses synchronized with the BCI2000 data stream. The task includes: * Normal and inverted joystick-to-cursor mappings. * Unannounced mapping changes between trials. * Six seq..." |
m Major task changes documenting reliability jitter changes |
||
| (7 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
==Synopsis== | ==Synopsis== | ||
'''FEP_VisuomotorJoystickTask''' is a BCI2000 application module | '''FEP_VisuomotorJoystickTask''' is a BCI2000 application module implementing a center-out visuomotor reaching task designed to investigate how participants adapt their behavior when the relationship between their actions and sensory consequences changes unexpectedly. | ||
The task includes: | Participants control a cursor using a USB HID joystick and repeatedly move from a central starting location to peripheral targets. The joystick-to-cursor mapping is treated as a hidden environmental state: on a given trial, joystick movement may produce either a normal cursor movement or an inverted cursor movement. These mappings are not explicitly cued to the participant. | ||
The task was developed in the context of the '''Free Energy Principle (FEP)''' and related theories of predictive processing and active inference. In this framework, an agent maintains an internal model of the causes of its sensory observations and uses incoming evidence to update that model. When observations conflict with the agent's expectations, the agent may need to revise its estimate of the current hidden state. | |||
The present task operationalizes this problem using a simple visuomotor environment. The hidden state is the current joystick-to-cursor mapping. Participants first accumulate experience with particular mappings and mapping frequencies, creating different histories of prior exposure. The mapping can then change without warning, requiring the participant to infer from the resulting cursor behavior that the current sensorimotor relationship has changed. | |||
The task therefore allows behavioral measurements to be related to three major features of inference: | |||
* '''Prior experience''': Different experimental blocks expose participants to different frequencies of Normal and Inverted mappings. | |||
* '''Unexpected state changes''': Mapping changes may occur between trials without an explicit visual cue. | |||
* '''Behavioral updating''': Reaction time, movement time, total time, and cursor trajectory may be examined following mapping switches and across subsequent trials. | |||
The experiment also includes a configurable visual sensory-reliability manipulation. On selected trials, Gaussian spatial noise perturbs the displayed cursor without changing the task-logic cursor position. High reliability has no visual noise; Medium and Low reliability use configurable noise amplitudes. This is a visual-feedback noise manipulation, not a cursor-gain manipulation. | |||
Importantly, the software does not itself compute free energy, prediction error, posterior probability, Bayesian belief, or another formal FEP quantity. Instead, it creates a controlled hidden-state visuomotor task whose behavioral and neural data may be used to investigate questions motivated by those theories. | |||
The current implementation includes: | |||
* Normal and inverted joystick-to-cursor mappings. | * Normal and inverted joystick-to-cursor mappings. | ||
* Unannounced mapping changes between trials. | * Unannounced mapping changes between trials. | ||
* Six sequential experimental block roles with different mapping frequencies. | * Six sequential experimental block roles with different mapping frequencies. | ||
* | * High, Medium, and Low visual sensory-reliability conditions with configurable Gaussian cursor noise (disabled by default). | ||
* Mapping-switch, prior-condition, and trials-since-switch state logging. | * Mapping-switch, prior-condition, and trials-since-switch state logging. | ||
* A | * A minimal participant introduction. | ||
* A | * A Normal-mapping joystick sandbox. | ||
* Reaction-time, movement-time, total-time, cursor, joystick, target, | * Reaction-time, movement-time, total-time, displayed and true cursor, joystick (when logging is enabled), target, mapping, reliability, noise, and researcher-control states in the BCI2000 data stream. | ||
* Experimenter controls for resetting, skipping, pausing, and resuming the task. | |||
The | The participant is not explicitly informed about mapping changes, sensory-reliability conditions, mapping probabilities, or experimental block structure. Visual noise may nevertheless be perceptible. | ||
==Location== | ==Location== | ||
Upon completion of an SVN update or checkout of the relevant source tree, the current FEP Visuomotor Joystick Task is located in: | |||
< | <pre> | ||
src/custom/FEP_VisuomotorJoystickTask/ | |||
</pre> | |||
The main implementation is contained in: | The main implementation is contained in: | ||
< | <pre> | ||
FEP_VisuomotorJoystickTask.cpp | |||
</pre> | |||
with the corresponding header and build configuration in: | with the corresponding header and build configuration in: | ||
| Line 35: | Line 54: | ||
The application is included from: | The application is included from: | ||
< | <pre> | ||
src/custom/CMakeLists.txt | |||
</pre> | |||
The CMake target | The current CMake target is: | ||
<pre> | <pre> | ||
FEP_VisuomotorJoystickTask_custom | |||
</pre> | </pre> | ||
The module uses <code>NOBUNDLE</code> in its <code>bci2000_add_application_module</code> declaration. Its Windows executable is typically named: | |||
<pre> | |||
FEP_VisuomotorJoystickTask_custom.exe | |||
</pre> | |||
A separate <code>src/custom/FEP_VisuomotorJoystickTask_pacing_test/</code> diagnostic module is also included in the custom build. That module is for investigating a rendering/pacing issue and is not the experimental task. | |||
==Versioning== | ==Versioning== | ||
| Line 56: | Line 84: | ||
Developed in the Friedman Lab. | Developed in the Friedman Lab. | ||
Contact: | Contact: speer@wustl.edu | ||
===Version History=== | ===Version History=== | ||
====New version: 19 October 2026==== | |||
This updated version replaces the earlier Normal/High cursor-gain manipulation with configurable High/Medium/Low visual sensory reliability; introduces temporally correlated Gaussian cursor noise and separate true-versus-displayed cursor states; adds researcher controls for skipping trials, blocks, introduction, and sandbox and for pausing/resuming; adds associated BCI2000 event and reliability states; provides configurable cursor and target diameters; and redesigns the diagnostic window to show real-time timings and run averages. The experimental mapping and six block roles remain in place. The current build uses the <code>FEP_VisuomotorJoystickTask_custom</code> target. | |||
No independent numeric version identifier is declared in the inspected module; the date above identifies this documentation update and implementation revision, not an asserted source revision number. | |||
The current FEP task is maintained under <code>src/custom</code>. In the inspected development checkout, the module does not currently have independent Git or SVN revision history. | |||
An earlier inspected BCI2000 build was produced using: | |||
== | * BCI2000 framework 3.6.9535 | ||
* BCI2000 source revision 9535 | |||
* Visual Studio 2022 / MSVC 19.35 | |||
* Release x64 configuration | |||
These values refer to an inspected BCI2000 build containing the module, not to an independently verified revision number of the current FEP task. | |||
==Scientific Motivation== | |||
===Free Energy Principle=== | |||
The Free Energy Principle proposes that biological agents maintain internal models of the causes of their sensory inputs and continually update those models in order to reduce discrepancies between predicted and observed sensory states. | |||
A useful way to interpret the present task is as a hidden-state inference problem. | |||
The participant directly observes: | |||
* Joystick movement. | |||
* Cursor movement. | |||
* Target position. | |||
* The sensory consequences of each movement. | |||
The | The participant is not directly told: | ||
* Which joystick-to-cursor mapping is currently active. | |||
* Whether the mapping has changed. | |||
* The probability of a mapping occurring. | |||
* The current experimental block. | |||
* Whether visual sensory reliability has changed. | |||
The current mapping therefore acts as a hidden environmental state that must be inferred from the relationship between action and observed cursor movement. | |||
For example, after many Normal trials, a participant may expect the cursor to move in the same direction as the joystick. If the next trial unexpectedly uses the Inverted mapping, the observed cursor movement conflicts with that expectation. Subsequent behavior can then be examined to determine how rapidly the participant adjusts to the new mapping. | |||
===Why the Task Was Developed=== | |||
The task was designed to create an experimentally controlled situation in which prior experience and new sensory evidence can come into conflict. | |||
Several aspects of the experiment make this possible. | |||
First, the frequency of Normal and Inverted mappings changes across blocks. This changes the participant's recent history of mapping exposure. | |||
Second, mapping changes are not announced. Participants therefore cannot simply follow an explicit instruction telling them which mapping to use. | |||
Third, the task records the exact trials on which the mapping changes and the number of trials that have occurred since the most recent switch. | |||
This makes it possible to compare behavior: | |||
* Before and after an unexpected mapping change. | |||
* On switch versus non-switch trials. | |||
* Across successive trials following a switch. | |||
* Under different histories of Normal and Inverted mapping exposure. | |||
* Under High, Medium, and Low visual sensory reliability (when enabled). | |||
The task can therefore be used to investigate how prior experience influences behavioral adaptation to unexpected changes in sensorimotor contingencies. | |||
===Implementation Versus Theory=== | |||
The current application implements the experimental manipulations required for this type of analysis, but it does not contain an explicit computational model of the participant. | |||
In particular, the software does not calculate: | |||
* Variational free energy. | |||
* Prediction error. | |||
* Posterior probability. | |||
* Belief distributions. | |||
* Bayesian surprise. | |||
* Learning rate. | |||
* Adaptation score. | |||
These quantities, if used, must be estimated during offline behavioral or neural analysis. | |||
==Functional Description== | |||
===Mapping Conditions=== | |||
The | The FEP task uses two joystick-to-cursor mappings: | ||
{| class="wikitable" | |||
! <code>TaskCondition</code> | |||
! Mapping | |||
! Description | |||
|- | |||
| 0 | |||
| Normal | |||
| Joystick displacement moves the cursor in the corresponding direction. | |||
|- | |||
| 1 | |||
| Inverted | |||
| Joystick displacement moves the cursor in the opposite direction on both axes. | |||
|} | |||
The current mapping is not visually indicated to the participant. | |||
Unlike the earlier USBHIDJoystickTask, the FEP task does not use the terms '''Automatic''' and '''Controlled''' in its implementation. | |||
===Behavioral Measurements=== | |||
The task records information that may be used to examine: | |||
* Reaction time. | |||
* Movement time. | |||
* Total target-acquisition time. | |||
* Cursor trajectory. | |||
* Initial movement direction. | |||
* Trajectory curvature. | |||
* Performance immediately following a mapping switch. | |||
* Performance as a function of trials since the previous switch. | |||
* Effects of different mapping-frequency contexts. | |||
* Effects of High, Medium, and Low visual sensory reliability when the manipulation is enabled. | |||
* Differences between true and displayed cursor trajectories under visual noise. | |||
==Experiment Structure== | |||
Each run proceeds in the following order: | |||
# | # Introduction (unless skipped by the researcher). | ||
# Joystick sandbox (unless bypassed or skipped). | |||
# Experimental block 1, if enabled. | |||
# Experimental block 2, if enabled. | |||
# Experimental block 3, if enabled. | |||
# Experimental block 4, if enabled. | |||
# Experimental block 5, if enabled. | |||
# Experimental block 6, if enabled. | |||
# Experiment completion. | |||
Experimental block transitions are not announced to the participant. Skipping the introduction using the researcher window enters the experiment directly and also bypasses the sandbox. Trial and block skipping can change which trials are actually performed. | |||
Each experimental trial proceeds as follows: | |||
The | # The participant returns the cursor to the center. | ||
# The participant holds the cursor within the center region. | |||
# A yellow warning cue appears. | |||
# A pre-target delay occurs. | |||
# A peripheral target appears. | |||
# The participant moves the cursor toward the target. | |||
# The target is acquired. | |||
# A short feedback interval occurs. | |||
# The task advances to the next trial. | |||
==Introduction== | |||
The introduction provides only the minimum information needed to operate the task. | |||
The participant is shown: | The participant is shown: | ||
| Line 195: | Line 256: | ||
</pre> | </pre> | ||
A rising press of <code>JoystickButtons1</code> advances the | During the introduction: | ||
* <code>Introduction=1</code> | |||
* <code>TutorialPhase=1</code> | |||
* <code>TaskPhase=0</code> | |||
* The cursor is hidden. | |||
* The center marker is hidden. | |||
* The warning cue is hidden. | |||
* The target is hidden. | |||
* The central cross is hidden. | |||
* The progress bar is hidden. | |||
A rising press of <code>JoystickButtons1</code> advances to the sandbox. The experimenter may instead select <code>SKIP INTRODUCTION</code> (with confirmation), which enters the experiment directly and bypasses the sandbox. | |||
The participant is not told about: | |||
* Normal versus Inverted mappings. | |||
* Mapping switches. | |||
* Changes in visual sensory reliability. | |||
* Mapping probabilities. | |||
* Experimental blocks. | |||
* Prior conditions. | |||
==Sandbox== | ==Sandbox== | ||
| Line 207: | Line 285: | ||
The participant sees: | The participant sees: | ||
* | * A black cursor. | ||
* | * A gray center marker. | ||
* | * A black center cross. | ||
* No peripheral target. | * No peripheral target. | ||
* No warning cue. | * No warning cue. | ||
* No | * No progress bar. | ||
The | The participant is shown: | ||
<pre> | <pre> | ||
| Line 231: | Line 309: | ||
* <code>TaskCondition=0</code> | * <code>TaskCondition=0</code> | ||
* Normal direct mapping is used. | * Normal direct mapping is used. | ||
* | * There is no gain manipulation; the sandbox uses direct Normal mapping without visual noise. | ||
* No targets are generated. | * No targets are generated. | ||
* No experimental timing phases occur. | * No experimental timing phases occur. | ||
The sandbox ends | The sandbox ends when both of the following conditions are satisfied: | ||
# The cursor is inside the center tolerance region. | # The cursor is inside the center tolerance region. | ||
# A new joystick-button press occurs. | # A new joystick-button press occurs. | ||
Because continuation uses rising-edge detection, the participant must release the button after leaving the introduction screen before pressing it again to leave the sandbox. The researcher can also select <code>SKIP SANDBOX</code> to enter the experiment. | |||
When the sandbox finishes: | When the sandbox finishes: | ||
* <code>Introduction</code> | * <code>Introduction</code> becomes 0. | ||
* <code>TutorialPhase</code> | * <code>TutorialPhase</code> becomes 0. | ||
* <code>TaskPhase</code> becomes 1. | * <code>TaskPhase</code> becomes 1. | ||
* Experimental block and trial states become active. | * Experimental block and trial states become active. | ||
==Experimental Blocks== | ==Experimental Blocks== | ||
The task | The task contains six predefined block roles. | ||
There is no <code>ExperimentMode</code> parameter. | There is no <code>ExperimentMode</code> parameter. | ||
A block may be omitted by setting its trial-count parameter to 0. | |||
<code>TaskBlock</code> retains the original block-role number, so block numbers may skip values when one or more blocks are disabled. | |||
{| class="wikitable" | {| class="wikitable" | ||
| Line 271: | Line 341: | ||
! Trial-count parameter | ! Trial-count parameter | ||
! <code>PriorCondition</code> | ! <code>PriorCondition</code> | ||
! Mapping composition | |||
|- | |||
| 1 | |||
| <code>BaselineTrials</code> | |||
| 0, Fixed | |||
| 100% Normal | |||
|- | |||
| 2 | |||
| <code>InitialInvertedTrials</code> | |||
| 0, Fixed | |||
| 100% Inverted | |||
|- | |||
| 3 | |||
| <code>ReturnNormalTrials</code> | |||
| 0, Fixed | |||
| 100% Normal | |||
|- | |||
| 4 | |||
| <code>MixedTrials</code> | |||
| 1, HiddenMixed | |||
| Approximately 50% Normal and 50% Inverted | |||
|- | |||
| 5 | |||
| <code>StrongPriorTrials</code> | |||
| 2, StrongNormal | |||
| Approximately 90% Normal and 10% Inverted | |||
|- | |||
| 6 | |||
| <code>BalancedPriorTrials</code> | |||
| 3, Balanced | |||
| Approximately 50% Normal and 50% Inverted | |||
|} | |||
===Blocks 4 and 6=== | |||
For blocks 4 and 6: | For blocks 4 and 6: | ||
* <code>floor(N/2)</code> trials are assigned the Inverted mapping. | * <code>floor(N/2)</code> trials are assigned the Inverted mapping. | ||
* | * All remaining trials are assigned the Normal mapping. | ||
* If the | * If the number of trials is odd, the additional trial is Normal. | ||
===Block 5=== | |||
Block 5 contains a strongly Normal-dominant mapping distribution. | |||
Approximately 10% of trials are assigned the Inverted mapping, using a rounded fixed trial count. | |||
The remaining trials are Normal. | |||
This is not implemented as an independent 10% switch probability on each trial. | |||
===Pseudorandomization=== | ===Pseudorandomization=== | ||
For blocks 4 through 6, mapping order is pseudorandomized. | |||
The task attempts up to 64 candidate shuffles. | |||
A candidate is preferred when: | |||
* | * It does not strictly alternate throughout sequences of at least four trials. | ||
* | * It does not contain excessively long runs of one mapping. | ||
The maximum | The preferred maximum run length is: | ||
<pre> | <pre> | ||
| Line 340: | Line 417: | ||
using integer division. | using integer division. | ||
If no candidate satisfies the constraints after 64 attempts, the final generated sequence is used. | |||
After the mapping sequence is generated, sensory-reliability conditions are assigned separately using a dedicated random generator. Rather than an independent shuffle, the assignment algorithm attempts to counterbalance reliability categories across Normal/Inverted mappings and mapping-switch/non-switch trials while preserving the configured counts. Reliability assignment does not alter the mapping order. See [[#Sensory Reliability|Sensory Reliability]]. | |||
==Prior Conditions== | ==Prior Conditions== | ||
<code>PriorCondition</code> | <code>PriorCondition</code> represents the mapping-frequency context associated with the current block. | ||
It does | It does not represent the immediately preceding trial's mapping. | ||
{| class="wikitable" | {| class="wikitable" | ||
! Value | ! Value | ||
! | ! Name | ||
! Meaning | |||
|- | |||
| 0 | |||
| Fixed | |||
| Fixed-mapping context used in blocks 1 through 3. | |||
|- | |||
| 1 | |||
| HiddenMixed | |||
| Approximately balanced hidden mapping context used in block 4. | |||
|- | |||
| 2 | |||
| StrongNormal | |||
| Strongly Normal-dominant mapping context used in block 5. | |||
|- | |||
| 3 | |||
| Balanced | |||
| Approximately balanced mapping context used in block 6. | |||
|} | |||
The mapping used on the preceding trial may be determined offline from the previous trial's <code>TaskCondition</code>. | |||
==Joystick Input== | ==Joystick Input== | ||
Joystick input is | Joystick input is provided through BCI2000's [[User Reference:Logging Input|input logging]] system. | ||
The application | The application reads: | ||
* <code>JoystickXpos</code> | * <code>JoystickXpos</code> | ||
| Line 385: | Line 461: | ||
* <code>JoystickButtons1</code> | * <code>JoystickButtons1</code> | ||
Joystick X and Y values normally range from 0 through 32767. | |||
Each axis is converted into the task's 0-through-1023 coordinate system: | Each axis is converted into the task's 0-through-1023 coordinate system: | ||
| Line 393: | Line 469: | ||
</pre> | </pre> | ||
The converted value is normalized internally: | |||
<pre> | <pre> | ||
| Line 399: | Line 475: | ||
</pre> | </pre> | ||
The FEP application does not itself | The FEP application does not itself enable joystick logging. | ||
Joystick logging should therefore be enabled using BCI2000's <code>LogJoystick</code> option. | |||
See [[User Reference:Logging Input#LogJoystick|LogJoystick]]. | See [[User Reference:Logging Input#LogJoystick|LogJoystick]]. | ||
==Joystick-to-Cursor | ==Joystick-to-Cursor Mapping== | ||
Before target onset, | Before target onset, cursor position normally follows direct absolute joystick position: | ||
<pre> | <pre> | ||
| Line 412: | Line 490: | ||
</pre> | </pre> | ||
The | The mapping transformation used for target-directed movement is activated at target onset. The code defines no <code>HighCursorGain</code> parameter, no <code>CursorGainCondition</code> state, and no high-gain movement condition in this version. | ||
===Anchor Capture=== | ===Anchor Capture=== | ||
When the target appears, the application stores: | |||
* Current joystick X position. | * Current joystick X position. | ||
| Line 422: | Line 500: | ||
* Current cursor X position. | * Current cursor X position. | ||
* Current cursor Y position. | * Current cursor Y position. | ||
* Current mapping direction | * Current mapping direction (<code>+1</code> for Normal or <code>-1</code> for Inverted). | ||
These values form the anchor for transformed | These values form the anchor for transformed movement. Because joystick displacement relative to the anchor is initially zero, activating the transformed mapping does not cause an immediate cursor jump. | ||
===Normal Mapping=== | |||
With Normal mapping, the cursor follows the joystick directly: | |||
<pre> | <pre> | ||
| Line 438: | Line 513: | ||
</pre> | </pre> | ||
===Inverted Mapping | ===Inverted Mapping=== | ||
After target onset on an Inverted trial: | |||
<pre> | <pre> | ||
| Line 447: | Line 522: | ||
</pre> | </pre> | ||
Both axes are inverted. | Both axes are inverted. Cursor coordinates are constrained to the normalized range <code>[0, 1]</code>. While returning from a preceding anchored Inverted trial, that preceding transformation may remain active until the joystick returns to its stored anchor. | ||
The cursor position resulting from mapping and clipping, but before sensory noise, is called the <b>true cursor</b>. Sensory noise perturbs only the <b>displayed cursor</b>. | |||
==Sensory Reliability== | |||
< | The current implementation manipulates visual sensory reliability using trial-wise Gaussian spatial noise added to the displayed cursor. This replaces the cursor-gain manipulation described in earlier versions. Sensory reliability is disabled by default (<code>EnableSensoryReliability=0</code>). | ||
===Reliability Conditions=== | |||
{| class="wikitable" | |||
! <code>SensoryReliabilityCondition</code> | |||
! Condition | |||
! Visual-noise standard deviation | |||
! Description | |||
|- | |||
| 0 | |||
| High | |||
| 0 pixels | |||
| Noise-free visual cursor | |||
|- | |||
| 1 | |||
| Medium | |||
| <code>MediumReliabilityNoiseStd</code> (default 5 pixels) | |||
| Gaussian cursor-position noise | |||
|- | |||
| 2 | |||
| Low | |||
| <code>LowReliabilityNoiseStd</code> (default 15 pixels) | |||
| Larger Gaussian cursor-position noise | |||
|} | |||
The noise standard deviations are specified in reference-display pixels, normalized using the task's nominal 1000 by 750 coordinate system. Noise affects only the cursor during the <code>TargetVisible</code> phase; the target, center marker, warning marker, cross, and joystick input are not perturbed. | |||
</ | |||
=== | ===Enabling Reliability by Block=== | ||
When <code>EnableSensoryReliability=0</code>, all trials use High reliability and no visual noise is applied, regardless of the requested proportions or block list. Therefore, <code>SensoryReliabilityCondition=0</code> does not by itself establish that reliability manipulation was enabled. | |||
< | When enabled, reliability conditions are assigned only within the numbered blocks listed in <code>SensoryReliabilityBlocks</code>, which defaults to blocks 4, 5, and 6. Blocks not listed always use High reliability. The block list may instead select any subset of the six block roles. A block disabled by setting its trial count to zero has no trials to assign. | ||
===Reliability Assignment and Counterbalancing=== | |||
For each enabled block, counts for High, Medium, and Low trials are calculated from the configured proportions by taking their floors and distributing remaining trials according to the largest fractional remainders. The result matches the block's total trial count. | |||
The application then uses a dedicated <code>std::mt19937</code> generator to assign those conditions in a randomized trial order. The selection score favors counterbalancing reliability across (1) Normal versus Inverted mapping and (2) mapping-switch versus non-switch trials, subject to the remaining required condition counts. Thus reliability assignment is not a wholly independent shuffle of the mapping sequence. Exact balance in small blocks or uneven sequences is not guaranteed. | |||
The | Reliability is assigned after the Normal/Inverted mapping sequence has been built and does not change that sequence. Only mapping changes, not reliability changes, generate <code>MappingSwitch</code> events. The dedicated noise/assignment seed is distinct from BCI2000's mapping/target random-number generator. | ||
The configured proportions default to 0.34 High, 0.33 Medium, and 0.33 Low, and their sum must equal 1 within <code>1e-6</code>. Low-reliability noise SD must be at least Medium-reliability noise SD. | |||
===Temporally Correlated Visual Noise=== | |||
X and Y noise are generated from independent Gaussian innovations and evolved over processing updates as: | |||
<pre> | <pre> | ||
1 | a = exp(-elapsedSeconds / correlationTimeSeconds) | ||
noiseX = a * previousNoiseX + SD * sqrt(1 - a*a) * N_X(0,1) | |||
noiseY = a * previousNoiseY + SD * sqrt(1 - a*a) * N_Y(0,1) | |||
</pre> | </pre> | ||
The | The temporal correlation time is set by <code>SensoryNoiseCorrelationTimeMs</code> (default 100 ms); a value of zero produces independent innovations on each update. Each trial's noise generator is initialized from the effective seed and trial/block identity. Noise begins at zero at target onset, so the process builds up rather than beginning with stationary variance. Noise is cleared when the task leaves the target-visible phase and on trial reset or skip. | ||
The displayed cursor is calculated as: | |||
<pre> | |||
displayedX = clamp(trueX + noiseX / 1000, 0, 1) | |||
displayedY = clamp(trueY + noiseY / 750, 0, 1) | |||
</pre> | |||
The true cursor is used for center detection and target-hit detection. Movement onset is detected from joystick movement. Therefore a displayed cursor that appears to touch the target is not necessarily counted as a hit, and a true cursor that reaches the target can register a hit despite noise displacing the displayed cursor away from it. | |||
===Noise Seeds and State Encoding=== | |||
<code>SensoryNoiseSeed</code> defaults to 1. Setting it to 0 selects an automatically generated effective seed, recorded in <code>SensoryNoiseSeedEffective</code> and reported in the BCI2000 operator log. | |||
Noise values are stored as positive integer states with an offset to represent negative noise; the configured SD is stored in hundredths of a pixel: | |||
== | <pre> | ||
noiseX_pixels = (SensoryNoiseX - 1073741824) / 100 | |||
noiseY_pixels = (SensoryNoiseY - 1073741824) / 100 | |||
noiseSD_pixels = SensoryNoiseStd / 100 | |||
</pre> | |||
The recorded <code>TrueCursorX/Y</code> and <code>CursorX/Y</code> coordinates are quantized to the task's 0–1023 range. The noise states represent the generated visual perturbation before final boundary clipping; consequently, the difference between displayed and true coordinates may not equal the encoded noise exactly near display edges. | |||
<b>Important:</b> <code>TrueCursorX/Y</code> is post-mapping, pre-noise position, not a pre-mapping/raw joystick trajectory. The raw joystick trajectory is available from logged joystick input states. | |||
==Return-to-Anchor Behavior== | |||
After an Inverted trial, the previous transformed mapping may temporarily remain active while the participant returns the joystick toward its previous anchor. | |||
The 8- | The stored transformation is released once both joystick axes are within 8 task-coordinate units of the previous joystick anchor. | ||
Normal direct mapping is then restored for ordinary centering. | |||
It is not | This behavior reduces abrupt cursor jumps between transformed target movement and subsequent centering. It is also engaged when an in-progress Inverted trial is skipped or when an Inverted trial is reset during target-visible movement. Skipping an entire block does not explicitly engage this return path, so direct mapping may be restored immediately in that case. | ||
==Mapping Switches== | ==Mapping Switches== | ||
| Line 535: | Line 627: | ||
</pre> | </pre> | ||
Mapping switches occur only at trial boundaries. Changes in sensory reliability alone do not produce mapping-switch events. | |||
They do not occur: | |||
* During target-directed movement. | |||
* During the Feedback phase before the feedback interval ends. | |||
The new mapping is selected when the task advances into the next trial. | |||
===MappingSwitch | ===MappingSwitch=== | ||
<code>MappingSwitch</code> is an event-like state. | <code>MappingSwitch</code> is an event-like state. | ||
| Line 553: | Line 642: | ||
It is: | It is: | ||
* 1 on the processing block that advances into a trial whose mapping differs from the completed trial. | * 1 on the processing block that advances into a new trial whose mapping differs from the completed trial. | ||
* 0 on the following processing block. | * 0 on the following processing block. | ||
* 0 when no mapping change | * 0 when no mapping change occurred. | ||
It should therefore be | It should therefore be interpreted as a one-processing-block pulse. | ||
===TrialsSinceMappingSwitch=== | ===TrialsSinceMappingSwitch=== | ||
<code>TrialsSinceMappingSwitch</code> | <code>TrialsSinceMappingSwitch</code> records how many consecutive no-switch trial transitions have occurred since the most recent mapping change. | ||
Behavior: | Behavior is: | ||
* First experimental trial: 0. | * First experimental trial: 0. | ||
* | * First trial following a mapping switch: 0. | ||
* Next | * Next same-mapping trial: 1. | ||
* Next same-mapping trial: 2. | * Next same-mapping trial: 2. | ||
* And so forth. | * And so forth. | ||
Because the first trial | Because the first experimental trial also begins at 0, <code>TrialsSinceMappingSwitch==0</code> by itself does not identify a switch. | ||
Use <code>MappingSwitch</code> | Use <code>MappingSwitch</code> or a transition in <code>TaskCondition</code> to identify mapping changes. When skip controls are used, event states can be stale or missing for a processing block; compare adjacent trials and consult the skip-state guidance below. | ||
===Example=== | ===Example=== | ||
Consider the following mapping sequence: | |||
<pre> | <pre> | ||
| Line 583: | Line 672: | ||
</pre> | </pre> | ||
Within block 4, the corresponding states would behave approximately as follows: | |||
{| class="wikitable" | {| class="wikitable" | ||
| Line 590: | Line 679: | ||
! <code>MappingSwitch</code> | ! <code>MappingSwitch</code> | ||
! <code>TrialsSinceMappingSwitch</code> | ! <code>TrialsSinceMappingSwitch</code> | ||
! <code>PriorCondition</code> | |||
|- | |||
| - | | Normal | ||
| | | 0 | ||
| 0 | | 0 | ||
| 0 | | Depends on previous trial history | ||
| Depends on | | 1 | ||
| 1 | |- | ||
| - | | Normal | ||
| | | 0 | ||
| 0 | | 0 | ||
| 0 | | Previous value + 1 | ||
| Previous value + 1 | | 1 | ||
| 1 | |- | ||
| - | | Inverted | ||
| | | 1 | ||
| 1 | | 1 on the transition processing block | ||
| 1 | | 0 | ||
| 0 | | 1 | ||
| 1 | |- | ||
| - | | Inverted | ||
| | | 1 | ||
| 1 | | 0 | ||
| 0 | | 1 | ||
| 1 | | 1 | ||
| 1 | |} | ||
| } | |||
==Target Generation== | ==Target Generation== | ||
A new target angle is generated for | A new target angle is generated for each new experimental trial. | ||
<code>TargetAngle</code> ranges from: | |||
<pre> | <pre> | ||
| Line 630: | Line 716: | ||
</pre> | </pre> | ||
The value represents tenths of a degree: | |||
<pre> | <pre> | ||
| Line 642: | Line 728: | ||
</pre> | </pre> | ||
Target coordinates are generated according to: | |||
Target | |||
<pre> | <pre> | ||
| Line 651: | Line 735: | ||
</pre> | </pre> | ||
The unequal normalized X and Y radii correspond to | The unequal normalized X and Y radii correspond to an approximately circular 300-pixel radius in the nominal 1000 by 750 design. | ||
Targets: | Targets: | ||
* Are | * Are black. | ||
* Are not | * Are visually identical across all mapping conditions. | ||
* Are not | * Are visually identical across reliability conditions. | ||
* Are not | * Are not determined by mapping condition. | ||
* Are not determined by reliability condition. | |||
* Are not determined by mapping-switch status. | |||
* May repeat. | * May repeat. | ||
* Are not explicitly angularly balanced. | * Are not explicitly angularly balanced. | ||
* | * Do not appear during the introduction. | ||
* Do not appear during the | * Do not appear during the sandbox. | ||
A target is generated: | A new target is generated: | ||
* For the first experimental trial. | * For the first experimental trial. | ||
* After each completed non-final trial. | * After each completed non-final trial. | ||
Resetting | Resetting a trial does not generate a new target. Advancing after a skipped trial generates a new target; skipping the remaining trials of a block may consume multiple target generations and change the subsequent target sequence. | ||
== | ==Trial Phases== | ||
The current experimental phase is stored in <code>TaskPhase</code>. | |||
<code>TaskPhase | |||
{| class="wikitable" | {| class="wikitable" | ||
! Value | ! Value | ||
! Phase | ! Phase | ||
! | ! Description | ||
! Participant display | |||
|- | |||
| 0 | |||
| Introduction / Sandbox | |||
| No active experimental trial | |||
| Introduction text or sandbox | |||
|- | |||
| 1 | |||
| WaitingForCenter | |||
| Waiting for cursor to enter the center region | |||
| Cursor, gray center, cross | |||
|- | |||
| 2 | |||
| HoldingCenter | |||
| Required uninterrupted center hold | |||
| Cursor, gray center, cross | |||
|- | |||
| 3 | |||
| Warning | |||
| Warning interval | |||
| Cursor, yellow warning marker, cross | |||
|- | |||
| 4 | |||
| PreTargetDelay | |||
| Delay immediately before target appearance | |||
| Cursor, gray center, cross | |||
|- | |||
| 5 | |||
| TargetVisible | |||
| Target-directed movement | |||
| Cursor, black target, cross | |||
|- | |||
| 6 | |||
| Feedback | |||
| Post-acquisition interval | |||
| Cursor and cross | |||
|- | |||
| 7 | |||
| Finished | |||
| Experiment complete | |||
| End message | |||
|} | |||
An experimental target onset may be identified by a transition into: | |||
An experimental target onset may be identified by transition into: | |||
<pre> | <pre> | ||
| Line 822: | Line 825: | ||
TargetHit == 1 | TargetHit == 1 | ||
</pre> | </pre> | ||
Center and target-hit testing use the true, pre-noise cursor, not the displayed noisy cursor. During a skip operation, <code>TaskPhase</code> and related trial states may remain stale because the normal state-update path is bypassed. In particular, a skip directly to completion may not record <code>TaskPhase=7</code>. | |||
==Participant Display== | ==Participant Display== | ||
The participant-facing | The participant-facing window contains: | ||
* | * A light background. | ||
* | * A black cursor (diameter configurable with <code>CursorDiameterPixels</code>). | ||
* | * A black central cross. | ||
* | * A gray center marker. | ||
* | * A larger yellow warning marker. | ||
* | * A black peripheral target (diameter configurable with <code>TargetDiameterPixels</code>). | ||
* Introduction and sandbox text. | * An experimental progress indicator. | ||
* | * Introduction and sandbox instructions in white text on a dark-gray background. | ||
* An experiment-completion message. | |||
The | The participant receives no explicit visual indication of the current mapping, current reliability condition, mapping switches, <code>PriorCondition</code>, block or trial numbers, block transitions, or mapping probabilities. However, noise under Medium and Low reliability may be perceptible as cursor jitter during target-visible movement. | ||
The | The target remains black across all mapping and reliability conditions. There is no explicit success-color cue; the target disappears after successful acquisition. The completion text is the literal string <code>" ended "</code> shown in white. | ||
The target diameter affects both its drawing and the radius used for target-hit testing. The cursor diameter affects its appearance only; it does not change the center tolerance or the target-hit radius. | |||
The | |||
==Diagnostic Window== | ==Diagnostic Window== | ||
| Line 863: | Line 858: | ||
is displayed to the experimenter. | is displayed to the experimenter. | ||
===Displayed Information=== | |||
* Current stage. | During experimental trials, the visible metrics panel displays: | ||
* Original block number | |||
* | * Current task stage. | ||
* | * Original block role number (<code>Block: N / 6</code>), even if some blocks were disabled. | ||
* Trial number within the current block and block trial count. | |||
* Current | * Overall trial number and total configured active trials. | ||
* | * Current Normal or Inverted mapping. | ||
* | * Current High, Medium, or Low reliability condition. | ||
* Configured visual-noise standard deviation for that trial, in pixels. | |||
* Current task phase. | * Current task phase. | ||
* | * Real-time reaction time, movement time, and total time. | ||
* Cumulative overall, Normal-mapping, and Reversed-mapping averages of reaction time, movement time, and total time. | |||
* | |||
The visible panel does <b>not</b> show target angle or coordinates, joystick coordinates, cursor coordinates, mapping-switch flag, trials-since-switch counter, movement-started status, <code>PriorCondition</code>, or a separate reset/status message. Run averages are divided by mapping, not by sensory reliability. A separate diagnostic text label exists internally but is hidden and not populated. | |||
===Diagnostic Controls=== | ===Diagnostic Controls=== | ||
{| class="wikitable" | |||
! Control | |||
! Availability | |||
! Effect | |||
! Confirmation | |||
|- | |||
| <code>RESET CURRENT TRIAL</code> | |||
| Experiment phases 1–5; shown as <code>RESET UNAVAILABLE</code> otherwise | |||
| Restarts the same trial and emits <code>TrialReset</code> | |||
| No | |||
|- | |||
| <code>SKIP TRIAL</code> | |||
| Experiment phases 1–5, not paused | |||
| Abandons the current trial and advances; emits <code>TrialSkipped</code> | |||
| No | |||
|- | |||
| <code>SKIP CURRENT BLOCK</code> | |||
| Experiment phases 1–5, not paused | |||
| Advances past the remaining trials of the block; emits <code>ConditionSkipped</code> | |||
| Yes | |||
|- | |||
| <code>SKIP INTRODUCTION</code> | |||
| Introduction stage, not paused | |||
| Enters the experiment directly, bypassing sandbox; emits <code>IntroductionSkipped</code> | |||
| Yes | |||
|- | |||
| <code>SKIP SANDBOX</code> | |||
| Sandbox stage, not paused | |||
| Enters the experiment; emits <code>SandboxSkipped</code> | |||
| No | |||
|- | |||
| <code>PAUSE</code> / <code>RESUME</code> | |||
| All stages/phases except Finished | |||
| Freezes task-phase progression and resumes with adjusted internal timestamps; uses <code>TaskPaused</code> | |||
| No | |||
|} | |||
There is no separate diagnostic Continue button for the introduction or sandbox. Those stages normally advance using a rising joystick-button press, or may be bypassed using the skip controls. | |||
There is no diagnostic introduction- | |||
==Trial Reset== | ==Trial Reset== | ||
A trial may be manually reset during: | |||
* Waiting for center. | * Waiting for center. | ||
| Line 933: | Line 937: | ||
* Returns the task to <code>WaitingForCenter</code>. | * Returns the task to <code>WaitingForCenter</code>. | ||
* Restarts the phase timer. | * Restarts the phase timer. | ||
* Clears movement-onset timing. | * Clears movement-onset timing. | ||
* Clears target-onset timing. | |||
* Clears <code>MovementStarted</code>. | * Clears <code>MovementStarted</code>. | ||
* Clears <code>TargetHit</code>. | * Clears <code>TargetHit</code>. | ||
* Produces a <code>TrialReset</code> pulse. | * Produces a <code>TrialReset</code> pulse. | ||
* Clears | * Clears timing states. | ||
* | * Resets baseline accumulation. | ||
* Clears | * Clears visual-noise state. | ||
* Keeps the same target. | * Keeps the same target. | ||
* Keeps the same mapping. | * Keeps the same mapping. | ||
* Keeps the same | * Keeps the same sensory-reliability condition. | ||
* Keeps the same block number. | * Keeps the same block number. | ||
* Keeps the same trial number. | * Keeps the same trial number. | ||
* Keeps | * Keeps <code>PriorCondition</code>. | ||
* Keeps | * Keeps <code>TrialsSinceMappingSwitch</code>. | ||
* Does not rebuild or reshuffle the experimental sequence. | * Does not rebuild or reshuffle the experimental sequence. | ||
<code>TrialReset</code> is | <code>TrialReset</code> lasts for one processing block. Resetting an Inverted trial during target-visible movement also enables the return-to-anchor behavior. A reset request is not processed while paused; requests pending at the time of a pause are deferred until processing resumes. | ||
==Skipping Trials, Blocks, and Tutorial Stages== | |||
===Skip Trial=== | |||
<code>SKIP TRIAL</code> is available during experimental phases before Feedback. It emits a one-processing-block <code>TrialSkipped</code> pulse, clears the current movement/timing values, does not count the abandoned trial in completed-trial performance averages, and advances to the next trial or finishes the run. A new target is generated on each non-final advance. Skipping an Inverted trial engages the return-to-anchor behavior. | |||
===Skip Current Block=== | |||
<code>SKIP CURRENT BLOCK</code> requires confirmation and is available during experimental phases before Feedback. It emits <code>ConditionSkipped</code>, advances through all remaining trials in the current block, and starts the next enabled block or finishes the run. It does not register those abandoned trials as completed performance measurements. The operation calls the normal advancement routine repeatedly, consuming target-generation random-number draws. Unlike single-trial skip, it does not explicitly engage return-to-anchor for the interrupted Inverted trial. | |||
===Skip Introduction and Sandbox=== | |||
<code>SKIP INTRODUCTION</code>, after confirmation, emits <code>IntroductionSkipped</code> and enters the experimental phase directly, also bypassing the sandbox. <code>SKIP SANDBOX</code> emits <code>SandboxSkipped</code> and enters the experimental phase from the sandbox. Both are available only in their corresponding stage when not paused. | |||
===Pause and Resume=== | |||
<code>PAUSE</code> is available during introduction, sandbox, and experimental phases, including Feedback, but not Finished. While paused, <code>TaskPaused</code> is held at 1, phase progression and cursor rendering updates stop, and joystick states continue to be sampled. On resumption, internal phase, target-onset, movement-onset, and noise-update timestamps are shifted by the pause duration so that measured task intervals exclude paused time. Skip controls are disabled while paused; pending requests are not executed until processing resumes. | |||
===State-Logging Caveats During Skips=== | |||
The skip-handling branches return early from <code>Process()</code> before the usual end-of-block state publication. Consequently, <code>TaskTrial</code>, <code>TaskBlock</code>, <code>TaskCondition</code>, <code>TaskPhase</code>, <code>TrialsSinceMappingSwitch</code>, and other trial states may show the preceding values on the skip processing block. They normally update on a later ordinary processing block. <code>MappingSwitch</code> can be stale or fail to pulse on the skip block. If a skip ends the run, the usual <code>TaskPhase=7</code> update may never be recorded. Do not rely on a single isolated processing block to reconstruct skip transitions; inspect adjacent samples, skip event states, and trial/block identifiers. These behaviors are analysis considerations of the current implementation, not intended additional task conditions. | |||
==Timing Measurements== | ==Timing Measurements== | ||
Timing | Timing uses <code>std::chrono::steady_clock</code>. | ||
Events are detected | Events are detected during BCI2000 <code>Process()</code> calls, so effective timing resolution is limited by the signal-processing block interval. | ||
===Movement Onset=== | ===Movement Onset=== | ||
The joystick baseline is initialized when center | The joystick baseline is initialized when the center-hold phase begins and updated during center holding. | ||
Movement onset | Movement onset is detected when either joystick axis differs from the center-hold baseline by more than 8 task-coordinate units. | ||
<pre> | <pre> | ||
| Line 982: | Line 1,005: | ||
<pre> | <pre> | ||
target onset -> | target onset -> movement onset | ||
</pre> | </pre> | ||
and | and stored in: | ||
<code>ReactionTimeMs</code> | <code>ReactionTimeMs</code> | ||
| Line 994: | Line 1,017: | ||
<pre> | <pre> | ||
movement onset -> target acquisition | |||
</pre> | </pre> | ||
and | and stored in: | ||
<code>MovementTimeMs</code> | <code>MovementTimeMs</code> | ||
| Line 1,009: | Line 1,032: | ||
</pre> | </pre> | ||
and | and stored in: | ||
<code>TotalTimeMs</code> | <code>TotalTimeMs</code> | ||
Timing values are expressed | Timing values are expressed in rounded milliseconds. | ||
Timing states remain populated through the Feedback phase. When a target is reached without a detected movement onset, reaction and movement times are recorded as 0 and excluded from the corresponding run averages, while total time is still recorded. Paused durations are excluded through adjustment of internal timestamps when resuming. | |||
==Parameters== | ==Parameters== | ||
| Line 1,035: | Line 1,049: | ||
! Default | ! Default | ||
! Range | ! Range | ||
! Description | |||
|- | |||
| <code>BaselineTrials</code> | |||
| Integer | |||
| 20 | |||
| 0-10000 | |||
| Number of Normal trials in block 1 | |||
|- | |||
| <code>InitialInvertedTrials</code> | |||
| Integer | |||
| 5 | |||
| 0-10000 | |||
| Number of Inverted trials in block 2 | |||
|- | |||
| <code>ReturnNormalTrials</code> | |||
| Integer | |||
| 5 | |||
| 0-10000 | |||
| Number of Normal trials in block 3 | |||
|- | |||
| <code>MixedTrials</code> | |||
| Integer | |||
| 20 | |||
| 0-10000 | |||
| Number of approximately balanced trials in block 4 | |||
|- | |||
| <code>StrongPriorTrials</code> | |||
| Integer | |||
| 20 | |||
| 0-10000 | |||
| Number of Normal-dominant trials in block 5 | |||
|- | |||
| <code>BalancedPriorTrials</code> | |||
| Integer | |||
| 20 | |||
| 0-10000 | |||
| Number of approximately balanced trials in block 6 | |||
|} | |||
At least one trial must be configured across the six block parameters. A count of zero disables that block without renumbering the remaining block roles. | |||
===Task Timing and Display=== | |||
= | {| class="wikitable" | ||
! Parameter | |||
! Type | |||
! Default | |||
! Range | |||
! Description | |||
|- | |||
| <code>CenterHoldSeconds</code> | |||
| Float | |||
| 3.0 | |||
| 0.0-60.0 | |||
| Required uninterrupted center-hold duration in seconds | |||
|- | |||
| <code>WarningSeconds</code> | |||
| Float | |||
| 0.5 | |||
| 0.0-60.0 | |||
| Yellow warning interval in seconds | |||
|- | |||
| <code>PreTargetDelaySeconds</code> | |||
| Float | |||
| 0.5 | |||
| 0.0-60.0 | |||
| Delay between warning and target onset in seconds | |||
|- | |||
| <code>FeedbackSeconds</code> | |||
| Float | |||
| 0.5 | |||
| 0.0-60.0 | |||
| Feedback interval following target acquisition, in seconds | |||
|- | |||
| <code>CursorDiameterPixels</code> | |||
| Float | |||
| 16.0 | |||
| 1.0-1000.0 | |||
| Cursor drawing diameter in nominal reference pixels | |||
|- | |||
| <code>TargetDiameterPixels</code> | |||
| Float | |||
| 36.0 | |||
| 1.0-1000.0 | |||
| Target drawing and hit-test diameter in nominal reference pixels | |||
|- | |||
| <code>StimulusDisplay</code> | |||
| Integer | |||
| 0 | |||
| 0 through number of detected displays | |||
| Physical monitor for participant stimuli; 0 uses default BCI2000 placement | |||
|} | |||
On Windows, the application enumerates available monitors for <code>StimulusDisplay</code>. <code>CursorDiameterPixels</code> affects cursor appearance only; <code>TargetDiameterPixels</code> also changes the hit-test radius. | |||
===Sensory Reliability Configuration=== | |||
Type | {| class="wikitable" | ||
! Parameter | |||
! Type | |||
! Default | |||
<code>1.5</code> | ! Range | ||
! Description | |||
|- | |||
| <code>EnableSensoryReliability</code> | |||
| Integer | |||
| 0 | |||
| 0-1 | |||
| Enable trial-wise visual-reliability noise; 0 disables it | |||
|- | |||
| <code>MediumReliabilityNoiseStd</code> | |||
| Float | |||
| 5.0 | |||
| 0.0-1000.0 | |||
| Gaussian noise SD in pixels for Medium reliability | |||
|- | |||
| <code>LowReliabilityNoiseStd</code> | |||
| Float | |||
| 15.0 | |||
| 0.0-1000.0 | |||
| Gaussian noise SD in pixels for Low reliability | |||
|- | |||
| <code>HighReliabilityProportion</code> | |||
| Float | |||
| 0.34 | |||
| 0.0-1.0 | |||
| Target High-reliability trial proportion in enabled blocks | |||
|- | |||
| <code>MediumReliabilityProportion</code> | |||
| Float | |||
| 0.33 | |||
| 0.0-1.0 | |||
| Target Medium-reliability trial proportion in enabled blocks | |||
|- | |||
| <code>LowReliabilityProportion</code> | |||
| Float | |||
| 0.33 | |||
| 0.0-1.0 | |||
| Target Low-reliability trial proportion in enabled blocks | |||
|- | |||
| <code>SensoryNoiseCorrelationTimeMs</code> | |||
| Float | |||
| 100.0 | |||
| 0.0-60000.0 | |||
| Temporal correlation time constant of noise, in milliseconds; zero gives independent innovations | |||
|- | |||
| <code>SensoryNoiseSeed</code> | |||
| Integer | |||
| 1 | |||
| 0-2147483647 | |||
| Dedicated condition-assignment and noise seed; zero automatically selects a seed | |||
|- | |||
| <code>SensoryReliabilityBlocks</code> | |||
| List | |||
| 4 5 6 (BCI2000 definition: <code>3 4 5 6</code>, where 3 is the list length) | |||
| Entries 1-6; no duplicates | |||
| Block role numbers in which reliability conditions may be assigned; an empty list means all trials are High reliability | |||
|} | |||
===Parameter Validation=== | |||
<code> | Preflight requires at least one configured experimental trial, finite and nonnegative reliability values, noise SD for Low reliability not less than that for Medium, reliability proportions summing to 1 within <code>1e-6</code>, valid unduplicated reliability-block numbers, positive cursor and target diameters, nonnegative task durations, and a valid selected display. The published parameter definitions also specify the listed bounds. | ||
<code>HighCursorGain</code> is no longer a parameter in this version. There is no <code>ExperimentMode</code> or <code>ResultsFile</code> parameter. | |||
<code> | |||
==States== | ==States== | ||
The following states are | The following states are declared by the FEP task. Widths and initial values refer to their published definitions; runtime values may change immediately on <code>StartRun()</code> or during <code>Process()</code>. | ||
{| class="wikitable" | {| class="wikitable" | ||
! State | ! State | ||
! Width | ! Width | ||
! Initial | ! Initial Value | ||
! Meaning | |||
|- | |||
| <code>CursorX</code> | |||
| - | | 10 bit | ||
| <code>CursorX</code> | | 512 | ||
| 10 bit | | Displayed horizontal cursor position, after mapping, sensory noise, and clipping (0-1023) | ||
| 512 | |- | ||
| 0-1023 | | <code>CursorY</code> | ||
| 10 bit | |||
| - | | 512 | ||
| <code>CursorY</code> | | Displayed vertical cursor position, after mapping, sensory noise, and clipping (0-1023) | ||
| 10 bit | |- | ||
| 512 | | <code>TaskPhase</code> | ||
| 0-1023 | | 3 bit | ||
| 0 | |||
| - | | Current task phase (0-7) | ||
| <code>TaskPhase</code> | |- | ||
| 3 bit | | <code>TaskCondition</code> | ||
| 0 | | 1 bit | ||
| 0-7 | | 0 | ||
| 0 Normal, 1 Inverted mapping | |||
| - | |- | ||
| <code>TaskCondition</code> | | <code>TargetAngle</code> | ||
| 1 bit | | 12 bit | ||
| 0 | |||
| 0 | | Target angle in tenths of a degree | ||
| 0 Normal, 1 Inverted | |- | ||
| - | | <code>TargetX</code> | ||
| <code>TargetAngle</code> | | 10 bit | ||
| 12 bit | | 512 | ||
| 0 | | Horizontal target coordinate (0-1023) | ||
|- | |||
| Target angle in tenths of a degree | | <code>TargetY</code> | ||
| - | | 10 bit | ||
| <code>TargetX</code> | | 512 | ||
| 10 bit | | Vertical target coordinate (0-1023) | ||
| 512 | |- | ||
| <code>TaskBlock</code> | |||
| Horizontal target coordinate | | 8 bit | ||
| - | | 0 | ||
| <code>TargetY</code> | | Current original experimental block role (1-6; 0 before experiment) | ||
| 10 bit | |- | ||
| 512 | | <code>TaskTrial</code> | ||
| 16 bit | |||
| Vertical target coordinate | | 0 | ||
| - | | Overall 1-based experimental trial number (0 before experiment) | ||
| <code>TaskBlock</code> | |- | ||
| 8 bit | | <code>MovementStarted</code> | ||
| 0 | | 1 bit | ||
| | | 0 | ||
| Level flag indicating detected movement onset during the trial | |||
| - | |- | ||
| <code>TaskTrial</code> | | <code>TargetHit</code> | ||
| 16 bit | | 1 bit | ||
| 0 | | 0 | ||
| | | One-processing-block target-acquisition pulse | ||
| | |- | ||
| - | | <code>TrialReset</code> | ||
| <code> | | 1 bit | ||
| 1 bit | | 0 | ||
| 0 | | One-processing-block manual-reset pulse | ||
| | |- | ||
| | | <code>TrialSkipped</code> | ||
| - | | 1 bit | ||
| <code> | | 0 | ||
| 1 bit | | One-processing-block trial-skip pulse | ||
| 0 | |- | ||
| | | <code>ConditionSkipped</code> | ||
| One-processing-block | | 1 bit | ||
| - | | 0 | ||
| <code> | | One-processing-block current-block-skip pulse | ||
| 1 bit | |- | ||
| 0 | | <code>IntroductionSkipped</code> | ||
| | | 1 bit | ||
| One-processing-block | | 0 | ||
| - | | One-processing-block introduction-skip pulse | ||
| <code> | |- | ||
| 1 bit | | <code>SandboxSkipped</code> | ||
| 0 | | 1 bit | ||
| | | 0 | ||
| One-processing-block mapping-change event | | One-processing-block sandbox-skip pulse | ||
| - | |- | ||
| <code>TrialsSinceMappingSwitch</code> | | <code>TaskPaused</code> | ||
| 16 bit | | 1 bit | ||
| 0 | | 0 | ||
| | | Level flag: 1 while paused; 0 otherwise | ||
|- | |||
| - | | <code>MappingSwitch</code> | ||
| <code>PriorCondition</code> | | 1 bit | ||
| 2 bit | | 0 | ||
| One-processing-block mapping-change event during normal progression; see skip caveats | |||
| 0 | |- | ||
| Current block-level prior | | <code>TrialsSinceMappingSwitch</code> | ||
| - | | 16 bit | ||
| <code> | | 0 | ||
| 1 bit | | Consecutive non-switch trial transitions since the most recent mapping change | ||
| 0 | |- | ||
| 0 | | <code>PriorCondition</code> | ||
| 0 | | 2 bit | ||
| - | | 0 | ||
| <code> | | Current block-level prior-frequency context (0-3) | ||
| | |- | ||
| 0 | | <code>Introduction</code> | ||
| | | 1 bit | ||
| | | 0 | ||
| - | | 1 during introduction or sandbox; 0 during experiment | ||
| <code> | |- | ||
| | | <code>TutorialPhase</code> | ||
| 0 | | 4 bit | ||
| | | 0 | ||
| 0 | | 0 experiment, 1 introduction, 2 sandbox | ||
| - | |- | ||
| <code> | | <code>ReactionTimeMs</code> | ||
| | | 32 bit | ||
| 0 | | 0 | ||
| | | Reaction time in rounded milliseconds | ||
| | |- | ||
| - | | <code>MovementTimeMs</code> | ||
| <code> | | 32 bit | ||
| | | 0 | ||
| | | Movement time in rounded milliseconds | ||
| | |- | ||
| | | <code>TotalTimeMs</code> | ||
| - | | 32 bit | ||
| <code> | | 0 | ||
| | | Target-onset to acquisition time in rounded milliseconds | ||
| | |- | ||
| | | <code>SensoryReliabilityCondition</code> | ||
| | | 2 bit | ||
| } | | 0 | ||
| 0 High, 1 Medium, 2 Low reliability | |||
|- | |||
| <code>TrueCursorX</code> | |||
| 10 bit | |||
| 512 | |||
| Post-mapping, pre-noise horizontal task-logic cursor position (0-1023) | |||
|- | |||
| <code>TrueCursorY</code> | |||
| 10 bit | |||
| 512 | |||
| Post-mapping, pre-noise vertical task-logic cursor position (0-1023) | |||
|- | |||
| <code>SensoryNoiseX</code> | |||
| 31 bit | |||
| 1073741824 | |||
| X noise encoded as 1073741824 + round(100 * noise pixels) | |||
|- | |||
| <code>SensoryNoiseY</code> | |||
| 31 bit | |||
| 1073741824 | |||
| Y noise encoded as 1073741824 + round(100 * noise pixels) | |||
|- | |||
| <code>SensoryNoiseStd</code> | |||
| 18 bit | |||
| 0 | |||
| Configured noise SD encoded as round(100 * pixels) | |||
|- | |||
| <code>SensoryNoiseSeedEffective</code> | |||
| 32 bit | |||
| 1 | |||
| Effective noise and reliability-assignment seed | |||
|} | |||
===External Joystick States=== | ===External Joystick States=== | ||
{| class="wikitable" | {| class="wikitable" | ||
! State | ! State | ||
! Description | |||
|- | |||
| <code>JoystickXpos</code> | |||
| Raw horizontal joystick position supplied through BCI2000 input logging | |||
|- | |||
| <code>JoystickYpos</code> | |||
| Raw vertical joystick position supplied through BCI2000 input logging | |||
|- | |||
| <code>JoystickButtons1</code> | |||
| Joystick button used to advance the introduction and sandbox | |||
|} | |||
The application also accesses BCI2000's standard <code>Running</code> state when ending the experiment. Joystick logging must be configured separately using <code>LogJoystick</code>. | |||
===States Not Present in the Current Implementation=== | |||
<code> | The task does not define <code>DisplayedCursorX</code>, <code>DisplayedCursorY</code>, an exact state named <code>SensoryReliability</code>, <code>PracticeTrial</code>, <code>TaskBlockType</code>, or <code>CursorGainCondition</code>. Instead, displayed coordinates use <code>CursorX/Y</code>, pre-noise coordinates use <code>TrueCursorX/Y</code>, and visual reliability is recorded through <code>SensoryReliabilityCondition</code> and the sensory-noise states. | ||
===State Lifecycle and Encoding Notes=== | |||
<code>TargetX/Y</code> have published initial values of 512 but are explicitly set to 0 during introduction/sandbox. <code>TaskTrial</code> is 1-based once experimental trials begin. Pulse states normally clear on the following processing block, whereas <code>TaskPaused</code> is held at 1 throughout a pause and <code>MovementStarted</code> remains high from movement detection until trial advancement. Noise states use fixed-point encoding described in [[#Noise Seeds and State Encoding|Noise Seeds and State Encoding]]. State publication immediately after skip operations has known limitations described in [[#State-Logging Caveats During Skips|State-Logging Caveats During Skips]]. | |||
==Cursor Coordinates== | ==Cursor Coordinates== | ||
<code>CursorX</code> and <code>CursorY</code> represent the final cursor | <code>CursorX</code> and <code>CursorY</code> represent the final displayed cursor position including mapping inversion, return-to-anchor transformation, any applied Gaussian visual noise, and display-boundary clipping. | ||
<code>TrueCursorX</code> and <code>TrueCursorY</code> record the separate <b>post-mapping, pre-noise</b> cursor trajectory. This is the trajectory used for center detection and target-hit detection. It does not represent untransformed joystick input. | |||
using the | The participant-visible drawing is positioned using the displayed cursor. Both true and displayed coordinates are recorded as 10-bit states over the range 0-1023. Encoded noise samples are recorded separately. The diagnostic window does not currently show either cursor coordinate pair. | ||
The application does not record an independent pre-mapping cursor state. When enabled, <code>JoystickXpos/Ypos</code> provide the underlying joystick samples needed to reconstruct a raw joystick-equivalent trajectory offline. | |||
==Data Recording== | ==Data Recording== | ||
The task records its behavioral variables as synchronized BCI2000 states in the standard <code>.dat</code> file, subject to the configured BCI2000 recording and joystick-logging settings. | |||
Recorded information includes: | |||
* | * Displayed and true cursor trajectories (<code>CursorX/Y</code> and <code>TrueCursorX/Y</code>). | ||
* | * Joystick trajectory when external joystick logging is enabled. | ||
* | * Task phase, Normal/Inverted mapping, prior context, and mapping-switch history. | ||
* | * Sensory-reliability condition, actual generated noise, configured noise SD, and effective seed. | ||
* Target angle | * Target angle and coordinates, experimental block, and trial number. | ||
* Movement onset, target acquisition, and reaction/movement/total timing. | |||
* Trial reset, trial skip, block skip, introduction skip, sandbox skip, and pause status. | |||
* Introduction/sandbox status and experiment completion as represented by task states. | |||
* Movement onset | |||
* Trial | |||
* Introduction/sandbox status | |||
The application passes signal channels through unchanged: | The application passes signal channels through unchanged: | ||
| Line 1,430: | Line 1,442: | ||
</pre> | </pre> | ||
=== | ===Operator Logging=== | ||
The | The application writes <code>bciout</code> messages for task startup and shutdown, the effective sensory-noise seed, per-block High/Medium/Low reliability distributions split by Normal/Inverted mapping and switch status, and trial-completion results including trial, block, mapping, reliability, reaction time, and movement time. These are diagnostic/operator messages rather than a separate structured task-results file. | ||
===Secondary Output=== | |||
There is no <code>ResultsFile</code> parameter. | The current implementation does not write an application-specific CSV file, JSON file, text results file, or database. There is no <code>ResultsFile</code> parameter. | ||
==Offline Analysis Notes== | |||
The table below gives common event and measurement identifications. When reset, skip, or pause controls are used, inspect adjacent processing blocks and the recorded configuration instead of relying solely on one state sample. | |||
{| class="wikitable" | {| class="wikitable" | ||
! Measurement | ! Measurement or Event | ||
! Recommended Identification | |||
|- | |||
| - | | Experimental samples | ||
| Experimental samples | | <code>Introduction == 0</code> | ||
| <code>Introduction == 0</code> | |- | ||
| - | | Introduction | ||
| Introduction | | <code>Introduction == 1</code> and <code>TutorialPhase == 1</code> | ||
| <code>Introduction == 1</code> and <code>TutorialPhase == 1</code> | |- | ||
| - | | Sandbox | ||
| Sandbox | | <code>Introduction == 1</code> and <code>TutorialPhase == 2</code> | ||
| <code>Introduction == 1</code> and <code>TutorialPhase == 2</code> | |- | ||
| - | | Active experimental trial | ||
| Active experimental trial | | <code>Introduction == 0</code>, <code>TaskTrial > 0</code>, and <code>TaskPhase</code> from 1 through 6 | ||
| <code>Introduction == 0</code>, <code>TaskTrial | |- | ||
| - | | Target onset | ||
| Target onset | | Transition into <code>TaskPhase == 5</code> | ||
| Transition into <code>TaskPhase == 5</code> | |- | ||
| - | | Movement onset | ||
| Movement onset | | Rising transition of <code>MovementStarted</code> | ||
| Rising transition of <code>MovementStarted</code> | |- | ||
| - | | Target acquisition | ||
| Target acquisition | | <code>TargetHit == 1</code> | ||
| <code>TargetHit == 1</code> | |- | ||
| - | | Normal mapping | ||
| Normal mapping | | <code>TaskCondition == 0</code> | ||
| <code>TaskCondition == 0</code> | |- | ||
| - | | Inverted mapping | ||
| Inverted mapping | | <code>TaskCondition == 1</code> | ||
| <code>TaskCondition == 1</code> | |- | ||
| | | High reliability | ||
| | | <code>SensoryReliabilityCondition == 0</code> | ||
| <code> | |- | ||
| - | | Medium reliability | ||
| | | <code>SensoryReliabilityCondition == 1</code> | ||
| <code> | |- | ||
| - | | Low reliability | ||
| | | <code>SensoryReliabilityCondition == 2</code> | ||
| <code> | |- | ||
| - | | Reliability globally disabled | ||
| | | Verify <code>EnableSensoryReliability == 0</code> in recorded parameters; all trials then use condition 0 | ||
| | |- | ||
| - | | Configured visual-noise SD | ||
| Trials since switch | | <code>SensoryNoiseStd / 100</code> pixels | ||
| <code>TrialsSinceMappingSwitch</code> | |- | ||
| - | | Actual X visual noise | ||
| Previous mapping | | <code>(SensoryNoiseX - 1073741824) / 100</code> pixels | ||
| | |- | ||
| - | | Actual Y visual noise | ||
| Prior | | <code>(SensoryNoiseY - 1073741824) / 100</code> pixels | ||
| <code>PriorCondition</code> | |- | ||
| - | | Pre-noise task-logic cursor trajectory | ||
| | | <code>TrueCursorX</code> and <code>TrueCursorY</code> | ||
| <code>TaskBlock</code> | |- | ||
| - | | Displayed cursor trajectory | ||
| Overall trial | | <code>CursorX</code> and <code>CursorY</code> | ||
| <code>TaskTrial</code> | |- | ||
| - | | Mapping switch | ||
| Target angle | | <code>MappingSwitch == 1</code> (subject to skip-operation caveats) | ||
| <code>TargetAngle / 10</code> degrees | |- | ||
| - | | Trials since switch | ||
| Target position | | <code>TrialsSinceMappingSwitch</code> (subject to skip-operation caveats) | ||
| <code>TargetX</code> and <code>TargetY</code> | |- | ||
| - | | Previous mapping | ||
| | | Previous trial's <code>TaskCondition</code> | ||
| <code>JoystickXpos</code> and <code>JoystickYpos</code> | |- | ||
| | | Prior context | ||
| | | <code>PriorCondition</code> | ||
| <code> | |- | ||
| | | Experimental block | ||
| | | <code>TaskBlock</code> | ||
| <code> | |- | ||
| - | | Overall trial | ||
| | | <code>TaskTrial</code> | ||
| <code> | |- | ||
| - | | Target angle | ||
| | | <code>TargetAngle / 10</code> degrees | ||
| <code> | |- | ||
| - | | Target position | ||
| | | <code>TargetX</code> and <code>TargetY</code> | ||
| <code> | |- | ||
| - | | Joystick trajectory | ||
| | | <code>JoystickXpos</code> and <code>JoystickYpos</code> | ||
| <code> | |- | ||
| } | | Reaction time | ||
| <code>ReactionTimeMs</code> | |||
|- | |||
| Movement time | |||
| <code>MovementTimeMs</code> | |||
|- | |||
| Total time | |||
| <code>TotalTimeMs</code> | |||
|- | |||
| Manual reset | |||
| <code>TrialReset == 1</code> | |||
|- | |||
| Trial skipped | |||
| <code>TrialSkipped == 1</code> | |||
|- | |||
| Current block skipped | |||
| <code>ConditionSkipped == 1</code> | |||
|- | |||
| Introduction skipped | |||
| <code>IntroductionSkipped == 1</code> | |||
|- | |||
| Sandbox skipped | |||
| <code>SandboxSkipped == 1</code> | |||
|- | |||
| Task paused | |||
| <code>TaskPaused == 1</code> | |||
|- | |||
| Experiment completion | |||
| <code>TaskPhase == 7</code> in ordinary progression; may be absent for skip-to-finish | |||
|} | |||
===Event-Like | ===Event-Like States=== | ||
The following are designed to be one-processing-block event flags: <code>MappingSwitch</code>, <code>TargetHit</code>, <code>TrialReset</code>, <code>TrialSkipped</code>, <code>ConditionSkipped</code>, <code>IntroductionSkipped</code>, and <code>SandboxSkipped</code>. <code>MovementStarted</code> instead remains high from movement onset through the rest of the trial and Feedback. <code>TaskPaused</code> is a level state held at 1 throughout a pause. | |||
===Analysis Considerations=== | |||
* Use <code>CursorX/Y</code> for what the participant saw and <code>TrueCursorX/Y</code> for the cursor that determined hits and centering. Visual noise and display clipping can make the two disagree. | |||
* Divide cursor-state coordinates by 1023 to recover normalized coordinates. Use the provided noise-state offset and scale to recover noise in pixels. | |||
* Use the recorded parameter <code>EnableSensoryReliability</code> to distinguish a disabled manipulation from genuine High-reliability trials. | |||
* Reconstruct prior mapping by inspecting previous trials; <code>PriorCondition</code> is a block context rather than a previous-trial label or inferred belief. | |||
* Check skip pulses and neighboring trial/block values when deriving event onsets. Mapping-switch pulses, trial identifiers, and <code>TaskPhase</code> may be stale or missing on early-return skip processing blocks. | |||
* Paused intervals should be identified from <code>TaskPaused</code>, and internal timing measurements exclude pause duration on resume. | |||
* If target acquisition occurs without a detected movement onset, reaction and movement timing states are zero but total time is recorded; such zero values should not automatically be interpreted as physiologically instantaneous responses. | |||
* Raw joystick reconstruction requires external input logging; the application itself does not activate <code>LogJoystick</code>. | |||
==Differences from USBHIDJoystickTask== | ==Differences from USBHIDJoystickTask== | ||
===Retained=== | ===Retained=== | ||
* BCI2000 <code>ApplicationBase</code> | * BCI2000 <code>ApplicationBase</code> structure. | ||
* USB joystick input | * USB joystick input. | ||
* Center-out reaching | * Center-out reaching. | ||
* Center hold. | * Center hold. | ||
* | * Warning interval. | ||
* Pre-target delay. | * Pre-target delay. | ||
* Target-directed movement. | * Target-directed movement. | ||
| Line 1,587: | Line 1,601: | ||
* Movement-time measurement. | * Movement-time measurement. | ||
* Total-time measurement. | * Total-time measurement. | ||
* Manual trial reset. | * Manual trial reset. | ||
* | * Progress bar. | ||
* BCI2000 state logging. | * BCI2000 state logging. | ||
* Direct and inverted joystick-control | * Direct and inverted joystick-control mappings. | ||
===Removed=== | ===Removed=== | ||
The FEP task | The FEP task removes the earlier task's: | ||
* <code>ExperimentMode</code>. | * <code>ExperimentMode</code>. | ||
* Automatic-only | * Automatic-only and Controlled-only modes. | ||
* Ordered-start condition. | |||
* Ordered- | |||
* <code>TaskBlockType</code>. | * <code>TaskBlockType</code>. | ||
* Green | * Green versus red condition-specific targets. | ||
* Explicit condition instructions. | |||
* | |||
* Explicit teaching of the inverted mapping. | * Explicit teaching of the inverted mapping. | ||
* Condition-specific practice trials. | * Condition-specific practice trials. | ||
* <code>PracticeTrial</code>. | * <code>PracticeTrial</code>. | ||
* Optional tutorial | * Optional tutorial setting. | ||
* Diagnostic | * Diagnostic Continue button. | ||
* Secondary CSV results file. | |||
* Secondary CSV | |||
* Participant-facing block announcements. | * Participant-facing block announcements. | ||
| Line 1,623: | Line 1,628: | ||
The FEP task adds: | The FEP task adds: | ||
* | * Six predefined experimental block roles. | ||
* Hidden Normal and Inverted mappings. | * Hidden Normal and Inverted mappings. | ||
* Unannounced mapping switches. | |||
* <code>MappingSwitch</code>. | * <code>MappingSwitch</code>. | ||
* <code>TrialsSinceMappingSwitch</code>. | * <code>TrialsSinceMappingSwitch</code>. | ||
* <code>PriorCondition</code>. | * <code>PriorCondition</code>. | ||
* <code> | * <code>SensoryReliabilityCondition</code> and configurable High/Medium/Low visual sensory reliability. | ||
* <code> | * Configurable Gaussian cursor noise and correlation time. | ||
* | * Separate <code>TrueCursorX/Y</code> and displayed <code>CursorX/Y</code> logging. | ||
* | * <code>SensoryNoiseX/Y</code>, <code>SensoryNoiseStd</code>, and <code>SensoryNoiseSeedEffective</code>. | ||
* Researcher controls for skipping trial, block, introduction, and sandbox, and pausing/resuming. | |||
* <code>TrialSkipped</code>, <code>ConditionSkipped</code>, <code>IntroductionSkipped</code>, <code>SandboxSkipped</code>, and <code>TaskPaused</code> states. | |||
* | * Configurable <code>CursorDiameterPixels</code> and <code>TargetDiameterPixels</code> parameters. | ||
* | * Diagnostic real-time timing values and run averages. | ||
* A minimal Normal-mapping sandbox. | |||
* Black targets across all mapping conditions. | |||
* Normal-dominant and approximately balanced mapping contexts. | |||
* | |||
* | |||
* | |||
==Known Limitations and Analysis Considerations== | ==Known Limitations and Analysis Considerations== | ||
* The | * The current module does not implement an explicit computational Free Energy Principle model. | ||
* <code>PriorCondition</code> represents experimental block context rather than an inferred participant belief. | |||
* Participant surprise or expectation is not measured directly by the application. | |||
* Blocks 4 and 6 use similar approximately balanced mapping-generation rules but occur after different preceding mapping histories. | |||
* <code>PriorCondition</code> | * Mapping pseudorandomization constraints are attempted but are not guaranteed if all 64 candidate sequences fail. | ||
* Blocks 4 and 6 use | |||
* | |||
* There is no unsuccessful-trial timeout. | * There is no unsuccessful-trial timeout. | ||
* | * Reliability manipulation is disabled by default; <code>SensoryReliabilityCondition=0</code> by itself does not show that reliability was enabled. | ||
* | * Reliability is assigned with a counterbalancing heuristic across mapping and switch status, not by a wholly independent shuffle. | ||
* | * Gaussian noise affects the displayed cursor only during target-visible movement; it does not change the cursor position used for center and target-hit detection. | ||
* | * The display may visually disagree with the target-hit decision because logic uses the true pre-noise cursor. | ||
* | * The correlated noise process begins at zero at target onset rather than stationary variance. | ||
* The true cursor is separately recorded, but no independent pre-mapping/untransformed cursor trajectory is recorded. | |||
* The diagnostic window does not show target, joystick, cursor, switch, trials-since-switch, or free-form status fields; run averages are divided by Normal/Reversed mapping, not by reliability. | |||
* <code>TargetDiameterPixels</code> changes target-hit radius; <code>CursorDiameterPixels</code> changes only cursor appearance. | |||
* Skip operations can result in stale or missing per-block values for <code>MappingSwitch</code>, <code>TaskPhase</code>, and trial/block identifiers. Skip-to-finish may not publish <code>TaskPhase=7</code>. | |||
* A block skip during Inverted target-visible movement does not explicitly preserve the anchored return mapping. | |||
* Pausing is allowed during introduction, sandbox, and feedback, and the timing system compensates for pause duration on resume. | |||
* Physical display geometry depends on the configured participant monitor and BCI2000 window dimensions. | |||
* No application-specific CSV, JSON, text results file, or database is generated. | |||
==References== | |||
The | Friston, K. The free-energy principle: a unified brain theory?. Nat Rev Neurosci 11, 127–138 (2010). https://doi.org/10.1038/nrn2787 | ||
==See also== | ==See also== | ||
* [[VisuomotorJoystickTask|Visuomotor Joystick Task]] | |||
* [[User Reference:Logging Input|Logging Input]] | * [[User Reference:Logging Input|Logging Input]] | ||
* [[User Reference:Logging Input#LogJoystick|LogJoystick]] | * [[User Reference:Logging Input#LogJoystick|LogJoystick]] | ||
| Line 1,699: | Line 1,681: | ||
* [[Technical Reference:BCI2000 File Format|BCI2000 File Format]] | * [[Technical Reference:BCI2000 File Format|BCI2000 File Format]] | ||
* [[Programming Reference:ApplicationBase Class|ApplicationBase Class]] | * [[Programming Reference:ApplicationBase Class|ApplicationBase Class]] | ||
* [[Category:User Application]] | |||
Latest revision as of 15:38, 19 October 2026
Synopsis
FEP_VisuomotorJoystickTask is a BCI2000 application module implementing a center-out visuomotor reaching task designed to investigate how participants adapt their behavior when the relationship between their actions and sensory consequences changes unexpectedly.
Participants control a cursor using a USB HID joystick and repeatedly move from a central starting location to peripheral targets. The joystick-to-cursor mapping is treated as a hidden environmental state: on a given trial, joystick movement may produce either a normal cursor movement or an inverted cursor movement. These mappings are not explicitly cued to the participant.
The task was developed in the context of the Free Energy Principle (FEP) and related theories of predictive processing and active inference. In this framework, an agent maintains an internal model of the causes of its sensory observations and uses incoming evidence to update that model. When observations conflict with the agent's expectations, the agent may need to revise its estimate of the current hidden state.
The present task operationalizes this problem using a simple visuomotor environment. The hidden state is the current joystick-to-cursor mapping. Participants first accumulate experience with particular mappings and mapping frequencies, creating different histories of prior exposure. The mapping can then change without warning, requiring the participant to infer from the resulting cursor behavior that the current sensorimotor relationship has changed.
The task therefore allows behavioral measurements to be related to three major features of inference:
- Prior experience: Different experimental blocks expose participants to different frequencies of Normal and Inverted mappings.
- Unexpected state changes: Mapping changes may occur between trials without an explicit visual cue.
- Behavioral updating: Reaction time, movement time, total time, and cursor trajectory may be examined following mapping switches and across subsequent trials.
The experiment also includes a configurable visual sensory-reliability manipulation. On selected trials, Gaussian spatial noise perturbs the displayed cursor without changing the task-logic cursor position. High reliability has no visual noise; Medium and Low reliability use configurable noise amplitudes. This is a visual-feedback noise manipulation, not a cursor-gain manipulation.
Importantly, the software does not itself compute free energy, prediction error, posterior probability, Bayesian belief, or another formal FEP quantity. Instead, it creates a controlled hidden-state visuomotor task whose behavioral and neural data may be used to investigate questions motivated by those theories.
The current implementation includes:
- Normal and inverted joystick-to-cursor mappings.
- Unannounced mapping changes between trials.
- Six sequential experimental block roles with different mapping frequencies.
- High, Medium, and Low visual sensory-reliability conditions with configurable Gaussian cursor noise (disabled by default).
- Mapping-switch, prior-condition, and trials-since-switch state logging.
- A minimal participant introduction.
- A Normal-mapping joystick sandbox.
- Reaction-time, movement-time, total-time, displayed and true cursor, joystick (when logging is enabled), target, mapping, reliability, noise, and researcher-control states in the BCI2000 data stream.
- Experimenter controls for resetting, skipping, pausing, and resuming the task.
The participant is not explicitly informed about mapping changes, sensory-reliability conditions, mapping probabilities, or experimental block structure. Visual noise may nevertheless be perceptible.
Location
Upon completion of an SVN update or checkout of the relevant source tree, the current FEP Visuomotor Joystick Task is located in:
src/custom/FEP_VisuomotorJoystickTask/
The main implementation is contained in:
FEP_VisuomotorJoystickTask.cpp
with the corresponding header and build configuration in:
FEP_VisuomotorJoystickTask.hCMakeLists.txt
The application is included from:
src/custom/CMakeLists.txt
The current CMake target is:
FEP_VisuomotorJoystickTask_custom
The module uses NOBUNDLE in its bci2000_add_application_module declaration. Its Windows executable is typically named:
FEP_VisuomotorJoystickTask_custom.exe
A separate src/custom/FEP_VisuomotorJoystickTask_pacing_test/ diagnostic module is also included in the custom build. That module is for investigating a rendering/pacing issue and is not the experimental task.
Versioning
Author
Alexander Speer
Friedman Lab, Department of Neurosurgery
Washington University in St. Louis
Developed in the Friedman Lab.
Contact: speer@wustl.edu
Version History
New version: 19 October 2026
This updated version replaces the earlier Normal/High cursor-gain manipulation with configurable High/Medium/Low visual sensory reliability; introduces temporally correlated Gaussian cursor noise and separate true-versus-displayed cursor states; adds researcher controls for skipping trials, blocks, introduction, and sandbox and for pausing/resuming; adds associated BCI2000 event and reliability states; provides configurable cursor and target diameters; and redesigns the diagnostic window to show real-time timings and run averages. The experimental mapping and six block roles remain in place. The current build uses the FEP_VisuomotorJoystickTask_custom target.
No independent numeric version identifier is declared in the inspected module; the date above identifies this documentation update and implementation revision, not an asserted source revision number.
The current FEP task is maintained under src/custom. In the inspected development checkout, the module does not currently have independent Git or SVN revision history.
An earlier inspected BCI2000 build was produced using:
- BCI2000 framework 3.6.9535
- BCI2000 source revision 9535
- Visual Studio 2022 / MSVC 19.35
- Release x64 configuration
These values refer to an inspected BCI2000 build containing the module, not to an independently verified revision number of the current FEP task.
Scientific Motivation
Free Energy Principle
The Free Energy Principle proposes that biological agents maintain internal models of the causes of their sensory inputs and continually update those models in order to reduce discrepancies between predicted and observed sensory states.
A useful way to interpret the present task is as a hidden-state inference problem.
The participant directly observes:
- Joystick movement.
- Cursor movement.
- Target position.
- The sensory consequences of each movement.
The participant is not directly told:
- Which joystick-to-cursor mapping is currently active.
- Whether the mapping has changed.
- The probability of a mapping occurring.
- The current experimental block.
- Whether visual sensory reliability has changed.
The current mapping therefore acts as a hidden environmental state that must be inferred from the relationship between action and observed cursor movement.
For example, after many Normal trials, a participant may expect the cursor to move in the same direction as the joystick. If the next trial unexpectedly uses the Inverted mapping, the observed cursor movement conflicts with that expectation. Subsequent behavior can then be examined to determine how rapidly the participant adjusts to the new mapping.
Why the Task Was Developed
The task was designed to create an experimentally controlled situation in which prior experience and new sensory evidence can come into conflict.
Several aspects of the experiment make this possible.
First, the frequency of Normal and Inverted mappings changes across blocks. This changes the participant's recent history of mapping exposure.
Second, mapping changes are not announced. Participants therefore cannot simply follow an explicit instruction telling them which mapping to use.
Third, the task records the exact trials on which the mapping changes and the number of trials that have occurred since the most recent switch.
This makes it possible to compare behavior:
- Before and after an unexpected mapping change.
- On switch versus non-switch trials.
- Across successive trials following a switch.
- Under different histories of Normal and Inverted mapping exposure.
- Under High, Medium, and Low visual sensory reliability (when enabled).
The task can therefore be used to investigate how prior experience influences behavioral adaptation to unexpected changes in sensorimotor contingencies.
Implementation Versus Theory
The current application implements the experimental manipulations required for this type of analysis, but it does not contain an explicit computational model of the participant.
In particular, the software does not calculate:
- Variational free energy.
- Prediction error.
- Posterior probability.
- Belief distributions.
- Bayesian surprise.
- Learning rate.
- Adaptation score.
These quantities, if used, must be estimated during offline behavioral or neural analysis.
Functional Description
Mapping Conditions
The FEP task uses two joystick-to-cursor mappings:
TaskCondition
|
Mapping | Description |
|---|---|---|
| 0 | Normal | Joystick displacement moves the cursor in the corresponding direction. |
| 1 | Inverted | Joystick displacement moves the cursor in the opposite direction on both axes. |
The current mapping is not visually indicated to the participant.
Unlike the earlier USBHIDJoystickTask, the FEP task does not use the terms Automatic and Controlled in its implementation.
Behavioral Measurements
The task records information that may be used to examine:
- Reaction time.
- Movement time.
- Total target-acquisition time.
- Cursor trajectory.
- Initial movement direction.
- Trajectory curvature.
- Performance immediately following a mapping switch.
- Performance as a function of trials since the previous switch.
- Effects of different mapping-frequency contexts.
- Effects of High, Medium, and Low visual sensory reliability when the manipulation is enabled.
- Differences between true and displayed cursor trajectories under visual noise.
Experiment Structure
Each run proceeds in the following order:
- Introduction (unless skipped by the researcher).
- Joystick sandbox (unless bypassed or skipped).
- Experimental block 1, if enabled.
- Experimental block 2, if enabled.
- Experimental block 3, if enabled.
- Experimental block 4, if enabled.
- Experimental block 5, if enabled.
- Experimental block 6, if enabled.
- Experiment completion.
Experimental block transitions are not announced to the participant. Skipping the introduction using the researcher window enters the experiment directly and also bypasses the sandbox. Trial and block skipping can change which trials are actually performed.
Each experimental trial proceeds as follows:
- The participant returns the cursor to the center.
- The participant holds the cursor within the center region.
- A yellow warning cue appears.
- A pre-target delay occurs.
- A peripheral target appears.
- The participant moves the cursor toward the target.
- The target is acquired.
- A short feedback interval occurs.
- The task advances to the next trial.
Introduction
The introduction provides only the minimum information needed to operate the task.
The participant is shown:
Use the joystick to control the cursor. At the beginning of each trial, return the cursor to the center and hold it there. The center will turn yellow before the target appears. Once the target appears, move the cursor to the target. Press the joystick button to continue.
During the introduction:
Introduction=1TutorialPhase=1TaskPhase=0- The cursor is hidden.
- The center marker is hidden.
- The warning cue is hidden.
- The target is hidden.
- The central cross is hidden.
- The progress bar is hidden.
A rising press of JoystickButtons1 advances to the sandbox. The experimenter may instead select SKIP INTRODUCTION (with confirmation), which enters the experiment directly and bypasses the sandbox.
The participant is not told about:
- Normal versus Inverted mappings.
- Mapping switches.
- Changes in visual sensory reliability.
- Mapping probabilities.
- Experimental blocks.
- Prior conditions.
Sandbox
After the introduction, the participant enters a free-movement sandbox.
The participant sees:
- A black cursor.
- A gray center marker.
- A black center cross.
- No peripheral target.
- No warning cue.
- No progress bar.
The participant is shown:
Practice moving the cursor with the joystick. When you are ready to begin, return the cursor to the center and press the joystick button.
During the sandbox:
Introduction=1TutorialPhase=2TaskPhase=0TaskBlock=0TaskTrial=0TaskCondition=0- Normal direct mapping is used.
- There is no gain manipulation; the sandbox uses direct Normal mapping without visual noise.
- No targets are generated.
- No experimental timing phases occur.
The sandbox ends when both of the following conditions are satisfied:
- The cursor is inside the center tolerance region.
- A new joystick-button press occurs.
Because continuation uses rising-edge detection, the participant must release the button after leaving the introduction screen before pressing it again to leave the sandbox. The researcher can also select SKIP SANDBOX to enter the experiment.
When the sandbox finishes:
Introductionbecomes 0.TutorialPhasebecomes 0.TaskPhasebecomes 1.- Experimental block and trial states become active.
Experimental Blocks
The task contains six predefined block roles.
There is no ExperimentMode parameter.
A block may be omitted by setting its trial-count parameter to 0.
TaskBlock retains the original block-role number, so block numbers may skip values when one or more blocks are disabled.
| Block | Trial-count parameter | PriorCondition
|
Mapping composition |
|---|---|---|---|
| 1 | BaselineTrials
|
0, Fixed | 100% Normal |
| 2 | InitialInvertedTrials
|
0, Fixed | 100% Inverted |
| 3 | ReturnNormalTrials
|
0, Fixed | 100% Normal |
| 4 | MixedTrials
|
1, HiddenMixed | Approximately 50% Normal and 50% Inverted |
| 5 | StrongPriorTrials
|
2, StrongNormal | Approximately 90% Normal and 10% Inverted |
| 6 | BalancedPriorTrials
|
3, Balanced | Approximately 50% Normal and 50% Inverted |
Blocks 4 and 6
For blocks 4 and 6:
floor(N/2)trials are assigned the Inverted mapping.- All remaining trials are assigned the Normal mapping.
- If the number of trials is odd, the additional trial is Normal.
Block 5
Block 5 contains a strongly Normal-dominant mapping distribution.
Approximately 10% of trials are assigned the Inverted mapping, using a rounded fixed trial count.
The remaining trials are Normal.
This is not implemented as an independent 10% switch probability on each trial.
Pseudorandomization
For blocks 4 through 6, mapping order is pseudorandomized.
The task attempts up to 64 candidate shuffles.
A candidate is preferred when:
- It does not strictly alternate throughout sequences of at least four trials.
- It does not contain excessively long runs of one mapping.
The preferred maximum run length is:
max(3, unavoidableRun + 1)
where:
unavoidableRun = (majority + minority) / (minority + 1)
using integer division.
If no candidate satisfies the constraints after 64 attempts, the final generated sequence is used.
After the mapping sequence is generated, sensory-reliability conditions are assigned separately using a dedicated random generator. Rather than an independent shuffle, the assignment algorithm attempts to counterbalance reliability categories across Normal/Inverted mappings and mapping-switch/non-switch trials while preserving the configured counts. Reliability assignment does not alter the mapping order. See Sensory Reliability.
Prior Conditions
PriorCondition represents the mapping-frequency context associated with the current block.
It does not represent the immediately preceding trial's mapping.
| Value | Name | Meaning |
|---|---|---|
| 0 | Fixed | Fixed-mapping context used in blocks 1 through 3. |
| 1 | HiddenMixed | Approximately balanced hidden mapping context used in block 4. |
| 2 | StrongNormal | Strongly Normal-dominant mapping context used in block 5. |
| 3 | Balanced | Approximately balanced mapping context used in block 6. |
The mapping used on the preceding trial may be determined offline from the previous trial's TaskCondition.
Joystick Input
Joystick input is provided through BCI2000's input logging system.
The application reads:
JoystickXposJoystickYposJoystickButtons1
Joystick X and Y values normally range from 0 through 32767.
Each axis is converted into the task's 0-through-1023 coordinate system:
taskJoystick = round(BCIJoystick * 1023 / 32767)
The converted value is normalized internally:
rawPosition = taskJoystick / 1023
The FEP application does not itself enable joystick logging.
Joystick logging should therefore be enabled using BCI2000's LogJoystick option.
See LogJoystick.
Joystick-to-Cursor Mapping
Before target onset, cursor position normally follows direct absolute joystick position:
cursorX = rawX cursorY = rawY
The mapping transformation used for target-directed movement is activated at target onset. The code defines no HighCursorGain parameter, no CursorGainCondition state, and no high-gain movement condition in this version.
Anchor Capture
When the target appears, the application stores:
- Current joystick X position.
- Current joystick Y position.
- Current cursor X position.
- Current cursor Y position.
- Current mapping direction (
+1for Normal or-1for Inverted).
These values form the anchor for transformed movement. Because joystick displacement relative to the anchor is initially zero, activating the transformed mapping does not cause an immediate cursor jump.
Normal Mapping
With Normal mapping, the cursor follows the joystick directly:
cursorX = joystickX / 1023 cursorY = joystickY / 1023
Inverted Mapping
After target onset on an Inverted trial:
cursorX = anchorCursorX - (joystickX - anchorJoystickX) / 1023 cursorY = anchorCursorY - (joystickY - anchorJoystickY) / 1023
Both axes are inverted. Cursor coordinates are constrained to the normalized range [0, 1]. While returning from a preceding anchored Inverted trial, that preceding transformation may remain active until the joystick returns to its stored anchor.
The cursor position resulting from mapping and clipping, but before sensory noise, is called the true cursor. Sensory noise perturbs only the displayed cursor.
Sensory Reliability
The current implementation manipulates visual sensory reliability using trial-wise Gaussian spatial noise added to the displayed cursor. This replaces the cursor-gain manipulation described in earlier versions. Sensory reliability is disabled by default (EnableSensoryReliability=0).
Reliability Conditions
SensoryReliabilityCondition
|
Condition | Visual-noise standard deviation | Description |
|---|---|---|---|
| 0 | High | 0 pixels | Noise-free visual cursor |
| 1 | Medium | MediumReliabilityNoiseStd (default 5 pixels)
|
Gaussian cursor-position noise |
| 2 | Low | LowReliabilityNoiseStd (default 15 pixels)
|
Larger Gaussian cursor-position noise |
The noise standard deviations are specified in reference-display pixels, normalized using the task's nominal 1000 by 750 coordinate system. Noise affects only the cursor during the TargetVisible phase; the target, center marker, warning marker, cross, and joystick input are not perturbed.
Enabling Reliability by Block
When EnableSensoryReliability=0, all trials use High reliability and no visual noise is applied, regardless of the requested proportions or block list. Therefore, SensoryReliabilityCondition=0 does not by itself establish that reliability manipulation was enabled.
When enabled, reliability conditions are assigned only within the numbered blocks listed in SensoryReliabilityBlocks, which defaults to blocks 4, 5, and 6. Blocks not listed always use High reliability. The block list may instead select any subset of the six block roles. A block disabled by setting its trial count to zero has no trials to assign.
Reliability Assignment and Counterbalancing
For each enabled block, counts for High, Medium, and Low trials are calculated from the configured proportions by taking their floors and distributing remaining trials according to the largest fractional remainders. The result matches the block's total trial count.
The application then uses a dedicated std::mt19937 generator to assign those conditions in a randomized trial order. The selection score favors counterbalancing reliability across (1) Normal versus Inverted mapping and (2) mapping-switch versus non-switch trials, subject to the remaining required condition counts. Thus reliability assignment is not a wholly independent shuffle of the mapping sequence. Exact balance in small blocks or uneven sequences is not guaranteed.
Reliability is assigned after the Normal/Inverted mapping sequence has been built and does not change that sequence. Only mapping changes, not reliability changes, generate MappingSwitch events. The dedicated noise/assignment seed is distinct from BCI2000's mapping/target random-number generator.
The configured proportions default to 0.34 High, 0.33 Medium, and 0.33 Low, and their sum must equal 1 within 1e-6. Low-reliability noise SD must be at least Medium-reliability noise SD.
X and Y noise are generated from independent Gaussian innovations and evolved over processing updates as:
a = exp(-elapsedSeconds / correlationTimeSeconds) noiseX = a * previousNoiseX + SD * sqrt(1 - a*a) * N_X(0,1) noiseY = a * previousNoiseY + SD * sqrt(1 - a*a) * N_Y(0,1)
The temporal correlation time is set by SensoryNoiseCorrelationTimeMs (default 100 ms); a value of zero produces independent innovations on each update. Each trial's noise generator is initialized from the effective seed and trial/block identity. Noise begins at zero at target onset, so the process builds up rather than beginning with stationary variance. Noise is cleared when the task leaves the target-visible phase and on trial reset or skip.
The displayed cursor is calculated as:
displayedX = clamp(trueX + noiseX / 1000, 0, 1) displayedY = clamp(trueY + noiseY / 750, 0, 1)
The true cursor is used for center detection and target-hit detection. Movement onset is detected from joystick movement. Therefore a displayed cursor that appears to touch the target is not necessarily counted as a hit, and a true cursor that reaches the target can register a hit despite noise displacing the displayed cursor away from it.
Noise Seeds and State Encoding
SensoryNoiseSeed defaults to 1. Setting it to 0 selects an automatically generated effective seed, recorded in SensoryNoiseSeedEffective and reported in the BCI2000 operator log.
Noise values are stored as positive integer states with an offset to represent negative noise; the configured SD is stored in hundredths of a pixel:
noiseX_pixels = (SensoryNoiseX - 1073741824) / 100 noiseY_pixels = (SensoryNoiseY - 1073741824) / 100 noiseSD_pixels = SensoryNoiseStd / 100
The recorded TrueCursorX/Y and CursorX/Y coordinates are quantized to the task's 0–1023 range. The noise states represent the generated visual perturbation before final boundary clipping; consequently, the difference between displayed and true coordinates may not equal the encoded noise exactly near display edges.
Important: TrueCursorX/Y is post-mapping, pre-noise position, not a pre-mapping/raw joystick trajectory. The raw joystick trajectory is available from logged joystick input states.
Return-to-Anchor Behavior
After an Inverted trial, the previous transformed mapping may temporarily remain active while the participant returns the joystick toward its previous anchor.
The stored transformation is released once both joystick axes are within 8 task-coordinate units of the previous joystick anchor.
Normal direct mapping is then restored for ordinary centering.
This behavior reduces abrupt cursor jumps between transformed target movement and subsequent centering. It is also engaged when an in-progress Inverted trial is skipped or when an Inverted trial is reset during target-visible movement. Skipping an entire block does not explicitly engage this return path, so direct mapping may be restored immediately in that case.
Mapping Switches
A mapping switch occurs when:
next trial TaskCondition != completed trial TaskCondition
Mapping switches occur only at trial boundaries. Changes in sensory reliability alone do not produce mapping-switch events.
They do not occur:
- During target-directed movement.
- During the Feedback phase before the feedback interval ends.
The new mapping is selected when the task advances into the next trial.
MappingSwitch
MappingSwitch is an event-like state.
It is:
- 1 on the processing block that advances into a new trial whose mapping differs from the completed trial.
- 0 on the following processing block.
- 0 when no mapping change occurred.
It should therefore be interpreted as a one-processing-block pulse.
TrialsSinceMappingSwitch
TrialsSinceMappingSwitch records how many consecutive no-switch trial transitions have occurred since the most recent mapping change.
Behavior is:
- First experimental trial: 0.
- First trial following a mapping switch: 0.
- Next same-mapping trial: 1.
- Next same-mapping trial: 2.
- And so forth.
Because the first experimental trial also begins at 0, TrialsSinceMappingSwitch==0 by itself does not identify a switch.
Use MappingSwitch or a transition in TaskCondition to identify mapping changes. When skip controls are used, event states can be stale or missing for a processing block; compare adjacent trials and consult the skip-state guidance below.
Example
Consider the following mapping sequence:
Normal -> Normal -> Inverted -> Inverted
Within block 4, the corresponding states would behave approximately as follows:
| Trial | TaskCondition
|
MappingSwitch
|
TrialsSinceMappingSwitch
|
PriorCondition
|
|---|---|---|---|---|
| Normal | 0 | 0 | Depends on previous trial history | 1 |
| Normal | 0 | 0 | Previous value + 1 | 1 |
| Inverted | 1 | 1 on the transition processing block | 0 | 1 |
| Inverted | 1 | 0 | 1 | 1 |
Target Generation
A new target angle is generated for each new experimental trial.
TargetAngle ranges from:
0 through 3599
The value represents tenths of a degree:
angle in degrees = TargetAngle / 10
Targets therefore span:
0.0 through 359.9 degrees
Target coordinates are generated according to:
TargetX = 0.5 + 0.3 * cos(angle) TargetY = 0.5 + 0.4 * sin(angle)
The unequal normalized X and Y radii correspond to an approximately circular 300-pixel radius in the nominal 1000 by 750 design.
Targets:
- Are black.
- Are visually identical across all mapping conditions.
- Are visually identical across reliability conditions.
- Are not determined by mapping condition.
- Are not determined by reliability condition.
- Are not determined by mapping-switch status.
- May repeat.
- Are not explicitly angularly balanced.
- Do not appear during the introduction.
- Do not appear during the sandbox.
A new target is generated:
- For the first experimental trial.
- After each completed non-final trial.
Resetting a trial does not generate a new target. Advancing after a skipped trial generates a new target; skipping the remaining trials of a block may consume multiple target generations and change the subsequent target sequence.
Trial Phases
The current experimental phase is stored in TaskPhase.
| Value | Phase | Description | Participant display |
|---|---|---|---|
| 0 | Introduction / Sandbox | No active experimental trial | Introduction text or sandbox |
| 1 | WaitingForCenter | Waiting for cursor to enter the center region | Cursor, gray center, cross |
| 2 | HoldingCenter | Required uninterrupted center hold | Cursor, gray center, cross |
| 3 | Warning | Warning interval | Cursor, yellow warning marker, cross |
| 4 | PreTargetDelay | Delay immediately before target appearance | Cursor, gray center, cross |
| 5 | TargetVisible | Target-directed movement | Cursor, black target, cross |
| 6 | Feedback | Post-acquisition interval | Cursor and cross |
| 7 | Finished | Experiment complete | End message |
An experimental target onset may be identified by a transition into:
TaskPhase == 5
Movement onset may be identified by a rising transition of:
MovementStarted
Target acquisition is identified by:
TargetHit == 1
Center and target-hit testing use the true, pre-noise cursor, not the displayed noisy cursor. During a skip operation, TaskPhase and related trial states may remain stale because the normal state-update path is bypassed. In particular, a skip directly to completion may not record TaskPhase=7.
Participant Display
The participant-facing window contains:
- A light background.
- A black cursor (diameter configurable with
CursorDiameterPixels). - A black central cross.
- A gray center marker.
- A larger yellow warning marker.
- A black peripheral target (diameter configurable with
TargetDiameterPixels). - An experimental progress indicator.
- Introduction and sandbox instructions in white text on a dark-gray background.
- An experiment-completion message.
The participant receives no explicit visual indication of the current mapping, current reliability condition, mapping switches, PriorCondition, block or trial numbers, block transitions, or mapping probabilities. However, noise under Medium and Low reliability may be perceptible as cursor jitter during target-visible movement.
The target remains black across all mapping and reliability conditions. There is no explicit success-color cue; the target disappears after successful acquisition. The completion text is the literal string " ended " shown in white.
The target diameter affects both its drawing and the radius used for target-hit testing. The cursor diameter affects its appearance only; it does not change the center tolerance or the target-hit radius.
Diagnostic Window
A separate Qt diagnostic window titled:
FEP Visuomotor Joystick Diagnostics
is displayed to the experimenter.
Displayed Information
During experimental trials, the visible metrics panel displays:
- Current task stage.
- Original block role number (
Block: N / 6), even if some blocks were disabled. - Trial number within the current block and block trial count.
- Overall trial number and total configured active trials.
- Current Normal or Inverted mapping.
- Current High, Medium, or Low reliability condition.
- Configured visual-noise standard deviation for that trial, in pixels.
- Current task phase.
- Real-time reaction time, movement time, and total time.
- Cumulative overall, Normal-mapping, and Reversed-mapping averages of reaction time, movement time, and total time.
The visible panel does not show target angle or coordinates, joystick coordinates, cursor coordinates, mapping-switch flag, trials-since-switch counter, movement-started status, PriorCondition, or a separate reset/status message. Run averages are divided by mapping, not by sensory reliability. A separate diagnostic text label exists internally but is hidden and not populated.
Diagnostic Controls
| Control | Availability | Effect | Confirmation |
|---|---|---|---|
RESET CURRENT TRIAL
|
Experiment phases 1–5; shown as RESET UNAVAILABLE otherwise
|
Restarts the same trial and emits TrialReset
|
No |
SKIP TRIAL
|
Experiment phases 1–5, not paused | Abandons the current trial and advances; emits TrialSkipped
|
No |
SKIP CURRENT BLOCK
|
Experiment phases 1–5, not paused | Advances past the remaining trials of the block; emits ConditionSkipped
|
Yes |
SKIP INTRODUCTION
|
Introduction stage, not paused | Enters the experiment directly, bypassing sandbox; emits IntroductionSkipped
|
Yes |
SKIP SANDBOX
|
Sandbox stage, not paused | Enters the experiment; emits SandboxSkipped
|
No |
PAUSE / RESUME
|
All stages/phases except Finished | Freezes task-phase progression and resumes with adjusted internal timestamps; uses TaskPaused
|
No |
There is no separate diagnostic Continue button for the introduction or sandbox. Those stages normally advance using a rising joystick-button press, or may be bypassed using the skip controls.
Trial Reset
A trial may be manually reset during:
- Waiting for center.
- Holding center.
- Warning.
- Pre-target delay.
- Target-visible movement.
Reset is unavailable during:
- Feedback.
- Finished.
- Introduction.
- Sandbox.
Resetting a trial:
- Returns the task to
WaitingForCenter. - Restarts the phase timer.
- Clears movement-onset timing.
- Clears target-onset timing.
- Clears
MovementStarted. - Clears
TargetHit. - Produces a
TrialResetpulse. - Clears timing states.
- Resets baseline accumulation.
- Clears visual-noise state.
- Keeps the same target.
- Keeps the same mapping.
- Keeps the same sensory-reliability condition.
- Keeps the same block number.
- Keeps the same trial number.
- Keeps
PriorCondition. - Keeps
TrialsSinceMappingSwitch. - Does not rebuild or reshuffle the experimental sequence.
TrialReset lasts for one processing block. Resetting an Inverted trial during target-visible movement also enables the return-to-anchor behavior. A reset request is not processed while paused; requests pending at the time of a pause are deferred until processing resumes.
Skipping Trials, Blocks, and Tutorial Stages
Skip Trial
SKIP TRIAL is available during experimental phases before Feedback. It emits a one-processing-block TrialSkipped pulse, clears the current movement/timing values, does not count the abandoned trial in completed-trial performance averages, and advances to the next trial or finishes the run. A new target is generated on each non-final advance. Skipping an Inverted trial engages the return-to-anchor behavior.
Skip Current Block
SKIP CURRENT BLOCK requires confirmation and is available during experimental phases before Feedback. It emits ConditionSkipped, advances through all remaining trials in the current block, and starts the next enabled block or finishes the run. It does not register those abandoned trials as completed performance measurements. The operation calls the normal advancement routine repeatedly, consuming target-generation random-number draws. Unlike single-trial skip, it does not explicitly engage return-to-anchor for the interrupted Inverted trial.
Skip Introduction and Sandbox
SKIP INTRODUCTION, after confirmation, emits IntroductionSkipped and enters the experimental phase directly, also bypassing the sandbox. SKIP SANDBOX emits SandboxSkipped and enters the experimental phase from the sandbox. Both are available only in their corresponding stage when not paused.
Pause and Resume
PAUSE is available during introduction, sandbox, and experimental phases, including Feedback, but not Finished. While paused, TaskPaused is held at 1, phase progression and cursor rendering updates stop, and joystick states continue to be sampled. On resumption, internal phase, target-onset, movement-onset, and noise-update timestamps are shifted by the pause duration so that measured task intervals exclude paused time. Skip controls are disabled while paused; pending requests are not executed until processing resumes.
State-Logging Caveats During Skips
The skip-handling branches return early from Process() before the usual end-of-block state publication. Consequently, TaskTrial, TaskBlock, TaskCondition, TaskPhase, TrialsSinceMappingSwitch, and other trial states may show the preceding values on the skip processing block. They normally update on a later ordinary processing block. MappingSwitch can be stale or fail to pulse on the skip block. If a skip ends the run, the usual TaskPhase=7 update may never be recorded. Do not rely on a single isolated processing block to reconstruct skip transitions; inspect adjacent samples, skip event states, and trial/block identifiers. These behaviors are analysis considerations of the current implementation, not intended additional task conditions.
Timing Measurements
Timing uses std::chrono::steady_clock.
Events are detected during BCI2000 Process() calls, so effective timing resolution is limited by the signal-processing block interval.
Movement Onset
The joystick baseline is initialized when the center-hold phase begins and updated during center holding.
Movement onset is detected when either joystick axis differs from the center-hold baseline by more than 8 task-coordinate units.
abs(currentX - baselineX) > 8
or:
abs(currentY - baselineY) > 8
Reaction Time
Reaction time is measured from:
target onset -> movement onset
and stored in:
ReactionTimeMs
Movement Time
Movement time is measured from:
movement onset -> target acquisition
and stored in:
MovementTimeMs
Total Time
Total time is measured from:
target onset -> target acquisition
and stored in:
TotalTimeMs
Timing values are expressed in rounded milliseconds.
Timing states remain populated through the Feedback phase. When a target is reached without a detected movement onset, reaction and movement times are recorded as 0 and excluded from the corresponding run averages, while total time is still recorded. Paused durations are excluded through adjustment of internal timestamps when resuming.
Parameters
Experiment Structure
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
BaselineTrials
|
Integer | 20 | 0-10000 | Number of Normal trials in block 1 |
InitialInvertedTrials
|
Integer | 5 | 0-10000 | Number of Inverted trials in block 2 |
ReturnNormalTrials
|
Integer | 5 | 0-10000 | Number of Normal trials in block 3 |
MixedTrials
|
Integer | 20 | 0-10000 | Number of approximately balanced trials in block 4 |
StrongPriorTrials
|
Integer | 20 | 0-10000 | Number of Normal-dominant trials in block 5 |
BalancedPriorTrials
|
Integer | 20 | 0-10000 | Number of approximately balanced trials in block 6 |
At least one trial must be configured across the six block parameters. A count of zero disables that block without renumbering the remaining block roles.
Task Timing and Display
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
CenterHoldSeconds
|
Float | 3.0 | 0.0-60.0 | Required uninterrupted center-hold duration in seconds |
WarningSeconds
|
Float | 0.5 | 0.0-60.0 | Yellow warning interval in seconds |
PreTargetDelaySeconds
|
Float | 0.5 | 0.0-60.0 | Delay between warning and target onset in seconds |
FeedbackSeconds
|
Float | 0.5 | 0.0-60.0 | Feedback interval following target acquisition, in seconds |
CursorDiameterPixels
|
Float | 16.0 | 1.0-1000.0 | Cursor drawing diameter in nominal reference pixels |
TargetDiameterPixels
|
Float | 36.0 | 1.0-1000.0 | Target drawing and hit-test diameter in nominal reference pixels |
StimulusDisplay
|
Integer | 0 | 0 through number of detected displays | Physical monitor for participant stimuli; 0 uses default BCI2000 placement |
On Windows, the application enumerates available monitors for StimulusDisplay. CursorDiameterPixels affects cursor appearance only; TargetDiameterPixels also changes the hit-test radius.
Sensory Reliability Configuration
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
EnableSensoryReliability
|
Integer | 0 | 0-1 | Enable trial-wise visual-reliability noise; 0 disables it |
MediumReliabilityNoiseStd
|
Float | 5.0 | 0.0-1000.0 | Gaussian noise SD in pixels for Medium reliability |
LowReliabilityNoiseStd
|
Float | 15.0 | 0.0-1000.0 | Gaussian noise SD in pixels for Low reliability |
HighReliabilityProportion
|
Float | 0.34 | 0.0-1.0 | Target High-reliability trial proportion in enabled blocks |
MediumReliabilityProportion
|
Float | 0.33 | 0.0-1.0 | Target Medium-reliability trial proportion in enabled blocks |
LowReliabilityProportion
|
Float | 0.33 | 0.0-1.0 | Target Low-reliability trial proportion in enabled blocks |
SensoryNoiseCorrelationTimeMs
|
Float | 100.0 | 0.0-60000.0 | Temporal correlation time constant of noise, in milliseconds; zero gives independent innovations |
SensoryNoiseSeed
|
Integer | 1 | 0-2147483647 | Dedicated condition-assignment and noise seed; zero automatically selects a seed |
SensoryReliabilityBlocks
|
List | 4 5 6 (BCI2000 definition: 3 4 5 6, where 3 is the list length)
|
Entries 1-6; no duplicates | Block role numbers in which reliability conditions may be assigned; an empty list means all trials are High reliability |
Parameter Validation
Preflight requires at least one configured experimental trial, finite and nonnegative reliability values, noise SD for Low reliability not less than that for Medium, reliability proportions summing to 1 within 1e-6, valid unduplicated reliability-block numbers, positive cursor and target diameters, nonnegative task durations, and a valid selected display. The published parameter definitions also specify the listed bounds.
HighCursorGain is no longer a parameter in this version. There is no ExperimentMode or ResultsFile parameter.
States
The following states are declared by the FEP task. Widths and initial values refer to their published definitions; runtime values may change immediately on StartRun() or during Process().
| State | Width | Initial Value | Meaning |
|---|---|---|---|
CursorX
|
10 bit | 512 | Displayed horizontal cursor position, after mapping, sensory noise, and clipping (0-1023) |
CursorY
|
10 bit | 512 | Displayed vertical cursor position, after mapping, sensory noise, and clipping (0-1023) |
TaskPhase
|
3 bit | 0 | Current task phase (0-7) |
TaskCondition
|
1 bit | 0 | 0 Normal, 1 Inverted mapping |
TargetAngle
|
12 bit | 0 | Target angle in tenths of a degree |
TargetX
|
10 bit | 512 | Horizontal target coordinate (0-1023) |
TargetY
|
10 bit | 512 | Vertical target coordinate (0-1023) |
TaskBlock
|
8 bit | 0 | Current original experimental block role (1-6; 0 before experiment) |
TaskTrial
|
16 bit | 0 | Overall 1-based experimental trial number (0 before experiment) |
MovementStarted
|
1 bit | 0 | Level flag indicating detected movement onset during the trial |
TargetHit
|
1 bit | 0 | One-processing-block target-acquisition pulse |
TrialReset
|
1 bit | 0 | One-processing-block manual-reset pulse |
TrialSkipped
|
1 bit | 0 | One-processing-block trial-skip pulse |
ConditionSkipped
|
1 bit | 0 | One-processing-block current-block-skip pulse |
IntroductionSkipped
|
1 bit | 0 | One-processing-block introduction-skip pulse |
SandboxSkipped
|
1 bit | 0 | One-processing-block sandbox-skip pulse |
TaskPaused
|
1 bit | 0 | Level flag: 1 while paused; 0 otherwise |
MappingSwitch
|
1 bit | 0 | One-processing-block mapping-change event during normal progression; see skip caveats |
TrialsSinceMappingSwitch
|
16 bit | 0 | Consecutive non-switch trial transitions since the most recent mapping change |
PriorCondition
|
2 bit | 0 | Current block-level prior-frequency context (0-3) |
Introduction
|
1 bit | 0 | 1 during introduction or sandbox; 0 during experiment |
TutorialPhase
|
4 bit | 0 | 0 experiment, 1 introduction, 2 sandbox |
ReactionTimeMs
|
32 bit | 0 | Reaction time in rounded milliseconds |
MovementTimeMs
|
32 bit | 0 | Movement time in rounded milliseconds |
TotalTimeMs
|
32 bit | 0 | Target-onset to acquisition time in rounded milliseconds |
SensoryReliabilityCondition
|
2 bit | 0 | 0 High, 1 Medium, 2 Low reliability |
TrueCursorX
|
10 bit | 512 | Post-mapping, pre-noise horizontal task-logic cursor position (0-1023) |
TrueCursorY
|
10 bit | 512 | Post-mapping, pre-noise vertical task-logic cursor position (0-1023) |
SensoryNoiseX
|
31 bit | 1073741824 | X noise encoded as 1073741824 + round(100 * noise pixels) |
SensoryNoiseY
|
31 bit | 1073741824 | Y noise encoded as 1073741824 + round(100 * noise pixels) |
SensoryNoiseStd
|
18 bit | 0 | Configured noise SD encoded as round(100 * pixels) |
SensoryNoiseSeedEffective
|
32 bit | 1 | Effective noise and reliability-assignment seed |
External Joystick States
| State | Description |
|---|---|
JoystickXpos
|
Raw horizontal joystick position supplied through BCI2000 input logging |
JoystickYpos
|
Raw vertical joystick position supplied through BCI2000 input logging |
JoystickButtons1
|
Joystick button used to advance the introduction and sandbox |
The application also accesses BCI2000's standard Running state when ending the experiment. Joystick logging must be configured separately using LogJoystick.
States Not Present in the Current Implementation
The task does not define DisplayedCursorX, DisplayedCursorY, an exact state named SensoryReliability, PracticeTrial, TaskBlockType, or CursorGainCondition. Instead, displayed coordinates use CursorX/Y, pre-noise coordinates use TrueCursorX/Y, and visual reliability is recorded through SensoryReliabilityCondition and the sensory-noise states.
State Lifecycle and Encoding Notes
TargetX/Y have published initial values of 512 but are explicitly set to 0 during introduction/sandbox. TaskTrial is 1-based once experimental trials begin. Pulse states normally clear on the following processing block, whereas TaskPaused is held at 1 throughout a pause and MovementStarted remains high from movement detection until trial advancement. Noise states use fixed-point encoding described in Noise Seeds and State Encoding. State publication immediately after skip operations has known limitations described in State-Logging Caveats During Skips.
Cursor Coordinates
CursorX and CursorY represent the final displayed cursor position including mapping inversion, return-to-anchor transformation, any applied Gaussian visual noise, and display-boundary clipping.
TrueCursorX and TrueCursorY record the separate post-mapping, pre-noise cursor trajectory. This is the trajectory used for center detection and target-hit detection. It does not represent untransformed joystick input.
The participant-visible drawing is positioned using the displayed cursor. Both true and displayed coordinates are recorded as 10-bit states over the range 0-1023. Encoded noise samples are recorded separately. The diagnostic window does not currently show either cursor coordinate pair.
The application does not record an independent pre-mapping cursor state. When enabled, JoystickXpos/Ypos provide the underlying joystick samples needed to reconstruct a raw joystick-equivalent trajectory offline.
Data Recording
The task records its behavioral variables as synchronized BCI2000 states in the standard .dat file, subject to the configured BCI2000 recording and joystick-logging settings.
Recorded information includes:
- Displayed and true cursor trajectories (
CursorX/YandTrueCursorX/Y). - Joystick trajectory when external joystick logging is enabled.
- Task phase, Normal/Inverted mapping, prior context, and mapping-switch history.
- Sensory-reliability condition, actual generated noise, configured noise SD, and effective seed.
- Target angle and coordinates, experimental block, and trial number.
- Movement onset, target acquisition, and reaction/movement/total timing.
- Trial reset, trial skip, block skip, introduction skip, sandbox skip, and pause status.
- Introduction/sandbox status and experiment completion as represented by task states.
The application passes signal channels through unchanged:
Output = Input;
Operator Logging
The application writes bciout messages for task startup and shutdown, the effective sensory-noise seed, per-block High/Medium/Low reliability distributions split by Normal/Inverted mapping and switch status, and trial-completion results including trial, block, mapping, reliability, reaction time, and movement time. These are diagnostic/operator messages rather than a separate structured task-results file.
Secondary Output
The current implementation does not write an application-specific CSV file, JSON file, text results file, or database. There is no ResultsFile parameter.
Offline Analysis Notes
The table below gives common event and measurement identifications. When reset, skip, or pause controls are used, inspect adjacent processing blocks and the recorded configuration instead of relying solely on one state sample.
| Measurement or Event | Recommended Identification |
|---|---|
| Experimental samples | Introduction == 0
|
| Introduction | Introduction == 1 and TutorialPhase == 1
|
| Sandbox | Introduction == 1 and TutorialPhase == 2
|
| Active experimental trial | Introduction == 0, TaskTrial > 0, and TaskPhase from 1 through 6
|
| Target onset | Transition into TaskPhase == 5
|
| Movement onset | Rising transition of MovementStarted
|
| Target acquisition | TargetHit == 1
|
| Normal mapping | TaskCondition == 0
|
| Inverted mapping | TaskCondition == 1
|
| High reliability | SensoryReliabilityCondition == 0
|
| Medium reliability | SensoryReliabilityCondition == 1
|
| Low reliability | SensoryReliabilityCondition == 2
|
| Reliability globally disabled | Verify EnableSensoryReliability == 0 in recorded parameters; all trials then use condition 0
|
| Configured visual-noise SD | SensoryNoiseStd / 100 pixels
|
| Actual X visual noise | (SensoryNoiseX - 1073741824) / 100 pixels
|
| Actual Y visual noise | (SensoryNoiseY - 1073741824) / 100 pixels
|
| Pre-noise task-logic cursor trajectory | TrueCursorX and TrueCursorY
|
| Displayed cursor trajectory | CursorX and CursorY
|
| Mapping switch | MappingSwitch == 1 (subject to skip-operation caveats)
|
| Trials since switch | TrialsSinceMappingSwitch (subject to skip-operation caveats)
|
| Previous mapping | Previous trial's TaskCondition
|
| Prior context | PriorCondition
|
| Experimental block | TaskBlock
|
| Overall trial | TaskTrial
|
| Target angle | TargetAngle / 10 degrees
|
| Target position | TargetX and TargetY
|
| Joystick trajectory | JoystickXpos and JoystickYpos
|
| Reaction time | ReactionTimeMs
|
| Movement time | MovementTimeMs
|
| Total time | TotalTimeMs
|
| Manual reset | TrialReset == 1
|
| Trial skipped | TrialSkipped == 1
|
| Current block skipped | ConditionSkipped == 1
|
| Introduction skipped | IntroductionSkipped == 1
|
| Sandbox skipped | SandboxSkipped == 1
|
| Task paused | TaskPaused == 1
|
| Experiment completion | TaskPhase == 7 in ordinary progression; may be absent for skip-to-finish
|
Event-Like States
The following are designed to be one-processing-block event flags: MappingSwitch, TargetHit, TrialReset, TrialSkipped, ConditionSkipped, IntroductionSkipped, and SandboxSkipped. MovementStarted instead remains high from movement onset through the rest of the trial and Feedback. TaskPaused is a level state held at 1 throughout a pause.
Analysis Considerations
- Use
CursorX/Yfor what the participant saw andTrueCursorX/Yfor the cursor that determined hits and centering. Visual noise and display clipping can make the two disagree. - Divide cursor-state coordinates by 1023 to recover normalized coordinates. Use the provided noise-state offset and scale to recover noise in pixels.
- Use the recorded parameter
EnableSensoryReliabilityto distinguish a disabled manipulation from genuine High-reliability trials. - Reconstruct prior mapping by inspecting previous trials;
PriorConditionis a block context rather than a previous-trial label or inferred belief. - Check skip pulses and neighboring trial/block values when deriving event onsets. Mapping-switch pulses, trial identifiers, and
TaskPhasemay be stale or missing on early-return skip processing blocks. - Paused intervals should be identified from
TaskPaused, and internal timing measurements exclude pause duration on resume. - If target acquisition occurs without a detected movement onset, reaction and movement timing states are zero but total time is recorded; such zero values should not automatically be interpreted as physiologically instantaneous responses.
- Raw joystick reconstruction requires external input logging; the application itself does not activate
LogJoystick.
Differences from USBHIDJoystickTask
Retained
- BCI2000
ApplicationBasestructure. - USB joystick input.
- Center-out reaching.
- Center hold.
- Warning interval.
- Pre-target delay.
- Target-directed movement.
- Feedback interval.
- Continuous target-angle generation.
- Reaction-time measurement.
- Movement-time measurement.
- Total-time measurement.
- Manual trial reset.
- Progress bar.
- BCI2000 state logging.
- Direct and inverted joystick-control mappings.
Removed
The FEP task removes the earlier task's:
ExperimentMode.- Automatic-only and Controlled-only modes.
- Ordered-start condition.
TaskBlockType.- Green versus red condition-specific targets.
- Explicit condition instructions.
- Explicit teaching of the inverted mapping.
- Condition-specific practice trials.
PracticeTrial.- Optional tutorial setting.
- Diagnostic Continue button.
- Secondary CSV results file.
- Participant-facing block announcements.
Added
The FEP task adds:
- Six predefined experimental block roles.
- Hidden Normal and Inverted mappings.
- Unannounced mapping switches.
MappingSwitch.TrialsSinceMappingSwitch.PriorCondition.SensoryReliabilityConditionand configurable High/Medium/Low visual sensory reliability.- Configurable Gaussian cursor noise and correlation time.
- Separate
TrueCursorX/Yand displayedCursorX/Ylogging. SensoryNoiseX/Y,SensoryNoiseStd, andSensoryNoiseSeedEffective.- Researcher controls for skipping trial, block, introduction, and sandbox, and pausing/resuming.
TrialSkipped,ConditionSkipped,IntroductionSkipped,SandboxSkipped, andTaskPausedstates.- Configurable
CursorDiameterPixelsandTargetDiameterPixelsparameters. - Diagnostic real-time timing values and run averages.
- A minimal Normal-mapping sandbox.
- Black targets across all mapping conditions.
- Normal-dominant and approximately balanced mapping contexts.
Known Limitations and Analysis Considerations
- The current module does not implement an explicit computational Free Energy Principle model.
PriorConditionrepresents experimental block context rather than an inferred participant belief.- Participant surprise or expectation is not measured directly by the application.
- Blocks 4 and 6 use similar approximately balanced mapping-generation rules but occur after different preceding mapping histories.
- Mapping pseudorandomization constraints are attempted but are not guaranteed if all 64 candidate sequences fail.
- There is no unsuccessful-trial timeout.
- Reliability manipulation is disabled by default;
SensoryReliabilityCondition=0by itself does not show that reliability was enabled. - Reliability is assigned with a counterbalancing heuristic across mapping and switch status, not by a wholly independent shuffle.
- Gaussian noise affects the displayed cursor only during target-visible movement; it does not change the cursor position used for center and target-hit detection.
- The display may visually disagree with the target-hit decision because logic uses the true pre-noise cursor.
- The correlated noise process begins at zero at target onset rather than stationary variance.
- The true cursor is separately recorded, but no independent pre-mapping/untransformed cursor trajectory is recorded.
- The diagnostic window does not show target, joystick, cursor, switch, trials-since-switch, or free-form status fields; run averages are divided by Normal/Reversed mapping, not by reliability.
TargetDiameterPixelschanges target-hit radius;CursorDiameterPixelschanges only cursor appearance.- Skip operations can result in stale or missing per-block values for
MappingSwitch,TaskPhase, and trial/block identifiers. Skip-to-finish may not publishTaskPhase=7. - A block skip during Inverted target-visible movement does not explicitly preserve the anchored return mapping.
- Pausing is allowed during introduction, sandbox, and feedback, and the timing system compensates for pause duration on resume.
- Physical display geometry depends on the configured participant monitor and BCI2000 window dimensions.
- No application-specific CSV, JSON, text results file, or database is generated.
References
Friston, K. The free-energy principle: a unified brain theory?. Nat Rev Neurosci 11, 127–138 (2010). https://doi.org/10.1038/nrn2787
See also
- Visuomotor Joystick Task
- Logging Input
- LogJoystick
- Module Command Line Options
- ApplicationWindow Class
- BCI2000 File Format
- ApplicationBase Class