Skip to content

Commit 0c85fb7

Browse files
committed
Fix complicated corner cases in openephys legacy when small chunk when gap_mode=True
1 parent 06ea9d0 commit 0c85fb7

File tree

3 files changed

+38
-39
lines changed

3 files changed

+38
-39
lines changed

neo/rawio/openephysrawio.py

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ def _parse_header(self):
8787
self._sigs_memmap[seg_index] = {}
8888
self._sig_has_gap[seg_index] = {}
8989

90-
all_sigs_length = []
9190
all_first_timestamps = []
9291
all_last_timestamps = []
9392
all_samplerate = []
@@ -107,26 +106,18 @@ def _parse_header(self):
107106
dtype=continuous_dtype, shape=(size, ))
108107
self._sigs_memmap[seg_index][chan_index] = data_chan
109108

110-
# print(data_chan)
111-
112-
# import matplotlib.pyplot as plt
113-
# fig, ax = plt.subplots()
114-
# ax.plot(data_chan['timestamp'])
115-
# plt.show()
116-
117-
# all_sigs_length.append(data_chan.size * RECORD_SIZE)
118109
all_first_timestamps.append(data_chan[0]['timestamp'])
119110
all_last_timestamps.append(data_chan[-1]['timestamp'] + RECORD_SIZE)
120111
all_samplerate.append(chan_info['sampleRate'])
121112

122113
# check for continuity (no gaps)
123114
diff = np.diff(data_chan['timestamp'])
124-
self._sig_has_gap[seg_index][chan_index] = not np.all(diff == RECORD_SIZE)
125-
# if not np.all(diff == RECORD_SIZE) and not self._ignore_timestamps_errors:
126-
# raise ValueError(
127-
# 'Not continuous timestamps for {}. ' \
128-
# 'Maybe because recording was paused/stopped.'.format(continuous_filename)
129-
# )
115+
channel_has_gaps = not np.all(diff == RECORD_SIZE)
116+
self._sig_has_gap[seg_index][chan_index] = channel_has_gaps
117+
118+
if channel_has_gaps:
119+
# protect against strange timestamp block like in file 'OpenEphys_SampleData_3' CH32
120+
assert np.median(diff) == RECORD_SIZE, f"This file has strange block timestamp for channel {chan_id}"
130121

131122
if seg_index == 0:
132123
# add in channel list
@@ -339,17 +330,32 @@ def _get_analogsignal_chunk(self, block_index, seg_index, i_start, i_stop,
339330
# slow mode
340331
for i, global_chan_index in enumerate(global_channel_indexes):
341332
data = self._sigs_memmap[seg_index][global_chan_index]
342-
t0 = data[0]['timestamp']
333+
timestamp0 = data[0]['timestamp']
343334

344335
# find first block
345-
block0 = np.searchsorted(data['timestamp'], t0 + i_start, side='right') - 1
346-
shift0 = i_start + t0 - data[block0]['timestamp']
347-
pos = RECORD_SIZE - shift0
348-
sigs_chunk[:, i][:pos] = data[block0]['samples'][shift0:]
336+
block0 = np.searchsorted(data['timestamp'], timestamp0 + i_start, side='right') - 1
337+
block0_pos = data[block0]['timestamp'] - timestamp0
349338

339+
if i_start - block0_pos > RECORD_SIZE:
340+
# the block has gap!!
341+
pos = - ((i_start - block0_pos) % RECORD_SIZE)
342+
block_index = block0 + 1
343+
else:
344+
# the first block do not have gaps
345+
shift0 = i_start - block0_pos
346+
347+
if shift0 + (i_stop - i_start) < RECORD_SIZE:
348+
# protect when only one small block
349+
pos = (i_stop - i_start)
350+
sigs_chunk[:, i][:pos] = data[block0]['samples'][shift0:shift0 + pos]
351+
else:
352+
353+
pos = RECORD_SIZE - shift0
354+
sigs_chunk[:, i][:pos] = data[block0]['samples'][shift0:]
355+
block_index = block0 + 1
356+
350357
# full block
351-
block_index = block0 + 1
352-
while data[block_index]['timestamp'] - t0 < i_stop - RECORD_SIZE:
358+
while block_index < data.size and data[block_index]['timestamp'] - timestamp0 < i_stop - RECORD_SIZE:
353359
diff = data[block_index]['timestamp'] - data[block_index - 1]['timestamp']
354360
if diff > RECORD_SIZE:
355361
# gap detected need jump
@@ -361,7 +367,10 @@ def _get_analogsignal_chunk(self, block_index, seg_index, i_start, i_stop,
361367

362368
# last block
363369
if pos < i_stop - i_start:
364-
sigs_chunk[:, i][pos:] = data[block_index]['samples'][:i_stop - i_start - pos]
370+
diff = data[block_index]['timestamp'] - data[block_index - 1]['timestamp']
371+
if diff == RECORD_SIZE:
372+
# ensure no gaps for last block
373+
sigs_chunk[:, i][pos:] = data[block_index]['samples'][:i_stop - i_start - pos]
365374

366375
return sigs_chunk
367376

@@ -505,6 +514,7 @@ def explore_folder(dirname):
505514
"100_CH0_2.continuous" ---> seg_index 1
506515
"100_CH0_N.continuous" ---> seg_index N-1
507516
"""
517+
print(dirname, type(dirname))
508518
filenames = os.listdir(dirname)
509519
filenames.sort()
510520

neo/test/rawiotest/rawio_compliance.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ def read_analogsignals(reader):
243243
chunks.append(raw_chunk)
244244
i_start += chunksize
245245
chunk_raw_sigs = np.concatenate(chunks, axis=0)
246+
246247
np.testing.assert_array_equal(ref_raw_sigs, chunk_raw_sigs)
247248

248249

neo/test/rawiotest/test_openephysrawio.py

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,12 @@ class TestOpenEphysRawIO(BaseTestRawIO, unittest.TestCase, ):
1010
'openephys'
1111
]
1212
entities_to_test = [
13-
'openephys/OpenEphys_SampleData_1',
14-
# 'OpenEphys_SampleData_2_(multiple_starts)', # This not implemented this raise error
15-
# 'OpenEphys_SampleData_3',
13+
# 'openephys/OpenEphys_SampleData_1',
14+
# this file has gaps and this is now handle corretly
15+
'openephys/OpenEphys_SampleData_2_(multiple_starts)',
16+
# 'openephys/OpenEphys_SampleData_3',
1617
]
1718

18-
def test_raise_error_if_discontinuous_files(self):
19-
# the case of discontinuous signals is NOT cover by the IO for the moment
20-
# It must raise an error
21-
reader = OpenEphysRawIO(dirname=self.get_local_path(
22-
'openephys/OpenEphys_SampleData_2_(multiple_starts)'))
23-
with self.assertRaises(ValueError):
24-
reader.parse_header()
25-
# if ignore_timestamps_errors=True, no exception is raised
26-
reader = OpenEphysRawIO(dirname=self.get_local_path(
27-
'openephys/OpenEphys_SampleData_2_(multiple_starts)'),
28-
ignore_timestamps_errors=True)
29-
reader.parse_header()
30-
3119

3220
def test_raise_error_if_strange_timestamps(self):
3321
# In this dataset CH32 have strange timestamps

0 commit comments

Comments
 (0)