Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New feature: EEG standardization function #189

Open
christian-oreilly opened this issue Nov 19, 2024 · 1 comment
Open

New feature: EEG standardization function #189

christian-oreilly opened this issue Nov 19, 2024 · 1 comment
Assignees
Labels
enhancement New feature or request
Milestone

Comments

@christian-oreilly
Copy link
Collaborator

I'd like to add a function that allows to standardize the EEG so that it can be easily used to combine datasets with different sampling and spatial frequencies. Uniformizing the sampling frequency can be done easily with the resampling functions from MNE (https://mne.tools/stable/auto_tutorials/preprocessing/30_filtering_resampling.html).

For the spatial resampling, we need to interpolate on a standard EEG montage. The idea here is to

  1. Get original montage (montage1)
  2. Get montage to interpolate to (montage2)
  3. Co-register montage2 with montage1 on a same head surface if these are not already co-registered (not in the code above)
  4. Create a Raw structure containing with flat signals (zeros) for the data associated with montage2
  5. Merge the two montages
  6. Merge the two raw objects and set the raw montage
  7. Flag all the channels from montage2 as 'bad' in the merged raw
  8. Interpolate bad channels
  9. Drop channels from montage 1

This is a snippet of code taken from one of my previous analyses that do more or less that:

    montage_egi = mne.channels.read_dig_fif(str(Path(subjects_dir) / template / "montages" / montage_name_egi))
    montage_egi.ch_names = ["E" + str(int(ch_name[3:])) for ch_name in montage_egi.ch_names]
    montage_egi.ch_names[128] = "Cz"

    raw_egi = preprocessed_raw(path, line_freqs[dataset], montage_egi,
                                rename_channel=False, apply_ica=apply_ica)
    events = process_events_resting_state(raw_egi, dataset, age)
    if events is None:
        return None

    montage_1010 = mne.channels.read_dig_fif(str(Path(subjects_dir) / template / "montages" / montage_name_1010))
    montage_1010.ch_names = ["S" + str(int(ch_name[3:])) for ch_name in montage_1010.ch_names]
    info_1010 = mne.create_info(montage_1010.ch_names, sfreq=500, ch_types="eeg")
    raw_1010 = mne.io.RawArray(np.zeros((len(montage_1010.ch_names), raw_egi.get_data().shape[1])),
                               info_1010, copy=None, verbose=False).set_montage(montage_1010)

    merged_montage = montage_egi + montage_1010
    merged_data = np.vstack([raw_egi.get_data(), raw_1010.get_data()])
    merged_info = mne.create_info(merged_montage.ch_names, sfreq=raw_egi.info["sfreq"], ch_types="eeg")
    merged_info['bads'] = montage_1010.ch_names
    merged_raw = mne.io.RawArray(merged_data, merged_info).set_montage(merged_montage)
    merged_raw = merged_raw.interpolate_bads()

    merged_raw.pick(montage_1010.ch_names)
    merged_raw.set_annotations(raw_egi.annotations)

(not complete and executable in its current form)

As an added bonus, adding this feature will put us in a very good place to close #131

@christian-oreilly christian-oreilly self-assigned this Nov 19, 2024
@christian-oreilly christian-oreilly added the enhancement New feature or request label Nov 19, 2024
@christian-oreilly christian-oreilly added this to the 0.03 milestone Nov 19, 2024
@christian-oreilly
Copy link
Collaborator Author

As pointed out by @scott-huberty, we should consider using the feature implemented in mne-tools/mne-python#13044 whenever this PR merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants