简介:一份以图形化方式讲解5G NR下行数据传输流程的PDF资料,源自“5G NR in BULLETS”系列,面向5G技术入门者、网络工程师及通信专业学生,帮助读者从协议栈视角看清数据包从应用层到物理层的完整旅程。资源以CU-DU分离架构下的用户平面协议栈为起点,通过Figure 212、Figure 213、Figure 214三张示意图,依次拆解应用层HTTP GET请求、TCP头部(源/目的端口、序列号、确认号、窗口大小、校验和)与IP头部(源/目的IP地址、DSCP、ECN、协议号)的封装细节,并串联起下行数据经SDAP、PDCP、RLC、MAC到物理层无线传输的逐层处理逻辑。全包仅1个PDF文件,大小约874KB,图文结合、要点密集,适合碎片化学习。目前已超270人学习浏览,对希望直观理解5G下行用户面协议栈与TCP/IP封装关系的读者而言,是一份轻量而清晰的图解参考。
1. 5G下行数据传输流程的“图形化”到底在画什么
不少工程师第一次接触5G下行数据流程,习惯先翻协议栈图,但38.300里那张层间结构图是给协议实现者看的,不是给业务感知用的。下行数据从UPF进gNB到UE的App里点亮一个视频帧,中间经历的封装、调度、HARQ、调制映射每一步都有很强的时序和资源特征,纯文字或者纯分层框图很难建立起“数据到底怎么一步步到终端”的空间感。图形化的价值在于把协议栈的纵向层次映射成横向的时间轴,把传输块(TB)在物理资源块(PRB)上的映射画成网格。这篇内容就围绕“画出能解释清楚5G下行全流程的图”展开,覆盖从SDAP到PHY的数据面路径、MATLAB与Matplotlib两种绘图方案、时延和HARQ重传的可视化标注,以及最终拿真实抓包数据校验图像正确性的方法。适合需要做技术分享、写排障文档,或者给新人做5G下行数据流培训的人。
2. 5G下行数据传输流程的分层模型与图形化关键要素
2.1 从UPF到UE:数据面每一跳到底做了什么
5G下行数据传输流程的起点是UPF收到来自DN(数据网络)的IP包,终点是UE的应用层。中间的gNB和UE协议栈是图形化要表达的主体。按功能划分,数据面从上到下依次是SDAP、PDCP、RLC、MAC、PHY,每一层对数据做的处理各不相同:SDAP把QoS流映射到DRB,PDCP做头压缩、加密和序列号添加,RLC根据模式做分段或级联,MAC组装MAC PDU并做调度决策,PHY则负责速率匹配、加扰、调制和天线映射。画图的时候,最容易让读者混淆的是“IP包只有一个,但到MAC层被拆成了多个TB”。因此图形化的首要任务就是绘制一个IP包经过逐层封装后如何变成一个或多个TB的过程。
2.2 图形化中的核心对象:QoS流、DRB、TB和HARQ进程
按下行数据流程中承载关系来分,图形上至少要有四个对象:QoS流、DRB、逻辑信道、传输块。QoS流是5G核心网引入的抽象,每个QoS流带一个QFI(QoS Flow Identifier),SDAP根据QFI把它映射到某个DRB上。在图上,画成一条从UPF拉进gNB SDAP层的带箭头线,并在旁边标注QFI值。DRB是空口承载,一个UE可以配置多个DRB,图形上用不同颜色区分。逻辑信道在MAC层与DRB对应,但属于不同协议层,绘制时放在MAC子层顶部。真正值得细画的是传输块。DL-SCH每传输时间间隔(TTI)最多产生一个TB,而一个TB在HARQ上对应一个进程ID,图形化时用带编号的方块串在时间轴上,一次下行调度就推进一个编号。
2.3 用表格锁定图形化中每个流程点的关键参数
绘图之前,建议先建一张参数表,把图形上要标注的信息固定下来。这张表的作用是保证图里出现的内容都有协议依据,不会画出凭空的“数据包”。
| 流程阶段 | 协议层 | 图形化表达方式 | 关键参数 | | --- | --- | --- | --- | | QoS流映射 | SDAP | 带箭头的横向管道 | QFI → DRB ID | | 头压缩与加密 | PDCP | 方块+尾部附加 | 序列号长度(12/18 bit) | | 分段与级联 | RLC | 长条被切开 | SDU长度、分段偏移 | | 逻辑信道优先级 | MAC | 多个流并排汇入一个集合 | LCG ID、优先比特率 | | 下行调度 | MAC/PHY | 资源网格上着色 | RB数、MCS、时隙偏移 | | HARQ进程 | MAC | 轮转编号块 | 进程数(8/16) | | 调制与层映射 | PHY | 星座点与层数标注 | QPSK/16QAM/64QAM/256QAM、层数 |参数在图上不能只写英文缩略词,要附一个具体示例值,比如MCS=20对应256QAM加约0.7的码率,这样看图的人能直接对照CQI表反推信道质量。图形化不是把协议栈重画一遍,而是把“这一段发生了什么、影响了什么参数”用视觉语言讲出来。
2.4 个人画下行流程图的习惯方案
我一般会先用一张“横向泳道图”做全局,泳道从上到下依次是UPF、gNB用户面协议栈、空口、UE协议栈,横向是时间轴。数据包从UPF出发后,在gNB栈内逐层向下,每过一层就画一个状态变化点。这个图适合开局展示。第二张图拉近到MAC层和PHY层的交互,用资源网格展示调度结果:时隙横轴、PRB纵轴,一个TB对应的PRB集合被标成一个连续色块,旁边标注MCS和功率信息。这样看的人就能把“调度”这个概念和物理资源占用对应起来。
3. 用Matplotlib把5G下行数据传输流程画成动态时序图
3.1 为什么选择Python绘图而不是Visio
Visio画静态框图很快,但5G下行数据传输流程里最不好画的是“时序关系”,例如gNB在slot n下发PDSCH,UE在slot n+K1反馈HARQ-ACK,重传发生在slot n+K2。这类时间偏移关系在静态框图上难以表达,而Python的Matplotlib可以精确控制每个元素的位置和颜色,还能输出GIF动图。对5G工程师来说,用Python脚本控制图形的另一个好处是参数可复用:把MCS、RB数、时隙编号定义为变量,下次用真实链路参数时直接改配置就能重新出图。
3.2 最小可运行脚本:绘制下行链路逐层封装
下面的脚本绘制一条下行数据从PDCP层进入MAC层、然后映射到PDSCH资源的过程。为了照顾可读性,脚本里用矩形表示处理节点,用带箭头的线表示数据流向。
import matplotlib.pyplot as plt import matplotlib.patches as mpatches from matplotlib.patches import FancyArrowPatch fig, ax = plt.subplots(figsize=(12, 6)) ax.set_xlim(0, 10) ax.set_ylim(0, 6) ax.axis('off') # 节点坐标与宽度 nodes = { "UPF": (0.5, 4.5), "SDAP": (2.0, 4.5), "PDCP": (3.5, 4.5), "RLC": (5.0, 4.5), "MAC": (6.5, 4.5), "PHY": (8.0, 4.5), } width, height = 1.2, 0.8 # 绘制协议层节点 for name, (x, y) in nodes.items(): rect = mpatches.FancyBboxPatch( (x, y), width, height, boxstyle="round,pad=0.1", edgecolor="black", facecolor="#dbe9f6" ) ax.add_patch(rect) ax.text(x + width/2, y + height/2, name, ha="center", va="center", fontsize=12) # 绘制数据流:UPF -> SDAP -> PDCP -> RLC -> MAC -> PHY flow_order = ["UPF", "SDAP", "PDCP", "RLC", "MAC", "PHY"] for idx in range(len(flow_order) - 1): start = nodes[flow_order[idx]] end = nodes[flow_order[idx + 1]] arrow = FancyArrowPatch( (start[0] + width, start[1] + height/2), (end[0], end[1] + height/2), arrowstyle="-|>", mutation_scale=20, linewidth=2 ) ax.add_patch(arrow) # 在MAC层下方标注传输块生成 tb_rect = mpatches.FancyBboxPatch( (6.5, 2.0), 2.0, 0.8, boxstyle="round,pad=0.1", edgecolor="red", facecolor="#ffe4e1" ) ax.add_patch(tb_rect) ax.text(7.5, 2.4, "TB 生成", ha="center", va="center", color="red", fontsize=12) ax.text(5.0, 0.5, "下行数据流程:IP包 -> TB映射", ha="center", fontsize=14) plt.tight_layout() plt.savefig("dl_flow_overview.png", dpi=150) plt.show()这段代码把协议栈节点画成圆角矩形,通过横向箭头连接相邻层,并在MAC层下方额外画了一个“TB生成”标注。逻辑上,IP包从UPF往下传,每经过一层就增加对应协议头,但为了视觉简洁,管线里没有展开每个头的长度。如果想体现PDCP头、RLC头的占位效果,可以在两个节点之间画一个小矩形条,高度固定、宽度与真实头长度成正比,这是让画面更接近协议细节的常用做法。
3.3 把传输块到资源块的映射画成网格
传输块在物理层要占用PDSCH资源,图形上用时隙-频域资源网格表示最形象。
import numpy as np import matplotlib.pyplot as plt # 模拟一个时隙内14个OFDM符号 x 24个PRB的资源网格 n_symbols = 14 n_prbs = 24 grid = np.zeros((n_prbs, n_symbols)) # 假设TB占用符号0-10、PRB 4-20 grid[4:21, 0:11] = 1 fig, ax = plt.subplots(figsize=(12, 5)) ax.imshow(grid, aspect="auto", cmap="Blues", interpolation="nearest") # 标注DMRS位置(符号2和11,PRB每6个一个) for sym in [2, 11]: for prb in range(0, n_prbs, 6): ax.plot(sym, prb, marker="s", color="red", markersize=6) ax.set_xticks(range(n_symbols)) ax.set_xticklabels([f"#{i}" for i in range(n_symbols)]) ax.set_xlabel("OFDM符号索引") ax.set_yticks(range(n_prbs)) ax.set_yticklabels([f"PRB {i}" for i in range(n_prbs)]) ax.set_title("PDSCH资源网格:TB占用区域与DMRS位置") plt.tight_layout() plt.savefig("pdsch_grid.png", dpi=150) plt.show()grid用二维数组模拟资源网格,“1”表示该RE被PDSCH占用。DMRS位置被单独标红,这是因为它虽然是物理信号但不是业务数据,在图上颜色区分后,读者能清楚地看到“数据打在有导频的符号周围”这一事实。这个脚本直接对应协议里的时频资源概念:横轴是时间(OFDM符号),纵轴是频率(PRB),一个TB落在一块连续区域内。
3.4 参数调整建议:MCS与资源块数量的联动显示
图像上如果只画网格而不标MCS,读者仍看不出速率差异。建议在图上叠加一个文本框,显示MCS、调制阶数和编码速率的关系:
mcs = 20 modulation_order = 6 # 64QAM code_rate = 0.7 rb_count = 17 total_bits = rb_count * 12 * 11 * modulation_order * code_rate text_str = f"MCS={mcs} | {2**modulation_order}QAM | R={code_rate}\n" \ f"RB数={rb_count} | 近似TB大小={int(total_bits)} bits" ax.text(0.02, 0.95, text_str, transform=ax.transAxes, verticalalignment="top", fontsize=10, bbox=dict(boxstyle="round", facecolor="white", alpha=0.8))这段文本能帮你快速验证图上画的资源块是否够装下传输块。常见错误是图上画的RB数对应的比特数和TB size不匹配,比如MCS=28却只分配了4个RB,按协议查表实际根本放不下。画图时把这个校验做进去,图就同时具备自查能力。
4. 进阶图形化:下行链路时延标注与HARQ可视化
4.1 三个必须标注的时间点:gNB处理、空口传播、UE处理
图形化5G下行数据传输流程,不能只画数据流向,时延是另一个核心维度。下行用户面时延从gNB侧数据到达MAC层开始算,到UE侧MAC层收到TB为止,其中包含gNB调度等待、PHY编码、空口传输、UE PHY解码。画时序图时常用三段式标注:gNB侧处理标注为T1,空口传输标注为T2,UE侧处理标注为T3。T1典型值在1到2毫秒量级,取决于调度器排队情况;T2由子载波间隔决定,15kHz对应1毫秒时隙,30kHz对应0.5毫秒;T3与UE解调能力相关,一般比T1略小。图上用三条不同颜色的水平条并列放在基站和UE泳道之间,长度与时延成正比,格式上推荐画成堆叠条形图。
4.2 HARQ进程轮转可视化方案
HARQ是下行数据流程中最难用静态图表达的部分。每个HARQ进程有一个ID,进程在收到ACK之前不能复用,但gNB可以并行操作多个进程。用Matplotlib可以按时间轴绘制进程占用状态:横轴是slot编号,纵轴是进程ID,每个格子上色表示该进程当前承载了一个TB,颜色深浅表示状态(浅灰:等待反馈,绿色:ACK接收,红色:NACK并重传)。
import numpy as np import matplotlib.pyplot as plt import matplotlib.colors as mcolors n_slots = 16 n_processes = 8 status_matrix = np.zeros((n_processes, n_slots)) # 状态编码: 0=空闲, 1=传输待ACK, 2=重传, 3=ACK完成 for slot in range(n_slots): process_id = slot % n_processes status_matrix[process_id, slot] = 1 if slot > 0 and status_matrix[process_id, slot-1] == 1: status_matrix[process_id, slot] = 1 # 人为制造一次NACK重传 status_matrix[2, 6] = 2 status_matrix[2, 7] = 2 status_matrix[2, 8] = 3 cmap = mcolors.ListedColormap(["#ffffff", "#73b3e3", "#e37b73", "#8bc47f"]) fig, ax = plt.subplots(figsize=(14, 4)) ax.imshow(status_matrix, aspect="auto", cmap=cmap, interpolation="nearest") ax.set_yticks(range(n_processes)) ax.set_yticklabels([f"HP ID {i}" for i in range(n_processes)]) ax.set_xticks(range(n_slots)) ax.set_xticklabels([f"slot {i}" for i in range(n_slots)]) ax.set_xlabel("时间轴") ax.set_title("HARQ进程占用与重传可视化") plt.tight_layout() plt.savefig("harq_timeline.png", dpi=150) plt.show()这个图配合文字说明:HARQ进程8个一轮,每slot调度一个进程,如果某次传输失败,在图上对应位置从浅蓝变红,下一次调度同一进程时若为重传则持续红色,直到反馈ACK变绿。这个表达和《5G/NR标准》中HARQ RTT的概念一致,是技术分享时最容易引起共鸣的信息点。
4.3 gNB侧时序的绘制方式:用“发号”顺序体现NDI翻转
下行调度里还有一层微妙信息:NDI(新数据指示符)。每个HARQ进程配一个NDI,gNB用NDI翻转通知UE“这是新数据”还是“这是重传”。图形化时,需要在每个TB块旁标注NDI的bit值。第一次传进程3时NDI=0,重传时NDI保持不变,UE通过比较前后两次调度的NDI是否有翻转来判断是否为新数据。这个细节画出来能解释很多UE日志分析中的困惑,因为很多新人在抓取log时看到同一进程被连续调度就以为是重传,实际要看NDI。
# 在下行调度图上标注NDI翻转 tb_labels = [ (0, 3, "HP3 NDI=0"), (1, 5, "HP5 NDI=0"), (2, 3, "HP3 NDI=0(重传)"), (3, 3, "HP3 NDI=1(新数据)"), ] for slot, process, label in tb_labels: ax.text(slot, process, label, ha="center", va="center", fontsize=8, color="black")脚本里这段逻辑是直接把NDI标注嵌入前面画好的网格图上,读图的人一眼能看到HP3在slot2是重传、slot3变成新数据。这种图的“形象感”来自对比而不是堆叠,所以绘制时要保证同一进程的多次传输在纵向上对齐。
5. 图形化后如何验证画得对:对照协议与实测数据
5.1 用真实抓包数据反推图形参数
图像画完不能只靠视觉判断,最好用实验室或现网抓包数据反推验证。常见做法是用gNB侧Wireshark抓MAC层调度的log,或者用UE侧modem log解析PDSCH assignment。抓到一条DCI后,里面包含的资源分配、MCS、HARQ进程号、NDI标注,都可以直接映射到前面脚本的参数。验证时重点检查三件事:资源分配对应的RB数量是否和图上色块宽度一致;MCS对应调制阶数是否与图上标的一致;HARQ进程号是否在自己设置的时间轮转序列上。
5.2 对照TS 38.214中的MCS表做一致性检查
图形化最容易出现的错误是调制阶数标错。TS 38.214的MCS索引表里,不同MCS对应不同的调制方式和目标码率。画图时建议在脚本里内置一张简化映射表:
mcs_table = { 0: ("QPSK", 0.30), 10: ("16QAM", 0.55), 20: ("64QAM", 0.70), 28: ("256QAM", 0.75), } try: mod, rate = mcs_table[mcs] except KeyError: raise ValueError(f"MCS {mcs} 不在简化表中,请补充协议定义")这样在做资源网格可视化时,如果图上标注的MCS=20而调制阶数写成了4(16QAM),表格查完后会直接报错,从源头上杜绝一致性错误。对做排障场景的图来说,这个校验比画图本身更重要。
5.3 动图输出的建议:帧率不要超过10FPS
如果要把图做成动画,比如展示TB在资源网格上的逐slot移动,Matplotlib的FuncAnimation配合interval=300毫秒是合适的设置。每帧显示一个slot的资源分配,重传发生时会连续几帧红色块不变。动画帧率过高会让观看者忽略NDI翻转的细节,低于5帧每秒又会觉得卡顿。这个场景下动图是辅助理解的手段,不是最终交付物,因此我一般保存为GIF而非视频,方便嵌入PPT和文档。
5G下行数据传输流程的图形化本质上是把抽象协议栈映射到时间和频率两个维度。画图前先建参数表,画图时把HARQ、NDI、MCS这类关键对象做成可变量,画完用MCS表和真实DCI做双向验证,这套方法可以保证每张图都能被人追问细节而不会露怯。
本文还有配套的精品资源,点击获取