def make_dipole_projectors(info, pos, ori, bem, trans, verbose=None): """Make dipole projectors. Parameters ---------- info : instance of Info The measurement info. pos : ndarray, shape (n_dip, 3) The dipole positions. ori : ndarray, shape (n_dip, 3) The dipole orientations. bem : instance of ConductorModel The conductor model to use. trans : instance of Transform The mri-to-head transformation. %(verbose)s Returns ------- projs : list of Projection The projectors. """ pos = np.atleast_2d(pos).astype(float) ori = np.atleast_2d(ori).astype(float) if pos.shape[1] != 3 or pos.shape != ori.shape: raise ValueError('pos and ori must be 2D, the same shape, and have ' f'last dimension 3, got {pos.shape} and {ori.shape}') dip = Dipole(pos=pos, ori=ori, amplitude=np.ones(pos.shape[0]), gof=np.ones(pos.shape[0]), times=np.arange(pos.shape[0])) info = pick_info(info, pick_types(info, meg=True, eeg=True, exclude=())) fwd, _ = make_forward_dipole(dip, bem, info, trans) assert fwd['sol']['data'].shape[1] == pos.shape[0] projs = list() for kind in ('meg', 'eeg'): kwargs = dict(meg=False, eeg=False, exclude=()) kwargs.update({kind: True}) picks = pick_types(info, **kwargs) if len(picks) > 0: ch_names = [info['ch_names'][pick] for pick in picks] projs.extend([ Projection(data=dict(data=p[np.newaxis, picks], row_names=None, nrow=1, col_names=list(ch_names), ncol=len(ch_names)), kind=FIFF.FIFFV_PROJ_ITEM_DIP_FIX, explained_var=None, active=False, desc=f'Dipole #{pi}') for pi, p in enumerate(fwd['sol']['data'].T, 1) ]) return projs
def gen_forward_solution(pos, bem, info, trans, verbose=True): # NOTE: # Both, dipole amplitude and orientation, are set to arbitrary values # here: They are merely required to instantiate a Dipole object, which # we then use to conveniently retrieve a forward solution via # `make_forward_dipole()`. This forward solution is returned in "fixed" # orientation. We then convert it back to "free" orientation mode before # returning the forward object. amplitude = np.array([1]).reshape(1, ) # Arbitraty amplitude. ori = np.array([1., 1., 1.]).reshape(1, 3) # Arbitrary orientation. ori /= np.linalg.norm(ori) pos = pos.reshape(1, 3) gof = np.array([100]).reshape(1, ) dip = mne.Dipole(times=[0], pos=pos, ori=ori, amplitude=amplitude, gof=gof) fwd, _ = mne.make_forward_dipole(dip, bem=bem, info=info, trans=trans, verbose=verbose) fwd = mne.convert_forward_solution(fwd, force_fixed=False, verbose=verbose) return fwd
def test_simulate_calculate_chpi_positions(): """Test calculation of cHPI positions with simulated data.""" # Read info dict from raw FIF file info = read_info(raw_fname) # Tune the info structure chpi_channel = u'STI201' ncoil = len(info['hpi_results'][0]['order']) coil_freq = 10 + np.arange(ncoil) * 5 hpi_subsystem = {'event_channel': chpi_channel, 'hpi_coils': [{'event_bits': np.array([256, 0, 256, 256], dtype=np.int32)}, {'event_bits': np.array([512, 0, 512, 512], dtype=np.int32)}, {'event_bits': np.array([1024, 0, 1024, 1024], dtype=np.int32)}, {'event_bits': np.array([2048, 0, 2048, 2048], dtype=np.int32)}], 'ncoil': ncoil} info['hpi_subsystem'] = hpi_subsystem for l, freq in enumerate(coil_freq): info['hpi_meas'][0]['hpi_coils'][l]['coil_freq'] = freq picks = pick_types(info, meg=True, stim=True, eeg=False, exclude=[]) info['sfreq'] = 100. # this will speed it up a lot info = pick_info(info, picks) info['chs'][info['ch_names'].index('STI 001')]['ch_name'] = 'STI201' info._update_redundant() info['projs'] = [] info_trans = info['dev_head_t']['trans'].copy() dev_head_pos_ini = np.concatenate([rot_to_quat(info_trans[:3, :3]), info_trans[:3, 3]]) ez = np.array([0, 0, 1]) # Unit vector in z-direction of head coordinates # Define some constants duration = 30 # Time / s # Quotient of head position sampling frequency # and raw sampling frequency head_pos_sfreq_quotient = 0.1 # Round number of head positions to the next integer S = int(duration / (info['sfreq'] * head_pos_sfreq_quotient)) dz = 0.001 # Shift in z-direction is 0.1mm for each step dev_head_pos = np.zeros((S, 10)) dev_head_pos[:, 0] = np.arange(S) * info['sfreq'] * head_pos_sfreq_quotient dev_head_pos[:, 1:4] = dev_head_pos_ini[:3] dev_head_pos[:, 4:7] = dev_head_pos_ini[3:] + \ np.outer(np.arange(S) * dz, ez) dev_head_pos[:, 7] = 1.0 # cm/s dev_head_pos[:, 9] = 100 * dz / (info['sfreq'] * head_pos_sfreq_quotient) # Round number of samples to the next integer raw_data = np.zeros((len(picks), int(duration * info['sfreq'] + 0.5))) raw = RawArray(raw_data, info) dip = Dipole(np.array([0.0, 0.1, 0.2]), np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]), np.array([1e-9, 1e-9, 1e-9]), np.array([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]), np.array([1.0, 1.0, 1.0]), 'dip') sphere = make_sphere_model('auto', 'auto', info=info, relative_radii=(1.0, 0.9), sigmas=(0.33, 0.3)) fwd, stc = make_forward_dipole(dip, sphere, info) stc.resample(info['sfreq']) raw = simulate_raw(raw, stc, None, fwd['src'], sphere, cov=None, blink=False, ecg=False, chpi=True, head_pos=dev_head_pos, mindist=1.0, interp='zero', verbose=None, use_cps=True) quats = _calculate_chpi_positions( raw, t_step_min=raw.info['sfreq'] * head_pos_sfreq_quotient, t_step_max=raw.info['sfreq'] * head_pos_sfreq_quotient, t_window=1.0) _assert_quats(quats, dev_head_pos, dist_tol=0.001, angle_tol=1.)
def test_simulate_calculate_chpi_positions(): """Test calculation of cHPI positions with simulated data.""" # Read info dict from raw FIF file info = read_info(raw_fname) # Tune the info structure chpi_channel = u'STI201' ncoil = len(info['hpi_results'][0]['order']) coil_freq = 10 + np.arange(ncoil) * 5 hpi_subsystem = { 'event_channel': chpi_channel, 'hpi_coils': [{ 'event_bits': np.array([256, 0, 256, 256], dtype=np.int32) }, { 'event_bits': np.array([512, 0, 512, 512], dtype=np.int32) }, { 'event_bits': np.array([1024, 0, 1024, 1024], dtype=np.int32) }, { 'event_bits': np.array([2048, 0, 2048, 2048], dtype=np.int32) }], 'ncoil': ncoil } info['hpi_subsystem'] = hpi_subsystem for l, freq in enumerate(coil_freq): info['hpi_meas'][0]['hpi_coils'][l]['coil_freq'] = freq picks = pick_types(info, meg=True, stim=True, eeg=False, exclude=[]) info['sfreq'] = 100. # this will speed it up a lot info = pick_info(info, picks) info['chs'][info['ch_names'].index('STI 001')]['ch_name'] = 'STI201' info._update_redundant() info['projs'] = [] info_trans = info['dev_head_t']['trans'].copy() dev_head_pos_ini = np.concatenate( [rot_to_quat(info_trans[:3, :3]), info_trans[:3, 3]]) ez = np.array([0, 0, 1]) # Unit vector in z-direction of head coordinates # Define some constants duration = 30 # Time / s # Quotient of head position sampling frequency # and raw sampling frequency head_pos_sfreq_quotient = 0.1 # Round number of head positions to the next integer S = int(duration / (info['sfreq'] * head_pos_sfreq_quotient)) dz = 0.001 # Shift in z-direction is 0.1mm for each step dev_head_pos = np.zeros((S, 10)) dev_head_pos[:, 0] = np.arange(S) * info['sfreq'] * head_pos_sfreq_quotient dev_head_pos[:, 1:4] = dev_head_pos_ini[:3] dev_head_pos[:, 4:7] = dev_head_pos_ini[3:] + \ np.outer(np.arange(S) * dz, ez) dev_head_pos[:, 7] = 1.0 # cm/s dev_head_pos[:, 9] = 100 * dz / (info['sfreq'] * head_pos_sfreq_quotient) # Round number of samples to the next integer raw_data = np.zeros((len(picks), int(duration * info['sfreq'] + 0.5))) raw = RawArray(raw_data, info) dip = Dipole(np.array([0.0, 0.1, 0.2]), np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]), np.array([1e-9, 1e-9, 1e-9]), np.array([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]), np.array([1.0, 1.0, 1.0]), 'dip') sphere = make_sphere_model('auto', 'auto', info=info, relative_radii=(1.0, 0.9), sigmas=(0.33, 0.3)) fwd, stc = make_forward_dipole(dip, sphere, info) stc.resample(info['sfreq']) raw = simulate_raw(raw, stc, None, fwd['src'], sphere, cov=None, blink=False, ecg=False, chpi=True, head_pos=dev_head_pos, mindist=1.0, interp='zero', verbose=None) quats = _calculate_chpi_positions( raw, t_step_min=raw.info['sfreq'] * head_pos_sfreq_quotient, t_step_max=raw.info['sfreq'] * head_pos_sfreq_quotient, t_window=1.0) _assert_quats(quats, dev_head_pos, dist_tol=0.001, angle_tol=1.)
evoked_fit_left.info.normalize_proj() evoked_fit_right.info.normalize_proj() cov_fit_left['projs'] = evoked_fit_left.info['projs'] cov_fit_right['projs'] = evoked_fit_right.info['projs'] # Fit the dipoles with the subset of sensors. dip_left, _ = mne.fit_dipole(evoked_fit_left, cov_fit_left, bem) dip_right, _ = mne.fit_dipole(evoked_fit_right, cov_fit_right, bem) ############################################################################### # Now that we have the location and orientations of the dipoles, compute the # full timecourses using MNE, assigning activity to both dipoles at the same # time while preventing leakage between the two. We use a very low ``lambda`` # value to ensure both dipoles are fully used. fwd, _ = mne.make_forward_dipole([dip_left, dip_right], bem, info) # Apply MNE inverse inv = make_inverse_operator(info, fwd, cov, fixed=True, depth=0) stc_left = apply_inverse(evoked_left, inv, method='MNE', lambda2=1E-6) stc_right = apply_inverse(evoked_right, inv, method='MNE', lambda2=1E-6) # Plot the timecourses of the resulting source estimate fig, axes = plt.subplots(nrows=2, sharex=True, sharey=True) axes[0].plot(stc_left.times, stc_left.data.T) axes[0].set_title('Left auditory stimulation') axes[0].legend(['Dipole 1', 'Dipole 2']) axes[1].plot(stc_right.times, stc_right.data.T) axes[1].set_title('Right auditory stimulation') axes[1].set_xlabel('Time (s)') fig.supylabel('Dipole amplitude')