Using HARQ

This notebook shows how to use HARQ functionality in NeoRadium.

[1]:
import numpy as np
import time

from neoradium import LdpcEncoder, HarqEntity, random, Modem
from neoradium.utils import toLinear

Creating an LDPC Encoder object

[2]:
modulation="16QAM"      # Modulation scheme
codeRate = 490/1024     # Target code rate
numLayers = 1           # To test this with 2 codewords, set this to a value between 5 and 8
ldpcEncoder = LdpcEncoder(baseGraphNo=1,  modulation=modulation, txLayers=numLayers, targetRate=codeRate)
ldpcEncoder.print()     # Print the LDPC encoder's properties

LDPC Encoder Properties:
  Base Graph:         1
  Modulation:         16QAM
  Number of layers:   1
  Target Rate:        0.478515625

Instantiating a HARQ entity object

[3]:
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

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

Main transmission loop

[6]:
ebNoDb = 3                                                  # Set the Eb/No ratio (dB)
snrDb = ebNoDb + 10*np.log10(ldpcEncoder.qm * codeRate)     # Convert Eb/No to SNR (dB)
snr = toLinear(snrDb)                                       # Linear SNR
noiseStd = np.sqrt(1/snr)                                   # Noise standard deviation

rangen = random.getGenerator(123)                           # Create new random generator and make results reproducible
modem = Modem(modulation)                                   # The Modem instance used for modulation/demodulation
numTransmissions = 1000                                     # Total number of transmissions
txBlockSizes = harq.numCW*[10000]                           # Transport block sizes. One per codeword.

# Print the header lines:
print("Tx Bits     Rx Bits     Throughput(%)  TX Blocks  RX Blocks  BLER(%)  Retry Mean  time(Sec.)")
print("----------  ----------  -------------  ---------  ---------  -------  ----------  ----------")

t0 = time.time()                                            # Start our timer
harq.reset()                                                # Reset HARQ for each execution of this cell
for t in range(numTransmissions):                           # Run this "numTransmissions" times
    txBlocks = []                                           # Transport blocks. One per codeword.
    for c in range(harq.numCW):
        if harq.needNewData[c]:                             # New transmission.
            txBlocks += [ random.bits(txBlockSizes[c]) ]    # Create random bits for the new transport block
        else:                                               # Retransmission
            txBlocks += [ None ]                            # Set transport block to None to indicate retransmission

    rateMatchedCodeWords = harq.getRateMatchedCodeBlocks(txBlocks)  # Prepare the bitstream for transmission

    llrs = []                                               # Received Log-Likelihood Ratios. One per codeword.
    for c in range(harq.numCW):
        channelOutput = modem.modulate(rateMatchedCodeWords[c])                     # Modulate the codeblocks
        noisyRxSignal = channelOutput + rangen.awgn(channelOutput.shape, noiseStd)  # Add Noise
        llrs += [ modem.getLLRsFromSymbols(noisyRxSignal, noiseStd**2) ]            # Calculate the LLRs for each codeword

    decodedTxBlocks, blockErrors = harq.decodeLLRs(llrs, txBlockSizes)              # Decode the LLRs into transport blocks

    # 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='')
    harq.goNext()                                           # Get ready for the next transmission

harq.printStats()                                           # Print HARQ entity's statistics
Tx Bits     Rx Bits     Throughput(%)  TX Blocks  RX Blocks  BLER(%)  Retry Mean  time(Sec.)
----------  ----------  -------------  ---------  ---------  -------  ----------  ----------
10000000    4960000     49.60          1000       496        50.40    1.00        64.76
HARQ Entity Statistics:
  txBits (per try):     [5040000 4960000       0       0]
  rxBits (per try):     [      0 4960000       0       0]
  txBlocks (per try):   [504 496   0   0]
  rxBlocks (per try):   [  0 496   0   0]
  numTimeouts:          0
  totalTxBlocks:        1000
  totalRxBlocks:        496
  totalTxBits:          10000000
  totalRxBits:          4960000
  throughput:           49.60%
  bler:                 50.40%
  Average Num. Retries: 1.00%

[ ]: