# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. import numpy as np from .._fiff.pick import _picks_to_idx from ..evoked import Evoked from ..utils import _ensure_int, _validate_type, verbose def _temp_proj(ref_2, ref_1, raw_data, n_proj=6): # Orthonormalize gradiometer and magnetometer data by a QR decomposition ref_1_orth = np.linalg.qr(ref_1.T)[0] ref_2_orth = np.linalg.qr(ref_2.T)[0] # Calculate cross-correlation cross_corr = np.dot(ref_1_orth.T, ref_2_orth) # Channel weights for common temporal subspace by SVD of cross-correlation ref_1_ch_weights, _, _ = np.linalg.svd(cross_corr) # Get temporal signals from channel weights proj_mat = ref_1_orth @ ref_1_ch_weights # Project out common subspace filtered_data = raw_data proj_vec = proj_mat[:, :n_proj] weights = filtered_data @ proj_vec filtered_data -= weights @ proj_vec.T @verbose def cortical_signal_suppression( evoked, picks=None, mag_picks=None, grad_picks=None, n_proj=6, *, verbose=None ): """Apply cortical signal suppression (CSS) to evoked data. Parameters ---------- evoked : instance of Evoked The evoked object to use for CSS. Must contain magnetometer, gradiometer, and EEG channels. %(picks_good_data)s mag_picks : array-like of int Array of the first set of channel indices that will be used to find the common temporal subspace. If None (default), all magnetometers will be used. grad_picks : array-like of int Array of the second set of channel indices that will be used to find the common temporal subspace. If None (default), all gradiometers will be used. n_proj : int The number of projection vectors. %(verbose)s Returns ------- evoked_subcortical : instance of Evoked The evoked object with contributions from the ``mag_picks`` and ``grad_picks`` channels removed from the ``picks`` channels. Notes ----- This method removes the common signal subspace between two sets of channels (``mag_picks`` and ``grad_picks``) from a set of channels (``picks``) via a temporal projection using ``n_proj`` number of projection vectors. In the reference publication :footcite:`Samuelsson2019`, the joint subspace between magnetometers and gradiometers is used to suppress the cortical signal in the EEG data. In principle, other combinations of sensor types (or channels) could be used to suppress signals from other sources. References ---------- .. footbibliography:: """ _validate_type(evoked, Evoked, "evoked") n_proj = _ensure_int(n_proj, "n_proj") picks = _picks_to_idx(evoked.info, picks, none="data", exclude="bads") mag_picks = _picks_to_idx(evoked.info, mag_picks, none="mag", exclude="bads") grad_picks = _picks_to_idx(evoked.info, grad_picks, none="grad", exclude="bads") evoked_subcortical = evoked.copy() # Get data all_data = evoked.data mag_data = all_data[mag_picks] grad_data = all_data[grad_picks] # Process data with temporal projection algorithm data = all_data[picks] _temp_proj(mag_data, grad_data, data, n_proj=n_proj) evoked_subcortical.data[picks, :] = data return evoked_subcortical