Exemple #1
0
def test_apply_dics_csd(_load_forward):
    """Test applying a DICS beamformer to a CSD matrix."""
    fwd_free, fwd_surf, fwd_fixed, _, label = _load_forward
    epochs, _, csd, source_vertno = _simulate_data(fwd_fixed)
    vertices = np.intersect1d(label.vertices, fwd_free['src'][0]['vertno'])
    source_ind = vertices.tolist().index(source_vertno)
    reg = 1  # Lots of regularization for our toy dataset

    with pytest.raises(RuntimeError, match='several sensor types'):
        make_dics(epochs.info, fwd_free, csd)
    epochs.pick_types(meg='grad')

    # Try different types of forward models
    assert label.hemi == 'lh'
    assert vertices[source_ind] == source_vertno
    rr_want = fwd_free['src'][0]['rr'][source_vertno]
    for fwd in [fwd_free, fwd_surf, fwd_fixed]:
        filters = make_dics(epochs.info,
                            fwd,
                            csd,
                            label=label,
                            reg=reg,
                            inversion='single')
        power, f = apply_dics_csd(csd, filters)
        assert f == [10, 20]

        # Did we find the true source at 20 Hz?
        idx = np.argmax(power.data[:, 1])
        rr_got = fwd_free['src'][0]['rr'][vertices[idx]]
        dist = np.linalg.norm(rr_got - rr_want)
        assert dist == 0.

        # Is the signal stronger at 20 Hz than 10?
        assert power.data[source_ind, 1] > power.data[source_ind, 0]
Exemple #2
0
def test_apply_dics_csd(_load_forward, idx, inversion, weight_norm):
    """Test applying a DICS beamformer to a CSD matrix."""
    fwd_free, fwd_surf, fwd_fixed, _ = _load_forward
    epochs, _, csd, source_vertno, label, vertices, source_ind = \
        _simulate_data(fwd_fixed, idx)
    reg = 1  # Lots of regularization for our toy dataset

    with pytest.raises(ValueError, match='several sensor types'):
        make_dics(epochs.info, fwd_free, csd)
    epochs.pick_types(meg='grad')

    # Try different types of forward models
    assert label.hemi == 'lh'
    for fwd in [fwd_free, fwd_surf, fwd_fixed]:
        filters = make_dics(epochs.info, fwd, csd, label=label, reg=reg,
                            inversion=inversion, weight_norm=weight_norm)
        power, f = apply_dics_csd(csd, filters)
        assert f == [10, 20]

        # Did we find the true source at 20 Hz?
        dist = _fwd_dist(power, fwd_free, vertices, source_ind)
        assert dist == 0.

        # Is the signal stronger at 20 Hz than 10?
        assert power.data[source_ind, 1] > power.data[source_ind, 0]
Exemple #3
0
def test_make_dics_rank(_load_forward, idx, whiten):
    """Test making DICS beamformer filters with rank param."""
    _, fwd_surf, fwd_fixed, _ = _load_forward
    epochs, _, csd, _, label, _, _ = _simulate_data(fwd_fixed, idx)
    if whiten:
        noise_csd, want_rank = _make_rand_csd(epochs.info, csd)
        kind = 'mag + grad'
    else:
        noise_csd = None
        epochs.pick_types(meg='grad')
        want_rank = len(epochs.ch_names)
        assert want_rank == 41
        kind = 'grad'

    with catch_logging() as log:
        filters = make_dics(epochs.info,
                            fwd_surf,
                            csd,
                            label=label,
                            noise_csd=noise_csd,
                            verbose=True)
    log = log.getvalue()
    assert f'Estimated rank ({kind}): {want_rank}' in log, log
    stc, _ = apply_dics_csd(csd, filters)
    other_rank = want_rank - 1  # shouldn't make a huge difference
    use_rank = dict(meg=other_rank)
    if not whiten:
        # XXX it's a bug that our rank functions don't treat "meg"
        # properly here...
        use_rank['grad'] = use_rank.pop('meg')
    with catch_logging() as log:
        filters_2 = make_dics(epochs.info,
                              fwd_surf,
                              csd,
                              label=label,
                              noise_csd=noise_csd,
                              rank=use_rank,
                              verbose=True)
    log = log.getvalue()
    assert f'Computing rank from covariance with rank={use_rank}' in log, log
    stc_2, _ = apply_dics_csd(csd, filters_2)
    corr = np.corrcoef(stc_2.data.ravel(), stc.data.ravel())[0, 1]
    assert 0.8 < corr < 0.99999

    # degenerate conditions
    if whiten:
        # make rank deficient
        data = noise_csd.get_data(0.)
        data[0] = data[:0] = 0
        noise_csd._data[:, 0] = _sym_mat_to_vector(data)
        with pytest.raises(ValueError, match='meg data rank.*the noise rank'):
            filters = make_dics(epochs.info,
                                fwd_surf,
                                csd,
                                label=label,
                                noise_csd=noise_csd,
                                verbose=True)
Exemple #4
0
def test_real(_load_forward):
    """Test using a real-valued filter."""
    fwd_free, fwd_surf, fwd_fixed, fwd_vol, label = _load_forward
    epochs, _, csd, source_vertno = _simulate_data(fwd_fixed)
    vertices = np.intersect1d(label.vertices, fwd_free['src'][0]['vertno'])
    source_ind = vertices.tolist().index(source_vertno)
    rr_want = fwd_free['src'][0]['rr'][source_vertno]
    epochs.pick_types('grad')
    reg = 1  # Lots of regularization for our toy dataset
    filters_real = make_dics(epochs.info,
                             fwd_surf,
                             csd,
                             label=label,
                             reg=reg,
                             real_filter=True)
    # Also test here that no warings are thrown - implemented to check whether
    # src should not be None warning occurs:
    with pytest.warns(None) as w:
        power, f = apply_dics_csd(csd, filters_real)
    assert len(w) == 0

    assert f == [10, 20]
    assert np.argmax(power.data[:, 1]) == source_ind
    assert power.data[source_ind, 1] > power.data[source_ind, 0]

    # Test rank reduction
    filters_real = make_dics(epochs.info,
                             fwd_surf,
                             csd,
                             label=label,
                             reg=5,
                             pick_ori='max-power',
                             inversion='matrix',
                             reduce_rank=True)
    power, f = apply_dics_csd(csd, filters_real)
    assert f == [10, 20]
    idx = np.argmax(power.data[:, 1])
    rr_got = fwd_free['src'][0]['rr'][vertices[idx]]
    dist = np.linalg.norm(rr_got - rr_want)
    assert dist <= 0.02
    assert power.data[source_ind, 1] > power.data[source_ind, 0]

    # Test computing source power on a volume source space
    filters_vol = make_dics(epochs.info, fwd_vol, csd, reg=reg)
    power, f = apply_dics_csd(csd, filters_vol)
    vol_source_ind = 3851  # FIXME: not make this hardcoded
    assert f == [10, 20]
    assert np.argmax(power.data[:, 1]) == vol_source_ind
    assert power.data[vol_source_ind, 1] > power.data[vol_source_ind, 0]

    # check whether a filters object without src_type throws expected warning
    del filters_vol['src_type']  # emulate 0.16 behaviour to cause warning
    with pytest.warns(RuntimeWarning,
                      match='spatial filter does not contain '
                      'src_type'):
        apply_dics_csd(csd, filters_vol)
Exemple #5
0
def test_real(_load_forward, idx, mat_tol, vol_tol):
    """Test using a real-valued filter."""
    fwd_free, fwd_surf, fwd_fixed, fwd_vol = _load_forward
    epochs, _, csd, source_vertno, label, vertices, source_ind = \
        _simulate_data(fwd_fixed, idx)
    epochs.pick_types('grad')
    reg = 1  # Lots of regularization for our toy dataset
    filters_real = make_dics(epochs.info,
                             fwd_surf,
                             csd,
                             label=label,
                             reg=reg,
                             real_filter=True)
    # Also test here that no warings are thrown - implemented to check whether
    # src should not be None warning occurs:
    with pytest.warns(None) as w:
        power, f = apply_dics_csd(csd, filters_real)
    assert len(w) == 0

    assert f == [10, 20]
    dist = _fwd_dist(power, fwd_surf, vertices, source_ind)
    assert dist == 0
    assert power.data[source_ind, 1] > power.data[source_ind, 0]

    # Test rank reduction
    filters_real = make_dics(epochs.info,
                             fwd_surf,
                             csd,
                             label=label,
                             reg=5,
                             pick_ori='max-power',
                             inversion='matrix',
                             reduce_rank=True)
    power, f = apply_dics_csd(csd, filters_real)
    assert f == [10, 20]
    dist = _fwd_dist(power, fwd_surf, vertices, source_ind)
    assert dist == 0
    assert power.data[source_ind, 1] > power.data[source_ind, 0]

    # Test computing source power on a volume source space
    filters_vol = make_dics(epochs.info, fwd_vol, csd, reg=reg)
    power, f = apply_dics_csd(csd, filters_vol)
    vol_source_ind = _nearest_vol_ind(fwd_vol, fwd_surf, vertices, source_ind)
    assert f == [10, 20]
    dist = _fwd_dist(power, fwd_vol, fwd_vol['src'][0]['vertno'],
                     vol_source_ind)
    assert dist <= vol_tol
    assert power.data[vol_source_ind, 1] > power.data[vol_source_ind, 0]

    # check whether a filters object without src_type throws expected warning
    del filters_vol['src_type']  # emulate 0.16 behaviour to cause warning
    with pytest.warns(RuntimeWarning,
                      match='spatial filter does not contain '
                      'src_type'):
        apply_dics_csd(csd, filters_vol)
Exemple #6
0
def test_apply_dics_ori_inv(_load_forward, pick_ori, inversion):
    """Testpicking different orientations and inversion modes."""
    fwd_free, fwd_surf, fwd_fixed, fwd_vol, label = _load_forward
    epochs, _, csd, source_vertno = _simulate_data(fwd_fixed)
    epochs.pick_types('grad')
    vertices = np.intersect1d(label.vertices, fwd_free['src'][0]['vertno'])
    source_ind = vertices.tolist().index(source_vertno)
    rr_want = fwd_free['src'][0]['rr'][source_vertno]

    reg_ = 5 if inversion == 'matrix' else 1
    filters = make_dics(epochs.info,
                        fwd_surf,
                        csd,
                        label=label,
                        reg=reg_,
                        pick_ori=pick_ori,
                        inversion=inversion,
                        normalize_fwd=False,
                        weight_norm='unit-noise-gain')
    power, f = apply_dics_csd(csd, filters)
    assert f == [10, 20]
    idx = np.argmax(power.data[:, 1])
    rr_got = fwd_free['src'][0]['rr'][vertices[idx]]
    dist = np.linalg.norm(rr_got - rr_want)
    assert dist <= (0.03 if inversion == 'matrix' else 0.)
    assert power.data[source_ind, 1] > power.data[source_ind, 0]

    # Test unit-noise-gain weighting
    csd_noise = csd.copy()
    inds = np.triu_indices(csd.n_channels)
    csd_noise._data[...] = np.eye(csd.n_channels)[inds][:, np.newaxis]
    noise_power, f = apply_dics_csd(csd_noise, filters)
    assert np.allclose(noise_power.data, 1)

    # Test filter with forward normalization instead of weight
    # normalization
    filters = make_dics(epochs.info,
                        fwd_surf,
                        csd,
                        label=label,
                        reg=reg_,
                        pick_ori=pick_ori,
                        inversion=inversion,
                        weight_norm=None,
                        normalize_fwd=True)
    power, f = apply_dics_csd(csd, filters)
    assert f == [10, 20]
    idx = np.argmax(power.data[:, 1])
    rr_got = fwd_free['src'][0]['rr'][vertices[idx]]
    dist = np.linalg.norm(rr_got - rr_want)
    assert dist <= (0.035 if inversion == 'matrix' else 0.)
    assert power.data[source_ind, 1] > power.data[source_ind, 0]
