Skip to content

Commit 2495cd9

Browse files
committed
extract device_info + refactoring
1 parent 5de6062 commit 2495cd9

2 files changed

Lines changed: 77 additions & 66 deletions

File tree

mne/io/curry/curry.py

Lines changed: 68 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,62 @@ def _check_curry_labels_filename(fname):
8080
return fname_labels
8181

8282

83+
def _get_curry_meas_info(fname):
84+
# get other essential info not provided by curryreader
85+
fname_hdr = _check_curry_header_filename(fname)
86+
content_hdr = fname_hdr.read_text()
87+
88+
# read meas_date
89+
meas_date = [
90+
int(re.compile(rf"{v}\s*=\s*-?\d+").search(content_hdr).group(0).split()[-1])
91+
for v in [
92+
"StartYear",
93+
"StartMonth",
94+
"StartDay",
95+
"StartHour",
96+
"StartMin",
97+
"StartSec",
98+
"StartMillisec",
99+
]
100+
]
101+
try:
102+
meas_date = datetime(
103+
*meas_date[:-1],
104+
meas_date[-1] * 1000, # -> microseconds
105+
timezone.utc,
106+
)
107+
except Exception:
108+
meas_date = None
109+
110+
# read datatype
111+
byteorder = (
112+
re.compile(r"DataByteOrder\s*=\s*[A-Z]+")
113+
.search(content_hdr)
114+
.group()
115+
.split()[-1]
116+
)
117+
is_ascii = byteorder == "ASCII"
118+
119+
# amp info
120+
# TODO - seems like there can be identifiable information (serial numbers, dates).
121+
# MNE anonymization functions only overwrite "serial" and "site", though
122+
# TODO - there can be filter details, too
123+
amp_info = (
124+
re.compile(r"AmplifierInfo\s*=.*\n")
125+
.search(content_hdr)
126+
.group()
127+
.strip("\n")
128+
.split("= ")[-1]
129+
.strip()
130+
)
131+
132+
device_info = (
133+
dict(type=amp_info) if amp_info != "" else None # model="", serial="", site=""
134+
)
135+
136+
return meas_date, is_ascii, device_info
137+
138+
83139
def _get_curry_recording_type(fname):
84140
_soft_import("curryreader", "read recording modality")
85141

@@ -175,7 +231,9 @@ def _extract_curry_info(fname):
175231
hpimatrix = currydata["hpimatrix"]
176232

177233
# data
178-
orig_format = "single" # curryreader.py always reads float32. is this correct?
234+
orig_format = "int"
235+
# curryreader.py always reads float32, but this is probably just numpy.
236+
# legacy MNE code states int.
179237

180238
# events
181239
events = currydata["events"]
@@ -189,46 +247,6 @@ def _extract_curry_info(fname):
189247

190248
# get other essential info not provided by curryreader
191249
fname_hdr = _check_curry_header_filename(fname)
192-
content_hdr = fname_hdr.read_text()
193-
194-
# read meas_date
195-
meas_date = [
196-
int(re.compile(rf"{v}\s*=\s*-?\d+").search(content_hdr).group(0).split()[-1])
197-
for v in [
198-
"StartYear",
199-
"StartMonth",
200-
"StartDay",
201-
"StartHour",
202-
"StartMin",
203-
"StartSec",
204-
"StartMillisec",
205-
]
206-
]
207-
try:
208-
meas_date = datetime(
209-
*meas_date[:-1],
210-
meas_date[-1] * 1000, # -> microseconds
211-
timezone.utc,
212-
)
213-
except Exception:
214-
meas_date = None
215-
216-
print(f"meas_date: {meas_date}")
217-
218-
# read datatype
219-
byteorder = (
220-
re.compile(r"DataByteOrder\s*=\s*[A-Z]+")
221-
.search(content_hdr)
222-
.group()
223-
.split()[-1]
224-
)
225-
is_ascii = byteorder == "ASCII"
226-
227-
# amp info
228-
# TODO
229-
# amp_info = (
230-
# re.compile(r"AmplifierInfo\s*=.*\n").search(content_hdr).group().split("= ")
231-
# )
232250

