@@ -745,36 +745,43 @@ def read_spikeglx(file: str | Path) -> Probe:
745745 for field , field_value in zip (imro_fields , values ):
746746 contact_info [field ].append (field_value )
747747
748- # Extract electrode IDs from IMRO table
749- channel_ids = np .array (contact_info ["channel" ])
748+ # Convert IMRO channel numbers to physical electrode IDs
749+ # The IMRO table specifies which electrodes were recorded, but different probe types
750+ # encode this information differently:
751+ readout_channel_ids = np .array (contact_info ["channel" ]) # 0-383 for NP1.0
752+
750753 if "electrode" in contact_info :
751- elec_ids = np .array (contact_info ["electrode" ])
754+ # NP2.0 and some probes directly specify the physical electrode ID
755+ physical_electrode_ids = np .array (contact_info ["electrode" ])
752756 else :
753- if contact_info . get ( "bank" ) is not None :
754- bank_key = " bank"
755- elif contact_info . get ( "bank_mask" ) is not None :
756- bank_key = "bank_mask"
757- banks = np .array (contact_info [bank_key ])
758- elec_ids = banks * 384 + channel_ids
757+ # NP1.0 uses banks to encode electrode position
758+ # Physical electrode ID = bank * 384 + channel
759+ # (e.g., bank 0, channel 0 → electrode 0; bank 1, channel 0 → electrode 384)
760+ bank_key = "bank" if "bank" in contact_info else "bank_mask"
761+ bank_indices = np .array (contact_info [bank_key ])
762+ physical_electrode_ids = bank_indices * 384 + readout_channel_ids
759763
760764 # ===== 4. Slice full probe to IMRO-selected electrodes =====
761- # Match the electrode IDs from IMRO table to contacts in the full probe
762- keep_indices = []
763- for elec_id in elec_ids :
764- # For multi-shank probes, we need to check if shank info is in contact_info
765+ # The full probe has all electrodes (e.g., 960 for NP1.0). We need to find which
766+ # indices in the full probe array correspond to the electrodes selected in the IMRO table.
767+ selected_contact_indices = []
768+
769+ for idx , electrode_id in enumerate (physical_electrode_ids ):
770+ # Build the contact ID string that matches the full probe's contact_ids array
765771 if "shank" in contact_info :
766- # Get the shank for this electrode from IMRO table
767- shank_idx = contact_info ["shank" ][len ( keep_indices ) ]
768- contact_id = f"s{ shank_idx } e{ elec_id } "
772+ # Multi- shank probes: contact ID = "s{shank}e{electrode}"
773+ shank_id = contact_info ["shank" ][idx ]
774+ contact_id_str = f"s{ shank_id } e{ electrode_id } "
769775 else :
770- contact_id = f"e{ elec_id } "
776+ # Single-shank probes: contact ID = "e{electrode}"
777+ contact_id_str = f"e{ electrode_id } "
771778
772- # Search for this contact ID in the full probe
773- matching_indices = np .where (full_probe .contact_ids == contact_id )[0 ]
774- if len (matching_indices ) > 0 :
775- keep_indices .append (matching_indices [0 ])
779+ # Find where this contact appears in the full probe
780+ full_probe_index = np .where (full_probe .contact_ids == contact_id_str )[0 ]
781+ if len (full_probe_index ) > 0 :
782+ selected_contact_indices .append (full_probe_index [0 ])
776783
777- probe = full_probe .get_slice (np .array (keep_indices , dtype = int ))
784+ probe = full_probe .get_slice (np .array (selected_contact_indices , dtype = int ))
778785
779786 # Add IMRO-specific contact annotations (acquisition settings)
780787 probe .annotate (probe_type = probe_type )
@@ -805,9 +812,7 @@ def read_spikeglx(file: str | Path) -> Probe:
805812 probe .annotate (slot = imDatPrb_slot )
806813
807814 # ===== 7. Set device channel indices (wiring) =====
808- # Device channel indices map probe contacts to data file channels.
809- # After all slicing, channels are numbered 0, 1, 2, ... N-1 in the order they appear
810- # in the binary data file, so we wire them sequentially.
815+ # I am unsure why are we are doing this. If someone knows please document it here.
811816 probe .set_device_channel_indices (np .arange (probe .get_contact_count ()))
812817
813818 return probe
0 commit comments