From 3dc57290dbde0aeaa5048f2301ee75015a93fe26 Mon Sep 17 00:00:00 2001 From: Alessio Buccino Date: Mon, 29 Dec 2025 15:43:44 +0100 Subject: [PATCH 1/3] Test IBL extractors tests failing for PI update --- src/spikeinterface/extractors/tests/test_iblextractors.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/spikeinterface/extractors/tests/test_iblextractors.py b/src/spikeinterface/extractors/tests/test_iblextractors.py index 972a8e7bb0..56d01e38cf 100644 --- a/src/spikeinterface/extractors/tests/test_iblextractors.py +++ b/src/spikeinterface/extractors/tests/test_iblextractors.py @@ -76,8 +76,8 @@ def test_offsets(self): def test_probe_representation(self): probe = self.recording.get_probe() - expected_probe_representation = "Probe - 384ch - 1shanks" - assert repr(probe) == expected_probe_representation + expected_probe_representation = "Probe - 384ch" + assert expected_probe_representation in repr(probe) def test_property_keys(self): expected_property_keys = [ From 61c317aba92608d9f096a3a374bc3d43e27faaba Mon Sep 17 00:00:00 2001 From: Alessio Buccino Date: Fri, 6 Mar 2026 10:09:46 -0800 Subject: [PATCH 2/3] Fix OpenEphys tests --- .../extractors/neoextractors/openephys.py | 20 ++++++++++++------- .../extractors/tests/test_neoextractors.py | 3 +++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/spikeinterface/extractors/neoextractors/openephys.py b/src/spikeinterface/extractors/neoextractors/openephys.py index 1c39a1b97c..1d16df534b 100644 --- a/src/spikeinterface/extractors/neoextractors/openephys.py +++ b/src/spikeinterface/extractors/neoextractors/openephys.py @@ -351,13 +351,19 @@ def __init__( # Ensure device channel index corresponds to channel_ids probe_channel_names = probe.contact_annotations.get("channel_name", None) if probe_channel_names is not None and not np.array_equal(probe_channel_names, self.channel_ids): - device_channel_indices = [] - probe_channel_names = list(probe_channel_names) - device_channel_indices = np.zeros(len(self.channel_ids), dtype=int) - for i, ch in enumerate(self.channel_ids): - index_in_probe = probe_channel_names.index(ch) - device_channel_indices[index_in_probe] = i - probe.set_device_channel_indices(device_channel_indices) + if set(probe_channel_names) == set(self.channel_ids): + device_channel_indices = [] + probe_channel_names = list(probe_channel_names) + device_channel_indices = np.zeros(len(self.channel_ids), dtype=int) + for i, ch in enumerate(self.channel_ids): + index_in_probe = probe_channel_names.index(ch) + device_channel_indices[index_in_probe] = i + probe.set_device_channel_indices(device_channel_indices) + else: + warnings.warn( + "Channel names in the probe do not match the channel ids from Neo. " + "Cannot set device channel indices, but this might lead to incorrect probe geometries" + ) if probe.shank_ids is not None: self.set_probe(probe, in_place=True, group_mode="by_shank") diff --git a/src/spikeinterface/extractors/tests/test_neoextractors.py b/src/spikeinterface/extractors/tests/test_neoextractors.py index f80f62ebf0..f40b4d05ab 100644 --- a/src/spikeinterface/extractors/tests/test_neoextractors.py +++ b/src/spikeinterface/extractors/tests/test_neoextractors.py @@ -121,6 +121,9 @@ class OpenEphysBinaryRecordingTest(RecordingCommonTestSuite, unittest.TestCase): ("openephysbinary/v0.5.x_two_nodes", {"stream_id": "0"}), ("openephysbinary/v0.5.x_two_nodes", {"stream_id": "1"}), ("openephysbinary/v0.6.x_neuropixels_multiexp_multistream", {"stream_id": "0", "block_index": 0}), + # TODO: block_indices 1/2 of v0.6.x_neuropixels_multiexp_multistream have a mismatch in the channel names between + # the settings files (starting with CH0) and structure.oebin (starting at CH1). + # Currently, the extractor will skip remapping to match order in oebin and settings file, raising a warning ("openephysbinary/v0.6.x_neuropixels_multiexp_multistream", {"stream_id": "1", "block_index": 1}), ( "openephysbinary/v0.6.x_neuropixels_multiexp_multistream", From bb4bdaf58ac74136bc2e8492b063481295c710e7 Mon Sep 17 00:00:00 2001 From: Alessio Buccino Date: Mon, 16 Mar 2026 12:04:18 +0100 Subject: [PATCH 3/3] docs: clarify unsigned_to_signed versus offset_to_uV --- doc/how_to/unsigned_to_signed.rst | 34 ++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/doc/how_to/unsigned_to_signed.rst b/doc/how_to/unsigned_to_signed.rst index 969cf27da0..87a861bcc9 100644 --- a/doc/how_to/unsigned_to_signed.rst +++ b/doc/how_to/unsigned_to_signed.rst @@ -53,7 +53,6 @@ For users that receive an error because their :code:`Recording` is unsigned, the Now with the signed dtype of the :code:`Recording` one can use a SpikeInterface pipeline as usual. - If you are curious if your :code:`Recording` is unsigned you can simply check the repr or use :code:`get_dtype()` .. code:: python @@ -89,6 +88,39 @@ while converting the data from unsigned to signed. recording_signed = spre.unsigned_to_signed(recording_unsigned, bit_depth=12) +Reading an unsigned binary file +------------------------------- + +If you have a binary file saved in unsigned integers, you can use the ``si.read_binary`` function to read it into +SpikeInterface: + +.. code:: python + + recording_unsigned = se.read_binary( + file_path, + sampling_frequency=30000., + dtype=np.uint16, + num_channels=384, + gain_to_uV=3.05176, + offset_to_uV=0, + ) + +Note that the ``offset_to_uV`` is not meant to be used to correct for the unsigned nature of the data, +but rather to correct for any additional offset that may be present in the data (e.g., due to the recording equipment). + +The ``unsigned_to_signed`` function will take care of the conversion from unsigned to signed, so you can simply pass +the ``recording_unsigned`` to it: + +.. code:: python + + recording_signed = spre.unsigned_to_signed(recording_unsigned, bit_depth=12) + + +When retrieving traces and scaling them to µV, first the data will be converted from unsigned to signed using the +specified bit depth, and then the gain and offset (in this case 0) will be applied to convert the data to µV. +This ensures that the data is correctly centered around 0 and scaled to the appropriate units for further analysis. + + Additional Notes ----------------