Source code for ezmsg.sigproc.quantize
import numpy as np
import ezmsg.core as ez
from ezmsg.util.messages.axisarray import AxisArray, replace
from .base import BaseTransformer, BaseTransformerUnit
[docs]
class QuantizeSettings(ez.Settings):
"""
Settings for the Quantizer.
"""
max_val: float
"""
Clip the data to this maximum value before quantization and map the [min_val max_val] range to the quantized range.
"""
min_val: float = 0.0
"""
Clip the data to this minimum value before quantization and map the [min_val max_val] range to the quantized range.
Default: 0
"""
bits: int = 8
"""
Number of bits for quantization.
Note: The data type will be integer of the next power of 2 greater than or equal to this value.
Default: 8
"""
[docs]
class QuantizeTransformer(BaseTransformer[QuantizeSettings, AxisArray, AxisArray]):
def _process(
self,
message: AxisArray,
) -> AxisArray:
expected_range = self.settings.max_val - self.settings.min_val
scale_factor = 2**self.settings.bits - 1
clip_max = self.settings.max_val
# Determine appropriate integer type based on bits
if self.settings.bits <= 1:
dtype = bool
elif self.settings.bits <= 8:
dtype = np.uint8
elif self.settings.bits <= 16:
dtype = np.uint16
elif self.settings.bits <= 32:
dtype = np.uint32
else:
dtype = np.uint64
if self.settings.bits == 64:
# The practical upper bound before converting to int is: 2**64 - 1025
# Anything larger will wrap around to 0.
#
clip_max *= 1 - 2e-16
data = message.data.clip(self.settings.min_val, clip_max)
data = (data - self.settings.min_val) / expected_range
# Scale to the quantized range [0, 2^bits - 1]
data = np.rint(scale_factor * data).astype(dtype)
# Create a new AxisArray with the quantized data
return replace(message, data=data)
[docs]
class QuantizerUnit(
BaseTransformerUnit[QuantizeSettings, AxisArray, AxisArray, QuantizeTransformer]
):
SETTINGS = QuantizeSettings