Exemple #7
0
def test_apply_dics_ori_inv(_load_forward, pick_ori, inversion, idx):
    """Test picking different orientations and inversion modes."""
    fwd_free, fwd_surf, fwd_fixed, fwd_vol = _load_forward
    epochs, _, csd, source_vertno, label, vertices, source_ind = \
        _simulate_data(fwd_fixed, idx)
    epochs.pick_types(meg='grad')

    reg_ = 5 if inversion == 'matrix' else 1
    filters = make_dics(epochs.info,
                        fwd_surf,
                        csd,
                        label=label,
                        reg=reg_,
                        pick_ori=pick_ori,
                        inversion=inversion,
                        depth=None,
                        weight_norm='unit-noise-gain')
    power, f = apply_dics_csd(csd, filters)
    assert f == [10, 20]
    dist = _fwd_dist(power, fwd_surf, vertices, source_ind)
    # This is 0. for unit-noise-gain-invariant:
    assert dist <= (0.02 if inversion == 'matrix' else 0.)
    assert power.data[source_ind, 1] > power.data[source_ind, 0]

    # Test unit-noise-gain weighting
    csd_noise = csd.copy()
    inds = np.triu_indices(csd.n_channels)
    csd_noise._data[...] = np.eye(csd.n_channels)[inds][:, np.newaxis]
    noise_power, f = apply_dics_csd(csd_noise, filters)
    want_norm = 3 if pick_ori is None else 1.
    assert_allclose(noise_power.data, want_norm, atol=1e-7)

    # Test filter with forward normalization instead of weight
    # normalization
    filters = make_dics(epochs.info,
                        fwd_surf,
                        csd,
                        label=label,
                        reg=reg_,
                        pick_ori=pick_ori,
                        inversion=inversion,
                        weight_norm=None,
                        depth=1.)
    power, f = apply_dics_csd(csd, filters)
    assert f == [10, 20]
    dist = _fwd_dist(power, fwd_surf, vertices, source_ind)
    mat_tol = {0: 0.055, 100: 0.20, 200: 0.015, 233: 0.035}[idx]
    max_ = (mat_tol if inversion == 'matrix' else 0.)
    assert 0 <= dist <= max_
    assert power.data[source_ind, 1] > power.data[source_ind, 0]
Exemple #8
0
def test_apply_dics_ori_inv(_load_forward, pick_ori, inversion, idx, mat_tol,
                            vol_tol):
    """Testpicking different orientations and inversion modes."""
    fwd_free, fwd_surf, fwd_fixed, fwd_vol = _load_forward
    epochs, _, csd, source_vertno, label, vertices, source_ind = \
        _simulate_data(fwd_fixed, idx)
    epochs.pick_types('grad')

    reg_ = 5 if inversion == 'matrix' else 1
    filters = make_dics(epochs.info,
                        fwd_surf,
                        csd,
                        label=label,
                        reg=reg_,
                        pick_ori=pick_ori,
                        inversion=inversion,
                        normalize_fwd=False,
                        weight_norm='unit-noise-gain')
    power, f = apply_dics_csd(csd, filters)
    assert f == [10, 20]
    dist = _fwd_dist(power, fwd_surf, vertices, source_ind)
    assert dist <= (0.03 if inversion == 'matrix' else 0.)
    assert power.data[source_ind, 1] > power.data[source_ind, 0]

    # Test unit-noise-gain weighting
    csd_noise = csd.copy()
    inds = np.triu_indices(csd.n_channels)
    csd_noise._data[...] = np.eye(csd.n_channels)[inds][:, np.newaxis]
    noise_power, f = apply_dics_csd(csd_noise, filters)
    assert np.allclose(noise_power.data, 1)

    # Test filter with forward normalization instead of weight
    # normalization
    filters = make_dics(epochs.info,
                        fwd_surf,
                        csd,
                        label=label,
                        reg=reg_,
                        pick_ori=pick_ori,
                        inversion=inversion,
                        weight_norm=None,
                        normalize_fwd=True)
    power, f = apply_dics_csd(csd, filters)
    assert f == [10, 20]
    dist = _fwd_dist(power, fwd_surf, vertices, source_ind)
    max_ = (mat_tol if inversion == 'matrix' else 0.)
    assert 0 <= dist <= max_
    assert power.data[source_ind, 1] > power.data[source_ind, 0]
Exemple #9
0
def test_localization_bias_free(bias_params_free, reg, pick_ori, weight_norm,
                                use_cov, depth, lower, upper, real_filter):
    """Test localization bias for free-orientation DICS."""
    evoked, fwd, noise_cov, data_cov, want = bias_params_free
    noise_csd = _cov_as_csd(noise_cov, evoked.info)
    data_csd = _cov_as_csd(data_cov, evoked.info)
    del noise_cov, data_cov
    if not use_cov:
        evoked.pick_types(meg='grad')
        noise_csd = None
    loc = apply_dics(
        evoked,
        make_dics(evoked.info,
                  fwd,
                  data_csd,
                  reg,
                  noise_csd,
                  pick_ori=pick_ori,
                  weight_norm=weight_norm,
                  depth=depth,
                  real_filter=real_filter)).data
    loc = np.linalg.norm(loc, axis=1) if pick_ori == 'vector' else np.abs(loc)
    # Compute the percentage of sources for which there is no loc bias:
    perc = (want == np.argmax(loc, axis=0)).mean() * 100
    assert lower <= perc <= upper
def _gen_dics(active_win, baseline_win, epochs):
    freqs = np.logspace(np.log10(12), np.log10(30), 9)
    csd = csd_morlet(epochs, freqs, tmin=-1, tmax=1.5, decim=20)
    csd_baseline = csd_morlet(epochs, freqs, tmin=baseline_win[0],
                              tmax=baseline_win[1], decim=20)
    csd_ers = csd_morlet(epochs, freqs, tmin=active_win[0], tmax=active_win[1],
                         decim=20)
    filters = make_dics(epochs.info, fwd, csd.mean(), pick_ori='max-power',
                        reduce_rank=True, real_filter=True)
    stc_base, freqs = apply_dics_csd(csd_baseline.mean(), filters)
    stc_act, freqs = apply_dics_csd(csd_ers.mean(), filters)
    stc_act /= stc_base
    return stc_act
Exemple #11
0
def test_orientation_max_power(bias_params_fixed, bias_params_free,
                               weight_norm, lower, upper, lower_ori, upper_ori,
                               real_filter):
    """Test orientation selection for bias for max-power DICS."""
    # we simulate data for the fixed orientation forward and beamform using
    # the free orientation forward, and check the orientation match at the end
    evoked, _, noise_cov, data_cov, want = bias_params_fixed
    noise_csd = _cov_as_csd(noise_cov, evoked.info)
    data_csd = _cov_as_csd(data_cov, evoked.info)
    del data_cov, noise_cov
    fwd = bias_params_free[1]
    filters = make_dics(evoked.info,
                        fwd,
                        data_csd,
                        0.05,
                        noise_csd,
                        pick_ori='max-power',
                        weight_norm=weight_norm,
                        depth=None,
                        real_filter=real_filter)
    loc = np.abs(apply_dics(evoked, filters).data)
    ori = filters['max_power_ori'][0]
    assert ori.shape == (246, 3)
    loc = np.abs(loc)
    # Compute the percentage of sources for which there is no loc bias:
    max_idx = np.argmax(loc, axis=0)
    mask = want == max_idx  # ones that localized properly
    perc = mask.mean() * 100
    assert lower <= perc <= upper
    # Compute the dot products of our forward normals and
    # assert we get some hopefully reasonable agreement
    assert fwd['coord_frame'] == FIFF.FIFFV_COORD_HEAD
    nn = np.concatenate(
        [s['nn'][v] for s, v in zip(fwd['src'], filters['vertices'])])
    nn = nn[want]
    nn = apply_trans(invert_transform(fwd['mri_head_t']), nn, move=False)
    assert_allclose(np.linalg.norm(nn, axis=1), 1, atol=1e-6)
    assert_allclose(np.linalg.norm(ori, axis=1), 1, atol=1e-12)
    dots = np.abs((nn[mask] * ori[mask]).sum(-1))
    assert_array_less(dots, 1)
    assert_array_less(0, dots)
    got = np.mean(dots)
    assert lower_ori < got < upper_ori
Exemple #12
0
def test_apply_dics_timeseries():
    """Test DICS applied to timeseries data."""
    fwd_free, fwd_surf, fwd_fixed, fwd_vol, label = _load_forward()
    epochs, evoked, csd, source_vertno = _simulate_data(fwd_fixed)
    vertices = np.intersect1d(label.vertices, fwd_free['src'][0]['vertno'])
    source_ind = vertices.tolist().index(source_vertno)
    reg = 5  # Lots of regularization for our toy dataset

    multiple_filters = make_dics(evoked.info, fwd_surf, csd, label=label,
                                 reg=reg)

    # Sanity checks on the resulting STC after applying DICS on evoked
    stcs = apply_dics(evoked, multiple_filters)
    assert isinstance(stcs, list)
    assert len(stcs) == len(multiple_filters['weights'])
    assert_array_equal(stcs[0].vertices[0], multiple_filters['vertices'][0])
    assert_array_equal(stcs[0].vertices[1], multiple_filters['vertices'][1])
    assert_allclose(stcs[0].times, evoked.times)

    # Applying filters for multiple frequencies on epoch data should fail
    raises(ValueError, apply_dics_epochs, epochs, multiple_filters)

    # From now on, only apply filters with a single frequency (20 Hz).
    csd20 = csd.pick_frequency(20)
    filters = make_dics(evoked.info, fwd_surf, csd20, label=label, reg=reg)

    # Sanity checks on the resulting STC after applying DICS on epochs.
    # 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:
        stcs = apply_dics_epochs(epochs, filters)
    assert len(w) == 0

    assert isinstance(stcs, list)
    assert len(stcs) == 1
    assert_array_equal(stcs[0].vertices[0], filters['vertices'][0])
    assert_array_equal(stcs[0].vertices[1], filters['vertices'][1])
    assert_allclose(stcs[0].times, epochs.times)

    # Did we find the source?
    stc = (stcs[0] ** 2).mean()
    assert np.argmax(stc.data) == source_ind

    # Apply filters to evoked
    stc = apply_dics(evoked, filters)
    stc = (stc ** 2).mean()
    assert np.argmax(stc.data) == source_ind

    # Test if wrong channel selection is detected in application of filter
    evoked_ch = cp.deepcopy(evoked)
    evoked_ch.pick_channels(evoked_ch.ch_names[:-1])
    raises(ValueError, apply_dics, evoked_ch, filters)

    # Test whether projections are applied, by adding a custom projection
    filters_noproj = make_dics(evoked.info, fwd_surf, csd20, label=label)
    stc_noproj = apply_dics(evoked, filters_noproj)
    evoked_proj = evoked.copy()
    p = compute_proj_evoked(evoked_proj, n_grad=1, n_mag=0, n_eeg=0)
    proj_matrix = make_projector(p, evoked_proj.ch_names)[0]
    evoked_proj.info['projs'] += p
    filters_proj = make_dics(evoked_proj.info, fwd_surf, csd20, label=label)
    assert_array_equal(filters_proj['proj'], proj_matrix)
    stc_proj = apply_dics(evoked_proj, filters_proj)
    assert np.any(np.not_equal(stc_noproj.data, stc_proj.data))

    # Test detecting incompatible projections
    filters_proj['proj'] = filters_proj['proj'][:-1, :-1]
    raises(ValueError, apply_dics, evoked_proj, filters_proj)

    # Test returning a generator
    stcs = apply_dics_epochs(epochs, filters, return_generator=False)
    stcs_gen = apply_dics_epochs(epochs, filters, return_generator=True)
    assert_array_equal(stcs[0].data, next(stcs_gen).data)

    # Test computing timecourses on a volume source space
    filters_vol = make_dics(evoked.info, fwd_vol, csd20, reg=reg)
    stc = apply_dics(evoked, filters_vol)
    stc = (stc ** 2).mean()
    assert np.argmax(stc.data) == 3851  # TODO: don't make this hard coded

    # check whether a filters object without src_type throws expected warning
    del filters_vol['src_type']  # emulate 0.16 behaviour to cause warning
    with pytest.warns(RuntimeWarning, match='spatial filter does not contain '
                      'src_type'):
        apply_dics_epochs(epochs, filters_vol)
