|
| 1 | +""" |
| 2 | +.. _ex-kernel-opm-phantom: |
| 3 | +
|
| 4 | +Kernel OPM phantom data |
| 5 | +======================= |
| 6 | +
|
| 7 | +In this dataset, a Neuromag phantom was placed inside the Kernel OPM helmet and |
| 8 | +stimulated with 7 modules active (121 channels). Here we show some example traces. |
| 9 | +""" |
| 10 | + |
| 11 | +import numpy as np |
| 12 | + |
| 13 | +import mne |
| 14 | + |
| 15 | +data_path = mne.datasets.phantom_kernel.data_path() |
| 16 | +fname = data_path / "phantom_32_100nam_raw.fif" |
| 17 | +raw = mne.io.read_raw_fif(fname).load_data() |
| 18 | +events = mne.find_events(raw, stim_channel="STI101") |
| 19 | + |
| 20 | +# Bads identified by inspecting averages |
| 21 | +raw.info["bads"] = [ |
| 22 | + "RC2.bx.ave", |
| 23 | + "LC3.bx.ave", |
| 24 | + "RC2.by.7", |
| 25 | + "RC2.bz.7", |
| 26 | + "RC2.bx.4", |
| 27 | + "RC2.by.4", |
| 28 | + "LC3.bx.5", |
| 29 | +] |
| 30 | +# Drop the module-average channels |
| 31 | +raw.drop_channels([ch_name for ch_name in raw.ch_names if ".ave" in ch_name]) |
| 32 | +# Add field correction projectors |
| 33 | +raw.add_proj(mne.preprocessing.compute_proj_hfc(raw.info, order=2)) |
| 34 | +raw.pick("meg", exclude="bads") |
| 35 | +raw.filter(0.5, 40) |
| 36 | +epochs = mne.Epochs( |
| 37 | + raw, |
| 38 | + events, |
| 39 | + tmin=-0.1, |
| 40 | + tmax=0.25, |
| 41 | + decim=5, |
| 42 | + preload=True, |
| 43 | + baseline=(None, 0), |
| 44 | +) |
| 45 | +evoked = epochs["17"].average() # a high-SNR dipole for these data |
| 46 | +fig = evoked.plot() |
| 47 | +t_peak = 0.016 # based on visual inspection of evoked |
| 48 | +fig.axes[0].axvline(t_peak, color="k", ls=":", lw=3, zorder=2) |
| 49 | + |
| 50 | +# %% |
| 51 | +# The data covariance has an interesting structure because of densely packed sensors: |
| 52 | +cov = mne.compute_covariance(epochs, tmax=-0.01) |
| 53 | +mne.viz.plot_cov(cov, raw.info) |
| 54 | + |
| 55 | +# %% |
| 56 | +# So let's be careful and compute rank ahead of time and regularize: |
| 57 | + |
| 58 | +rank = mne.compute_rank(epochs, tol=1e-3, tol_kind="relative") |
| 59 | +cov = mne.compute_covariance(epochs, tmax=-0.01, rank=rank, method="shrunk") |
| 60 | +mne.viz.plot_cov(cov, raw.info) |
| 61 | + |
| 62 | +# %% |
| 63 | +# Look at our alignment: |
| 64 | + |
| 65 | +sphere = mne.make_sphere_model(r0=(0.0, 0.0, 0.0), head_radius=0.08) |
| 66 | +trans = mne.transforms.Transform("head", "mri", np.eye(4)) |
| 67 | +align_kwargs = dict( |
| 68 | + trans=trans, |
| 69 | + bem=sphere, |
| 70 | + surfaces={"outer_skin": 0.2}, |
| 71 | + show_axes=True, |
| 72 | +) |
| 73 | +mne.viz.plot_alignment( |
| 74 | + raw.info, |
| 75 | + coord_frame="meg", |
| 76 | + meg=dict(sensors=1.0, helmet=0.05), |
| 77 | + **align_kwargs, |
| 78 | +) |
| 79 | + |
| 80 | +# %% |
| 81 | +# Let's do dipole fits, which are not great because the dev_head_t is approximate and |
| 82 | +# the sensor coverage is sparse: |
| 83 | + |
| 84 | +data = list() |
| 85 | +for ii in range(1, 33): |
| 86 | + evoked = epochs[str(ii)][1:-1].average().crop(t_peak, t_peak) |
| 87 | + data.append(evoked.data[:, 0]) |
| 88 | +evoked = mne.EvokedArray(np.array(data).T, evoked.info, tmin=0.0) |
| 89 | +del epochs |
| 90 | +dip, residual = mne.fit_dipole(evoked, cov, sphere, n_jobs=None) |
| 91 | +actual_pos, actual_ori = mne.dipole.get_phantom_dipoles() |
| 92 | +actual_amp = np.ones(len(dip)) # fake amp, needed to create Dipole instance |
| 93 | +actual_gof = np.ones(len(dip)) # fake GOF, needed to create Dipole instance |
| 94 | +dip_true = mne.Dipole(dip.times, actual_pos, actual_amp, actual_ori, actual_gof) |
| 95 | + |
| 96 | +fig = mne.viz.plot_alignment( |
| 97 | + evoked.info, coord_frame="head", meg="sensors", **align_kwargs |
| 98 | +) |
| 99 | +mne.viz.plot_dipole_locations( |
| 100 | + dipoles=dip_true, mode="arrow", color=(0.0, 0.0, 0.0), fig=fig |
| 101 | +) |
| 102 | +mne.viz.plot_dipole_locations(dipoles=dip, mode="arrow", color=(0.2, 1.0, 0.5), fig=fig) |
| 103 | +mne.viz.set_3d_view(figure=fig, azimuth=30, elevation=70, distance=0.4) |
0 commit comments