Skip to content

Multi-Channel Memory Layout

rfsoc_rfdc.multi_ch_mem_layout

Classes

MCHMemLayout

Bases: ABC

Source code in rfsoc_rfdc/multi_ch_mem_layout.py
class MCHMemLayout(ABC):

    def __init__(self, channel_count, dp_vect_dim):
        self.channel_count = channel_count
        self.dp_vect_dim = dp_vect_dim

    @abstractmethod
    def gen_layout(self, mch_i_samples, mch_q_samples):
        """Generate memory layout given I/Q samples for each DAC channels"""
        pass

    @abstractmethod
    def dec_layout(self, raw_mch_data):
        """Decode I/Q samples for each ADC channels given interleaved memory layout"""
        pass
Functions
gen_layout(mch_i_samples, mch_q_samples) abstractmethod

Generate memory layout given I/Q samples for each DAC channels

Source code in rfsoc_rfdc/multi_ch_mem_layout.py
@abstractmethod
def gen_layout(self, mch_i_samples, mch_q_samples):
    """Generate memory layout given I/Q samples for each DAC channels"""
    pass
dec_layout(raw_mch_data) abstractmethod

Decode I/Q samples for each ADC channels given interleaved memory layout

Source code in rfsoc_rfdc/multi_ch_mem_layout.py
@abstractmethod
def dec_layout(self, raw_mch_data):
    """Decode I/Q samples for each ADC channels given interleaved memory layout"""
    pass

MchIq2RLayout

Bases: MCHMemLayout

For multi-channel IQ-to-real memory layout generator (Tx)

Source code in rfsoc_rfdc/multi_ch_mem_layout.py
class MchIq2RLayout(MCHMemLayout):
    """For multi-channel IQ-to-real memory layout generator (Tx)"""

    def __init__(self, channel_count, dp_vect_dim):
        super().__init__(channel_count, dp_vect_dim)

    def mch_duplication(self, data):
        """Duplicate the data across multiple channels"""
        return np.tile(data, (1, self.channel_count))

    def gen_layout(self, mch_data):
        # Ensure input mch_data is channel_count x waveform_length
        assert len(
            mch_data.shape) == 2 and mch_data.shape[0] == self.channel_count, f"Wrong dimension for mch_data"

        rows, cols = mch_data.shape

        # Pad zeros
        remains = cols % self.dp_vect_dim
        if remains != 0:
            pad_size = self.dp_vect_dim - remains
            mch_data = np.pad(mch_data, ((0, 0), (0, pad_size)),
                              mode='constant', constant_values=0)

        mch_layout = []
        for col_start in range(0, cols, self.dp_vect_dim):
            for row in range(rows):
                for col in range(col_start, col_start + self.dp_vect_dim):
                    mch_layout.append(int(mch_data[row, col].real))
                    mch_layout.append(int(mch_data[row, col].imag))
        return np.array(mch_layout)

    def dec_layout(self, raw_mch_data):
        raise RuntimeError(f"dec_layout is not available.")
Functions
mch_duplication(data)

Duplicate the data across multiple channels

Source code in rfsoc_rfdc/multi_ch_mem_layout.py
def mch_duplication(self, data):
    """Duplicate the data across multiple channels"""
    return np.tile(data, (1, self.channel_count))

MchR2RLayout

Bases: MCHMemLayout

For multi-channel real-to-real memory layout generator and decoding (Tx and Rx)

Source code in rfsoc_rfdc/multi_ch_mem_layout.py
class MchR2RLayout(MCHMemLayout):
    """For multi-channel real-to-real memory layout generator and decoding (Tx and Rx)"""

    def __init__(self, channel_count, dp_vect_dim):
        super().__init__(channel_count, dp_vect_dim)

    def gen_layout(self, data):
        # Reshape according to the dp_vect_dim count
        vect_dim = np.reshape(data, (-1, self.dp_vect_dim))
        # Duplicate data for multi-channel
        mch_dim = np.tile(vect_dim, (1, self.channel_count))
        # Flatten matrices
        mch = mch_dim.flatten()
        # Interleaved IQ
        return mch

    def dec_layout(self, raw_mch_data):
        arr_size_per_ch = len(raw_mch_data) // self.channel_count
        mch = np.zeros(
            (self.channel_count, arr_size_per_ch), dtype=np.complex128)

        step_size = self.channel_count * self.dp_vect_dim
        for ch in range(self.channel_count):
            if self.dp_vect_dim != 1:
                vect_dimension = np.zeros(
                    (self.dp_vect_dim, arr_size_per_ch // self.dp_vect_dim), dtype=np.complex128)
                for vect in range(self.dp_vect_dim):
                    vect_dimension[vect] = raw_mch_data[self.dp_vect_dim *
                                                        ch + vect::step_size]
                mch[ch] = np.stack(vect_dimension).T.reshape(-1)
            else:  # dp_vect_dim = 1
                iq = raw_mch_data[ch::step_size]
                mch[ch] = iq
        return mch

MchR2IqLayout

Bases: MCHMemLayout

For multi-channel real-to-IQ memory layout decoding (Rx)

Source code in rfsoc_rfdc/multi_ch_mem_layout.py
class MchR2IqLayout(MCHMemLayout):
    """For multi-channel real-to-IQ memory layout decoding (Rx)"""

    def __init__(self, channel_count, dp_vect_dim):
        super().__init__(channel_count, dp_vect_dim)

    def gen_layout(self, iq):
        raise RuntimeError(f"gen_layout function is not available.")

    def dec_layout(self, raw_mch_data):
        arr_size_per_ch = len(raw_mch_data) // self.channel_count
        mch_iq = np.zeros(
            (self.channel_count, arr_size_per_ch), dtype=np.complex128)

        step_size = self.channel_count * self.dp_vect_dim
        for ch in range(self.channel_count):
            if self.dp_vect_dim != 1:
                vect_dimension = np.zeros(
                    (self.dp_vect_dim, arr_size_per_ch // self.dp_vect_dim), dtype=np.complex128)
                for vect in range(self.dp_vect_dim):
                    vect_dimension[vect] = raw_mch_data[self.dp_vect_dim *
                                                        ch + vect::step_size]
                interleaved = np.stack(vect_dimension).T.reshape(-1)
                mch_iq[ch] = interleaved
            else:  # dp_vect_dim = 1
                iq = raw_mch_data[ch::step_size]
                mch_iq[ch] = iq
        return mch_iq