Using pyAerial for PUSCH decoding on Aerial Data Lake data#

This example shows how to use the pyAerial bindings to run cuPHY GPU accelerated PUSCH decoding for 5G NR PUSCH. The 5G NR PUSCH data is read from an example over the air captured PUSCH dataset collected and stored using Aerial Data Lake. A complete PUSCH receiver using individual separate Python function calls to individual PUSCH receiver components is used so that channel estimates can be shown.

In this setup there are two cells:

  • Cell 51 is an active cell being used with the OAI L2+ using slot pattern DDDSU and commercial UEs.

  • Cell 41 is a passive “listener” cell using the same slot pattern as cell 51 but is being driven by testmac to request IQ samples for every uplink slot.

There are multiple UEs connected to cell 51, as is shown in the nUEs field of the fapi table. The first two plots show the power in all of the resource elements for the given slot on both cells. The plots after that show just the resource elements scheduled for a given UE (RNTI) across both cells, as well pre- and post- equalized samples, then channel estimates, for IQ samples from each cell, followed by text indicating whether the transmission decoded successfully.

Note: This example requires that the clickhouse server is running and that the example data has been stored in the database. Refer to the Aerial Data Lake documentation on how to do this. https://docs.nvidia.com/aerial/cuda-accelerated-ran/aerial_data_lake/index.html#clickhouse-client

Imports#

[1]:
import math
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "0"

import numpy as np
import pandas as pd
from IPython.display import Markdown
from IPython.display import display

# Connecting to clickhouse on remote server
import clickhouse_connect

# Plotting with Matplotlib.
import matplotlib.pyplot as plt
from matplotlib import dates as mdates


# pyAerial imports
from aerial.phy5g.config import PuschConfig
from aerial.phy5g.config import PuschUeConfig
from aerial.phy5g.algorithms import ChannelEstimator
from aerial.phy5g.algorithms import ChannelEqualizer
from aerial.phy5g.algorithms import NoiseIntfEstimator
from aerial.phy5g.ldpc import LdpcDeRateMatch
from aerial.phy5g.ldpc import LdpcDecoder
from aerial.phy5g.ldpc import CrcChecker
from aerial.util.cuda import get_cuda_stream
from aerial.util.fapi import dmrs_fapi_to_bit_array

# Hide log10(10) warning
_ = np.seterr(divide='ignore', invalid='ignore')
pd.set_option('display.max_rows', 500)
pd.set_option('display.max_columns', 500)
pd.set_option('display.width', 1000)

np.set_printoptions(threshold=100)  # Control the number of elements to display
np.set_printoptions(edgeitems=100)  # Control the number of edge items to display
np.set_printoptions(linewidth=200) # Control the width of the display

plt.rcParams['figure.figsize'] = [10, 4]

Create the PUSCH pipelines#

This is a PUSCH receiver pipeline made up of separately called pyAerial PUSCH receiver components.

[2]:
# Whether to plot intermediate results within the PUSCH pipeline, such as channel estimates and equalized symbols.
plot_figures = True

num_ues = 1
num_tx_ant = 2             # UE antennas
num_rx_ant = 4             # gNB antennas
enable_pusch_tdi = 0       # Enable time interpolation for equalizer coefficients
eq_coeff_algo = 1          # Equalizer algorithm

