>
Home5G NRMAC — Medium Access ControlHARQ
🧩 MAC — Medium Access ControlIntermediate

HARQ (Downlink & Uplink) in 5G NR

Stop-and-wait HARQ processes, soft combining, NDI/RV, and how UL differs from DL.

📚 3GPP-basedTS 38.321TS 38.214

A radio link makes errors, and it makes them in bursts. The natural engineering response — encode conservatively enough that errors never happen — is enormously wasteful, because the coding has to be sized for the worst instant rather than the average one. NR instead deliberately schedules to fail: the link adaptation loop aims at roughly a 10 % block error rate on first transmission, accepts that one block in ten will not decode, and recovers those with a retransmission mechanism cheap enough that the trade is worth it.

Contents
  1. 01Why HARQ Exists, and the Division of Labour with RLC ARQ
  2. 02Stop-and-Wait, Parallelised: Processes and the Pipeline
  3. 03Asynchronous in Both Directions — and Where LTE's Model Misleads
  4. 04The New Data Indicator: One Bit That Decides Everything
  5. 05The Circular Buffer, Rate Matching and Redundancy Versions
  6. 06Base Graphs, Code Blocks and the Transport Block Size
  7. 07Soft Combining, the Soft Buffer and Limited Buffer Rate Matching
  8. 08K1 and K2: the Timing Offsets, Worked to an Absolute Slot
  9. 09HARQ-ACK Codebooks: Type-1, Type-2 and Type-3
  10. 10Code Block Group Based Transmission
  11. 11Uplink HARQ Without a PHICH
  12. 12Disabled HARQ Feedback and Very Long Round Trips
  13. 13HARQ, DRX, and the Timers That Connect Them
  14. 14Parameter Reference: ASN.1, Ranges and Effects
  15. 15Failure Modes and What Each One Means
  16. 16ASN.1 Extracts
  17. 17Illustrative Message Traces
  18. 18Release Deltas: Rel-15 to Rel-18
  19. 19Reading HARQ in Logs: A Checklist
  20. 20Glossary
  21. 21References

1. Why HARQ Exists, and the Division of Labour with RLC ARQ

A radio link makes errors, and it makes them in bursts. The natural engineering response — encode conservatively enough that errors never happen — is enormously wasteful, because the coding has to be sized for the worst instant rather than the average one. NR instead deliberately schedules to fail: the link adaptation loop aims at roughly a 10 % block error rate on first transmission, accepts that one block in ten will not decode, and recovers those with a retransmission mechanism cheap enough that the trade is worth it.

HARQ is that mechanism. The hybrid in the name is the important part. Plain ARQ discards a failed transmission and sends it again; HARQ keeps the failed attempt as soft information and combines it with the retransmission, so the second attempt starts from an accumulated signal rather than from nothing. That means a retransmission does not have to be independently decodable — it only has to close the gap — which is why HARQ recovers from a marginal failure in one extra attempt where plain ARQ might need several.

There are two retransmission layers in NR and the separation is deliberate. Each is bad at what the other is good at:

HARQ (MAC/PHY)RLC ARQ (Acknowledged Mode)
TimescaleA handful of slots — hundreds of microseconds to a few millisecondsTens of milliseconds; bounded by t-PollRetransmit and the status-report cadence
Unit of retransmissionA transport block, or a code block group within it (§10)An RLC PDU or a segment of one, identified by sequence number
FeedbackOne bit per transport block, carried on PUCCH or multiplexed on PUSCHAn RLC STATUS PDU listing missing sequence numbers — much richer, much slower
CombiningSoft combining of stored channel informationNone — a retransmitted PDU is decoded on its own
Failure modelFeedback itself can be misread (an ACK/NACK error), so HARQ is not reliable on its ownSequence numbers make loss detectable with certainty
Retry budgetNot configured anywhere in NR — entirely scheduler policy (§15)maxRetxThreshold (t1 … t32); exceeding it is an RLC failure and triggers RLF
Typical residual error left behind≈10⁻² to 10⁻³ after a few attempts≈10⁻⁴ to 10⁻⁶, which is what TCP and the 5QI budgets assume

Table 1. The two layers, and why both are needed. Residual error figures are typical design targets rather than specified values.

💡
Key Point

HARQ is fast but fundamentally unreliable, and that is the reason RLC ARQ exists at all. The feedback is a single bit with no CRC of its own: a NACK misread as an ACK loses a transport block silently, and an ACK misread as a NACK wastes a retransmission. PUCCH is therefore power-controlled to a much lower error target than PDSCH — commonly around 10⁻³ for the ACK-to-NACK direction — but it is never zero, so something above HARQ has to be able to notice a gap. That something is the RLC sequence number.

The error budget cascades. Reading it top to bottom is the clearest way to see why the link adaptation target is deliberately poor:

StageTypical error rateWhat removes itWhat is left over
PDSCH first transmission≈10⁻¹ (the link adaptation target)HARQ retransmission with incremental redundancyBlocks whose second attempt also fails
After 2–4 HARQ attempts≈10⁻² … 10⁻³RLC ARQ, from a status reportPDUs lost because a NACK was misread as an ACK, or because the process was flushed
After RLC ARQ (AM)≈10⁻⁴ … 10⁻⁶PDCP duplication, or the applicationEffectively nothing at the radio layer; what remains is a latency problem, not a loss problem

Table 2. Why aiming at 10 % BLER is correct rather than sloppy: the spectral efficiency gained by coding for the average instead of the worst case far exceeds the cost of retransmitting one block in ten. Figures are design targets, not specified requirements.

2. Stop-and-Wait, Parallelised: Processes and the Pipeline

One HARQ process is the simplest possible protocol: send a transport block, wait for the answer, then either send new data or resend. The problem is the waiting. At 30 kHz a slot is 0.5 ms, and the round trip from transmission to the earliest possible retransmission is typically five to ten slots once UE decoding time, feedback timing and the gNB's own turnaround are included. A single stop-and-wait process would leave the link idle for nine slots out of ten.

NR runs many processes in parallel, each an independent stop-and-wait instance identified by a HARQ process ID carried explicitly in the scheduling DCI. While process 3 waits, processes 4, 5, 6 and the rest carry new data. Stop-and-wait applies per process; it never applies to the link.

Sixteen Processes, One Frame: Why Stop-and-Wait Does Not Stall the LinkSixteen Processes, One Frame: Why Stop-and-Wait Does Not Stall the Link30 kHz SCS, K1 chosen per slot so every HARQ-ACK lands in the next uplink slotTDD patternDDDSUDDDSUDDDSUDDDSUDDDSUPDSCH(HARQ pid)0123456789101112131415PUCCHHARQ-ACKpid 0-3pid 4-7pid 8-11pid 12-15pid 0occupancypid 0 busyRTT ~ 6 slotspid 0 could be reused from slot 6 -- but by then fifteen others are in flight02468101214161820Slot within the 10 ms frameSixteen processes are enough to fill sixteen downlink and special slots -- one frame at 30 kHz -- before the first oneis freed. Cut the process count to four and the scheduler runs out of processes in slot 3 and has to leave slots 5, 6 and 7 empty.
Figure 1. One frame at 30 kHz on a DDDSU pattern. Sixteen processes fill every downlink and special slot in the frame before the first one becomes reusable — which is the sizing argument for the number 16, not an arbitrary choice.
One Downlink HARQ Retransmission, Start to FinishOne Downlink HARQ Retransmission, Start to FinishUEgNB16 DL HARQ processes, C-RNTI 0x4601, 30 kHz TDD DDDSU, K1 = 2 slots.Stored NDI for pid 3 is 0.PDSCH pid 3 NDI = 1 RV = 0SFN 412 slot 7 | MCS 15, 100 PRB, TBS 31 752, 4 code blocks1NDI toggled 0 -> 1: new data.Flush pid 3 soft buffer, decode.CRC FAIL -- retain 52 800 soft bits.PUCCH HARQ-ACK = NACK for pid 3SFN 412 slot 9 = n + K1; PUCCH format 1, 1 bit2PDSCH pid 5 NDI = 1 RV = 0unrelated new data in slot 10 -- the pipeline never stalls waiting for pid 33PDSCH pid 3 NDI = 1 (unchanged) RV = 2SFN 412 slot 12; same TBS, k_0 = 12 672 -> mostly parity the UE has never seen4NDI unchanged for pid 3: retransmission.Soft-combine at the RV2 offset. CRC PASS.PUCCH HARQ-ACK = ACK for pid 3SFN 412 slot 145pid 3 released; TB delivered upward, in order or notthe next transport block on the same processPDSCH pid 3 NDI = 0 (toggled) RV = 0the toggle is the only signal that this is a different TB -- UE flushes first6Nothing else in the DCI distinguishes new data from a repeat.Same pid, same TBS, same RNTI -- only the NDI changed.Note step 3. Between the NACK and the retransmission the gNB is free to schedule any other process, which is the entirereason for having sixteen of them: stop-and-wait per process, but never across the link.
Figure 2. The same pipeline seen from one process. Note that step 3 schedules a completely unrelated process between the NACK and the retransmission: that interleaving is what the process count buys.

2.1 How many processes, and why

Two things bound the count. The first is arithmetic: the HARQ process number field in DCI formats 1_0/1_1 and 0_0/0_1 is 4 bits, so Rel-15 and Rel-16 can address at most 16. The second is what the pipeline actually needs, which is roughly the round trip divided by the slot duration — and since the round trip is dominated by fixed processing time while the slot shrinks with numerology, the needed count grows with SCS. That is exactly why Rel-17, introducing 480 and 960 kHz for FR2-2 and non-terrestrial links with round trips measured in hundreds of milliseconds, had to widen the field to 5 bits and allow 32.

Channel / useASN.1RangeDefaultNotes
PDSCH, dynamicnrofHARQ-ProcessesForPDSCH in PDSCH-ServingCellConfign2, n4, n6, n10, n12, n168 (if absent)Per serving cell. The default is 8, not 16 — a common surprise when comparing two cells that look identically configured.
PDSCH, Rel-17
nrofHARQ-ProcessesForPDSCH-v1700
adds n32For FR2-2 numerologies and NTN. Requires the 5-bit DCI field.
PUSCH, dynamicfixed in Rel-15/161616Not configurable. Rel-17 adds nrofHARQ-ProcessesForPUSCH-r17 with an n32 option.
PDSCH, SPSnrofHARQ-Processes in SPS-Config1 … 8A configured downlink assignment derives its process ID from the timing, so this bounds a separate small pool (§11.2).
PUSCH, configured grantnrofHARQ-Processes in ConfiguredGrantConfig1 … 16Same idea, with harq-ProcID-Offset (Rel-16) to keep it from colliding with the dynamic pool.

