10
10
import numpy as np
11
11
12
12
from ..._fiff .meas_info import create_info
13
+ from ..._fiff .utils import _mult_cal_one , _read_segments_file
13
14
from ...annotations import annotations_from_events
14
15
from ...channels import make_dig_montage
15
- from ...utils import verbose
16
+ from ...utils import verbose , warn
16
17
from ..base import BaseRaw
17
18
18
19
@@ -59,7 +60,7 @@ class RawCurry(BaseRaw):
59
60
"""
60
61
61
62
@verbose
62
- def __init__ (self , fname , preload = True , verbose = None ):
63
+ def __init__ (self , fname , preload = False , verbose = None ):
63
64
fname = Path (fname )
64
65
65
66
# use curry-python-reader
@@ -70,7 +71,15 @@ def __init__(self, fname, preload=True, verbose=None):
70
71
71
72
# extract info
72
73
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
+
74
83
n_ch = currydata ["info" ]["channels" ]
75
84
ch_names = currydata ["labels" ]
76
85
ch_pos = currydata ["sensorpos" ]
@@ -80,17 +89,20 @@ def __init__(self, fname, preload=True, verbose=None):
80
89
# extract data
81
90
orig_format = "single" # curryreader.py always reads float32. is this correct?
82
91
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
86
96
events = currydata ["events" ]
87
97
# annotations = currydata[
88
98
# "annotations"
89
99
# ] # dont always seem to correspond to events?!
90
100
# impedances = currydata["impedances"] # see read_impedances_curry
91
101
# 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
94
106
95
107
# extract other essential info not provided by curryreader
96
108
fname_hdr = None
@@ -100,6 +112,7 @@ def __init__(self, fname, preload=True, verbose=None):
100
112
101
113
ch_types , units = [], []
102
114
if fname_hdr :
115
+ # read channel types
103
116
ch_groups = fname_hdr .read_text ().split ("DEVICE_PARAMETERS" )[1 ::2 ]
104
117
for ch_group in ch_groups :
105
118
ch_group = re .compile (r"\s+" ).sub (" " , ch_group ).strip ()
@@ -116,9 +129,14 @@ def __init__(self, fname, preload=True, verbose=None):
116
129
# combine info
117
130
ch_types += [ch_type ] * n_ch_group
118
131
units += [unit ] * n_ch_group
119
-
120
132
assert len (ch_types ) == len (units ) == len (ch_names ) == n_ch
121
133
134
+ # read datatype
135
+ byteorder = (
136
+ fname_hdr .read_text ().split ("DataByteOrder" )[1 ].strip ().split (" " )[1 ]
137
+ )
138
+ is_ascii = "ASCII" in byteorder
139
+
122
140
else :
123
141
raise NotImplementedError
124
142
@@ -127,17 +145,23 @@ def __init__(self, fname, preload=True, verbose=None):
127
145
128
146
# scale data to SI units
129
147
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
137
160
138
161
# construct info
139
162
info = create_info (ch_names = ch_names , sfreq = sfreq , ch_types = ch_types )
140
163
last_samps = [n_samples - 1 ]
164
+ raw_extras = dict (is_ascii = is_ascii )
141
165
142
166
# create raw object
143
167
super ().__init__ (
@@ -146,9 +170,11 @@ def __init__(self, fname, preload=True, verbose=None):
146
170
filenames = [fname ],
147
171
last_samps = last_samps ,
148
172
orig_format = orig_format ,
173
+ raw_extras = [raw_extras ],
149
174
orig_units = orig_units ,
150
175
verbose = verbose ,
151
176
)
177
+ self ._cals = np .array (cals )
152
178
153
179
# set events / annotations
154
180
# format from curryreader: sample, etype, startsample, endsample
@@ -166,6 +192,33 @@ def __init__(self, fname, preload=True, verbose=None):
166
192
167
193
# add HPI data (if present)
168
194
# 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
+ )
169
222
170
223
171
224
def _make_curry_montage (ch_names , ch_pos , landmarks , landmarkslabels ):
0 commit comments