def test_calculate_chpi_coil_locs_artemis(): """Test computing just cHPI locations.""" raw = read_raw_fif(chpi_fif_fname, allow_maxshield='yes', preload=True) # This is a little hack (aliasing while decimating) to make it much faster # for testing purposes only. We can relax this later if we find it breaks # something. raw_dec = _decimate_chpi(raw, 15) times, cHPI_digs = _calculate_chpi_coil_locs(raw_dec, verbose='debug') # spot check assert_allclose(times[0], 9., atol=1e-2) assert_allclose(cHPI_digs[0][2]['r'], [-0.01937833, 0.00346804, 0.06331209], atol=1e-3) assert_allclose(cHPI_digs[0][2]['gof'], 0.9957, atol=1e-3) assert_allclose(cHPI_digs[0][4]['r'], [-0.0655, 0.0755, 0.0004], atol=3e-3) assert_allclose(cHPI_digs[0][4]['gof'], 0.9323, atol=1e-3) _check_dists(raw.info, cHPI_digs[0], n_bad=1) # test on 5k artemis data raw = read_raw_artemis123(art_fname, preload=True) times, cHPI_digs = _calculate_chpi_coil_locs(raw, verbose='debug') assert len(np.setdiff1d(times, raw.times + raw.first_time)) == 0 # Should be somewhere around 1.5 sec, depending on coil GOF values # around 0.98 it can change assert_allclose(times[5], 1.5, atol=2e-1) assert_allclose(cHPI_digs[5][0]['gof'], 0.995, atol=5e-3) assert_allclose(cHPI_digs[5][0]['r'], [-0.0157, 0.0655, 0.0018], atol=1e-3) _check_dists(raw.info, cHPI_digs[5]) coil_amplitudes = compute_chpi_amplitudes(raw) with pytest.raises(ValueError, match='too_close'): compute_chpi_locs(raw.info, coil_amplitudes, too_close='foo') # ensure values are in a reasonable range amps = np.linalg.norm(coil_amplitudes['slopes'], axis=-1) amps /= coil_amplitudes['slopes'].shape[-1] assert amps.shape == (len(coil_amplitudes['times']), 3) assert_array_less(amps, 1e-11) assert_array_less(1e-13, amps) # with nan amplitudes (i.e., cHPI off) it should return an empty array, # but still one that is 3D coil_amplitudes['slopes'].fill(np.nan) chpi_locs = compute_chpi_locs(raw.info, coil_amplitudes) assert chpi_locs['rrs'].shape == (0, 3, 3) pos = compute_head_pos(raw.info, chpi_locs) assert pos.shape == (0, 10)
def _calculate_chpi_positions(raw, t_step_min=0.01, t_step_max=1., t_window='auto', too_close='raise', dist_limit=0.005, gof_limit=0.98, ext_order=1, verbose=None): chpi_amplitudes = compute_chpi_amplitudes(raw, t_step_min=t_step_min, t_window=t_window, ext_order=ext_order, verbose=verbose) chpi_locs = compute_chpi_locs(raw.info, chpi_amplitudes, t_step_max=t_step_max, too_close=too_close, verbose=verbose) head_pos = compute_head_pos(raw.info, chpi_locs, dist_limit=dist_limit, gof_limit=gof_limit, verbose=verbose) return head_pos
def test_simulate_raw_chpi(): """Test simulation of raw data with cHPI.""" raw = read_raw_fif(raw_chpi_fname, allow_maxshield='yes') picks = np.arange(len(raw.ch_names)) picks = np.setdiff1d(picks, pick_types(raw.info, meg=True, eeg=True)[::4]) raw.load_data().pick_channels([raw.ch_names[pick] for pick in picks]) raw.info.normalize_proj() sphere = make_sphere_model('auto', 'auto', raw.info) # make sparse spherical source space sphere_vol = tuple(sphere['r0']) + (sphere.radius, ) src = setup_volume_source_space(sphere=sphere_vol, pos=70., sphere_units='m') stcs = [_make_stc(raw, src)] * 15 # simulate data with cHPI on raw_sim = simulate_raw(raw.info, stcs, None, src, sphere, head_pos=pos_fname, interp='zero', first_samp=raw.first_samp) # need to trim extra samples off this one raw_chpi = add_chpi(raw_sim.copy(), head_pos=pos_fname, interp='zero') # test cHPI indication hpi_freqs, hpi_pick, hpi_ons = _get_hpi_info(raw.info) assert_allclose(raw_sim[hpi_pick][0], 0.) assert_allclose(raw_chpi[hpi_pick][0], hpi_ons.sum()) # test that the cHPI signals make some reasonable values picks_meg = pick_types(raw.info, meg=True, eeg=False) picks_eeg = pick_types(raw.info, meg=False, eeg=True) for picks in [picks_meg[:3], picks_eeg[:3]]: psd_sim, freqs_sim = psd_welch(raw_sim, picks=picks) psd_chpi, freqs_chpi = psd_welch(raw_chpi, picks=picks) assert_array_equal(freqs_sim, freqs_chpi) freq_idx = np.sort( [np.argmin(np.abs(freqs_sim - f)) for f in hpi_freqs]) if picks is picks_meg: assert (psd_chpi[:, freq_idx] > 100 * psd_sim[:, freq_idx]).all() else: assert_allclose(psd_sim, psd_chpi, atol=1e-20) # test localization based on cHPI information chpi_amplitudes = compute_chpi_amplitudes(raw, t_step_min=10.) coil_locs = compute_chpi_locs(raw.info, chpi_amplitudes) quats_sim = compute_head_pos(raw_chpi.info, coil_locs) quats = read_head_pos(pos_fname) _assert_quats(quats, quats_sim, dist_tol=5e-3, angle_tol=3.5, vel_atol=0.03) # velicity huge because of t_step_min above
def test_calculate_chpi_coil_locs_artemis(): """Test computing just cHPI locations.""" raw = read_raw_fif(chpi_fif_fname, allow_maxshield='yes', preload=True) # This is a little hack (aliasing while decimating) to make it much faster # for testing purposes only. We can relax this later if we find it breaks # something. raw_dec = _decimate_chpi(raw, 15) times, cHPI_digs = _calculate_chpi_coil_locs(raw_dec, verbose='debug') # spot check assert_allclose(times[0], 9., atol=1e-2) assert_allclose(cHPI_digs[0][2]['r'], [-0.01937833, 0.00346804, 0.06331209], atol=1e-3) assert_allclose(cHPI_digs[0][2]['gof'], 0.9957, atol=1e-3) assert_allclose(cHPI_digs[0][4]['r'], [-0.0655, 0.0755, 0.0004], atol=3e-3) assert_allclose(cHPI_digs[0][4]['gof'], 0.9323, atol=1e-3) _check_dists(raw.info, cHPI_digs[0], n_bad=1) # test on 5k artemis data raw = read_raw_artemis123(art_fname, preload=True) times, cHPI_digs = _calculate_chpi_coil_locs(raw, verbose='debug') assert_allclose(times[5], 1.5, atol=1e-3) assert_allclose(cHPI_digs[5][0]['gof'], 0.995, atol=5e-3) assert_allclose(cHPI_digs[5][0]['r'], [-0.0157, 0.0655, 0.0018], atol=1e-3) _check_dists(raw.info, cHPI_digs[5]) coil_amplitudes = compute_chpi_amplitudes(raw) with pytest.raises(ValueError, match='too_close'): compute_chpi_locs(raw, coil_amplitudes, too_close='foo') # ensure values are in a reasonable range amps = np.linalg.norm(coil_amplitudes['slopes'], axis=-1) amps /= coil_amplitudes['slopes'].shape[-1] assert amps.shape == (len(coil_amplitudes['times']), 3) assert_array_less(amps, 1e-11) assert_array_less(1e-13, amps)
def test_initial_fit_redo(): """Test that initial fits can be redone based on moments.""" raw = read_raw_fif(chpi_fif_fname, allow_maxshield='yes') slopes = np.array( [[c['slopes'] for c in raw.info['hpi_meas'][0]['hpi_coils']]]) amps = np.linalg.norm(slopes, axis=-1) amps /= slopes.shape[-1] assert_array_less(amps, 5e-11) assert_array_less(1e-12, amps) proj, _, _ = _setup_ext_proj(raw.info, ext_order=1) chpi_amplitudes = dict(times=np.zeros(1), slopes=slopes, proj=proj) chpi_locs = compute_chpi_locs(raw.info, chpi_amplitudes) # check GOF coil_gof = raw.info['hpi_results'][0]['goodness'] assert_allclose(chpi_locs['gofs'][0], coil_gof, atol=0.3) # XXX not good # check moment # XXX our forward and theirs differ by an extra mult by _MAG_FACTOR coil_moment = raw.info['hpi_results'][0]['moments'] / _MAG_FACTOR py_moment = chpi_locs['moments'][0] coil_amp = np.linalg.norm(coil_moment, axis=-1, keepdims=True) py_amp = np.linalg.norm(py_moment, axis=-1, keepdims=True) assert_allclose(coil_amp, py_amp, rtol=0.2) coil_ori = coil_moment / coil_amp py_ori = py_moment / py_amp angles = np.rad2deg(np.arccos(np.abs(np.sum(coil_ori * py_ori, axis=1)))) assert_array_less(angles, 20) # check resulting dev_head_t head_pos = compute_head_pos(raw.info, chpi_locs) assert head_pos.shape == (1, 10) nm_pos = raw.info['dev_head_t']['trans'] dist = 1000 * np.linalg.norm(nm_pos[:3, 3] - head_pos[0, 4:7]) assert 0.1 < dist < 2 angle = np.rad2deg( _angle_between_quats(rot_to_quat(nm_pos[:3, :3]), head_pos[0, 1:4])) assert 0.1 < angle < 2 gof = head_pos[0, 7] assert_allclose(gof, 0.9999, atol=1e-4)
def _calculate_chpi_coil_locs(raw, verbose): """Wrap to facilitate change diff.""" chpi_amplitudes = compute_chpi_amplitudes(raw, verbose=verbose) chpi_locs = compute_chpi_locs(raw.info, chpi_amplitudes, verbose=verbose) return _chpi_locs_to_times_dig(chpi_locs)
def compute_head_position(src: Path) -> np.ndarray: raw = read_raw_fif(src) chpi_ampl = compute_chpi_amplitudes(raw) chpi_locs = compute_chpi_locs(raw.info, chpi_ampl) return compute_head_pos(raw.info, chpi_locs)