233251
# channel types and units
234252
ch_types, units = [], []
@@ -304,9 +322,7 @@ def _extract_curry_info(fname):
304322
events,
305323
orig_format,
306324
orig_units,
307-
is_ascii,
308325
cals,
309-
meas_date,
310326
)
311327

312328

@@ -328,9 +344,7 @@ def _read_annotations_curry(fname, sfreq="auto"):
328344
"""
329345
fname = _check_curry_filename(fname)
330346

331-
(sfreq_fromfile, _, _, _, _, _, _, _, events, _, _, _, _, _) = _extract_curry_info(
332-
fname
333-
)
347+
(sfreq_fromfile, _, _, _, _, _, _, _, events, _, _, _) = _extract_curry_info(fname)
334348
if sfreq == "auto":
335349
sfreq = sfreq_fromfile
336350
elif np.isreal(sfreq):
@@ -494,7 +508,7 @@ def _set_chanloc_curry(inst, ch_types, ch_pos, landmarks, landmarkslabels):
494508
else:
495509
raise NotImplementedError
496510

497-
# _make_trans_dig(curry_paths, inst.info, curry_dev_dev_t) # TODO?!
511+
# _make_trans_dig(curry_paths, inst.info, curry_dev_dev_t) # TODO - necessary?!
498512

499513

500514
@verbose
@@ -579,13 +593,14 @@ def __init__(self, fname, preload=False, verbose=None):
579593
events,
580594
orig_format,
581595
orig_units,
582-
is_ascii,
583596
cals,
584-
meas_date,
585597
) = _extract_curry_info(fname)
586598

599+
meas_date, is_ascii, device_info = _get_curry_meas_info(fname)
600+
587601
# construct info
588602
info = create_info(ch_names=ch_names, sfreq=sfreq, ch_types=ch_types)
603+
info["device_info"] = device_info
589604

590605
# create raw object
591606
last_samps = [n_samples - 1]
@@ -620,7 +635,7 @@ def __init__(self, fname, preload=False, verbose=None):
620635
self.set_annotations(annot)
621636

622637
# add sensor locations
623-
# TODO - is this working correctly?
638+
# TODO - review wanted!
624639
assert len(self.info["ch_names"]) == len(ch_types) >= len(ch_pos)
625640
_set_chanloc_curry(
626641
inst=self,
@@ -725,20 +740,7 @@ def read_montage_curry(fname, verbose=None):
725740
The montage.
726741
"""
727742
fname = _check_curry_filename(fname)
728-
(
729-
_,
730-
_,
731-
ch_names,
732-
ch_types,
733-
ch_pos,
734-
landmarks,
735-
landmarkslabels,
736-
_,
737-
_,
738-
_,
739-
_,
740-
_,
741-
_,
742-
_,
743-
) = _extract_curry_info(fname)
743+
(_, _, ch_names, ch_types, ch_pos, landmarks, landmarkslabels, _, _, _, _, _) = (
744+
_extract_curry_info(fname)
745+
)
744746
return _make_curry_montage(ch_names, ch_types, ch_pos, landmarks, landmarkslabels)

mne/io/curry/tests/test_curry.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,15 @@ def test_read_files_missing_channel(fname, expected_channel_list):
239239
assert raw.ch_names == expected_channel_list
240240

241241

242+
@testing.requires_testing_data
243+
def test_read_device_info():
244+
"""Test extraction of device_info."""
245+
raw = read_raw_curry(curry7_bdf_file)
246+
assert not raw.info["device_info"]
247+
raw2 = read_raw_curry(Ref_chan_omitted_file)
248+
assert isinstance(raw2.info["device_info"], dict)
249+
250+
242251
@testing.requires_testing_data
243252
@pytest.mark.parametrize(
244253
"fname",

0 commit comments

Comments
 (0)