# The PUSCH receiver chain built from separately called pyAerial Python components is defined here.
class PuschRxSeparate:
    """PUSCH receiver class.

    This class encapsulates the whole PUSCH receiver chain built using
    pyAerial components.
    """

    def __init__(self,
                 num_rx_ant,
                 enable_pusch_tdi,
                 eq_coeff_algo,
                 plot_figures):
        """Initialize the PUSCH receiver."""
        self.cuda_stream = get_cuda_stream()

        # Build the components of the receiver.
        self.channel_estimator = ChannelEstimator(
            num_rx_ant=num_rx_ant,
            cuda_stream=self.cuda_stream)
        self.channel_equalizer = ChannelEqualizer(
            num_rx_ant=num_rx_ant,
            enable_pusch_tdi=enable_pusch_tdi,
            eq_coeff_algo=eq_coeff_algo,
            cuda_stream=self.cuda_stream)
        self.noise_intf_estimator = NoiseIntfEstimator(
            num_rx_ant=num_rx_ant,
            eq_coeff_algo=eq_coeff_algo,
            cuda_stream=self.cuda_stream)
        self.derate_match = LdpcDeRateMatch(
            enable_scrambling=True,
            cuda_stream=self.cuda_stream)
        self.decoder = LdpcDecoder(cuda_stream=self.cuda_stream)
        self.crc_checker = CrcChecker(cuda_stream=self.cuda_stream)

        # Whether to plot the intermediate results.
        self.plot_figures = plot_figures

    def run(
        self,
        rx_slot,
        slot,
        pusch_configs,
        cell_num
    ):
        """Run the receiver."""
        # Channel estimation.
        ch_est = self.channel_estimator.estimate(
            rx_slot=rx_slot,
            slot=slot,
            pusch_configs=pusch_configs
        )

        # Noise and interference estimation.
        lw_inv, noise_var_pre_eq = self.noise_intf_estimator.estimate(
            rx_slot=rx_slot,
            channel_est=ch_est,
            slot=slot,
            pusch_configs=pusch_configs
        )

        # Channel equalization and soft demapping. The first return value are the LLRs,
        # second are the equalized symbols. We only want the LLRs now.
        llrs, sym = self.channel_equalizer.equalize(
            rx_slot=rx_slot,
            channel_est=ch_est,
            lw_inv=lw_inv,
            noise_var_pre_eq=noise_var_pre_eq,
            pusch_configs=pusch_configs
        )

        if self.plot_figures:
            fig, axs = plt.subplots(1,4)
            for ant in range(4):
                axs[ant].imshow(10*np.log10(np.abs(rx_slot[:, :, ant]**2)), aspect='auto')
                axs[ant].set_ylim([(pusch_record.rbStart + pusch_record.rbSize) * 12,pusch_record.rbStart * 12])
                axs[ant].set_title('Ant ' + str(ant))
                axs[ant].set(xlabel='Symbol', ylabel='Resource Element')
                axs[ant].label_outer()
            fig.suptitle('Power in PUSCH REs cell {} for RNTI {}'.format(cell_num,pusch_record.rnti))

            fig, axs = plt.subplots(1,2)
            axs[0].scatter(rx_slot.reshape(-1).real, rx_slot.reshape(-1).imag)
            axs[0].set_title("Pre-Equalized samples")
            axs[0].set_aspect('equal')

            axs[1].scatter(np.array(sym).reshape(-1).real, np.array(sym).reshape(-1).imag)
            axs[1].set_title("Post-Equalized samples")
            axs[1].set_aspect('equal')

            fig, axs = plt.subplots(1)
            axs.set_title("Channel estimates from the PUSCH pipeline")
            for ant in range(4):
                axs.plot(np.abs(ch_est[0][ant, 0, :, 0]))
            axs.legend(["Rx antenna 0, estimate",
                        "Rx antenna 1, estimate",
                        "Rx antenna 2, estimate",
                        "Rx antenna 3, estimate"])
            axs.grid(True)
            plt.show()

        coded_blocks = self.derate_match.derate_match(
            input_llrs=llrs,
            pusch_configs=pusch_configs
        )

        code_blocks = self.decoder.decode(
            input_llrs=coded_blocks,
            pusch_configs=pusch_configs
        )

        decoded_tbs, _ = self.crc_checker.check_crc(
            input_bits=code_blocks,
            pusch_configs=pusch_configs
        )

        return decoded_tbs

pusch_rx_separate = PuschRxSeparate(
    num_rx_ant=num_rx_ant,
    enable_pusch_tdi=enable_pusch_tdi,
    eq_coeff_algo=eq_coeff_algo,
    plot_figures=plot_figures
)

Querying the database#

Below shows how to connect to the clickhouse database and querying the data from it.

