Source code for eegunity.utils.channel_align_raw

import numpy as np
import mne
from eegunity.modules.parser.eeg_parser import set_montage_any


[docs] def channel_align_raw(mne_raw, channel_order, min_matched_channel=1): """ Aligns and orders the channels of an MNE Raw object according to a specified channel order. This function ensures that the channels in the raw MNE object are aligned and ordered according to the specified `channel_order`. If some channels from `channel_order` are missing in the raw data, they will be added with zero values and later interpolated. Parameters ---------- mne_raw : mne.io.Raw The raw EEG/MEG data in an MNE Raw object. channel_order : list of str The desired order of channels. min_matched_channel : int, optional The minimum required number of matched channels, by default 1. Returns ------- mne.io.Raw The modified raw object with channels aligned and missing channels interpolated. Raises ------ ValueError If the number of matched channels is less than `min_matched_channel`. Notes ----- - The function picks and reorders the matched channels to match `channel_order`. - If some channels from `channel_order` are missing in `mne_raw`, they are added as zero data channels and interpolated. - The missing channels are first marked as 'bad' before interpolation. Examples -------- >>> import mne >>> raw = mne.io.read_raw_fif('sample_raw.fif', preload=True) >>> desired_order = ['Fp1', 'Fp2', 'F3', 'F4', 'C3', 'C4', 'P3', 'P4', 'O1', 'O2'] >>> aligned_raw = channel_align_raw(raw, desired_order, min_matched_channel=5) """ # Get existing channels in the raw object existing_channels = mne_raw.ch_names # Find the matched channels between the raw data and the desired channel order matched_channels = [ch for ch in channel_order if ch in existing_channels] # If the number of matched channels is less than the minimum required, raise an error if len(matched_channels) < min_matched_channel: raise ValueError( f"Error: Matched channels ({len(matched_channels)}) are less than the required minimum ({min_matched_channel})") # If there are missing channels in the raw data, handle them if len(matched_channels) < len(channel_order): missing_channels = [ch for ch in channel_order if ch not in existing_channels] mne_raw.load_data() # Create minimal info for the missing channels (only basic info required) missing_info = mne.create_info(missing_channels, sfreq=mne_raw.info['sfreq'], ch_types='eeg') # Create the missing channels with zero data missing_raw = mne.io.RawArray(np.zeros((len(missing_channels), len(mne_raw.times))), missing_info) # Add the missing channels to the raw data mne_raw.add_channels([missing_raw], force_update_info=True) # Use set_montage_any to add the montage (coordinates) for missing channels mne_raw = set_montage_any(mne_raw, verbose='CRITICAL') # Manually mark the missing channels as 'bads' so they can be interpolated mne_raw.info['bads'].extend(missing_channels) # Interpolate missing channels mne_raw.interpolate_bads(reset_bads=True, origin='auto', method=dict(meg="MNE", eeg="MNE", fnirs="nearest")) # Pick the matched channels and ensure the correct order mne_raw.pick_channels(matched_channels) mne_raw.reorder_channels(matched_channels) # Ensures the channels are in the specified order return mne_raw