Skip to content

Commit a8286d8

Browse files
committed
add preload option
1 parent 63c4da3 commit a8286d8

File tree

1 file changed

+69
-16
lines changed

1 file changed

+69
-16
lines changed

mne/io/curry/curry.py

Lines changed: 69 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@
1010
import numpy as np
1111

1212
from ..._fiff.meas_info import create_info
13+
from ..._fiff.utils import _mult_cal_one, _read_segments_file
1314
from ...annotations import annotations_from_events
1415
from ...channels import make_dig_montage
15-
from ...utils import verbose
16+
from ...utils import verbose, warn
1617
from ..base import BaseRaw
1718

1819

@@ -59,7 +60,7 @@ class RawCurry(BaseRaw):
5960
"""
6061

6162
@verbose
62-
def __init__(self, fname, preload=True, verbose=None):
63+
def __init__(self, fname, preload=False, verbose=None):
6364
fname = Path(fname)
6465

6566
# use curry-python-reader
@@ -70,7 +71,15 @@ def __init__(self, fname, preload=True, verbose=None):
7071

7172
# extract info
7273
sfreq = currydata["info"]["samplingfreq"]
73-
n_samples = currydata["info"]["samples"]
74+
if currydata["info"]["samples"] == currydata["data"].shape[0]:
75+
n_samples = currydata["info"]["samples"]
76+
else:
77+
n_samples = currydata["data"].shape[0]
78+
warn(
79+
"sample count from header doesn't match actual data! "
80+
"file corrupted? will use data shape"
81+
)
82+
7483
n_ch = currydata["info"]["channels"]
7584
ch_names = currydata["labels"]
7685
ch_pos = currydata["sensorpos"]
@@ -80,17 +89,20 @@ def __init__(self, fname, preload=True, verbose=None):
8089
# extract data
8190
orig_format = "single" # curryreader.py always reads float32. is this correct?
8291

83-
preload = currydata["data"].T.astype(
84-
"float64"
85-
) # curryreader returns float32, but mne seems to need float64
92+
if isinstance(preload, bool | np.bool_) and preload:
93+
preload = currydata["data"].T.astype(
94+
"float64"
95+
) # curryreader returns float32, but mne seems to need float64
8696
events = currydata["events"]
8797
# annotations = currydata[
8898
# "annotations"
8999
# ] # dont always seem to correspond to events?!
90100
# impedances = currydata["impedances"] # see read_impedances_curry
91101
# epochinfo = currydata["epochinfo"] # TODO
92-
# epochlabels = currydata["epochlabels"] # TODO
93-
# hpimatrix = currydata["hpimatrix"] # TODO
102+
epochlabels = currydata["epochlabels"] # TODO
103+
if epochlabels != []:
104+
warn("epoched recording detected; WIP")
105+
hpimatrix = currydata["hpimatrix"] # TODO
94106

95107
# extract other essential info not provided by curryreader
96108
fname_hdr = None
@@ -100,6 +112,7 @@ def __init__(self, fname, preload=True, verbose=None):
100112

101113
ch_types, units = [], []
102114
if fname_hdr:
115+
# read channel types
103116
ch_groups = fname_hdr.read_text().split("DEVICE_PARAMETERS")[1::2]
104117
for ch_group in ch_groups:
105118
ch_group = re.compile(r"\s+").sub(" ", ch_group).strip()
@@ -116,9 +129,14 @@ def __init__(self, fname, preload=True, verbose=None):
116129
# combine info
117130
ch_types += [ch_type] * n_ch_group
118131
units += [unit] * n_ch_group
119-
120132
assert len(ch_types) == len(units) == len(ch_names) == n_ch
121133

134+
# read datatype
135+
byteorder = (
136+
fname_hdr.read_text().split("DataByteOrder")[1].strip().split(" ")[1]
137+
)
138+
is_ascii = "ASCII" in byteorder
139+
122140
else:
123141
raise NotImplementedError
124142

@@ -127,17 +145,23 @@ def __init__(self, fname, preload=True, verbose=None):
127145

128146
# scale data to SI units
129147
orig_units = dict(zip(ch_names, units))
130-
for i_ch, unit in enumerate(units):
131-
if unit == "fT": # femtoTesla
132-
preload[i_ch, :] /= 1e15
133-
elif unit == "uV": # microVolt
134-
preload[i_ch, :] /= 1e6
135-
else: # leave as is
136-
pass
148+
cals = [
149+
1.0 / 1e15 if (u == "fT") else 1.0 / 1e6 if (u == "uV") else 1.0
150+
for u in units
151+
]
152+
if isinstance(preload, np.ndarray):
153+
for i_ch, unit in enumerate(units):
154+
if unit == "fT": # femtoTesla
155+
preload[i_ch, :] /= 1e15
156+
elif unit == "uV": # microVolt
157+
preload[i_ch, :] /= 1e6
158+
else: # leave as is
159+
pass
137160

138161
# construct info
139162
info = create_info(ch_names=ch_names, sfreq=sfreq, ch_types=ch_types)
140163
last_samps = [n_samples - 1]
164+
raw_extras = dict(is_ascii=is_ascii)
141165

142166
# create raw object
143167
super().__init__(
@@ -146,9 +170,11 @@ def __init__(self, fname, preload=True, verbose=None):
146170
filenames=[fname],
147171
last_samps=last_samps,
148172
orig_format=orig_format,
173+
raw_extras=[raw_extras],
149174
orig_units=orig_units,
150175
verbose=verbose,
151176
)
177+
self._cals = np.array(cals)
152178

153179
# set events / annotations
154180
# format from curryreader: sample, etype, startsample, endsample
@@ -166,6 +192,33 @@ def __init__(self, fname, preload=True, verbose=None):
166192

167193
# add HPI data (if present)
168194
# TODO
195+
if not isinstance(hpimatrix, list):
196+
warn("HPI data found, but reader not implemented.")
197+
198+
def _rescale_curry_data(self):
199+
orig_units = self._orig_units
200+
for i_ch, unit in enumerate(orig_units):
201+
if unit == "fT": # femtoTesla
202+
self._data[i_ch, :] /= 1e15
203+
elif unit == "µV": # microVolt
204+
self._data[i_ch, :] /= 1e6
205+
else: # leave as is
206+
pass
207+
208+
def _read_segment_file(self, data, idx, fi, start, stop, cals, mult):
209+
"""Read a chunk of raw data."""
210+
if self._raw_extras[fi]["is_ascii"]:
211+
if isinstance(idx, slice):
212+
idx = np.arange(idx.start, idx.stop)
213+
block = np.loadtxt(
214+
self.filenames[0], skiprows=start, max_rows=stop - start, ndmin=2
215+
).T
216+
_mult_cal_one(data, block, idx, cals, mult)
217+
218+
else:
219+
_read_segments_file(
220+
self, data, idx, fi, start, stop, cals, mult, dtype="<f4"
221+
)
169222

170223

171224
def _make_curry_montage(ch_names, ch_pos, landmarks, landmarkslabels):

0 commit comments

Comments
 (0)