.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_tutorials/tutorial_09_sliding_window_ebb_layer.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_tutorials_tutorial_09_sliding_window_ebb_layer.py: Sliding time window EBBlayer =============================== This tutorial demonstrates the need for a sliding window, layer-specific version of EBB reconstruction to accurately infer two distinct laminar sources across time and space. It builds on the laminar CSD tutorial and addresses limitations, as well as best practices for using EBB for laminar inference. It is composed of two parts: one adressing the need for sliding windows and the other for EBBlayer, a version of EBB that accounts for correlated sources across layers. Two sources are simulated, one in superficial and one in deep layers, either consecutively or simultaneously. Source reconstruction is performed on the simulated sensor data using a forward model based on the multilayer mesh, first on the whole time window using EBB, then using a sliding time window EBB, an finally using a sliding time window with a modified version of EBB with specific priors accounting for correlated sources across layers. Laminar CSD analysis is then run on the laminar source reconstructed signals at the location of the peak variance. .. GENERATED FROM PYTHON SOURCE LINES 23-29 Part I: Temporal smoothing effect: the need for sliding time windows -------------------------------------------------------------------- **Setting up the simulations** Simulations are based on an existing dataset, which is used to define the sampling rate, number of trials, duration of each trial, and the channel layout. .. GENERATED FROM PYTHON SOURCE LINES 29-65 .. code-block:: default import os import shutil import numpy as np import matplotlib.pyplot as plt import tempfile from IPython.display import Image import base64 from lameg.invert import invert_ebb, invert_sliding_window_ebb, invert_sliding_window_ebb_layer, coregister, load_source_time_series from lameg.laminar import compute_csd from lameg.simulate import run_current_density_simulation from lameg.surf import LayerSurfaceSet from lameg.util import get_fiducial_coords, load_meg_sensor_data, init_spm_parallel_pool from lameg.viz import show_surface, color_map, plot_csd import spm_standalone # Subject information for data to base the simulations on subj_id = 'sub-104' ses_id = 'ses-01' # Fiducial coil coordinates fid_coords = get_fiducial_coords(subj_id, '../test_data/participants.tsv') # Data file to base simulations on data_file = os.path.join( '../test_data', subj_id, 'meg', ses_id, f'spm/pspm-converted_autoreject-{subj_id}-{ses_id}-001-btn_trial-epo.mat' ) spm = spm_standalone.initialize() init_spm_parallel_pool(spm, 16) .. GENERATED FROM PYTHON SOURCE LINES 66-67 The simulations and source reconstructions will be based on a forward model using the multilayer mesh, with 11 layers .. GENERATED FROM PYTHON SOURCE LINES 67-72 .. code-block:: default surf_set = LayerSurfaceSet(subj_id, 11) verts_per_surf = surf_set.get_vertices_per_layer() .. GENERATED FROM PYTHON SOURCE LINES 73-74 We’re going to copy the data file to a temporary directory and direct all output there. .. GENERATED FROM PYTHON SOURCE LINES 74-99 .. code-block:: default # Extract base name and path of data file data_path, data_file_name = os.path.split(data_file) data_base = os.path.splitext(data_file_name)[0] # Where to put simulated data tmp_dir = tempfile.mkdtemp() # Copy data files to tmp directory if not os.path.exists(tmp_dir): os.mkdir(tmp_dir) # Copy data files to tmp directory shutil.copy( os.path.join(data_path, f'{data_base}.mat'), os.path.join(tmp_dir, f'{data_base}.mat') ) shutil.copy( os.path.join(data_path, f'{data_base}.dat'), os.path.join(tmp_dir, f'{data_base}.dat') ) # Construct base file name for simulations base_fname = os.path.join(tmp_dir, f'{data_base}.mat') .. GENERATED FROM PYTHON SOURCE LINES 100-101 Invert the subject’s data using the multilayer mesh. This step only has to be done once - this is just to compute the forward model that will be used in the simulations .. GENERATED FROM PYTHON SOURCE LINES 101-124 .. code-block:: default # Patch size to use for inversion (in this case it matches the simulated patch size) patch_size = 5 # Number of temporal modes to use for EBB inversion n_temp_modes = 4 # Coregister data to multilayer mesh coregister( fid_coords, base_fname, surf_set, spm_instance=spm ) # Run inversion [_,_] = invert_ebb( base_fname, surf_set, patch_size=patch_size, n_temp_modes=n_temp_modes, spm_instance=spm ) .. GENERATED FROM PYTHON SOURCE LINES 125-129 **Simulating two sources in different layers** In other tutorials we explored the case of a single laminar source but in real data, we might expect several consecutive sources in different layers. We’re going to simulate 200ms of 2 Gaussian with a dipole moment of 5nAm, a width of 25ms, the second one occuring 80ms after the first .. GENERATED FROM PYTHON SOURCE LINES 129-149 .. code-block:: default _, time, _ = load_meg_sensor_data(base_fname) print(f'Time from {time[0]} to {time[-1]}, with shape {time.shape}') # Strength of simulated activity (nAm) dipole_moment = 5 # Temporal width of the simulated Gaussian signal_width= 10 # 25ms # Sampling rate (must match the data file) s_rate = 600 zero_time1=-40 zero_time2=40 sim_signal1=np.exp(-((time-zero_time1)**2)/(2*signal_width**2)).reshape(1,-1) sim_signal2=np.exp(-((time-zero_time2)**2)/(2*signal_width**2)).reshape(1,-1) plt.plot(time,dipole_moment*sim_signal1[0,:],label='sim1') plt.plot(time,dipole_moment*sim_signal2[0,:],label='sim2') plt.xlabel('Time (s)') plt.ylabel('Amplitude (nAm)') .. GENERATED FROM PYTHON SOURCE LINES 150-151 Select the best vertex to simulate at (based on anatomical measures), and get the corresponding layer vertices. See other tutorials. .. GENERATED FROM PYTHON SOURCE LINES 151-159 .. code-block:: default # Vertex to simulate activity at sim_vertex=10561 sim_vertices = [ surf_set.get_multilayer_vertex(1, sim_vertex), # simulating in superficial surf_set.get_multilayer_vertex(9, sim_vertex) # simulating in deep ] .. GENERATED FROM PYTHON SOURCE LINES 160-161 We’ll simulate a 5mm patch of activity with -5 dB SNR at the sensor level. The desired level of SNR is achieved by adding white noise to the projected sensor signals .. GENERATED FROM PYTHON SOURCE LINES 161-182 .. code-block:: default # Size of simulated patch of activity (mm) sim_patch_size = 5 # SNR of simulated data (dB) SNR = -5 prefix = f'sim_{sim_vertex}_' # Generate simulated data sim_fname = run_current_density_simulation( base_fname, prefix, sim_vertices, np.vstack([sim_signal1, sim_signal2]), [dipole_moment, dipole_moment], [sim_patch_size, sim_patch_size], SNR, average_trials=True, spm_instance=spm ) .. GENERATED FROM PYTHON SOURCE LINES 183-186 .. image:: ../_static/tutorial_09_sim_consec.png :width: 800 :alt: .. GENERATED FROM PYTHON SOURCE LINES 188-195 **Inversion** Now we’ll run a source reconstruction using the multilayer mesh, select the vertex to examine, extract the source signals at each layer in that location, and compute a laminar CSD *Inversion on the full time window* We will first look at the behavior of inverting the full window with the basic EBB algorithm .. GENERATED FROM PYTHON SOURCE LINES 195-217 .. code-block:: default [_,_, MU] = invert_ebb( sim_fname, surf_set, patch_size=patch_size, n_temp_modes=n_temp_modes, return_mu_matrix= True, spm_instance=spm ) pial_layer_vertices = np.arange(verts_per_surf) pial_layer_ts, time, _ = load_source_time_series( sim_fname, vertices=pial_layer_vertices ) # Peak mean_pial_layer_ts = np.mean(pial_layer_ts,axis=-1) peak = np.argmax(mean_pial_layer_ts) print(f'Simulated vertex={sim_vertex}, Prior vertex={peak}') .. GENERATED FROM PYTHON SOURCE LINES 218-219 We can see that the peak is at the same location we simulated at .. GENERATED FROM PYTHON SOURCE LINES 219-249 .. code-block:: default # Plot colors and camera view max_abs = np.max(np.abs(mean_pial_layer_ts)) c_range = [-max_abs, max_abs] # Plot peak colors,_ = color_map( mean_pial_layer_ts, "RdYlBu_r", c_range[0], c_range[1] ) thresh_colors=np.ones((colors.shape[0],4))*255 thresh_colors[:,:3]=colors thresh_colors[mean_pial_layer_ts` .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: tutorial_09_sliding_window_ebb_layer.ipynb ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_