Using HARQ

This notebook demonstrates how to use HARQ functionality in NeoRadium.

[1]:
import numpy as np
import time

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

Creating an LdpcCodec 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
txBlockSizes = [10000,10000]    # Transport block size (TBS) (one per codeword)
ldpc = LdpcCodec(modulation, coderate, txBlockSizes, numLayers)
ldpc.print()                    # Print the LDPC encoder's properties

LDPC Encode/Decode Properties:
  Num layers:         1
  Num codewords:      1
  numIter:            5
  nRef:               0
  Modulation:         16QAM
  Coderate:           490/1024
  TBS:                10000
  numLayers:          1
  Base Graph:         1
  Code Block Size:    5280
  Num Code Blocks:    2
  Lifting Size:       240

Instantiating a HARQ entity object

[3]:
harqType = "IR"                             # "IR" -> "Incremental Redundancy", "CC" -> "Chase Combining"
numProc = 16                                # Number of HARQ processes
harq = HarqEntity(ldpc, 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
  LDPC codec:
    Num layers:         1
    Num codewords:      1
    numIter:            5
    nRef:               0
    Modulation:         16QAM
    Coderate:           490/1024
    TBS:                10000
    numLayers:          1
    Base Graph:         1
    Code Block Size:    5280
    Num Code Blocks:    2
    Lifting Size:       240

Main transmission loop

[4]:
rangen = random.getGenerator(123)                       # Create new random generator and make results reproducible
modem = Modem(modulation)                               # The Modem instance used for modulation/demodulation

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

numTransmissions = 1000                                 # Total number of transmissions

# Print the header lines:
print("Tx Bits     Rx Bits     Throughput(%)  TX Blocks  RX Blocks  BLER(%)  Avg. Retransmissions  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

    rateMatchedCodeBlocks = harq.encode(txBlocks)        # Prepare the bitstream for transmission

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

    decodedTxBlocks, crcMatches = harq.decode(llrs)     # Decode the LLRs into transport blocks

    # Print the statistics so far:
    print("\r%-10d  %-10d  %-13.2f  %-9d  %-9d  %-7.2f  %-20.2f  %-10.2f"
          %(harq.totalTxBits, harq.totalRxBits, harq.throughput, harq.totalTxBlocks,
            harq.totalRxBlocks, harq.bler, harq.meanRetransmissions, 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(%)  Avg. Retransmissions  time(Sec.)
----------  ----------  -------------  ---------  ---------  -------  --------------------  ----------
10000000    4960000     49.60          1000       496        50.40    1.00                  105.29
HARQ Entity Statistics:
  numTxBits (per try):      [5040000 4960000       0       0]
  numRxBits (per try):      [      0 4960000       0       0]
  numTxBlocks (per try):    [504 496   0   0]
  numRxBlocks (per try):    [  0 496   0   0]
  numTimeouts:              0
  totalTxBlocks:            1000
  totalRxBlocks:            496
  totalTxBits:              10000000
  totalRxBits:              4960000
  throughput:               49.60%
  bler:                     50.40%
  bler1st:                  100.00%
  Avg. retransmissions:     1.00
  Avg. failed transmissions:1.00

[ ]: