def test_multipolar_bases(): """Test multipolar moment basis calculation using sensor information.""" from scipy.io import loadmat # Test our basis calculations info = read_info(raw_fname) with use_coil_def(elekta_def_fname): coils = _prep_meg_channels(info, accurate=True, do_es=True)[0] # Check against a known benchmark sss_data = loadmat(bases_fname) exp = dict(int_order=int_order, ext_order=ext_order) for origin in ((0, 0, 0.04), (0, 0.02, 0.02)): o_str = ''.join('%d' % (1000 * n) for n in origin) exp.update(origin=origin) S_tot = _sss_basis_basic(exp, coils, method='alternative') # Test our real<->complex conversion functions S_tot_complex = _bases_real_to_complex(S_tot, int_order, ext_order) S_tot_round = _bases_complex_to_real(S_tot_complex, int_order, ext_order) assert_allclose(S_tot, S_tot_round, atol=1e-7) S_tot_mat = np.concatenate([sss_data['Sin' + o_str], sss_data['Sout' + o_str]], axis=1) S_tot_mat_real = _bases_complex_to_real(S_tot_mat, int_order, ext_order) S_tot_mat_round = _bases_real_to_complex(S_tot_mat_real, int_order, ext_order) assert_allclose(S_tot_mat, S_tot_mat_round, atol=1e-7) assert_allclose(S_tot_complex, S_tot_mat, rtol=1e-4, atol=1e-8) assert_allclose(S_tot, S_tot_mat_real, rtol=1e-4, atol=1e-8) # Now normalize our columns S_tot /= np.sqrt(np.sum(S_tot * S_tot, axis=0))[np.newaxis] S_tot_complex /= np.sqrt(np.sum( (S_tot_complex * S_tot_complex.conj()).real, axis=0))[np.newaxis] # Check against a known benchmark S_tot_mat = np.concatenate([sss_data['SNin' + o_str], sss_data['SNout' + o_str]], axis=1) # Check this roundtrip S_tot_mat_real = _bases_complex_to_real(S_tot_mat, int_order, ext_order) S_tot_mat_round = _bases_real_to_complex(S_tot_mat_real, int_order, ext_order) assert_allclose(S_tot_mat, S_tot_mat_round, atol=1e-7) assert_allclose(S_tot_complex, S_tot_mat, rtol=1e-4, atol=1e-8) # Now test our optimized version S_tot = _sss_basis_basic(exp, coils) with use_coil_def(elekta_def_fname): S_tot_fast = _trans_sss_basis( exp, all_coils=_prep_mf_coils(info), trans=info['dev_head_t']) # there are some sign differences for columns (order/degrees) # in here, likely due to Condon-Shortley. Here we use a # Magnetometer channel to figure out the flips because the # gradiometer channels have effectively zero values for first three # external components (i.e., S_tot[grad_picks, 80:83]) flips = (np.sign(S_tot_fast[2]) != np.sign(S_tot[2])) flips = 1 - 2 * flips assert_allclose(S_tot, S_tot_fast * flips, atol=1e-16)