Source code for baseband.dada.payload

# Licensed under the GPLv3 - see LICENSE
"""Payload for DADA format."""
from collections import namedtuple

import numpy as np

from ..base.payload import PayloadBase


__all__ = ['DADAPayload', "MKBFPayload"]


def decode_8bit(words):
    return words.view(np.int8, np.ndarray).astype(np.float32)


def encode_8bit(values):
    return np.clip(np.rint(values), -128, 127).astype(np.int8)


[docs] class DADAPayload(PayloadBase): """Container for decoding and encoding DADA payloads. Parameters ---------- words : `~numpy.ndarray` Array containg LSB unsigned words (with the right size) that encode the payload. header : `~baseband.dada.DADAHeader` Header that provides information about how the payload is encoded. If not given, the following arguments have to be passed in. bps : int, optional Number of bits per sample part (i.e., per channel and per real or imaginary component). Default: 8. sample_shape : tuple, optional Shape of the samples; e.g., (nchan,). Default: (). complex_data : bool, optional Whether data are complex. Default: `False`. """ _decoders = { 8: decode_8bit} _encoders = { 8: encode_8bit} _memmap = True _sample_shape_maker = namedtuple('SampleShape', 'npol, nchan') def __new__(cls, words, *, header=None, **kwargs): # Override instrument if header is given. if header is not None and header.get("INSTRUMENT") == "MKBF": cls = MKBFPayload return super().__new__(cls)
[docs] class MKBFPayload(DADAPayload): """Container for decoding and encoding MKBF DADA payloads. Subclass of `~baseband.dada.DADAPayload` that takes into account that the samples are organized in heaps of 256 samples, with order (nheap, npol, nchan, nsub=256). Some information on the instrument writing it can be found in `Van der Byl et al. 2021 <https://doi.org/10.1117/1.JATIS.8.1.011006>`_ """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Change view of words to indicate one element containts 256 # samples for each part of the sample_shape (this also ensures # bpw=bits-per-word is correct in _item_to_slices). self._dtype_word = np.dtype( [("heaps", [("real", f"int{self.bps}"), ("imag", f"int{self.bps}")], self.sample_shape + (256,))]) self.words = self.words.view(self._dtype_word) def _decode(self, words, data_slice=()): words = np.moveaxis(words["heaps"], -1, 1).ravel().reshape( -1, *self.sample_shape)[data_slice] return super()._decode(words) def _encode(self, data): data = np.moveaxis(data.reshape(-1, 256, *self.sample_shape), 1, -1) return super()._encode(data) def __getitem__(self, item=()): words_slice, data_slice = self._item_to_slices(item) return self._decode(self.words[words_slice], data_slice) data = property(__getitem__, doc="Full decoded payload.")