Repository: mne-tools/mne-bids

Issue:
BIDS channel type issue
bids_path = BIDSPath(root='../ds003061')

Channels 65 to 79 are not EEG (and marked as such in the BIDS repo). Yet MNE thinks 2 of these channels are EEG.

https://openneuro.org/datasets/ds003061


Discussion:
Hello! 👋 Thanks for opening your first issue here! ❤️ We will try to get back to you soon. 🚴🏽‍♂️

Hi @arnodelorme

Is this an error when you read the file? BIDSPath is just a class for creating file paths in bids datasets. I'm guessing maybe when you run read_raw_bids(?)

is it possible for you to upload a code segment and also the MNE and related package versions? E.g. a Minimal working example for the error. 

output of 'mne sys_info' will show you the relevant versions. 
Hi @arnodelorme

Is this an error when you read the file? BIDSPath is just a class for creating file paths in bids datasets. I'm guessing maybe when you run read_raw_bids(?)

is it possible for you to upload a code segment and also the MNE and related package versions? E.g. a Minimal working example for the error. 

output of 'mne sys_info' will show you the relevant versions. 
Of course

```python
import os
import os.path as op
import mne
from mne.datasets import sample
from mne_bids import BIDSPath, read_raw_bids, print_dir_tree, make_report, inspect_dataset, mark_channels

bids_path = BIDSPath(root='ds003061', datatype='eeg', suffix = 'eeg')
res = bids_path.match()
rawraw = read_raw_bids(bids_path=res[0], verbose=False)
```

ds003061 is available from https://openneuro.org/datasets/ds003061
Sys info

```

Platform:         macOS-10.16-x86_64-i386-64bit
Python:           3.8.5 (default, Sep  4 2020, 02:22:02)  [Clang 10.0.0 ]
Executable:       /Users/arno/miniconda3/envs/p38env/bin/python
CPU:              i386: 16 cores
Memory:           Unavailable (requires "psutil" package)
mne:              1.1.0
numpy:            1.19.2 {blas=mkl_rt, lapack=mkl_rt}
scipy:            1.4.1
matplotlib:       3.3.3 {backend=module://ipykernel.pylab.backend_inline}

sklearn:          0.24.1
numba:            Not found
nibabel:          Not found
nilearn:          Not found
dipy:             Not found
cupy:             Not found
pandas:           1.2.1
pyvista:          Not found
pyvistaqt:        Not found
ipyvtklink:       Not found
vtk:              Not found
qtpy:             Not found
ipympl:           Not found
pyqtgraph:        Not found
pooch:            v1.6.0

mne_bids:         0.10
mne_nirs:         Not found
mne_features:     Not found
mne_qt_browser:   Not found
mne_connectivity: Not found
mne_icalabel:     Not found   
```
@arnodelorme 
`*_channels.tsv` (and `_electrodes.tsv`) only contain a small subset of the channels present in the data. Hence, I would argue that the dataset is corrupted or incomplete, and the only reason the BIDS validator doesn't complain is because it lacks that capability of actually loading and inspecting the data.

One could argue that MNE-BIDS should handle things more gracefully here (or raise an exception); but ultimately I'd say the dataset needs to be fixed.

> and marked as such in the BIDS repo

But where?

And which are the problematic channels, exactly?

