EEGPhasePy documentation
EEGPhasePy is an open-source toolkit for developing real-time EEG phase estimation and analyzing the results of EEG phase estimation results. It includes implementations of common statistics and figures used to quantify EEG phase estimation results. EEGPhasePy also includes implementations of EEG phase estimation algorithms alongside optimizations of parameters of these algorithms to improve their performance on a participant-by-participant basis.
Getting started
We will walk through getting started with your first real-time EEG phase estimation experiment using EEGPhasePy, including real-time phase estimation and analysis of the outcome of the experiment. To get started, install the package from PyPi by running the command:
pip install eegphasepy
Once you’ve installed EEGPhasePy, you will need to select the model you’re planning to run phase estimation with. Below, we are using the Educated Temporal Prediction (ETP) model Shirinpour et al. [1], see API Reference for the models currently implemented in EEGPhasePy.
from EEGPhasePy.estimators import ETP
We will perform mu-band phase estimation from the C3 electrode
Real-time phase estimation
In a live experiment your amplifier sends packets of samples at a fixed rate. On each packet arrival you append the new samples to a rolling 2 s buffer, run ETP on that buffer, and schedule a trigger to fire at the sample offset ETP returns. predict returns the number of samples from the end of the current window at which the target phase is expected — converting that to wall-clock time (offset / fs) gives you how far in the future to schedule the stimulus.
import numpy as np
import scipy.signal as signal
import collections, time
from EEGPhasePy.estimators import ETP
fs = 2000
window_len = 2 * fs # 2 s rolling buffer
packet_size = int(0.06 * fs) # samples per amplifier packet (~60 ms)
rt_filter = signal.firwin(120, [8, 12], fs=fs, pass_zero=False)
gt_filter = signal.firwin(300, [8, 12], fs=fs, pass_zero=False)
etp = ETP(rt_filter, gt_filter, fs)
etp.fit(training_signal, min_ipi=int(fs * 1/12))
buffer = collections.deque(maxlen=window_len) # auto-drops oldest samples
triggers = []
# This would typically be a while loop that gets the latest packet from your amplifier, here we've just simulated a sliding window with a simulated signal
for packet_start in range(0, len(testing_signal) - packet_size, packet_size):
packet = testing_signal[packet_start:packet_start + packet_size]
buffer.extend(packet)
if len(buffer) < window_len:
continue # wait until the buffer is full
window = np.array(buffer)
try:
offset = etp.predict(window, target_phase=0) # here we use ETP to predict the next sample of a peak on EEG
trigger_time = time.time() + offset / fs # absolute wall-clock time
trigger_sample = packet_start + packet_size + offset
triggers.append(trigger_sample)
# schedule_trigger(trigger_time) # call your hardware trigger here
except RuntimeError:
pass # no peaks found in this window
Analysing the output
In raw EEG, you would typically have trigger markers stored as annotations in your EEG file. EEGPhasePy just needs the sample number each trigger occurs at to analyze the outcome of your phase estimation experiment.
To quantify how well the desired phase was targetted you can use mean_phase_from_triggers() and std_phase_from_triggers(), which return the circular mean and standard deviation of the phase at each trigger (a std of 50°–70° is typical in published studies). phase_accuracy_from_triggers() returns a 0–1 score where 0.5 is chance, 0 is anti-phase, and 1 is perfect locking.
mean_phase = etp.mean_phase_from_triggers(testing_signal, triggers, degree=True)
std_phase = etp.std_phase_from_triggers(testing_signal, triggers, degree=True)
accuracy = etp.phase_accuracy_from_triggers(testing_signal, triggers, 0)
print(f"Mean phase: {mean_phase:.1f}° | Std: {std_phase:.1f}° | Accuracy: {accuracy * 100:.1f}%")
Guide
Estimators
Optimizing
Analysis
Examples
Bibliography
Sina Shirinpour, Ivan Alekseichuk, Kathleen Mantell, and Alexander Opitz. Experimental evaluation of methods for real-time EEG phase-specific transcranial magnetic stimulation. J. Neural Eng., 17(4):046002, July 2020.
Christoph Zrenner, Dragana Galevska, Jaakko O Nieminen, David Baur, Maria-Ioanna Stefanou, and Ulf Ziemann. The shaky ground truth of real-time phase estimation. Neuroimage, 214(116761):116761, July 2020.
Christoph Zrenner, Debora Desideri, Paolo Belardinelli, and Ulf Ziemann. Real-time EEG-defined excitability states determine efficacy of TMS-induced plasticity in human motor cortex. Brain Stimul., 11(2):374–389, March 2018.
Hao Liu, Zihui Qi, Yihang Wang, Zhengyi Yang, Lingzhong Fan, Nianming Zuo, and Tianzi Jiang. A novel real-time phase prediction network in EEG rhythm. Neurosci. Bull., 41(3):391–405, March 2025. doi:10.1007/s12264-024-01321-z.
Sina Shirinpour, Ivan Alekseichuk, Malte R. Güth, Zachary Haigh, Miles Wischnewski, and Alexander Opitz. Bayesian temporal prediction: a robust algorithm for real-time eeg phase-dependent brain stimulation. IEEE Transactions on Biomedical Engineering, 73(2):611–620, 2026. doi:10.1109/TBME.2025.3589970.
Ahmed Fawzy Gad. Pygad: an intuitive genetic algorithm python library. Multimedia Tools and Applications, pages 1–14, 2023.