Skip to main content

EEGPhasePy

Tests codecov PyPI version Python versions License: BSD-3-Clause

A toolkit for developing and analyzing real-time and pseudo-real-time EEG phase estimation.

EEGPhasePy includes implementations of various EEG phase estimation algorithms — including Educated Temporal Prediction (ETP) and PHASTIMATE (autoregressive) — alongside offline analysis helpers for evaluating phase estimation experiments. For background on EEG phase estimation and its applications, see Zrenner & Ziemann (2024). More phase estimators will continue to be added in the future.

Features

  • ETP — Educated Temporal Prediction (Shirinpour et al., 2020): uses average interpeak-interval to determine time to next target phase. Similar accuracy to AR with the added benefit of working well with amplifiers that have low packet send rates.
  • PHASTIMATE — Autoregressive phase estimator (Zrenner et al., 2020): uses an AR model to compensate for filter edge effects and extracts instantaneous phase via the Hilbert transform. Estimates ongoing phase rather than predicting.
  • Parameter optimization — Bayesian and genetic optimization (via bayesian-optimization and PyGAD) over AR order and window edge for PHASTIMATE. Improve accuracy of the AR model on a participant-by-participant basis.
  • Visualization — Polar phase histograms and average ± std pre/post-trigger waveforms via matplotlib.
  • Supports Python 3.9–3.13.

Documentation

Full documentation including API reference, usage guides, and examples is available at eegphasepy.readthedocs.io.

Table of contents

Section Pages
Guide What is EEG phase estimation? · Real-time phase estimation
Models ETP-based phase estimation · Autoregressive phase estimation
Optimizing Bayesian optimization of PHASTIMATE · Genetic optimization of PHASTIMATE
Analysis Waveform plots · Polar histograms · Phase estimation statistics
Examples Gallery
Reference API reference

Installation

pip install eegphasepy

Quick start

Setting up a model

Select the model you plan to run phase estimation with. Below we use ETP; see the models documentation for all available estimators.

import numpy as np
import scipy.signal as signal
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))

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 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 collections, time

buffer = collections.deque(maxlen=window_len)  # auto-drops oldest samples
triggers = []

# In a real experiment this would be a while loop reading packets from your amplifier
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)  # predict next peak
        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.

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}%")

mean_phase_from_triggers and std_phase_from_triggers 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.

Visualization

import EEGPhasePy.viz as viz

# Polar histogram of triggered phases
polar_fig = etp.polar_histogram_from_triggers(testing_signal, triggers)

# Average ± std waveform around trigger events
waveform_fig = etp.plot_mean_std_waveform_from_triggers(
    testing_signal, triggers, tmin=0.1, tmax=0.1
)

Both functions return a matplotlib.figure.Figure. See the waveform plots and polar histograms documentation for color and style customization options.

Contributing

Contributions are welcome. Please open an issue or pull request on GitHub.

Citation

If you use EEGPhasePy in your research, please cite the underlying algorithm(s) you end up using:

  • ETP: Shirinpour et al. (2020). Experimental Evaluation of Methods for Real-Time EEG Phase-Specific Transcranial Magnetic Stimulation. PMC8293904
  • PHASTIMATE: Zrenner et al. (2020). The shaky ground truth of real-time phase estimation. PMID 29191438

Licence

BSD 3-Clause Licence. See LICENCE for details.

Acknowledgements

Metadata

Release files for eegphasepy 0.0.8

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for eegphasepy 0.0.8
File Size Uploaded
eegphasepy-0.0.8.tar.gz 17.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for eegphasepy 0.0.8
File Interpreter ABI Platform
eegphasepy-0.0.8-py3-none-any.whl Python 3 none any Details

Total release size: 35.1 kB

Release files / eegphasepy-0.0.8.tar.gz

Download URL eegphasepy-0.0.8.tar.gz
Size 17.7 kB
Tags Source
SHA-256 checksum
How to use checksums
486ab21804e85f2d9a09d09589954395522a158ea839b65a8dcc8b07df7f6dab
BLAKE2b-256 checksum
How to use checksums
bfbab51b0b0e75af80909feb09e047ae9668c980f7b557fe61080e51fe9e1f61
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.12.3

Release files / eegphasepy-0.0.8-py3-none-any.whl

Download URL eegphasepy-0.0.8-py3-none-any.whl
Size 17.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
139899a2f184de13f93e01046f700521876f3cd115a815f42641e5ef94e87351
BLAKE2b-256 checksum
How to use checksums
7f40cd6e53c77942603f338076c679a47985f8d3d3753a85f6e5e0c1b5aa441b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.12.3

Release history Release notifications | RSS feed

This release

0.0.8 This release

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page