Skip to content

Commit 205744b

Browse files
committed
antoher dynamic determined function removed
1 parent 780d0e3 commit 205744b

File tree

1 file changed

+60
-114
lines changed

1 file changed

+60
-114
lines changed

neo/rawio/blackrockrawio.py

Lines changed: 60 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -187,12 +187,6 @@ def __init__(
187187

188188
# These dictionaries are used internally to map the file specification
189189
# revision of the nsx and nev files to one of the reading routines
190-
self._nsx_params = {
191-
"2.1": self._get_nsx_param_spec_v21,
192-
"2.2": self._get_nsx_param_spec_v22_30,
193-
"2.3": self._get_nsx_param_spec_v22_30,
194-
"3.0": self._get_nsx_param_spec_v22_30,
195-
}
196190
# NEV
197191
self._waveform_size = {
198192
"2.1": self._get_waveform_size_spec_v21,
@@ -399,14 +393,8 @@ def _parse_header(self):
399393
if spec_version in ["2.2", "2.3", "3.0"]:
400394
ext_header = self._nsx_ext_header[nsx_nb]
401395
elif spec_version == "2.1":
402-
ext_header = []
403-
keys = ["labels", "units", "min_analog_val", "max_analog_val", "min_digital_val", "max_digital_val"]
404-
params = self._nsx_params[spec_version](nsx_nb)
405-
for i in range(len(params["labels"])):
406-
d = {}
407-
for key in keys:
408-
d[key] = params[key][i]
409-
ext_header.append(d)
396+
# v2.1 has no extended headers - construct from NEV digitization factors
397+
ext_header = self._build_nsx_v21_ext_header(nsx_nb)
410398

411399
if len(ext_header) > 0:
412400
# in blackrock : one stream per buffer so same id
@@ -455,7 +443,7 @@ def _parse_header(self):
455443
if "timestamp_resolution" in self._nsx_basic_header[nsx_nb].dtype.names:
456444
ts_res = self._nsx_basic_header[nsx_nb]["timestamp_resolution"]
457445
elif spec == "2.1":
458-
ts_res = self._nsx_params[spec](nsx_nb)["timestamp_resolution"]
446+
ts_res = 30_000 # v2.1 always uses 30kHz timestamp resolution
459447
else:
460448
ts_res = 30_000
461449
period = self._nsx_basic_header[nsx_nb]["period"]
@@ -1053,12 +1041,15 @@ def _parse_nsx_data_v21(self, nsx_nb):
10531041
# Create file memmap
10541042
file_memmap = np.memmap(filename, dtype='uint8', mode='r')
10551043

1056-
# Get parameters
1057-
params = self._nsx_params["2.1"](nsx_nb)
1044+
# Calculate header size and data points for v2.1
10581045
channels = int(self._nsx_basic_header[nsx_nb]["channel_count"])
1059-
num_samples = int(params["nb_data_points"])
1060-
offset = int(params["bytes_in_headers"])
1061-
1046+
bytes_in_headers = (
1047+
self._nsx_basic_header[nsx_nb].dtype.itemsize
1048+
+ self._nsx_ext_header[nsx_nb].dtype.itemsize * channels
1049+
)
1050+
filesize = self._get_file_size(filename)
1051+
num_samples = int((filesize - bytes_in_headers) / (2 * channels) - 1)
1052+
offset = bytes_in_headers
10621053
# Create data view into memmap
10631054
data = np.ndarray(
10641055
shape=(num_samples, channels),
@@ -1330,6 +1321,52 @@ def _segment_nsx_data(self, data_blocks_dict, nsx_nb):
13301321

13311322
return segments
13321323

1324+
def _build_nsx_v21_ext_header(self, nsx_nb):
1325+
"""
1326+
Build extended header structure for v2.1 NSX files.
1327+
1328+
v2.1 NSX files don't have extended headers with analog/digital ranges.
1329+
We estimate these from the digitization factor in the NEV file.
1330+
dig_factor = max_analog_val / max_digital_val
1331+
We set max_digital_val = 1000, so max_analog_val = dig_factor
1332+
dig_factor is in nV, so units are uV.
1333+
1334+
Information from Kian Torab, Blackrock Microsystems.
1335+
"""
1336+
ext_header = []
1337+
1338+
for i, elid in enumerate(self._nsx_ext_header[nsx_nb]["electrode_id"]):
1339+
# Get digitization factor from NEV
1340+
if self._avail_files["nev"]:
1341+
# Workaround for DigitalFactor overflow in buggy Cerebus systems
1342+
# Fix from NPMK toolbox (openNEV, line 464, git rev d0a25eac)
1343+
dig_factor = self._nev_params("digitization_factor")[elid]
1344+
if dig_factor == 21516:
1345+
dig_factor = 152592.547
1346+
units = "uV"
1347+
else:
1348+
dig_factor = float("nan")
1349+
units = ""
1350+
if i == 0: # Only warn once
1351+
warnings.warn("Cannot rescale to voltage, raw data will be returned.", UserWarning)
1352+
1353+
# Generate label
1354+
if elid < 129:
1355+
label = f"chan{elid}"
1356+
else:
1357+
label = f"ainp{(elid - 129 + 1)}"
1358+
1359+
ext_header.append({
1360+
"labels": label,
1361+
"units": units,
1362+
"min_analog_val": -float(dig_factor),
1363+
"max_analog_val": float(dig_factor),
1364+
"min_digital_val": -1000,
1365+
"max_digital_val": 1000,
1366+
})
1367+
1368+
return ext_header
1369+
13331370
def _read_nev_header(self, spec, filename):
13341371
"""
13351372
Extract nev header information for any specification version.
@@ -1607,9 +1644,8 @@ def _match_nsx_and_nev_segment_ids(self, nsx_nb):
16071644
if len(data[mask_after_seg]) > 0:
16081645
# Warning if spikes are after last segment
16091646
if i == len(list_nonempty_nsx_segments) - 1:
1610-
timestamp_resolution = self._nsx_params[self._nsx_spec[nsx_nb]](
1611-
"timestamp_resolution", nsx_nb
1612-
)
1647+
# Get timestamp resolution from header (available for v2.2+)
1648+
timestamp_resolution = self._nsx_basic_header[nsx_nb]["timestamp_resolution"]
16131649
time_after_seg = (
16141650
data[mask_after_seg]["timestamp"][-1] - end_of_current_nsx_seg
16151651
) / timestamp_resolution
@@ -1828,96 +1864,6 @@ def _get_left_sweep_waveforms(self):
18281864

18291865
return wf_left_sweep
18301866

1831-
def _get_nsx_param_spec_v21(self, nsx_nb):
1832-
"""
1833-
Returns parameter (param_name) for a given nsx (nsx_nb) for file spec
1834-
2.1.
1835-
"""
1836-
# Here, min/max_analog_val and min/max_digital_val are not available in
1837-
# the nsx, so that we must estimate these parameters from the
1838-
# digitization factor of the nev (information by Kian Torab, Blackrock
1839-
# Microsystems). Here dig_factor=max_analog_val/max_digital_val. We set
1840-
# max_digital_val to 1000, and max_analog_val=dig_factor. dig_factor is
1841-
# given in nV by definition, so the units turn out to be uV.
1842-
labels = []
1843-
dig_factor = []
1844-
for elid in self._nsx_ext_header[nsx_nb]["electrode_id"]:
1845-
if self._avail_files["nev"]:
1846-
# This is a workaround for the DigitalFactor overflow in NEV
1847-
# files recorded with buggy Cerebus system.
1848-
# Fix taken from: NMPK toolbox by Blackrock,
1849-
# file openNEV, line 464,
1850-
# git rev. d0a25eac902704a3a29fa5dfd3aed0744f4733ed
1851-
df = self._nev_params("digitization_factor")[elid]
1852-
if df == 21516:
1853-
df = 152592.547
1854-
dig_factor.append(df)
1855-
else:
1856-
dig_factor.append(float("nan"))
1857-
1858-
if elid < 129:
1859-
labels.append(f"chan{elid}")
1860-
else:
1861-
labels.append(f"ainp{(elid - 129 + 1)}")
1862-
1863-
filename = ".".join([self._filenames["nsx"], f"ns{nsx_nb}"])
1864-
1865-
bytes_in_headers = (
1866-
self._nsx_basic_header[nsx_nb].dtype.itemsize
1867-
+ self._nsx_ext_header[nsx_nb].dtype.itemsize * self._nsx_basic_header[nsx_nb]["channel_count"]
1868-
)
1869-
1870-
if np.isnan(dig_factor[0]):
1871-
units = ""
1872-
warnings.warn("Cannot rescale to voltage, raw data will be returned.", UserWarning)
1873-
else:
1874-
units = "uV"
1875-
1876-
nsx_parameters = {
1877-
"nb_data_points": int(
1878-
(int(self._get_file_size(filename)) - int(bytes_in_headers))
1879-
/ int(2 * self._nsx_basic_header[nsx_nb]["channel_count"])
1880-
- 1
1881-
),
1882-
"labels": labels,
1883-
"units": np.array([units] * self._nsx_basic_header[nsx_nb]["channel_count"]),
1884-
"min_analog_val": -1 * np.array(dig_factor, dtype="float"),
1885-
"max_analog_val": np.array(dig_factor, dtype="float"),
1886-
"min_digital_val": np.array([-1000] * self._nsx_basic_header[nsx_nb]["channel_count"]),
1887-
"max_digital_val": np.array([1000] * self._nsx_basic_header[nsx_nb]["channel_count"]),
1888-
"timestamp_resolution": 30000,
1889-
"bytes_in_headers": bytes_in_headers,
1890-
"sampling_rate": 30000 / self._nsx_basic_header[nsx_nb]["period"] * pq.Hz,
1891-
"time_unit": pq.CompoundUnit(f"1.0/{30000 / self._nsx_basic_header[nsx_nb]['period']}*s"),
1892-
}
1893-
1894-
# Returns complete dictionary because then it does not need to be called so often
1895-
return nsx_parameters
1896-
1897-
def _get_nsx_param_spec_v22_30(self, param_name, nsx_nb):
1898-
"""
1899-
Returns parameter (param_name) for a given nsx (nsx_nb) for file spec
1900-
2.2 and 2.3.
1901-
"""
1902-
nsx_parameters = {
1903-
"labels": self._nsx_ext_header[nsx_nb]["electrode_label"],
1904-
"units": self._nsx_ext_header[nsx_nb]["units"],
1905-
"min_analog_val": self._nsx_ext_header[nsx_nb]["min_analog_val"],
1906-
"max_analog_val": self._nsx_ext_header[nsx_nb]["max_analog_val"],
1907-
"min_digital_val": self._nsx_ext_header[nsx_nb]["min_digital_val"],
1908-
"max_digital_val": self._nsx_ext_header[nsx_nb]["max_digital_val"],
1909-
"timestamp_resolution": self._nsx_basic_header[nsx_nb]["timestamp_resolution"],
1910-
"bytes_in_headers": self._nsx_basic_header[nsx_nb]["bytes_in_headers"],
1911-
"sampling_rate": self._nsx_basic_header[nsx_nb]["timestamp_resolution"]
1912-
/ self._nsx_basic_header[nsx_nb]["period"]
1913-
* pq.Hz,
1914-
"time_unit": pq.CompoundUnit(
1915-
f"1.0/{self._nsx_basic_header[nsx_nb]['timestamp_resolution'] / self._nsx_basic_header[nsx_nb]['period']}*s"
1916-
),
1917-
}
1918-
1919-
return nsx_parameters[param_name]
1920-
19211867
def _get_nonneural_evdicts_spec_v21_22(self, data):
19221868
"""
19231869
Defines event types and the necessary parameters to extract them from
@@ -2630,7 +2576,7 @@ def _is_set(self, flag, pos):
26302576
"2.1": None,
26312577
# Versions 2.2+ use data block headers with timestamp size based on major version
26322578
"2.2": [("header_flag", "uint8"), ("timestamp", "uint32"), ("nb_data_points", "uint32")],
2633-
"2.3": [("header_flag", "uint8"), ("timestamp", "uint32"), ("nb_data_points", "uint32")],
2579+
"2.3": [("header_flag", "uint8"), ("timestamp", "uint32"), ("nb_data_points", "uint32")],
26342580
"3.0": [("header_flag", "uint8"), ("timestamp", "uint64"), ("nb_data_points", "uint32")],
26352581
# PTP variant has a completely different structure with samples embedded
26362582
"3.0-ptp": lambda channel_count: [

0 commit comments

Comments
 (0)