Download eegannotationtool/senua_eegpt/preprocessing.py from SenuaLab/EEG-IED-Detection: direct link, hf CLI and curl.
- Browser
- Download file 2.04 kB
-
https://huggingface.co/SenuaLab/EEG-IED-Detection/resolve/main/eegannotationtool/senua_eegpt/preprocessing.py
- Command line
-
hf download hf://SenuaLab/EEG-IED-Detection/eegannotationtool/senua_eegpt/preprocessing.py
-
curl -L -o preprocessing.py https://huggingface.co/SenuaLab/EEG-IED-Detection/resolve/main/eegannotationtool/senua_eegpt/preprocessing.py
2.04 kB
| """Exact four-second preprocessing used by the released SenuaLab models.""" | |
| from __future__ import annotations | |
| import math | |
| import numpy as np | |
| from scipy.signal import butter, resample, resample_poly, sosfiltfilt | |
| NUM_CHANNELS = 19 | |
| INTERNATIONAL_10_20_CHANNELS = [ | |
| "Fp1", "Fp2", "F3", "F4", "C3", "C4", "P3", "P4", "O1", "O2", | |
| "F7", "F8", "T3", "T4", "T5", "T6", "Fz", "Cz", "Pz", | |
| ] | |
| DATASET_29_CHANNEL_ORDER = INTERNATIONAL_10_20_CHANNELS | |
| def normalize_sample(sample): | |
| x = np.asarray(sample, dtype=np.float32) | |
| mean = x.mean() | |
| std = x.std() | |
| return np.clip((x - mean) / max(float(std), 1e-7), -8.0, 8.0).astype(np.float32) | |
| def preprocess_batch( | |
| batch, | |
| *, | |
| source_sfreq=None, | |
| target_sfreq=250, | |
| target_samples=1000, | |
| channel_names=None, | |
| ): | |
| """Filter, average-reference, resample, and globally normalize `[B,C,T]`.""" | |
| del channel_names # IED Finder has already arranged the declared channel order. | |
| x = np.asarray(batch, dtype=np.float32) | |
| if x.ndim == 2: | |
| x = x[None] | |
| if x.ndim != 3 or x.shape[1] != NUM_CHANNELS: | |
| raise ValueError(f"Expected [batch,19,time], received {x.shape}") | |
| sfreq = float(source_sfreq or target_sfreq) | |
| if sfreq <= 90.0: | |
| raise ValueError(f"Sampling rate must be above the 45 Hz cutoff; received {sfreq}") | |
| sos = butter(4, [1.0, 45.0], btype="bandpass", fs=sfreq, output="sos") | |
| x = sosfiltfilt(sos, x, axis=-1).astype(np.float32, copy=False) | |
| x -= x.mean(axis=1, keepdims=True) | |
| if not math.isclose(sfreq, float(target_sfreq)): | |
| up = int(target_sfreq) | |
| down = int(round(sfreq)) | |
| common = math.gcd(up, down) | |
| x = resample_poly(x, up // common, down // common, axis=-1).astype(np.float32) | |
| if x.shape[-1] != int(target_samples): | |
| x = resample(x, int(target_samples), axis=-1).astype(np.float32) | |
| mean = x.mean(axis=(1, 2), keepdims=True) | |
| std = x.std(axis=(1, 2), keepdims=True) | |
| return np.clip((x - mean) / np.maximum(std, 1e-7), -8.0, 8.0).astype(np.float32) | |