Modeling Transport Channel
This notebook shows how to use HARQ and PDSCH to model a 5G downlink transport channel.
[1]:
import numpy as np
import time
from neoradium import Carrier, PDSCH, LdpcEncoder, HarqEntity, random
[2]:
# First create a carrier with 52 RBs and 15KHz subcarrier spacing
carrier = Carrier(numRbs=52, spacing=15)
bwp = carrier.curBwp # The only bandwidth part (uses the entire carrier bandwidth)
snrDb = 5 # SNR (dB)
modulation="16QAM" # Modulation scheme
codeRate = 490/1024 # Target code rate
# Create the PDSCH object
pdsch = PDSCH(bwp, numLayers=1, nID=carrier.cellId, modulation=modulation)
pdsch.setDMRS(prgSize=0, configType=2, additionalPos=2) # Specify the DMRS configuration
# Create the LDPC encoder object
ldpcEncoder = LdpcEncoder(baseGraphNo=1, modulation=modulation, txLayers=pdsch.numLayers, targetRate=codeRate)
# HARQ configuration:
harqType = "IR" # "IR" -> "Incremental Redundancy", "CC" -> "Chase Combining"
numProc = 16 # Number of HARQ processes
harq = HarqEntity(ldpcEncoder, harqType, numProc) # Create the HARQ entity
harq.print() # Print the HARQ entity's properties
rangen = random.getGenerator(123) # Create a new random generator to make results reproducible
numTransmissions = 100 # Number of transmissions to simulate
t0 = time.time() # Start the timer
# Print the header lines:
print("Tx Bits Rx Bits Throughput(%) TX Blocks RX Blocks BLER(%) Retry Mean time(Sec.)")
print("---------- ---------- ------------- --------- --------- ------- ---------- ----------")
for t in range(numTransmissions):
grid = pdsch.getGrid() # Create a resource grid already populated with DMRS
txBlockSizes = pdsch.getTxBlockSize(codeRate) # Transport Block Size
numBits = pdsch.getBitSizes(grid) # Actual number of bits available in the resource grid
if harq.needNewData[0]: # New transmission =>
txBlock = rangen.bits(txBlockSizes[0]) # Create random bits for the new transport block
else: # Retransmission =>
txBlock = None # Set transport block to None to indicate retransmission
# Let HARQ do the magic: This returns a bitstream, ready for transmission/retransmission
rateMatchedCodeBlocks = harq.getRateMatchedCodeBlocks([txBlock], numBits)
pdsch.populateGrid(grid, rateMatchedCodeBlocks) # Map/modulate the data to the resource grid
pdschIndexes = pdsch.getReIndexes(grid, "PDSCH") # Indexes of the PDSCH data in the grid
rxGrid = grid.addNoise(snrDb=snrDb, useRxPower=True) # Add AWGN
llrs = pdsch.getLLRsFromGrid(rxGrid, pdschIndexes) # Demodulate the rxGrid to get LLRs
# HARQ handles retransmissions and returns the decoded transport block(s)
decodedTxBlocks, blockErrors = harq.decodeLLRs(llrs, txBlockSizes)
# Print the statistics so far:
print("\r%-10d %-10d %-13.2f %-9d %-9d %-7.2f %-10.2f %-10.2f"
%(harq.totalTxBits, harq.totalRxBits, harq.throughput, harq.totalTxBlocks,
harq.totalRxBlocks, harq.bler, harq.meanTries, time.time()-t0), end='')
# Prepare for the next transmission
carrier.goNext()
harq.goNext()
# Print all statistics collected by the HARQ entity:
print("")
harq.printStats()
HARQ Entity Properties:
HARQ Type: IR
Num. Processes: 16
Num. Codewords: 1
RV sequence: [0, 2, 3, 1]
maxTries: 4
Encoder:
Base Graph: 1
Modulation: 16QAM
Number of layers: 1
Target Rate: 0.478515625
Decoder:
Base Graph: 1
Modulation: 16QAM
Number of layers: 1
Tx Bits Rx Bits Throughput(%) TX Blocks RX Blocks BLER(%) Retry Mean time(Sec.)
---------- ---------- ------------- --------- --------- ------- ---------- ----------
1562400 749952 48.00 100 48 52.00 1.00 12.67
HARQ Entity Statistics:
txBits (per try): [812448 749952 0 0]
rxBits (per try): [ 0 749952 0 0]
txBlocks (per try): [52 48 0 0]
rxBlocks (per try): [ 0 48 0 0]
numTimeouts: 0
totalTxBlocks: 100
totalRxBlocks: 48
totalTxBits: 1562400
totalRxBits: 749952
throughput: 48.00%
bler: 52.00%
Average Num. Retries: 1.00%
[ ]:
[ ]: