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

store digitization for (non-existing) reference channel(s) #1012

Open
dominikwelke opened this issue Jun 8, 2022 · 6 comments
Open

store digitization for (non-existing) reference channel(s) #1012

dominikwelke opened this issue Jun 8, 2022 · 6 comments

Comments

@dominikwelke
Copy link
Contributor

dominikwelke commented Jun 8, 2022

Describe the problem

hi all,

I noticed that it is not straight forward to store the digitization for an EEG reference channel if this channel is not present in the raw recorded data (as is the case for my raw data recorded with brainvision recorder).

while it makes sense to only store digitization points for channels that are present, it still feels like a minor bug to me.
in the end, the digitization for the ref channel(s) was recorded and would be lost when sharing the raw BIDS formatted data.

Describe your solution

it is possible to acchieve storage of the ref channel location(s) by first adding an empty ref channel to the raw data, and then attaching the montage:

raw = mne.io.read_raw_Brainvision('path/to/file', preload=True)
raw.add_reference_channels('myEEGRef')

montage = mne.channels.make_dig_montage(digiargs)  
raw.set_montage(montage)

write_raw_bids(
        raw,
        bids_path='bids/path',
        allow_preload=True, format='BrainVision')

however, this requires preloading, changes the data and is hence not optimal.
also, in my case of brainvision-recorder-files, the comments in the header (including impedance measures etc) are lost this way.

Describe possible alternatives

what do you think, is there an easy way to support this?

@adam2392
Copy link
Member

adam2392 commented Jun 8, 2022

I haven't dealt much with needing to store reference chs, can you educate us a bit on what the purpose of storing an empty reference channel is in *channels.tsv BIDS files?

@sappelhoff
Copy link
Member

Is the reference channel listed in the VHDR file? To my knowledge it might show up under "impedances", but not otherwise 🤔 Do you have a [Coordinates] section in your VHDR file? Or is the montage from elsewhere (e.g., a CapTrak file)?

re: impedances: These are parsed and saved to electrodes.tsv via BIDS, but I understand that it's undesirable to not have them in the VHDR anymore (albeit not really bad)

apart from this: I think there was a discussion once whether tracking EEG reference channels in mne-python might be possible. It'd be quite nice also to fill the EEGReference metadata in BIDS

@hoechenberger
Copy link
Member

It'd be quite nice also to fill the EEGReference metadata in BIDS

👍

@dominikwelke
Copy link
Contributor Author

dominikwelke commented Jun 8, 2022

I haven't dealt much with needing to store reference chs, can you educate us a bit on what the purpose of storing an empty reference channel is in *channels.tsv BIDS files?

Do you have a [Coordinates] section in your VHDR file? Or is the montage from elsewhere (e.g., a CapTrak file)?

@sappelhoff : yes, I recorded channel positions (with a polhemus fasttrack device, in this case). sorry if this didnt come through!
@adam2392 : this mainly becomes relevant if you apply e.g. common average reference down the line, as this will "restore" the data of the empty reference channel to the average of all other channels. in my case, i would then have one channel (the restored ref channel) without coordinates, even though these have been recorded.

Is the reference channel listed in the VHDR file? To my knowledge it might show up under "impedances", but not otherwise 🤔

It'd be quite nice also to fill the EEGReference metadata in BIDS

well, in my case the ref is listed in the "Amplifier Setup" section, but not otherwise (brainvision recorder V. 1.23.0003). the impedance list only holds the name of the ref channel (not marked as ref) and Gnd without location/position name.

A m p l i f i e r  S e t u p
============================
Number of channels: 65
Sampling Rate [Hz]: 1000
Sampling Interval [µS]: 1000

Channels
--------
#     Name      Phys. Chn.    Resolution / Unit   Low Cutoff [s]   High Cutoff [Hz]   Notch [Hz]    Gradient         Offset
1     Fp1         1          0.0488281 µV             DC              280              Off
2     Fp2         2          0.0488281 µV             DC              280              Off
(...)

Reference Channel Name = FCz
Reference Phys. Chn.   = 28
Use active/dry Electrodes = Yes 
Good Level [kOhms]     = 10
Bad Level [kOhms]      = 50
(...)

here is a full example header file (masked as .txt for upload):
sub-00_task-aeAHA_eeg.vhdr

i found this curious, because if I read the header correctly i'd also expect the Ref to be listed in the Channel info for each channel

[Channel Infos]
; Each entry: Ch<Channel number>=<Name>,<Reference channel name>,
; <Resolution in "Unit">,<Unit>, Future extensions..
; Fields are delimited by commas, some fields might be omitted (empty).
; Commas in channel names are coded as "\1".
Ch1=Fp1,,0.0488281,µV
Ch2=Fp2,,0.0488281,µV
(...)

above, you see the reference channel value is empty (same for all my channels), even though the recorder obviously had this information..

by the way, i just noticed that the procedure i described above (preloading data, adding ref and montage, writing BIDS from MNE object) does change another thing besides omitting the additional info from the header:
the "Resolution" entries of the channels are changed (in my case to 0.1 across the bench). the above section in the .vhdr file now reads:

[Channel Infos]
; Each entry: Ch<Channel number>=<Name>,<Reference channel name>,
; <Resolution in "Unit">,<Unit>, Future extensions..
; Fields are delimited by commas, some fields might be omitted (empty).
; Commas in channel names are coded as "\1".
Ch1=Fp1,,0.1,µV
Ch2=Fp2,,0.1,µV
(...)

re: impedances: These are parsed and saved to electrodes.tsv via BIDS, but I understand that it's undesirable to not have them in the VHDR anymore (albeit not really bad)

good to know, thanks! it even takes the correct impedance for the recently added ref channel!

apart from this: I think there was a discussion once whether tracking EEG reference channels in mne-python might be possible.

yes, i also saw this: mne-tools/mne-python#8962

@sappelhoff
Copy link
Member

yes, I recorded channel positions (with a polhemus fasttrack device, in this case). sorry if this didnt come through!

It did come through - thanks for the info on the used device -- I was most interested whether you also got the coordinates to show up in the VHDR file itself ... as opposed to having a separate polhemus file with the coordinates.

in my case the ref is listed in the "Amplifier Setup" section, but not otherwise (brainvision recorder V. 1.23.0003)

damn these headers really differ a lot in terms of included information by used software, hardware, and their versions

here is a full example header file (masked as .txt for upload):

I think you (accidentally?) posted the pybv converted header :)

the "Resolution" entries of the channels are changed

yes, that's to be expected based on our code, it's a precaution against loss of precision:

  • it's a benign change
  • mne-bids/mne_bids/write.py

    Lines 1001 to 1013 in 2c1cdea

    # We enforce conversion to float32 format
    # XXX: pybv can also write to int16, to do that, we need to get
    # original units of data prior to conversion, and add an optimization
    # function to pybv that maximizes the resolution parameter while
    # ensuring that int16 can represent the data in original units.
    if raw.orig_format != 'single':
    warn(f'Encountered data in "{raw.orig_format}" format. '
    f'Converting to float32.', RuntimeWarning)
    # Writing to float32 µV with 0.1 resolution are the pybv defaults,
    # which guarantees accurate roundtrip for values >= 1e-7 µV
    fmt = 'binary_float32'
    resolution = 1e-1
  • but it could be optimized (in pybv)

overall I am not sure what we could practically do right now.

@dominikwelke
Copy link
Contributor Author

I think you (accidentally?) posted the pybv converted header :)

urgs, sorry!
sub-00_task-aeAHA_eeg.vhdr

no coordinates in the vhdr file

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

No branches or pull requests

4 participants