Decoding packed sensor samples#
Many data acquisition formats pack fixed-width readings without padding each sample to a full byte. Here each ADC reading is 12 bits, so four samples fit in six bytes.
from tibs import Tibs
BITS_PER_SAMPLE = 12
ADC_MAX = (1 << BITS_PER_SAMPLE) - 1
REFERENCE_VOLTS = 3.3
def pack_samples(samples):
return Tibs.from_joined(
Tibs.from_u(sample, BITS_PER_SAMPLE)
for sample in samples
)
def unpack_samples(payload):
bits = Tibs.from_bytes(payload)
complete_samples = len(bits) // BITS_PER_SAMPLE
return [
sample.u
for sample in bits.chunks(BITS_PER_SAMPLE, complete_samples)
]
def sample_to_volts(sample):
return sample * REFERENCE_VOLTS / ADC_MAX
samples = [0, 103, 2048, 4095]
packed = pack_samples(samples)
assert packed.hex == "000067800fff"
assert packed.bytes.hex() == "000067800fff"
round_tripped = unpack_samples(packed.bytes)
assert round_tripped == samples
voltages = [round(sample_to_volts(sample), 3) for sample in round_tripped]
assert voltages == [0.0, 0.083, 1.65, 3.3]
The example trims the byte stream to the number of complete samples before chunking it. That is useful when a real transport pads the final byte or record.