[3]:
# Connect to the local database
import clickhouse_connect

client = clickhouse_connect.get_client(host='localhost')

# Pick a packet from the database,
pusch_records = client.query_df('select * from fapi order by TsTaiNs,rbStart')
#print(pusch_records[['TsTaiNs','SFN','Slot','nUEs','rnti','rbStart','rbSize','StartSymbolIndex','NrOfSymbols','CQI']])

Extract the PUSCH parameters and run the pipelines#

In this section we use the timestamp of the start of a slot to query the IQ sample database for both cells and demonstrate that the transmission can be decoded in the IQ samples of both cells.

[4]:
runReceiver = True
#Only show the full slot pattern the first time through:
shownTsTaiNs = -1
pusch_records = client.query_df('select * from fapi order by TsTaiNs,rbStart limit 8')
print(pusch_records[['TsTaiNs','SFN','Slot','CellId','nUEs','rnti','rbStart','rbSize','StartSymbolIndex','NrOfSymbols','nrOfLayers','TBSize','CQI']])

for index, pusch_record in pusch_records.iterrows():
    query = f"""select TsTaiNs,CellId,fhData from fh where TsTaiNs == toDateTime64(\'{pusch_record.TsTaiNs.timestamp()}\',9)"""
    fh = client.query_df(query)

    #Skip RNTI 20000 as we know it won't decode
    if pusch_record.rnti == 20000:
        continue

    # Extract all the needed parameters from the PUSCH record and create the PuschConfig.
    pusch_ue_config = PuschUeConfig(
        scid=int(pusch_record.SCID),
        layers=pusch_record.nrOfLayers,
        dmrs_ports=pusch_record.dmrsPorts,
        rnti=pusch_record.rnti,
        data_scid=pusch_record.dataScramblingId,
        mcs_table=pusch_record.mcsTable,
        mcs_index=pusch_record.mcsIndex,
        code_rate=pusch_record.targetCodeRate,
        mod_order=pusch_record.qamModOrder,
        tb_size=pusch_record.TBSize
    )

    slot = int(pusch_record.Slot)
    tb_input = np.array(pusch_record.pduData)

    # Note that this is a list. One UE group only in this case.
    pusch_configs = [PuschConfig(
        ue_configs=[pusch_ue_config],
        num_dmrs_cdm_grps_no_data=pusch_record.numDmrsCdmGrpsNoData,
        dmrs_scrm_id=pusch_record.ulDmrsScramblingId,
        start_prb=pusch_record.rbStart,
        num_prbs=pusch_record.rbSize,
        dmrs_syms=dmrs_fapi_to_bit_array(int(pusch_record.ulDmrsSymbPos)),
        dmrs_max_len=1,
        dmrs_add_ln_pos=2,
        start_sym=pusch_record.StartSymbolIndex,
        num_symbols=pusch_record.NrOfSymbols
    )]
    numCells = fh.index.size
    if shownTsTaiNs != pusch_record.TsTaiNs.timestamp():
        shownTsTaiNs = pusch_record.TsTaiNs.timestamp()
        display(Markdown("### SFN.Slot {}.{}, RNTI {} at time {}"
                     .format(pusch_record.SFN, pusch_record.Slot, pusch_record.rnti,pusch_record.TsTaiNs
        )))
        fig=plt.figure(constrained_layout=True)
        if numCells > 1:
            outer = fig.subfigures(1,numCells)
            for cellNum, cellPlot in enumerate(outer.flat):
                fh_samp = (np.array(fh['fhData'].iloc[cellNum], dtype=np.int16).view(np.float16)).astype(np.float32)
                rx_slot = np.swapaxes(fh_samp.view(np.complex64).reshape(4, 14, 273 * 12), 2, 0)

                axs = cellPlot.subplots(1,4)
                for ant, ax in enumerate(axs.flat):
                    ax.imshow(10*np.log10(np.abs(rx_slot[:, :, ant]**2)), aspect='auto')
                    ax.set_title('Ant ' + str(ant))
                    ax.set(xlabel='Symbol', ylabel='Resource Element')
                    ax.label_outer()
                    cellPlot.suptitle('Power in RU Antennas Cell '+str(fh['CellId'].iloc[cellNum]))
            plt.show()
        else:
            cellNum = 0
            fig, axs = plt.subplots(1,4)
            fh_samp = (np.array(fh['fhData'].iloc[cellNum], dtype=np.int16).view(np.float16)).astype(np.float32)
            rx_slot = np.swapaxes(fh_samp.view(np.complex64).reshape(4, 14, 273 * 12), 2, 0)
            for ant in range(4):
                axs[ant].imshow(10*np.log10(np.abs(rx_slot[:, :, ant]**2)), aspect='auto')
                axs[ant].set_ylim([pusch_record.rbStart * 12, (pusch_record.rbStart+pusch_record.rbSize) * 12])
                axs[ant].set_title('Ant ' + str(ant))
                axs[ant].set(xlabel='Symbol', ylabel='Resource Element')
                axs[ant].label_outer()
            fig.suptitle('Power in RU Antennas')

            fig, axs = plt.subplots(1,2)
            axs[0].scatter(rx_slot.reshape(-1).real, rx_slot.reshape(-1).imag)
            axs[0].set_title("Pre-Equalized samples")
            axs[0].set_aspect('equal')

            axs[1].scatter(np.array(sym).reshape(-1).real, np.array(sym).reshape(-1).imag)
            axs[1].set_title("Post-Equalized samples")
            axs[1].set_aspect('equal')

            fig, axs = plt.subplots(1)
            axs.set_title("Channel estimates from the PUSCH pipeline")
            for ant in range(4):
                axs.plot(np.abs(ch_est[0][ant, 0, :, 0]))
            axs.legend(["Rx antenna 0, estimate",
                        "Rx antenna 1, estimate",
                        "Rx antenna 2, estimate",
                        "Rx antenna 3, estimate"])
            axs.grid(True)
            plt.show()

    if runReceiver:
        for cellNum in range(0,numCells):
            cellId = fh['CellId'].iloc[cellNum]
            #fh_samp = np.array(fh['fhData'].iloc[cellNum], dtype=np.float32)
            fh_samp = (np.array(fh['fhData'].iloc[cellNum], dtype=np.int16).view(np.float16)).astype(np.float32)
            rx_slot = np.swapaxes(fh_samp.view(np.complex64).reshape(4, 14, 273 * 12), 2, 0)
            tbs = pusch_rx_separate.run(
                rx_slot=rx_slot,
                slot=slot,
                pusch_configs=pusch_configs,
                cell_num=cellId
            )
            if np.array_equal(tbs[0][:tb_input.size], tb_input):
                display(Markdown("**PUSCH decoding success** for SFN.Slot {}.{} RNTI {} from cell {} "
                         .format(pusch_record.SFN, pusch_record.Slot, pusch_record.rnti, cellId)))
            else:
                display(Markdown("**PUSCH decoding failure**"))
                print("Output bytes:")
                print(tbs[0][:tb_input.size])
                print("Expected output:")
                print(tb_input)

        # Run the receiver using the second cell data
        cell_num = fh['CellId'].iloc[1]
        fh_samp = (np.array(fh['fhData'].iloc[1], dtype=np.int16).view(np.float16)).astype(np.float32)

        rx_slot = np.swapaxes(fh_samp.view(np.complex64).reshape(4, 14, 273 * 12), 2, 0)
        tbs = pusch_rx_separate.run(
            rx_slot=rx_slot,
            slot=slot,
            pusch_configs=pusch_configs,
            cell_num=cell_num
        )
        if np.array_equal(tbs[0][:tb_input.size], tb_input):
            display(Markdown("**PUSCH decoding success** for SFN.Slot {}.{} RNTI {} from cell {} "
                         .format(pusch_record.SFN, pusch_record.Slot, pusch_record.rnti, cell_num)))
        else:
            display(Markdown("**PUSCH decoding failure**"))
            print("Output bytes:")
            print(tbs[0][:tb_input.size])
            print("Expected output:")
            print(tb_input)
                  TsTaiNs  SFN  Slot  CellId  nUEs   rnti  rbStart  rbSize  StartSymbolIndex  NrOfSymbols  nrOfLayers  TBSize        CQI
