Skip to content

Commit 7bf5208

Browse files
committed
Fix shape convention to be consistent with HDF5 pattern
When time_axis=1, shape should be (channels, time) not (time, channels). This makes raw binary handling consistent with HDF5: - time_axis=0: shape is (time, channels) - MULTIPLEXED - time_axis=1: shape is (channels, time) - VECTORIZED Changes: - BrainVisionRawIO: Set shape as (channels, time) when VECTORIZED - BaseRawIO: Use shape[time_axis] consistently for i_stop default - Removed duplicate time_axis retrieval All tests pass with identical MNE-Python validation.
1 parent d214b4a commit 7bf5208

File tree

2 files changed

+21
-16
lines changed

2 files changed

+21
-16
lines changed

neo/rawio/baserawio.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,14 +1577,11 @@ def __init__(self, *arg, **kwargs):
15771577
def _get_signal_size(self, block_index, seg_index, stream_index):
15781578
buffer_id = self.header["signal_streams"][stream_index]["buffer_id"]
15791579
buffer_desc = self.get_analogsignal_buffer_description(block_index, seg_index, buffer_id)
1580-
# For "raw" type, shape is always (time, channels) regardless of file layout
1581-
# For "hdf5" type, shape can be (time, channels) or (channels, time) based on time_axis
1582-
if buffer_desc["type"] == "raw":
1583-
return buffer_desc["shape"][0]
1584-
else:
1585-
# some hdf5 revert the buffer
1586-
time_axis = buffer_desc.get("time_axis", 0)
1587-
return buffer_desc["shape"][time_axis]
1580+
# time_axis indicates which dimension is time:
1581+
# time_axis=0: shape is (time, channels)
1582+
# time_axis=1: shape is (channels, time)
1583+
time_axis = buffer_desc.get("time_axis", 0)
1584+
return buffer_desc["shape"][time_axis]
15881585

15891586
def _get_analogsignal_chunk(
15901587
self,
@@ -1603,13 +1600,14 @@ def _get_analogsignal_chunk(
16031600

16041601
buffer_desc = self.get_analogsignal_buffer_description(block_index, seg_index, buffer_id)
16051602

1603+
# Get time_axis to determine which dimension is time
1604+
time_axis = buffer_desc.get("time_axis", 0)
1605+
16061606
i_start = i_start or 0
1607-
i_stop = i_stop or buffer_desc["shape"][0]
1607+
i_stop = i_stop or buffer_desc["shape"][time_axis]
16081608

16091609
if buffer_desc["type"] == "raw":
16101610

1611-
time_axis = buffer_desc.get("time_axis", 0)
1612-
16131611
if time_axis == 0:
16141612
# MULTIPLEXED: time_axis=0 means (time, channels) layout
16151613
# open files on demand and keep reference to opened file
@@ -1637,12 +1635,12 @@ def _get_analogsignal_chunk(
16371635
)
16381636

16391637
elif time_axis == 1:
1640-
# VECTORIZED: time_axis=1 means (channels, time) layout
1638+
# VECTORIZED: time_axis=1 means shape is (channels, time)
16411639
# Data is stored as [all_samples_ch1, all_samples_ch2, ...]
16421640
dtype = np.dtype(buffer_desc["dtype"])
1643-
num_channels = buffer_desc["shape"][1]
1641+
num_channels = buffer_desc["shape"][0] # shape is (channels, time)
16441642
num_samples = i_stop - i_start
1645-
total_samples_per_channel = buffer_desc["shape"][0]
1643+
total_samples_per_channel = buffer_desc["shape"][1] # shape is (channels, time)
16461644

16471645
# Determine which channels to read
16481646
if channel_indexes is None:

neo/rawio/brainvisionrawio.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,18 @@ def _parse_header(self):
9191
self._buffer_descriptions = {0: {0: {}}}
9292
self._stream_buffer_slice = {}
9393

94-
shape = get_memmap_shape(binary_filename, sig_dtype, num_channels=nb_channel, offset=0)
95-
9694
# time_axis indicates data layout: 0 for MULTIPLEXED (time, channels), 1 for VECTORIZED (channels, time)
9795
time_axis = 0 if self._data_orientation == "MULTIPLEXED" else 1
9896

97+
# Get shape - always returns (num_samples, num_channels)
98+
temp_shape = get_memmap_shape(binary_filename, sig_dtype, num_channels=nb_channel, offset=0)
99+
100+
# For consistency with HDF5 pattern: when time_axis=1, shape should be (channels, time)
101+
if time_axis == 1:
102+
shape = (temp_shape[1], temp_shape[0]) # (num_channels, num_samples)
103+
else:
104+
shape = temp_shape # (num_samples, num_channels)
105+
99106
self._buffer_descriptions[0][0][buffer_id] = {
100107
"type": "raw",
101108
"file_path": binary_filename,

0 commit comments

Comments
 (0)