Table 3. Where the process count comes from. See the companion 08 Scheduling document for SPS and configured grants themselves.

The process count is not free. Every process needs its own soft buffer, and the UE's total soft-buffer memory is a capability, not a configuration — so doubling the process count halves the soft bits available per process unless limited buffer rate matching is in play (§7). Configuring n16 on a cell that only ever needs six processes does not improve throughput; it can reduce the combining gain available to each retransmission.

3. Asynchronous in Both Directions — and Where LTE's Model Misleads

Anyone arriving from LTE carries a mental model that is half wrong here. In LTE, downlink HARQ was asynchronous (the process ID was signalled) but uplink HARQ was synchronous: retransmissions happened on a fixed 8 ms cycle and the process ID was implied by the subframe number, with no field for it anywhere. NR abandoned that. Both directions are asynchronous, and both carry the process ID explicitly in the DCI.

Downlink (PDSCH)Uplink (PUSCH)
Process IDExplicit, 4 bits in DCI 1_0/1_1/1_2Explicit, 4 bits in DCI 0_0/0_1/0_2 — this is the LTE difference
Retransmission timingAny later slot the scheduler choosesAny later slot the scheduler chooses, subject to K2 and the UE's preparation time N2
FeedbackExplicit: one HARQ-ACK bit per TB on PUCCH, or multiplexed on PUSCHNone. There is no PHICH in NR. The next grant for that process is the feedback (§11)
How the receiver tells new from repeatNDI toggleNDI toggle — identical logic, opposite direction
Soft combining held byThe UEThe gNB
Where timing is boundedK0 (DCI→PDSCH) and K1 (PDSCH→HARQ-ACK)K2 (DCI→PUSCH); no feedback offset exists to bound

Table 4. Downlink and uplink HARQ in NR. The single genuinely asymmetric row is feedback: the downlink has an explicit channel for it, the uplink does not.

There is one place where timing-derived process IDs survive, and it is worth knowing because it looks like the LTE behaviour: configured grants and semi-persistent scheduling. A transmission on a configured resource has no DCI, so there is no field to carry the process ID; the specification therefore derives it from the time the transmission occurs TS 38.321 cl. 5.4.1:

TS 38.321 cl. 5.4.1 -- the one place the process ID is implicit
Uplink configured grant, HARQ process ID:

  HARQ Process ID = floor( CURRENT_symbol / periodicity )
                    modulo nrofHARQ-Processes
                    ( + harq-ProcID-Offset2, Rel-16 )

  CURRENT_symbol =   SFN x numberOfSlotsPerFrame x numberOfSymbolsPerSlot
                   + slot number in the frame x numberOfSymbolsPerSlot
                   + symbol number in the slot

Downlink SPS uses the equivalent expression over slots and the SPS
periodicity, modulo the SPS nrofHARQ-Processes.
⚠️
Common Pitfall

This formula is a real source of confusion in traces. A configured-grant transmission that the gNB does schedule a retransmission for gets a DCI with an explicit process ID, and that ID must match the one the formula produced — if the periodicity or nrofHARQ-Processes on the two sides disagree even slightly, the gNB retransmits into a process the UE has something else in. The symptom is corrupted uplink data with no HARQ errors reported by either side, which is about as unhelpful a symptom as exists.

4. The New Data Indicator: One Bit That Decides Everything

The receiver has to answer one question before it does anything else: is this transport block new, or is it another attempt at the one I already have soft bits for? Nothing else in the DCI answers it. The process ID is the same either way. The transport block size is the same. The RNTI is the same. The redundancy version hints at it but does not decide it — a retransmission can legitimately reuse RV0. The answer is carried by a single bit, the New Data Indicator, and the semantics are a toggle, not a flag:

  • NDI differs from the value stored for that process → new data. Flush the soft buffer, store the new NDI value, decode what just arrived on its own.
  • NDI is unchanged → retransmission. Keep the stored soft bits, add the new coded bits at the offset the RV indicates, decode the combination.
  • No stored value for that process (first use, or after a flush) → treat as new data.
The HARQ-Related Fields of DCI Format 1_1The HARQ-Related Fields of DCI Format 1_1TS 38.212 cl. 7.3.1.2.2 -- the HARQ-relevant subset, not the whole DCIbit76543210Oct 1Modulation and Coding Scheme (TB 1)NDIRVOct 2HARQ process number (0..15)counter DAItotal DAIOct 3TPCPUCCHPUCCH resourceindicatorPDSCH-to-HARQ_ACKtiming (K1 index)Oct 4CBGTI -- one bit per code block groupCBGFIprioRows are groups of eight bits for legibility only: a DCI is a bit string and its fields are not octet-aligned, so the 'Oct'labels here are just row numbers. Several of these fields are configuration-dependent and can be zero bits wide -- totalDAI is absent with a single serving cell, CBGTI is absent unless codeBlockGroupTransmission is configured, priority is Rel-16.
Figure 3. The HARQ-related fields of DCI 1_1, drawn to scale against each other. The NDI is one bit out of a DCI that is commonly 50–70 bits long, and it is the field with the most consequence.
HARQ reception decision flowWhat the Receiver Decides Before It Touches the Soft BufferTS 38.321 cl. 5.3.2.2 -- the HARQ entity's reception procedurePDSCH received,scheduled by a DCIcarrying HARQprocess id iNDI toggledsince the lastPDSCH onprocess i?NEW DATAFlush the soft buffer for i,store the new NDI, decode thereceived bits on their own.RV0 is self-decodable.RETRANSMISSIONKeep the stored soft bits,write the new coded bits in attheir RV offset, decode theaccumulated combination.CRCpass?Deliver the TBupward, ACK atn + K1, releaseprocess iRetain the softbits, NACK atn + K1, processi stays occupiedyesnoyesnoA first transmission on a process the UE has no stored NDI for is treated as new data. So is any assignment for which the UEwas told to flush -- a CBGFI of 0, or a configured downlink assignment. Everything else hangs on one bit.
Figure 4. The reception procedure of TS 38.321 cl. 5.3.2.2, reduced to its decisions. The path taken determines whether the soft buffer is cleared or added to — and getting it wrong corrupts the combining for every subsequent attempt.
💡
Key Point

A toggle rather than a flag is a deliberate robustness choice. If new data were signalled by NDI = 1 and a retransmission by NDI = 0, then two consecutive new transport blocks on the same process would both carry NDI = 1 and be indistinguishable — the receiver would soft-combine the second with the first and produce garbage. Because the semantics are "different from last time", each new TB inverts the bit and every transition is visible. The cost is that the NDI is only meaningful relative to state the receiver holds, which is why a UE that has lost that state (buffer flush after timeAlignmentTimer expiry, DRX wake-up with a stale process) treats the next reception as new data rather than guessing.

5. The Circular Buffer, Rate Matching and Redundancy Versions

The LDPC encoder does not produce a transmission — it produces a pool of coded bits far larger than any single transmission needs. For base graph 1 the encoder output per code block is 66·Z_c bits, of which 22·Z_c are systematic (the information bits themselves) and 44·Z_c are parity. That pool is written into a circular buffer, and rate matching is the act of reading a contiguous run out of it, wrapping at the end, long enough to fill the resource elements the scheduler allocated.

The redundancy version is simply where in that buffer the read starts. It is not a different encoding, not a different puncturing pattern, and not a mode. Two bits in the DCI select one of four starting offsets TS 38.212 cl. 5.4.2.1, Table 5.4.2.1-2:

rv_idk_0 for base graph 1As % of N_cbk_0 for base graph 2As % of N_cb
000 %00 %
1⌊17·N_cb / (66·Z_c)⌋ · Z_c25.8 %⌊13·N_cb / (50·Z_c)⌋ · Z_c26 %
2⌊33·N_cb / (66·Z_c)⌋ · Z_c50 %⌊25·N_cb / (50·Z_c)⌋ · Z_c50 %
3⌊56·N_cb / (66·Z_c)⌋ · Z_c84.8 %⌊43·N_cb / (50·Z_c)⌋ · Z_c86 %

Table 5. Redundancy version starting positions. The percentages assume no limited buffer rate matching, so N_cb = N; with LBRM the offsets compress towards the start of the buffer (§7).

Redundancy Versions Are Starting Points in One Circular BufferRedundancy Versions Are Starting Points in One Circular BufferLDPC base graph 1, N_cb = 66 Z_c, each transmission carrying about half the buffercircularbuffersystematic bits (22 Z_c)parity bits (44 Z_c)1st txRV0 k_0 = 02nd txRV2 k_0 = 33 Z_c (50 %)3rd txRV3 k_0 = 56 Z_c (84.8 %) -- wrapsRV3 starts4th txRV1 k_0 = 17 Z_c (25.8 %)0102030405060708090100Position in the circular buffer (% of N_cb)Read the four starting points as percentages -- 0, 25.8, 50, 84.8 -- and the cycling order 0 -> 2 -> 3 -> 1 is simply theorder that keeps consecutive transmissions as far apart in the buffer as possible, so each one carries the most paritythe receiver has not yet seen.
Figure 5. Why the cycling order is 0 → 2 → 3 → 1 and not 0 → 1 → 2 → 3. Read the four starting points as percentages — 0, 50, 85, 26 — and the sequence is the one that keeps consecutive attempts as far apart in the buffer as possible, so each attempt delivers the most parity the receiver has not already seen.

