diff --git a/sigmf/__init__.py b/sigmf/__init__.py index 4bbd62b..1987443 100644 --- a/sigmf/__init__.py +++ b/sigmf/__init__.py @@ -5,7 +5,7 @@ # SPDX-License-Identifier: LGPL-3.0-or-later # version of this python module -__version__ = "1.5.0" +__version__ = "1.5.1" # matching version of the SigMF specification __specification__ = "1.2.6" diff --git a/sigmf/sigmffile.py b/sigmf/sigmffile.py index c40e7e8..a72043e 100644 --- a/sigmf/sigmffile.py +++ b/sigmf/sigmffile.py @@ -314,50 +314,59 @@ def __next__(self): raise StopIteration def __getitem__(self, sli): - mem = self._memmap[sli] # matches behavior of numpy.ndarray.__getitem__() + """ + Enable slicing and indexing into the dataset samples. - # apply _return_type conversion if set - if self._return_type is None: - # no special conversion needed - if not self.autoscale: - return mem - else: - # apply autoscaling for fixed-point data when autoscale=True - dtype = dtype_info(self.get_global_field(self.DATATYPE_KEY)) - is_fixedpoint_data = dtype["is_fixedpoint"] - - if is_fixedpoint_data: - # apply scaling for fixed-point data - is_unsigned_data = dtype["is_unsigned"] - component_size = dtype["component_size"] - data_type_out = np.dtype("f4") if not self.is_complex_data else np.dtype("f4, f4") - - data = mem.astype(data_type_out) - data = data.view(np.dtype("f4")) + Should match behavior of ndarray.__getitem__() and apply autoscaling similar to read_samples(). + """ + mem = self._memmap[sli] + + # apply autoscaling for fixed-point data when autoscale=True + if self.autoscale: + dtype = dtype_info(self.get_global_field(self.DATATYPE_KEY)) + if dtype["is_fixedpoint"]: + # extract scaling parameters + is_unsigned_data = dtype["is_unsigned"] + component_size = dtype["component_size"] + + # convert to float and apply scaling + if self.is_complex_data: + # for complex data, mem is shaped (..., 2) where last dim is [real, imag] + real_part = mem[..., 0].astype(np.float32) + imag_part = mem[..., 1].astype(np.float32) + + # apply scaling to both parts + if is_unsigned_data: + real_part -= 2 ** (component_size * 8 - 1) + imag_part -= 2 ** (component_size * 8 - 1) + real_part *= 2 ** -(component_size * 8 - 1) + imag_part *= 2 ** -(component_size * 8 - 1) + + # combine into complex numbers + data = real_part + 1.0j * imag_part + else: + # for real data, direct scaling + data = mem.astype(np.float32) if is_unsigned_data: data -= 2 ** (component_size * 8 - 1) data *= 2 ** -(component_size * 8 - 1) - data = data.view(data_type_out) - if self.is_complex_data: - data = data.view(np.complex64) - # for single-channel complex data, flatten the last dimension - if data.ndim > 1 and self.num_channels == 1: - data = data.flatten() - return data[0] if isinstance(sli, int) else data - else: - # floating-point data, no scaling needed - return mem - - # handle complex data type conversion - if self._memmap.ndim == 2: - # num_channels == 1 - ray = mem[:, 0].astype(self._return_type) + 1.0j * mem[:, 1].astype(self._return_type) - elif self._memmap.ndim == 3: - # num_channels > 1 - ray = mem[:, :, 0].astype(self._return_type) + 1.0j * mem[:, :, 1].astype(self._return_type) - else: - raise ValueError("unhandled ndim in SigMFFile.__getitem__(); this shouldn't happen") - return ray[0] if isinstance(sli, int) else ray # return element instead of 1-element array + + return data + + # handle complex data type conversion if _return_type is set (no autoscaling was applied) + if self._return_type is not None: + if self._memmap.ndim == 2: + # num_channels == 1 + ray = mem[:, 0].astype(self._return_type) + 1.0j * mem[:, 1].astype(self._return_type) + elif self._memmap.ndim == 3: + # num_channels > 1 + ray = mem[:, :, 0].astype(self._return_type) + 1.0j * mem[:, :, 1].astype(self._return_type) + else: + raise ValueError("unhandled ndim in SigMFFile.__getitem__(); this shouldn't happen") + return ray[0] if isinstance(sli, int) else ray # return element instead of 1-element array + + # return raw data (no autoscaling, no complex conversion needed) + return mem def get_num_channels(self): """Return integer number of channels."""