Exemple #13
0
def test_apply_dics_csd():
    """Test applying a DICS beamformer to a CSD matrix."""
    fwd_free, fwd_surf, fwd_fixed, fwd_vol, label = _load_forward()
    epochs, _, csd, source_vertno = _simulate_data(fwd_fixed)
    vertices = np.intersect1d(label.vertices, fwd_free['src'][0]['vertno'])
    source_ind = vertices.tolist().index(source_vertno)
    reg = 1  # Lots of regularization for our toy dataset

    # Construct an identity "noise" CSD, which we will use to test the
    # 'unit-noise-gain' setting.
    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]

    # Try different types of forward models
    for fwd in [fwd_free, fwd_surf, fwd_fixed]:
        filters = make_dics(epochs.info, fwd, csd, label=label, reg=reg,
                            inversion='single')
        power, f = apply_dics_csd(csd, filters)
        assert f == [10, 20]

        # Did we find the true source at 20 Hz?
        assert np.argmax(power.data[:, 1]) == source_ind

        # Is the signal stronger at 20 Hz than 10?
        assert power.data[source_ind, 1] > power.data[source_ind, 0]

    # Try picking different orientations and inversion modes
    for pick_ori in [None, 'normal', 'max-power']:
        for inversion in ['single', 'matrix']:
            # Matrix inversion mode needs more regularization for this toy
            # dataset.
            if inversion == 'matrix':
                reg_ = 5
            else:
                reg_ = reg

            filters = make_dics(epochs.info, fwd_surf, csd, label=label,
                                reg=reg_, pick_ori=pick_ori,
                                inversion=inversion,
                                weight_norm='unit-noise-gain')
            power, f = apply_dics_csd(csd, filters)
            assert f == [10, 20]
            assert np.argmax(power.data[:, 1]) == source_ind
            assert power.data[source_ind, 1] > power.data[source_ind, 0]

            # Test unit-noise-gain weighting
            noise_power, f = apply_dics_csd(csd_noise, filters)
            assert np.allclose(noise_power.data, 1)

            # Test filter with forward normalization instead of weight
            # normalization
            filters = make_dics(epochs.info, fwd_surf, csd, label=label,
                                reg=reg_, pick_ori=pick_ori,
                                inversion=inversion, weight_norm=None,
                                normalize_fwd=True)
            power, f = apply_dics_csd(csd, filters)
            assert f == [10, 20]
            assert np.argmax(power.data[:, 1]) == source_ind
            assert power.data[source_ind, 1] > power.data[source_ind, 0]

    # Test using a real-valued filter
    filters_real = make_dics(epochs.info, fwd_surf, csd, label=label, reg=reg,
                             real_filter=True)
    # Also test here that no warings are thrown - implemented to check whether
    # src should not be None warning occurs:
    with pytest.warns(None) as w:
        power, f = apply_dics_csd(csd, filters_real)
    assert len(w) == 0

    assert f == [10, 20]
    assert np.argmax(power.data[:, 1]) == source_ind
    assert power.data[source_ind, 1] > power.data[source_ind, 0]

    # Test rank reduction
    filters_real = make_dics(epochs.info, fwd_surf, csd, label=label, reg=5,
                             pick_ori='max-power', inversion='matrix',
                             reduce_rank=True)
    power, f = apply_dics_csd(csd, filters_real)
    assert f == [10, 20]
    assert np.argmax(power.data[:, 1]) == source_ind
    assert power.data[source_ind, 1] > power.data[source_ind, 0]

    # Test computing source power on a volume source space
    filters_vol = make_dics(epochs.info, fwd_vol, csd, reg=reg)
    power, f = apply_dics_csd(csd, filters_vol)
    vol_source_ind = 3851  # FIXME: not make this hardcoded
    assert f == [10, 20]
    assert np.argmax(power.data[:, 1]) == vol_source_ind
    assert power.data[vol_source_ind, 1] > power.data[vol_source_ind, 0]

    # check whether a filters object without src_type throws expected warning
    del filters_vol['src_type']  # emulate 0.16 behaviour to cause warning
    with pytest.warns(RuntimeWarning, match='spatial filter does not contain '
                      'src_type'):
        apply_dics_csd(csd, filters_vol)