0 2024-07-19 10:42:46.272  391     4      41     7  20000        0       8                 0           10           1      63  -7.352562
1 2024-07-19 10:42:46.272  391     4      51     7  62290        0       5                 0           13           1     185  31.755341
2 2024-07-19 10:42:46.272  391     4      51     7  53137        5       5                 0           13           1     185  30.275444
3 2024-07-19 10:42:46.272  391     4      51     7   1624       10       5                 0           13           1     185  31.334328
4 2024-07-19 10:42:46.272  391     4      51     7  47905       15       5                 0           13           1     185  30.117304
5 2024-07-19 10:42:46.272  391     4      51     7  57375       20       5                 0           13           1     185  29.439499
6 2024-07-19 10:42:46.272  391     4      51     7  20216       25     248                 0           13           1   19985  25.331459
7 2024-07-19 10:42:47.292  493     4      41     6  20000        0       8                 0           10           1      63  -7.845479

SFN.Slot 391.4, RNTI 62290 at time 2024-07-19 10:42:46.272000#

../../_images/content_notebooks_datalake_pusch_multicell_8_2.png
../../_images/content_notebooks_datalake_pusch_multicell_8_3.png
../../_images/content_notebooks_datalake_pusch_multicell_8_4.png
../../_images/content_notebooks_datalake_pusch_multicell_8_5.png

