def test_lcmv_fieldtrip(): """Test LCMV vs fieldtrip output.""" evoked, data_cov, fwd = _get_bf_data() # beamformer types to be tested: unit-gain (vector and scalar) and # unit-noise-gain bf_types = ['ug_vec', 'ug_scal', 'ung'] weight_norms = [None, None, 'unit-noise-gain'] pick_oris = [None, 'max-power', 'max-power'] for bf_type, weight_norm, pick_ori in zip(bf_types, weight_norms, pick_oris): # run the MNE-Python beamformer filters = make_lcmv(evoked.info, fwd, data_cov=data_cov, noise_cov=None, pick_ori=pick_ori, reg=0.05, weight_norm=weight_norm) stc_mne = apply_lcmv(evoked, filters) # take the absolute value, since orientation is arbitrary by 180 degr. stc_mne.data[:, :] = np.abs(stc_mne.data) # load the FieldTrip output ft_fname = op.join(ft_data_path, 'ft_source_' + bf_type + '-vol.stc') stc_ft = mne.read_source_estimate(ft_fname) # calculate the Pearson correlation between the source solutions: pearson = np.corrcoef(np.concatenate(stc_mne.data), np.concatenate(stc_ft.data)) assert pearson[0, 1] >= 0.99
def test_lcmv_fieldtrip(_get_bf_data, bf_type, weight_norm, pick_ori, pwr): """Test LCMV vs fieldtrip output.""" evoked, data_cov, fwd = _get_bf_data # run the MNE-Python beamformer filters = make_lcmv(evoked.info, fwd, data_cov=data_cov, noise_cov=None, pick_ori=pick_ori, reg=0.05, weight_norm=weight_norm) if pwr is True: stc_mne = apply_lcmv_cov(data_cov, filters) else: stc_mne = apply_lcmv(evoked, filters) # take the absolute value, since orientation can be flipped stc_mne.data[:, :] = np.abs(stc_mne.data) # load the FieldTrip output ft_fname = op.join(ft_data_path, 'ft_source_' + bf_type + '-vol.stc') stc_ft = mne.read_source_estimate(ft_fname) # calculate the Pearson correlation between the source solutions: pearson = np.corrcoef(stc_mne.data.ravel(), stc_ft.data.ravel())[0, 1] assert pearson >= 0.99
def run_lcmv_evoked(evoked, fwd, data_cov, reg, noise_cov=None, pick_ori='max-power', weight_norm='nai'): """Run LCMV on average. Run weight-normalized LCMV beamformer on evoked data, will return an stc object. Parameters: ----------- evoked : MNE evoked evoked data to source reconstruct. fwd : MNE forward model forward model. data_cov : MNE covariance estimate data covariance matrix. reg : float regularization parameter noise_cov : MNE covariance estimate noise covariance matrix, optional Returns ------- stc : MNE stcs original output of apply_lcmv filters : dict spatial filter used in computation """ filters = make_lcmv(evoked.info, fwd, data_cov=data_cov, noise_cov=noise_cov, pick_ori=pick_ori, reg=reg, weight_norm=weight_norm) # apply that filter to epochs stc = apply_lcmv(evoked, filters, max_ori_out='signed') return stc, filters
# matrix enables whitening of the data and forward solution. Source orientation # is optimized by setting pick_ori to 'max-power'. # weight_norm can also be set to 'unit-noise-gain'. Source orientation can also # be 'normal' (but only when using a surface-based source space) or None, # which computes a vector beamfomer. Note, however, that not all combinations # of orientation selection and weight normalization are implemented yet. filters = make_lcmv(evoked.info, forward, data_cov, reg=0.05, noise_cov=noise_cov, pick_ori='max-power', weight_norm='nai', rank=None) print(filters) # You can save these with: # filters.save('filters-lcmv.h5') # Apply this spatial filter to the evoked data. stc = apply_lcmv(evoked, filters, max_ori_out='signed') ############################################################################### # Plot source space activity: # You can save result in stc files with: # stc.save('lcmv-vol') clim = dict(kind='value', pos_lims=[0.3, 0.6, 0.9]) stc.plot(src=forward['src'], subject='sample', subjects_dir=subjects_dir, clim=clim) ############################################################################### # We can also visualize the activity on a "glass brain" (shown here with # absolute values):
def test_make_lcmv(tmpdir): """Test LCMV with evoked data and single trials.""" raw, epochs, evoked, data_cov, noise_cov, label, forward,\ forward_surf_ori, forward_fixed, forward_vol = _get_data() for fwd in [forward, forward_vol]: filters = make_lcmv(evoked.info, fwd, data_cov, reg=0.01, noise_cov=noise_cov) stc = apply_lcmv(evoked, filters, max_ori_out='signed') stc.crop(0.02, None) stc_pow = np.sum(np.abs(stc.data), axis=1) idx = np.argmax(stc_pow) max_stc = stc.data[idx] tmax = stc.times[np.argmax(max_stc)] assert 0.09 < tmax < 0.12, tmax assert 0.9 < np.max(max_stc) < 3., np.max(max_stc) if fwd is forward: # Test picking normal orientation (surface source space only). filters = make_lcmv(evoked.info, forward_surf_ori, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='normal', weight_norm=None) stc_normal = apply_lcmv(evoked, filters, max_ori_out='signed') stc_normal.crop(0.02, None) stc_pow = np.sum(np.abs(stc_normal.data), axis=1) idx = np.argmax(stc_pow) max_stc = stc_normal.data[idx] tmax = stc_normal.times[np.argmax(max_stc)] assert 0.04 < tmax < 0.13, tmax assert 3e-7 < np.max(max_stc) < 5e-7, np.max(max_stc) # No weight normalization was applied, so the amplitude of normal # orientation results should always be smaller than free # orientation results. assert (np.abs(stc_normal.data) <= stc.data).all() # Test picking source orientation maximizing output source power filters = make_lcmv(evoked.info, fwd, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='max-power') stc_max_power = apply_lcmv(evoked, filters, max_ori_out='signed') stc_max_power.crop(0.02, None) stc_pow = np.sum(np.abs(stc_max_power.data), axis=1) idx = np.argmax(stc_pow) max_stc = np.abs(stc_max_power.data[idx]) tmax = stc.times[np.argmax(max_stc)] assert 0.08 < tmax < 0.12, tmax assert 0.8 < np.max(max_stc) < 3., np.max(max_stc) stc_max_power.data[:, :] = np.abs(stc_max_power.data) if fwd is forward: # Maximum output source power orientation results should be # similar to free orientation results in areas with channel # coverage label = mne.read_label(fname_label) mean_stc = stc.extract_label_time_course(label, fwd['src'], mode='mean') mean_stc_max_pow = \ stc_max_power.extract_label_time_course(label, fwd['src'], mode='mean') assert_array_less(np.abs(mean_stc - mean_stc_max_pow), 0.6) # Test NAI weight normalization: filters = make_lcmv(evoked.info, fwd, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='max-power', weight_norm='nai') stc_nai = apply_lcmv(evoked, filters, max_ori_out='signed') stc_nai.crop(0.02, None) # Test whether unit-noise-gain solution is a scaled version of NAI pearsoncorr = np.corrcoef(np.concatenate(np.abs(stc_nai.data)), np.concatenate(stc_max_power.data)) assert_almost_equal(pearsoncorr[0, 1], 1.) # Test sphere head model with unit-noise gain beamformer and orientation # selection and rank reduction of the leadfield sphere = mne.make_sphere_model(r0=(0., 0., 0.), head_radius=0.080) src = mne.setup_volume_source_space(subject=None, pos=15., mri=None, sphere=(0.0, 0.0, 0.0, 80.0), bem=None, mindist=5.0, exclude=2.0) fwd_sphere = mne.make_forward_solution(evoked.info, trans=None, src=src, bem=sphere, eeg=False, meg=True) # Test that we get an error if not reducing rank with pytest.raises(ValueError): # Singular matrix or complex spectrum make_lcmv(evoked.info, fwd_sphere, data_cov, reg=0.1, noise_cov=noise_cov, weight_norm='unit-noise-gain', pick_ori='max-power', reduce_rank=False, rank='full') # Now let's reduce it filters = make_lcmv(evoked.info, fwd_sphere, data_cov, reg=0.1, noise_cov=noise_cov, weight_norm='unit-noise-gain', pick_ori='max-power', reduce_rank=True) stc_sphere = apply_lcmv(evoked, filters, max_ori_out='signed') stc_sphere = np.abs(stc_sphere) stc_sphere.crop(0.02, None) stc_pow = np.sum(stc_sphere.data, axis=1) idx = np.argmax(stc_pow) max_stc = stc_sphere.data[idx] tmax = stc_sphere.times[np.argmax(max_stc)] assert 0.08 < tmax < 0.15, tmax assert 0.4 < np.max(max_stc) < 2., np.max(max_stc) # Test if spatial filter contains src_type assert 'src_type' in filters # __repr__ assert 'LCMV' in repr(filters) assert 'unknown subject' not in repr(filters) assert '484' in repr(filters) assert '20' in repr(filters) assert 'rank 17' in repr(filters) # I/O fname = op.join(str(tmpdir), 'filters.h5') with pytest.warns(RuntimeWarning, match='-lcmv.h5'): filters.save(fname) filters_read = read_beamformer(fname) assert isinstance(filters, Beamformer) assert isinstance(filters_read, Beamformer) # deal with object_diff strictness filters_read['rank'] = int(filters_read['rank']) filters['rank'] = int(filters['rank']) assert object_diff(filters, filters_read) == '' # Test if fixed forward operator is detected when picking normal or # max-power orientation pytest.raises(ValueError, make_lcmv, evoked.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='normal') pytest.raises(ValueError, make_lcmv, evoked.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='max-power') # Test if non-surface oriented forward operator is detected when picking # normal orientation pytest.raises(ValueError, make_lcmv, evoked.info, forward, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='normal') # Test if volume forward operator is detected when picking normal # orientation pytest.raises(ValueError, make_lcmv, evoked.info, forward_vol, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='normal') # Test if missing of noise covariance matrix is detected when more than # one channel type is present in the data pytest.raises(ValueError, make_lcmv, evoked.info, forward_vol, data_cov=data_cov, reg=0.01, noise_cov=None, pick_ori='max-power') # Test if wrong channel selection is detected in application of filter evoked_ch = deepcopy(evoked) evoked_ch.pick_channels(evoked_ch.ch_names[1:]) filters = make_lcmv(evoked.info, forward_vol, data_cov, reg=0.01, noise_cov=noise_cov) pytest.raises(ValueError, apply_lcmv, evoked_ch, filters, max_ori_out='signed') # Test if discrepancies in channel selection of data and fwd model are # handled correctly in apply_lcmv # make filter with data where first channel was removed filters = make_lcmv(evoked_ch.info, forward_vol, data_cov, reg=0.01, noise_cov=noise_cov) # applying that filter to the full data set should automatically exclude # this channel from the data # also test here that no warnings are thrown - implemented to check whether # src should not be None warning occurs with pytest.warns(None) as w: stc = apply_lcmv(evoked, filters, max_ori_out='signed') assert len(w) == 0 # the result should be equal to applying this filter to a dataset without # this channel: stc_ch = apply_lcmv(evoked_ch, filters, max_ori_out='signed') assert_array_almost_equal(stc.data, stc_ch.data) # Test if non-matching SSP projection is detected in application of filter raw_proj = deepcopy(raw) raw_proj.del_proj() pytest.raises(ValueError, apply_lcmv_raw, raw_proj, filters, max_ori_out='signed') # Test if setting reduce_rank to True returns a NotImplementedError # when no orientation selection is done or pick_ori='normal' pytest.raises(NotImplementedError, make_lcmv, evoked.info, forward_vol, data_cov, noise_cov=noise_cov, pick_ori=None, weight_norm='nai', reduce_rank=True) pytest.raises(NotImplementedError, make_lcmv, evoked.info, forward_surf_ori, data_cov, noise_cov=noise_cov, pick_ori='normal', weight_norm='nai', reduce_rank=True) # Test if spatial filter contains src_type assert 'src_type' in filters # check whether a filters object without src_type throws expected warning del filters['src_type'] # emulate 0.16 behaviour to cause warning with pytest.warns(RuntimeWarning, match='spatial filter does not contain ' 'src_type'): apply_lcmv(evoked, filters, max_ori_out='signed') # Now test single trial using fixed orientation forward solution # so we can compare it to the evoked solution filters = make_lcmv(epochs.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov) stcs = apply_lcmv_epochs(epochs, filters, max_ori_out='signed') stcs_ = apply_lcmv_epochs(epochs, filters, return_generator=True, max_ori_out='signed') assert_array_equal(stcs[0].data, advance_iterator(stcs_).data) epochs.drop_bad() assert (len(epochs.events) == len(stcs)) # average the single trial estimates stc_avg = np.zeros_like(stcs[0].data) for this_stc in stcs: stc_avg += this_stc.data stc_avg /= len(stcs) # compare it to the solution using evoked with fixed orientation filters = make_lcmv(evoked.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov) stc_fixed = apply_lcmv(evoked, filters, max_ori_out='signed') assert_array_almost_equal(stc_avg, stc_fixed.data) # use a label so we have few source vertices and delayed computation is # not used filters = make_lcmv(epochs.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov, label=label) stcs_label = apply_lcmv_epochs(epochs, filters, max_ori_out='signed') assert_array_almost_equal(stcs_label[0].data, stcs[0].in_label(label).data) # Test condition where the filters weights are zero. There should not be # any divide-by-zero errors zero_cov = data_cov.copy() zero_cov['data'][:] = 0 filters = make_lcmv(epochs.info, forward_fixed, zero_cov, reg=0.01, noise_cov=noise_cov) assert_array_equal(filters['weights'], 0)
evoked = evoked_joint else: raise ValueError('Invalid sensor type: %s', sensor_type) filters = make_lcmv(evoked.info, fwd, data_cov, reg=reg, pick_ori=pick_ori, weight_norm=weight_norm, inversion=inversion, depth=1. if normalize_fwd else None, noise_cov=noise_cov if use_noise_cov else None, reduce_rank=reduce_rank) stc_est = apply_lcmv(evoked, filters) if pick_ori == 'vector': # Combine vector time source if project_pca: stc_proj, _ = stc_est.project('pca', fwd['src']) else: stc_proj = stc_est.magnitude() stc_est_power = (stc_proj**2).sum() peak_vertex, peak_time = stc_est_power.get_peak(vert_as_index=True, time_as_index=True) estimated_time_course = np.abs(stc_est.data[peak_vertex]) else: stc_est_power = (stc_est**2).sum() peak_vertex, peak_time = stc_est_power.get_peak(vert_as_index=True, time_as_index=True)
def test_lcmv(): """Test LCMV with evoked data and single trials.""" raw, epochs, evoked, data_cov, noise_cov, label, forward,\ forward_surf_ori, forward_fixed, forward_vol = _get_data() for fwd in [forward, forward_vol]: filters = make_lcmv(evoked.info, fwd, data_cov, reg=0.01, noise_cov=noise_cov) stc = apply_lcmv(evoked, filters, max_ori_out='signed') stc.crop(0.02, None) stc_pow = np.sum(np.abs(stc.data), axis=1) idx = np.argmax(stc_pow) max_stc = stc.data[idx] tmax = stc.times[np.argmax(max_stc)] assert 0.09 < tmax < 0.12, tmax assert 0.9 < np.max(max_stc) < 3., np.max(max_stc) if fwd is forward: # Test picking normal orientation (surface source space only) filters = make_lcmv(evoked.info, forward_surf_ori, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='normal') stc_normal = apply_lcmv(evoked, filters, max_ori_out='signed') stc_normal.crop(0.02, None) stc_pow = np.sum(np.abs(stc_normal.data), axis=1) idx = np.argmax(stc_pow) max_stc = stc_normal.data[idx] tmax = stc_normal.times[np.argmax(max_stc)] assert 0.04 < tmax < 0.12, tmax assert 0.4 < np.max(max_stc) < 2., np.max(max_stc) # The amplitude of normal orientation results should always be # smaller than free orientation results assert (np.abs(stc_normal.data) <= stc.data).all() # Test picking source orientation maximizing output source power filters = make_lcmv(evoked.info, fwd, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='max-power') stc_max_power = apply_lcmv(evoked, filters, max_ori_out='signed') stc_max_power.crop(0.02, None) stc_pow = np.sum(np.abs(stc_max_power.data), axis=1) idx = np.argmax(stc_pow) max_stc = np.abs(stc_max_power.data[idx]) tmax = stc.times[np.argmax(max_stc)] assert 0.08 < tmax < 0.12, tmax assert 0.8 < np.max(max_stc) < 3., np.max(max_stc) stc_max_power.data[:, :] = np.abs(stc_max_power.data) if fwd is forward: # Maximum output source power orientation results should be # similar to free orientation results in areas with channel # coverage label = mne.read_label(fname_label) mean_stc = stc.extract_label_time_course(label, fwd['src'], mode='mean') mean_stc_max_pow = \ stc_max_power.extract_label_time_course(label, fwd['src'], mode='mean') assert_array_less(np.abs(mean_stc - mean_stc_max_pow), 0.6) # Test NAI weight normalization: filters = make_lcmv(evoked.info, fwd, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='max-power', weight_norm='nai') stc_nai = apply_lcmv(evoked, filters, max_ori_out='signed') stc_nai.crop(0.02, None) # Test whether unit-noise-gain solution is a scaled version of NAI pearsoncorr = np.corrcoef(np.concatenate(np.abs(stc_nai.data)), np.concatenate(stc_max_power.data)) assert_almost_equal(pearsoncorr[0, 1], 1.) # Test sphere head model with unit-noise gain beamformer and orientation # selection and rank reduction of the leadfield sphere = mne.make_sphere_model(r0=(0., 0., 0.), head_radius=0.080) src = mne.setup_volume_source_space(subject=None, pos=15., mri=None, sphere=(0.0, 0.0, 0.0, 80.0), bem=None, mindist=5.0, exclude=2.0) fwd_sphere = mne.make_forward_solution(evoked.info, trans=None, src=src, bem=sphere, eeg=False, meg=True) # Test that we get an error if not reducing rank pytest.raises(ValueError, make_lcmv, evoked.info, fwd_sphere, data_cov, reg=0.1, noise_cov=noise_cov, weight_norm='unit-noise-gain', pick_ori='max-power', reduce_rank=False) # Now let's reduce it filters = make_lcmv(evoked.info, fwd_sphere, data_cov, reg=0.1, noise_cov=noise_cov, weight_norm='unit-noise-gain', pick_ori='max-power', reduce_rank=True) stc_sphere = apply_lcmv(evoked, filters, max_ori_out='signed') stc_sphere = np.abs(stc_sphere) stc_sphere.crop(0.02, None) stc_pow = np.sum(stc_sphere.data, axis=1) idx = np.argmax(stc_pow) max_stc = stc_sphere.data[idx] tmax = stc_sphere.times[np.argmax(max_stc)] assert 0.08 < tmax < 0.15, tmax assert 0.4 < np.max(max_stc) < 2., np.max(max_stc) # Test if spatial filter contains src_type assert 'src_type' in filters # Test if fixed forward operator is detected when picking normal or # max-power orientation pytest.raises(ValueError, make_lcmv, evoked.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='normal') pytest.raises(ValueError, make_lcmv, evoked.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='max-power') # Test if non-surface oriented forward operator is detected when picking # normal orientation pytest.raises(ValueError, make_lcmv, evoked.info, forward, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='normal') # Test if volume forward operator is detected when picking normal # orientation pytest.raises(ValueError, make_lcmv, evoked.info, forward_vol, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='normal') # Test if missing of noise covariance matrix is detected when more than # one channel type is present in the data pytest.raises(ValueError, make_lcmv, evoked.info, forward_vol, data_cov=data_cov, reg=0.01, noise_cov=None, pick_ori='max-power') # Test if not-yet-implemented orientation selections raise error with # neural activity index pytest.raises(NotImplementedError, make_lcmv, evoked.info, forward_surf_ori, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='normal', weight_norm='nai') pytest.raises(NotImplementedError, make_lcmv, evoked.info, forward_vol, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori=None, weight_norm='nai') # Test if no weight-normalization and max-power source orientation throws # an error pytest.raises(NotImplementedError, make_lcmv, evoked.info, forward_vol, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='max-power', weight_norm=None) # Test if wrong channel selection is detected in application of filter evoked_ch = deepcopy(evoked) evoked_ch.pick_channels(evoked_ch.ch_names[1:]) filters = make_lcmv(evoked.info, forward_vol, data_cov, reg=0.01, noise_cov=noise_cov) pytest.raises(ValueError, apply_lcmv, evoked_ch, filters, max_ori_out='signed') # Test if discrepancies in channel selection of data and fwd model are # handled correctly in apply_lcmv # make filter with data where first channel was removed filters = make_lcmv(evoked_ch.info, forward_vol, data_cov, reg=0.01, noise_cov=noise_cov) # applying that filter to the full data set should automatically exclude # this channel from the data # also test here that no warnings are thrown - implemented to check whether # src should not be None warning occurs with pytest.warns(None) as w: stc = apply_lcmv(evoked, filters, max_ori_out='signed') assert len(w) == 0 # the result should be equal to applying this filter to a dataset without # this channel: stc_ch = apply_lcmv(evoked_ch, filters, max_ori_out='signed') assert_array_almost_equal(stc.data, stc_ch.data) # Test if non-matching SSP projection is detected in application of filter raw_proj = deepcopy(raw) raw_proj.del_proj() pytest.raises(ValueError, apply_lcmv_raw, raw_proj, filters, max_ori_out='signed') # Test if setting reduce_rank to True returns a NotImplementedError # when no orientation selection is done or pick_ori='normal' pytest.raises(NotImplementedError, make_lcmv, evoked.info, forward_vol, data_cov, noise_cov=noise_cov, pick_ori=None, weight_norm='nai', reduce_rank=True) pytest.raises(NotImplementedError, make_lcmv, evoked.info, forward_surf_ori, data_cov, noise_cov=noise_cov, pick_ori='normal', weight_norm='nai', reduce_rank=True) # Test if spatial filter contains src_type assert 'src_type' in filters # check whether a filters object without src_type throws expected warning del filters['src_type'] # emulate 0.16 behaviour to cause warning with pytest.warns(RuntimeWarning, match='spatial filter does not contain ' 'src_type'): apply_lcmv(evoked, filters, max_ori_out='signed') # Now test single trial using fixed orientation forward solution # so we can compare it to the evoked solution filters = make_lcmv(epochs.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov) stcs = apply_lcmv_epochs(epochs, filters, max_ori_out='signed') stcs_ = apply_lcmv_epochs(epochs, filters, return_generator=True, max_ori_out='signed') assert_array_equal(stcs[0].data, advance_iterator(stcs_).data) epochs.drop_bad() assert (len(epochs.events) == len(stcs)) # average the single trial estimates stc_avg = np.zeros_like(stcs[0].data) for this_stc in stcs: stc_avg += this_stc.data stc_avg /= len(stcs) # compare it to the solution using evoked with fixed orientation filters = make_lcmv(evoked.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov) stc_fixed = apply_lcmv(evoked, filters, max_ori_out='signed') assert_array_almost_equal(stc_avg, stc_fixed.data) # use a label so we have few source vertices and delayed computation is # not used filters = make_lcmv(epochs.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov, label=label) stcs_label = apply_lcmv_epochs(epochs, filters, max_ori_out='signed') assert_array_almost_equal(stcs_label[0].data, stcs[0].in_label(label).data)
def test_lcmv_vector(): """Test vector LCMV solutions.""" info = mne.io.read_raw_fif(fname_raw).info # For speed and for rank-deficiency calculation simplicity, # just use grads: info = mne.pick_info(info, mne.pick_types(info, meg='grad', exclude=())) info.update(bads=[], projs=[]) forward = mne.read_forward_solution(fname_fwd) forward = mne.pick_channels_forward(forward, info['ch_names']) vertices = [s['vertno'][::100] for s in forward['src']] n_vertices = sum(len(v) for v in vertices) assert 5 < n_vertices < 20 amplitude = 100e-9 stc = mne.SourceEstimate(amplitude * np.eye(n_vertices), vertices, 0, 1. / info['sfreq']) forward_sim = mne.convert_forward_solution(forward, force_fixed=True, use_cps=True, copy=True) forward_sim = mne.forward.restrict_forward_to_stc(forward_sim, stc) noise_cov = mne.make_ad_hoc_cov(info) noise_cov.update(data=np.diag(noise_cov['data']), diag=False) evoked = simulate_evoked(forward_sim, stc, info, noise_cov, nave=1) source_nn = forward_sim['source_nn'] source_rr = forward_sim['source_rr'] # Figure out our indices mask = np.concatenate([np.in1d(s['vertno'], v) for s, v in zip(forward['src'], vertices)]) mapping = np.where(mask)[0] assert_array_equal(source_rr, forward['source_rr'][mapping]) # Don't check NN because we didn't rotate to surf ori del forward_sim # # Let's do minimum norm as a sanity check (dipole_fit is slower) # inv = make_inverse_operator(info, forward, noise_cov, loose=1.) stc_vector_mne = apply_inverse(evoked, inv, pick_ori='vector') mne_ori = stc_vector_mne.data[mapping, :, np.arange(n_vertices)] mne_ori /= np.linalg.norm(mne_ori, axis=-1)[:, np.newaxis] mne_angles = np.rad2deg(np.arccos(np.sum(mne_ori * source_nn, axis=-1))) assert np.mean(mne_angles) < 35 # # Now let's do LCMV # data_cov = mne.make_ad_hoc_cov(info) # just a stub for later with pytest.raises(ValueError, match='pick_ori must be one of'): make_lcmv(info, forward, data_cov, 0.05, noise_cov, pick_ori='bad') lcmv_ori = list() for ti in range(n_vertices): this_evoked = evoked.copy().crop(evoked.times[ti], evoked.times[ti]) data_cov['data'] = (np.outer(this_evoked.data, this_evoked.data) + noise_cov['data']) vals = linalg.svdvals(data_cov['data']) assert vals[0] / vals[-1] < 1e5 # not rank deficient filters = make_lcmv(info, forward, data_cov, 0.05, noise_cov) filters_vector = make_lcmv(info, forward, data_cov, 0.05, noise_cov, pick_ori='vector') stc = apply_lcmv(this_evoked, filters) assert isinstance(stc, mne.SourceEstimate) stc_vector = apply_lcmv(this_evoked, filters_vector) assert isinstance(stc_vector, mne.VectorSourceEstimate) assert_allclose(stc.data, stc_vector.magnitude().data) # Check the orientation by pooling across some neighbors, as LCMV can # have some "holes" at the points of interest idx = np.where(cdist(forward['source_rr'], source_rr[[ti]]) < 0.02)[0] lcmv_ori.append(np.mean(stc_vector.data[idx, :, 0], axis=0)) lcmv_ori[-1] /= np.linalg.norm(lcmv_ori[-1]) lcmv_angles = np.rad2deg(np.arccos(np.sum(lcmv_ori * source_nn, axis=-1))) assert np.mean(lcmv_angles) < 55
evoked = evoked_joint else: raise ValueError('Invalid sensor type: %s', sensor_type) filters = make_lcmv(evoked.info, fwd_disc_true, cov, reg=reg, pick_ori=pick_ori, weight_norm=weight_norm, inversion=inversion, depth=1. if normalize_fwd else None, noise_cov=noise_cov if use_noise_cov else None, reduce_rank=reduce_rank) stc_est = apply_lcmv(evoked, filters).crop(0.001, 1) # Estimated source location is at peak power if pick_ori == 'vector': stc_est_power = (stc_est.magnitude()**2).sum().sqrt() else: stc_est_power = (stc_est**2).sum().sqrt() peak_vertex, _ = stc_est_power.get_peak(vert_as_index=True) # Compute distance between true and estimated source locations pos_est = fwd_disc_man['source_rr'][peak_vertex] pos_true = fwd_disc_man['source_rr'][config.vertex] dist = np.linalg.norm(pos_est - pos_true) # Ratio between estimated peak activity and all estimated activity. focality_score = stc_est_power.data[peak_vertex,
src = forward['src'] del forward # %% # Apply the spatial filter # ------------------------ # The spatial filter can be applied to different data types: raw, epochs, # evoked data or the data covariance matrix to gain a static image of power. # The function to apply the spatial filter to :class:`~mne.Evoked` data is # :func:`~mne.beamformer.apply_lcmv` which is # what we will use here. The other functions are # :func:`~mne.beamformer.apply_lcmv_raw`, # :func:`~mne.beamformer.apply_lcmv_epochs`, and # :func:`~mne.beamformer.apply_lcmv_cov`. stc = apply_lcmv(evoked, filters) stc_vec = apply_lcmv(evoked, filters_vec) del filters, filters_vec # %% # Visualize the reconstructed source activity # ------------------------------------------- # We can visualize the source estimate in different ways, e.g. as a volume # rendering, an overlay onto the MRI, or as an overlay onto a glass brain. # # The plots for the scalar beamformer show brain activity in the right temporal # lobe around 100 ms post stimulus. This is expected given the left-ear # auditory stimulation of the experiment. lims = [0.3, 0.45, 0.6] kwargs = dict(src=src, subject='sample', subjects_dir=subjects_dir,
mindist=5.0, n_jobs=2) # compute LCMV spatial filters filters_a = make_lcmv(evoked_a.info, fwd_a, data_cov_a, reg=0.05, noise_cov=noise_cov_a, pick_ori='max-power', weight_norm='nai', rank=None) filters_b = make_lcmv(evoked_b.info, fwd_b, data_cov_b, reg=0.05, noise_cov=noise_cov_b, pick_ori='max-power', weight_norm='nai', rank=None) # delete forward solutions to free memory space del fwd_a, fwd_b # apply the spacial filters to the ERPs stc_a = apply_lcmv(evoked_a, filters_a, max_ori_out='signed') stc_b = apply_lcmv(evoked_b, filters_b, max_ori_out='signed') # store results in list stcs_a.append(stc_a) stcs_b.append(stc_b) ############################################################################### # 2) save results # create dictionary containing LCMV beamforming results stcs = dict() stcs['cue_a'] = stcs_a stcs['cue_b'] = stcs_b # save to disk