Creating an experiment plugin
rtcog includes two built-in experiment types:
Basic: Performs basic real-time fMRI preprocessing.
ESAM (Experience Sampling): Builds on Basic to support template matching, response collection, and dynamic real-time data streaming.
Plugin Components
If you’re designing a custom experiment, such as an online neurofeedback protocol or novel stimulus design, you can create your own experiment plugin by implementing or extending these components:
Component |
Role |
|---|---|
Processor |
Defines how each fMRI volume is processed |
ActionSeries (Optional) |
Performs actions based on experiment state |
The Processor Class
The Processor handles how each TR is processed.
Because preprocessing and template matching are fully configurable via
the config file or subclassing PreprocStep, Matcher, and/or
HitDetector, subclassing Processor is not recommended. Most use
cases can simply reuse one of the following:
BasicProcessor: Basic real-time fMRI preprocessing.ESAMProcessor: ExtendsBasicProcessorto support online template matching and real-time data visualization.
The ActionSeries Class (Optional)
The ActionSeries class responds to the state of the experiment. By
extending BaseActionSeries, you can implement your own custom logic
for what should occur at each stage of the experiment:
on_start(): The beginning of the experimenton_loop(): Main experiment loopon_hit(): Triggered when a TR sufficiently matches a template (ESAM only)on_end(): The end of the experiment
ActionSeries are optional. If you don’t provide one, the experiment
will simply run without performing any additional actions. You can also
pass --no_action when running rtcog to prevent your
ActionSeries from running.
rtcog by default comes with two action series:
BasicActionSeries: Displays a basic GUI until the experiment endsESAMActionSeries: Also collects voice recording and question responses at each hit
If you have a GUI (outlined below), it should be owned by your ActionSeries so it can
be updated throughout the experiment.
Example for an ESAM experiment:
class MyActionSeries(BaseActionSeries):
def __init__(self):
gui = MyGUI(opts=opts)
super().__init__(sync, opts=opts, gui=gui)
def on_start(self):
startup_function()
self.gui.draw_resting_screen()
def on_loop(self):
poll_for_escape_key()
def on_hit(self):
self.gui.show_custom_prompt()
apply_stimulation()
def on_end(self):
teardown_function()
self.gui.close_psychopy_window()
The GUI Class (Optional)
The GUI defines what the participant sees and interacts with.
If you only want to change the Likert questions displayed to the participant, you can
simply create a json file with your custom questions and put the path in your config yaml
file under q_path. Define the text, labels, and name for each question:
{
"text": "Q1/11. How alert were you?",
"labels": ["Fully asleep", "Somewhat sleepy", "Somewhat alert", "Fully alert"],
"name": "alert"
}
See questions_v1.json for a full example.
However, if you want to create a more complex GUI, you can
create a custom GUI class.
You can inherit from:
Class |
Description |
|---|---|
|
Blank starting point |
|
Displays a fixation cross and general instructions |
|
Adds voice recording, question prompts, and response collection |
Example:
class MyGUI(EsamGUI):
def show_custom_prompt(self):
self._draw_stims(self._custom_stim)
You can present:
Visual prompts
Trial feedback
Questions or rating scales
Audio/voice recording
Or anything else that
Psychopysupports
Make sure to instantiate your GUI as an attribute of your
ActionSeries.
Registering Your Custom Experiment Plugin
To make your plugin available to rtcog, register it in
rtcog/experiment_registry.py:
"my_custom_experiment": {
"processor": ESAMProcessor, # Or BasicProcessor
"action" MyActionSeries # Optional
}
Now, you can pass the name of your experiment plugin when running rtcog and
it will look it up in the registry: --exp_type my_custom_experiment