聚焦 3GPP TS 38.213 Section 9.1/9.2,深度解析 Type-1 半静态码本与 Type-2 动态码本的构造机制、DAI 计数器原理、K1 时序控制,以及增强型 Type-2 (Type-3) 码本在 R16/R17 中的演进。
在5G NR中,下行数据传输(PDSCH)采用异步HARQ机制——UE在接收到PDSCH后,需要在指定的上行时隙通过PUCCH(或PUSCH捎带)向gNB反馈ACK/NACK。当UE配置了载波聚合(CA)或多时隙调度时,一个PUCCH资源可能需要承载多个PDSCH对应的HARQ-ACK反馈。
3GPP TS 38.213 Section 9 定义了一套码本(Codebook)构造规则,用于将多个HARQ-ACK比特按照固定或动态的方式组织成一个有序比特序列,使gNB能准确解析出每个PDSCH对应的反馈结果。
核心设计目标有三个:
需要UE进行HARQ-ACK反馈的三类下行传输:
| 触发源 | 说明 | RRC参数/DCI字段 |
|---|---|---|
| 动态PDSCH | DCI Format 1_0/1_1调度的PDSCH | DCI中的HARQ Process Number |
| SPS PDSCH释放 | DCI指示释放SPS配置 | DCI Format 1_0/1_1中NDI=0的特殊组合 |
| SPS PDSCH传输 | 半持续调度周期性PDSCH | sps-Config配置的周期 |
关键定时参数K1(PDSCH-to-HARQ_feedback timing indicator):DCI中的一个字段,指示PDSCH所在下行时隙到HARQ-ACK反馈上行时隙的偏移量(以slot为单位)。K1的具体取值集合由RRC参数dl-DataToUL-ACK(或dl-DataToUL-ACK-r16)配置,最多8个值,DCI中通过3-bit索引从中选择一个。
flowchart TD
A[UE接收PDSCH/DCI] --> B{码本类型?}
B -->|pdsch-HARQ-ACK-Codebook = semi-static| C[Type-1 半静态码本]
B -->|pdsch-HARQ-ACK-Codebook = dynamic| D[Type-2 动态码本]
C --> C1[确定反馈窗口: K1集合+候选PDSCH时机]
C1 --> C2[为每个候选位置生成HARQ-ACK比特]
C2 --> C3[未调度位置填NACK]
C3 --> C4[按固定顺序拼接成码本]
D --> D1[基于DAI计数器跟踪调度]
D1 --> D2[确定实际调度的PDSCH集合]
D2 --> D3[仅对实际调度的PDSCH生成反馈]
D3 --> D4[按C-DAI/T-DAI排序生成码本]
C4 --> E[映射到PUCCH资源传输]
D4 --> E
E --> F[gNB解析码本获取每个TB的ACK/NACK]
Type-1码本由RRC参数 pdsch-HARQ-ACK-Codebook = semi-static 激活,定义在TS 38.213 Section 9.1。
核心特征:码本大小半静态固定,仅取决于RRC配置参数和时隙结构,与实际调度情况无关。
对于每个服务小区 $c$,在每个下行时隙 $n$,UE需要确定可能的PDSCH候选接收时机。这取决于以下RRC参数:
dl-DataToUL-ACK:K1取值集合,如 {1, 2, 3, 4, 6, 8}pdsch-Config中的pdsch-TimeDomainAllocationList定义,确定每个时隙内可能的PDSCH起始符号和长度组合(SLIV)对于目标上行时隙 $n_{UL}$,所有满足 $n_{DL} = n_{UL} - K1$ 的下行时隙中的所有候选PDSCH位置,构成反馈窗口。
Type-1码本的遍历顺序严格固定:
for each serving cell c (按ServCellIndex升序):
for each slot n in feedback window (按时隙升序):
for each PDSCH candidate in slot n (按SLIV起始符号升序):
for each TB (1或2个, 取决于码字数):
分配1个HARQ-ACK比特位
| 候选位置状态 | 比特值 |
|---|---|
| 实际接收到PDSCH并正确解码 | ACK (1) |
| 实际接收到PDSCH但解码失败 | NACK (0) |
| 未调度(候选位置无实际PDSCH) | NACK (0) |
| SPS PDSCH释放指示 | ACK (1) |
关键设计意图:未调度的候选位置用NACK填充——gNB知道这些位置未调度,因此会忽略对应的NACK值。但码本大小保持固定,确保了gNB和UE对码本结构的完全一致理解。
sequenceDiagram
participant gNB
participant UE
Note over gNB,UE: RRC配置: K1={2,4}, 2个服务小区CC0/CC1
rect rgb(230, 245, 255)
Note over gNB,UE: 时隙n: gNB在CC0和CC1各调度1个PDSCH
gNB->>UE: DCI(CCO) K1=4
gNB->>UE: PDSCH(CCO) 时隙n
gNB->>UE: DCI(CC1) K1=4
gNB->>UE: PDSCH(CC1) 时隙n
end
rect rgb(255, 240, 230)
Note over gNB,UE: 时隙n+1: gNB仅在CC0调度PDSCH
gNB->>UE: DCI(CCO) K1=2
gNB->>UE: PDSCH(CCO) 时隙n+1
Note over UE: CC1时隙n+1无调度
end
rect rgb(230, 255, 230)
Note over gNB,UE: 时隙n+4: UE构造Type-1码本
Note over UE: 反馈窗口: 时隙n(K1=4) + 时隙n+2(K1=2)
Note over UE: 码本遍历: [CC0/时隙n, CC1/时隙n, CC0/时隙n+2, CC1/时隙n+2]
UE->>gNB: PUCCH: [ACK, ACK, ACK, NACK(占位)]
Note over gNB: 第4个NACK为CC1时隙n+2的占位,gNB忽略
end
设 $N_c$ 为服务小区数,$M$ 为反馈窗口内的下行时隙数(所有K1值对应的下行时隙总数),$P$ 为每个时隙内的最大候选PDSCH数(由时域分配表确定),$TB$ 为每PDSCH的传输块数(1或2),则:
$$Codebook_Size = N_c \times M \times P \times TB$$
开销分析:当调度稀疏时(如仅调度了4个PDSCH,但候选位置有20个),Type-1码本中80%的比特为无效占位。这正是Type-2码本被引入的核心原因。
Type-2码本由RRC参数 pdsch-HARQ-ACK-Codebook = dynamic 激活,定义在TS 38.213 Section 9.2。
核心特征:码本大小动态变化,仅包含实际被调度的PDSCH的HARQ-ACK反馈,通过DCI中的DAI(Downlink Assignment Index)计数器实现对调度数量的精确跟踪。
DAI是Type-2码本的核心,分为两种:
| DAI类型 | DCI字段 | 作用 | 比特数 |
|---|---|---|---|
| C-DAI(Counter DAI) | Counter DAI for HARQ-ACK |
累计计数当前已调度的PDSCH数量(按小区和时隙) | 2 bit(DCI 1_0)或4 bit(DCI 1_1) |
| T-DAI(Total DAI) | Total DAI for HARQ-ACK(仅DCI 1_1) |
指示当前HARQ-ACK反馈窗口内预期的PDSCH总数 | 4 bit |
C-DAI在DCI Format 1_1中为4-bit字段(0-15),计数规则遵循"先小区内、后跨时隙"的累加逻辑:
C-DAI = (当前服务小区当前时隙之前的所有服务小区的所有时隙中的PDSCH计数)
+ 当前服务小区当前时隙中的PDSCH序号
具体而言(TS 38.213 Section 9.2.3):
T-DAI仅在DCI Format 1_1中存在(4-bit),其值为gNB在该反馈窗口内实际调度的PDSCH总数(模16)。
T-DAI解决的核心问题:当UE漏检了最后一个DCI时,仅凭C-DAI无法确定码本大小。T-DAI通过"总数通告"机制让UE即使在漏检情况下也能从其他DCI中获取总调度数。
sequenceDiagram
participant gNB
participant UE
Note over gNB,UE: 配置: Type-2动态码本, 3个CC, K1=4
rect rgb(240, 240, 255)
Note over gNB,UE: 时隙n: gNB在CC0调度2个PDSCH, CC1调度1个
gNB->>UE: DCI(CC0,PDSCH#1) C-DAI=1, T-DAI=5
gNB->>UE: PDSCH(CC0,#1)
gNB->>UE: DCI(CC0,PDSCH#2) C-DAI=2, T-DAI=5
gNB->>UE: PDSCH(CC0,#2)
gNB->>UE: DCI(CC1,PDSCH#1) C-DAI=3, T-DAI=5
gNB->>UE: PDSCH(CC1,#1)
Note over UE: UE漏检CC2的DCI!
end
rect rgb(255, 255, 240)
Note over gNB,UE: 时隙n+1: gNB在CC2调度1个PDSCH
gNB->>UE: DCI(CC2,PDSCH#1) C-DAI=5, T-DAI=5
gNB->>UE: PDSCH(CC2,#1)
Note over UE: UE检测到C-DAI=5但之前仅收到1,2,3
end
rect rgb(240, 255, 240)
Note over gNB,UE: 时隙n+4: UE构造Type-2码本
Note over UE: 最大T-DAI = 5 → 码本大小=5
Note over UE: 已知位置: C-DAI=1→CC0#1, C-DAI=2→CC0#2, C-DAI=3→CC1#1
Note over UE: 缺失位置: C-DAI=4(漏检), C-DAI=5→CC2#1
UE->>gNB: PUCCH: [ACK, ACK, ACK, NACK(漏检占位), ACK]
Note over gNB: 第4个NACK表明UE漏检了C-DAI=4的DCI
end
UE在构造Type-2码本时的关键步骤(TS 38.213 Section 9.2.5):
漏检检测的精妙设计:
场景: gNB调度了5个PDSCH, UE仅收到C-DAI=1,2,3,5
结果: UE发现C-DAI=4缺失 → 该位置填NACK
gNB解析: 收到[NACK]在位置4 → 知道UE漏检了第4个DCI → 触发重传
这正是DAI机制的设计精髓:用隐式计数器实现DCI漏检的自动检测。
stateDiagram-v2
[*] --> 空闲: 初始状态
空闲 --> 计数中: 收到DCI(C-DAI=1)
计数中 --> 计数中: 收到DCI(C-DAI递增)
计数中 --> 漏检检测: C-DAI不连续
漏检检测 --> 计数中: 继续处理后续DCI\n缺失位填NACK
计数中 --> 码本生成: 所有时隙处理完毕\n使用T-DAI确定大小
漏检检测 --> 码本生成: 所有时隙处理完毕\n缺失位填NACK
码本生成 --> [*]: 在PUCCH上发送码本
Note right of 漏检检测: C-DAI跳跃表示\n中间有DCI被漏检
Note right of 码本生成: T-DAI=码本大小\n确保对齐
| 对比维度 | Type-1 半静态码本 | Type-2 动态码本 |
|---|---|---|
| TS 38.213章节 | Section 9.1 | Section 9.2 |
| RRC配置参数 | pdsch-HARQ-ACK-Codebook = semi-static |
pdsch-HARQ-ACK-Codebook = dynamic |
| 码本大小 | 固定(由RRC参数决定) | 动态(由DAI决定) |
| DCI字段依赖 | 不依赖DAI | 强依赖C-DAI和T-DAI |
| DCI漏检处理 | 无检测机制(全部填NACK) | DAI不连续自动检测漏检 |
| 典型码本大小 | 较大(含未调度占位) | 较小(仅含实际调度) |
| 上行开销 | 较高 | 较低 |
| gNB解析复杂度 | 低(固定映射) | 中(需匹配DAI序列) |
| 适用场景 | 低频调度、单小区、eMBB | 高频调度、CA、TDD |
| 可靠性 | 高(无DAI歧义) | 中(依赖DCI正确接收) |
| Release | Rel-15引入 | Rel-15引入, R16增强 |
3GPP Release 16引入了Type-3 HARQ-ACK码本(TS 38.213 Section 9.3),专为多TRP/多波束场景设计:
HARQ-ACK request字段或MAC CE激活Release 16对Type-2码本的关键增强:
| 增强特性 | 说明 | TS章节 |
|---|---|---|
| 基于CBG的HARQ-ACK反馈 | 每个CBG独立反馈ACK/NACK,而非整个TB | 38.213 Section 9.2.6 |
| 多PDSCH调度 | 单个DCI调度多个PDSCH时DAI的计数规则 | 38.213 Section 9.2.3 |
| 多TRP DAI处理 | 两个TRP独立维护DAI计数器 | 38.213 Section 9.2.3.1 |
| Sub-slot PUCCH | 支持小于1个时隙的PUCCH反馈粒度 | 38.213 Section 9.2.5 |
当配置了codeBlockGroupTransmission时,一个TB被分割为多个CBG(Code Block Group),UE需要对每个CBG独立反馈:
这在URLLC等需要精细重传控制的场景中尤为关键——仅重传失败的CBG而非整个TB,显著降低了重传开销和时延。
K1的配置位于PUCCH-Config中的dl-DataToUL-ACK(最多8个值),DCI Format 1_0/1_1通过3-bit的PDSCH-to-HARQ_feedback timing indicator字段从中选择一个:
| DCI字段值 | 选择的K1值 |
|---|---|
| 000 | dl-DataToUL-ACK[0] |
| 001 | dl-DataToUL-ACK[1] |
| ... | ... |
| 111 | dl-DataToUL-ACK[7] |
假设配置: - K1集合 = {2, 3, 4, 7} - 目标PUCCH时隙 = 时隙10 - TDD配置: DSUUD(下行D/特殊S/上行U/上行U/下行D)
K1=2 → 时隙10-2=时隙8(D) → 包含候选PDSCH
K1=3 → 时隙10-3=时隙7(U) → 无下行,排除
K1=4 → 时隙10-4=时隙6(D) → 包含候选PDSCH
K1=7 → 时隙10-7=时隙3(D) → 包含候选PDSCH
有效反馈窗口 = {时隙3, 时隙6, 时隙8}
设计意图:K1集合的灵活配置允许gNB根据当前负载和TDD配置选择最佳反馈时机——小K1值用于低时延场景(URLLC),大K1值用于gNB调度灵活性更高的eMBB场景。
在Wireshark/TShark中分析HARQ-ACK码本的关键过滤表达式:
# 过滤DCI Format 1_1中的DAI字段
ngap || nas-5gs || mac-nr || rrc-nr.dci
# 重点关注以下字段:
# - DCI中的 Counter DAI for HARQ-ACK (2或4 bits)
# - DCI中的 Total DAI for HARQ-ACK (4 bits)
# - DCI中的 PDSCH-to-HARQ_feedback timing indicator (3 bits)
# - PUCCH Format 1/2/3/4 中的HARQ-ACK payload大小
| 故障现象 | 可能原因 | 排查思路 |
|---|---|---|
| gNB收到大量NACK但PDSCH BLER正常 | Type-1码本占位NACK被误读为实际NACK | 检查码本类型配置,确认gNB是否正确忽略占位NACK |
| gNB反馈"unexpected HARQ-ACK payload size" | UE和gNB对码本大小理解不一致 | 核查K1集合、时域分配表、DAI值是否对齐 |
| UE漏检DCI后码本错位 | DAI回绕处理不正确(模16边界) | 检查是否在DAI=15→0回绕时丢失计数 |
| CA场景码本解析错误 | C-DAI跨小区计数顺序不一致 | 确认ServCellIndex顺序和DCI接收顺序 |
| PUCCH资源不足导致码本丢弃 | 码本大小超过PUCCH承载能力 | 检查PUCCH Format选择和UCI码率是否越限 |
| ## 十一、PUCCH Format与码本承载能力 |
| PUCCH Format | 比特容量 | 适用码本类型 | 调制方式 | 备注 |
|---|---|---|---|---|
| Format 0 | ≤2 bit | 1-2个ACK/NACK | BPSK/QPSK | 无DMRS,低开销 |
| Format 1 | ≤2 bit | 1-2个ACK/NACK | BPSK/QPSK | 序列+循环移位 |
| Format 2 | >2 bit | 中等码本 | QPSK | DMRS密度高 |
| Format 3 | >2 bit | 大码本 | QPSK/16QAM | 支持PI/2 BPSK |
| Format 4 | >2 bit | 中等码本(1RB) | QPSK | 仅1个PRB |
PUCCH Format选择逻辑:UE根据码本大小和RRC配置的PUCCH资源集合,自动选择合适的Format。当码本大小超过Format 2/3的承载能力时,UE会触发HARQ-ACK绑定(Spatial Bundling)或报告错误。
| RRC参数 | 所属IE | 作用 | 取值范围 |
|---|---|---|---|
pdsch-HARQ-ACK-Codebook |
PUCCH-Config | 选择码本类型 | semi-static / dynamic |
dl-DataToUL-ACK |
PUCCH-Config | K1取值集合(最多8个) | 1-15 |
maxNrofPDSCH-ToUL-ACK |
PUCCH-Config | K1集合最大元素数 | 1-8 |
pdsch-TimeDomainAllocationList |
PDSCH-Config | 时域候选PDSCH位置 | 可配置多行SLIV |
codeBlockGroupTransmission |
PDSCH-Config | CBG级反馈开关 | enable/disable |
maxCodeBlockGroupsPerTransportBlock |
PDSCH-Config | 每TB最大CBG数 | 2/4/6/8 |
nrofHARQ-Processes |
PDSCH-Config | HARQ进程数 | 1-16 |
Q1: Type-1码本中,未调度的PDSCH候选位置为什么填NACK而不是ACK?
A: 填NACK是安全设计选择。如果填ACK,一旦gNB和UE对候选位置的认定不一致(如时域分配表版本不同步),gNB可能误将ACK解读为某个实际调度的PDSCH被正确接收,从而不触发重传,导致数据丢失。NACK虽然可能触发不必要的重传,但不会导致数据丢失,符合通信系统"宁可重传不可丢包"的设计原则。
Q2: DAI只有2-bit(DCI 1_0)时如何处理超过4个PDSCH的调度?
A: DCI Format 1_0中C-DAI仅2-bit(模4计数),这限制了其在CA或多时隙场景下的能力。当调度数超过4个时,DAI会回绕(3→0),UE需要通过T-DAI(仅DCI 1_1有4-bit)来辅助判断。这也是为什么在高负载CA场景下推荐使用DCI Format 1_1和Type-2码本。
Q3: gNB如何区分Type-1码本中的"占位NACK"和"实际解码失败的NACK"?
A: gNB完全知道自己在哪些候选位置调度了PDSCH。解析码本时,gNB按照与UE相同的遍历顺序,仅关注有实际调度的位置的HARQ-ACK值,跳过未调度位置的NACK。这是一种"发送端知情"的设计——gNB利用自身的调度记录来过滤无效反馈。
Q4: R16引入的Type-3码本与Type-2有何本质区别?
A: Type-3码本的核心区别在于它不依赖时隙级的K1映射和DAI计数器,而是直接按HARQ进程号反馈所有活跃进程的状态。这相当于一次全量快照,适用于TRP切换或波束失败恢复后需要重新同步HARQ状态的场景。代价是码本大小可能较大(最多16个HARQ进程 × 每进程的CBG数)。
Q5: 在TDD网络中,Type-2码本是否一定优于Type-1?
A: 不一定。TDD网络中下行时隙比例高,反馈窗口内候选PDSCH数多,Type-1的开销确实更大。但Type-2依赖DCI的正确接收——在恶劣信道条件下,如果UE频繁漏检DCI,DAI的不连续会导致码本构造错误,反而可能降低系统吞吐量。实际部署中需要根据PDCCH BLER和调度密度综合选择,部分厂商采用自适应切换策略。
本文由「51学通信」技术团队出品。51学通信由通信行业18年老兵爱卫生(微信ID: gprshome201101)维护,聚焦5G/6G核心网、3GPP标准解读、通信前沿技术深度分析。 出版作品有《5G核心网原理与实践》《IMS原理与实践》等4本通信专业书籍。知识星球「51学通信」提供深度技术答疑和行业洞察。
[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。
