def _cov_as_csd(cov, info): rng = np.random.RandomState(0) assert cov['data'].ndim == 2 assert len(cov['data']) == len(cov['names']) # we need to make this have at least some complex structure data = cov['data'] + 1e-1 * _rand_csd(rng, info) assert data.dtype == np.complex128 return CrossSpectralDensity(_sym_mat_to_vector(data), cov['names'], 0., 16)
def _make_csd(): """Make a simple CrossSpectralDensity object.""" frequencies = [1., 2., 3., 4.] n_freqs = len(frequencies) names = ['CH1', 'CH2', 'CH3'] tmin, tmax = (0., 1.) data = np.arange(6. * n_freqs).reshape(n_freqs, 6).T return CrossSpectralDensity(data, names, frequencies, 1, tmin, tmax)
def test_plot_csd(): """Test plotting of CSD matrices.""" csd = CrossSpectralDensity([1, 2, 3], ['CH1', 'CH2'], frequencies=[(10, 20)], n_fft=1, tmin=0, tmax=1,) plot_csd(csd, mode='csd') # Plot cross-spectral density plot_csd(csd, mode='coh') # Plot coherence plt.close('all')
def _make_rand_csd(info, csd): rng = np.random.RandomState(0) data = _rand_csd(rng, info) # now we need to have the same null space as the data csd s, u = np.linalg.eigh(csd.get_data(csd.frequencies[0])) mask = np.abs(s) >= s[-1] * 1e-7 rank = mask.sum() assert rank == len(data) == len(info['ch_names']) noise_csd = CrossSpectralDensity( _sym_mat_to_vector(data), info['ch_names'], 0., csd.n_fft) return noise_csd, rank
def test_csd(): """Test constructing a CrossSpectralDensity.""" csd = CrossSpectralDensity([1, 2, 3], ['CH1', 'CH2'], frequencies=1, n_fft=1, tmin=0, tmax=1) assert_array_equal(csd._data, [[1], [2], [3]]) # Conversion to 2D array assert_array_equal(csd.frequencies, [1]) # Conversion to 1D array # Channels don't match raises(ValueError, CrossSpectralDensity, [1, 2, 3], ['CH1', 'CH2', 'Too many!'], tmin=0, tmax=1, frequencies=1, n_fft=1) raises(ValueError, CrossSpectralDensity, [1, 2, 3], ['too little'], tmin=0, tmax=1, frequencies=1, n_fft=1) # Frequencies don't match raises(ValueError, CrossSpectralDensity, [[1, 2], [3, 4], [5, 6]], ['CH1', 'CH2'], tmin=0, tmax=1, frequencies=1, n_fft=1) # Invalid dims raises(ValueError, CrossSpectralDensity, [[[1]]], ['CH1'], frequencies=1, n_fft=1, tmin=0, tmax=1)
def test_make_dics(tmpdir, _load_forward, idx, whiten): """Test making DICS beamformer filters.""" # We only test proper handling of parameters here. Testing the results is # done in test_apply_dics_timeseries and test_apply_dics_csd. fwd_free, fwd_surf, fwd_fixed, fwd_vol = _load_forward epochs, _, csd, _, label, vertices, source_ind = \ _simulate_data(fwd_fixed, idx) with pytest.raises(ValueError, match='several sensor types'): make_dics(epochs.info, fwd_surf, csd, label=label, pick_ori=None) if whiten: rng = np.random.RandomState(0) scales = mne.make_ad_hoc_cov(epochs.info).data n = scales.size # Some random complex correlation structure (with channel scalings) data = rng.randn(n, n) + 1j * rng.randn(n, n) data = data @ data.conj().T data *= scales data *= scales[:, np.newaxis] data.flat[::n + 1] = scales noise_csd = CrossSpectralDensity(_sym_mat_to_vector(data), epochs.ch_names, 0., csd.n_fft) else: noise_csd = None epochs.pick_types(meg='grad') with pytest.raises(ValueError, match="Invalid value for the 'pick_ori'"): make_dics(epochs.info, fwd_fixed, csd, pick_ori="notexistent", noise_csd=noise_csd) with pytest.raises(ValueError, match='rank, if str'): make_dics(epochs.info, fwd_fixed, csd, rank='foo', noise_csd=noise_csd) with pytest.raises(TypeError, match='rank must be'): make_dics(epochs.info, fwd_fixed, csd, rank=1., noise_csd=noise_csd) # Test if fixed forward operator is detected when picking normal # orientation with pytest.raises(ValueError, match='forward operator with free ori'): make_dics(epochs.info, fwd_fixed, csd, pick_ori="normal", noise_csd=noise_csd) # Test if non-surface oriented forward operator is detected when picking # normal orientation with pytest.raises(ValueError, match='oriented in surface coordinates'): make_dics(epochs.info, fwd_free, csd, pick_ori="normal", noise_csd=noise_csd) # Test if volume forward operator is detected when picking normal # orientation with pytest.raises(ValueError, match='oriented in surface coordinates'): make_dics(epochs.info, fwd_vol, csd, pick_ori="normal", noise_csd=noise_csd) # Test invalid combinations of parameters with pytest.raises(ValueError, match='reduce_rank cannot be used with'): make_dics(epochs.info, fwd_free, csd, inversion='single', reduce_rank=True, noise_csd=noise_csd) # TODO: Restore this? # with pytest.raises(ValueError, match='not stable with depth'): # make_dics(epochs.info, fwd_free, csd, weight_norm='unit-noise-gain', # inversion='single', depth=None) # Sanity checks on the returned filters n_freq = len(csd.frequencies) vertices = np.intersect1d(label.vertices, fwd_free['src'][0]['vertno']) n_verts = len(vertices) n_orient = 3 n_channels = len(epochs.ch_names) # Test return values weight_norm = 'unit-noise-gain' inversion = 'single' filters = make_dics(epochs.info, fwd_surf, csd, label=label, pick_ori=None, weight_norm=weight_norm, depth=None, noise_csd=noise_csd, inversion=inversion) assert filters['weights'].shape == (n_freq, n_verts * n_orient, n_channels) assert np.iscomplexobj(filters['weights']) assert filters['csd'].ch_names == epochs.ch_names assert isinstance(filters['csd'], CrossSpectralDensity) assert filters['ch_names'] == epochs.ch_names assert_array_equal(filters['proj'], np.eye(n_channels)) assert_array_equal(filters['vertices'][0], vertices) assert_array_equal(filters['vertices'][1], []) # Label was on the LH assert filters['subject'] == fwd_free['src']._subject assert filters['pick_ori'] is None assert filters['is_free_ori'] assert filters['inversion'] == inversion assert filters['weight_norm'] == weight_norm assert 'DICS' in repr(filters) assert 'subject "sample"' in repr(filters) assert str(len(vertices)) in repr(filters) assert str(n_channels) in repr(filters) assert 'rank' not in repr(filters) _, noise_cov = _prepare_noise_csd(csd, noise_csd, real_filter=False) _, _, _, _, G, _, _, _ = _prepare_beamformer_input(epochs.info, fwd_surf, label, 'vector', combine_xyz=False, exp=None, noise_cov=noise_cov) G.shape = (n_channels, n_verts, n_orient) G = G.transpose(1, 2, 0).conj() # verts, orient, ch _assert_weight_norm(filters, G) inversion = 'matrix' filters = make_dics(epochs.info, fwd_surf, csd, label=label, pick_ori=None, weight_norm=weight_norm, depth=None, noise_csd=noise_csd, inversion=inversion) _assert_weight_norm(filters, G) weight_norm = 'unit-noise-gain-invariant' inversion = 'single' filters = make_dics(epochs.info, fwd_surf, csd, label=label, pick_ori=None, weight_norm=weight_norm, depth=None, noise_csd=noise_csd, inversion=inversion) _assert_weight_norm(filters, G) # Test picking orientations. Also test weight norming under these different # conditions. weight_norm = 'unit-noise-gain' filters = make_dics(epochs.info, fwd_surf, csd, label=label, pick_ori='normal', weight_norm=weight_norm, depth=None, noise_csd=noise_csd, inversion=inversion) n_orient = 1 assert filters['weights'].shape == (n_freq, n_verts * n_orient, n_channels) assert not filters['is_free_ori'] _assert_weight_norm(filters, G) filters = make_dics(epochs.info, fwd_surf, csd, label=label, pick_ori='max-power', weight_norm=weight_norm, depth=None, noise_csd=noise_csd, inversion=inversion) n_orient = 1 assert filters['weights'].shape == (n_freq, n_verts * n_orient, n_channels) assert not filters['is_free_ori'] _assert_weight_norm(filters, G) # From here on, only work on a single frequency csd = csd[0] # Test using a real-valued filter filters = make_dics(epochs.info, fwd_surf, csd, label=label, pick_ori='normal', real_filter=True, noise_csd=noise_csd) assert not np.iscomplexobj(filters['weights']) # Test forward normalization. When inversion='single', the power of a # unit-noise CSD should be 1, even without weight normalization. if not whiten: csd_noise = csd.copy() inds = np.triu_indices(csd.n_channels) # Using [:, :] syntax for in-place broadcasting csd_noise._data[:, :] = np.eye(csd.n_channels)[inds][:, np.newaxis] filters = make_dics(epochs.info, fwd_surf, csd_noise, label=label, weight_norm=None, depth=1., noise_csd=noise_csd, inversion='single') w = filters['weights'][0][:3] assert_allclose(np.diag(w.dot(w.conjugate().T)), 1.0, rtol=1e-6, atol=0) # Test turning off both forward and weight normalization filters = make_dics(epochs.info, fwd_surf, csd, label=label, weight_norm=None, depth=None, noise_csd=noise_csd) w = filters['weights'][0][:3] assert not np.allclose( np.diag(w.dot(w.conjugate().T)), 1.0, rtol=1e-2, atol=0) # Test neural-activity-index weight normalization. It should be a scaled # version of the unit-noise-gain beamformer. filters_nai = make_dics(epochs.info, fwd_surf, csd, label=label, pick_ori='max-power', weight_norm='nai', depth=None, noise_csd=noise_csd) w_nai = filters_nai['weights'][0] filters_ung = make_dics(epochs.info, fwd_surf, csd, label=label, pick_ori='max-power', weight_norm='unit-noise-gain', depth=None, noise_csd=noise_csd) w_ung = filters_ung['weights'][0] assert_allclose(np.corrcoef(np.abs(w_nai).ravel(), np.abs(w_ung).ravel()), 1, atol=1e-7) # Test whether spatial filter contains src_type assert 'src_type' in filters fname = op.join(str(tmpdir), 'filters-dics.h5') filters.save(fname) filters_read = read_beamformer(fname) assert isinstance(filters, Beamformer) assert isinstance(filters_read, Beamformer) for key in ['tmin', 'tmax']: # deal with strictness of object_diff setattr(filters['csd'], key, np.float64(getattr(filters['csd'], key))) assert object_diff(filters, filters_read) == ''