Skip to content

Commit cf39185

Browse files
Merge pull request #16 from jsiegle/main
Update Open Ephys data reader
2 parents f07d131 + a85e835 commit cf39185

File tree

1 file changed

+57
-45
lines changed

1 file changed

+57
-45
lines changed

element_array_ephys/readers/openephys.py

Lines changed: 57 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
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
1010
Record Node 102
@@ -14,8 +14,8 @@
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

97106
class 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

Comments
 (0)