-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ENH] Add (poly)coherence functions (#76)
- Loading branch information
Showing
29 changed files
with
1,236 additions
and
88 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
meegkit.phase | ||
============= | ||
|
||
.. automodule:: meegkit.phase | ||
|
||
.. rubric:: Classes | ||
|
||
.. autosummary:: | ||
|
||
NonResOscillator | ||
ResOscillator | ||
Device | ||
ECHT | ||
|
||
.. rubric:: Functions | ||
|
||
.. autosummary:: | ||
|
||
locking_based_phase | ||
rk | ||
init_coefs | ||
one_step_oscillator | ||
one_step_integrator |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
|
||
:orphan: | ||
|
||
.. _sphx_glr_sg_execution_times: | ||
|
||
|
||
Computation times | ||
================= | ||
**00:29.509** total execution time for 13 files **from all galleries**: | ||
|
||
.. container:: | ||
|
||
.. raw:: html | ||
|
||
<style scoped> | ||
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet" /> | ||
<link href="https://cdn.datatables.net/1.13.6/css/dataTables.bootstrap5.min.css" rel="stylesheet" /> | ||
</style> | ||
<script src="https://code.jquery.com/jquery-3.7.0.js"></script> | ||
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script> | ||
<script src="https://cdn.datatables.net/1.13.6/js/dataTables.bootstrap5.min.js"></script> | ||
<script type="text/javascript" class="init"> | ||
$(document).ready( function () { | ||
$('table.sg-datatable').DataTable({order: [[1, 'desc']]}); | ||
} ); | ||
</script> | ||
|
||
.. list-table:: | ||
:header-rows: 1 | ||
:class: table table-striped sg-datatable | ||
|
||
* - Example | ||
- Time | ||
- Mem (MB) | ||
* - :ref:`sphx_glr_auto_examples_example_trca.py` (``../examples/example_trca.py``) | ||
- 00:11.533 | ||
- 0.0 | ||
* - :ref:`sphx_glr_auto_examples_example_dss_line.py` (``../examples/example_dss_line.py``) | ||
- 00:07.115 | ||
- 0.0 | ||
* - :ref:`sphx_glr_auto_examples_example_phase_estimation.py` (``../examples/example_phase_estimation.py``) | ||
- 00:07.064 | ||
- 0.0 | ||
* - :ref:`sphx_glr_auto_examples_example_mcca.py` (``../examples/example_mcca.py``) | ||
- 00:01.182 | ||
- 0.0 | ||
* - :ref:`sphx_glr_auto_examples_example_mcca_2.py` (``../examples/example_mcca_2.py``) | ||
- 00:00.535 | ||
- 0.0 | ||
* - :ref:`sphx_glr_auto_examples_example_asr.py` (``../examples/example_asr.py``) | ||
- 00:00.512 | ||
- 0.0 | ||
* - :ref:`sphx_glr_auto_examples_example_ress.py` (``../examples/example_ress.py``) | ||
- 00:00.459 | ||
- 0.0 | ||
* - :ref:`sphx_glr_auto_examples_example_detrend.py` (``../examples/example_detrend.py``) | ||
- 00:00.259 | ||
- 0.0 | ||
* - :ref:`sphx_glr_auto_examples_example_star_dss.py` (``../examples/example_star_dss.py``) | ||
- 00:00.246 | ||
- 0.0 | ||
* - :ref:`sphx_glr_auto_examples_example_star.py` (``../examples/example_star.py``) | ||
- 00:00.197 | ||
- 0.0 | ||
* - :ref:`sphx_glr_auto_examples_example_dss.py` (``../examples/example_dss.py``) | ||
- 00:00.146 | ||
- 0.0 | ||
* - :ref:`sphx_glr_auto_examples_example_echt.py` (``../examples/example_echt.py``) | ||
- 00:00.132 | ||
- 0.0 | ||
* - :ref:`sphx_glr_auto_examples_example_dering.py` (``../examples/example_dering.py``) | ||
- 00:00.129 | ||
- 0.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"\n# Endpoint-corrected Hilbert transform (ECHT) phase estimation\n\nThis example shows how to causally estimate the phase of a signal using\n\nUses `meegkit.phase.ECHT()`.\n\n## References\n.. [1] Schreglmann, S. R., Wang, D., Peach, R. L., Li, J., Zhang, X., Latorre,\n A., ... & Grossman, N. (2021). Non-invasive suppression of essential tremor\n via phase-locked disruption of its temporal coherence. Nature\n communications, 12(1), 363.\n" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": { | ||
"collapsed": false | ||
}, | ||
"outputs": [], | ||
"source": [ | ||
"import matplotlib.pyplot as plt\nimport numpy as np\nfrom scipy.signal import hilbert\n\nfrom meegkit.phase import ECHT\n\nrng = np.random.default_rng(38872)\n\nplt.rcParams[\"axes.grid\"] = True\nplt.rcParams[\"grid.linestyle\"] = \":\"" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"## Build data\nFirst, we generate a multi-component signal with amplitude and phase\nmodulations, as described in the paper [1]_.\n\n" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": { | ||
"collapsed": false | ||
}, | ||
"outputs": [], | ||
"source": [ | ||
"f0 = 2\n\nN = 500\nsfreq = 100\ntime = np.linspace(0, N / sfreq, N)\nX = np.cos(2 * np.pi * f0 * time - np.pi / 4)\nphase_true = np.angle(hilbert(X))\nX += rng.normal(0, 0.5, N) # Add noise" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"### Compute phase and amplitude\nWe compute the Hilbert phase, as well as the phase obtained with the ECHT\nfilter.\n\n" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": { | ||
"collapsed": false | ||
}, | ||
"outputs": [], | ||
"source": [ | ||
"phase_hilbert = np.angle(hilbert(X)) # Hilbert phase\n\n# Compute ECHT-filtered signal\nfilt_BW = f0 / 2\nl_freq = f0 - filt_BW / 2\nh_freq = f0 + filt_BW / 2\necht = ECHT(l_freq, h_freq, sfreq)\n\nXf = echt.fit_transform(X)\nphase_echt = np.angle(Xf)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"### Visualize signal\nPlot the results\n\n" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": { | ||
"collapsed": false | ||
}, | ||
"outputs": [], | ||
"source": [ | ||
"fig, ax = plt.subplots(3, 1, figsize=(8, 6))\nax[0].plot(time, X)\nax[0].set_xlabel(\"Time (s)\")\nax[0].set_title(\"Test signal\")\nax[0].set_ylabel(\"Amplitude\")\nax[1].psd(X, Fs=sfreq, NFFT=2048*4, noverlap=sfreq)\nax[1].set_ylabel(\"PSD (dB/Hz)\")\nax[1].set_title(\"Test signal's Fourier spectrum\")\nax[2].plot(time, phase_true, label=\"True phase\", ls=\":\")\nax[2].plot(time, phase_echt, label=\"ECHT phase\", lw=.5, alpha=.8)\nax[2].plot(time, phase_hilbert, label=\"Hilbert phase\", lw=.5, alpha=.8)\nax[2].set_title(\"Phase\")\nax[2].set_ylabel(\"Amplitude\")\nax[2].set_xlabel(\"Time (s)\")\nax[2].legend(loc=\"upper right\", fontsize=\"small\")\nplt.tight_layout()\nplt.show()" | ||
] | ||
} | ||
], | ||
"metadata": { | ||
"kernelspec": { | ||
"display_name": "Python 3", | ||
"language": "python", | ||
"name": "python3" | ||
}, | ||
"language_info": { | ||
"codemirror_mode": { | ||
"name": "ipython", | ||
"version": 3 | ||
}, | ||
"file_extension": ".py", | ||
"mimetype": "text/x-python", | ||
"name": "python", | ||
"nbconvert_exporter": "python", | ||
"pygments_lexer": "ipython3", | ||
"version": "3.12.2" | ||
} | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 0 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
""" | ||
Endpoint-corrected Hilbert transform (ECHT) phase estimation | ||
============================================================ | ||
This example shows how to causally estimate the phase of a signal using the | ||
Endpoint-corrected Hilbert transform (ECHT) [1]_. | ||
Uses `meegkit.phase.ECHT()`. | ||
References | ||
---------- | ||
.. [1] Schreglmann, S. R., Wang, D., Peach, R. L., Li, J., Zhang, X., Latorre, | ||
A., ... & Grossman, N. (2021). Non-invasive suppression of essential tremor | ||
via phase-locked disruption of its temporal coherence. Nature | ||
communications, 12(1), 363. | ||
""" | ||
import matplotlib.pyplot as plt | ||
import numpy as np | ||
from scipy.signal import hilbert | ||
|
||
from meegkit.phase import ECHT | ||
|
||
rng = np.random.default_rng(38872) | ||
|
||
plt.rcParams["axes.grid"] = True | ||
plt.rcParams["grid.linestyle"] = ":" | ||
|
||
############################################################################### | ||
# Build data | ||
# ----------------------------------------------------------------------------- | ||
# First, we generate a multi-component signal with amplitude and phase | ||
# modulations, as described in the paper [1]_. | ||
f0 = 2 | ||
|
||
N = 500 | ||
sfreq = 100 | ||
time = np.linspace(0, N / sfreq, N) | ||
X = np.cos(2 * np.pi * f0 * time - np.pi / 4) | ||
phase_true = np.angle(hilbert(X)) | ||
X += rng.normal(0, 0.5, N) # Add noise | ||
|
||
############################################################################### | ||
# Compute phase and amplitude | ||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
# We compute the Hilbert phase, as well as the phase obtained with the ECHT | ||
# filter. | ||
phase_hilbert = np.angle(hilbert(X)) # Hilbert phase | ||
|
||
# Compute ECHT-filtered signal | ||
filt_BW = f0 / 2 | ||
l_freq = f0 - filt_BW / 2 | ||
h_freq = f0 + filt_BW / 2 | ||
echt = ECHT(l_freq, h_freq, sfreq) | ||
|
||
Xf = echt.fit_transform(X) | ||
phase_echt = np.angle(Xf) | ||
|
||
############################################################################### | ||
# Visualize signal | ||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
# Here we plot the original signal, its Fourier spectrum, and the phase obtained | ||
# with the Hilbert transform and the ECHT filter. The ECHT filter provides a | ||
# much smoother phase estimate than the Hilbert transform | ||
fig, ax = plt.subplots(3, 1, figsize=(8, 6)) | ||
ax[0].plot(time, X) | ||
ax[0].set_xlabel("Time (s)") | ||
ax[0].set_title("Test signal") | ||
ax[0].set_ylabel("Amplitude") | ||
ax[1].psd(X, Fs=sfreq, NFFT=2048*4, noverlap=sfreq) | ||
ax[1].set_ylabel("PSD (dB/Hz)") | ||
ax[1].set_title("Test signal's Fourier spectrum") | ||
ax[2].plot(time, phase_true, label="True phase", ls=":") | ||
ax[2].plot(time, phase_echt, label="ECHT phase", lw=.5, alpha=.8) | ||
ax[2].plot(time, phase_hilbert, label="Hilbert phase", lw=.5, alpha=.8) | ||
ax[2].set_title("Phase") | ||
ax[2].set_ylabel("Amplitude") | ||
ax[2].set_xlabel("Time (s)") | ||
ax[2].legend(loc="upper right", fontsize="small") | ||
plt.tight_layout() | ||
plt.show() |
Oops, something went wrong.