1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
|
import os.path as op
import numpy as np
from numpy.testing import assert_allclose
import pytest
from mne.datasets import testing
from mne import find_events, Epochs, pick_types
from mne.io import read_raw_fif
from mne.io.constants import FIFF
from mne.label import read_label
from mne.minimum_norm import (read_inverse_operator, apply_inverse_epochs,
prepare_inverse_operator, INVERSE_METHODS)
from mne.minimum_norm.time_frequency import (source_band_induced_power,
source_induced_power,
compute_source_psd,
compute_source_psd_epochs)
from mne.time_frequency.multitaper import psd_array_multitaper
data_path = testing.data_path(download=False)
fname_inv = op.join(data_path, 'MEG', 'sample',
'sample_audvis_trunc-meg-eeg-oct-4-meg-inv.fif')
fname_data = op.join(data_path, 'MEG', 'sample',
'sample_audvis_trunc_raw.fif')
fname_label = op.join(data_path, 'MEG', 'sample', 'labels', 'Aud-lh.label')
@testing.requires_testing_data
@pytest.mark.parametrize('method', INVERSE_METHODS)
def test_tfr_with_inverse_operator(method):
"""Test time freq with MNE inverse computation."""
tmin, tmax, event_id = -0.2, 0.5, 1
# Setup for reading the raw data
raw = read_raw_fif(fname_data)
events = find_events(raw, stim_channel='STI 014')
inv = read_inverse_operator(fname_inv)
inv = prepare_inverse_operator(inv, nave=1, lambda2=1. / 9., method=method)
raw.info['bads'] += ['MEG 2443', 'EEG 053'] # bads + 2 more
# picks MEG gradiometers
picks = pick_types(raw.info, meg=True, eeg=False, eog=True,
stim=False, exclude='bads')
# Load condition 1
event_id = 1
events3 = events[:3] # take 3 events to keep the computation time low
epochs = Epochs(raw, events3, event_id, tmin, tmax, picks=picks,
baseline=(None, 0), reject=dict(grad=4000e-13, eog=150e-6),
preload=True)
# Compute a source estimate per frequency band
bands = dict(alpha=[10, 10])
label = read_label(fname_label)
# XXX someday we should refactor this so that you don't have to pass
# method -- maybe `prepare_inverse_operator` should add a `method`
# to it and when `prepared=True` the value passed in can be ignored
# (or better, default method=None means "dSPM if unprepared" and if they
# actually pass a value, we check against `inv['method']`)
stcs = source_band_induced_power(epochs, inv, bands, method=method,
n_cycles=2, use_fft=False, pca=True,
label=label, prepared=True)
stc = stcs['alpha']
assert len(stcs) == len(list(bands.keys()))
assert np.all(stc.data > 0)
assert_allclose(stc.times, epochs.times, atol=1e-6)
stcs_no_pca = source_band_induced_power(epochs, inv, bands, method=method,
n_cycles=2, use_fft=False,
pca=False, label=label,
prepared=True)
assert_allclose(stcs['alpha'].data, stcs_no_pca['alpha'].data)
# Compute a source estimate per frequency band
epochs = Epochs(raw, events[:10], event_id, tmin, tmax, picks=picks,
baseline=(None, 0), reject=dict(grad=4000e-13, eog=150e-6),
preload=True)
freqs = np.arange(7, 30, 2) # define frequencies of interest
power, phase_lock = source_induced_power(
epochs, inv, freqs, label, baseline=(-0.1, 0), baseline_mode='percent',
n_cycles=2, n_jobs=None, method=method, prepared=True)
assert np.all(phase_lock > 0)
assert np.all(phase_lock <= 1)
assert 5 < np.max(power) < 7
@testing.requires_testing_data
@pytest.mark.parametrize('method', INVERSE_METHODS)
@pytest.mark.parametrize('pick_ori', (None, 'normal')) # XXX vector someday?
def test_source_psd(method, pick_ori):
"""Test source PSD computation from raw."""
raw = read_raw_fif(fname_data)
raw.crop(0, 5).load_data()
inverse_operator = read_inverse_operator(fname_inv)
fmin, fmax = 40, 65 # Hz
n_fft = 512
assert inverse_operator['source_ori'] == FIFF.FIFFV_MNE_FREE_ORI
stc, ev = compute_source_psd(
raw, inverse_operator, lambda2=1. / 9., method=method,
fmin=fmin, fmax=fmax, pick_ori=pick_ori, n_fft=n_fft,
overlap=0., return_sensor=True, dB=True)
assert ev.data.shape == (len(ev.info['ch_names']), len(stc.times))
assert ev.times[0] >= fmin
assert ev.times[-1] <= fmax
# Time max at line frequency (60 Hz in US)
assert 58 <= ev.times[np.argmax(np.sum(ev.data, axis=0))] <= 61
assert ev.nave == 2
assert stc.shape[0] == inverse_operator['nsource']
assert stc.times[0] >= fmin
assert stc.times[-1] <= fmax
assert 58 <= stc.times[np.argmax(np.sum(stc.data, axis=0))] <= 61
if method in ('sLORETA', 'dSPM'):
stc_dspm = stc
stc_mne, _ = compute_source_psd(
raw, inverse_operator, lambda2=1. / 9., method='MNE',
fmin=fmin, fmax=fmax, pick_ori=pick_ori, n_fft=n_fft,
overlap=0., return_sensor=True, dB=True)
# normalize each source point by its power after undoing the dB
stc_dspm.data = 10 ** (stc_dspm.data / 10.)
stc_dspm /= stc_dspm.mean()
stc_mne.data = 10 ** (stc_mne.data / 10.)
stc_mne /= stc_mne.mean()
assert_allclose(stc_dspm.data, stc_mne.data, atol=1e-4)
@testing.requires_testing_data
@pytest.mark.parametrize('method', INVERSE_METHODS)
def test_source_psd_epochs(method):
"""Test multi-taper source PSD computation in label from epochs."""
raw = read_raw_fif(fname_data)
inverse_operator = read_inverse_operator(fname_inv)
label = read_label(fname_label)
event_id, tmin, tmax = 1, -0.2, 0.5
lambda2 = 1. / 9.
bandwidth = 8.
fmin, fmax = 0, 100
picks = pick_types(raw.info, meg=True, eeg=False, stim=True,
ecg=True, eog=True, include=['STI 014'],
exclude='bads')
reject = dict(grad=4000e-13, mag=4e-12, eog=150e-6)
events = find_events(raw, stim_channel='STI 014')
epochs = Epochs(raw, events, event_id, tmin, tmax, picks=picks,
baseline=(None, 0), reject=reject)
# only look at one epoch
epochs.drop_bad()
one_epochs = epochs[:1]
inv = prepare_inverse_operator(inverse_operator, nave=1,
lambda2=1. / 9., method="dSPM")
# return list
stc_psd = compute_source_psd_epochs(one_epochs, inv,
lambda2=lambda2, method=method,
pick_ori="normal", label=label,
bandwidth=bandwidth,
fmin=fmin, fmax=fmax,
prepared=True)[0]
# return generator
stcs = compute_source_psd_epochs(one_epochs, inv,
lambda2=lambda2, method=method,
pick_ori="normal", label=label,
bandwidth=bandwidth,
fmin=fmin, fmax=fmax,
return_generator=True,
prepared=True)
for stc in stcs:
stc_psd_gen = stc
assert_allclose(stc_psd.data, stc_psd_gen.data, atol=1e-7)
# compare with direct computation
stc = apply_inverse_epochs(one_epochs, inv,
lambda2=lambda2, method=method,
pick_ori="normal", label=label,
prepared=True)[0]
sfreq = epochs.info['sfreq']
psd, freqs = psd_array_multitaper(stc.data, sfreq=sfreq,
bandwidth=bandwidth, fmin=fmin,
fmax=fmax)
assert_allclose(psd, stc_psd.data, atol=1e-7)
assert_allclose(freqs, stc_psd.times)
# Check corner cases caused by tiny bandwidth
with pytest.raises(ValueError, match='use a value of at least'):
compute_source_psd_epochs(
one_epochs, inv, lambda2=lambda2, method=method,
pick_ori="normal", label=label, bandwidth=0.01, low_bias=True,
fmin=fmin, fmax=fmax, return_generator=False, prepared=True)
|