This repository contains a workflow for running closed-loop EEG experiments with stimulation being delivered as waveforms created by the soundcard. The waveforms can drive vibrating actuators, speakers or headphones. The stimulation feedback is triggered on a target phase of a target frequency of the EEG signal. The algorithm used to extract the target phase and determine the stimulation timing is based on McNamara et al.'s Oscilltrack (doi.org/10.1016/j.celrep.2022.111616): https://colinmcn.github.io/OscillTrack/ OscillTrack is subject to patent application WO/2020/183152 and is provided as is for research use only with the requirement that McNamara et al. (doi.org/) is cited in publications that avail of this method of oscillatory tracking.
In order to minimise computation delays, the workflow is split into components that are ran concurrently or in parallel (using threading.Thread
or multiprocessing.Process
respectively). The components implemented until now are reading (read.py
), writing (write.py
), analysing EEG & stimulation (analysis.py
) and plotting (plot.py
).
The workflow is then organised as : reading ->
analysis ->
plotting AND reading ->
writing .
Each component communicates with the components that it connects to or is connected to using ZMQ
, a message-passing protocol. This choice was inspired by Autopilot, an open-source package for running distributed behavioral experiments on Raspberry Pis. For a great introduction into ZMQ
in Python for scientists, check out this tutorial: Part 1 and Part 2.
This repository is not a registered Python package (yet). In order to use it, one would need to clone the repository and then use their favorite environment manager (e.g. conda
, venv
or virtualenv
). Use the requirements.txt
on a new environment to install most of dependencies of EEGVIBE
. The commands to create a new environment and install dependencies from requirements.txt
depend on the environment manager used, but they are all relatevely easy to find online.
EEGVIBE
is not yet a registered package as it depends on eego_sdk
for reading in EEG signals from an amplifier. The eego_sdk
package is a Python wrapper on a C++ library that needs to be built (using CMake) and linked to the current project or simply added to PYTHONPATH
so Python knows what to do at import eego_sdk
. Check the wrapper repository for instructions or contact Dr Petra Fischer for more details.
Includes functions for reading data from an EEG amplifier (read_from_stream
) or from an .HDF5
or .csv.
file containing stored data from a previous recording sesion (read_from_file
). The latter option is useful when developing new components and debugging them and/or being away from the lab where the EEG amplifier is.
This component includes two modes:
-
running the feedback loop, that is tracking the phase of the target frequency from one EEG signal channel and triggering stimulations when the target phase is reached.
-
replaying a stimulation schedule. This is an open-loop mode, where there are no frequency & phase targets on the EEG signal. All stimulation from a previous experiment are replayed at exactly the same timepoints as they were originally triggered, relative to the beginning of the experiment.
Includes a function (plot_stream
) that creates a Qt
plotting widget and updates it online as new EEG samples are read. The channel that is tracked (see Analysis section) is plotted by default, and more channels (e.g. EMG data channels) can be added to the same axes. A vertical offset is introduces to better distinguish between signals.
Component for storing data into files. By default the HDF5
format is used and data is stored in chunks, to make writing more efficient. Using HDF5
over other formats like csv
also makes reading data much faster, either when used to read_from_file
or for offline analysis after the recording session.
There are two ways of using EEGVIBE
. The more user-friendly and less flexible way is to use the functions in eegvibe/run.py
. These are wrappers around a closed-loop recording workflow (run_tracking
) and a replay workflow (run_replay
). They come with docstrings that explain all of their arguments.
Alternatively, one can adapt these run_
functions to their own workflow, e.g. by using different EEG filters, different phase tracking algorithms or different plots. This is a more modular approach, where one can pick and choose which components to use and which to change/extend to come up with their own workflow like the ones in eegvibe/run.py
.