Here's a MWE:
```python
# %%

# Data downloaded via:
#     openneuro-py download --dataset ds003061 --include sub-001

import mne_bids

bp = mne_bids.BIDSPath(
    root='/tmp/ds003061',
    subject='001',
    task='P300',
    run='1',
    datatype='eeg',
    suffix='eeg',
    extension='.set',
)
raw = mne_bids.read_raw_bids(bp)

for ch_name in raw.ch_names:
    ch_type = raw.get_channel_types(ch_name)[0]
    ch_idx = raw.ch_names.index(ch_name)
    print(f'{ch_idx:<5} {ch_name:<6} {ch_type}')
```
yields:
```
0     Fp1    eeg
1     AF7    eeg
2     AF3    eeg
3     F1     eeg
4     F3     eeg
5     F5     eeg
6     F7     eeg
7     FT7    eeg
8     FC5    eeg
9     FC3    eeg
10    FC1    eeg
11    C1     eeg
12    C3     eeg
13    C5     eeg
14    T7     eeg
15    TP7    eeg
16    CP5    eeg
17    CP3    eeg
18    CP1    eeg
19    P1     eeg
20    P3     eeg
21    P5     eeg
22    P7     eeg
23    P9     eeg
24    PO7    eeg
25    PO3    eeg
26    O1     eeg
27    Iz     eeg
28    Oz     eeg
29    POz    eeg
30    Pz     eeg
31    CPz    eeg
32    Fpz    eeg
33    Fp2    eeg
34    AF8    eeg
35    AF4    eeg
36    AFz    eeg
37    Fz     eeg
38    F2     eeg
39    F4     eeg
40    F6     eeg
41    F8     eeg
42    FT8    eeg
43    FC6    eeg
44    FC4    eeg
45    FC2    eeg
46    FCz    eeg
47    Cz     eeg
48    C2     eeg
49    C4     eeg
50    C6     eeg
51    T8     eeg
52    TP8    eeg
53    CP6    eeg
54    CP4    eeg
55    CP2    eeg
56    P2     eeg
57    P4     eeg
58    P6     eeg
59    P8     eeg
60    P10    eeg
61    PO8    eeg
62    PO4    eeg
63    O2     eeg
64    EXG1   misc
65    EXG2   misc
66    EXG3   misc
67    EXG4   misc
68    EXG5   misc
69    EXG6   misc
70    EXG7   misc
71    EXG8   misc
72    GSR1   eeg
73    GSR2   eeg
74    Erg1   misc
75    Erg2   misc
76    Resp   resp
77    Plet   misc
78    Temp   eeg
```
Yes, but this is the actual file. You can see that GSR1 and 2 have the type GSR and that TEMP has the type TEMP which are regular BIDS types.

https://openneuro.org/datasets/ds003061/versions/1.1.1/file-display/sub-001:eeg:sub-001_task-P300_run-1_channels.tsv

```
name	type	units
Fp1	EEG	microV
AF7	EEG	microV
AF3	EEG	microV
F1	EEG	microV
F3	EEG	microV
F5	EEG	microV
F7	EEG	microV
FT7	EEG	microV
FC5	EEG	microV
FC3	EEG	microV
FC1	EEG	microV
C1	EEG	microV
C3	EEG	microV
C5	EEG	microV
T7	EEG	microV
TP7	EEG	microV
CP5	EEG	microV
CP3	EEG	microV
CP1	EEG	microV
P1	EEG	microV
P3	EEG	microV
P5	EEG	microV
P7	EEG	microV
P9	EEG	microV
PO7	EEG	microV
PO3	EEG	microV
O1	EEG	microV
Iz	EEG	microV
Oz	EEG	microV
POz	EEG	microV
Pz	EEG	microV
CPz	EEG	microV
Fpz	EEG	microV
Fp2	EEG	microV
AF8	EEG	microV
AF4	EEG	microV
AFz	EEG	microV
Fz	EEG	microV
F2	EEG	microV
F4	EEG	microV
F6	EEG	microV
F8	EEG	microV
FT8	EEG	microV
FC6	EEG	microV
FC4	EEG	microV
FC2	EEG	microV
FCz	EEG	microV
Cz	EEG	microV
C2	EEG	microV
C4	EEG	microV
C6	EEG	microV
T8	EEG	microV
TP8	EEG	microV
CP6	EEG	microV
CP4	EEG	microV
CP2	EEG	microV
P2	EEG	microV
P4	EEG	microV
P6	EEG	microV
P8	EEG	microV
P10	EEG	microV
PO8	EEG	microV
PO4	EEG	microV
O2	EEG	microV
EXG1	MISC	n/a
EXG2	MISC	n/a
EXG3	MISC	n/a
EXG4	MISC	n/a
EXG5	MISC	n/a
EXG6	MISC	n/a
EXG7	MISC	n/a
EXG8	MISC	n/a
GSR1	GSR	n/a
GSR2	GSR	n/a
Erg1	MISC	n/a
Erg2	MISC	n/a
Resp	RESP	n/a
Plet	MISC	n/a
Temp	TEMP	n/a
```
> Yes, but this is the actual file. You can see that GSR1 and 2 have the type GSR and that TEMP has the type TEMP which are regular BIDS types.
> 
> https://openneuro.org/datasets/ds003061/versions/1.1.1/file-display/sub-001:eeg:sub-001_task-P300_run-1_channels.tsv

