pydmdeeg
Dynamic Mode Decomposition for EEG Signal Analysis
A Python library for extracting spatio-temporal coherent patterns from EEG data using Dynamic Mode Decomposition (DMD). This method enables data-driven decomposition of neural recordings into interpretable oscillatory modes.
Features
- Two DMD algorithms: Exact and standard implementations based on Tu et al. (2014)
- Sliding window analysis: Configurable window size and overlap for time-resolved decomposition
- Delay embedding: Shift-stacking technique for enhanced temporal dynamics capture
- SVD truncation: Optional hard thresholding (optht) or fixed-rank truncation for noise reduction
- Data scaling: Multiple preprocessing options (centering, normalization, z-scoring)
- Rich visualization: Built-in plotting for DMD spectra, channel statistics, and reconstruction errors
- Multi-trial support: Handle epoched EEG data with trial labels for condition comparisons
Installation
From PyPI (recommended)
pip install pydmdeeg
From source
git clone https://github.com/christiangoelz/pydmdeeg.git
cd pydmdeeg
pip install -e ".[dev]"
Quick Start
import numpy as np
from pydmdeeg import DMD
# Generate synthetic EEG-like data
# Shape: (n_trials, n_channels, n_timepoints)
n_trials, n_channels, n_times = 10, 64, 1000
sampling_rate = 256 # Hz
# Create data with oscillatory components
t = np.linspace(0, n_times/sampling_rate, n_times)
X = np.zeros((n_trials, n_channels, n_times))
for trial in range(n_trials):
for ch in range(n_channels):
# Alpha (10 Hz) and beta (20 Hz) oscillations with noise
X[trial, ch, :] = (
np.sin(2 * np.pi * 10 * t) +
0.5 * np.sin(2 * np.pi * 20 * t) +
0.3 * np.random.randn(n_times)
)
# Trial labels (e.g., 0 = rest, 1 = task)
y = np.array([0, 0, 0, 0, 0, 1, 1, 1, 1, 1])
# Channel names
channels = [f'Ch{i+1}' for i in range(n_channels)]
# Initialize DMD
dmd = DMD(
X=X,
y=y,
channels=channels,
dt=1/sampling_rate,
win_size=128,
overlap=64,
algorithm='exact',
datascale='norm'
)
# Run decomposition
dmd.DMD_win()
# Extract alpha band (8-12 Hz) mode statistics
alpha_stats = dmd.mode_stats(fbands=[[8, 12]], labels=[0, 1])
print(alpha_stats)
# Get mode magnitudes for specific frequency band
psi = dmd.get_PSI(fband=[8, 12], labels=[1])
API Reference
DMD Class
DMD(
X, # EEG data: (n_trials, n_channels, n_times) or (n_channels, n_times)
y, # Trial labels: (n_trials,)
channels, # Channel names: list of strings
dt, # Sampling interval: 1/sampling_rate
stacking_factor=0, # Delay embedding factor (0 = no stacking)
win_size=100, # Window size in samples
overlap=0, # Window overlap in samples
datascale='norm', # Scaling: 'none', 'centre', 'norm', 'centre_norm'
algorithm='exact', # DMD algorithm: 'exact' or 'standard'
truncation={'method': None, 'keep': None} # SVD truncation settings
)
Key Methods
| Method | Description |
|---|---|
DMD_win() |
Run DMD decomposition across sliding windows |
mode_stats(fbands, labels) |
Compute statistics for modes in frequency bands |
get_PSI(fband, labels) |
Extract mode magnitudes for frequency band |
get_AMP(fband, labels) |
Extract mode amplitudes for frequency band |
select_trials(selector) |
Select subset of trials |
plot_frRPsi(labels) |
Plot DMD power spectrum |
plot_frRLam(labels) |
Plot eigenvalue spectrum |
plot_statsCH() |
Plot channel statistics heatmap |
plot_ChAmpErr(labels) |
Plot reconstruction error |
Mathematical Background
Dynamic Mode Decomposition approximates the linear operator A that best maps consecutive time snapshots:
X' ≈ AX
where X and X' are time-shifted data matrices. The eigenvalues of A (λ) encode oscillation frequencies and growth/decay rates, while eigenvectors (Φ) represent spatial patterns.
For EEG analysis:
- Frequencies: μ = Im(log(λ)) / (2πΔt)
- Spatial modes: Φ shows channel contributions to each oscillatory pattern
- Amplitudes: |Φ| weighted by initial conditions
Publications Using This Method
This implementation has been validated in peer-reviewed neuroscience research:
-
Goelz C et al. (2021). Classification of visuomotor tasks based on electroencephalographic data depends on age-related differences in brain activity patterns. Neural Networks. DOI
-
Goelz C et al. (2021). Electrophysiological signatures of dedifferentiation differ between fit and less fit older adults. Cognitive Neurodynamics. DOI
-
Goelz C et al. (2018). Improved Neural Control of Movements Manifests in Expertise-Related Differences in Force Output and Brain Network Dynamics. Frontiers in Physiology. DOI
-
Vieluf S et al. (2018). Age- and Expertise-Related Differences of Sensorimotor Network Dynamics during Force Control. Neuroscience. DOI
References
- Brunton BW et al. (2016). Extracting spatial-temporal coherent patterns in large-scale neural recordings using dynamic mode decomposition. J Neurosci Methods. DOI
- Tu JH et al. (2014). On dynamic mode decomposition: Theory and applications. J Computational Dynamics. DOI
- Donoho D & Gavish M (2014). The Optimal Hard Threshold for Singular Values is 4/√3. IEEE Trans Information Theory. DOI
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
# Install development dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run linting
ruff check .
# Run type checking
mypy pydmdeeg
License
MIT License - see LICENSE for details.
Citation
If you use this software in your research, please cite:
@software{pydmdeeg,
author = {Goelz, Christian},
title = {pydmdeeg: Dynamic Mode Decomposition for EEG Analysis},
url = {https://github.com/christiangoelz/pydmdeeg},
version = {0.2.0},
year = {2024}
}
Metadata
Release files for pydmdeeg 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| pydmdeeg-0.2.0.tar.gz | 21.9 kB | Without provenance | Details for pydmdeeg-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pydmdeeg-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for pydmdeeg-0.2.0-py3-none-any.whl |
Total release size: 35.4 kB
Release files / pydmdeeg-0.2.0.tar.gz
| Download URL | pydmdeeg-0.2.0.tar.gz |
|---|---|
| Size | 21.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e194cf1954be152b14b06cf008ef7158f88e1cd4bcfc91494158df9a1afd3435
|
|
BLAKE2b-256 checksum How to use checksums |
794f38f0e9c4a7066b07e71cd123b4e1b68c11a5883379a3eb81461d1662362e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Release files / pydmdeeg-0.2.0-py3-none-any.whl
| Download URL | pydmdeeg-0.2.0-py3-none-any.whl |
|---|---|
| Size | 13.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3c051ecb0bac5c1e79f7f103944b7a2bf5a13eaa2deaf7d22c57d4c6f6bffe0c
|
|
BLAKE2b-256 checksum How to use checksums |
8648adb6e794a04cda1f574b92618f538212d48fdf37b8e18ac13467f302651e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Security for pydmdeeg 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.