
简介面向5G-NR物理层编码研究的MATLAB仿真资源围绕LDPC编译码误码率仿真展开译码算法采用OMS最小和偏置算法码率设定为0.5。资源针对通信工程、电子信息和移动通信方向的师生及算法工程师可帮助理解5G-NR标准中LDPC编译码流程并快速搭建仿真链路评估误码率性能。包体共14个文件以MATLAB的m脚本和函数为主辅以3个mat数据文件用于保存仿真中间结果或对比数据另有1个mp4教程视频直观演示运行方法。整个压缩包仅8.86MB轻量易用。目前已有269人学习/下载。通过这套资源读者既能获得可运行的LDPC编译码程序又能结合教程视频理清OMS偏置算法的实现要点可以直接运行主脚本复现不同信噪比下的误码率曲线适合作为课题入门、课程设计或算法对比的参考资料。 做5G物理层算法仿真这几年我经常遇到有人吐槽LDPC编码调用一下函数库就完事但一到译码就抓瞎尤其想自己实现OMSOffset Min-Sum偏置最小和译码器的时候网上资料不是抄3GPP规范就是甩一个公式然后没了下文最后自己做出来的误码率曲线怎么都对不上预期。这篇就用MATLAB把5G-NR-LDPC编译码误码率仿真完整走一遍码率固定0.5译码算法采用OMS从编码结构、速率匹配、QPSK软解调、迭代译码到实测结果全部讲透还配教学级代码片段。适合正在做通信系统课程设计、5G物理层算法评估或者刚接触LDPC内部机理的同学也适合想搞懂OMS实现细节再往硬件方向转的工程师。1. 5G-NR为什么选中LDPC一次信道编码的换代先交代一个背景。5G-NR的物理层数据信道PDSCH/PUSCH在R15版本定稿时做了一个重要决定信道编码从4G LTE的Turbo码全面切换成LDPC码。当时3GPP内部争论了很久最终LDPC胜出的核心原因就一个字快。5G的eMBB场景要求峰值吞吐率达到20Gbps级别这是LTE完全不可比的信道译码器不能在接收端变成瓶颈。1.1 高吞吐场景下的Turbo码瓶颈Turbo码的译码使用BCJR/MAP类算法每次迭代都需要做前向、后向递推而且这种递推是串行依赖的一个状态的计算结果会直接影响下一个状态天然不利于大规模并行。芯片上做高吞吐Turbo译码器要堆很多硬件资源才能勉强达到几十Gbps。LDPC完全不一样。它的校验矩阵是稀疏矩阵译码过程被拆成许多相互独立的校验节点和变量节点更新各个节点之间没有强时序依赖。这意味着在FPGA或ASIC上可以展开成大规模的并行计算结构几十Gbps甚至上百Gbps的译码吞吐在工程上是可实现的。另外5G还在控制信道PDCCH上选了Polar码数据信道用LDPC这是标准里两套信道编码体系并存的原因。1.2 这篇仿真要解决的具体问题很多教材讲LDPC只停留在稀疏校验矩阵BP迭代译码这个层面但实际到了5G-NR还要面对基矩阵选择、提升因子扩展、速率匹配、打孔位置LLR怎么处理等一系列工程问题。尤其是OMS这种偏置最小和译码算法教材里基本不会展开可它恰恰是硬件实现里非常讨喜的一个方案。这篇仿真就是想解决三个问题一是把5G-NR LDPC的码结构从基矩阵到实际校验矩阵彻底讲明白二是给出OMS译码器可以直接照着写的核心逻辑三是完整跑出一条BER曲线让读者知道一个可用的编译码链路应该长什么样。仿真参数我选了标准里典型的BG1基矩阵、码率0.5调制先用QPSK因为它软解调最简单可以把全部注意力集中在译码器本身上。2. 码率0.5的码字结构基矩阵、提升因子与速率匹配很多人第一次看5G-NR LDPC标准会懵因为标准里根本不给你一个现成的大尺寸H矩阵而是给了一张很小的基矩阵表。这背后的设计思想是准循环LDPC也就是QC-LDPC。2.1 QC-LDPC用基矩阵描述超大校验矩阵NR里定义了两张基矩阵称为BG1和BG2。BG1尺寸是46行×68列其中信息列数kb22适用于较大传输块和中高码率场景。BG2尺寸是42行×52列其中信息列数kb10适用于较小传输块和低码率场景。基矩阵里的每个元素不直接是0或1而是代表了Zc×Zc的块矩阵-1表示全零矩阵0表示单位阵正整数表示单位阵循环移位对应位数。这里的Zc叫做提升因子5G标准里Zc不是随便取的它必须来自标准规定的提升值集合。实际校验矩阵H的维度就是(M×Zc)行、(N×Zc)列。信息比特长度K与基矩阵信息列数kb和提升因子Zc直接相关K kb × Zc母码码长 N nb × Zc其中nb是基矩阵总列数举个例子我用BG1、Zc96那么一次编码处理的信息比特K22×962112比特母码码长N68×966528比特。注意这个Zc96在标准提升值集合里是合法的所以这个配置很干净。2.2 从母码率到0.5速率匹配在做什么BG1的母码率大约22/68≈0.32BG2的母码率大约10/52≈0.19。也就是说直接编码出来的母码码字码率低于0.5要做速率匹配通过打孔和比特选择把实际发送的码字码率提高到0.5。5G-NR的速率匹配有一套标准规则包含系统位打孔、校验位打孔和循环缓冲区比特选择。对于纯算法仿真为了聚焦OMS译码器本身我做一个合理的教学简化保留全部系统比特只在校验比特里做均匀打孔把发送比特数E控制为2K。这样实际码率就是R K / E 2112 / 4224 0.5这个简化虽然和标准细节有差异但BER曲线趋势和译码器行为是一致的。你在处理打孔位置时要特别注意一点没有发送的比特接收端没有信道观测值对应LLR必须置0表示完全不确定。如果这一步漏了误码率曲线会变得很奇怪。仿真参数可以先用这样一张表确定下来参数取值说明基矩阵BG146×68kb22提升因子Zc9696在标准提升值集合内信息比特数K211222×96母码码长N652868×96发送比特数E42242×K码率0.5调制方式QPSK每符号2比特最大迭代次数10迭代次数后面会讲怎么调OMS偏置β0.5典型值后面会讲影响3. OMS译码器原理从BP到偏置最小和的工程取舍LDPC译码本质上是在因子图上做消息传递每个变量节点、每个校验节点来回交换软信息直到整个码字满足所有校验方程。完整版的BP译码性能最好但代价非常高。3.1 BP译码和它难以落地的tanh运算BP译码里校验节点向变量节点传递消息时用到的公式是r_ji 2 * atanh(∏ tanh(q_ij / 2))这个公式里有tanh、atanh还有连乘。浮点计算一次两次没感觉但在每一轮迭代里每个校验节点每条边都要算一次硬件实现要消耗大量的面积和功耗。对5G这种追求超高吞吐的系统来说直接在芯片里铺BP所需的tanh运算单元成本高得离谱。3.2 Min-Sum、NMS和OMS三条近似路线既然tanh运算贵工程上就想办法近似。Min-Sum算法的出发点是一个观察当LLR绝对值变大时tanh值很快趋近±1一串数相乘的结果符号由负数的奇偶个数决定幅值则主要由绝对值最小的那个数主导。于是校验节点更新可以简化成r_ji ∏ sign(q_ij) × min|q_ij|这个近似把tanh、atanh全省了代价是Min-Sum会比BP差大概0.3到1dB原因在于它系统性高估了校验消息的幅值。为了补偿这个高估出现两条改进路线NMS归一化最小和乘一个小于1的缩放因子α通常取0.75到0.8OMS偏置最小和减去一个偏置β通常取0.5左右OMS的校验节点更新公式为r_ji ∏ sign(q_ij) × max(min|q_ij| - β, 0)三种方案放在一起对比结论很清晰算法核心操作性能硬件代价BPtanh/atanh、乘法最好最高NMS乘法缩放接近BPOMS之上多了乘法器OMS减法、取绝对值、比较接近NMS/BP最低标题里说的OMS最小和偏置算法全称就是Offset Min-Sum翻译过来是偏置最小和。Min-Sum是基础框架OMS在这个框架上加了偏置补偿。它最吸引人的地方在于整个校验更新过程只需要比较、减法、取符号一个乘法器都用不到这对FPGA和ASIC实现来说是巨大的优势。3.3 迭代译码的整体流程OMS译码器逐轮迭代的流程和BP是一致的初始化把所有变量节点发给校验节点的消息v2c初始化为信道LLR校验节点更新对每个校验节点收集相连变量节点的消息计算符号积、最小值和次小值然后按OMS公式生成c2v消息变量节点更新每个变量节点把信道LLR和所有c2v相加得到后验LLR然后减去对应边的c2v得到新v2c硬判决根据后验LLR的符号判断比特值早停校验如果当前硬判决满足所有校验方程说明收敛到了合法码字提前退出迭代这里有个关键点如果开启了早停平均迭代次数会明显下降但BER曲线不变。仿真时可以先用固定迭代次数比如10次确认性能稳定后再加早停。4. MATLAB仿真链路搭建编码、调制与LLR解调链路结构不复杂随机比特生成、LDPC编码、QPSK调制、AWGN信道、QPSK软解调得到LLR、OMS译码、误码统计。真正决定仿真能否跑通、曲线是否合理的是参数对齐和细节处理。4.1 仿真参数和链路结构我在MATLAB里把仿真参数集中放在一个脚本开头方便反复改。K2112这个块长不算小如果直接用教学版OMS译码器做全仿真速度会很慢。我的建议是第一遍先用小配置跑通比如BG2、Zc24这样K240、N1248教学版代码几分钟能出一轮结果确认逻辑无误后再上BG1、Zc96的大配置。LDPC编码有两种实现路径。有5G Toolbox环境的话可以调用工具箱里的LDPC编码函数具体接口以对应版本文档为准它内部已经处理好了基矩阵扩展和速率匹配。没有工具箱也不影响自己按QC-LDPC扩展规则把H矩阵构造出来然后利用5G基矩阵近似下三角的结构特点做递推编码。这里不展开完整编码函数因为篇幅太长但H矩阵构造必须要写对基矩阵里-1对应Zc×Zc全零矩阵非负整数对应单位阵循环移位后的矩阵这个步骤错了后面全错。4.2 QPSK软解调与Eb/N0换算QPSK可以看成两路独立的BPSKI路和Q路各传一个比特。我用0/1比特到星座点的映射为00对应(1,1)01对应(1,-1)10对应(-1,1)11对应(-1,-1)。收到带噪符号后I路和Q路的LLR可以分别计算LLR 2 × y / noise_var其中noise_var是每维度噪声方差实际代码里信号功率归一化后可以简单用noise_var 10^(-snr_db / 10)来计算前提是所有发送符号功率归一为1。Eb/N0和信噪比SNR的换算关系是SNR_dB EbN0_dB 10×log10(R) 10×log10(m)这里R是码率0.5m是每符号比特数QPSK时m2。所以当EbN02dB时SNR大约是2 (-3.01) 3.01 2dB。这个换算经常有人算错一错把所有曲线都平移了排查起来很痛苦。5. OMS译码器核心实现与仿真主循环这一段给出OMS译码器的教学版代码。教学版的意思是逻辑清晰、方便和理论公式对照效率不是最优。真正要跑大参数我建议在这个基础上把邻居关系预存成cell数组、向量化校验节点更新或者改写成MEX。5.1 教学版OMS译码函数function [hat_bits, iter_used] oms_decode(ch_llr, H, max_iter, beta) % OMS译码器 教学版 % ch_llr : 1xN 信道对数似然比, 长度等于母码码长N % H : MxN 稀疏校验矩阵 % max_iter: 最大迭代次数 % beta : OMS偏置量 [M, N] size(H); v2c zeros(M, N); % 变量节点发给校验节点的消息矩阵 c2v zeros(M, N); % 校验节点发给变量节点的消息矩阵 [row_idx, col_idx] find(H); % 初始化: v2c 等于信道LLR for k 1:length(row_idx) v2c(row_idx(k), col_idx(k)) ch_llr(col_idx(k)); end for it 1:max_iter % ---- 校验节点更新 ---- for m 1:M nbr col_idx(row_idx m); % 相邻变量节点 msg v2c(m, nbr); sgn prod(sign(msg)); % 符号积 [amp, order] sort(abs(msg)); % 按幅值排序 min1 amp(1); min2 amp(2); for k 1:length(nbr) n nbr(k); if abs(msg(k)) min1 min_ex min2; % 排除自身后的最小值 else min_ex min1; end c2v(m, n) sgn * sign(msg(k)) * max(min_ex - beta, 0); end end % ---- 变量节点更新 ---- for n 1:N nbr row_idx(col_idx n); % 相邻校验节点 post ch_llr(n) sum(c2v(nbr, n)); for k 1:length(nbr) m nbr(k); v2c(m, n) post - c2v(m, n); end end % ---- 硬判决与早停 ---- post_all ch_llr sum(c2v, 1); hat_bits double(post_all 0); % 0/1比特映射 if mod(H * hat_bits(:), 2) 0 iter_used it; return; end end iter_used max_iter; end这段代码里最值得揣摩的是校验节点更新中最小值和次小值的处理。对每个校验节点我只需要找到所有输入消息里幅值最小的两个然后给每条边回消息时排除自己那个输入用剩下输入里的最小值减去β再和0比较。这个逻辑是OMS实现里最容易写错的地方很多人直接用全体最小值而没有排除当前边导致性能严重下降。5.2 主仿真循环与误码统计主循环的框架可以这样组织我直接说明关键步骤而不是贴完整代码避免掩盖重点对每个EbN0点先把信号功率归一化为1计算对应noise_var然后进入帧循环。在每一帧里生成K个随机比特做LDPC编码得到N比特码字经过速率匹配选出E个发送比特QPSK调制后过AWGN信道软解调得到E个LLR。注意这E个LLR只是发送位置的译码器需要N个LLR所以要把打孔位置的LLR补成0还原出完整的LLR序列。之后调用oms_decode得到估计比特后只比较信息位部分统计错误比特数和传输总比特数。统计终止条件我习惯这样写每个SNR点至少累计到100个错误比特同时最多跑200帧。如果某点跑到200帧错误比特还不够100个就接受当前结果并继续下一个SNR点。这样做的好处是低误码率区域曲线不抖动每个点都有足够统计量支撑。6. 结果分析、参数影响与踩坑清单链路搭完仿真跑通后出来的BER曲线会非常直观地反映OMS译码器的行为。这里说两个我一定要强调的结果规律。6.1 误码率曲线与OMS/MS/BP对比用BG1、Zc96、K2112、码率0.5、QPSK这套配置BER曲线在EbN0约2dB附近可以进入1e-4以下。OMS译码器在低信噪比区域和BP的差距很小在高信噪比区域比Min-Sum大约好0.3dB左右比BP差大约0.1到0.2dB。这个性能差距换来的是硬件实现复杂度大幅降低非常划算。如果同时实现MS译码器做对比你会在曲线上看到一个很明显的特点MS在瀑布区下降得慢OMS的瀑布区更陡。因为OMS通过减去偏置实际上纠正了Min-Sum过度自信的问题让校验节点传递出去的软信息更接近BP的统计特性。6.2 偏置β与迭代次数怎么调β是OMS里最重要的超参数。拿0.5码率、QPSK、10次迭代这个配置来看β0.3补偿不足性能接近MSβ0.5性能最好β0.7补偿过头增益下降高信噪比下可能出现平台期偏置的取值和信噪比范围有关系通常取0.5附近不会出错。如果你做的是定点仿真β需要和量化精度一起调因为定点截断本身就会损失部分软信息精度。迭代次数方面5次迭代BER还明显偏高10次基本够用20次和10次的曲线几乎重合。这说明OMS在这个配置下大约10轮迭代就能收敛。配合早停机制后平均迭代次数通常不到最大迭代次数的一半这是硬件设计里非常关心的功耗指标。6.3 容易踩的坑最后把我在调试中踩过的坑集中列出来每一条都能让仿真结果从看起来离谱变成符合预期H矩阵扩展方向别搞反。基矩阵里的正整数偏移量代表循环移位方向扩展代码写错了整个矩阵就错了但译码器表面上还在运行很难一眼发现。打孔位置的LLR必须置0。我见过有人直接用随机小值代替结果相当于给译码器喂了假信息FER异常高。早停判断用mod(H * hat_bits, 2) 0不要直接判断H * hat_bits 0。后者在GF(2)上的语义是错的。LLR符号和调制映射必须统一。如果调制时1映射到-1那么LLR大于0应该判为1算法里是一致的但写的时候很容易在某个环节多乘一个负号导致BER永远停在0.5附近。统计帧数要够。每个SNR点至少100个错误比特再停止否则曲线抖动到没法看。教学版OMS代码跑大K很慢。建议先用BG2小Zc确认逻辑再切到大参数有条件就把邻居表预存成cell数组并把校验节点更新改写成按行向量化操作。最后分享一点个人经验。我最早做5G-NR LDPC仿真时总想一步到位跑BG1大块长结果教学版OMS一帧要算好久低误码率点根本跑不完。后来我改成小配置把每一条曲线都跑通理解清楚OMS的β行为和早停机制再上大参数做精细仿真效率高了不止一个量级。这篇给的教学版代码虽然慢但每一步都能对上公式等你能把校验节点更新里排除自身的最小值逻辑闭着眼睛写出来OMS译码器在工程实现上的优势你就真正体会到了。本文还有配套的精品资源点击获取