Oh, right.

I only looked at the TSV in my web browser and didn't realize there was a scrollbar on the right, so I only saw the first few channels 🤦 
We currently use the following channel type mapping from BIDS to MNE:
https://github.com/mne-tools/mne-bids/blob/16a7b0c1a4348256f6781f539cd82c0acf444de3/mne_bids/utils.py#L77-L83

We need to add `TEMP` and `GSR` here.

I don't believe MNE has "proper" support for these, so we should map them to `misc`.
@larsoner @agramfort WDYT?

@sappelhoff I don't think we should silently apply the BIDS datatype's channel type to channels for which we don't have a proper BIDS -> MNE mapping defined; instead, we should default to `misc`. WDYT?
> RESP='resp',

Either this is a bug, or we have incorrect documentation in MNE – `RESP` is **not** "respiration"

https://github.com/mne-tools/mne-python/blob/8baaa7675ea34d3b98dd2875ad8b5efaf6d44d16/mne/io/pick.py#L400-L402

We'd need to check the FIFF specs.
… says "respiration monitoring" here:

https://github.com/mne-tools/fiff-constants/blob/30d89d420d50c9e465f46524d4901795dac66741/DictionaryTypes.txt#L257

@larsoner What's correct now..? Is "resp" for "response" or for "respiration"?
for some reason my answer from yesterday never appeared here. Let me paste it here:

this data contains channels with type "temp" and "GSR"

I don't think its part of the standard. Cf https://bids-specification.readthedocs.io/en/stable/04-modality-specific-files/03-electroencephalography.html#channels-description-_channelstsv

Type of channel; MUST use the channel types listed below. Note that the type MUST be in upper-case.  

Must be one of: "MEGMAG", "MEGGRADAXIAL", "MEGGRADPLANAR", "MEGREFMAG", "MEGREFGRADAXIAL", "MEGREFGRADPLANAR", "MEGOTHER", "EEG", "ECOG", "SEEG", "DBS", "VEOG", "HEOG", "EOG", "ECG", "EMG", "TRIG", "AUDIO", "PD", "EYEGAZE", "PUPIL", "MISC", "SYSCLOCK", "ADC", "DAC", "HLU", "FITERR", "OTHER".

mne_bids converts them to EEG when it does not understand the type. You should get warnings when attempting to read the files with:

```python
from mne_bids import BIDSPath, read_raw_bids

bp = BIDSPath(
    root='./',
    subject='001',
    task='P300',
    run='1',
    datatype='eeg',
    suffix='eeg',
    extension='.set',
)

raw = read_raw_bids(bp)
```
> I don't think its part of the standard.


It is, you need to scroll down a little:

![image](https://user-images.githubusercontent.com/2046265/183889941-a7ec7d3d-16f7-4426-9960-6fb6aeb3d6bb.jpeg)


> @larsoner What's correct now..? Is "resp" for "response" or for "respiration"?

the `fif-constants` should be the gold standard, and it's "respiration" there, too:

https://github.com/mne-tools/fiff-constants/blob/aae5960007ee8a67dfc07535ea37d421d37dfe1b/DictionaryTypes.txt#L257

So our docs are wrong, can you make a quick PR to fix them?
Thanks @larsoner! I already fixed this a few days ago, I don't have the PR id at und right now though, as I'm on my phone 
Okay great!
next channel type we should add is temp (temperature in celsius)

> Message ID: ***@***.***>
>

@arnodelorme 
With #1052, we now set the type of all "unknown" and yet-unsupported BIDS channel types to "misc" when reading the data with MNE-BIDS.

This ensures that the temperature and GSR channels in your dataset will not show up as "eeg" channels anymore (but as "misc").

The next step for us is to amend the FIFF standard and add a proper EDA/GSR and temperature channel type. We're tracking this at https://github.com/mne-tools/mne-python/issues/11055
Wonderful. Thanks



Resolving patch:
diff --git a/mne_bids/config.py b/mne_bids/config.py
--- a/mne_bids/config.py
+++ b/mne_bids/config.py
@@ -31,7 +31,7 @@
     '.sqd': 'KitYokogawa',
 }
 