Three consequences follow, and all three show up in logs:

  • RV0 is self-decodable and the others are generally not. RV0 starts at the systematic bits, so a receiver with an empty buffer can decode it alone if the channel is good enough. A UE that receives RV2 as its first sight of a transport block — because it missed the RV0 transmission — will usually fail, and correctly so.
  • Chase combining and incremental redundancy are the same mechanism. Sending RV0 repeatedly is chase combining: identical bits, so the receiver accumulates energy. Sending RV0 then RV2 is incremental redundancy: different bits, so the receiver accumulates code rate. IR is stronger and is the default; CC is what you get when the allocation is so large that a single transmission already reads the whole buffer and wrapping makes every RV equivalent.
  • The order 0/2/3/1 is not a rule the UE enforces. It is the sequence TS 38.214 mandates for repetition (pdsch-AggregationFactor and pusch-AggregationFactor, Tables 5.1.2.1-2 and 6.1.2.1-2) and the sequence essentially every scheduler uses for dynamic retransmission. The DCI carries an arbitrary rv_id, so a scheduler is free to send 0, 0, 0, 0 — and some do, in poor coverage, because chase combining needs no buffer state at the UE.
🧮
Worked Calculation

Real numbers, from the transport block worked out in §6:

Base graph 1, Z_c = 384, so N = N_cb = 66 × 384 = 25 344 bits per code block.

rv0: k_0 = 0

rv1: ⌊17 × 25 344 / (66 × 384)⌋ × 384 = ⌊17⌋ × 384 = 6 528 (25.8 %)

rv2: ⌊33 × 25 344 / 25 344⌋ × 384 = 33 × 384 = 12 672 (50.0 %)

rv3: ⌊56 × 25 344 / 25 344⌋ × 384 = 56 × 384 = 21 504 (84.8 %)

Each transmission in that example carries E ≈ 13 200 bits per code block, i.e. about 52 % of the buffer. So:

RV0 covers 0 … 13 200 (systematic plus early parity)

RV2 covers 12 672 … 25 344 + a 528-bit wrap -> ~96 % new bits

RV3 covers 21 504 … 25 344 then 0 … 9 360 -> mixed, mostly new

After RV0 and RV2 the receiver holds nearly the entire circular buffer, which is a code rate of about 0.30 against an original 0.60 — an effective doubling of the coding, from one retransmission.

6. Base Graphs, Code Blocks and the Transport Block Size

Before there is a circular buffer there is a choice of LDPC base graph and a segmentation of the transport block into code blocks, and both depend on the transport block size and the target code rate. This is worth following once end to end, because the code block count is what sets the CBG granularity in §10 and the per-code-block rate matching length in §5.

6.1 Which base graph

Condition on TBS (A) and target rate (R)Base graphK_cbMother code rateWhy
A ≤ 292BG23840≈1/5Very small blocks. BG2 is optimised for short payloads and low rates; BG1's structure wastes little but gains nothing here.
A ≤ 3824 and R ≤ 0.67BG23840≈1/5Small and not aggressively coded — the regime BG2 was designed for.
R ≤ 0.25BG23840≈1/5Any size, if the rate is very low. BG2 reaches a lower mother rate, so it has more parity to give.
OtherwiseBG18448≈1/3Large blocks or high rates. BG1 has the better high-rate performance and a bigger maximum code block.

Table 6. LDPC base graph selection, TS 38.212 cl. 7.2.2 (downlink) and cl. 6.2.2 (uplink). The rules are evaluated in order and the first match wins.

6.2 Segmentation

TS 38.212 cl. 5.2.2 -- code block segmentation and CRC attachment
B  = A + 24                        -- transport block CRC (CRC24A)

if B <= K_cb :   C = 1,  B' = B                 -- no segmentation,
                                                --   no code block CRC
else :           L = 24                         -- CRC24B per code block
                 C = ceil( B / (K_cb - L) )
                 B' = B + C x L

K' = B' / C                                     -- bits per code block
Z_c = smallest lifting size with  K_b x Z_c >= K'
      ( K_b = 22 for BG1;  10, 9, 8 or 6 for BG2 depending on B )
K   = K_b_max x Z_c                             -- 22 Z_c for BG1
filler bits = K - K'                            -- set to NULL, not sent

N   = 66 x Z_c  (BG1)   or   50 x Z_c  (BG2)    -- circular buffer size

6.3 Transport block size, worked

TBS is not a free parameter: it is derived from the allocation, the MCS and the overhead, then quantised so that both ends compute the same value without signalling it TS 38.214 cl. 5.1.3.2. Here is one, all the way through, and the numbers feed §5 and §10.

🧮
Worked Calculation

Given: 30 kHz SCS, 100 PRB, 1 layer, MCS 15 from the 64QAM table (Q_m = 4, R = 616/1024 = 0.6016), 12 OFDM symbols of PDSCH, one front-loaded DMRS symbol with two CDM groups without data (N_DMRS = 12 RE/PRB), xOverhead absent (N_oh = 0).

N_RE' = 12 × 12 − 12 − 0 = 132 RE per PRB

N_RE = min(156, 132) × 100 = 13 200 RE

N_info = 13 200 × 0.6016 × 4 × 1 = 31 764 bits

N_info > 3824, so: n = ⌊log₂(31 764 − 24)⌋ − 5 = 14 − 5 = 9, 2⁹ = 512

N_info' = max(3840, 512 × round(31 740 / 512)) = 512 × 62 = 31 744

R > 1/4 and N_info' > 8424, so:

C = ⌈(31 744 + 24) / 8424⌉ = ⌈3.77⌉ = 4 code blocks

TBS = 8 × 4 × ⌈31 768 / 32⌉ − 24 = 32 × 993 − 24 = 31 752 bits

= 3969 bytes

Check the effective rate. Coded bits available = 13 200 × 4 = 52 800. Payload plus CRCs = 31 752 + 24 + 4×24 = 31 872. Effective code rate = 31 872 / 52 800 = 0.604, against a target of 0.602 — the quantisation cost is 0.3 %.

Base graph. TBS = 31 752 > 3824 and R = 0.602 > 0.25 → BG1, K_cb = 8448. B = 31 776 > 8448, so C = ⌈31 776 / 8424⌉ = 4 — the same answer the TBS formula produced, as it must. K' = 31 872 / 4 = 7968; Z_c = 384 (the smallest lifting size with 22·Z_c ≥ 7968); K = 8448, so 480 filler bits per code block.

⚠️
Common Pitfall

