{ "cells": [ { "cell_type": "markdown", "id": "1ea4038d-302f-4750-8468-5e35843d23f5", "metadata": {}, "source": [ "## Modeling Transport Channel\n", "This notebook shows how to use HARQ and PDSCH to model a 5G downlink transport channel." ] }, { "cell_type": "code", "execution_count": 1, "id": "e3664f61-6925-4e91-a826-5b49b9057030", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import time\n", "\n", "from neoradium import Carrier, PDSCH, LdpcEncoder, HarqEntity, random" ] }, { "cell_type": "code", "execution_count": 2, "id": "bd6bbd98-bba6-40fd-83f4-3847dfc95b68", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "HARQ Entity Properties:\n", " HARQ Type: IR\n", " Num. Processes: 16\n", " Num. Codewords: 1\n", " RV sequence: [0, 2, 3, 1]\n", " maxTries: 4\n", " Encoder:\n", " Base Graph: 1\n", " Modulation: 16QAM\n", " Number of layers: 1\n", " Target Rate: 0.478515625\n", " Decoder:\n", " Base Graph: 1\n", " Modulation: 16QAM\n", " Number of layers: 1\n", "\n", "Tx Bits Rx Bits Throughput(%) TX Blocks RX Blocks BLER(%) Retry Mean time(Sec.)\n", "---------- ---------- ------------- --------- --------- ------- ---------- ----------\n", "1562400 749952 48.00 100 48 52.00 1.00 12.67 \n", "\n", "HARQ Entity Statistics:\n", " txBits (per try): [812448 749952 0 0]\n", " rxBits (per try): [ 0 749952 0 0]\n", " txBlocks (per try): [52 48 0 0]\n", " rxBlocks (per try): [ 0 48 0 0]\n", " numTimeouts: 0\n", " totalTxBlocks: 100\n", " totalRxBlocks: 48\n", " totalTxBits: 1562400\n", " totalRxBits: 749952\n", " throughput: 48.00%\n", " bler: 52.00%\n", " Average Num. Retries: 1.00%\n", "\n" ] } ], "source": [ "# First create a carrier with 52 RBs and 15KHz subcarrier spacing\n", "carrier = Carrier(numRbs=52, spacing=15) \n", "bwp = carrier.curBwp # The only bandwidth part (uses the entire carrier bandwidth)\n", "\n", "snrDb = 5 # SNR (dB)\n", "modulation=\"16QAM\" # Modulation scheme\n", "codeRate = 490/1024 # Target code rate\n", "\n", "# Create the PDSCH object\n", "pdsch = PDSCH(bwp, numLayers=1, nID=carrier.cellId, modulation=modulation)\n", "pdsch.setDMRS(prgSize=0, configType=2, additionalPos=2) # Specify the DMRS configuration\n", "\n", "# Create the LDPC encoder object\n", "ldpcEncoder = LdpcEncoder(baseGraphNo=1, modulation=modulation, txLayers=pdsch.numLayers, targetRate=codeRate)\n", "\n", "# HARQ configuration:\n", "harqType = \"IR\" # \"IR\" -> \"Incremental Redundancy\", \"CC\" -> \"Chase Combining\"\n", "numProc = 16 # Number of HARQ processes\n", "harq = HarqEntity(ldpcEncoder, harqType, numProc) # Create the HARQ entity\n", "harq.print() # Print the HARQ entity's properties\n", "\n", "rangen = random.getGenerator(123) # Create a new random generator to make results reproducible\n", "numTransmissions = 100 # Number of transmissions to simulate\n", "\n", "t0 = time.time() # Start the timer\n", "# Print the header lines:\n", "print(\"Tx Bits Rx Bits Throughput(%) TX Blocks RX Blocks BLER(%) Retry Mean time(Sec.)\")\n", "print(\"---------- ---------- ------------- --------- --------- ------- ---------- ----------\")\n", "for t in range(numTransmissions):\n", " grid = pdsch.getGrid() # Create a resource grid already populated with DMRS \n", " txBlockSizes = pdsch.getTxBlockSize(codeRate) # Transport Block Size\n", " numBits = pdsch.getBitSizes(grid) # Actual number of bits available in the resource grid\n", "\n", " if harq.needNewData[0]: # New transmission =>\n", " txBlock = rangen.bits(txBlockSizes[0]) # Create random bits for the new transport block\n", " else: # Retransmission =>\n", " txBlock = None # Set transport block to None to indicate retransmission\n", "\n", " # Let HARQ do the magic: This returns a bitstream, ready for transmission/retransmission\n", " rateMatchedCodeBlocks = harq.getRateMatchedCodeBlocks([txBlock], numBits) \n", "\n", " pdsch.populateGrid(grid, rateMatchedCodeBlocks) # Map/modulate the data to the resource grid\n", " pdschIndexes = pdsch.getReIndexes(grid, \"PDSCH\") # Indexes of the PDSCH data in the grid\n", "\n", " \n", " rxGrid = grid.addNoise(snrDb=snrDb, useRxPower=True) # Add AWGN\n", " llrs = pdsch.getLLRsFromGrid(rxGrid, pdschIndexes) # Demodulate the rxGrid to get LLRs\n", "\n", " # HARQ handles retransmissions and returns the decoded transport block(s)\n", " decodedTxBlocks, blockErrors = harq.decodeLLRs(llrs, txBlockSizes)\n", " \n", " # Print the statistics so far:\n", " print(\"\\r%-10d %-10d %-13.2f %-9d %-9d %-7.2f %-10.2f %-10.2f\"\n", " %(harq.totalTxBits, harq.totalRxBits, harq.throughput, harq.totalTxBlocks, \n", " harq.totalRxBlocks, harq.bler, harq.meanTries, time.time()-t0), end='')\n", "\n", " # Prepare for the next transmission\n", " carrier.goNext()\n", " harq.goNext() \n", "\n", "# Print all statistics collected by the HARQ entity:\n", "print(\"\")\n", "harq.printStats()" ] }, { "cell_type": "code", "execution_count": null, "id": "979b8864-6416-44fd-b7ea-65ae02e9f42d", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "14bf867f-c6b8-42bf-8d68-124dc2192cfe", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.6" } }, "nbformat": 4, "nbformat_minor": 5 }