mekosotto Claude Sonnet 4.6 commited on
Commit
eccd68f
·
1 Parent(s): ebf1b60

test(eeg): add deterministic synthetic Raw fixture (5 ch, 256 Hz, 10 s)

Browse files
tests/fixtures/build_eeg_fixture.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Generate a deterministic synthetic MNE Raw fixture for EEG pipeline tests.
2
+
3
+ The fixture is committed to the repo alongside this script so test runs are
4
+ reproducible without re-running the script. Re-run only if the contract changes.
5
+
6
+ Channels: 4 EEG (Cz, Pz, O1, O2) + 1 EOG (EOG061).
7
+ Sampling rate: 256 Hz. Duration: 10 s.
8
+ Synthetic content: a 10 Hz alpha sine on each EEG channel, plus a 1.5 Hz EOG
9
+ "blink" injected on EOG061 and bleed-through on the frontal-most EEG channel
10
+ (Cz) so ICA has something to detect.
11
+ """
12
+ from __future__ import annotations
13
+
14
+ from pathlib import Path
15
+
16
+ import mne
17
+ import numpy as np
18
+
19
+
20
+ def build() -> Path:
21
+ rng = np.random.default_rng(seed=42)
22
+ sfreq = 256.0
23
+ duration_s = 10.0
24
+ n_samples = int(sfreq * duration_s)
25
+ t = np.arange(n_samples) / sfreq
26
+
27
+ # Base alpha (10 Hz) + small white noise on every EEG channel.
28
+ eeg_alpha = np.sin(2 * np.pi * 10.0 * t)
29
+ eeg_noise = rng.standard_normal((4, n_samples)) * 1e-6
30
+ eeg = (eeg_alpha[None, :] * 1e-5) + eeg_noise
31
+
32
+ # EOG blink: low-frequency square-ish pulse train at ~1.5 Hz.
33
+ eog_pulse = (np.sin(2 * np.pi * 1.5 * t) > 0.95).astype(float) * 1e-4
34
+
35
+ # Bleed EOG into Cz (channel 0) so ICA finds an EOG-correlated component.
36
+ eeg[0] += 0.3 * eog_pulse
37
+
38
+ data = np.vstack([eeg, eog_pulse[None, :]]) # shape: (5, n_samples)
39
+
40
+ info = mne.create_info(
41
+ ch_names=["Cz", "Pz", "O1", "O2", "EOG061"],
42
+ sfreq=sfreq,
43
+ ch_types=["eeg", "eeg", "eeg", "eeg", "eog"],
44
+ )
45
+ raw = mne.io.RawArray(data, info, verbose="ERROR")
46
+
47
+ out = Path(__file__).parent / "eeg_sample.fif"
48
+ raw.save(out, overwrite=True, verbose="ERROR")
49
+ return out
50
+
51
+
52
+ if __name__ == "__main__":
53
+ p = build()
54
+ print(f"Wrote {p}")
tests/fixtures/eeg_sample.fif ADDED
Binary file (52.4 kB). View file