The min(156, N_RE') cap in step two is easy to miss and it bites. It exists so that TBS does not grow without limit as the DMRS and overhead assumptions change, but the practical effect is that above 13 REs per symbol per PRB the extra resource elements are simply not counted. A scheduler that reduces DMRS overhead expecting a proportional TBS increase gets nothing back once the cap binds. In a log this looks like TBS refusing to move while the allocation changes.

7. Soft Combining, the Soft Buffer and Limited Buffer Rate Matching

What the receiver stores after a failed attempt is not the received bits but their log-likelihood ratios — soft values expressing how confident the demodulator is about each coded bit, positive for a likely zero and negative for a likely one, with magnitude proportional to confidence. When a retransmission arrives, the receiver adds the new LLRs into the same buffer at the positions the RV offset indicates. Positions covered twice accumulate confidence; positions covered for the first time fill in previously unknown parity. Then it runs the LDPC decoder over the whole accumulated buffer, not over the retransmission.

That is why the retransmission does not have to be independently decodable, and it is also why the soft buffer is expensive: it needs several bits of storage per coded bit, per code block, per HARQ process, per carrier. A UE aggregating four carriers with 16 processes each and four code blocks per transport block is holding 256 code blocks' worth of soft values.

Limited buffer rate matching is the escape valve. Instead of the full circular buffer N, rate matching is restricted to the first N_cb bits of it TS 38.212 cl. 5.4.2.1:

Limited buffer rate matching
N_cb = N                                        if LBRM is not in use
N_cb = min( N , N_ref )                         if LBRM is in use

  N_ref = floor( TBS_LBRM / (C x R_LBRM) )      with R_LBRM = 2/3

  TBS_LBRM is computed from a reference configuration: the maximum
  number of layers the UE is configured for on that cell, 256QAM if
  supported, the largest configured bandwidth part, and a code rate
  of 948/1024.

Consequence: the RV offsets in S5 are computed from N_cb, not N, so
with LBRM they all move towards the start of the buffer -- and the
highest-parity part of the code is never transmitted at all.
📘
Spec Detail

LBRM is a memory-versus-performance trade, and it changes what retransmissions are worth. With N_cb clipped to two thirds of N, RV3's offset lands at 84.8 % of a smaller buffer, so the fourth attempt re-sends bits the receiver already has instead of new parity — incremental redundancy quietly degrades toward chase combining as the attempt count rises. If a link shows good gain from the first retransmission and almost none from the third, LBRM is a candidate explanation before anything to do with the channel.

8. K1 and K2: the Timing Offsets, Worked to an Absolute Slot

NR signals every scheduling relationship as a slot offset, so that the same DCI formats work at every numerology and in every TDD pattern. Three offsets matter for HARQ:

OffsetFrom → toWhere the value comes fromRangeWhat constrains it
K0DCI → PDSCHk0 in the selected row of pdsch-TimeDomainAllocationList0 … 32 slotsK0 = 0 is same-slot scheduling: lowest latency, highest UE processing demand. Cross-slot (K0 ≥ 1) lets the UE micro-sleep through the PDCCH decode.
K1PDSCH → HARQ-ACKIndexed by the 0–3 bit PDSCH-to-HARQ_feedback timing indicator into dl-DataToUL-ACK; DCI 1_0 uses a fixed set insteaddl-DataToUL-ACK: up to 8 entries, each 0 … 15 slots. DCI 1_0: 1 … 8Must be at least the UE's PDSCH processing time N1, and must land on a slot with usable uplink symbols — which in TDD is the binding constraint.
K2DCI → PUSCHk2 in the selected row of pusch-TimeDomainAllocationList0 … 32 slotsMust be at least the UE's PUSCH preparation time N2. There is no K1 equivalent in the uplink because there is no feedback to time.

Table 7. The three HARQ-relevant timing offsets, TS 38.214 cl. 5.1.2.1 and 6.1.2.1, and TS 38.213 cl. 9.2.3 for the DCI 1_0 K1 table.

The processing times these offsets have to respect are capabilities, not configuration, and they are expressed in symbols so they shrink in absolute time but not in slots as numerology rises:

µSCSN1 (PDSCH decode, symbols)N2 (PUSCH prepare, symbols)N1 in slotsEffect
015 kHz8100.6K1 = 1 is achievable
130 kHz10120.7K1 = 1 still achievable
260 kHz17231.2K1 ≥ 2 in practice
3120 kHz20361.4K1 ≥ 2, K2 ≥ 3 in practice

Table 8. UE processing capability 1, front-loaded DMRS only, from TS 38.214 Table 5.3-1 and Table 6.4-1. Capability 2 (processingType2Enabled) is roughly half of these and is what makes sub-slot URLLC scheduling possible.

🧮
Worked Calculation

Given: 30 kHz SCS (20 slots per frame), TDD pattern DDDSU with a 2.5 ms periodicity, so slot s is uplink when s mod 5 = 4. dl-DataToUL-ACK = { 1, 2, 3, 4, 6, 7, 8, 9 }. A PDSCH is received in SFN 412, slot 7.

Slot 7: 7 mod 5 = 2 → a downlink slot. Good.

Candidate feedback slots: 7 + K1 for each configured K1.

K1 = 1 → slot 8 (8 mod 5 = 3, special slot)

K1 = 2 → slot 9 (9 mod 5 = 4, uplink ✓)

K1 = 3 → slot 10 (downlink ✗)

K1 = 7 → slot 14 (14 mod 5 = 4, uplink ✓)

The scheduler signals the index of K1 = 2. Absolute slot arithmetic:

absolute slot of the PDSCH = 412 × 20 + 7 = 8247

absolute slot of the PUCCH = 8247 + 2 = 8249 = SFN 412, slot 9

wall-clock offset from SFN 0 = 412 × 10 ms + 9 × 0.5 ms = 4124.5 ms

Is K1 = 2 legal? N1 at µ = 1 is 10 symbols ≈ 0.71 slots, and the PDSCH ends within slot 7, so two slots of headroom is comfortable. K1 = 1 would also satisfy N1 but slot 8 has too few uplink symbols to carry PUCCH in this pattern.

Earliest retransmission: the gNB must decode the PUCCH in slot 9 and prepare a PDSCH, so slot 11 (downlink) or slot 12 — a HARQ round trip of 5 slots = 2.5 ms.

⚠️
Common Pitfall

In TDD, dl-DataToUL-ACK is not a latency knob — it is a reachability list. Every downlink slot in the pattern needs at least one configured K1 that lands on an uplink slot, or PDSCH in that slot simply cannot be acknowledged and the scheduler must avoid it. A dl-DataToUL-ACK of { 2, 4 } on a DDDSU pattern leaves slot 1 unable to reach any uplink slot (1+2 = 3 is the special slot, 1+4 = 5 is downlink), so the cell quietly loses a fifth of its downlink capacity. The symptom is a scheduler that never uses certain slots, with no error anywhere.

9. HARQ-ACK Codebooks: Type-1, Type-2 and Type-3

One PUCCH transmission usually has to acknowledge more than one PDSCH: several downlink slots' worth of transport blocks, possibly across several carriers, all mapping onto the same uplink slot through their K1 values. The HARQ-ACK codebook is the agreement between UE and gNB about how many bits that PUCCH carries and which transport block each bit refers to. If the two sides disagree about the size, every bit is misaligned and the feedback is worse than useless.

Type-1 (semi-static)Type-2 (dynamic)Type-3 (one-shot)
Configured by
pdsch-HARQ-ACK-Codebook = semiStatic
pdsch-HARQ-ACK-Codebook = dynamic
pdsch-HARQ-ACK-OneShotFeedback (Rel-16), requested by a DCI bit
Size determined byConfiguration alone: the union over all configured K1 values of all candidate PDSCH occasions in the TDRA table, per serving cellWhat was actually scheduled, communicated through the DAI fieldsFixed: one entry per HARQ process of every configured serving cell
Robust to a missed DCI?Yes — the size never depends on what was sent. An unscheduled occasion is reported as NACK.Yes for a gap in the middle (counter DAI); across carriers only if total DAI is presentCompletely — it does not depend on any DCI having been received
OverheadOften large. A pattern with many candidate occasions produces a big codebook even when one PDSCH was sent.Minimal — exactly as many bits as there were assignmentsLarge: 16 or 32 bits per configured cell
Where it earns its placeSmall cells, few candidate occasions, or wherever robustness matters more than PUCCH overheadThe normal choice for a loaded carrier-aggregated UERecovering after a suspected codebook mismatch; NR-U, where whole bursts can be lost to listen-before-talk

Table 9. The three codebook types, TS 38.213 cl. 9.1.2 (Type-1), 9.1.3 (Type-2) and 9.1.4 (Type-3). Rel-16 also adds an enhanced dynamic codebook for NR-U that can group and retransmit feedback.

9.1 What the DAI fields actually do

In a dynamic codebook the UE cannot know the codebook size by configuration, so each DCI carries a counter DAI: a 2-bit value counting, modulo 4, the accumulated number of assignments up to and including this one, ordered first by serving cell and then by PDCCH monitoring occasion. A UE that misses one DCI sees the counter jump, infers exactly how many it missed, and pads the codebook with NACK at the right positions. The total DAI, present only when more than one serving cell is configured, states the total number of assignments across all cells up to the current monitoring occasion — which is the only defence against a DCI missed on a different carrier, where a counter jump would be indistinguishable from correct counting.

Type-2 Dynamic Codebook: What the DAI Is Actually ForType-2 Dynamic Codebook: What the DAI Is Actually ForUEgNBOne serving cell, four PDCCH monitoring occasions, four K1 values all pointing atuplink slot 9. Counter DAI counts assignments modulo 4.DCI 1_1 -> PDSCH #1 counter DAI = 0slot 5, K1 = 4 -> feedback in slot 91DCI 1_1 -> PDSCH #2 counter DAI = 1slot 6, K1 = 3 -> feedback in slot 92DCI 1_1 -> PDSCH #3 counter DAI = 2slot 7 -- PDCCH not decoded. The UE never learns this assignment existed.3DCI 1_1 -> PDSCH #4 counter DAI = 3slot 8, K1 = 1 -> feedback in slot 94counter DAI jumped 1 -> 3.One assignment is missing at position 3.Build a 4-bit codebook, bit 3 = NACK.PUCCH HARQ-ACK codebook: A A N Aslot 9, PUCCH format 2, 4 bits -- the size the gNB expects5bit 3 = NACK -> retransmit PDSCH #3(same pid, NDI unchanged, RV2)what happens without a counter DAIThe UE would report three bits. The gNB, expecting four, would align them toassignments 1, 2 and 3 -- so #4's ACK becomes #3's ACK, #3's NACK is lost, and thecodebook stays misaligned until something resets it.Counter DAI protects against a gap in the middle of the sequence. Total DAI, present only when more than one serving cellis configured, states how many assignments exist across all cells up to and including the current monitoring occasion --which is the only defence against a DCI missed on another carrier.
Figure 6. Four PDSCHs, one missed PDCCH, and a correctly sized codebook anyway. Without the counter DAI the UE would report three bits and the gNB would credit PDSCH #4's ACK to PDSCH #3.
🧮
Worked Calculation

Reconstructing the codebook. Single serving cell, four monitoring occasions, all K1 values pointing at uplink slot 9. Counter DAI is modulo 4, so the received values encode positions as (value + 1):

occasion 1: cDAI = 0 → assignment 1 decoded → ACK

occasion 2: cDAI = 1 → assignment 2 decoded → ACK

occasion 3: PDCCH missed — nothing received

occasion 4: cDAI = 3 → assignment 4

The UE sees 0, 1, 3. The step from 1 to 3 is 2 rather than 1, so exactly one assignment is unaccounted for, at position 3. Codebook size = highest position seen = 4 bits, contents [ACK, ACK, NACK, ACK].

The gNB reads four bits, sees bit 3 as NACK, and retransmits that transport block with the NDI unchanged. Total cost of the lost PDCCH: one retransmission.

The failure case. Modulo 4 wraps. If the UE misses four consecutive DCIs it sees 0 then 0 again and cannot tell four missing assignments from none — the codebook comes out one bit long instead of five. This is exactly the hole Type-3 one-shot feedback was added to plug.

9.2 Spatial bundling

On a cell configured for two transport blocks, each PDSCH produces two HARQ-ACK bits. harq-ACK-SpatialBundlingPUCCH and harq-ACK-SpatialBundlingPUSCH in PhysicalCellGroupConfig replace them with their logical AND, halving the codebook at the cost of retransmitting both transport blocks when only one failed. It is a PUCCH-overhead trade, and it is usually enabled on cells with many aggregated carriers and disabled where two-codeword MIMO is common enough for the wasted retransmissions to matter.

⚠️
Common Pitfall

Codebook type is configured per cell group, and both ends must agree exactly — including on the TDRA table and the K1 list, because with a Type-1 codebook those determine the size. A reconfiguration that changes pdsch-TimeDomainAllocationList changes the semi-static codebook size as a side effect, and if the UE applies the new configuration one slot before or after the gNB does, the feedback is misaligned for that slot. The signature is a burst of apparent NACKs immediately after an RRCReconfiguration, clearing by itself. It is not a radio problem.

10. Code Block Group Based Transmission

A transport block with four code blocks fails as a whole if any one code block fails, and a retransmission normally resends all four. When the failure is caused by something localised — a burst of interference hitting part of the allocation, or a pre-empted mini-slot — that is three quarters wasted. Code block group based transmission lets the scheduler retransmit only the failed subset.

Code Block Group Retransmission: One Quarter of the Air TimeCode Block Group Retransmission: One Quarter of the Air TimeC = 8 code blocks, maxCodeBlockGroupsPerTransportBlock = n4, so M = 4 groups of twoCB0CB1CB2CB3CB4CB5CB6CB7CBG 0CBG 1CBG 2CBG 3decodeddecodedCRC faildecodednot sentnot sentretransmittednot sentcode blocks['code block', 'groups']1st transmission['retransmission', 'CBGTI = 0010']01234567Code block index within the transport blockThe whole transport block is still one HARQ process, one NDI and one transport-block CRC -- only the coded bitssent are narrowed. The gain is air time; the cost is a per-CBG CRC and the CBGTI bitmap in every DCI.
Figure 7. Eight code blocks in four groups, one group failed, one group retransmitted. The transport block CRC still covers the whole block, so the UE only reports overall success once every group has decoded.
ElementASN.1 / DCI fieldRangeWhat it does
EnablecodeBlockGroupTransmission in PDSCH-ServingCellConfig (and PUSCH-ServingCellConfig)setup / releaseTurns CBG operation on for that serving cell and direction.
Group count
maxCodeBlockGroupsPerTransportBlock
n2, n4, n6, n8Upper bound N. The actual number is M = min(N, C), so a transport block with fewer code blocks than N gets fewer groups.
Which groups are sentCBGTI in DCI 1_1 / 0_12, 4, 6 or 8 bitsOne bit per group: 1 = this group is present in this transmission.
Whether to flushCBGFI in DCI 1_10 or 1 bit0 means the receiver should discard the soft bits it holds for the groups being retransmitted — used when the earlier attempt is known to be unusable rather than merely insufficient. Present only if codeBlockGroupFlushIndicator is configured.
Feedback granularityHARQ-ACK bits per TBM bits instead of 1The codebook grows by a factor of M, which is the price. This is why CBG and large aggregated codebooks interact badly.

Table 10. Code block group configuration and signalling, TS 38.212 cl. 7.3.1.2.2 and TS 38.214 cl. 5.1.7.

CBG earns its complexity in exactly two situations: large transport blocks (where retransmitting everything is expensive in absolute terms) and bursty, localised interference — most characteristically downlink pre-emption, where a URLLC mini-slot punches a hole in an eMBB allocation and damages a predictable subset of the code blocks. See the pre-emption indication (DCI 2_1) in the companion 08 Scheduling document. Outside those cases the M-fold increase in HARQ-ACK payload usually costs more than the saved retransmission, which is why most deployments leave codeBlockGroupTransmission unconfigured.

11. Uplink HARQ Without a PHICH

LTE had a dedicated physical channel, PHICH, whose only job was to carry one ACK/NACK bit per uplink transport block. NR deleted it. There is no downlink channel anywhere in NR that carries uplink HARQ feedback, and there is no MAC control element for it either. The feedback is the next grant.

11.1 How the UE infers the outcome

When the gNB fails to decode a PUSCH, it sends a new DCI for the same HARQ process with the NDI unchanged. The UE recognises that as "send that transport block again" and does so, at whatever RV the DCI specifies. When the gNB succeeds, it either sends a DCI for that process with the NDI toggled — which both acknowledges the old block and schedules a new one — or sends nothing at all for that process, leaving the UE holding the transport block in its buffer until something else happens.

  • No news is not good news, and it is not bad news either. A UE with no grant for a process simply waits. It does not retransmit on its own (except under a configured grant with cg-RetransmissionTimer, Rel-16 NR-U) and it does not flush.
  • There is no configured retry limit. Unlike LTE's maxHARQ-Tx, NR specifies no maximum number of HARQ transmissions in either direction. The scheduler decides when to stop, and the real bound comes from above: the PDCP discardTimer, the RLC maxRetxThreshold, and the delay budget of the 5QI.
  • Blind repetition is a separate mechanism. pusch-AggregationFactor (n2/n4/n8) and Rel-16 PUSCH repetition Type A and Type B send the same transport block several times without waiting for feedback, cycling the RV through 0/2/3/1. That is not HARQ retransmission; it is repetition, and it happens whether or not the first copy would have decoded.

11.2 Msg3 and configured grants

Two uplink cases sidestep the DCI entirely. The MAC PDU transmitted as MSG3 during Random Access uses HARQ process 0 by specification TS 38.321 cl. 5.4.2.1, because the UE has no C-RNTI-addressed DCI to carry a process ID at that point — see the companion 03 Random Access document. And a configured grant derives its process ID from the transmission time, using the formula in §3. Both are places where the process ID is not in any message you can read; you have to compute it.

🔍
What You See In Logs

The absence of a PHICH is why uplink HARQ debugging is asymmetric and harder. In the downlink you can see the UE's verdict directly, as a bit on PUCCH. In the uplink there is no verdict to see — only the gNB's reaction, which is a grant that may or may not appear, with an NDI whose meaning depends on state neither log necessarily prints. Always reconstruct the NDI history per process before drawing any conclusion about uplink HARQ.

12. Disabled HARQ Feedback and Very Long Round Trips

Everything so far assumes the round trip is short enough that a process waiting for feedback is a minor inefficiency. Over a geostationary satellite the round trip is around 270 ms, which at 30 kHz is 540 slots. Sixteen processes would leave the link idle 97 % of the time, and even 32 would not fix it. Rel-17 therefore allows HARQ feedback to be switched off per process.

MechanismSignallingEffectWhat replaces the reliability
Disabled downlink HARQ feedbackdownlinkHARQ-FeedbackDisabled-r17 in the Rel-17 extension of PDSCH-ServingCellConfig — a bit string with one bit per HARQ processFor a process with feedback disabled the UE reports no HARQ-ACK, and every reception on that process is treated as new data (no soft combining across transmissions)RLC ARQ, plus blind repetition. The 10⁻¹ first-attempt target is no longer viable, so link adaptation must aim much lower.
More processesnrofHARQ-ProcessesForPDSCH-v1700 = n32; 5-bit HARQ process number fieldDoubles the number of transport blocks that can be in flightNothing — this is pure pipelining, and it helps but does not solve a 270 ms round trip.
Shifted feedback timingcellSpecificKoffset-r17 and kmac-r17 in NTN-ConfigPushes K1, K2 and the RAR window far enough into the future that the propagation delay fits inside the scheduling relationshipNot a reliability mechanism — it makes the existing timing relationships expressible at all.

Table 11. Rel-17 long-round-trip mechanisms. The timing side of this is covered in the companion 04 Timing Advance document, which carries the same NTN-Config structure.

🔄
Release Delta

Disabling HARQ feedback is not only an NTN feature in effect. Any mechanism where the feedback costs more than it saves reaches for the same idea — which is why the Rel-17 signalling is a general per-process bitmap rather than an NTN mode. When feedback is disabled the process behaves like a fire-and-forget pipe: the NDI still toggles, but the receiver never combines and never answers, so the only thing standing between a lost transport block and the application is RLC. Traces from such a link show HARQ processes cycling with no PUCCH activity at all, and RLC status reports doing all the visible work.

13. HARQ, DRX, and the Timers That Connect Them

A UE in DRX is asleep most of the time, and a NACK it just sent creates an obligation to be awake later — but not immediately, because no retransmission is physically possible until the gNB has decoded the feedback and prepared one. Two per-process timers encode exactly that TS 38.321 cl. 5.7:

HARQ Retransmission Through a DRX SleepHARQ Retransmission Through a DRX Sleep30 kHz SCS; drx-HARQ-RTT-TimerDL is configured in symbols, drx-RetransmissionTimerDL in slotsDRXdrx-onDurationTimerOpportunity for DRX -- outside Active Time unless something holds the UE awakePDSCHpid 3RV0RV2retransmission arrives ->timer stopped, process freedHARQ-ACKNACKACKdrx-HARQ-RTT-TimerDL(3)running:UE may sleepdrx-RetransmissionTimerDL(3)Active Time: monitor PDCCHfor the retransmission051015202530Time (ms) from the start of the DRX cycleThe two timers exist so a NACK does not force the UE to stay awake for the whole round trip. It sleeps through the RTTtimer, wakes for the retransmission window, and sleeps again. Sizing drx-RetransmissionTimerDL shorter than thescheduler's actual retransmission delay makes retransmissions invisible to the UE -- see the companion 11 DRX document.
Figure 8. One retransmission through a DRX cycle. The UE sleeps through the round trip, wakes for the window in which a retransmission could plausibly arrive, and sleeps again. Both timers are per HARQ process, so a UE with several outstanding NACKs has several overlapping wake windows.
TimerUnit and rangeStarted whenEffect while running
drx-HARQ-RTT-TimerDL
Symbols, 0 … 56At the first symbol after the HARQ-ACK for that process has been transmittedThe UE need not monitor PDCCH for that process — no retransmission can arrive yet, so it may sleep.
drx-RetransmissionTimerDL
Slots: sl0, sl1, sl2, sl4, sl6, sl8, sl16, sl24, sl33, sl40, sl64, sl80, sl96, sl112, sl128, sl160, sl320On expiry of drx-HARQ-RTT-TimerDL, if the transport block was not successfully decodedThe UE is in DRX Active Time and must monitor PDCCH for that process. Stopped as soon as the retransmission is scheduled.
drx-HARQ-RTT-TimerUL
Symbols, 0 … 56At the first symbol after the end of the PUSCH transmission (the first repetition, if repetition is configured)Same logic in the uplink: no retransmission grant can arrive yet.
drx-RetransmissionTimerUL
Slots, same enumeration as DLOn expiry of drx-HARQ-RTT-TimerULActive Time, monitoring for a retransmission grant — which is the only form uplink HARQ feedback takes (§11).

Table 12. The four HARQ-related DRX timers. The RTT timer is a permission to sleep; the retransmission timer is an obligation to wake. See the companion 11 DRX document for how these sit inside the wider Active Time rules.

⚠️
Common Pitfall

drx-RetransmissionTimerDL has to be at least as long as the scheduler's actual retransmission delay, and nothing checks that it is. Set it to sl4 on a system whose scheduler typically retransmits eight slots after the NACK, and the UE stops monitoring before the retransmission arrives: the PDCCH is transmitted, missed, and the process stalls until something else wakes the UE. The symptom is downlink throughput that collapses only for UEs in DRX, with clean HARQ statistics for UEs that happen to be continuously active — because for those the timer never matters.

14. Parameter Reference: ASN.1, Ranges and Effects

ASN.1 nameWhereRange / valuesTypicalEffect
nrofHARQ-ProcessesForPDSCH
PDSCH-ServingCellConfig
n2, n4, n6, n10, n12, n16n16 (default 8 when absent)Size of the downlink process pool. Too few stalls the pipeline; too many divides the soft buffer.
pdsch-HARQ-ACK-Codebook
PhysicalCellGroupConfig
semiStatic, dynamicdynamicWhether the codebook size comes from configuration or from the DAI. Must match at both ends exactly (§9).
harq-ACK-SpatialBundlingPUCCH
PhysicalCellGroupConfig
true (present) / absentabsentANDs the two TBs' feedback on 2-codeword cells. Halves PUCCH payload, wastes retransmissions.
dl-DataToUL-ACK
PUCCH-Config
1 … 8 entries, each 0 … 15 slots{1,2,3,4,6,7,8,9} on DDDSUThe K1 candidate set. In TDD it decides which downlink slots are usable at all (§8).
k0 / k2PDSCH- / PUSCH-TimeDomainResourceAllocation0 … 32 slots0–1 / 2–4DCI-to-data offsets. K0 ≥ 1 enables cross-slot scheduling and UE power saving.
codeBlockGroupTransmission
PDSCH- / PUSCH-ServingCellConfigsetup / releaseabsentEnables CBG operation. Multiplies the HARQ-ACK payload by M (§10).
maxCodeBlockGroupsPerTransportBlock
PDSCH-CodeBlockGroupTransmission
n2, n4, n6, n8n4Upper bound on groups per TB; actual M = min(N, C).
codeBlockGroupFlushIndicator
sameBOOLEANfalseAdds the 1-bit CBGFI to DCI 1_1.
pdsch-AggregationFactor
PDSCH-Config
n2, n4, n8absentBlind repetition of PDSCH over consecutive slots, RV cycling 0/2/3/1. Not HARQ retransmission.
pusch-AggregationFactor
PUSCH-Config
n2, n4, n8absentThe uplink equivalent.
xOverhead
PDSCH-ServingCellConfig
xOh6, xOh12, xOh18absent (= 0)Assumed non-data overhead per PRB in the TBS formula. Changing it changes TBS on both sides — a mismatch is a silent decode failure.
processingType2Enabled
PDSCH-ServingCellConfig
BOOLEANfalseSelects UE processing capability 2, roughly halving N1/N2 and allowing smaller K1/K2.
drx-HARQ-RTT-TimerDL / -UL
DRX-Config
0 … 56 symbols≈ the round tripPermission to sleep through the round trip (§13).
drx-RetransmissionTimerDL / -UL
DRX-Config
sl0 … sl320sl16 … sl40Obligation to monitor for the retransmission. Too short loses it.
downlinkHARQ-FeedbackDisabled-r17
PDSCH-ServingCellConfig (Rel-17)bit string, one bit per processabsentPer-process feedback disable for long round trips (§12).

Table 13. HARQ-relevant configuration. Note how much of HARQ has no configuration at all: the NDI semantics, the RV offsets, the base graph rules and the retry budget are all fixed or left to the scheduler.

15. Failure Modes and What Each One Means

FailureDetected byWhat happens nextDiagnostic pointer
PDSCH CRC failsUESoft bits retained, NACK reported at n + K1, process stays occupiedEntirely normal at a 10 % rate. Only the rate is informative, and only against the link adaptation target.
NACK misread as ACK by the gNBNobody at MAC levelThe gNB frees the process and moves on; the transport block is lost silentlyShows up as an RLC retransmission with no corresponding HARQ retransmission. This is the single most important HARQ failure to be able to recognise, because HARQ statistics look perfect.
ACK misread as NACK by the gNBNobodyA pointless retransmission; the UE receives a duplicate of a TB it already decoded and discards itWasted capacity, no data impact. A high rate points at PUCCH power control or PUCCH resource collision, not at PDSCH.
PDCCH missed, so the UE never knows a PDSCH existedUE, indirectlyWith a dynamic codebook, the counter DAI reveals the gap and the UE reports NACK for it (§9). With a semi-static codebook the occasion was always in the codebook, so it is reported NACK anyway.PDCCH BLER. If the codebook size is wrong rather than one bit, suspect a Type-1 configuration mismatch instead.
Codebook size mismatch between UE and gNBNeither, immediatelyEvery bit in that PUCCH is misinterpreted; processes are freed or retransmitted at randomA burst of implausible feedback, often right after an RRCReconfiguration that touched the TDRA table or dl-DataToUL-ACK. Rel-16 Type-3 one-shot feedback exists to recover from it.
NDI state lost at the UE (buffer flush, DRX, TAG expiry)UEThe next reception on that process is treated as new data, so a retransmission is decoded without combining and almost certainly failsOne extra failed attempt per process after any flush event. Correlate against timeAlignmentTimer expiry — see the companion 04 Timing Advance document.
drx-RetransmissionTimer too shortNobodyThe UE stops monitoring before the retransmission is scheduled; the process stallsPoor throughput only for UEs in DRX, with normal HARQ statistics for continuously active UEs (§13).
Configured-grant process ID mismatchNobodyThe gNB retransmits into a process the UE has different data inCorrupted uplink with no HARQ error reported by either side. Recompute the process ID from the formula in §3 and compare (§3).
HARQ exhausted by scheduler policygNB (its own decision)The block is abandoned at MAC; RLC AM notices the sequence-number gap and retransmitsLook at the RLC status reports, not the HARQ counters. If maxRetxThreshold is then exceeded, RLC declares failure and RRC declares RLF — see the companion 16 RLM and RLF document.
Soft buffer exhausted / LBRM clippingUE, invisiblyLater redundancy versions re-send bits already held, so combining gain plateausGood gain from the first retransmission, little from the third (§7). Check the configured process count and the UE's soft-buffer capability.

Table 14. HARQ failure modes. Notice how many are detected by nobody — HARQ has almost no self-diagnosis, and its one-bit feedback has no integrity protection.

💡
Key Point

The failure worth memorising is the second row. A NACK misread as an ACK produces perfect HARQ statistics and lost data, because from HARQ's point of view nothing went wrong: the process was acknowledged and freed. The only visible trace is an RLC retransmission with no HARQ retransmission behind it. If you are chasing throughput loss that HARQ counters say cannot exist, compare RLC retransmission counts against HARQ retransmission counts — a persistent excess of the former is the signature.

16. ASN.1 Extracts

HARQ configuration is spread across four places: the per-cell PDSCH and PUSCH serving-cell configurations, the cell-group physical configuration, the PUCCH configuration for K1, and the DRX configuration. Abridged from TS 38.331; ... marks omitted fields and extension markers.

PDSCH-ServingCellConfig ::= SEQUENCE {
    codeBlockGroupTransmission  SetupRelease {
                                  PDSCH-CodeBlockGroupTransmission } OPTIONAL,
    xOverhead                   ENUMERATED { xOh6, xOh12, xOh18 } OPTIONAL,
    nrofHARQ-ProcessesForPDSCH  ENUMERATED { n2, n4, n6, n10, n12, n16 }
                                                                   OPTIONAL,
    pucch-Cell                  ServCellIndex                      OPTIONAL,
    ...,
    [[ maxMIMO-Layers           INTEGER (1..8)                     OPTIONAL,
       processingType2Enabled   BOOLEAN                            OPTIONAL ]],
    [[ downlinkHARQ-FeedbackDisabled-r17
                                SetupRelease { DownlinkHARQ-FeedbackDisabled-r17 }
                                                                   OPTIONAL,
       nrofHARQ-ProcessesForPDSCH-v1700
                                ENUMERATED { n32 }                 OPTIONAL ]]
}

PDSCH-CodeBlockGroupTransmission ::= SEQUENCE {
    maxCodeBlockGroupsPerTransportBlock  ENUMERATED { n2, n4, n6, n8 },
    codeBlockGroupFlushIndicator         BOOLEAN,
    ...
}

PhysicalCellGroupConfig ::= SEQUENCE {
    harq-ACK-SpatialBundlingPUCCH  ENUMERATED { true }             OPTIONAL,
    harq-ACK-SpatialBundlingPUSCH  ENUMERATED { true }             OPTIONAL,
    p-NR-FR1                       P-Max                           OPTIONAL,
    pdsch-HARQ-ACK-Codebook        ENUMERATED { semiStatic, dynamic },
    tpc-SRS-RNTI                   RNTI-Value                      OPTIONAL,
    ...,
    [[ pdsch-HARQ-ACK-OneShotFeedback-r16     ENUMERATED { true }  OPTIONAL,
       pdsch-HARQ-ACK-OneShotFeedbackNDI-r16  ENUMERATED { true }  OPTIONAL,
       pdsch-HARQ-ACK-OneShotFeedbackCBG-r16  ENUMERATED { true }  OPTIONAL ]]
}

Listing 1. Downlink HARQ configuration. Note that pdsch-HARQ-ACK-Codebook is mandatory and per cell group — there is no way to run different codebook types on different carriers of one group.

PUCCH-Config ::= SEQUENCE {
    resourceSetToAddModList   SEQUENCE (SIZE (1..4)) OF PUCCH-ResourceSet
                                                                  OPTIONAL,
    resourceToAddModList      SEQUENCE (SIZE (1..128)) OF PUCCH-Resource
                                                                  OPTIONAL,
    format1                   SetupRelease { PUCCH-FormatConfig } OPTIONAL,
    dl-DataToUL-ACK           SEQUENCE (SIZE (1..8)) OF INTEGER (0..15)
                                                                  OPTIONAL,
    pucch-PowerControl        PUCCH-PowerControl                  OPTIONAL,
    ...
}

PDSCH-TimeDomainResourceAllocation ::= SEQUENCE {
    k0                        INTEGER (0..32)                     OPTIONAL,
    mappingType               ENUMERATED { typeA, typeB },
    startSymbolAndLength      INTEGER (0..127)
}

PUSCH-TimeDomainResourceAllocation ::= SEQUENCE {
    k2                        INTEGER (0..32)                     OPTIONAL,
    mappingType               ENUMERATED { typeA, typeB },
    startSymbolAndLength      INTEGER (0..127)
}

DRX-Config ::= SEQUENCE {
    drx-onDurationTimer          CHOICE { subMilliSeconds INTEGER (1..31),
                                          milliSeconds ENUMERATED {...} },
    drx-InactivityTimer          ENUMERATED { ms0, ms1, ..., ms1280 },
    drx-HARQ-RTT-TimerDL         INTEGER (0..56),
    drx-HARQ-RTT-TimerUL         INTEGER (0..56),
    drx-RetransmissionTimerDL    ENUMERATED { sl0, sl1, sl2, sl4, sl6, sl8,
                                              sl16, sl24, sl33, sl40, sl64,
                                              sl80, sl96, sl112, sl128,
                                              sl160, sl320 },
    drx-RetransmissionTimerUL    ENUMERATED { ... same ... },
    ...
}

Listing 2. The timing side: K1 candidates, K0/K2, and the two pairs of DRX HARQ timers. drx-HARQ-RTT-Timer* is in symbols while drx-RetransmissionTimer* is in slots — a units mismatch that has caused real misconfigurations.

17. Illustrative Message Traces

🔍
About These Traces

Illustrative trace. Field names and encodings follow 3GPP; the values are constructed for this document and are not a capture from any deployed or lab network.

17.1 A downlink retransmission, decoded field by field

[PHY/MAC] downlink HARQ, first attempt fails
14:22:08.4120  [PHY-DL] PDCCH  DCI 1_1  CRC scrambled by C-RNTI 0x4601
                SFN 412  slot 7   (absolute slot 8247, 30 kHz)
                freq domain RA .............. 100 PRB from PRB 0
                time domain RA .............. row 2: k0=0, S=2, L=12
                MCS ......................... 15   -- Qm 4, R 616/1024
                NDI ......................... 1    -- stored value was 0
                RV .......................... 0
                HARQ process number ......... 3
                counter DAI ................. 0
                PUCCH resource indicator .... 1
                PDSCH-to-HARQ timing ind .... 1    -> dl-DataToUL-ACK[1]
                                                   -> K1 = 2 slots
14:22:08.4120  [MAC-DL] HARQ pid 3: NDI toggled 0 -> 1  => NEW DATA
                flush soft buffer for pid 3, store NDI = 1
                TBS ......................... 31752 bits (3969 bytes)
                code blocks ................. 4    -- BG1, Z_c 384
                N_RE ........................ 13200, coded bits 52800
                effective code rate ......... 0.604
14:22:08.4123  [PHY-DL] PDSCH decode  pid 3  CRC FAIL
                LDPC iterations ............. 8 (max)
                soft bits retained .......... 13200 per code block

14:22:08.4130  [PHY-UL] PUCCH format 1, 1 bit, HARQ-ACK = NACK
                SFN 412  slot 9  (8247 + K1 = 8249)

14:22:08.4145  [PHY-DL] PDCCH  DCI 1_1  C-RNTI 0x4601   SFN 412 slot 12
                MCS ......................... 15   -- unchanged
                NDI ......................... 1    -- UNCHANGED => retx
                RV .......................... 2
                HARQ process number ......... 3
14:22:08.4145  [MAC-DL] HARQ pid 3: NDI unchanged => RETRANSMISSION
                RV 2 -> k_0 = 33 x Z_c = 12672  (50.0 % of N_cb 25344)
                combine 13200 new soft bits at offset 12672
                accumulated coverage ........ ~96 % of the buffer
                effective code rate now ..... 0.31
14:22:08.4148  [PHY-DL] PDSCH decode  pid 3  CRC PASS  (3 iterations)
14:22:08.4155  [PHY-UL] PUCCH  HARQ-ACK = ACK   SFN 412 slot 14
14:22:08.4155  [MAC-DL] pid 3 released; TB delivered to demultiplexing

-- HARQ round trip: slot 7 -> slot 12 = 5 slots = 2.5 ms

Listing 3. One NACK and one successful retransmission, with the RV offset and the resulting code rate carried through. The falling code rate — 0.604 to 0.31 — is the incremental redundancy gain, quantified.

17.2 Dynamic codebook reconstruction after a missed PDCCH

[PHY/MAC] Type-2 codebook with one missed assignment
14:31:55.0000  [CFG] pdsch-HARQ-ACK-Codebook = dynamic,
                     one serving cell, no total DAI field present

14:31:55.0025  [PHY-DL] DCI 1_1  slot 5   pid 2  NDI 1  cDAI 0  K1 4
14:31:55.0028  [PHY-DL] PDSCH    slot 5   pid 2  CRC PASS
14:31:55.0030  [PHY-DL] DCI 1_1  slot 6   pid 3  NDI 0  cDAI 1  K1 3
14:31:55.0033  [PHY-DL] PDSCH    slot 6   pid 3  CRC PASS
14:31:55.0035  [PHY-DL] PDCCH blind decode set exhausted, slot 7
                        -- no DCI found; the UE does not know one was sent
14:31:55.0040  [PHY-DL] DCI 1_1  slot 8   pid 5  NDI 1  cDAI 3  K1 1
14:31:55.0043  [PHY-DL] PDSCH    slot 8   pid 5  CRC PASS

14:31:55.0045  [MAC-UL] building Type-2 HARQ-ACK codebook for slot 9
                cDAI values received ........ 0, 1, 3
                gap detected between 1 and 3 -> 1 assignment missed
                codebook size ............... 4 bits
                bit 1 (cDAI 0, pid 2) ....... ACK
                bit 2 (cDAI 1, pid 3) ....... ACK
                bit 3 (missed) .............. NACK
                bit 4 (cDAI 3, pid 5) ....... ACK
14:31:55.0047  [PHY-UL] PUCCH format 2, 4 bits: 1 1 0 1   slot 9

14:31:55.0060  [PHY-DL] DCI 1_1  slot 11  pid 4  NDI 1 (unchanged)  RV 2
                        -- gNB retransmitting the TB the UE never saw;
                        -- to the UE, pid 4 has no stored NDI, so this
                        -- is treated as NEW DATA and decoded alone
14:31:55.0063  [PHY-DL] PDSCH    slot 11  pid 4  CRC FAIL
                        -- RV2 is not self-decodable; expected outcome
14:31:55.0075  [PHY-DL] DCI 1_1  slot 12  pid 4  NDI 1 (unchanged)  RV 3
14:31:55.0078  [PHY-DL] PDSCH    slot 12  pid 4  CRC PASS
                        -- RV2 + RV3 together cover enough of the buffer

Listing 4. The codebook survives the missed PDCCH, but the retransmission does not survive it cleanly: the UE has no soft bits to combine, so a non-self-decodable RV2 fails and a second attempt is needed. This is normal and is why RV0 is sometimes repeated in poor coverage.

17.3 Uplink HARQ, where the grant is the feedback

[PHY/MAC] uplink HARQ, implicit feedback
14:44:02.1000  [PHY-DL] DCI 0_1  C-RNTI 0x4601   slot 3
                HARQ process number ......... 7
                NDI ......................... 0    -- stored was 1 => NEW
                RV .......................... 0
                MCS ......................... 11
                k2 .......................... 3   -> PUSCH in slot 6
14:44:02.1015  [MAC-UL] pid 7: new transmission, TBS 6272 bits
14:44:02.1015  [PHY-UL] PUSCH  slot 6  pid 7  RV 0
               -- no PHICH exists. The UE now waits, holding the TB.

14:44:02.1040  [PHY-DL] DCI 0_1  C-RNTI 0x4601   slot 8
                HARQ process number ......... 7
                NDI ......................... 0    -- UNCHANGED
                RV .......................... 2
14:44:02.1040  [MAC-UL] pid 7: NDI unchanged => this is a NACK,
                        expressed as a grant. Retransmit from the buffer.
14:44:02.1055  [PHY-UL] PUSCH  slot 11  pid 7  RV 2

14:44:02.1090  [PHY-DL] DCI 0_1  C-RNTI 0x4601   slot 16
                HARQ process number ......... 7
                NDI ......................... 1    -- TOGGLED
                RV .......................... 0
14:44:02.1090  [MAC-UL] pid 7: NDI toggled => the previous TB was
                        received. Flush pid 7, build a new TB from the
                        LCP procedure, transmit.
               -- the toggle is the only acknowledgement that ever
               -- arrives for an uplink transport block

Listing 5. Three grants and no acknowledgement channel. The NDI toggling at 14:44:02.1090 is simultaneously the ACK for the old transport block and the grant for the new one. See the companion 09 LCP document for how the new TB's contents are chosen.

17.4 The failure that HARQ cannot see

[PHY/MAC/RLC] NACK misread as ACK
15:02:11.2000  [PHY-DL] PDSCH  pid 9  NDI 1  RV 0   CRC FAIL
15:02:11.2010  [PHY-UL] PUCCH  HARQ-ACK = NACK for pid 9
                        UE transmit power .... 14.2 dBm
                        (gNB side) PUCCH DTX/ACK/NACK decision ... ACK
                        -- the gNB misread the NACK as an ACK
15:02:11.2010  [MAC-DL] (gNB) pid 9 acknowledged, process released
                        -- no retransmission will ever be scheduled
15:02:11.2010  [MAC-DL] (UE)  pid 9 still holds soft bits, waiting

15:02:11.2500  [MAC-DL] PDSCH  pid 9  NDI 0  RV 0
                        -- a completely different transport block
15:02:11.2500  [MAC-DL] (UE) NDI toggled => new data, flush pid 9
                        -- the old TB's soft bits are discarded. The TB
                        -- itself was never delivered and never will be
                        -- by HARQ.

15:02:11.3120  [RLC-DL] AM: SN gap detected, SN 4471 missing
                        t-Reassembly started
15:02:11.3620  [RLC-UL] RLC STATUS PDU: ACK_SN 4478, NACK_SN 4471
15:02:11.3700  [RLC-DL] retransmission of SN 4471 (segment 0)
15:02:11.3700  [MAC-DL] PDSCH  pid 12  NDI 1  RV 0   CRC PASS
                        -- carrying the RLC retransmission

-- HARQ counters for this interval:
--   PDSCH transmissions ....... 148
--   HARQ retransmissions ...... 14   (9.5 %  -- on target)
--   HARQ failures ............. 0
--   RLC AM retransmissions .... 3    <-- the real story is here

Listing 6. A NACK-to-ACK error. HARQ statistics are flawless — no failures, retransmission rate exactly on target — and a transport block was lost anyway. The only evidence is the RLC retransmission count. This is the pattern described in §15.

Two habits pay for themselves when reading traces like §17.4. First, always read HARQ retransmission counts next to RLC retransmission counts — HARQ alone cannot report the failure that matters most. Second, reconstruct the NDI history per process rather than reading each DCI in isolation; the NDI means nothing on its own, and a log line showing NDI = 1 is not information until you know what the previous value for that process was.

18. Release Deltas: Rel-15 to Rel-18

ReleaseChangeWhy it matters when reading HARQ
Rel-1516 asynchronous processes in both directions, explicit process ID, NDI toggle, four RVs over a circular buffer, LDPC with two base graphs, Type-1 and Type-2 codebooks, CBG transmission, spatial bundling, no PHICHThe baseline. Everything in §§2–11 is Rel-15 and unchanged.
Rel-16Type-3 (one-shot) HARQ-ACK feedback, requested by a DCI 1_1 bitA UE can now be asked to dump feedback for every process on every cell, which is the only clean recovery from a codebook mismatch.
Rel-16Enhanced dynamic codebook and codebook retransmission for NR-U; cg-RetransmissionTimer for autonomous configured-grant retriesUplink retransmission can now happen without a grant, which breaks the "grant = feedback" rule of §11 in exactly one place.
Rel-16DCI formats 0_2 and 1_2 with configurable field sizes; dl-DataToUL-ACKForDCIFormat1_2The HARQ fields can be different widths in the same cell depending on which DCI format scheduled the PDSCH.
Rel-16Physical-layer priority indicator (1 bit) in DCI 0_1/1_1; intra-UE prioritisationTwo HARQ-ACK payloads can now collide and one wins by priority rather than by rule — see the companion 08 Scheduling document.
Rel-16PUSCH repetition Type B (back-to-back nominal repetitions with segmentation)Repeated transmissions of one TB are no longer slot-aligned, so counting "transmissions per process" in a trace needs care.
Rel-17Disabled downlink HARQ feedback per process (downlinkHARQ-FeedbackDisabled), for NTNA process can legitimately show no PUCCH activity at all and no soft combining (§12).
Rel-1732 HARQ processes, 5-bit process number field (nrofHARQ-ProcessesForPDSCH-v1700, nrofHARQ-ProcessesForPUSCH-r17)A logged process ID above 15 is valid. Decoders that mask 4 bits will silently alias process 17 onto process 1.
Rel-17480 and 960 kHz numerologies (FR2-2); cellSpecificKoffset for NTNK1 and K2 in slots no longer imply the timings the terrestrial intuitions in §8 assume.
Rel-17Multicast/broadcast (MBS) with DCI formats 4_0/4_1/4_2 and group-common HARQ feedback modesHARQ-ACK can now be reported for a group-addressed transmission, or not at all, depending on the mode.
Rel-18Further NTN and MBS refinements; enhancements to multi-carrier scheduling with a single DCIOne DCI can carry HARQ fields for more than one cell, so process IDs and codebook positions are no longer one-to-one with the DCI.

Table 15. HARQ changes by release. Confirm feature presence against the UE capability exchange — see the companion 26 UE Capability document.

19. Reading HARQ in Logs: A Checklist

1. Group everything by HARQ process ID first. A HARQ trace read in time order is nearly meaningless; read in per-process order it tells a story. Watch for process IDs above 15 — valid from Rel-17, and a common decoder bug (§18).

2. Reconstruct the NDI history per process. A single NDI = 1 line carries no information. Only the change from the previous transmission on that process does, and a flush event resets the reference (§4).

3. Check the RV against the attempt number. RV0 on a first attempt is normal. RV0 on every attempt means chase combining, which is a deliberate scheduler choice in poor coverage, not a fault. RV2 as the first thing a process sees means the initial PDCCH was missed, and a failure there is expected (§5, §17.2).

4. Verify the K1 arithmetic against the TDD pattern. Compute n + K1 and confirm it lands on a slot with usable uplink symbols. If some downlink slots have no reachable uplink slot, the scheduler is losing capacity silently (§8).

5. Establish the codebook type before interpreting any PUCCH payload. A 4-bit codebook read as 1 bit, or a semi-static codebook read as dynamic, makes every subsequent conclusion wrong. If the size looks implausible, look for a recent RRCReconfiguration (§9).

6. Follow the counter DAI sequence. Gaps are the record of missed PDCCHs, and they are the cheapest available PDCCH BLER estimate. A counter that wraps without a visible gap can hide four missed assignments (§9.1).

7. Read HARQ and RLC retransmission counts together, always. An excess of RLC retransmissions over HARQ retransmissions is the signature of NACK-to-ACK errors, which HARQ itself reports as perfect health (§15).

8. For uplink, look for the grant, not for feedback. There is no PHICH. Success is an NDI toggle on the next grant for that process, and "no grant" means neither success nor failure (§11).

9. Check whether the UE is in DRX before blaming the scheduler. A stalled process on a DRX UE with healthy statistics for active UEs points at drx-RetransmissionTimer, not at radio (§13).

10. Recompute configured-grant and SPS process IDs from the formula. They are in no message. A mismatch between the two sides' periodicity or process count corrupts data with no error reported anywhere (§3).

20. Glossary

TermExpansionMeaning in this document
HARQHybrid Automatic Repeat reQuestRetransmission with soft combining, at MAC/PHY. Hybrid = ARQ plus forward error correction that accumulates across attempts.
HARQ processOne independent stop-and-wait instance, with its own soft buffer and its own NDI state. Identified by a 4-bit (Rel-17: 5-bit) ID in the DCI.
NDINew Data IndicatorOne bit whose change since the last transmission on that process means new data. Not a flag (§4).
RVRedundancy VersionTwo bits selecting one of four starting offsets into the circular buffer. Not a coding mode (§5).
Circular bufferThe full LDPC encoder output per code block: 66·Z_c bits for BG1, 50·Z_c for BG2. Rate matching reads a wrapping run out of it.
N_cbThe portion of the circular buffer rate matching may use. Equal to N unless limited buffer rate matching applies (§7).
Z_cLifting sizeThe LDPC expansion factor, chosen as the smallest value large enough to hold the code block. Sets the buffer size and the RV granularity.
IR / CCIncremental Redundancy / Chase CombiningRetransmitting different coded bits, versus the same ones. In NR both are just choices of RV (§5).
Soft bufferReceiver memory holding log-likelihood ratios for a not-yet-decoded code block, per process.
K0 / K1 / K2Slot offsets: DCI→PDSCH, PDSCH→HARQ-ACK, DCI→PUSCH (§8).
DAIDownlink Assignment IndexCounter DAI numbers the assignments so a UE can size a dynamic codebook after a missed DCI; total DAI does the same across carriers (§9.1).
CodebookHARQ-ACK codebookThe agreed mapping from bits in one PUCCH transmission to transport blocks. Type-1 semi-static, Type-2 dynamic, Type-3 one-shot.
CBGCode Block GroupA subset of a transport block's code blocks that can be retransmitted on its own (§10).
CBGTI / CBGFICBG Transmission / Flushing Out InformationDCI fields saying which groups are present, and whether to discard what is held for them.
PHICHPhysical HARQ Indicator ChannelAn LTE channel carrying uplink HARQ feedback. Does not exist in NR (§11).
LBRMLimited Buffer Rate MatchingClipping N_cb to bound receiver memory, at the cost of later redundancy versions repeating rather than adding (§7).

21. References

  • 3GPP TS 38.321NR MAC protocol specification. Clause 5.3.2 (downlink HARQ operation and the reception procedure), 5.4.1 (configured-grant HARQ process ID derivation), 5.4.2 (uplink HARQ operation), 5.7 (DRX, including drx-HARQ-RTT-Timer and drx-RetransmissionTimer behaviour).
  • 3GPP TS 38.212Multiplexing and channel coding. Clause 5.2.2 (code block segmentation and CRC attachment), 5.3.2 (LDPC coding), 5.4.2.1 (rate matching, the circular buffer, N_cb, LBRM and Table 5.4.2.1-2 giving the RV starting positions), 6.2.2 and 7.2.2 (LDPC base graph selection), 7.3.1.1 and 7.3.1.2 (DCI formats 0_x and 1_x field definitions, including NDI, RV, HARQ process number, DAI, CBGTI and CBGFI).
  • 3GPP TS 38.213Physical layer procedures for control. Clause 9.1.2 (Type-1 semi-static codebook), 9.1.3 (Type-2 dynamic codebook and the DAI), 9.1.4 (Type-3 one-shot, Rel-16), 9.2.3 (PUCCH resource and the DCI 1_0 K1 table), 9.2.5 (multiplexing HARQ-ACK on PUSCH).
  • 3GPP TS 38.214Physical layer procedures for data. Clause 5.1.2 (PDSCH time-domain allocation and K0), 5.1.3 (modulation order, target code rate and the transport block size determination), Table 5.1.2.1-2 (RV sequence for pdsch-AggregationFactor), 5.1.7 (CBG-based transmission), 5.3 (UE PDSCH processing procedure time, N1), 6.1.2 (PUSCH time-domain allocation and K2), Table 6.1.2.1-2 (RV sequence for pusch-AggregationFactor), 6.4 (UE PUSCH preparation time, N2).
  • 3GPP TS 38.331RRC protocol specification. PDSCH-ServingCellConfig, PDSCH-CodeBlockGroupTransmission, PUSCH-ServingCellConfig, PhysicalCellGroupConfig, PUCCH-Config (dl-DataToUL-ACK), PDSCH-TimeDomainResourceAllocation, PUSCH-TimeDomainResourceAllocation, DRX-Config, SPS-Config, ConfiguredGrantConfig.
  • 3GPP TS 38.322RLC protocol specification, for the ARQ layer that catches what HARQ misses: maxRetxThreshold, t-PollRetransmit, t-Reassembly and the STATUS PDU.
  • 3GPP TS 38.300NR overall description. Clause 5.4 and 6.2 for where HARQ sits in the protocol stack and its relationship with RLC.

Companion documents in this set

  • 02 Radio Frame Structure — slots, symbols and numerology, which every K0/K1/K2 offset counts in.
  • 03 Random Access — MSG3 and its use of HARQ process 0.
  • 04 Timing AdvancetimeAlignmentTimer expiry flushes every HARQ buffer, and the NTN mechanisms in §12 share its NTN-Config.
  • 06 Channel Mapping — how DL-SCH and UL-SCH transport blocks relate to PDSCH and PUSCH.
  • 07 MAC PDU and Control Elements — what is inside the transport block HARQ is protecting.
  • 08 Scheduling — DCI formats, the TDRA tables that supply K0 and K2, SPS and configured grants, MCS tables, link adaptation and the pre-emption indication that makes CBG worthwhile.
  • 09 LCP — how the contents of a new uplink transport block are chosen once an NDI toggle frees the process.
  • 11 DRX — the full Active Time rules that §13's two timers plug into.
  • 16 RLM and RLF — where RLC's maxRetxThreshold failure ends up.
  • 26 UE Capability — processing capability 2, soft buffer size, and which of the Rel-16/17 features in §18 the UE actually supports.