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

[Feature Request] expose original units for each channel in BaseRaw #5607

Closed
sappelhoff opened this issue Oct 13, 2018 · 8 comments · Fixed by #5633
Closed

[Feature Request] expose original units for each channel in BaseRaw #5607

sappelhoff opened this issue Oct 13, 2018 · 8 comments · Fixed by #5633

Comments

@sappelhoff
Copy link
Member

Upon reading a raw data file, MNE-Python converts the units to e.g., Volts (and others, see here).

It would be good to expose the channel wise units as they are in the original data file within the BaseRaw object.

Concretely, we need this in MNE-BIDS, see: mne-tools/mne-bids#81

@agramfort
Copy link
Member

agramfort commented Oct 13, 2018 via email

@sappelhoff
Copy link
Member Author

sappelhoff commented Oct 14, 2018

for EEG:

  • BrainVision (.vhdr / .vmrk / .eeg)
  • EDF / BDF
  • Neuroscan (.cnt)
  • EEGLAB (.set / .fdt)

for MEG it depends a bit. In BIDS, all MEG file formats are accepted (i.e., no restrictions like we have in EEG). So for MEG, we need the requested feature for all file formats, that natively save data in a unit that is different from the one that MNE-Python converts to.

@agramfort
Copy link
Member

agramfort commented Oct 14, 2018 via email

@sappelhoff
Copy link
Member Author

sappelhoff commented Oct 14, 2018

both would be fine, but a read_xxx_header public function could potentially return a lot more information and could be helpful for other issues as well.

On the other hand, this would mean many new functions (one per data format), while making the information available in BaseRaw would only need adding a few private lines of code within each data reader in the IO module.

Are you more inclined to having a read_xxx_header function for each data format?

@larsoner
Copy link
Member

read_xxx_header would probably require refactoring raw readers and, probably more annoyingly, introducing a bunch of otherwise unnecessary public functions. After all, read_xxx_raw(..., preload=False) is already very close to what the read_xxx_header would do and raw.info is very close to what it would return (though also annoyingly, not quite identical because it would also need to give the original channel types). So I don't see the point of a separate function, it seems cleaner to expose a raw._orig_units or something that is used only by BIDS.

@agramfort
Copy link
Member

agramfort commented Oct 14, 2018 via email

@sappelhoff
Copy link
Member Author

sappelhoff commented Oct 19, 2018

Listing the lines of the respective data readers, from where the original units could be forwarded to some _orig_units attribute.

BrainVision

if len(props) < 4:
props += (u'µV',)
name, _, resolution, unit = props[:4]
ch_dict[chan] = name
ch_names[n] = name
if resolution == "":
if not(unit): # For truncated vhdrs (e.g. EEGLAB export)
resolution = 0.000001

EDF

units = [fid.read(8).strip().decode() for ch in channels]

Neuroscan

... seems to be a bit more complicated than BrainVision and EDF ... no units, but "sensitivity" and "cal" (=calibration?):

for ch_idx in range(n_channels): # ELECTLOC fields
fid.seek(data_offset + 75 * ch_idx)
ch_name = read_str(fid, 10)
ch_names.append(ch_name)
fid.seek(data_offset + 75 * ch_idx + 4)
if np.fromfile(fid, dtype='u1', count=1)[0]:
bads.append(ch_name)
fid.seek(data_offset + 75 * ch_idx + 19)
xy = np.fromfile(fid, dtype='f4', count=2)
xy[1] *= -1 # invert y-axis
pos.append(xy)
fid.seek(data_offset + 75 * ch_idx + 47)
# Baselines are subtracted before scaling the data.
baselines.append(np.fromfile(fid, dtype='i2', count=1)[0])
fid.seek(data_offset + 75 * ch_idx + 59)
sensitivity = np.fromfile(fid, dtype='f4', count=1)[0]
fid.seek(data_offset + 75 * ch_idx + 71)
cal = np.fromfile(fid, dtype='f4', count=1)
cals.append(cal * sensitivity * 1e-6 / 204.8)

EEGLAB

... I can't find a "unit" field in the EEGLAB file structure ... it might be that it's not given and that the units are implicitly thought to all be in microVolts, see: https://sccn.ucsd.edu/pipermail/eeglablist/2014/008004.html

@agramfort
Copy link
Member

agramfort commented Oct 19, 2018 via email

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

Successfully merging a pull request may close this issue.

3 participants