Analyses
For each recording: the spectrum of every block from its fourth second on, the background fitted to the eyes-closed spectrum, and alpha as the periodic part above it. The peak and the center of gravity of that part from 7 to 14 hertz are two estimates of the individual alpha frequency. Reactivity is the log ratio of closed to open power, in a band 2 hertz either side of the center of gravity and in the fixed band. The share is the demo's measure, from the same spectrum.
import numpy as np
import mne
from scipy.signal import welch
BLOCK, SKIP = 45, 3 # seconds in a block, and seconds left out at its start
def spectra(path):
"""Each block's spectrum, averaged over channels: Welch, 4-s Hann segments, half overlap."""
raw = mne.io.read_raw_bdf(path, preload=True, verbose="error")
fs = raw.info["sfreq"]
x = 1e6 * raw.get_data(picks="eeg") # microvolts
blocks = []
for b in range(int(x.shape[1] / fs // BLOCK)):
seg = x[:, int((BLOCK * b + SKIP) * fs):int(BLOCK * (b + 1) * fs)]
f, p = welch(seg, fs=fs, nperseg=int(4 * fs))
blocks.append(p.mean(axis=0))
return f, np.array(blocks) # open, closed, open, closed
def background(f, p):
"""A line in log-log through 2 to 6 and 15 to 40 Hz: the exponent, and the background."""
fit = ((f >= 2) & (f < 6)) | ((f >= 15) & (f < 40))
slope, offset = np.polyfit(np.log10(f[fit]), np.log10(p[fit]), 1)
return -slope, 10 ** offset * np.maximum(f, 0.25) ** slope
def band(f, p, lo, hi):
pick = (f >= lo) & (f < hi)
return np.trapezoid(p[pick], f[pick])
def describe(path):
f, p = spectra(path)
opened, closed = p[0::2].mean(axis=0), p[1::2].mean(axis=0)
exponent, bg = background(f, closed)
above = np.clip(closed - bg, 0, None) # the periodic part, eyes closed
win = (f >= 7) & (f <= 14)
peak = f[win][np.argmax(above[win])]
cog = np.sum(f[win] * above[win]) / np.sum(above[win])
own = band(f, closed, cog - 2, cog + 2) / band(f, opened, cog - 2, cog + 2)
return dict(peak=peak, cog=cog, exponent=exponent, reactivity=np.log10(own),
fixed=np.log10(band(f, closed, 8, 13) / band(f, opened, 8, 13)),
above=band(f, above, cog - 2, cog + 2),
share=band(f, closed, 8, 13) / band(f, closed, 4, 30))
rows = {f"{w}-{run}": describe(f"{w}-{run}.bdf") # the paths the program printed
for w in ("w1", "w2", "w3") for run in ("oz-a", "oz-b", "fpz")}
print(" " * 8 + "".join(f"{k:>11}" for k in rows["w1-oz-a"]))
for name, d in rows.items():
print(f"{name:8}" + "".join(f"{v:11.2f}" for v in d.values()))
Then report, from your group's recordings and the class's:
- The two estimates of individual alpha frequency for each wearer, and where they disagree.
- Reactivity in each wearer's own band against the fixed band, and whose differ most.
- Run a against run b, for every measure. Pool the class's wearers, and compute each measure's intraclass correlation.
- The forehead against the back: alpha above the background, and the exponent.
- Across the class's recordings, how much of the variation in the share follows the exponent rather than alpha above the background.
import numpy as np
def icc(a, b):
"""One-way intraclass correlation, from two measurements of each person."""
x = np.column_stack([a, b])
between = 2 * np.var(x.mean(axis=1), ddof=1)
within = np.sum((x - x.mean(axis=1, keepdims=True)) ** 2) / len(x)
return (between - within) / (between + within)
# every wearer in the class: run a, then run b
print(icc([8.86, 10.16, 9.89], [8.91, 10.11, 9.90]))
Sources
Berger, H. (1929). Über das Elektrenkephalogramm des Menschen. Archiv für Psychiatrie und Nervenkrankheiten.
Adrian, E. D., and Matthews, B. H. C. (1934). The Berger rhythm: potential changes from the occipital lobes in man. Brain.
Klimesch, W. (1999). EEG alpha and theta oscillations reflect cognitive and memory performance: a review and analysis. Brain Research Reviews.
Barry, R. J., Clarke, A. R., Johnstone, S. J., Magee, C. A., and Rushby, J. A. (2007). EEG differences between eyes-closed and eyes-open resting conditions. Clinical Neurophysiology.
Jensen, O., and Mazaheri, A. (2010). Shaping functional architecture by oscillatory alpha activity: gating by inhibition. Frontiers in Human Neuroscience.
Grandy, T. H., and others (2013). Peak individual alpha frequency qualifies as a stable neurophysiological trait marker in healthy younger and older adults. Psychophysiology.
Haegens, S., Cousijn, H., Wallis, G., Harrison, P. J., and Nobre, A. C. (2014). Inter- and intra-individual variability in alpha peak frequency. NeuroImage.
Corcoran, A. W., Alday, P. M., Schlesewsky, M., and Bornkessel-Schlesewsky, I. (2018). Toward a reliable, automated method of individual alpha frequency (IAF) quantification. Psychophysiology.
Donoghue, T., and others (2020). Parameterizing neural power spectra into periodic and aperiodic components. Nature Neuroscience.
Pernet, C., and others (2020). Issues and recommendations from the OHBM COBIDAS MEEG committee for reproducible EEG and MEG research. Nature Neuroscience.