def test_inverse_residual(evoked): """Test MNE inverse application.""" # use fname_inv as it will be faster than fname_full (fewer verts and chs) evoked = evoked.pick_types() inv = read_inverse_operator(fname_inv_fixed_depth) fwd = read_forward_solution(fname_fwd) pick_channels_forward(fwd, evoked.ch_names, copy=False) fwd = convert_forward_solution(fwd, force_fixed=True, surf_ori=True) matcher = re.compile(r'.* ([0-9]?[0-9]?[0-9]?\.[0-9])% variance.*') for method in ('MNE', 'dSPM', 'sLORETA'): with catch_logging() as log: stc, residual = apply_inverse(evoked, inv, method=method, return_residual=True, verbose=True) log = log.getvalue() match = matcher.match(log.replace('\n', ' ')) assert match is not None match = float(match.group(1)) assert 45 < match < 50 if method == 'MNE': # must be first! recon = apply_forward(fwd, stc, evoked.info) proj_op = make_projector(evoked.info['projs'], evoked.ch_names)[0] recon.data[:] = np.dot(proj_op, recon.data) residual_fwd = evoked.copy() residual_fwd.data -= recon.data corr = np.corrcoef(residual_fwd.data.ravel(), residual.data.ravel())[0, 1] assert corr > 0.999 with catch_logging() as log: _, residual = apply_inverse(evoked, inv, 0., 'MNE', return_residual=True, verbose=True) log = log.getvalue() match = matcher.match(log.replace('\n', ' ')) assert match is not None match = float(match.group(1)) assert match == 100. assert_array_less(np.abs(residual.data), 1e-15) # Degenerate: we don't have the right representation for eLORETA for this with pytest.raises(ValueError, match='eLORETA does not .* support .*'): apply_inverse(evoked, inv, method="eLORETA", return_residual=True)
def test_inverse_residual(evoked, method): """Test MNE inverse application.""" # use fname_inv as it will be faster than fname_full (fewer verts and chs) evoked = evoked.pick_types(meg=True) inv = read_inverse_operator(fname_inv_fixed_depth) fwd = read_forward_solution(fname_fwd) pick_channels_forward(fwd, evoked.ch_names, copy=False) fwd = convert_forward_solution(fwd, force_fixed=True, surf_ori=True) matcher = re.compile(r'.* ([0-9]?[0-9]?[0-9]?\.[0-9])% variance.*') # make it complex to ensure we handle it properly evoked.data = 1j * evoked.data with catch_logging() as log: stc, residual = apply_inverse( evoked, inv, method=method, return_residual=True, verbose=True) # revert the complex-ification (except STC, allow that to be complex still) assert_array_equal(residual.data.real, 0) residual.data = (-1j * residual.data).real evoked.data = (-1j * evoked.data).real # continue testing log = log.getvalue() match = matcher.match(log.replace('\n', ' ')) assert match is not None match = float(match.group(1)) assert 45 < match < 50 if method not in ('dSPM', 'sLORETA'): # revert effects of STC being forced to be complex recon = apply_forward(fwd, stc, evoked.info) recon.data = (-1j * recon.data).real proj_op = make_projector(evoked.info['projs'], evoked.ch_names)[0] recon.data[:] = np.dot(proj_op, recon.data) residual_fwd = evoked.copy() residual_fwd.data -= recon.data corr = np.corrcoef(residual_fwd.data.ravel(), residual.data.ravel())[0, 1] assert corr > 0.999 if method != 'sLORETA': # XXX divide by zero error with catch_logging() as log: _, residual = apply_inverse( evoked, inv, 0., method, return_residual=True, verbose=True) log = log.getvalue() match = matcher.match(log.replace('\n', ' ')) assert match is not None match = float(match.group(1)) assert match == 100. assert_array_less(np.abs(residual.data), 1e-15)
def test_inverse_residual(): """Test MNE inverse application.""" # use fname_inv as it will be faster than fname_full (fewer verts and chs) evoked = _get_evoked().pick_types() inv = read_inverse_operator(fname_inv_fixed_depth) fwd = read_forward_solution(fname_fwd) fwd = convert_forward_solution(fwd, force_fixed=True, surf_ori=True) fwd = pick_channels_forward(fwd, evoked.ch_names) matcher = re.compile(r'.* ([0-9]?[0-9]?[0-9]?\.[0-9])% variance.*') for method in ('MNE', 'dSPM', 'sLORETA'): with catch_logging() as log: stc, residual = apply_inverse( evoked, inv, method=method, return_residual=True, verbose=True) log = log.getvalue() match = matcher.match(log.replace('\n', ' ')) assert match is not None match = float(match.group(1)) assert 45 < match < 50 if method == 'MNE': # must be first! recon = apply_forward(fwd, stc, evoked.info) proj_op = make_projector(evoked.info['projs'], evoked.ch_names)[0] recon.data[:] = np.dot(proj_op, recon.data) residual_fwd = evoked.copy() residual_fwd.data -= recon.data corr = np.corrcoef(residual_fwd.data.ravel(), residual.data.ravel())[0, 1] assert corr > 0.999 with catch_logging() as log: _, residual = apply_inverse( evoked, inv, 0., 'MNE', return_residual=True, verbose=True) log = log.getvalue() match = matcher.match(log.replace('\n', ' ')) assert match is not None match = float(match.group(1)) assert match == 100. assert_array_less(np.abs(residual.data), 1e-15) # Degenerate: we don't have the right representation for eLORETA for this with pytest.raises(ValueError, match='eLORETA does not .* support .*'): apply_inverse(evoked, inv, method="eLORETA", return_residual=True)
def simulate_evoked_osc(info, fwd, n_trials, freq, label, loc_in_label=None, picks=None, loc_seed=None, snr=None, mu=None, noise_type="white", return_matrix=True, filtering=None, phase_lock=False): """Simulate evoked oscillatory data based on a given fwd model and dipole. Parameters: ----------- info : MNE info object data info, e.g., from raw fwd : MNE forward object forward model object freq : float freq of simulated oscillation n_trials : int number of trials label : MNE label source space label to simulate data in loc_in_label : None | int Specify the random generator state for dipole simulation within the label. Defaults to np.random.RandomState if None. picks : None | string Channel types to pick from evoked, can be 'mag' or 'grad'. None defaults to all. seed : None | int Seed for the time series simulation, only relevant for location in label. snr : None | float If not None, signal-to-noise ratio in dB for resulting signal (adding noise). mu : None | float To directly manipulate noise level (e.g. to keep constant across conditions). noise_type : str Type of noise. Supported is at the moment: "white" and "brownian". return_matrix : bool If True, a matrix of epochs will be returned and the evoked object will be averaged across trials. filtering : None | dict If None (default), no filtering is done. If filtering should be done, the dictionary needs to contain the following keys: "hp" : high pass cutoff, float. "lp" : low pass cutoff, float. "fir_design" : FIR design, string, see evoked.filter() "lp_tw" : transition width for low pass, float, optional. "hp_tw" : transition width for high pass, float, optional. phase_lock : bool If True, the oscillation will be phase-locked across trials. Returns: -------- evoked : MNE evoked object Simulated sensor data. stc : MNE source time course object Simulated source space data. epochs : np.array Matrix with epochs, if return_matrix is True. """ if loc_seed is not None: np.random.seed(loc_seed) if loc_in_label is None: loc_in_label = np.random.RandomState() np.random.seed() # reset to random seed to not get funky results for noise times = np.arange(0., n_trials, 1. / info['sfreq']) stc = simulate_sparse_stc( fwd['src'], n_dipoles=1, times=times, random_state=loc_in_label, labels=label, data_fun=lambda times: generate_signal( times, freq, n_trials, phase_lock=phase_lock)) # go to sensor space evoked = apply_forward(fwd, stc, info, verbose=False, use_cps=False) # pick channel types if applicable if picks is not None: evoked.pick_types(meg=picks) if filtering is not None: if "lp_tw" not in filtering: filtering["lp_tw"] = "auto" if "hp_tw" not in filtering: filtering["hp_tw"] = "auto" if snr is not None: snr = 10**(snr / 20) # convert dB to ratio if noise_type == "white": noise_data = np.random.randn(*evoked.data.shape) elif noise_type == "brownian": # make white noise first noise_data = np.random.randn(*evoked.data.shape) elif noise_type == "pink": noise_data = make_pink_noise(evoked.data.shape[1], 10, evoked.data.shape[0]) else: raise ValueError('So far, only white, brownian, and pink noise is ' 'implemented, got %s' % noise_type) if filtering is not None: # filter the noise noise_evoked = evoked.copy() noise_evoked.data[:] = noise_data noise_evoked.filter(filtering["hp"], filtering["lp"], fir_design=filtering["fir_design"], l_trans_bandwidth=filtering["hp_tw"], h_trans_bandwidth=filtering["lp_tw"], verbose=False) noise_data = noise_evoked.data # scale the noise # shape: trials x sensor x time noise_matrix = noise_data.reshape([len(evoked.ch_names), n_trials, -1]).transpose(1, 0, 2) signal_matrix = evoked._data.reshape( [len(evoked.ch_names), n_trials, -1]).transpose(1, 0, 2) if mu is None: mu = np.linalg.norm(signal_matrix, 'fro', axis=(1, 2)) mu /= (snr * np.sqrt(len(evoked.ch_names) * (len(times) / n_trials))) if noise_type == 'brownian': noise_matrix = np.cumsum(mu[:, np.newaxis, np.newaxis] * noise_matrix, axis=1) signal_matrix += noise_matrix else: signal_matrix += (mu[:, np.newaxis, np.newaxis] * noise_matrix) evoked.data = signal_matrix.transpose(1, 0, 2).reshape( [len(evoked.ch_names), int(n_trials * (len(times) / n_trials))]) # evoked.data *= 1e-11 if filtering is not None: # filter all the data again evoked.filter(filtering["hp"], filtering["lp"], fir_design=filtering["fir_design"], l_trans_bandwidth=filtering["hp_tw"], h_trans_bandwidth=filtering["lp_tw"], verbose=False) # take care of trials: if return_matrix is True: epochs = evoked._data epochs = epochs.reshape([len(evoked.ch_names), n_trials, -1]).transpose(1, 0, 2) evoked.crop(0., evoked.times[int((times.shape[0] / n_trials) - 1)]) evoked._data[:, :] = epochs.mean(axis=0) return evoked, stc, epochs, mu else: return evoked, stc, mu