Skip to main content

A toolkit for EEG phase estimation

Project description

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

eegphasepy-0.0.6.tar.gz (17.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

eegphasepy-0.0.6-py3-none-any.whl (17.2 kB view details)

Uploaded Python 3

File details

Details for the file eegphasepy-0.0.6.tar.gz.

File metadata

  • Download URL: eegphasepy-0.0.6.tar.gz
  • Upload date:
  • Size: 17.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.3

File hashes

Hashes for eegphasepy-0.0.6.tar.gz
Algorithm Hash digest
SHA256 b47b7a3177691d522f0199e4087774886b933ddac0d0c2d46017344354695ed8
MD5 864b14cbeb82e3fcca533bc0b27806c8
BLAKE2b-256 163664066f010a8de8b211951133355a7c140d7616b6a1f79e62039234493d7f

See more details on using hashes here.

File details

Details for the file eegphasepy-0.0.6-py3-none-any.whl.

File metadata

  • Download URL: eegphasepy-0.0.6-py3-none-any.whl
  • Upload date:
  • Size: 17.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.3

File hashes

Hashes for eegphasepy-0.0.6-py3-none-any.whl
Algorithm Hash digest
SHA256 4e836bcf6045476a2610d4fdecbed905cf60a3c64023a483108c9b12b8ef0b14
MD5 624e0aa2a31661307b0bf35e2c6c7428
BLAKE2b-256 c50f1bbd9343e3e8e2d9494a50daa2d1a60e0ecad54a6a3cb2034816c56a1a78

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page