44
55
66"""
7- OpenEphys plug-in for Neuropixels recording saves data in binary format the following the directory structure:
7+ The Open Ephys Record Node saves Neuropixels data in binary format according to the following the directory structure:
88(https://open-ephys.github.io/gui-docs/User-Manual/Recording-data/Binary-format.html)
99
1010Record Node 102
1414 -- continuous
1515 -- Neuropix-PXI-100.0 (probe0 ap)
1616 -- Neuropix-PXI-100.1 (probe0 lf)
17- -- Neuropix-PXI-101.0 (probe1 ap)
18- -- Neuropix-PXI-101.1 (probe1 lf)
17+ -- Neuropix-PXI-100.2 (probe1 ap)
18+ -- Neuropix-PXI-100.3 (probe1 lf)
1919 ...
2020 -- events
2121 -- spikes
@@ -46,8 +46,8 @@ def __init__(self, experiment_dir):
4646
4747 def load_probe_data (self ):
4848 """
49- Loop through all OpenEphys "processors", identify the processor for
50- neuropixels probe, extract probe info
49+ Loop through all Open Ephys "processors", identify the processor for
50+ the Neuropixels probe(s) , extract probe info
5151 Loop through all recordings, associate recordings to
5252 the matching probes, extract recording info
5353
@@ -58,53 +58,65 @@ def load_probe_data(self):
5858 probes = {}
5959 for processor in self .experiment .settings ['SIGNALCHAIN' ]['PROCESSOR' ]:
6060 if processor ['@pluginName' ] in ('Neuropix-PXI' , 'Neuropix-3a' ):
61- oe_probe = Probe (processor )
62- for rec in self .experiment .recordings :
63- for cont_info , analog_signal in zip (rec ._oebin ['continuous' ],
64- rec .analog_signals ):
65- if cont_info ['source_processor_id' ] != oe_probe .processor_id :
66- continue
67-
68- if cont_info ['source_processor_sub_idx' ] == 0 : # ap data
69- assert cont_info ['sample_rate' ] == analog_signal .sample_rate == 30000
70- cont_type = 'ap'
71-
72- oe_probe .recording_info ['recording_count' ] += 1
73- oe_probe .recording_info ['recording_datetimes' ].append (
74- rec .datetime )
75- oe_probe .recording_info ['recording_durations' ].append (
76- float (rec .duration ))
77- oe_probe .recording_info ['recording_files' ].append (
78- rec .absolute_foldername / 'continuous' / cont_info ['folder_name' ])
79-
80- elif cont_info ['source_processor_sub_idx' ] == 1 : # lfp data
81- assert cont_info ['sample_rate' ] == analog_signal .sample_rate == 2500
82- cont_type = 'lfp'
83-
84- if getattr (oe_probe , cont_type + '_meta' ) is None :
85- cont_info ['channels_ids' ] = analog_signal .channel_ids
86- cont_info ['channels_names' ] = analog_signal .channel_names
87- cont_info ['channels_gains' ] = analog_signal .gains
88- setattr (oe_probe , cont_type + '_meta' , cont_info )
89-
90- oe_probe .__dict__ [f'{ cont_type } _analog_signals' ].append (analog_signal )
91-
92- probes [oe_probe .probe_SN ] = oe_probe
61+ if processor ['@pluginName' ] == 'Neuropix-3a' :
62+ oe_probe = Probe (processor )
63+ probes [oe_probe .probeSN ] = oe_probe
64+ else :
65+ for probe_index in range (len (processor ['EDITOR' ]['NP_PROBE' ])):
66+ oe_probe = Probe (processor , probe_index )
67+ probes [oe_probe .probe_SN ] = oe_probe
68+
69+ for probe_index , probe_SN in enumerate (probes .keys ()):
70+
71+ oe_probe = probes [probe_SN ]
72+
73+ for rec in self .experiment .recordings :
74+ for cont_info , analog_signal in zip (rec ._oebin ['continuous' ],
75+ rec .analog_signals ):
76+ if cont_info ['source_processor_id' ] != oe_probe .processor_id :
77+ continue
78+
79+ if cont_info ['source_processor_sub_idx' ] == probe_index * 2 : # ap data
80+ assert cont_info ['sample_rate' ] == analog_signal .sample_rate == 30000
81+ cont_type = 'ap'
82+
83+ oe_probe .recording_info ['recording_count' ] += 1
84+ oe_probe .recording_info ['recording_datetimes' ].append (
85+ rec .datetime )
86+ oe_probe .recording_info ['recording_durations' ].append (
87+ float (rec .duration ))
88+ oe_probe .recording_info ['recording_files' ].append (
89+ rec .absolute_foldername / 'continuous' / cont_info ['folder_name' ])
90+
91+ elif cont_info ['source_processor_sub_idx' ] == probe_index * 2 + 1 : # lfp data
92+ assert cont_info ['sample_rate' ] == analog_signal .sample_rate == 2500
93+ cont_type = 'lfp'
94+
95+ if getattr (oe_probe , cont_type + '_meta' ) is None :
96+ cont_info ['channels_ids' ] = analog_signal .channel_ids
97+ cont_info ['channels_names' ] = analog_signal .channel_names
98+ cont_info ['channels_gains' ] = analog_signal .gains
99+ setattr (oe_probe , cont_type + '_meta' , cont_info )
100+
101+ oe_probe .__dict__ [f'{ cont_type } _analog_signals' ].append (analog_signal )
93102
94103 return probes
95104
96105
97106class Probe :
98107
99- def __init__ (self , processor ):
108+ def __init__ (self , processor , probe_index = 0 ):
100109 self .processor_id = int (processor ['@NodeId' ])
101- self .probe_info = processor ['EDITOR' ]['PROBE' ]
102- self .probe_SN = self .probe_info ['@probe_serial_number' ]
103-
104- # Determine probe-model (TODO: how to determine npx 2.0 SS and MS?)
105- self .probe_model = {
106- "Neuropix-PXI" : "neuropixels 1.0 - 3B" ,
107- "Neuropix-3a" : "neuropixels 1.0 - 3A" }[processor ['@pluginName' ]]
110+
111+ if processor ['@pluginName' ] == 'Neuropix-3a' :
112+
113+ self .probe_info = processor ['EDITOR' ]['PROBE' ]
114+ self .probe_SN = self .probe_info ['@probe_serial_number' ]
115+ self .probe_model = "Neuropixels 3A"
116+ else :
117+ self .probe_info = processor ['EDITOR' ]['NP_PROBE' ][probe_index ]
118+ self .probe_SN = self .probe_info ['@probe_serial_number' ]
119+ self .probe_model = self .probe_info ['@probe_name' ]
108120
109121 self .ap_meta = None
110122 self .lfp_meta = None
0 commit comments