def test_pick_channels_cov(): """Test picking channels from a Covariance object.""" info = create_info(['CH1', 'CH2', 'CH3'], 1., ch_types='eeg') cov = make_ad_hoc_cov(info) cov['data'] = np.array([1., 2., 3.]) cov_copy = pick_channels_cov(cov, ['CH2', 'CH1'], ordered=False, copy=True) assert cov_copy.ch_names == ['CH1', 'CH2'] assert_array_equal(cov_copy['data'], [1., 2.]) # Test re-ordering channels cov_copy = pick_channels_cov(cov, ['CH2', 'CH1'], ordered=True, copy=True) assert cov_copy.ch_names == ['CH2', 'CH1'] assert_array_equal(cov_copy['data'], [2., 1.]) # Test picking in-place pick_channels_cov(cov, ['CH2', 'CH1'], copy=False) assert cov.ch_names == ['CH1', 'CH2'] assert_array_equal(cov['data'], [1., 2.]) # Test whether `method` and `loglik` are dropped when None cov['method'] = None cov['loglik'] = None cov_copy = pick_channels_cov(cov, ['CH1', 'CH2'], copy=True) assert 'method' not in cov_copy assert 'loglik' not in cov_copy
def test_check_info_inv(): """Test checks for common channels across fwd model and cov matrices.""" epochs, data_cov, noise_cov, forward = _get_data() # make sure same channel lists exist in data to make testing life easier assert epochs.info['ch_names'] == data_cov.ch_names assert epochs.info['ch_names'] == noise_cov.ch_names # check whether bad channels get excluded from the channel selection # info info_bads = epochs.info.copy() info_bads['bads'] = info_bads['ch_names'][1:3] # include two bad channels picks = _check_info_inv(info_bads, forward, noise_cov=noise_cov) assert [1, 2] not in picks # covariance matrix data_cov_bads = data_cov.copy() data_cov_bads['bads'] = data_cov_bads.ch_names[0] picks = _check_info_inv(epochs.info, forward, data_cov=data_cov_bads) assert 0 not in picks # noise covariance matrix noise_cov_bads = noise_cov.copy() noise_cov_bads['bads'] = noise_cov_bads.ch_names[1] picks = _check_info_inv(epochs.info, forward, noise_cov=noise_cov_bads) assert 1 not in picks # test whether reference channels get deleted info_ref = epochs.info.copy() info_ref['chs'][0]['kind'] = 301 # pretend to have a ref channel picks = _check_info_inv(info_ref, forward, noise_cov=noise_cov) assert 0 not in picks # pick channels in all inputs and make sure common set is returned epochs.pick_channels([epochs.ch_names[ii] for ii in range(10)]) data_cov = pick_channels_cov( data_cov, include=[data_cov.ch_names[ii] for ii in range(5, 20)]) noise_cov = pick_channels_cov( noise_cov, include=[noise_cov.ch_names[ii] for ii in range(7, 12)]) picks = _check_info_inv(epochs.info, forward, noise_cov=noise_cov, data_cov=data_cov) assert list(range(7, 10)) == picks
def test_check_info_inv(): """Test checks for common channels across fwd model and cov matrices.""" epochs, data_cov, noise_cov, forward = _get_data() # make sure same channel lists exist in data to make testing life easier assert epochs.info['ch_names'] == data_cov.ch_names assert epochs.info['ch_names'] == noise_cov.ch_names # check whether bad channels get excluded from the channel selection # info info_bads = epochs.info.copy() info_bads['bads'] = info_bads['ch_names'][1:3] # include two bad channels picks = _check_info_inv(info_bads, forward, noise_cov=noise_cov) assert [1, 2] not in picks # covariance matrix data_cov_bads = data_cov.copy() data_cov_bads['bads'] = data_cov_bads.ch_names[0] picks = _check_info_inv(epochs.info, forward, data_cov=data_cov_bads) assert 0 not in picks # noise covariance matrix noise_cov_bads = noise_cov.copy() noise_cov_bads['bads'] = noise_cov_bads.ch_names[1] picks = _check_info_inv(epochs.info, forward, noise_cov=noise_cov_bads) assert 1 not in picks # test whether reference channels get deleted info_ref = epochs.info.copy() info_ref['chs'][0]['kind'] = 301 # pretend to have a ref channel picks = _check_info_inv(info_ref, forward, noise_cov=noise_cov) assert 0 not in picks # pick channels in all inputs and make sure common set is returned epochs.pick_channels([epochs.ch_names[ii] for ii in range(10)]) data_cov = pick_channels_cov(data_cov, include=[data_cov.ch_names[ii] for ii in range(5, 20)]) noise_cov = pick_channels_cov(noise_cov, include=[noise_cov.ch_names[ii] for ii in range(7, 12)]) picks = _check_info_inv(epochs.info, forward, noise_cov=noise_cov, data_cov=data_cov) assert list(range(7, 10)) == picks
def test_rank_deficiency(): """Test adding noise from M/EEG float32 (I/O) cov with projectors.""" # See gh-5940 evoked = read_evokeds(ave_fname, 0, baseline=(None, 0)) evoked.info['bads'] = ['MEG 2443'] evoked.info['lowpass'] = 20 # fake for decim picks = pick_types(evoked.info, meg=True, eeg=False) picks = picks[::16] evoked.pick_channels([evoked.ch_names[pick] for pick in picks]) evoked.info.normalize_proj() cov = read_cov(cov_fname) cov['projs'] = [] cov = regularize(cov, evoked.info, rank=None) cov = pick_channels_cov(cov, evoked.ch_names) evoked.data[:] = 0 add_noise(evoked, cov) cov_new = compute_covariance( EpochsArray(evoked.data[np.newaxis], evoked.info), verbose='error') assert cov['names'] == cov_new['names'] r = np.corrcoef(cov['data'].ravel(), cov_new['data'].ravel())[0, 1] assert r > 0.98
def test_rank_deficiency(): """Test adding noise from M/EEG float32 (I/O) cov with projectors.""" # See gh-5940 evoked = read_evokeds(ave_fname, 0, baseline=(None, 0)) evoked.info['bads'] = ['MEG 2443'] evoked.info['lowpass'] = 20 # fake for decim picks = pick_types(evoked.info, meg=True, eeg=False) picks = picks[::16] evoked.pick_channels([evoked.ch_names[pick] for pick in picks]) evoked.info.normalize_proj() cov = read_cov(cov_fname) cov['projs'] = [] cov = regularize(cov, evoked.info, rank=None) cov = pick_channels_cov(cov, evoked.ch_names) evoked.data[:] = 0 add_noise(evoked, cov) cov_new = compute_covariance( EpochsArray(evoked.data[np.newaxis], evoked.info), verbose='error') assert cov['names'] == cov_new['names'] r = np.corrcoef(cov['data'].ravel(), cov_new['data'].ravel())[0, 1] assert r > 0.98
def make_lcmv(info, forward, data_cov, reg=0.05, noise_cov=None, label=None, pick_ori=None, rank=None, weight_norm='unit-noise-gain', reduce_rank=False, verbose=None): """Compute LCMV spatial filter. Parameters ---------- info : dict The measurement info to specify the channels to include. Bad channels in info['bads'] are not used. forward : dict Forward operator. data_cov : Covariance The data covariance. reg : float The regularization for the whitened data covariance. noise_cov : Covariance The noise covariance. If provided, whitening will be done. Providing a noise covariance is mandatory if you mix sensor types, e.g. gradiometers with magnetometers or EEG with MEG. label : Label Restricts the LCMV solution to a given label. pick_ori : None | 'normal' | 'max-power' If 'normal', rather than pooling the orientations by taking the norm, only the radial component is kept. If 'max-power', the source orientation that maximizes output source power is chosen. If None, the solution depends on the forward model: if the orientation is fixed, a scalar beamformer is computed. If the forward model has free orientation, a vector beamformer is computed, combining the output for all source orientations. rank : None | int | dict Specified rank of the noise covariance matrix. If None, the rank is detected automatically. If int, the rank is specified for the MEG channels. A dictionary with entries 'eeg' and/or 'meg' can be used to specify the rank for each modality. weight_norm : 'unit-noise-gain' | 'nai' | None If 'unit-noise-gain', the unit-noise gain minimum variance beamformer will be computed (Borgiotti-Kaplan beamformer) [2]_, if 'nai', the Neural Activity Index [1]_ will be computed, if None, the unit-gain LCMV beamformer [2]_ will be computed. reduce_rank : bool If True, the rank of the leadfield will be reduced by 1 for each spatial location. Setting reduce_rank to True is typically necessary if you use a single sphere model for MEG. verbose : bool, str, int, or None If not None, override default verbose level (see :func:`mne.verbose` and :ref:`Logging documentation <tut_logging>` for more). Returns ------- filters | dict Beamformer weights. Notes ----- The original reference is [1]_. References ---------- .. [1] Van Veen et al. Localization of brain electrical activity via linearly constrained minimum variance spatial filtering. Biomedical Engineering (1997) vol. 44 (9) pp. 867--880 .. [2] Sekihara & Nagarajan. Adaptive spatial filters for electromagnetic brain imaging (2008) Springer Science & Business Media """ picks = _setup_picks(info, forward, data_cov, noise_cov) is_free_ori, ch_names, proj, vertno, G = \ _prepare_beamformer_input(info, forward, label, picks, pick_ori) data_cov = pick_channels_cov(data_cov, include=ch_names) Cm = data_cov['data'] # check number of sensor types present in the data # This line takes ~23 ms on kernprof # _check_one_ch_type(info, picks, noise_cov) # apply SSPs is_ssp = False if info['projs']: Cm = np.dot(proj, np.dot(Cm, proj.T)) is_ssp = True if noise_cov is not None: # Handle whitening + data covariance whitener, _ = compute_whitener(noise_cov, info, picks, rank=rank) # whiten the leadfield G = np.dot(whitener, G) # whiten data covariance Cm = np.dot(whitener, np.dot(Cm, whitener.T)) else: whitener = None # Tikhonov regularization using reg parameter d to control for # trade-off between spatial resolution and noise sensitivity Cm_inv, d = _reg_pinv(Cm.copy(), reg) if weight_norm is not None: # estimate noise level based on covariance matrix, taking the # smallest eigenvalue that is not zero noise, _ = linalg.eigh(Cm) if rank is not None: rank_Cm = rank else: rank_Cm = estimate_rank(Cm, tol='auto', norm=False, return_singular=False) noise = noise[len(noise) - rank_Cm] # use either noise floor or regularization parameter d noise = max(noise, d) # Compute square of Cm_inv used for weight normalization Cm_inv_sq = np.dot(Cm_inv, Cm_inv) del Cm # leadfield rank and optional rank reduction if reduce_rank: if not pick_ori == 'max-power': raise NotImplementedError('The computation of spatial filters ' 'with rank reduction using reduce_rank ' 'parameter is only implemented with ' 'pick_ori=="max-power".') if not isinstance(reduce_rank, bool): raise ValueError('reduce_rank has to be True or False ' ' (got %s).' % reduce_rank) # Compute spatial filters W = np.dot(G.T, Cm_inv) n_orient = 3 if is_free_ori else 1 n_sources = G.shape[1] // n_orient TMP = np.dot(G.T, Cm_inv_sq) G = np.asfortranarray(G) max_ori = np.empty(n_orient * n_sources, order='F') pwr = np.empty(n_sources, order='F') tmp_prod = _beam_loop(n_sources, W, G, n_orient, TMP) max_ori = stacked_power_iteration(tmp_prod) W = multiply_by_orientations_rowwise(W, max_ori) G_or = multiply_by_orientations_columnwise(G, max_ori) TMP_or = multiply_by_orientations_rowwise(TMP, max_ori) pwr = np.array([TMP_or[k, :] @ G_or[:, k] for k in range(n_sources)]) denom = np.sqrt(pwr) W /= np.expand_dims(denom, axis=1) is_free_ori = False filters = dict(weights=W, data_cov=data_cov, noise_cov=noise_cov, whitener=whitener, weight_norm=weight_norm, pick_ori=pick_ori, ch_names=ch_names, proj=proj, is_ssp=is_ssp, vertices=vertno, is_free_ori=is_free_ori, nsource=forward['nsource'], src=deepcopy(forward['src'])) return filters