HARQ
The module harq.py contains the API for Hybrid Automatic Repeat reQuest (HARQ), a fundamental mechanism in 5G NR
used for error correction and reliable data transfer over radio links. The class structure follows the 3GPP
HARQ hierarchy:
HarqEntity: The main HARQ management object. It implements the “HARQ Entity” as specified in 3GPP TS 38.321, Section 5.3.2.1.HarqProcess: Each HARQ entity contains one or more HARQ processes. This class implements the “HARQ Process” object as specified in 3GPP TS 38.321, Section 5.3.2.2.HarqCW: Each HARQ process can handle up to two codewords. This class implements HARQ processing for a single codeword. AHarqProcesscan have one or twoHarqCWobjects, depending on the number of codewords.
This implementation adheres to the procedures specified in 3GPP TS 38.321, TS 38.212, and TS 38.214.
A typical HARQ workflow:
Here’s a typical workflow example for using HARQ in your simulations:
Create an
LdpcCodecobject, for instance:ldpc = pdsch.getLdpcCodec(coderates=490/1024)
Create a HARQ entity object, passing in the
LdpcCodecobject:harq = HarqEntity(ldpc, harqType="IR", numProc=16) # Using "Incremental Redundancy" with 16 HARQ processes
For each transmission and each codeword, check the
needNewDataproperty. If it is True for a codeword, create the transport block bits for the corresponding codeword. Otherwise, set the transport block to None (for retransmission). Once the transport blocks are ready for each codeword, call theHarqEntity.encode()function to prepare the rate-matched bitstreams for transmission. Here is an example:txBlocks = [] # Transport blocks, one per codeword. for c in range(numCodewords): 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 indicating retransmission rateMatchedCodeBlocks = harq.encode(txBlocks) # Prepare the bitstream for transmission
At the receiving end, after demodulating the LLRs, the
HarqEntity.decode()method is invoked to obtain the decoded transport block or blocks and their CRC results. For instance:decodedTxBlocks, crcMatches = harq.decode(llrs) # Decode received LLRs
Near the end of the transmission loop, the HARQ entity’s
goNext()method is called to transition to the next HARQ process for the subsequent transmission.harq.goNext()
Please refer to the notebook Using HARQ for a complete example of the above workflow.
- class neoradium.harq.HarqCW(process, cwIdx)
This class implements HARQ processing for a single codeword. The
neoradium.harq.HarqProcessclass can have either one or twoHarqCWobjects.- Parameters:
process (
HarqProcess) – TheHarqProcessobject that holds thisHarqCWinstance.cwIdx (int) – The codeword index, which is 0 for the first codeword, or 1 for the second codeword.
Other Read-Only Properties:
- curTry:
This indicates the current number of retransmissions. It starts at zero for the first transmission for this codeword. This value increments after each transmission failure.
- rv:
This represents the redundancy version used for retransmissions. For “Chase Combining” retransmission, this value is always zero. For “Incremental Redundancy” retransmission, it is updated based on the
rvSequenceparameter of theHarqEntityobject.- needNewData:
This indicates whether the
HarqCWobject is ready to receive a new transport block for transmission. If it is True, it means it is ready to transmit the new block. If it is False, it means it is still busy retransmitting the previous block. This mirrors the role of New Data Indicator (NDI) in 3GPP TS 38.212
- class neoradium.harq.HarqProcess(entity, id, numCW)
This class encapsulates the functionality of a HARQ process as outlined in 3GPP TS 38.321, Section 5.3.2.2. A HARQ entity manages multiple parallel HARQ processes, each identified by a unique HARQ process identifier. The UE capabilities determine the maximum number of HARQ processes per cell, which can be 16 or 32. A single HARQ process can support one or two Transport Blocks, depending on the number of codewords. In this implementation, each codeword is processed by a dedicated
HarqCWobject.- Parameters:
entity (
HarqEntity) – TheHarqEntityobject that holds thisHarqProcessinstance.id (int) – The unique identifier associated with this HARQ process.
numCW (int) – The number of codewords processed by this HARQ process. It can be 1 or 2.
Other Read-Only Properties:
- needNewData:
A list of one or two boolean values, corresponding to each codeword. For each element in the list, a True value indicates that the HARQ process is ready to receive a new transport block for transmission, while a False value signifies that it is currently busy retransmitting the previous transport block. This aligns with the New Data Indicator (NDI) defined in 3GPP TS 38.212.
- reset()
Resets this HARQ process to prepare it for new transmissions. It resets the counters and releases any encoder/decoder retransmission buffers by calling the reset method of the
HarqCWobjects.
- print(indent=0, title=None, getStr=False)
Prints the properties of this
HarqProcessobject and itsHarqCWobjects.- Parameters:
indent (int) – The number of indentation characters.
title (str) – If specified, it is used as the title for the printed information.
getStr (bool) – If True, returns a string instead of printing it.
- Returns:
If the
getStrparameter is True, then this function returns the information in a string. Otherwise, nothing is returned.- Return type:
None or str
- encode(txBlocks, g, concatCBs)
This function takes a list of one or two transport blocks (
txBlocks) based on the number of codewords and returns a list of LDPC-encoded and rate-matched bitstreams for each codeword. If a transport block in thetxBlockslist is set to None, it uses the buffered encoded bitstream and only applies rate matching for retransmitting the previously encoded transport block. Otherwise, it assumes new transmission and encodes the transport block, saving the encoded bits for future retransmissions. For more information about the LDPC encoding process, refer to theencode()method of theLdpcCodecclass.- Parameters:
txBlocks (list) – A list of one or two NumPy arrays for each codeword. The presence of a ‘None’ value for each transport block in the list indicates a retransmission of previously buffered encoded transport block.
g (list or None) – A list of one or two integer values for each codeword. Each element in the list represents the total number of bits available for transmitting the transport block. This value corresponds to the value \(G\) in the bit selection process explained in 3GPP TS 38.212, Section 5.4.2.1. If not provided (default), it is calculated using the formula \(G=\lceil \frac {B-24} R \rceil\), where \(B\) is the transport block size and \(R\) is the code rate.
concatCBs (bool) – If True (Default), the rate-matched code blocks are concatenated, and a single array of bits is returned for each codeword. Otherwise, for each codeword, a list of NumPy arrays is returned, where each element in the list represents the bit array corresponding to each code block.
- Returns:
If
concatCBsis True, a one-dimensional NumPy array is returned, containing the concatenation of all rate-matched coded blocks. Otherwise, a list of NumPy arrays is returned, where each element in the list corresponds to the bit array of a coded block.- Return type:
NumPy array or list of NumPy arrays
- getRateMatchedCodeBlocks(txBlocks, gs=None, concatCBs=True)
DEPRECATED: This method is deprecated and will be removed in future releases. Please use the
encode()method instead.
- decode(llrs)
This function takes a list of one or two NumPy arrays, each containing Log-Likelihood Ratios (LLRs) for the demodulated received signals for each codeword. It then returns the decoded transport block for a single codeword, or the decoded transport blocks for two codewords.
For each codeword, the function uses the
LdpcCodecCWmethods to recover the rate, decode the code blocks, check the code block CRCs, and merge all code blocks to reassemble the transport block. In case of retransmissions, the function combines the LLR values of the retransmission with those from previous transmissions before decoding the code blocks.- Parameters:
llrs (list) – A list of one or two NumPy arrays, each containing the Log-Likelihood Ratios (LLRs) from the demodulated received signals corresponding to each codeword.
- Returns:
A tuple containing:
- decodedTxBlocksNumPy array or list
The decoded transport block(s) (without CRC bits).
For a single codeword: a 1D NumPy array of length \(A\).
For two codewords: a list of two NumPy arrays.
- crcMatchesNumPy array or list
CRC check results for each codeword.
Each element is a boolean array of length
C + 1:The first element corresponds to the transport-block CRC (CRC24A),
The remaining elements correspond to code-block CRCs (CRC24B) when segmentation is used.
For two codewords, a list of two such arrays is returned.
- Return type:
tuple
- class neoradium.harq.HarqEntity(ldpcCodec, harqType='CC', numProc=8, rvSequence=[0, 2, 3, 1], maxTries=4, eventCallback=None)
This class encapsulates the functionality of a HARQ entity as specified in 3GPP TS 38.321, Section 5.3.2.1. A HARQ entity is configured for each Serving Cell to manage downlink (DL) and uplink (UL) HARQ operations. The primary purpose of a HARQ entity is to maintain multiple parallel HARQ processes and direct HARQ information and associated Transport Blocks to these corresponding processes. This HARQ information includes key parameters such as the New Data Indicator (NDI), Transport Block Size (TBS), Redundancy Version (RV), and the HARQ process ID.
Note
In the absence of scheduler/DCI modeling, this implementation advances HARQ processes in round-robin order. This is a simulation simplification that provides deterministic use of parallel HARQ processes, but it does not model scheduler-controlled HARQ process selection used in NR systems.
- Parameters:
ldpcCodec (
LdpcCodec) – Theneoradium.ldpccodec.LdpcCodecobject, used by this HARQ entity for LDPC coding.harqType (str) –
The retransmission method used by this HARQ entity. It can be one of
"CC"``(default) or ``"IR":- ”CC”:
Indicates Chase Combining which is a straightforward HARQ method where each retransmission is an exact copy of the original data. The receiver simply combines the energy (or LLRs) from these identical transmissions, which increases the signal-to-noise ratio and makes it more likely that the combined signal can be decoded correctly.
- ”IR”:
Indicates Incremental Redundancy, a more efficient and advanced method. Instead of re-sending identical copies, each retransmission contains new and different parity bits, known as redundancy versions. The receiver combines these unique pieces of information with the original transmission, progressively building a stronger and more complete coded block. This approach significantly improves the chances of successful decoding with fewer retransmissions compared to Chase Combining.
numProc (int) – The number of HARQ processes utilized by this HARQ entity. It varies depending on the capabilities of the UE. A HARQ entity can manage up to 32 HARQ processes, with the default being 8.
rvSequence (list of integers) – Defines the order in which standardized redundancy-version identifiers are used across retransmissions. In NR LDPC rate matching, the valid RV identifiers are 0, 1, 2, and 3, each corresponding to a different starting position in the circular buffer defined in TS 38.212 Table 5.4.2.1-2. The default sequence
[0, 2, 3, 1]is a common simulation choice for incremental-redundancy HARQ because it cycles through the four standardized RVs and exposes different portions of the coded block across retransmissions. It should be treated as a configurable retransmission policy rather than a universally mandated sequence for every scenario.maxTries (int) – The maximum number of transmission attempts for a specified transport block, including the initial transmission and any retransmissions. If a transport block still fails after this many attempts, a timeout event occurs.
eventCallback (function or None) –
If this callback function is provided, it will be invoked on the following events:
- ”RXFAILED”:
This event is triggered when a transport block transmission fails, whether it’s the original transmission or a retransmission.
- ”RXSUCCESS”:
This event is triggered when a transport block transmission succeeds, whether it’s the original transmission or a retransmission.
- ”TIMEOUT”:
This event is triggered when a transport block transmission fails after the
maxTriestransmissions.
For more information, refer to the Event callback function section below.
Other Read-Only Properties:
- processes:
A list of
HarqProcessobjects managed by this HARQ entity.- curProcess:
The HARQ process that is currently transmitting or retransmitting the transport blocks.
- curProcIdx:
The current HARQ process that is currently transmitting or retransmitting the transport blocks.
- numCW:
The number of codewords. This is based on the LDPC encoder’s
txLayersparameter.- needNewData:
A list of one or two boolean values, corresponding to each codeword. For each element in the list, a True value indicates that the current HARQ process (
curProcess) is ready to receive a new transport block for transmission, while a False value signifies that it is currently busy retransmitting the previous transport block. This mirrors the role of the New Data Indicator (NDI) defined in 3GPP TS 38.212.- totalTxBlocks:
The total number of transport blocks transmitted, including retransmissions.
- totalRxBlocks:
The total number of transport blocks received and successfully decoded.
- totalTxBits:
The total number of transport block bits transmitted, including retransmissions.
- totalRxBits:
The total number of transport block bits received and successfully decoded.
- throughput:
The communication throughput expressed as a percentage. It’s calculated as
totalRxBits*100/totalTxBits.- bler:
The block error rate expressed as a percentage. It’s calculated as
(totalTxBlocks-totalRxBlocks)*100/totalTxBlocks.- bler1st:
The first-transmission block error rate expressed as a percentage.
- numTimeouts:
The total number of timeout events for each codeword. A timeout occurs when a transport block fails after all retransmission attempts.
- meanFailedTransmissions:
The average number of failed transmissions. This values ranges from zero (indicating no failed transmissions) up to
maxTries(indicating all timed out transmissions).- meanRetransmissions:
The average number of retransmissions per transport block. This value ranges from zero (indicating no retransmissions) up to
maxTries-1.
Event Callback Function
This function is automatically invoked when a transmission event occurs. It accepts the following parameters:
- eventStr:
This string can be one of
"RXFAILED","RXSUCCESS", or"TIMEOUT", as explained above.- harqCW:
The
HarqCWobject that triggered the event. This object can be used to obtain more information about the event.
Here is an example of an event callback function that prints all triggered events:
def myEventHandler(eventStr, harqCW): print(f"HARQ Process {harqCW.process.id:2d} CW{harqCW.cwIdx+1}:{eventStr:10s} curTry:{harqCW.curTry} RV:{harqCW.rv}")
Please refer to the notebook HARQ Event Callback for a complete example of using event callback functions.
- reset()
Resets this HARQ entity to prepare it for a new set of transmissions. It resets the counters and releases any LDPC retransmission buffers by invoking
HarqProcess.reset()for all HARQ processes.
- setLdpc(ldpcCodec)
Update the LDPC codec used for new HARQ transmissions.
The new codec is applied only to HARQ processes that are idle or starting a new transport block. Processes with an active retransmission keep using the LDPC codec associated with their original transmission until that HARQ process completes. This preserves soft-combining consistency across retransmissions, even if the modulation scheme, code rate, or other LDPC-related parameters change.
- Parameters:
ldpcCodec (
LdpcCodec) – New LDPC codec to use for subsequent HARQ transmissions.
- setLA(la)
Set the link-adaptation object associated with this HARQ entity.
The link-adaptation object is notified when ACK/NACK feedback becomes available, allowing it to update its adaptation state, such as an OLLA CQI offset. This method is typically called by the link-adaptation object during initialization.
- Parameters:
la (
OLLA) – Link-adaptation object associated with this HARQ entity. The object is expected to provide anupdatemethod that accepts ACK/NACK feedback.
- print(indent=0, title=None, getStr=False)
Prints the properties of this
HarqEntityobject.- Parameters:
indent (int) – The number of indentation characters.
title (str) – If specified, it is used as the title for the printed information.
getStr (bool) – If True, returns a string instead of printing it.
- Returns:
If the
getStrparameter is True, then this function returns the information in a string. Otherwise, nothing is returned.- Return type:
None or str
- printStats(getStr=False)
Prints the statistics of this
HarqEntityobject.- Parameters:
getStr (bool) – If True, returns a string instead of printing it.
- Returns:
If the
getStrparameter is True, then this function returns the information in a string. Otherwise, nothing is returned.- Return type:
None or str
- goNext()
This function should be called after the transmission of each transport block. It updates the internal pointer
curProcIdxto point to the next HARQ process.
- encode(txBlocks, gs=None, concatCBs=True)
This function takes a list of one or two transport blocks (
txBlocks) based on the number of codewords and returns a list of LDPC-encoded and rate-matched bitstreams for each codeword. If a transport block in thetxBlockslist is set to None, it uses the buffered encoded bitstream and only applies rate matching for retransmitting the previously encoded transport block. Otherwise, it assumes new transmission and encodes the transport block and saves the encoded bits into the HARQ process for future retransmissions. This function internally calls theencode()method of theHarqProcessclass. For more details, refer to the documentation ofHarqProcess.encode().Note
This function replaces the deprecated function
getRateMatchedCodeBlocks(). The following example shows how to migrate existing code to use this method:# Old: rateMatchedCodeBlocks = harq.getRateMatchedCodeBlocks(txBlocks, numBits) # New: rateMatchedCodeBlocks = harq.encode(txBlocks, numBits)
- getRateMatchedCodeBlocks(txBlocks, gs=None, concatCBs=True)
DEPRECATED: This method is deprecated and will be removed in future releases. Please use the
encode()method instead.
- decode(llrs)
This function takes a list of one or two NumPy arrays, each containing Log-Likelihood Ratios (LLRs) for the demodulated received signals for each codeword. It then returns one or two decoded transport blocks.
For each codeword, the function performs rate recovery, decodes the code blocks using LDPC decoding, checks the code block CRCs, and merges all code blocks to reassemble the transport block. In case of retransmissions, the function combines the LLR values of the retransmissions with those from previous transmissions before decoding the code blocks.
This function internally calls the
decode()method of theHarqProcessclass. For more details, refer to the documentation ofHarqProcess.decode().Note
This function replaces the deprecated function
decodeLLRs(). The following example shows how to migrate existing code to use this method:# Old: decodedTxBlocks, blockErrors = harq.decodeLLRs(llrs, txBlockSizes, numIter=2) # New: # numIter is set at instantiation # crcMatch is returned instead of blockErrors (consistent with LdpcCodec.decode) decodedTxBlock, crcMatch = pdsch.decode(llrs)