PUSCH decoding success for SFN.Slot 391.4 RNTI 62290 from cell 41

../../_images/content_notebooks_datalake_pusch_multicell_8_7.png
../../_images/content_notebooks_datalake_pusch_multicell_8_8.png
../../_images/content_notebooks_datalake_pusch_multicell_8_9.png

PUSCH decoding success for SFN.Slot 391.4 RNTI 62290 from cell 51

../../_images/content_notebooks_datalake_pusch_multicell_8_11.png
../../_images/content_notebooks_datalake_pusch_multicell_8_12.png
../../_images/content_notebooks_datalake_pusch_multicell_8_13.png

PUSCH decoding success for SFN.Slot 391.4 RNTI 62290 from cell 51

../../_images/content_notebooks_datalake_pusch_multicell_8_15.png
../../_images/content_notebooks_datalake_pusch_multicell_8_16.png
../../_images/content_notebooks_datalake_pusch_multicell_8_17.png

PUSCH decoding success for SFN.Slot 391.4 RNTI 53137 from cell 41

../../_images/content_notebooks_datalake_pusch_multicell_8_19.png
../../_images/content_notebooks_datalake_pusch_multicell_8_20.png
../../_images/content_notebooks_datalake_pusch_multicell_8_21.png

PUSCH decoding success for SFN.Slot 391.4 RNTI 53137 from cell 51

../../_images/content_notebooks_datalake_pusch_multicell_8_23.png
../../_images/content_notebooks_datalake_pusch_multicell_8_24.png
../../_images/content_notebooks_datalake_pusch_multicell_8_25.png

PUSCH decoding success for SFN.Slot 391.4 RNTI 53137 from cell 51

../../_images/content_notebooks_datalake_pusch_multicell_8_27.png
../../_images/content_notebooks_datalake_pusch_multicell_8_28.png
../../_images/content_notebooks_datalake_pusch_multicell_8_29.png

PUSCH decoding failure

Output bytes:
[ 10  48 209 157   5   8 230 133  18   7 201 217  29 224 195 211  75  82 203 164  42 142 110 189 231  69  70  88 148 156 122 210 236 205 149   1 102 101  17 214  64  76 192 196 211 223  93 129  42
 233 190 143 210  13 147  97  98 229  82 113 100 198 129 100  95 179 133  51  17 125 165  57 245  57 122 193  19 201 180 182 145 112 250  78 205 147  95  32 160 193 175 111 193  83 242 204  90   0
 212  53  41 107  67  85 225 209 202  11  84 211  52 217  30 144 187  50 195  11 137 227 178 151  55 252 154 113  95  89 183 132 145  63 166 125 202 148 178 113  98 240 131 126  87  31 114  83 219
 160  51 215 185 137 117 136 150  17  57 218 125 214  24  59 132  79 104  77 219 137 213 200  97  13  55   7  65 250 239 146 219  35 250  17   4  69  36]
Expected output:
[61  0 57 63 51 63 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33
 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33
 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33]
../../_images/content_notebooks_datalake_pusch_multicell_8_32.png
../../_images/content_notebooks_datalake_pusch_multicell_8_33.png
../../_images/content_notebooks_datalake_pusch_multicell_8_34.png

PUSCH decoding success for SFN.Slot 391.4 RNTI 1624 from cell 51

../../_images/content_notebooks_datalake_pusch_multicell_8_36.png
../../_images/content_notebooks_datalake_pusch_multicell_8_37.png
../../_images/content_notebooks_datalake_pusch_multicell_8_38.png

PUSCH decoding success for SFN.Slot 391.4 RNTI 1624 from cell 51

../../_images/content_notebooks_datalake_pusch_multicell_8_40.png
../../_images/content_notebooks_datalake_pusch_multicell_8_41.png
../../_images/content_notebooks_datalake_pusch_multicell_8_42.png

PUSCH decoding failure

Output bytes:
[191 131 138 184 120 175   5 126 179  48 203  46 204 202  78 207  17  10 250 235 190  59 104  12  73 128  35 212  70 147 142 156 143  28 189 255 224  80   7 239  67 103 113 195  28  97 168 251  18
 207 117 170 102  35  17 226 165 243 249 216 239  31  57   8  28 244 146 107   2  89 180 202 164  70 140 134  94  10 138 214 228 137  36 179 154 136  94 187 165 204  70 127  33  96 176 125 119 246
  24  81  21 227 134 227 188   8 151  72   1 250  48  60 176 216 113 141  11  87 168 246 182 217   8 182  99  26 161 187 161  23 160   8  86 167  64  86  54 217 151 141 208 133  91  79 156   7  96
 252 211 183 115 214 194 111  75  79  70 114 139  39 203  54  24  91 232   7 106 253  47 105  54 123 122   9  27 104 151  76 176 133  55  95  18 177 105]
Expected output:
[61  0 57 63 51 63 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33
 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33
 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33]
../../_images/content_notebooks_datalake_pusch_multicell_8_45.png
../../_images/content_notebooks_datalake_pusch_multicell_8_46.png
../../_images/content_notebooks_datalake_pusch_multicell_8_47.png

PUSCH decoding success for SFN.Slot 391.4 RNTI 47905 from cell 51

../../_images/content_notebooks_datalake_pusch_multicell_8_49.png
../../_images/content_notebooks_datalake_pusch_multicell_8_50.png
../../_images/content_notebooks_datalake_pusch_multicell_8_51.png

PUSCH decoding success for SFN.Slot 391.4 RNTI 47905 from cell 51

../../_images/content_notebooks_datalake_pusch_multicell_8_53.png
../../_images/content_notebooks_datalake_pusch_multicell_8_54.png
../../_images/content_notebooks_datalake_pusch_multicell_8_55.png

PUSCH decoding failure

Output bytes:
[229 153 165  35  61 137 241  89  85   2  26 167 119 112 238 106 195 165  32  49 195 131  94 248 170  70 176 178 213 122 191 133 189  72  62  12  62  11  54  80  81 114 219   8  27 199 181 168 139
  25 220  25  76 151 114  88 140 103 152 101  78   6 146   8 148 167  82 177  13 137 203 186 129  73 219 218 215  51  97 194  97 174  50 174 190  94  61  30   2 136 108 127 225 180  84 201 100 196
  27 241   9  55  58  27 112 113 232 151  34 242 250 250 135 102 143 243 105  60 198  38  70  79  40 151 168 108 165 106 194 102 189 123 231 127  10  76  80 250  44 190 162  77  12 110  70 179 101
 105 208  22  69 171 184 187 195 190 169 227  92 218  36 253  29  89 246 121  36  32 191  58 235  74  82  66 153 105  84 127  59 227 172  46 197   9 116]
