6
6
import re
7
7
from pathlib import Path
8
8
9
+ import curryreader
9
10
import numpy as np
10
11
11
12
from ..._fiff .meas_info import create_info
12
13
from ...annotations import annotations_from_events
13
14
from ...channels import make_dig_montage
14
15
from ...utils import verbose
15
16
from ..base import BaseRaw
16
- from .curryreader import read
17
-
18
- _RE_COMBINE_WHITESPACE = re .compile (r"\s+" )
19
17
20
18
21
19
@verbose
@@ -61,12 +59,12 @@ class RawCurry(BaseRaw):
61
59
"""
62
60
63
61
@verbose
64
- def __init__ (self , fname , preload = False , verbose = None ):
62
+ def __init__ (self , fname , preload = True , verbose = None ):
65
63
fname = Path (fname )
66
64
67
65
# use curry-python-reader
68
66
try :
69
- currydata = read (str (fname ), plotdata = 0 , verbosity = 1 )
67
+ currydata = curryreader . read (str (fname ), plotdata = 0 , verbosity = 1 )
70
68
except Exception as e :
71
69
raise ValueError (f"file could not be read - { e } " )
72
70
@@ -80,44 +78,39 @@ def __init__(self, fname, preload=False, verbose=None):
80
78
landmarkslabels = currydata ["landmarkslabels" ]
81
79
82
80
# extract data
83
- orig_format = (
84
- "single"
85
- if isinstance (currydata ["data" ].dtype , type (np .dtype ("float32" )))
86
- else None
87
- )
81
+ orig_format = "single" # curryreader.py always reads float32. is this correct?
82
+
88
83
preload = currydata ["data" ].T .astype (
89
84
"float64"
90
85
) # curryreader returns float32, but mne seems to need float64
91
86
events = currydata ["events" ]
92
87
# annotations = currydata[
93
88
# "annotations"
94
89
# ] # dont always seem to correspond to events?!
90
+ # impedances = currydata["impedances"] # see read_impedances_curry
95
91
# epochinfo = currydata["epochinfo"] # TODO
96
92
# epochlabels = currydata["epochlabels"] # TODO
97
- # impedances = currydata["impedances"] # TODO
98
93
# hpimatrix = currydata["hpimatrix"] # TODO
99
94
100
- # extract some more essential info not provided by reader
95
+ # extract other essential info not provided by curryreader
101
96
fname_hdr = None
102
97
for hdr_suff in [".cdt.dpa" , ".cdt.dpo" , ".dap" ]:
103
98
if fname .with_suffix (hdr_suff ).exists ():
104
99
fname_hdr = fname .with_suffix (hdr_suff )
105
100
106
101
ch_types , units = [], []
107
102
if fname_hdr :
108
- changroups = fname_hdr .read_text ().split ("DEVICE_PARAMETERS" )[1 ::2 ]
109
- for changroup_info in changroups :
110
- changroup_info = _RE_COMBINE_WHITESPACE .sub (" " , changroup_info ).strip ()
111
- groupid = changroup_info .split ()[0 ]
112
- unit = changroup_info .split ("DataUnit = " )[1 ].split ()[0 ]
113
- n_ch_group = int (
114
- changroup_info .split ("NumChanThisGroup = " )[1 ].split ()[0 ]
115
- )
103
+ ch_groups = fname_hdr .read_text ().split ("DEVICE_PARAMETERS" )[1 ::2 ]
104
+ for ch_group in ch_groups :
105
+ ch_group = re .compile (r"\s+" ).sub (" " , ch_group ).strip ()
106
+ groupid = ch_group .split ()[0 ]
107
+ unit = ch_group .split ("DataUnit = " )[1 ].split ()[0 ]
108
+ n_ch_group = int (ch_group .split ("NumChanThisGroup = " )[1 ].split ()[0 ])
116
109
ch_type = (
117
110
"mag"
118
111
if ("MAG" in groupid )
119
112
else "misc"
120
- if ("OTHER" ) in groupid
113
+ if ("OTHER" in groupid )
121
114
else "eeg"
122
115
)
123
116
# combine info
@@ -127,11 +120,10 @@ def __init__(self, fname, preload=False, verbose=None):
127
120
assert len (ch_types ) == len (units ) == len (ch_names ) == n_ch
128
121
129
122
else :
130
- # not implemented
131
123
raise NotImplementedError
132
124
133
125
# finetune channel types (e.g. stim, eog etc might be identified by name)
134
- # TODO
126
+ # TODO?
135
127
136
128
# scale data to SI units
137
129
orig_units = dict (zip (ch_names , units ))
@@ -172,6 +164,9 @@ def __init__(self, fname, preload=False, verbose=None):
172
164
mont = _make_curry_montage (ch_names , ch_pos , landmarks , landmarkslabels )
173
165
self .set_montage (mont , on_missing = "ignore" )
174
166
167
+ # add HPI data (if present)
168
+ # TODO
169
+
175
170
176
171
def _make_curry_montage (ch_names , ch_pos , landmarks , landmarkslabels ):
177
172
ch_pos_dict = dict (zip (ch_names , ch_pos ))
@@ -180,10 +175,17 @@ def _make_curry_montage(ch_names, ch_pos, landmarks, landmarkslabels):
180
175
if k not in landmark_dict .keys ():
181
176
landmark_dict [k ] = None
182
177
if len (landmarkslabels ) > 0 :
183
- hpi_pos = landmarks [[i for i , n in enumerate (landmarkslabels ) if "HPI" in n ], :]
178
+ hpi_pos = landmarks [
179
+ [i for i , n in enumerate (landmarkslabels ) if re .match ("HPI[1-99]" , n )], :
180
+ ]
184
181
else :
185
182
hpi_pos = None
186
- # TODO headshape (H1,2,3..)
183
+ if len (landmarkslabels ) > 0 :
184
+ hsp_pos = landmarks [
185
+ [i for i , n in enumerate (landmarkslabels ) if re .match ("H[1-99]" , n )], :
186
+ ]
187
+ else :
188
+ hsp_pos = None
187
189
188
190
mont = None
189
191
if ch_pos .shape [1 ] == 3 : # eeg xyz space
@@ -192,7 +194,7 @@ def _make_curry_montage(ch_names, ch_pos, landmarks, landmarkslabels):
192
194
nasion = landmark_dict ["Nas" ],
193
195
lpa = landmark_dict ["LPA" ],
194
196
rpa = landmark_dict ["RPA" ],
195
- hsp = None ,
197
+ hsp = hsp_pos ,
196
198
hpi = hpi_pos ,
197
199
coord_frame = "unknown" ,
198
200
)
@@ -203,3 +205,47 @@ def _make_curry_montage(ch_names, ch_pos, landmarks, landmarkslabels):
203
205
pass
204
206
205
207
return mont
208
+
209
+
210
+ def read_impedances_curry (fname ):
211
+ """Read impedance measurements from Curry files.
212
+
213
+ Parameters
214
+ ----------
215
+ fname : path-like
216
+ Path to a curry file with extensions ``.dat``, ``.dap``, ``.rs3``,
217
+ ``.cdt``, ``.cdt.dpa``, ``.cdt.cef`` or ``.cef``.
218
+
219
+ Returns
220
+ -------
221
+ ch_names : list
222
+ A list object containing channel names
223
+ impedances : np.ndarray
224
+ An array containing up to 10 impedance measurements for all recorded channels.
225
+
226
+ """
227
+ # use curry-python-reader to load data
228
+ try :
229
+ currydata = curryreader .read (str (fname ), plotdata = 0 , verbosity = 1 )
230
+ except Exception as e :
231
+ raise ValueError (f"file could not be read - { e } " )
232
+
233
+ impedances = currydata ["impedances" ]
234
+ ch_names = currydata ["labels" ]
235
+
236
+ # try get measurement times
237
+ # TODO possible?
238
+ annotations = currydata [
239
+ "annotations"
240
+ ] # dont really seem to correspond to events!?!
241
+ for anno in set (annotations ):
242
+ if "impedance" in anno .lower ():
243
+ print ("FOUND IMPEDANCE ANNOTATION!" )
244
+ print (f"'{ anno } ' - N={ len ([a for a in annotations if a == anno ])} " )
245
+
246
+ # print impedances
247
+ print ("impedance measurements:" )
248
+ for iimp in range (impedances .shape [0 ]):
249
+ print ({ch : float (imp ) for ch , imp in zip (ch_names , impedances [iimp ])})
250
+
251
+ return ch_names , impedances
0 commit comments