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.7.tar.gz (17.6 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.7-py3-none-any.whl (17.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: eegphasepy-0.0.7.tar.gz
  • Upload date:
  • Size: 17.6 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.7.tar.gz
Algorithm Hash digest
SHA256 daa75f9b07eaf4ba587ea7d5a7f770a8bce79619d6ce9f09384a5cdba9c3150b
MD5 6c0b2064b3626bcd84927648301fdf81
BLAKE2b-256 587e04af68f10e3460c86b47fd738724ea2c9b937a5d53dc01a7cd03aae0f8c4

See more details on using hashes here.

File details

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

File metadata

  • Download URL: eegphasepy-0.0.7-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.7-py3-none-any.whl
Algorithm Hash digest
SHA256 43701522332e9118534e37ed4dba706f28fd4f45554b261e02849d4e960d90a1
MD5 66baf2a8a2b00b8b18bb6796e40c2aad
BLAKE2b-256 736f9285d15b3afa8589c83b17ee81c6aa07d44170cbbe73ff7946bbd020934d

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