Expected output:
[ 4  3  0  0 80 61  0 57 63 51 63 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33
 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33
 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33]
../../_images/content_notebooks_datalake_pusch_multicell_8_58.png
../../_images/content_notebooks_datalake_pusch_multicell_8_59.png
../../_images/content_notebooks_datalake_pusch_multicell_8_60.png

PUSCH decoding success for SFN.Slot 391.4 RNTI 57375 from cell 51

../../_images/content_notebooks_datalake_pusch_multicell_8_62.png
../../_images/content_notebooks_datalake_pusch_multicell_8_63.png
../../_images/content_notebooks_datalake_pusch_multicell_8_64.png

PUSCH decoding success for SFN.Slot 391.4 RNTI 57375 from cell 51

../../_images/content_notebooks_datalake_pusch_multicell_8_66.png
../../_images/content_notebooks_datalake_pusch_multicell_8_67.png
../../_images/content_notebooks_datalake_pusch_multicell_8_68.png

PUSCH decoding failure

Output bytes:
[132  39 255 193 116 103 251 170  83 195 178  86  92  32 202 220  21 123  13 225 204 129 100 223  92 167 215  25 184  20 118  92  62  88  99  18 204 218 199 180  10 128  62  53  87  85 125 144 155
 161 193 213 192 181 140 135 163 168 247  53  91 209  99 199 194 119  21 153 220  32 232  11 190  91 253  94  65  99 190 192  34  80  44  35 149   5  53  50 104 221 210  21 162 108  96 226  46  87
 166 142 ...  65 143 205 214   1 154 247  25 253 233  43  62 132 213  83  14  79 187 110 205 230  73 100 128 175   9 135  78 192 143 155 124 230 205  99 142 180  61  20 116  55 148 237  89  49 191
 229 142 125 136 194 179 126 125 212 176 237 155 248  16 253 252  23 178 255 194 177 132 114  46 193 255 136 121 138 210 216  79  81  62  25  43 164  14 202 113  43  36 145 153 160 233  44  15  24
 242 118  81   5 225]
Expected output:
[ 68   1 133 160  13 151   4  71  52  53  54  55  56  57  48  49  50  51  52  53  54  55  56  57  48  49  50  51  52  53  54  55  56  57  48  49  50  51  52  53  54  55  56  57  48  49  50  51  52
  53  54  55  56  57  48  49  50  51  52  53  54  55  56  57  48  49  50  51  52  53  54  55  56  57  48  49  50  51  52  53  54  55  56  57  48  49  50  51  52  53  54  55  56  57  48  49  50  51
  52  53 ...  49  50  51  52  53  54  55  56  57  48  49  50  51  52  53  54  55  56  57  48  49  50  51  52  53  54  55  56  57  48  49  50  51  52  53  54  55  56  57  48  49  50  51  52  53  54
  55  56  57  48  49  50  51  52  53  54  55  56  57  48  49  50  51  52  53  54  55  56  57  48  49  50  51  52  53  54  55  56  57  48  49  50  51  52  53  54  55  56  57  48  49  50  51  52  53
  54  55  56  57  48]
../../_images/content_notebooks_datalake_pusch_multicell_8_71.png
../../_images/content_notebooks_datalake_pusch_multicell_8_72.png
../../_images/content_notebooks_datalake_pusch_multicell_8_73.png

PUSCH decoding success for SFN.Slot 391.4 RNTI 20216 from cell 51

../../_images/content_notebooks_datalake_pusch_multicell_8_75.png
../../_images/content_notebooks_datalake_pusch_multicell_8_76.png
../../_images/content_notebooks_datalake_pusch_multicell_8_77.png

PUSCH decoding success for SFN.Slot 391.4 RNTI 20216 from cell 51