Exemple #14
0
def test_make_dics(tmpdir):
    """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, label = _load_forward()
    epochs, _, csd, _ = _simulate_data(fwd_fixed)

    raises(ValueError, make_dics, epochs.info, fwd_fixed, csd,
           pick_ori="notexistent")
    with raises(ValueError, match='rank, if str'):
        make_dics(epochs.info, fwd_fixed, csd, rank='foo')
    with raises(TypeError, match='rank must be'):
        make_dics(epochs.info, fwd_fixed, csd, rank=1.)

    # Test if fixed forward operator is detected when picking normal
    # orientation
    raises(ValueError, make_dics, epochs.info, fwd_fixed, csd,
           pick_ori="normal")

    # Test if non-surface oriented forward operator is detected when picking
    # normal orientation
    raises(ValueError, make_dics, epochs.info, fwd_free, csd,
           pick_ori="normal")

    # Test if volume forward operator is detected when picking normal
    # orientation
    raises(ValueError, make_dics, epochs.info, fwd_vol, csd, pick_ori="normal")

    # Test invalid combinations of parameters
    raises(NotImplementedError, make_dics, epochs.info, fwd_free, csd,
           reduce_rank=True, pick_ori=None)
    raises(NotImplementedError, make_dics, epochs.info, fwd_free, csd,
           reduce_rank=True, pick_ori='max-power', inversion='single')

    # 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 = csd.n_channels

    # Test return values
    filters = make_dics(epochs.info, fwd_surf, csd, label=label, pick_ori=None,
                        weight_norm='unit-noise-gain')
    assert filters['weights'].shape == (n_freq, n_verts * n_orient, n_channels)
    assert np.iscomplexobj(filters['weights'])
    assert filters['csd'] == csd
    assert filters['ch_names'] == csd.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'][0]['subject_his_id']
    assert filters['pick_ori'] is None
    assert filters['n_orient'] == n_orient
    assert filters['inversion'] == 'single'
    assert filters['normalize_fwd']
    assert filters['weight_norm'] == 'unit-noise-gain'
    assert 'DICS' in repr(filters)
    assert 'subject "sample"' in repr(filters)
    assert '13' in repr(filters)
    assert '62' in repr(filters)
    assert 'rank' not in repr(filters)
    _test_weight_norm(filters)

    # Test picking orientations. Also test weight norming under these different
    # conditions.
    filters = make_dics(epochs.info, fwd_surf, csd, label=label,
                        pick_ori='normal', weight_norm='unit-noise-gain')
    n_orient = 1
    assert filters['weights'].shape == (n_freq, n_verts * n_orient, n_channels)
    assert filters['n_orient'] == n_orient
    _test_weight_norm(filters)

    filters = make_dics(epochs.info, fwd_surf, csd, label=label,
                        pick_ori='max-power', weight_norm='unit-noise-gain')
    n_orient = 1
    assert filters['weights'].shape == (n_freq, n_verts * n_orient, n_channels)
    assert filters['n_orient'] == n_orient
    _test_weight_norm(filters)

    # 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)
    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.
    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, normalize_fwd=True)
    w = filters['weights'][0][:3]
    assert_allclose(np.diag(w.dot(w.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, normalize_fwd=False)
    w = filters['weights'][0][:3]
    assert not np.allclose(np.diag(w.dot(w.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,
                            weight_norm='nai', normalize_fwd=False)
    w_nai = filters_nai['weights'][0]
    filters_ung = make_dics(epochs.info, fwd_surf, csd, label=label,
                            weight_norm='unit-noise-gain', normalize_fwd=False)
    w_ung = filters_ung['weights'][0]
    assert np.allclose(np.corrcoef(np.abs(w_nai).ravel(),
                                   np.abs(w_ung).ravel()), 1)

    # 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.float(getattr(filters['csd'], key)))
    assert object_diff(filters, filters_read) == ''
    csd_pos_theta = mne.time_frequency.read_csd("{dir}nc_{meg}-csd_pos_theta.h5".format(dir=meg_dir,meg=meg))
    csd_pos_theta = csd_pos_theta.mean()
    csd_pos_beta_low = mne.time_frequency.read_csd("{dir}nc_{meg}-csd_pos_beta_low.h5".format(dir=meg_dir,meg=meg))
    csd_pos_beta_low = csd_pos_beta_low.mean()
    csd_pos_beta_high = mne.time_frequency.read_csd("{dir}nc_{meg}-csd_pos_beta_high.h5".format(dir=meg_dir,meg=meg))
    csd_pos_beta_high = csd_pos_beta_high.mean()
    csd_pos_gamma = mne.time_frequency.read_csd("{dir}nc_{meg}-csd_pos_gamma.h5".format(dir=meg_dir,meg=meg))
    csd_pos_gamma = csd_pos_gamma.mean()
    # csd_rest_alpha = mne.time_frequency.read_csd("{dir}nc_{meg}-csd_rest_alpha.h5".format(dir=meg_dir,meg=meg))
    # csd_rest_theta = mne.time_frequency.read_csd("{dir}nc_{meg}-csd_rest_theta.h5".format(dir=meg_dir,meg=meg))
    # csd_rest_beta_low = mne.time_frequency.read_csd("{dir}nc_{meg}-csd_rest_beta_low.h5".format(dir=meg_dir,meg=meg))
    # csd_rest_beta_high = mne.time_frequency.read_csd("{dir}nc_{meg}-csd_rest_beta_high.h5".format(dir=meg_dir,meg=meg))
    # csd_rest_gamma = mne.time_frequency.read_csd("{dir}nc_{meg}-csd_rest_gamma.h5".format(dir=meg_dir,meg=meg))

    # make DICS beamformers / filters (common filters) for different freq bands
    filters_exp_alpha = make_dics(epo_exp.info,fwd_exp,csd_exp_alpha,pick_ori='max-power',rank=None,inversion='single',weight_norm=None,normalize_fwd=True,real_filter=False)
    filters_exp_theta = make_dics(epo_exp.info,fwd_exp,csd_exp_theta,pick_ori='max-power',rank=None,inversion='single',weight_norm=None,normalize_fwd=True,real_filter=False)
    filters_exp_beta_low = make_dics(epo_exp.info,fwd_exp,csd_exp_beta_low,pick_ori='max-power',rank=None,inversion='single',weight_norm=None,normalize_fwd=True,real_filter=False)
    filters_exp_beta_high = make_dics(epo_exp.info,fwd_exp,csd_exp_beta_high,pick_ori='max-power',rank=None,inversion='single',weight_norm=None,normalize_fwd=True,real_filter=False)
    filters_exp_gamma = make_dics(epo_exp.info,fwd_exp,csd_exp_gamma,pick_ori='max-power',rank=None,inversion='single',weight_norm=None,normalize_fwd=True,real_filter=False)

    # apply the DICS beamformers to get source Estimates for ton, neg, pos using common filters & save to file
    stc_ton_alpha, freqs_ton_alpha = apply_dics_csd(csd_ton_alpha,filters_exp_alpha)
    stc_ton_theta, freqs_ton_theta = apply_dics_csd(csd_ton_theta,filters_exp_theta)
    stc_ton_beta_low, freqs_ton_beta_low = apply_dics_csd(csd_ton_beta_low,filters_exp_beta_low)
    stc_ton_beta_high, freqs_ton_beta_high = apply_dics_csd(csd_ton_beta_high,filters_exp_beta_high)
    stc_ton_gamma, freqs_ton_gamma = apply_dics_csd(csd_ton_gamma,filters_exp_gamma)
    stc_ton_alpha.save(fname=meg_dir+"nc_{}_stc_ton_alpha".format(meg))
    stc_ton_theta.save(fname=meg_dir+"nc_{}_stc_ton_theta".format(meg))
    stc_ton_beta_low.save(fname=meg_dir+"nc_{}_stc_ton_beta_low".format(meg))
    stc_ton_beta_high.save(fname=meg_dir+"nc_{}_stc_ton_beta_high".format(meg))
Exemple #16
0
csd_ers = csd_morlet(epochs, freqs, tmin=0.5, tmax=1.5, decim=20)
info = epochs.info
del epochs

# %%
# To compute the source power for a frequency band, rather than each frequency
# separately, we average the CSD objects across frequencies.
csd = csd.mean()
csd_baseline = csd_baseline.mean()
csd_ers = csd_ers.mean()

# %%
# Computing DICS spatial filters using the CSD that was computed on the entire
# timecourse.
fwd = mne.read_forward_solution(fname_fwd)
filters = make_dics(info, fwd, csd, noise_csd=csd_baseline,
                    pick_ori='max-power', reduce_rank=True, real_filter=True)
del fwd

# %%
# Applying DICS spatial filters separately to the CSD computed using the
# baseline and the CSD computed during the ERS activity.
baseline_source_power, freqs = apply_dics_csd(csd_baseline, filters)
beta_source_power, freqs = apply_dics_csd(csd_ers, filters)

# %%
# Visualizing source power during ERS activity relative to the baseline power.
stc = beta_source_power / baseline_source_power
message = 'DICS source power in the 12-30 Hz frequency band'
brain = stc.plot(hemi='both', views='axial', subjects_dir=subjects_dir,
                 subject=subject, time_label=message)
Exemple #17
0
def test_apply_dics_timeseries():
    """Test DICS applied to timeseries data."""
    fwd_free, fwd_surf, fwd_fixed, fwd_vol, label = _load_forward()
    epochs, evoked, csd, source_vertno = _simulate_data(fwd_fixed)
    vertices = np.intersect1d(label.vertices, fwd_free['src'][0]['vertno'])
    source_ind = vertices.tolist().index(source_vertno)
    reg = 5  # Lots of regularization for our toy dataset

    multiple_filters = make_dics(evoked.info, fwd_surf, csd, label=label,
                                 reg=reg)

    # Sanity checks on the resulting STC after applying DICS on evoked
    stcs = apply_dics(evoked, multiple_filters)
    assert isinstance(stcs, list)
    assert len(stcs) == len(multiple_filters['weights'])
    assert_array_equal(stcs[0].vertices[0], multiple_filters['vertices'][0])
    assert_array_equal(stcs[0].vertices[1], multiple_filters['vertices'][1])
    assert_allclose(stcs[0].times, evoked.times)

    # Applying filters for multiple frequencies on epoch data should fail
    raises(ValueError, apply_dics_epochs, epochs, multiple_filters)

    # From now on, only apply filters with a single frequency (20 Hz).
    csd20 = csd.pick_frequency(20)
    filters = make_dics(evoked.info, fwd_surf, csd20, label=label, reg=reg)

    # Sanity checks on the resulting STC after applying DICS on epochs.
    # 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:
        stcs = apply_dics_epochs(epochs, filters)
    assert len(w) == 0

    assert isinstance(stcs, list)
    assert len(stcs) == 1
    assert_array_equal(stcs[0].vertices[0], filters['vertices'][0])
    assert_array_equal(stcs[0].vertices[1], filters['vertices'][1])
    assert_allclose(stcs[0].times, epochs.times)

    # Did we find the source?
    stc = (stcs[0] ** 2).mean()
    assert np.argmax(stc.data) == source_ind

    # Apply filters to evoked
    stc = apply_dics(evoked, filters)
    stc = (stc ** 2).mean()
    assert np.argmax(stc.data) == source_ind

    # Test if wrong channel selection is detected in application of filter
    evoked_ch = cp.deepcopy(evoked)
    evoked_ch.pick_channels(evoked_ch.ch_names[:-1])
    raises(ValueError, apply_dics, evoked_ch, filters)

    # Test whether projections are applied, by adding a custom projection
    filters_noproj = make_dics(evoked.info, fwd_surf, csd20, label=label)
    stc_noproj = apply_dics(evoked, filters_noproj)
    evoked_proj = evoked.copy()
    p = compute_proj_evoked(evoked_proj, n_grad=1, n_mag=0, n_eeg=0)
    proj_matrix = make_projector(p, evoked_proj.ch_names)[0]
    evoked_proj.info['projs'] += p
    filters_proj = make_dics(evoked_proj.info, fwd_surf, csd20, label=label)
    assert_array_equal(filters_proj['proj'], proj_matrix)
    stc_proj = apply_dics(evoked_proj, filters_proj)
    assert np.any(np.not_equal(stc_noproj.data, stc_proj.data))

    # Test detecting incompatible projections
    filters_proj['proj'] = filters_proj['proj'][:-1, :-1]
    raises(ValueError, apply_dics, evoked_proj, filters_proj)

    # Test returning a generator
    stcs = apply_dics_epochs(epochs, filters, return_generator=False)
    stcs_gen = apply_dics_epochs(epochs, filters, return_generator=True)
    assert_array_equal(stcs[0].data, advance_iterator(stcs_gen).data)

    # Test computing timecourses on a volume source space
    filters_vol = make_dics(evoked.info, fwd_vol, csd20, reg=reg)
    stc = apply_dics(evoked, filters_vol)
    stc = (stc ** 2).mean()
    assert np.argmax(stc.data) == 3851  # TODO: don't make this hard coded

    # check whether a filters object without src_type throws expected warning
    del filters_vol['src_type']  # emulate 0.16 behaviour to cause warning
    with pytest.warns(RuntimeWarning, match='spatial filter does not contain '
                      'src_type'):
        apply_dics_epochs(epochs, filters_vol)
            info = epochs_grad.info
        elif sensor_type == 'mag':
            info = epochs_mag.info
        elif sensor_type == 'joint':
            info = epochs_joint.info
        else:
            raise ValueError('Invalid sensor type: %s', sensor_type)

        info_eq, fwd_eq, csd_eq = mne.channels.equalize_channels(
            [info, fwd, csd])
        filters = make_dics(info_eq,
                            fwd_eq,
                            csd_eq,
                            reg=reg,
                            pick_ori=pick_ori,
                            inversion=inversion,
                            weight_norm=weight_norm,
                            noise_csd=csd_baseline if use_noise_cov else None,
                            normalize_fwd=normalize_fwd,
                            real_filter=real_filter,
                            reduce_rank=reduce_rank)

        # Compute source power
        stc_baseline, _ = apply_dics_csd(csd_baseline, filters)
        stc_power, _ = apply_dics_csd(csd_ers, filters)

        # Normalize with baseline power.
        stc_power /= stc_baseline
        stc_power.data = np.log(stc_power.data)

        peak_vertex, _ = stc_power.get_peak(vert_as_index=True)
Exemple #19
0
# Rotate the view and add a title.
mlab.view(0, 0, 550, [0, 0, 0])
mlab.title('MNE-dSPM inverse (RMS)', height=0.9)

###############################################################################
# Computing a cortical power map at 10 Hz. using a DICS beamformer:

# Estimate the cross-spectral density (CSD) matrix on the trial containing the
# signal.
csd_signal = csd_morlet(epochs['signal'], frequencies=[10])

# Compute the DICS powermap. For this simulated dataset, we need a lot of
# regularization for the beamformer to behave properly. For real recordings,
# this amount of regularization is probably too much.
filters = make_dics(epochs.info, fwd, csd_signal, reg=1, pick_ori='max-power')
power, f = apply_dics_csd(csd_signal, filters)

# Plot the DICS power map.
brain = power.plot('sample',
                   subjects_dir=subjects_dir,
                   hemi='both',
                   figure=2,
                   size=400)

# Indicate the true locations of the source activity on the plot.
brain.add_foci(source_vert1, coords_as_verts=True, hemi='lh')
brain.add_foci(source_vert2, coords_as_verts=True, hemi='rh')

# Rotate the view and add a title.
mlab.view(0, 0, 550, [0, 0, 0])
Exemple #20
0
def test_tf_dics():
    """Test 5D time-frequency beamforming based on DICS."""
    fwd_free, fwd_surf, fwd_fixed, fwd_vol, label = _load_forward()
    epochs, evoked, _, source_vertno = _simulate_data(fwd_fixed)
    vertices = np.intersect1d(label.vertices, fwd_free['src'][0]['vertno'])
    source_ind = vertices.tolist().index(source_vertno)
    reg = 1  # Lots of regularization for our toy dataset

    tmin = 0
    tmax = 9
    tstep = 4
    win_lengths = [5, 5]
    frequencies = [10, 20]
    freq_bins = [(8, 12), (18, 22)]

    # Compute DICS for two time windows and two frequencies
    for mode in ['fourier', 'multitaper', 'cwt_morlet']:
        stcs = tf_dics(epochs, fwd_surf, None, tmin, tmax, tstep, win_lengths,
                       mode=mode, freq_bins=freq_bins, frequencies=frequencies,
                       decim=10, reg=reg, label=label)

        # Did we find the true source at 20 Hz?
        assert np.argmax(stcs[1].data[:, 0]) == source_ind
        assert np.argmax(stcs[1].data[:, 1]) == source_ind

        # 20 Hz power should decrease over time
        assert stcs[1].data[source_ind, 0] > stcs[1].data[source_ind, 1]

        # 20 Hz power should be more than 10 Hz power at the true source
        assert stcs[1].data[source_ind, 0] > stcs[0].data[source_ind, 0]

    # Manually compute source power and compare with the last tf_dics result.
    source_power = []
    time_windows = [(0, 5), (4, 9)]
    for time_window in time_windows:
        csd = csd_morlet(epochs, frequencies=[frequencies[1]],
                         tmin=time_window[0], tmax=time_window[1], decim=10)
        csd = csd.sum()
        csd._data /= csd.n_fft
        filters = make_dics(epochs.info, fwd_surf, csd, reg=reg, label=label)
        stc_source_power, _ = apply_dics_csd(csd, filters)
        source_power.append(stc_source_power.data)

    # Comparing tf_dics results with dics_source_power results
    assert_allclose(stcs[1].data, np.array(source_power).squeeze().T, atol=0)

    # Test using noise csds. We're going to use identity matrices. That way,
    # since we're using unit-noise-gain weight normalization, there should be
    # no effect.
    stcs = tf_dics(epochs, fwd_surf, None, tmin, tmax, tstep, win_lengths,
                   mode='cwt_morlet', frequencies=frequencies, decim=10,
                   reg=reg, label=label, normalize_fwd=False,
                   weight_norm='unit-noise-gain')
    noise_csd = csd.copy()
    inds = np.triu_indices(csd.n_channels)
    # Using [:, :] syntax for in-place broadcasting
    noise_csd._data[:, :] = 2 * np.eye(csd.n_channels)[inds][:, np.newaxis]
    noise_csd.n_fft = 2  # Dividing by n_fft should yield an identity CSD
    noise_csds = [noise_csd, noise_csd]  # Two frequency bins
    stcs_norm = tf_dics(epochs, fwd_surf, noise_csds, tmin, tmax, tstep,
                        win_lengths, mode='cwt_morlet',
                        frequencies=frequencies, decim=10, reg=reg,
                        label=label, normalize_fwd=False,
                        weight_norm='unit-noise-gain')
    assert_allclose(stcs_norm[0].data, stcs[0].data, atol=0)
    assert_allclose(stcs_norm[1].data, stcs[1].data, atol=0)

    # Test invalid parameter combinations
    raises(ValueError, tf_dics, epochs, fwd_surf, None, tmin, tmax, tstep,
           win_lengths, mode='fourier', freq_bins=None)
    raises(ValueError, tf_dics, epochs, fwd_surf, None, tmin, tmax, tstep,
           win_lengths, mode='cwt_morlet', frequencies=None)

    # Test if incorrect number of noise CSDs is detected
    raises(ValueError, tf_dics, epochs, fwd_surf, [noise_csds[0]], tmin, tmax,
           tstep, win_lengths, freq_bins=freq_bins)

    # Test if freq_bins and win_lengths incompatibility is detected
    raises(ValueError, tf_dics, epochs, fwd_surf, None, tmin, tmax, tstep,
           win_lengths=[0, 1, 2], freq_bins=freq_bins)

    # Test if time step exceeding window lengths is detected
    raises(ValueError, tf_dics, epochs, fwd_surf, None, tmin, tmax, tstep=0.15,
           win_lengths=[0.2, 0.1], freq_bins=freq_bins)

    # Test if incorrent number of n_ffts is detected
    raises(ValueError, tf_dics, epochs, fwd_surf, None, tmin, tmax, tstep,
           win_lengths, freq_bins=freq_bins, n_ffts=[1])

    # Test if incorrect number of mt_bandwidths is detected
    raises(ValueError, tf_dics, epochs, fwd_surf, None, tmin, tmax, tstep,
           win_lengths=win_lengths, freq_bins=freq_bins, mode='multitaper',
           mt_bandwidths=[20])

    # Test if subtracting evoked responses yields NaN's, since we only have one
    # epoch. Suppress division warnings.
    with pytest.warns(RuntimeWarning, match='[invalid|empty]'):
        stcs = tf_dics(epochs, fwd_surf, None, tmin, tmax, tstep, win_lengths,
                       mode='cwt_morlet', frequencies=frequencies,
                       subtract_evoked=True, reg=reg, label=label, decim=20)
    assert np.all(np.isnan(stcs[0].data))
Exemple #21
0
#
#  1. The approach as described in :footcite:`vanVlietEtAl2018`, which first
#     normalizes the forward solution and computes a vector beamformer.
#  2. The scalar beamforming approach based on
#     :footcite:`SekiharaNagarajan2008`, which uses weight normalization
#     instead of normalizing the forward solution.

# Estimate the cross-spectral density (CSD) matrix on the trial containing the
# signal.
csd_signal = csd_morlet(epochs['signal'], frequencies=[10])

# Compute the spatial filters for each vertex, using two approaches.
filters_approach1 = make_dics(info,
                              fwd,
                              csd_signal,
                              reg=0.05,
                              pick_ori='max-power',
                              depth=1.,
                              inversion='single',
                              weight_norm=None)
print(filters_approach1)

filters_approach2 = make_dics(info,
                              fwd,
                              csd_signal,
                              reg=0.05,
                              pick_ori='max-power',
                              depth=None,
                              inversion='matrix',
                              weight_norm='unit-noise-gain')
print(filters_approach2)
Exemple #22
0
            x.info["dev_head_t"] = epos[0].info["dev_head_t"]
        epo = mne.concatenate_epochs(epos)
        csd = csd_morlet(epo,
                         frequencies=freqs,
                         n_jobs=n_jobs,
                         n_cycles=c,
                         decim=3)
        #csd = csd.mean()
        fwd_name = "{dir}nc_{sub}_{sp}-fwd.fif".format(dir=proc_dir,
                                                       sub=sub,
                                                       sp=spacing)
        fwd = mne.read_forward_solution(fwd_name)
        filters = make_dics(epo.info,
                            fwd,
                            csd,
                            real_filter=True,
                            weight_norm="nai",
                            reduce_rank=False,
                            pick_ori="max-power")
        del epo, csd, fwd

        print("\n\n")
        print("\n\n")
        # if not doTones:
        #     epos = epo_conds
        #     epo_names = epo_cond_names
        # for epo,epo_name in zip(epos,epo_names):
        #     epo_csd = csd_morlet(epo, frequencies=freqs,
        #                          n_jobs=n_jobs, n_cycles=c, decim=3)
        #     #epo_csd = epo_csd.mean()
        #     stc, freqs = apply_dics_csd(epo_csd,filters)
Exemple #23
0
for setting in settings:
    (reg, sensor_type, pick_ori, inversion, weight_norm, normalize_fwd,
     real_filter) = setting
    try:
        if sensor_type == 'grad':
            info = epochs_grad.info
        elif sensor_type == 'mag':
            info = epochs_mag.info
        else:
            raise ValueError('Invalid sensor type: %s', sensor_type)

        filters = make_dics(info,
                            fwd,
                            csd,
                            reg=reg,
                            pick_ori=pick_ori,
                            inversion=inversion,
                            weight_norm=weight_norm,
                            normalize_fwd=normalize_fwd,
                            real_filter=real_filter)
        stc, freqs = apply_dics_csd(csd, filters)

        # Compute distance between true and estimated source
        dip_true = make_dipole(stc_signal, fwd['src'])
        dip_est = make_dipole(stc, fwd['src'])
        dist = np.linalg.norm(dip_true.pos - dip_est.pos)

        # Fancy evaluation metric
        ev = evaluate_stc(stc, stc_signal)
    except Exception as e:
        print(e)
        try:
            if sensor_type == 'grad':
                info = epochs_grad.info
            elif sensor_type == 'mag':
                info = epochs_mag.info
            elif sensor_type == 'joint':
                info = epochs_joint.info
            else:
                raise ValueError('Invalid sensor type: %s', sensor_type)

            filters = make_dics(info,
                                fwd,
                                csd,
                                reg=reg,
                                pick_ori=pick_ori,
                                inversion=inversion,
                                weight_norm=weight_norm,
                                noise_csd=noise_csd if use_noise_cov else None,
                                normalize_fwd=normalize_fwd,
                                reduce_rank=reduce_rank,
                                real_filter=real_filter)

            stc, freqs = apply_dics_csd(csd, filters)

            vert1_idx = np.searchsorted(src_sel, config.vertex)
            vert2_idx = np.searchsorted(src_sel, nb_vertex)
            ratio1 = stc.data[vert1_idx, 1] / stc.data[vert1_idx, 0]
            ratio2 = stc.data[vert2_idx, 0] / stc.data[vert2_idx, 1]
            ratio = np.sqrt(ratio1 * ratio2)
            corrs.append(list(setting) + [nb_vertex, nb_dist, ratio])
# Set picks
picks = mne.pick_types(raw.info, meg=True, eeg=False, eog=False,
                       stim=False, exclude='bads')

# Read epochs
event_id, tmin, tmax = 1, -0.2, 0.5
events = mne.read_events(event_fname)
epochs = mne.Epochs(raw, events, event_id, tmin, tmax, proj=True,
                    picks=picks, baseline=(None, 0), preload=True,
                    reject=dict(grad=4000e-13, mag=4e-12))
evoked = epochs.average()

# Read forward operator
forward = mne.read_forward_solution(fname_fwd)

###############################################################################
# Computing the cross-spectral density matrix at 4 evenly spaced frequencies
# from 6 to 10 Hz. We use a decim value of 20 to speed up the computation in
# this example at the loss of accuracy.
csd = csd_morlet(epochs, tmin=0, tmax=0.5, decim=20,
                 frequencies=np.linspace(6, 10, 4))

# Compute DICS spatial filter and estimate source power.
filters = make_dics(epochs.info, forward, csd, reg=0.5)
stc, freqs = apply_dics_csd(csd, filters)

message = 'DICS source power in the 8-12 Hz frequency band'
brain = stc.plot(surface='inflated', hemi='rh', subjects_dir=subjects_dir,
                 time_label=message)
Exemple #26
0
def test_tf_dics(_load_forward, idx, mat_tol, vol_tol):
    """Test 5D time-frequency beamforming based on DICS."""
    fwd_free, fwd_surf, fwd_fixed, _ = _load_forward
    epochs, _, _, source_vertno, label, vertices, source_ind = \
        _simulate_data(fwd_fixed, idx)
    reg = 1  # Lots of regularization for our toy dataset

    tmin = 0
    tmax = 9
    tstep = 4
    win_lengths = [5, 5]
    frequencies = [10, 20]
    freq_bins = [(8, 12), (18, 22)]

    with pytest.raises(RuntimeError, match='several sensor types'):
        stcs = tf_dics(epochs,
                       fwd_surf,
                       None,
                       tmin,
                       tmax,
                       tstep,
                       win_lengths,
                       freq_bins=freq_bins,
                       frequencies=frequencies,
                       decim=10,
                       reg=reg,
                       label=label)
    epochs.pick_types(meg='grad')
    # Compute DICS for two time windows and two frequencies
    for mode in ['fourier', 'multitaper', 'cwt_morlet']:
        stcs = tf_dics(epochs,
                       fwd_surf,
                       None,
                       tmin,
                       tmax,
                       tstep,
                       win_lengths,
                       mode=mode,
                       freq_bins=freq_bins,
                       frequencies=frequencies,
                       decim=10,
                       reg=reg,
                       label=label)

        # Did we find the true source at 20 Hz?
        dist = _fwd_dist(stcs[1], fwd_surf, vertices, source_ind, tidx=0)
        assert dist == 0
        dist = _fwd_dist(stcs[1], fwd_surf, vertices, source_ind, tidx=1)
        assert dist == 0

        # 20 Hz power should decrease over time
        assert stcs[1].data[source_ind, 0] > stcs[1].data[source_ind, 1]

        # 20 Hz power should be more than 10 Hz power at the true source
        assert stcs[1].data[source_ind, 0] > stcs[0].data[source_ind, 0]

    # Manually compute source power and compare with the last tf_dics result.
    source_power = []
    time_windows = [(0, 5), (4, 9)]
    for time_window in time_windows:
        csd = csd_morlet(epochs,
                         frequencies=[frequencies[1]],
                         tmin=time_window[0],
                         tmax=time_window[1],
                         decim=10)
        csd = csd.sum()
        csd._data /= csd.n_fft
        filters = make_dics(epochs.info, fwd_surf, csd, reg=reg, label=label)
        stc_source_power, _ = apply_dics_csd(csd, filters)
        source_power.append(stc_source_power.data)

    # Comparing tf_dics results with dics_source_power results
    assert_allclose(stcs[1].data, np.array(source_power).squeeze().T, atol=0)

    # Test using noise csds. We're going to use identity matrices. That way,
    # since we're using unit-noise-gain weight normalization, there should be
    # no effect.
    stcs = tf_dics(epochs,
                   fwd_surf,
                   None,
                   tmin,
                   tmax,
                   tstep,
                   win_lengths,
                   mode='cwt_morlet',
                   frequencies=frequencies,
                   decim=10,
                   reg=reg,
                   label=label,
                   normalize_fwd=False,
                   weight_norm='unit-noise-gain')
    noise_csd = csd.copy()
    inds = np.triu_indices(csd.n_channels)
    # Using [:, :] syntax for in-place broadcasting
    noise_csd._data[:, :] = 2 * np.eye(csd.n_channels)[inds][:, np.newaxis]
    noise_csd.n_fft = 2  # Dividing by n_fft should yield an identity CSD
    noise_csds = [noise_csd, noise_csd]  # Two frequency bins
    stcs_norm = tf_dics(epochs,
                        fwd_surf,
                        noise_csds,
                        tmin,
                        tmax,
                        tstep,
                        win_lengths,
                        mode='cwt_morlet',
                        frequencies=frequencies,
                        decim=10,
                        reg=reg,
                        label=label,
                        normalize_fwd=False,
                        weight_norm='unit-noise-gain')
    assert_allclose(stcs_norm[0].data, stcs[0].data, atol=0)
    assert_allclose(stcs_norm[1].data, stcs[1].data, atol=0)

    # Test invalid parameter combinations
    with pytest.raises(ValueError, match='fourier.*freq_bins" parameter'):
        tf_dics(epochs,
                fwd_surf,
                None,
                tmin,
                tmax,
                tstep,
                win_lengths,
                mode='fourier',
                freq_bins=None)
    with pytest.raises(ValueError, match='cwt_morlet.*frequencies" param'):
        tf_dics(epochs,
                fwd_surf,
                None,
                tmin,
                tmax,
                tstep,
                win_lengths,
                mode='cwt_morlet',
                frequencies=None)

    # Test if incorrect number of noise CSDs is detected
    with pytest.raises(ValueError, match='One noise CSD object expected per'):
        tf_dics(epochs,
                fwd_surf, [noise_csds[0]],
                tmin,
                tmax,
                tstep,
                win_lengths,
                freq_bins=freq_bins)

    # Test if freq_bins and win_lengths incompatibility is detected
    with pytest.raises(ValueError, match='One time window length expected'):
        tf_dics(epochs,
                fwd_surf,
                None,
                tmin,
                tmax,
                tstep,
                win_lengths=[0, 1, 2],
                freq_bins=freq_bins)

    # Test if time step exceeding window lengths is detected
    with pytest.raises(ValueError, match='Time step should not be larger'):
        tf_dics(epochs,
                fwd_surf,
                None,
                tmin,
                tmax,
                tstep=0.15,
                win_lengths=[0.2, 0.1],
                freq_bins=freq_bins)

    # Test if incorrect number of n_ffts is detected
    with pytest.raises(ValueError, match='When specifying number of FFT'):
        tf_dics(epochs,
                fwd_surf,
                None,
                tmin,
                tmax,
                tstep,
                win_lengths,
                freq_bins=freq_bins,
                n_ffts=[1])

    # Test if incorrect number of mt_bandwidths is detected
    with pytest.raises(ValueError, match='When using multitaper mode and'):
        tf_dics(epochs,
                fwd_surf,
                None,
                tmin,
                tmax,
                tstep,
                win_lengths=win_lengths,
                freq_bins=freq_bins,
                mode='multitaper',
                mt_bandwidths=[20])

    # Test if subtracting evoked responses yields NaN's, since we only have one
    # epoch. Suppress division warnings.
    assert len(epochs) == 1, len(epochs)
    with np.errstate(invalid='ignore'):
        stcs = tf_dics(epochs,
                       fwd_surf,
                       None,
                       tmin,
                       tmax,
                       tstep,
                       win_lengths,
                       mode='cwt_morlet',
                       frequencies=frequencies,
                       subtract_evoked=True,
                       reg=reg,
                       label=label,
                       decim=20)
    assert np.all(np.isnan(stcs[0].data))
Exemple #27
0
# approaches here:
#
#  1. The approach as described in [2]_, which first normalizes the forward
#     solution and computes a vector beamformer.
#  2. The scalar beamforming approach based on [3]_, which uses weight
#     normalization instead of normalizing the forward solution.

# Estimate the cross-spectral density (CSD) matrix on the trial containing the
# signal.
csd_signal = csd_morlet(epochs['signal'], frequencies=[10])

# Compute the spatial filters for each vertex, using two approaches.
filters_approach1 = make_dics(info,
                              fwd,
                              csd_signal,
                              reg=0.05,
                              pick_ori='max-power',
                              normalize_fwd=True,
                              inversion='single',
                              weight_norm=None)
print(filters_approach1)

filters_approach2 = make_dics(info,
                              fwd,
                              csd_signal,
                              reg=0.1,
                              pick_ori='max-power',
                              normalize_fwd=False,
                              inversion='matrix',
                              weight_norm='unit-noise-gain')
print(filters_approach2)
event_id, tmin, tmax = 1, -0.2, 0.5
events = mne.read_events(event_fname)
epochs = mne.Epochs(raw, events, event_id, tmin, tmax, proj=True,
                    picks=picks, baseline=(None, 0), preload=True,
                    reject=dict(grad=4000e-13, mag=4e-12))
evoked = epochs.average()

# Read forward operator
forward = mne.read_forward_solution(fname_fwd)

###############################################################################
# Computing the cross-spectral density matrix at 4 evenly spaced frequencies
# from 6 to 10 Hz. We use a decim value of 20 to speed up the computation in
# this example at the loss of accuracy.
#
# .. warning:: The use of several sensor types with the DICS beamformer is
#              not heavily tested yet. Here we use verbose='error' to
#              suppress a warning along these lines.
csd = csd_morlet(epochs, tmin=0, tmax=0.5, decim=20,
                 frequencies=np.linspace(6, 10, 4),
                 n_cycles=2.5)  # short signals, must live with few cycles

# Compute DICS spatial filter and estimate source power.
filters = make_dics(epochs.info, forward, csd, reg=0.5, verbose='error')
print(filters)
stc, freqs = apply_dics_csd(csd, filters)

message = 'DICS source power in the 8-12 Hz frequency band'
brain = stc.plot(surface='inflated', hemi='rh', subjects_dir=subjects_dir,
                 time_label=message)
Exemple #29
0
def test_make_dics():
    """Test making DICS beamformer filters."""
    # We only test proper handling of parameters here. Testing the results is
    # done in apply_dics_timeseries and apply_dics_csd.

    fwd_free, fwd_surf, fwd_fixed, fwd_vol, label = _load_forward()
    epochs, _, csd, _ = _simulate_data(fwd_fixed)

    raises(ValueError, make_dics, epochs.info, fwd_fixed, csd,
           pick_ori="notexistent")

    # Test if fixed forward operator is detected when picking normal
    # orientation
    raises(ValueError, make_dics, epochs.info, fwd_fixed, csd,
           pick_ori="normal")

    # Test if non-surface oriented forward operator is detected when picking
    # normal orientation
    raises(ValueError, make_dics, epochs.info, fwd_free, csd,
           pick_ori="normal")

    # Test if volume forward operator is detected when picking normal
    # orientation
    raises(ValueError, make_dics, epochs.info, fwd_vol, csd, pick_ori="normal")

    # Test invalid combinations of parameters
    raises(NotImplementedError, make_dics, epochs.info, fwd_free, csd,
           reduce_rank=True, pick_ori=None)
    raises(NotImplementedError, make_dics, epochs.info, fwd_free, csd,
           reduce_rank=True, pick_ori='max-power', inversion='single')

    # 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 = csd.n_channels

    # Test return values
    filters = make_dics(epochs.info, fwd_surf, csd, label=label, pick_ori=None,
                        weight_norm='unit-noise-gain')
    assert filters['weights'].shape == (n_freq, n_verts * n_orient, n_channels)
    assert np.iscomplexobj(filters['weights'])
    assert filters['csd'] == csd
    assert filters['ch_names'] == csd.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'][0]['subject_his_id']
    assert filters['pick_ori'] is None
    assert filters['n_orient'] == n_orient
    assert filters['inversion'] == 'single'
    assert filters['normalize_fwd']
    assert filters['weight_norm'] == 'unit-noise-gain'
    _test_weight_norm(filters)

    # Test picking orientations. Also test weight norming under these different
    # conditions.
    filters = make_dics(epochs.info, fwd_surf, csd, label=label,
                        pick_ori='normal', weight_norm='unit-noise-gain')
    n_orient = 1
    assert filters['weights'].shape == (n_freq, n_verts * n_orient, n_channels)
    assert filters['n_orient'] == n_orient
    _test_weight_norm(filters)

    filters = make_dics(epochs.info, fwd_surf, csd, label=label,
                        pick_ori='max-power', weight_norm='unit-noise-gain')
    n_orient = 1
    assert filters['weights'].shape == (n_freq, n_verts * n_orient, n_channels)
    assert filters['n_orient'] == n_orient
    _test_weight_norm(filters)

    # Test using a real-valued filter
    filters = make_dics(epochs.info, fwd_surf, csd, label=label,
                        pick_ori='normal', real_filter=True)
    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.
    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, normalize_fwd=True)
    w = filters['weights'][0][:3]
    assert_allclose(np.diag(w.dot(w.T)), 1.0, rtol=1e-6, atol=0)

    # Test turning off both forward and weight normalization
    filters = make_dics(epochs.info, fwd_surf, csd_noise, label=label,
                        weight_norm=None, normalize_fwd=False)
    w = filters['weights'][0][:3]
    assert not np.allclose(np.diag(w.dot(w.T)), 1.0, rtol=1e-2, atol=0)

    # Test whether spatial filter contains src_type
    assert 'src_type' in filters
Exemple #30
0
def test_make_dics():
    """Test making DICS beamformer filters."""
    # We only test proper handling of parameters here. Testing the results is
    # done in apply_dics_timeseries and apply_dics_csd.

    fwd_free, fwd_surf, fwd_fixed, fwd_vol, label = _load_forward()
    epochs, _, csd, _ = _simulate_data(fwd_fixed)

    raises(ValueError, make_dics, epochs.info, fwd_fixed, csd,
           pick_ori="notexistent")

    # Test if fixed forward operator is detected when picking normal
    # orientation
    raises(ValueError, make_dics, epochs.info, fwd_fixed, csd,
           pick_ori="normal")

    # Test if non-surface oriented forward operator is detected when picking
    # normal orientation
    raises(ValueError, make_dics, epochs.info, fwd_free, csd,
           pick_ori="normal")

    # Test if volume forward operator is detected when picking normal
    # orientation
    raises(ValueError, make_dics, epochs.info, fwd_vol, csd, pick_ori="normal")

    # Test invalid combinations of parameters
    raises(NotImplementedError, make_dics, epochs.info, fwd_free, csd,
           reduce_rank=True, pick_ori=None)
    raises(NotImplementedError, make_dics, epochs.info, fwd_free, csd,
           reduce_rank=True, pick_ori='max-power', inversion='single')

    # 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 = csd.n_channels

    # Test return values
    filters = make_dics(epochs.info, fwd_surf, csd, label=label, pick_ori=None,
                        weight_norm='unit-noise-gain')
    assert filters['weights'].shape == (n_freq, n_verts * n_orient, n_channels)
    assert np.iscomplexobj(filters['weights'])
    assert filters['csd'] == csd
    assert filters['ch_names'] == csd.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'][0]['subject_his_id']
    assert filters['pick_ori'] is None
    assert filters['n_orient'] == n_orient
    assert filters['inversion'] == 'single'
    assert filters['normalize_fwd']
    assert filters['weight_norm'] == 'unit-noise-gain'
    _test_weight_norm(filters)

    # Test picking orientations. Also test weight norming under these different
    # conditions.
    filters = make_dics(epochs.info, fwd_surf, csd, label=label,
                        pick_ori='normal', weight_norm='unit-noise-gain')
    n_orient = 1
    assert filters['weights'].shape == (n_freq, n_verts * n_orient, n_channels)
    assert filters['n_orient'] == n_orient
    _test_weight_norm(filters)

    filters = make_dics(epochs.info, fwd_surf, csd, label=label,
                        pick_ori='max-power', weight_norm='unit-noise-gain')
    n_orient = 1
    assert filters['weights'].shape == (n_freq, n_verts * n_orient, n_channels)
    assert filters['n_orient'] == n_orient
    _test_weight_norm(filters)

    # Test using a real-valued filter
    filters = make_dics(epochs.info, fwd_surf, csd, label=label,
                        pick_ori='normal', real_filter=True)
    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.
    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, normalize_fwd=True)
    w = filters['weights'][0][:3]
    assert_allclose(np.diag(w.dot(w.T)), 1.0, rtol=1e-6, atol=0)

    # Test turning off both forward and weight normalization
    filters = make_dics(epochs.info, fwd_surf, csd_noise, label=label,
                        weight_norm=None, normalize_fwd=False)
    w = filters['weights'][0][:3]
    assert not np.allclose(np.diag(w.dot(w.T)), 1.0, rtol=1e-2, atol=0)
Exemple #31
0
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:
        noise_csd, rank = _make_rand_csd(epochs.info, csd)
        assert rank == len(epochs.info['ch_names']) == 62
    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, real_filter=False,
                        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) == ''
# log scale, from 12 to 30 Hz.
freqs = np.logspace(np.log10(12), np.log10(30), 9)

###############################################################################
# Computing the cross-spectral density matrix for the beta frequency band, for
# different time intervals. We use a decim value of 20 to speed up the
# computation in this example at the loss of accuracy.
csd = csd_morlet(epochs, freqs, tmin=-1, tmax=1.5, decim=20)
csd_baseline = csd_morlet(epochs, freqs, tmin=-1, tmax=0, decim=20)
# ERS activity starts at 0.5 seconds after stimulus onset
csd_ers = csd_morlet(epochs, freqs, tmin=0.5, tmax=1.5, decim=20)

###############################################################################
# Computing DICS spatial filters using the CSD that was computed on the entire
# timecourse.
filters = make_dics(epochs.info, fwd, csd.mean(), pick_ori='max-power')

###############################################################################
# Applying DICS spatial filters separately to the CSD computed using the
# baseline and the CSD computed during the ERS activity.
baseline_source_power, freqs = apply_dics_csd(csd_baseline.mean(), filters)
beta_source_power, freqs = apply_dics_csd(csd_ers.mean(), filters)

###############################################################################
# Visualizing source power during ERS activity relative to the baseline power.
stc = beta_source_power / baseline_source_power
message = 'DICS source power in the 12-30 Hz frequency band'
brain = stc.plot(hemi='both',
                 views='par',
                 subjects_dir=subjects_dir,
                 subject=subject,
Exemple #33
0
def test_apply_dics_timeseries(_load_forward, idx):
    """Test DICS applied to timeseries data."""
    fwd_free, fwd_surf, fwd_fixed, fwd_vol = _load_forward
    epochs, evoked, csd, source_vertno, label, vertices, source_ind = \
        _simulate_data(fwd_fixed, idx)
    reg = 5  # Lots of regularization for our toy dataset

    with pytest.raises(ValueError, match='several sensor types'):
        make_dics(evoked.info, fwd_surf, csd)
    evoked.pick_types(meg='grad')

    multiple_filters = make_dics(evoked.info, fwd_surf, csd, label=label,
                                 reg=reg)

    # Sanity checks on the resulting STC after applying DICS on evoked
    stcs = apply_dics(evoked, multiple_filters)
    assert isinstance(stcs, list)
    assert len(stcs) == len(multiple_filters['weights'])
    assert_array_equal(stcs[0].vertices[0], multiple_filters['vertices'][0])
    assert_array_equal(stcs[0].vertices[1], multiple_filters['vertices'][1])
    assert_allclose(stcs[0].times, evoked.times)

    # Applying filters for multiple frequencies on epoch data should fail
    with pytest.raises(ValueError, match='computed for a single frequency'):
        apply_dics_epochs(epochs, multiple_filters)

    # From now on, only apply filters with a single frequency (20 Hz).
    csd20 = csd.pick_frequency(20)
    filters = make_dics(evoked.info, fwd_surf, csd20, label=label, reg=reg,
                        inversion='single')

    # Sanity checks on the resulting STC after applying DICS on epochs.
    # 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:
        stcs = apply_dics_epochs(epochs, filters)
    assert len(w) == 0

    assert isinstance(stcs, list)
    assert len(stcs) == 1
    assert_array_equal(stcs[0].vertices[0], filters['vertices'][0])
    assert_array_equal(stcs[0].vertices[1], filters['vertices'][1])
    assert_allclose(stcs[0].times, epochs.times)

    # Did we find the source?
    stc = (stcs[0] ** 2).mean()
    dist = _fwd_dist(stc, fwd_surf, vertices, source_ind, tidx=0)
    assert dist == 0

    # Apply filters to evoked
    stc = apply_dics(evoked, filters)
    stc = (stc ** 2).mean()
    dist = _fwd_dist(stc, fwd_surf, vertices, source_ind, tidx=0)
    assert dist == 0

    # Test if wrong channel selection is detected in application of filter
    evoked_ch = cp.deepcopy(evoked)
    evoked_ch.pick_channels(evoked_ch.ch_names[:-1])
    with pytest.raises(ValueError, match='MEG 2633 which is not present'):
        apply_dics(evoked_ch, filters)

    # Test whether projections are applied, by adding a custom projection
    filters_noproj = make_dics(evoked.info, fwd_surf, csd20, label=label)
    stc_noproj = apply_dics(evoked, filters_noproj)
    evoked_proj = evoked.copy()
    p = compute_proj_evoked(evoked_proj, n_grad=1, n_mag=0, n_eeg=0)
    proj_matrix = make_projector(p, evoked_proj.ch_names)[0]
    evoked_proj.info['projs'] += p
    filters_proj = make_dics(evoked_proj.info, fwd_surf, csd20, label=label)
    assert_array_equal(filters_proj['proj'], proj_matrix)
    stc_proj = apply_dics(evoked_proj, filters_proj)
    assert np.any(np.not_equal(stc_noproj.data, stc_proj.data))

    # Test detecting incompatible projections
    filters_proj['proj'] = filters_proj['proj'][:-1, :-1]
    with pytest.raises(ValueError, match='operands could not be broadcast'):
        apply_dics(evoked_proj, filters_proj)

    # Test returning a generator
    stcs = apply_dics_epochs(epochs, filters, return_generator=False)
    stcs_gen = apply_dics_epochs(epochs, filters, return_generator=True)
    assert_array_equal(stcs[0].data, next(stcs_gen).data)

    # Test computing timecourses on a volume source space
    filters_vol = make_dics(evoked.info, fwd_vol, csd20, reg=reg,
                            inversion='single')
    stc = apply_dics(evoked, filters_vol)
    stc = (stc ** 2).mean()
    assert stc.data.shape[1] == 1
    vol_source_ind = _nearest_vol_ind(fwd_vol, fwd_surf, vertices, source_ind)
    dist = _fwd_dist(stc, fwd_vol, fwd_vol['src'][0]['vertno'], vol_source_ind,
                     tidx=0)
    vol_tols = {100: 0.008, 200: 0.015}
    vol_tol = vol_tols.get(idx, 0.)
    assert dist <= vol_tol

    # check whether a filters object without src_type throws expected warning
    del filters_vol['src_type']  # emulate 0.16 behaviour to cause warning
    with pytest.warns(RuntimeWarning, match='filter does not contain src_typ'):
        apply_dics_epochs(epochs, filters_vol)
Exemple #34
0
# over the way the filter weights are computed. Currently, there is no clear
# consensus regarding the best approach. This is why we will demonstrate two
# approaches here:
#
#  1. The approach as described in [2]_, which first normalizes the forward
#     solution and computes a vector beamformer.
#  2. The scalar beamforming approach based on [3]_, which uses weight
#     normalization instead of normalizing the forward solution.

# Estimate the cross-spectral density (CSD) matrix on the trial containing the
# signal.
csd_signal = csd_morlet(epochs['signal'], frequencies=[10])

# Compute the spatial filters for each vertex, using two approaches.
filters_approach1 = make_dics(
    info, fwd, csd_signal, reg=0.05, pick_ori='max-power', normalize_fwd=True,
    inversion='single', weight_norm=None)
filters_approach2 = make_dics(
    info, fwd, csd_signal, reg=0.05, pick_ori='max-power', normalize_fwd=False,
    inversion='matrix', weight_norm='unit-noise-gain')

# Compute the DICS power map by applying the spatial filters to the CSD matrix.
power_approach1, f = apply_dics_csd(csd_signal, filters_approach1)
power_approach2, f = apply_dics_csd(csd_signal, filters_approach2)

# Plot the DICS power maps for both approaches.
for approach, power in enumerate([power_approach1, power_approach2], 1):
    brain = power.plot('sample', subjects_dir=subjects_dir, hemi='both',
                       figure=approach + 1, size=600)

    # Indicate the true locations of the source activity on the plot.
Exemple #35
0
def test_apply_dics_csd():
    """Test applying a DICS beamformer to a CSD matrix."""
    fwd_free, fwd_surf, fwd_fixed, fwd_vol, label = _load_forward()
    epochs, _, csd, source_vertno = _simulate_data(fwd_fixed)
    vertices = np.intersect1d(label.vertices, fwd_free['src'][0]['vertno'])
    source_ind = vertices.tolist().index(source_vertno)
    reg = 1  # Lots of regularization for our toy dataset

    # Construct an identity "noise" CSD, which we will use to test the
    # 'unit-noise-gain' setting.
    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]

    # Try different types of forward models
    for fwd in [fwd_free, fwd_surf, fwd_fixed]:
        filters = make_dics(epochs.info, fwd, csd, label=label, reg=reg,
                            inversion='single')
        power, f = apply_dics_csd(csd, filters)
        assert f == [10, 20]

        # Did we find the true source at 20 Hz?
        assert np.argmax(power.data[:, 1]) == source_ind

        # Is the signal stronger at 20 Hz than 10?
        assert power.data[source_ind, 1] > power.data[source_ind, 0]

    # Try picking different orientations and inversion modes
    for pick_ori in [None, 'normal', 'max-power']:
        for inversion in ['single', 'matrix']:
            # Matrix inversion mode needs more regularization for this toy
            # dataset.
            if inversion == 'matrix':
                reg_ = 5
            else:
                reg_ = reg

            filters = make_dics(epochs.info, fwd_surf, csd, label=label,
                                reg=reg_, pick_ori=pick_ori,
                                inversion=inversion,
                                weight_norm='unit-noise-gain')
            power, f = apply_dics_csd(csd, filters)
            assert f == [10, 20]
            assert np.argmax(power.data[:, 1]) == source_ind
            assert power.data[source_ind, 1] > power.data[source_ind, 0]

            # Test unit-noise-gain weighting
            noise_power, f = apply_dics_csd(csd_noise, filters)
            assert np.allclose(noise_power.data, 1)

            # Test filter with forward normalization instead of weight
            # normalization
            filters = make_dics(epochs.info, fwd_surf, csd, label=label,
                                reg=reg_, pick_ori=pick_ori,
                                inversion=inversion, weight_norm=None,
                                normalize_fwd=True)
            power, f = apply_dics_csd(csd, filters)
            assert f == [10, 20]
            assert np.argmax(power.data[:, 1]) == source_ind
            assert power.data[source_ind, 1] > power.data[source_ind, 0]

    # Test using a real-valued filter
    filters_real = make_dics(epochs.info, fwd_surf, csd, label=label, reg=reg,
                             real_filter=True)
    # Also test here that no warings are thrown - implemented to check whether
    # src should not be None warning occurs:
    with pytest.warns(None) as w:
        power, f = apply_dics_csd(csd, filters_real)
    assert len(w) == 0

    assert f == [10, 20]
    assert np.argmax(power.data[:, 1]) == source_ind
    assert power.data[source_ind, 1] > power.data[source_ind, 0]

    # Test rank reduction
    filters_real = make_dics(epochs.info, fwd_surf, csd, label=label, reg=5,
                             pick_ori='max-power', inversion='matrix',
                             reduce_rank=True)
    power, f = apply_dics_csd(csd, filters_real)
    assert f == [10, 20]
    assert np.argmax(power.data[:, 1]) == source_ind
    assert power.data[source_ind, 1] > power.data[source_ind, 0]

    # Test computing source power on a volume source space
    filters_vol = make_dics(epochs.info, fwd_vol, csd, reg=reg)
    power, f = apply_dics_csd(csd, filters_vol)
    vol_source_ind = 3851  # FIXME: not make this hardcoded
    assert f == [10, 20]
    assert np.argmax(power.data[:, 1]) == vol_source_ind
    assert power.data[vol_source_ind, 1] > power.data[vol_source_ind, 0]

    # check whether a filters object without src_type throws expected warning
    del filters_vol['src_type']  # emulate 0.16 behaviour to cause warning
    with pytest.warns(RuntimeWarning, match='spatial filter does not contain '
                      'src_type'):
        apply_dics_csd(csd, filters_vol)
Exemple #36
0
# ERS activity starts at 0.5 seconds after stimulus onset
csd_ers = csd_morlet(epochs, freqs, tmin=0.5, tmax=1.5, decim=20)

###############################################################################
# To compute the source power for a frequency band, rather than each frequency
# separately, we average the CSD objects across frequencies.
csd = csd.mean()
csd_baseline = csd_baseline.mean()
csd_ers = csd_ers.mean()

###############################################################################
# Computing DICS spatial filters using the CSD that was computed on the entire
# timecourse.
filters = make_dics(epochs.info,
                    fwd,
                    csd,
                    noise_csd=csd_baseline,
                    pick_ori='max-power')

###############################################################################
# Applying DICS spatial filters separately to the CSD computed using the
# baseline and the CSD computed during the ERS activity.
baseline_source_power, freqs = apply_dics_csd(csd_baseline, filters)
beta_source_power, freqs = apply_dics_csd(csd_ers, filters)

###############################################################################
# Visualizing source power during ERS activity relative to the baseline power.
stc = beta_source_power / baseline_source_power
message = 'DICS source power in the 12-30 Hz frequency band'
brain = stc.plot(hemi='both',
                 views='par',
Exemple #37
0
def test_tf_dics():
    """Test 5D time-frequency beamforming based on DICS."""
    fwd_free, fwd_surf, fwd_fixed, fwd_vol, label = _load_forward()
    epochs, evoked, _, source_vertno = _simulate_data(fwd_fixed)
    vertices = np.intersect1d(label.vertices, fwd_free['src'][0]['vertno'])
    source_ind = vertices.tolist().index(source_vertno)
    reg = 1  # Lots of regularization for our toy dataset

    tmin = 0
    tmax = 9
    tstep = 4
    win_lengths = [5, 5]
    frequencies = [10, 20]
    freq_bins = [(8, 12), (18, 22)]

    # Compute DICS for two time windows and two frequencies
    for mode in ['fourier', 'multitaper', 'cwt_morlet']:
        stcs = tf_dics(epochs, fwd_surf, None, tmin, tmax, tstep, win_lengths,
                       mode=mode, freq_bins=freq_bins, frequencies=frequencies,
                       decim=10, reg=reg, label=label)

        # Did we find the true source at 20 Hz?
        assert np.argmax(stcs[1].data[:, 0]) == source_ind
        assert np.argmax(stcs[1].data[:, 1]) == source_ind

        # 20 Hz power should decrease over time
        assert stcs[1].data[source_ind, 0] > stcs[1].data[source_ind, 1]

        # 20 Hz power should be more than 10 Hz power at the true source
        assert stcs[1].data[source_ind, 0] > stcs[0].data[source_ind, 0]

    # Manually compute source power and compare with the last tf_dics result.
    source_power = []
    time_windows = [(0, 5), (4, 9)]
    for time_window in time_windows:
        csd = csd_morlet(epochs, frequencies=[frequencies[1]],
                         tmin=time_window[0], tmax=time_window[1], decim=10)
        csd = csd.sum()
        csd._data /= csd.n_fft
        filters = make_dics(epochs.info, fwd_surf, csd, reg=reg, label=label)
        stc_source_power, _ = apply_dics_csd(csd, filters)
        source_power.append(stc_source_power.data)

    # Comparing tf_dics results with dics_source_power results
    assert_allclose(stcs[1].data, np.array(source_power).squeeze().T, atol=0)

    # Test using noise csds. We're going to use identity matrices. That way,
    # since we're using unit-noise-gain weight normalization, there should be
    # no effect.
    stcs = tf_dics(epochs, fwd_surf, None, tmin, tmax, tstep, win_lengths,
                   mode='cwt_morlet', frequencies=frequencies, decim=10,
                   reg=reg, label=label, normalize_fwd=False,
                   weight_norm='unit-noise-gain')
    noise_csd = csd.copy()
    inds = np.triu_indices(csd.n_channels)
    # Using [:, :] syntax for in-place broadcasting
    noise_csd._data[:, :] = 2 * np.eye(csd.n_channels)[inds][:, np.newaxis]
    noise_csd.n_fft = 2  # Dividing by n_fft should yield an identity CSD
    noise_csds = [noise_csd, noise_csd]  # Two frequency bins
    stcs_norm = tf_dics(epochs, fwd_surf, noise_csds, tmin, tmax, tstep,
                        win_lengths, mode='cwt_morlet',
                        frequencies=frequencies, decim=10, reg=reg,
                        label=label, normalize_fwd=False,
                        weight_norm='unit-noise-gain')
    assert_allclose(stcs_norm[0].data, stcs[0].data, atol=0)
    assert_allclose(stcs_norm[1].data, stcs[1].data, atol=0)

    # Test invalid parameter combinations
    raises(ValueError, tf_dics, epochs, fwd_surf, None, tmin, tmax, tstep,
           win_lengths, mode='fourier', freq_bins=None)
    raises(ValueError, tf_dics, epochs, fwd_surf, None, tmin, tmax, tstep,
           win_lengths, mode='cwt_morlet', frequencies=None)

    # Test if incorrect number of noise CSDs is detected
    raises(ValueError, tf_dics, epochs, fwd_surf, [noise_csds[0]], tmin, tmax,
           tstep, win_lengths, freq_bins=freq_bins)

    # Test if freq_bins and win_lengths incompatibility is detected
    raises(ValueError, tf_dics, epochs, fwd_surf, None, tmin, tmax, tstep,
           win_lengths=[0, 1, 2], freq_bins=freq_bins)

    # Test if time step exceeding window lengths is detected
    raises(ValueError, tf_dics, epochs, fwd_surf, None, tmin, tmax, tstep=0.15,
           win_lengths=[0.2, 0.1], freq_bins=freq_bins)

    # Test if incorrent number of n_ffts is detected
    raises(ValueError, tf_dics, epochs, fwd_surf, None, tmin, tmax, tstep,
           win_lengths, freq_bins=freq_bins, n_ffts=[1])

    # Test if incorrect number of mt_bandwidths is detected
    raises(ValueError, tf_dics, epochs, fwd_surf, None, tmin, tmax, tstep,
           win_lengths=win_lengths, freq_bins=freq_bins, mode='multitaper',
           mt_bandwidths=[20])

    # Test if subtracting evoked responses yields NaN's, since we only have one
    # epoch. Suppress division warnings.
    with pytest.warns(RuntimeWarning, match='[invalid|empty]'):
        stcs = tf_dics(epochs, fwd_surf, None, tmin, tmax, tstep, win_lengths,
                       mode='cwt_morlet', frequencies=frequencies,
                       subtract_evoked=True, reg=reg, label=label, decim=20)
    assert np.all(np.isnan(stcs[0].data))
# We are interested in the beta band. Define a range of frequencies, using a
# log scale, from 12 to 30 Hz.
freqs = np.logspace(np.log10(12), np.log10(30), 9)

###############################################################################
# Computing the cross-spectral density matrix for the beta frequency band, for
# different time intervals. We use a decim value of 20 to speed up the
# computation in this example at the loss of accuracy.
csd = csd_morlet(epochs, freqs, tmin=-1, tmax=1.5, decim=20)
csd_baseline = csd_morlet(epochs, freqs, tmin=-1, tmax=0, decim=20)
# ERS activity starts at 0.5 seconds after stimulus onset
csd_ers = csd_morlet(epochs, freqs, tmin=0.5, tmax=1.5, decim=20)

###############################################################################
# Computing DICS spatial filters using the CSD that was computed on the entire
# timecourse.
filters = make_dics(epochs.info, fwd, csd.mean(), pick_ori='max-power')

###############################################################################
# Applying DICS spatial filters separately to the CSD computed using the
# baseline and the CSD computed during the ERS activity.
baseline_source_power, freqs = apply_dics_csd(csd_baseline.mean(), filters)
beta_source_power, freqs = apply_dics_csd(csd_ers.mean(), filters)

###############################################################################
# Visualizing source power during ERS activity relative to the baseline power.
stc = beta_source_power / baseline_source_power
message = 'DICS source power in the 12-30 Hz frequency band'
brain = stc.plot(hemi='both', views='par', subjects_dir=subjects_dir,
                 time_label=message)