-UNITS = {
+EXT_TO_UNIT_MAP = {
     '.con': 'm',
     '.ds': 'cm',
     '.fif': 'm',
@@ -39,6 +39,10 @@
     '.sqd': 'm'
 }
 
+UNITS_MNE_TO_BIDS_MAP = {
+    'C': 'oC',  # temperature in deg. C
+}
+
 meg_manufacturers = {
     '.con': 'KIT/Yokogawa',
     '.ds': 'CTF',
diff --git a/mne_bids/utils.py b/mne_bids/utils.py
--- a/mne_bids/utils.py
+++ b/mne_bids/utils.py
@@ -66,7 +66,8 @@ def _get_ch_type_mapping(fro='mne', to='bids'):
     if fro == 'mne' and to == 'bids':
         mapping = dict(eeg='EEG', misc='MISC', stim='TRIG', emg='EMG',
                        ecog='ECOG', seeg='SEEG', eog='EOG', ecg='ECG',
-                       resp='RESP', bio='MISC', dbs='DBS',
+                       resp='RESP', bio='MISC', dbs='DBS', gsr='GSR',
+                       temperature='TEMP',
                        # NIRS
                        fnirs_cw_amplitude='NIRSCWAMPLITUDE',
                        # MEG channels
@@ -78,7 +79,7 @@ def _get_ch_type_mapping(fro='mne', to='bids'):
     elif fro == 'bids' and to == 'mne':
         mapping = dict(EEG='eeg', MISC='misc', TRIG='stim', EMG='emg',
                        ECOG='ecog', SEEG='seeg', EOG='eog', ECG='ecg',
-                       RESP='resp',
+                       RESP='resp', GSR='gsr', TEMP='temperature',
                        # NIRS
                        NIRSCWAMPLITUDE='fnirs_cw_amplitude',
                        NIRS='fnirs_cw_amplitude',
diff --git a/mne_bids/write.py b/mne_bids/write.py
--- a/mne_bids/write.py
+++ b/mne_bids/write.py
@@ -51,12 +51,13 @@
 from mne_bids.read import _find_matching_sidecar, _read_events
 from mne_bids.sidecar_updates import update_sidecar_json
 
-from mne_bids.config import (ORIENTATION, UNITS, MANUFACTURERS,
+from mne_bids.config import (ORIENTATION, EXT_TO_UNIT_MAP, MANUFACTURERS,
                              IGNORED_CHANNELS, ALLOWED_DATATYPE_EXTENSIONS,
                              BIDS_VERSION, REFERENCES, _map_options, reader,
                              ALLOWED_INPUT_EXTENSIONS, CONVERT_FORMATS,
                              ANONYMIZED_JSON_KEY_WHITELIST, PYBV_VERSION,
-                             BIDS_STANDARD_TEMPLATE_COORDINATE_SYSTEMS)
+                             BIDS_STANDARD_TEMPLATE_COORDINATE_SYSTEMS,
+                             UNITS_MNE_TO_BIDS_MAP,)
 
 
 _FIFF_SPLIT_SIZE = '2GB'  # MNE-Python default; can be altered during debugging
@@ -102,7 +103,10 @@ def _channels_tsv(raw, fname, overwrite=False):
                     ias='Internal Active Shielding',
                     dbs='Deep Brain Stimulation',
                     fnirs_cw_amplitude='Near Infrared Spectroscopy '
-                                       '(continuous wave)',)
+                                       '(continuous wave)',
+                    resp='Respiration',
+                    gsr='Galvanic skin response (electrodermal activity, EDA)',
+                    temperature='Temperature',)
     get_specific = ('mag', 'ref_meg', 'grad')
 
     # get the manufacturer from the file in the Raw object
@@ -120,12 +124,19 @@ def _channels_tsv(raw, fname, overwrite=False):
         ch_type.append(map_chs[_channel_type])
         description.append(map_desc[_channel_type])
     low_cutoff, high_cutoff = (raw.info['highpass'], raw.info['lowpass'])
-    if raw._orig_units:
+    if raw._orig_units is not None:
         units = [raw._orig_units.get(ch, 'n/a') for ch in raw.ch_names]
     else:
         units = [_unit2human.get(ch_i['unit'], 'n/a')
                  for ch_i in raw.info['chs']]
         units = [u if u not in ['NA'] else 'n/a' for u in units]
+
+    # Translate from MNE to BIDS unit naming
+    for idx, mne_unit in enumerate(units):
+        if mne_unit in UNITS_MNE_TO_BIDS_MAP:
+            bids_unit = UNITS_MNE_TO_BIDS_MAP[mne_unit]
+            units[idx] = bids_unit
+
     n_channels = raw.info['nchan']
     sfreq = raw.info['sfreq']
 
@@ -1764,7 +1775,7 @@ def write_raw_bids(
                 bids_path.update(extension='.vhdr')
     # Read in Raw object and extract metadata from Raw object if needed
     orient = ORIENTATION.get(ext, 'n/a')
-    unit = UNITS.get(ext, 'n/a')
+    unit = EXT_TO_UNIT_MAP.get(ext, 'n/a')
     manufacturer = MANUFACTURERS.get(ext, 'n/a')
 
     # save readme file unless it already exists


Test patch:
diff --git a/mne_bids/tests/data/tiny_bids/code/make_tiny_bids_dataset.py b/mne_bids/tests/data/tiny_bids/code/make_tiny_bids_dataset.py
--- a/mne_bids/tests/data/tiny_bids/code/make_tiny_bids_dataset.py
+++ b/mne_bids/tests/data/tiny_bids/code/make_tiny_bids_dataset.py
@@ -1,8 +1,7 @@
 """Code used to generate the tiny_bids dataset."""
+
 # %%
 import json
-import os
-import os.path as op
 from pathlib import Path
 
 import mne
@@ -12,17 +11,20 @@
 from mne_bids import BIDSPath, write_raw_bids
 
 data_path = mne.datasets.testing.data_path()
-vhdr_fname = op.join(data_path, "montage", "bv_dig_test.vhdr")
-captrak_path = op.join(data_path, "montage", "captrak_coords.bvct")
+vhdr_path = data_path / "montage" / "bv_dig_test.vhdr"
+captrak_path = data_path / "montage" / "captrak_coords.bvct"
 
-mne_bids_root = Path(mne_bids.__file__).parent.parent
-tiny_bids = op.join(mne_bids_root, "mne_bids", "tests", "data", "tiny_bids")
-os.makedirs(tiny_bids, exist_ok=True)
+mne_bids_root = Path(mne_bids.__file__).parents[1]
+tiny_bids_root = mne_bids_root / "mne_bids" / "tests" / "data" / "tiny_bids"
+tiny_bids_root.mkdir(exist_ok=True)
 
-bids_path = BIDSPath(subject="01", task="rest", session="eeg", root=tiny_bids)
+bids_path = BIDSPath(
+    subject="01", task="rest", session="eeg", suffix="eeg", extension=".vhdr",
+    datatype="eeg", root=tiny_bids_root
+)
 
 # %%
-raw = mne.io.read_raw_brainvision(vhdr_fname)
+raw = mne.io.read_raw_brainvision(vhdr_path, preload=True)
 montage = mne.channels.read_dig_captrak(captrak_path)
 
 raw.set_channel_types(dict(ECG="ecg", HEOG="eog", VEOG="eog"))
@@ -39,25 +41,67 @@
     "hand": 3,
 }
 
-raw.set_annotations(None)
-events = np.array([[0, 0, 1], [1000, 0, 2]])
-event_id = {"start_experiment": 1, "show_stimulus": 2}
+# %%
+# Add GSR and temperature channels
+if 'GSR' not in raw.ch_names and 'Temperature' not in raw.ch_names:
+    gsr_data = np.array([2.1e-6] * len(raw.times))
+    temperature_data = np.array([36.5] * len(raw.times))
+
+    gsr_and_temp_data = np.concatenate([
+        np.atleast_2d(gsr_data),
+        np.atleast_2d(temperature_data),
+    ])
+    gsr_and_temp_info = mne.create_info(
+        ch_names=["GSR", "Temperature"],
+        sfreq=raw.info["sfreq"],
+        ch_types=["gsr", "temperature"],
+    )
+    gsr_and_temp_info["line_freq"] = raw.info["line_freq"]
+    gsr_and_temp_info["subject_info"] = raw.info["subject_info"]
+    with gsr_and_temp_info._unlock():
+        gsr_and_temp_info["lowpass"] = raw.info["lowpass"]
+        gsr_and_temp_info["highpass"] = raw.info["highpass"]
+    gsr_and_temp_raw = mne.io.RawArray(
+        data=gsr_and_temp_data,
+        info=gsr_and_temp_info,
+        first_samp=raw.first_samp,
+    )
+    raw.add_channels([gsr_and_temp_raw])
+    del gsr_and_temp_raw, gsr_and_temp_data, gsr_and_temp_info
 
 # %%
+raw.set_annotations(None)
+events = np.array([
+    [0, 0, 1],
+    [1000, 0, 2]
+])
+event_id = {
+    "start_experiment": 1,
+    "show_stimulus": 2
+}
 
+# %%
 write_raw_bids(
-    raw, bids_path, events=events, event_id=event_id, overwrite=True
+    raw, bids_path, events=events, event_id=event_id, overwrite=True,
+    allow_preload=True, format="BrainVision",
+)
+mne_bids.mark_channels(
+    bids_path=bids_path,
+    ch_names=['C3', 'C4', 'PO10', 'GSR', 'Temperature'],
+    status=['good', 'good', 'bad', 'good', 'good'],
+    descriptions=['resected', 'resected', 'continuously flat',
+                  'left index finger', 'left ear']
 )
 
 # %%
-
-dataset_description_json = op.join(tiny_bids, "dataset_description.json")
-with open(dataset_description_json, "r") as fin:
-    ds_json = json.load(fin)
+dataset_description_json_path = tiny_bids_root / "dataset_description.json"
+ds_json = json.loads(
+    dataset_description_json_path.read_text(encoding="utf-8")
+)
 
 ds_json["Name"] = "tiny_bids"
 ds_json["Authors"] = ["MNE-BIDS Developers", "And Friends"]
 
-with open(dataset_description_json, "w") as fout:
+with open(dataset_description_json_path, "w", encoding="utf-8") as fout:
     json.dump(ds_json, fout, indent=4)
     fout.write("\n")
diff --git a/mne_bids/tests/data/tiny_bids/sub-01/ses-eeg/eeg/sub-01_ses-eeg_electrodes.tsv b/mne_bids/tests/data/tiny_bids/sub-01/ses-eeg/eeg/sub-01_ses-eeg_electrodes.tsv
--- a/mne_bids/tests/data/tiny_bids/sub-01/ses-eeg/eeg/sub-01_ses-eeg_electrodes.tsv
+++ b/mne_bids/tests/data/tiny_bids/sub-01/ses-eeg/eeg/sub-01_ses-eeg_electrodes.tsv
@@ -63,6 +63,3 @@ PO3	-0.03295276056603997	-0.09836112961335748	0.09818535662931108	0.0
 POz	0.00141250247182117	-0.09659898488597438	0.1092860795662283	2.0
 PO4	0.03732555069518968	-0.09330847523481997	0.09871963971555255	0.0
 PO8	0.061422359682971855	-0.08824937021900595	0.06730156974139692	0.0
-ECG	n/a	n/a	n/a	n/a
-HEOG	n/a	n/a	n/a	n/a
-VEOG	n/a	n/a	n/a	n/a
diff --git a/mne_bids/tests/data/tiny_bids/sub-01/ses-eeg/eeg/sub-01_ses-eeg_task-rest_channels.tsv b/mne_bids/tests/data/tiny_bids/sub-01/ses-eeg/eeg/sub-01_ses-eeg_task-rest_channels.tsv
--- a/mne_bids/tests/data/tiny_bids/sub-01/ses-eeg/eeg/sub-01_ses-eeg_task-rest_channels.tsv
+++ b/mne_bids/tests/data/tiny_bids/sub-01/ses-eeg/eeg/sub-01_ses-eeg_task-rest_channels.tsv
@@ -66,3 +66,5 @@ PO8	EEG	µV	0.015915494309189534	1000.0	ElectroEncephaloGram	5000.0	good	n/a
 ECG	ECG	µV	0.015915494309189534	1000.0	ElectroCardioGram	5000.0	good	n/a
 HEOG	EOG	µV	0.015915494309189534	1000.0	ElectroOculoGram	5000.0	good	n/a
 VEOG	EOG	µV	0.015915494309189534	1000.0	ElectroOculoGram	5000.0	good	n/a
+GSR	GSR	S	0.015915494309189534	1000.0	Galvanic skin response (electrodermal activity, EDA)	5000.0	good	left index finger
+Temperature	TEMP	oC	0.015915494309189534	1000.0	Temperature	5000.0	good	left ear
diff --git a/mne_bids/tests/data/tiny_bids/sub-01/ses-eeg/eeg/sub-01_ses-eeg_task-rest_eeg.eeg b/mne_bids/tests/data/tiny_bids/sub-01/ses-eeg/eeg/sub-01_ses-eeg_task-rest_eeg.eeg
Binary files a/mne_bids/tests/data/tiny_bids/sub-01/ses-eeg/eeg/sub-01_ses-eeg_task-rest_eeg.eeg and b/mne_bids/tests/data/tiny_bids/sub-01/ses-eeg/eeg/sub-01_ses-eeg_task-rest_eeg.eeg differ
diff --git a/mne_bids/tests/data/tiny_bids/sub-01/ses-eeg/eeg/sub-01_ses-eeg_task-rest_eeg.vhdr b/mne_bids/tests/data/tiny_bids/sub-01/ses-eeg/eeg/sub-01_ses-eeg_task-rest_eeg.vhdr
--- a/mne_bids/tests/data/tiny_bids/sub-01/ses-eeg/eeg/sub-01_ses-eeg_task-rest_eeg.vhdr
+++ b/mne_bids/tests/data/tiny_bids/sub-01/ses-eeg/eeg/sub-01_ses-eeg_task-rest_eeg.vhdr
@@ -8,7 +8,7 @@ MarkerFile=sub-01_ses-eeg_task-rest_eeg.vmrk
 DataFormat=BINARY
 ; Data orientation: MULTIPLEXED=ch1,pt1, ch2,pt1 ...
 DataOrientation=MULTIPLEXED
-NumberOfChannels=67
+NumberOfChannels=69
 ; Sampling interval in microseconds
 SamplingInterval=200
 
@@ -87,6 +87,8 @@ Ch64=PO8,,0.1,µV
 Ch65=ECG,,0.1,µV
 Ch66=HEOG,,0.1,µV
 Ch67=VEOG,,0.1,µV
+Ch68=GSR,,0.1,S
+Ch69=Temperature,,0.1,C
 
 [Comment]
 
@@ -95,7 +97,7 @@ BrainVision Recorder Professional   -   V. 1.21.0303
 
 A m p l i f i e r  S e t u p
 ============================
-Number of channels: 67
+Number of channels: 69
 Sampling Rate [Hz]: 1000
 Sampling Interval [µS]: 1000
 
@@ -169,6 +171,8 @@ Channels
 65    ECG         65               0.1 µV             10             1000              Off                0
 66    HEOG        66               0.1 µV             10             1000              Off                0
 67    VEOG        67               0.1 µV             10             1000              Off                0
+68    GSR         68               0.1 µV             10             1000              Off                0
+69    Temperature 69               0.1 µV             10             1000              Off                0
 
 S o f t w a r e  F i l t e r s
 ==============================
diff --git a/mne_bids/tests/test_path.py b/mne_bids/tests/test_path.py
--- a/mne_bids/tests/test_path.py
+++ b/mne_bids/tests/test_path.py
@@ -145,22 +145,23 @@ def test_search_folder_for_text(capsys):
     test_dir = op.dirname(__file__)
     search_folder_for_text('n/a', test_dir)
     captured = capsys.readouterr()
-    assert 'sub-01_ses-eeg_electrodes.tsv' in captured.out
-    assert '    1    name      x         y         z         impedance' in \
-        captured.out.split('\n')
-    assert '    66   ECG       n/a       n/a       n/a       n/a' in \
-        captured.out.split('\n')
-
+    assert 'sub-01_ses-eeg_task-rest_eeg.json' in captured.out
+    assert (
+        '    1    name      type      units     low_cutof high_cuto descripti sampling_ status    status_de\n'  # noqa: E501
+        '    2    Fp1       EEG       µV        0.0159154 1000.0    ElectroEn 5000.0    good      n/a'          # noqa: E501
+    ) in captured.out
     # test if pathlib.Path object
     search_folder_for_text('n/a', Path(test_dir))
 
     # test returning a string and without line numbers
     out = search_folder_for_text(
-        'n/a', test_dir, line_numbers=False, return_str=True)
-    assert 'sub-01_ses-eeg_electrodes.tsv' in out
-    assert '    name      x         y         z         impedance' in \
-        out.split('\n')
-    assert '    ECG       n/a       n/a       n/a       n/a' in out.split('\n')
+        'n/a', test_dir, line_numbers=False, return_str=True
+    )
+    assert 'sub-01_ses-eeg_task-rest_eeg.json' in out
+    assert (
+        '    name      type      units     low_cutof high_cuto descripti sampling_ status    status_de\n'  # noqa: E501
+        '    Fp1       EEG       µV        0.0159154 1000.0    ElectroEn 5000.0    good      n/a'          # noqa: E501
+    ) in out
 
 
 def test_print_dir_tree(capsys):
diff --git a/mne_bids/tests/test_read.py b/mne_bids/tests/test_read.py
--- a/mne_bids/tests/test_read.py
+++ b/mne_bids/tests/test_read.py
@@ -58,8 +58,8 @@
 raw_fname_chpi = op.join(data_path, 'SSS', 'test_move_anon_raw.fif')
 
 # Tiny BIDS testing dataset
-mne_bids_root = Path(mne_bids.__file__).parent.parent
-tiny_bids = op.join(mne_bids_root, "mne_bids", "tests", "data", "tiny_bids")
+mne_bids_root = Path(mne_bids.__file__).parents[1]
+tiny_bids_root = mne_bids_root / "mne_bids" / "tests" / "data" / "tiny_bids"
 
 warning_str = dict(
     channel_unit_changed='ignore:The unit for chann*.:RuntimeWarning:mne',
@@ -572,6 +572,8 @@ def test_handle_scans_reading(tmp_path):
     assert new_acq_time != raw_01.info['meas_date']
 
 
+@requires_version('mne', '1.2')  # tiny_bids contains GSR & temperature chans
+@pytest.mark.filterwarnings(warning_str['channel_unit_changed'])
 def test_handle_scans_reading_brainvision(tmp_path):
     """Test stability of BrainVision's different file extensions"""
     test_scan_eeg = OrderedDict(
@@ -591,9 +593,9 @@ def test_handle_scans_reading_brainvision(tmp_path):
         _to_tsv(test_scan, tmp_path / test_scan['filename'][0])
 
     bids_path = BIDSPath(subject='01', session='eeg', task='rest',
-                         datatype='eeg', root=tiny_bids)
-    with pytest.warns(RuntimeWarning, match='Not setting positions'):
-        raw = read_raw_bids(bids_path)
+                         datatype='eeg', root=tiny_bids_root)
+
+    raw = read_raw_bids(bids_path)
 
     for test_scan in [test_scan_eeg, test_scan_vmrk]:
         _handle_scans_reading(tmp_path / test_scan['filename'][0],
@@ -690,7 +692,6 @@ def test_handle_info_reading(tmp_path):
         assert raw.info['line_freq'] == 55
 
 
-@requires_version('mne', '0.24')
 @pytest.mark.filterwarnings(warning_str['channel_unit_changed'])
 @pytest.mark.filterwarnings(warning_str['maxshield'])
 def test_handle_chpi_reading(tmp_path):
@@ -1272,3 +1273,16 @@ def test_file_not_found(tmp_path):
     bp.extension = None
     with pytest.raises(FileNotFoundError, match='File does not exist'):
         read_raw_bids(bids_path=bp)
+
+
+@requires_version('mne', '1.2')
+@pytest.mark.filterwarnings(warning_str['channel_unit_changed'])
+def test_gsr_and_temp_reading():
+    """Test GSR and temperature channels are handled correctly."""
+    bids_path = BIDSPath(
+        subject='01', session='eeg', task='rest', datatype='eeg',
+        root=tiny_bids_root
+    )
+    raw = read_raw_bids(bids_path)
+    assert raw.get_channel_types(['GSR']) == ['gsr']
+    assert raw.get_channel_types(['Temperature']) == ['temperature']