资讯动态

5G NR DL-SCH LDPC编码链路的MATLAB仿真实践

发布时间:2026/10/9 4:55:22 来源:尧图企业网站定制
做5G物理层仿真的同学最近应该都在跟LDPC编码打交道。5G NR的数据信道DL-SCH从传输块到物理层比特中间最关键的一环就是LDPC编码。MATLAB 5G Toolbox把DL-SCH这整条处理链封装得非常完整但从官方文档到真正能在自己的仿真工程里跑起来中间还是有不少细节需要抠。这篇就以官方LDPC处理链文档为核心线索聊聊我怎么理解DL-SCH链路、怎么调用工具箱里的编码接口、参数该怎么设置以及实际调试中容易踩的坑。1. 5G LDPC编码和DL-SCH处理链先看整体1.1 DL-SCH在5G数据链路中的角色DL-SCH是下行共享信道负责承载用户业务数据。从高层下来的传输块TB会先进入DL-SCH处理链经历CRC校验、码块分段、LDPC编码、速率匹配后面才交给物理层做调制和资源映射。你可以把它理解成一条流水线MAC层送进来一大包数据物理层需要的是切分好、加了校验、并打上合适长度标记的码字。所以DL-SCH处理链是MAC层和物理层的桥链路级仿真里几乎所有下行数据都要从这条链路过一遍。做仿真时我们通常关注的就是从传输块到码字比特这一段。如果只用官方封装好的对象可能几行代码就完事但你真的遇到问题去调试时还是得把每一段的角色弄清楚。我一开始直接用nrDLSCH跑通了但后来想自定义速率匹配或者看中间结果就把整条链路的每个环节都拆开验了一遍后面讲实操再展开。1.2 LDPC为什么被5G选做数据信道编码LDPC低密度奇偶校验码在5G里取代了LTE时期的Turbo码核心原因很简单LDPC天然支持高并行度的迭代译码吞吐量能拉得很高符合eMBB场景对大流量、低时延的要求。5G标准选定的LDPC是准循环结构QC-LDPC校验矩阵由循环移位矩阵拼接而来硬件实现友好MATLAB仿真也很容易表达。标准里定义了两种基图Base Graph一个叫BG1一个叫BG2。BG1码长更长、支持码率范围宽适合大传输块BG2码长相对短、稀疏度更高在低码率和中小数据块场景下性能更优。5G规范对基图选择有具体规则但如果你用matlab工具箱的nrDLSCH对象基本上不需要自己操心内部会按照标准自动选择BG。真正需要手动指定的是你拆开底层函数调用的场景。1.3 官方文档里的DL-SCH LDPC处理链MathWorks的文档页面“LDPC Processing Chain for DL-SCH”实际上是一个引导页它把5G Toolbox里DL-SCH编码例程的处理流程拆开讲主线是传输块CRC附加、码块分段每个码块再加CRC、LDPC编码、速率匹配最后码块级联输出。我第一次打开这个页面时被一堆函数名绕晕但其实它对应的就是几个环节。官方推荐的用法是用nrDLSCH这一个对象完成从传输块到速率匹配输出的全部工作底层函数留给需要自定义流程的人。文档页还顺带列出了相关示例链接比如PDSCH吞吐量仿真、HARQ重传链路等。我的建议是先看这个页面的流程图心里有一个“级联”的概念再去看代码否则你看到一串输入输出参数很容易不知道谁是谁的输入。2. MATLAB 5G Toolbox环境准备与核心API清单2.1 版本选择和工具箱安装要跑通这个链路MATLAB至少要R2019b以上因为5G Toolbox从那个版本开始提供完整的DL-SCH对象。我实际用的R2021b整体要好得多早期版本在参数校验上比较宽松有时候报错信息看不明白。注意并不是版本越新就一定对你越友好因为新版文档里的API写法可能和旧版不一致复制代码容易踩坑。安装方式不复杂在MATLAB的“附加功能”里搜索“5G Toolbox”按提示下载即可。装完用ver(5g)确认一下能看到版本号才算成功。如果你是公司内网离线环境那就麻烦一点需要下载Toolbox安装包后手动添加路径和许可证我碰到过这种情况下nrDLSCH一直显示未定义其实就是许可证没激活好。提示工具箱版本和MATLAB版本必须是匹配的。你把R2022a的5G工具箱装到R2020a上直接用会报依赖错误。2.2 必会的几个核心函数我整理了一张表覆盖DL-SCH编码链路最常用的接口新手照着这张表去查文档就够了接口作用使用场合nrDLSCH高层DL-SCH编码器对象封装CRC、分段、LDPC编码、速率匹配日常仿真首选nrCodeBlockSegmentLDPC对传输块做码块分段返回码块矩阵和分段信息底层拆解学习nrLDPCEncode对每个码块做LDPC编码输出系统位加校验位底层拆解学习nrRateMatchLDPC按冗余版本和码率做速率匹配得到最终输出比特底层拆解学习nrLDPCDecode接收端LDPC译码器常与以上接口配合做闭环闭环仿真setTransportBlock把传输块写入nrDLSCH对象配合nrDLSCH使用我自己的经验是如果不是研究算法细节优先用nrDLSCH它能自动处理标准里那些繁琐的填充、分段、CRC选择规则。只有当你需要定制速率匹配长度或者想观察某个中间变量的维度时才值得逐层拆开。2.3 官方文档怎么看才高效打开官方文档的方式有两种一是在MATLAB命令行直接输入doc搜索“LDPC Processing Chain for DL-SCH”二是去MathWorks官网看网页版。这里有个非常关键的建议一定要优先看本地文档而不是网页版。本地文档是和你当前工具箱版本严格绑定的网页版往往展示的是最新版API旧版不认。我踩过不止一次从网页复制一段最新版示例贴到R2021b里直接报“无法识别属性”。所以正确步骤是先在help里查找当前版本对应接口再结合网页版了解最新特性但代码要以本地版本能跑通为准。3. 手把手搭一条可运行的LDPC编码链路3.1 配置编码器并设置参数我最推荐的方式就是用nrDLSCH对象因为最不容易错。新建一个脚本先把调制方式和目标码率设成变量方便后面扫参数mod QPSK; % 调制方式 R 0.5; % 目标码率 TBS 1800; % 传输块大小(bit) encodeDLSCH nrDLSCH; encodeDLSCH.TargetCodeRate R; encodeDLSCH.Modulation mod; transportBlock randi([0 1], TBS, 1); setTransportBlock(encodeDLSCH, transportBlock); codedTrBlock encodeDLSCH(0);注意Modulation这个属性必须写标准字符串比如QPSK、16QAM、64QAM不能写小写或者带空格否则创建对象后设置属性会报错。encodeDLSCH(0)里的参数在不同版本里含义略有不同有的版本是HARQ进程号有的版本是冗余版本指示。我实测在R2021b里传0是正常的如果你在别的版本报错就打开doc nrDLSCH看当前版本的示例别硬套。3.2 底层分段、编码、速率匹配的拆开版本如果你想观察每一步的输入输出或者对接自定义的速率匹配逻辑建议拆开调用。流程是先做码块分段得到码块矩阵cbs再对每个码块调用nrLDPCEncode最后用nrRateMatchLDPC做速率匹配。代码骨架如下bg 1; % 基图选择实际应根据TBS和码率自动选择 cbs nrCodeBlockSegmentLDPC(transportBlock, TBS, bg); coded nrLDPCEncode(cbs); rv 0; Nref inf; % 不限参考缓冲长度 out nrRateMatchLDPC(coded, rv, mod, R, Nref);这里有个我踩过的坑nrCodeBlockSegmentLDPC要求输入的传输块必须是列向量且长度要和传入的TBS严格一致否则分段结果会出现错位。另外nrLDPCEncode的输入不是任意分段结果它会自动处理标准里要求的填充比特所以你不需要自己去补零直接把这个函数的输出当作下一步输入即可。3.3 验证输出结果是否合理跑完编码之后先别急着接调制我习惯做三个检查。第一看输出长度对不对第二用传输块大小除以输出长度算一下实际码率第三留意分段后码块数量是否合理特别是TBS刚好在分段边界附近时系统可能会多分一个码块导致额外CRC开销变大。验证代码很简单fprintf(输出比特数: %d\n, length(codedTrBlock)); fprintf(实际码率: %.3f\n, TBS / length(codedTrBlock));为什么实际码率和目标码率会不一样因为传输块前面要追加CRC分段后每个码块也要追加CRCLDPC编码本身还可能有填充比特。这些额外开销在小TBS场景下尤其明显。如果你发现实际码率远低于目标码率不要太惊讶先检查是不是CRC开销占比高再检查速率匹配输出长度是否设置正确。3.4 完整脚本示例与运行效果把几个环节合到一起我给一个可以在本地直接跑的完整脚本骨架。这里TBS故意取1800QPSK目标码率0.5你可以改成自己的参数mod QPSK; R 0.5; TBS 1800; encodeDLSCH nrDLSCH; encodeDLSCH.TargetCodeRate R; encodeDLSCH.Modulation mod; transportBlock randi([0 1], TBS, 1); setTransportBlock(encodeDLSCH, transportBlock); codedTrBlock encodeDLSCH(0); fprintf(Output length: %d\n, length(codedTrBlock)); fprintf(Effective rate: %.3f\n, TBS / length(codedTrBlock));在我的参数下输出长度会比TBS/R略大一些实际码率大约0.49原因就是前面说的CRC和填充开销。对于仿真来说这个偏差是正常的只要不过度偏离目标值就不影响后级调制和信道仿真。真正需要担心的是你在手动速率匹配时给的输出长度小于编码后最小长度那才是硬错误。4. 关键参数选型与背后逻辑4.1 BG1和BG2到底怎么选5G标准里基图选择有明确规定一句话概括传输块尺寸小或者目标码率低用BG2其他情况用BG1。更具体来说如果TBS小于等于3824比特并且目标码率小于等于0.25一般会落在BG2范围如果TBS比较大或码率偏高就会用BG1。实际当中最准确的依据是3GPP TS 38.212里那张判断表但日常仿真按这个经验判断基本够用。我在一开始做仿真时偷懒把所有场景都设成BG1结果在低码率场景下BLER表现明显差于理论预期。后来查资料才发现低码率场景需要用BG2因为它有更强的短环抑制和更稀疏的校验矩阵低码率译码门限更好。所以你在用底层接口时一定要按标准规则选择BG不要嫌麻烦。4.2 码率、调制阶数和速率匹配长度的关系速率匹配的本质是让编码后的比特数匹配物理层能提供的资源。物理层一个时隙能塞下的比特数量由调制阶数、层数、PRB数量共同决定。目标码率R只是业务层的一个请求真正落到物理层后实际码率是TBS加上CRC开销再除以速率匹配后的比特数。所以当你手工调用nrRateMatchLDPC时Nref这个参数非常关键。它表示参考HARQ缓冲区长度实际从物理层资源算出来的可用比特数如果小于LDPC编码后的原始长度就要做打孔如果大于原始长度就要做重复。很多初学者直接不传Nref或者传inf这在单发单收、不做HARQ时问题不大但一旦涉及HARQ合并缓冲区长度算错重传合并出来的结果就完全不对。4.3 HARQ冗余版本的增量冗余思想LDPC速率匹配支持RV0到RV3共四个冗余版本每个版本对应输出比特的不同起始位置和打孔模式。重传时选不同RV就能把上一次被去掉的校验比特补回来接收端合并后获得增量冗余增益这也是HARQ比纯重传有效的原因。我最初做闭环仿真时只跑RV0觉得能跑通就行。后来接上HARQ合并把RV1和RV2也加上才发现不同RV之间互补性非常明显。举个不严谨但好理解的类比相同文件发两遍和发两个不同压缩视角版本显然后者能让接收端恢复出更多信息。所以设计重传策略时不要随便都给RV0至少要按0、2、1、3的顺序尝试。4.4 实际码率与传输块大小的关系为了让你直观理解开销影响我整理了一个小表同样目标码率0.5不同TBS下的“理论最小编码输出长度”差异TBS (bit)TB CRC (bit)近似开销占比现象10024大实际码率明显低于0.5180024小实际码率接近0.51000024很小基本等于目标码率这不是精确计算只是为了说明一个规律传输块越大CRC开销占比越低。做小包业务仿真时如果你想精确控制目标码率最好用净荷加CRC综合计算而不是直接把TargetCodeRate当成最终码率。5. 实操中常见问题与调试心得5.1 工具箱版本差异导致的API报错最常见的问题是把网页版文档的最新示例复制到旧版运行报错“无法识别属性”或“输入参数数量不正确”。我的处理方法是先which nrDLSCH看看当前工具箱路径再在本地文档中搜索对应函数以本地文档为准。另外MATLAB的System object通常有默认状态如果你重复运行脚本对象里可能残留上一次的数据。我建议每次脚本开头执行clear encodeDLSCH或直接重新构造对象避免因为对象状态残留导致结果差几个比特。5.2 码块分段后LDPC输入矩阵需要填充nrLDPCEncode的输入并不是简单的分段码块。标准里每个码块在进入LDPC编码器前需要把信息位补齐到基图信息位长度不足的部分填零。这个填充操作非常容易出错尤其当你手动做分段时。好在MATLAB用nrCodeBlockSegmentLDPC返回的cbs已经是包含填充位结构的数据格式你只要原样传给nrLDPCEncode即可。所以我的建议是不要自己去截断或填充让工具箱函数处理你只需要确保它的输入符合函数文档要求即可。5.3 大数据量仿真太慢怎么办如果你跑蒙特卡洛仿真需要几千上万个传输块频繁创建编码器对象会非常慢。一个技巧是在循环外只创建一次nrDLSCH然后在循环内反复调用setTransportBlock更新传输块再调用对象获取编码输出。这样省去了对象构造和属性初始化的开销。另外底层逐码块循环在大TB下效率很低。高层编码器对象内部做了不少优化能批量处理码块。实测在相同数据量下高层对象比逐码块调用底层函数快接近一倍能走高层接口尽量走高层接口。5.4 在线文档与本地文档不一致的排查技巧这种情况在小版本更新后非常普遍。我用的R2021b在线文档已经更新到R2023a的写法同名的nrRateMatchLDPC在参数格式上就有变化。我现在看文档的习惯是先开本地help再上官网对照示例如果两者有出入以本地help为准。还有一个技巧直接在MATLAB的文档搜索框输入“LDPC Processing Chain for DL-SCH”会跳到你当前版本下的对应页面。这个页面里的示例代码一定是和当前版本匹配的比网页版靠谱得多。5.5 常见异常速查表我把自己遇到过的和身边同事遇到过的异常整理成了速查表方便你定位问题现象可能原因解决办法设置Modulation属性报错字符串格式不对或版本不支持确认当前版本支持的调制方式字符串编码输出长度异常速率匹配Nref设置错误重新计算物理层可用比特数实际码率比目标低很多TBS太小CRC和填充开销占比高用TBSCRC综合计算有效码率解码复现不成功发送接收速率匹配位置没对齐检查RV、Nref是否完全一致循环仿真越来越慢在循环内重建对象把对象创建移到循环外6. 从编码到解码闭环仿真扩展6.1 集成nrLDPCDecode的闭环思路光有编码链路只能验证发送端真正判断性能好坏必须闭环到解码端。接收端流程大致是信道输出软比特先做解速率匹配恢复出LDPC码字长度再调用nrLDPCDecode做迭代译码最后去填充、解密? 去CRC统计是否正确。我做闭环时的建议是先拿一个码块在无信道噪声下跑通确保发送端的out和接收端解速率匹配后的输入完全对齐。换句话说你先做一个“直连”闭环不发随机比特不加噪声打印发送比特和接收比特是否一一对应。只有这一关过了才能说明链路逻辑没问题否则后面加AWGN噪声只会更难排查。6.2 性能评估BLER曲线怎么画要画BLER曲线至少跑几千个TB才能得到可靠统计点。建议先低信噪比区间粗扫找到BLER在1e-1到1e-2附近的SNR范围再固定SNR跑足够多的点数。画图时横轴用SNR(dB)纵轴用BLER对数坐标可以直观看出瀑布区位置。对照时别只看绝对数值还要看曲线趋势。如果BLER在某个SNR后突然急剧下降说明译码门限正常如果下降很慢可能是LDPC参数选择不对或者接收端软比特没做对。我建议你在仿真脚本里保留一个开关可以把LDPC译码迭代次数抬高比如默认10次调试时调到50次如果性能有明显提升说明前期参数有潜在问题。6.3 官方例程的裁剪和改造建议如果你不想从零写可以直接从官方例程改起。在本地文档搜索“DLSCH”相关示例通常会找到一个完整的PDSCH链路例程里面含编码、速率匹配、HARQ和BLER统计。我的习惯是先把代码复制到自己的工程目录然后只改三个地方调制方式、目标码率、TBS先跑通再逐步加入自己的模块。这样做的好处是官方例程经过了充分验证至少保证链路逻辑没有低级错误。很多新手直接拿官方示例改参数发现跑不动其实是因为没看示例里的参数联动关系。比如TBS改大了可能分段个数变了速率匹配输出长度也要按新的码块数和物理层资源重新算官方例程有些地方已经把联动逻辑写好了但你改动时要注意别破坏了关联。最后分享一个我这两年用下来最顺手的调试技巧写LDPC编码链路时先在每个处理阶段的输出里都打印维度和矩阵校验值确认对了再接下一级。别看这方法土它帮我省下的排错时间比看十遍文档都管用。希望这篇能让你少踩几个坑把5G LDPC编码仿真跑得又快又稳。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