Skip to content

Commit 355754f

Browse files
committed
done, comments and warning
1 parent 8ba7849 commit 355754f

1 file changed

Lines changed: 35 additions & 21 deletions

File tree

src/probeinterface/neuropixels_tools.py

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,7 @@ def _interpret_imro_string(imro_table_string: str, probe_part_number: str) -> di
715715
for field, field_value in zip(imro_fields, values):
716716
imro_per_channel[field].append(field_value)
717717

718-
# Resolve electrode IDs for probe types whose IMRO format does not include them.
718+
# Resolve activate electrodes (i.e. `electrodes` entry) for probe types whose IMRO format does not include them.
719719
# NP2.x+ probes have "electrode" directly in the IMRO table. NP1.x probes encode
720720
# electrode selection indirectly and need computation.
721721
if "electrode" not in imro_per_channel:
@@ -776,6 +776,17 @@ def _resolve_active_contacts_for_np1110(imro_per_channel: dict, imro_table_strin
776776
if "group" not in imro_per_channel:
777777
return
778778

779+
# TODO: Remove this warning once we have test data for NP1110 recordings.
780+
warnings.warn(
781+
"NP1110 (Neuropixels 1.0 UHD2 active) support is experimental. "
782+
"The active electrode selection logic is translated directly from SpikeGLX "
783+
"(https://github.com/billkarsh/SpikeGLX, Src-imro/IMROTbl_T1110.cpp) but has not "
784+
"been validated against real NP1110 recordings. Please double-check the electrode "
785+
"selection and report any issues at https://github.com/SpikeInterface/probeinterface/issues",
786+
UserWarning,
787+
stacklevel=3, # Points to read_imro / read_spikeglx (caller of _interpret_imro_string)
788+
)
789+
779790
# Extract col_mode from IMRO header: (type,col_mode,ref_id,ap_gain,lf_gain,ap_hipas_flt)
780791
header_str = imro_table_string.strip().split(")")[0][1:] # remove leading "("
781792
header_fields = header_str.split(",")
@@ -784,51 +795,54 @@ def _resolve_active_contacts_for_np1110(imro_per_channel: dict, imro_table_strin
784795
groups_bankA = imro_per_channel["bankA"]
785796
groups_bankB = imro_per_channel["bankB"]
786797

798+
# With pain in my heart, I am following here the C++ convention of terse naming from the
799+
# original SpikeGLX implementation (IMROTbl_T1110.cpp). The purpose is to make it easy to
800+
# spot differences when comparing against the original code, until we have real NP1110 test
801+
# data to validate against and feel comfortable (if ever) renaming to our own conventions.
787802
col_tbl = [0, 3, 1, 2, 1, 2, 0, 3]
788803

789-
def _grp_idx(ch):
804+
def grpIdx(ch):
790805
return 2 * ((ch % 384) // 32) + ((ch % 384) & 1)
791806

792-
def _col(ch, bank):
793-
grp_index = _grp_idx(ch)
794-
grp_col = col_tbl[4 * (bank & 1) + (grp_index % 4)]
807+
def col(ch, bank):
808+
grp_col = col_tbl[4 * (bank & 1) + (grpIdx(ch) % 4)]
795809
crossed = (bank // 4) & 1
796810
ingrp_col = ((((ch % 64) % 32) // 2) & 1) ^ crossed
797811
if ch & 1:
798812
return 2 * grp_col + (1 - ingrp_col)
799813
else:
800814
return 2 * grp_col + ingrp_col
801815

802-
def _row(ch, bank):
803-
grp_index = _grp_idx(ch)
804-
grp_row = grp_index // 4
816+
def row(ch, bank):
817+
grp_row = grpIdx(ch) // 4
805818
ingrp_row = ((ch % 64) % 32) // 4
806819
if ch & 1:
807820
b0_row = 8 * grp_row + (7 - ingrp_row)
808821
else:
809822
b0_row = 8 * grp_row + ingrp_row
810823
return 48 * bank + b0_row
811824

812-
def _bank_for_channel(ch, bankA, bankB):
825+
def bank(ch, bankA, bankB):
813826
if col_mode == 2: # ALL
814827
return bankA
815828
# INNER (0) or OUTER (1): choose bankA or bankB based on column position
816-
c = _col(ch, bankA)
817-
if c < 4:
818-
use_bankA = (c % 2 == 0) if col_mode == 1 else (c % 2 == 1)
829+
c = col(ch, bankA)
830+
if c <= 3:
831+
if col_mode == 1: # OUTER
832+
return bankA if not (c & 1) else bankB
833+
else: # INNER
834+
return bankA if (c & 1) else bankB
819835
else:
820-
use_bankA = (c % 2 == 1) if col_mode == 1 else (c % 2 == 0)
821-
return bankA if use_bankA else bankB
836+
if col_mode == 1: # OUTER
837+
return bankA if (c & 1) else bankB
838+
else: # INNER
839+
return bankA if not (c & 1) else bankB
822840

823841
electrode_ids = []
824842
for ch in range(384):
825-
grp = _grp_idx(ch)
826-
bankA = groups_bankA[grp]
827-
bankB = groups_bankB[grp]
828-
bank = _bank_for_channel(ch, bankA, bankB)
829-
row = _row(ch, bank)
830-
col = _col(ch, bank)
831-
electrode_ids.append(8 * row + col)
843+
grp = grpIdx(ch)
844+
b = bank(ch, groups_bankA[grp], groups_bankB[grp])
845+
electrode_ids.append(8 * row(ch, b) + col(ch, b))
832846

833847
imro_per_channel["electrode"] = electrode_ids
834848
# Also add the "channel" key (0-383) since the IMRO entries are per-group, not per-channel

0 commit comments

Comments
 (0)