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

All EEG and EOG channels have type 'ecg' when reading HCP data using read_raw_bti() #10988

Closed
ckiefer0 opened this issue Aug 2, 2022 · 6 comments · Fixed by #11102
Closed
Assignees
Labels
Milestone

Comments

@ckiefer0
Copy link

ckiefer0 commented Aug 2, 2022

This bug report is based on this discussion in the MNE group.

I am using MNE and MNE-HCP to analyze HCP data. When I use the following function to read the HCP data, all ECG, EOG, and EEG channels have type 'ecg':

files = hcp.file_mapping.get_file_paths(subject=subj, data_type=datatype,
                                        output='raw', hcp_path=hcp_dir, run_index=run_index)
# read the raw data
raw = mne.io.read_raw_bti(files[0], head_shape_fname=None, convert=False, preload=True)

The same also happens when I simply use hcp.read_raw(). Here are the info files for the two variants.

mne.io.read_raw_bti:

<Info | 8 non-empty values
bads: []
ch_names: MEG 001, MEG 002, MEG 003, MEG 004, MEG 005, MEG 006, MEG 007, ...
chs: 248 Magnetometers, 2 Stimulus, 23 Reference Magnetometers, 13 ECG, 1 misc
custom_ref_applied: False
dev_ctf_t: CTF MEG device -> CTF/4D/KIT head transform
highpass: 0.0 Hz
lowpass: 1017.3 Hz
meas_date: 2014-05-21 14:38:37 UTC
nchan: 287
projs: []
sfreq: 2034.5 Hz

hcp.read_raw:

<Info | 8 non-empty values
bads: []
ch_names: TRIGGER, RESPONSE, MLzA, MLyA, MLzaA, MLyaA, MLxA, A22, MLxaA, ...
chs: 2 Stimulus, 23 Reference Magnetometers, 248 Magnetometers, 13 ECG, 1 misc
custom_ref_applied: False
dev_ctf_t: CTF MEG device -> CTF/4D/KIT head transform
highpass: 0.0 Hz
lowpass: 1017.3 Hz
meas_date: 2014-05-21 14:38:37 UTC
nchan: 287
projs: []
sfreq: 2034.5 Hz

Furthermore, when using mne.io.read_raw_bti(), the ECG+ and ECG- channels are not named correctly anymore. I am currently using these functions as a workaround:


def _set_custom_ref_to_off(raw):

    from mne.io.constants import FIFF
    with raw.info._unlock():
        raw.info['custom_ref_applied'] = FIFF.FIFFV_MNE_CUSTOM_REF_OFF


def set_ecg_eog_channels(raw):
    """
    Set correct channel type for EEG/ECG/EOG channels and re-reference
    ECG, VEOG, and HEOG channels using a bipolar referencing scheme.

    Operates in place.
    """
    # somehow all channels have type ECG -> set to EEG first
    ecg_picks = mne.pick_types(raw.info, ecg=True)
    for pick in ecg_picks:
        ch_name = raw.info['ch_names'][pick]
        raw.set_channel_types({ch_name: 'eeg'})

    # set correct channel names for ECG
    ecg_ch_mapping = {'EEG 001': 'ECG+', 'EEG 004': 'ECG-'}
    mne.channels.rename_channels(raw.info, ecg_ch_mapping)

    # combine ECG+/-, VEOG+/-, and HEOG+/- into three channels
    # and set appropriate channel types
    hcp.preprocessing.set_eog_ecg_channels(raw)

    # hcp.preprocessing.set_eog_ecg_channels() results in flag custom_ref_applied
    # being set to True -> set back to False to avoid errors
    # when calling mne.minimum_norm.apply_inverse_raw()
    _set_custom_ref_to_off(raw)

Versions:
MNE-HCP: 0.1.dev12
MNE: 1.03

@ckiefer0 ckiefer0 added the BUG label Aug 2, 2022
@larsoner larsoner added this to the 1.2 milestone Aug 3, 2022
@larsoner larsoner self-assigned this Aug 3, 2022
@larsoner
Copy link
Member

@ckiefer0 can you share a problematic file with me?

@larsoner
Copy link
Member

For the mne-hcp stuff you should open an issue in that repo. So here let's concentrate on the MNE-Python stuff.

Furthermore, when using mne.io.read_raw_bti(), the ECG+ and ECG- channels are not named correctly anymore

If I do:

import mne
raw = mne.io.read_raw_bti('3-restin/4D/c,rfDC', head_shape_fname=None, convert=False, rename_channels=False)
ch_types = dict()
for kind, ch_name in zip(raw.get_channel_types(), raw.ch_names):
    if kind in ('mag', 'ref_meg'):
        continue
    ch_types[kind] = ch_types.get(kind, list()) + [ch_name]
for key, val in ch_types.items():
    print(f'{key}: {val}')

I get:

stim: ['TRIGGER', 'RESPONSE']
ecg: ['SA1', 'SA2', 'SA3', 'ECG+', 'VEOG+', 'HEOG+', 'EMG_LF', 'EMG_LH', 'ECG-', 'VEOG-', 'HEOG-', 'EMG_RF', 'EMG_RH']
misc: ['UACurrent']

so at least the ECG channels seem to be named correctly if you pass rename_channels=False.

For the others that are clearly something else (I think!), I've opened #11102 . I think that covers what we need to change in MNE-Python, but let me know if you disagree @ckiefer0 !

@ckiefer0
Copy link
Author

@larsoner The changes in #11102 look good. I just have one question: Why are the two ECG channels renamed from ECG+ and ECG- to EEG 001 and EEG 004 when using rename_channels=True? Isn't ECG+ and ECG- much more meaningful especially since the EOG channels get to keep their names.

PS: I wasn't sure whether to reply here or in #11102.

@larsoner
Copy link
Member

Why are the two ECG channels renamed from ECG+ and ECG- to EEG 001 and EEG 004 when using rename_channels=True?

This seems like a bug. Want to try fixing it? It seems like only channels marked as EEG should get renamed using EEG names. The EOG ones should probably be EOG 001..., ECG as ECG 001..., etc.

@ckiefer0
Copy link
Author

I see. But why not keep the +/- naming? Then it would be immediately clear that there is a cathode/anode pair and for EOG you would immediately know whether it is a vertical or horizontal channel. Furthermore, it would help with compatibility with mne-hcp since one could use the following mne-hcp.preprocessing function without any further renaming:

def set_eog_ecg_channels(raw):
    """Set the HCP ECG and EOG channels

    .. note::
       Operates in place.

    Parameters
    ----------
    raw : instance of Raw
        the hcp raw data.
    """
    for kind in ['ECG', 'VEOG', 'HEOG']:
        set_bipolar_reference(
            raw, anode=kind + '-', cathode=kind + '+', ch_name=kind,
            copy=False)
    raw.set_channel_types({'ECG': 'ecg', 'VEOG': 'eog', 'HEOG': 'eog'})

@larsoner
Copy link
Member

I see. But why not keep the +/- naming?

The idea behind rename_channels IIRC was to give them Neurmag-like names. The closest would be ECG 001-style names I think.

Personally I would use rename_channels=False all the time nowadays

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Development

Successfully merging a pull request may close this issue.

2 participants