简介:这份资源聚焦5G NR标准下LDPC码的MATLAB实现,面向通信工程、无线算法方向的学生与工程师,以及需要理解5G信道编码原理的开发者。内容围绕5G标准定义的LDPC码族展开,涵盖校验矩阵构造、码率与码字大小等编码参数选择、比特交织与校验位生成,以及基于消息传递算法的迭代解码流程,帮助读者从规范层面打通编码与解码的完整链路。压缩包共9个文件,以7个m脚本和2个mat数据文件为主,脚本承担基图选择、提升尺寸计算、校验矩阵生成与仿真主流程,mat文件保存协议对应的校验矩阵数据,整体约20KB,结构紧凑便于直接运行与二次修改。目前已有1361人学习下载。读者可据此理解5G LDPC的H矩阵构造思路、编解码参数配置与迭代解码实现细节,并在此基础上针对具体场景调整码族与算法,为通信系统仿真和硬件移植提供可复用的参考代码。
1. 从一次链路仿真翻车说起:这套 5G LDPC 的 MATLAB 实现到底能干什么
第一次把 5G 标准里的 LDPC 搬到 MATLAB 上跑链路级仿真,我信心满满地设了个 1/2 码率、码长 8448,结果误码率曲线在 1e-3 附近直接躺平,加多少 SNR 都不往下掉。查了两天才发现,问题出在基图选错了——我按 4G 的思维默认用了 BG2,而 5G NR 里 BG1 和 BG2 的适用边界是按信息比特长度和码率划的,选错基图,后面的速率匹配、打孔、交织全跟着错位。这套LDPC_5GLDPC_5G标准下LDPC码的MATLAB实现资源,解决的正是这类问题:它把 3GPP 38.212 里那套 LDPC 编码链路——基图选择、提升值 Zc 计算、循环系数移位、速率匹配、比特交织——用 MATLAB 完整落了一遍。适合正在做 5G 物理层链路仿真、信道编码算法验证,或者被标准文档里那堆表格和公式绕晕的工程师。它不教你 LDPC 的置信传播原理,那是教科书的事;它给你的是能直接跑、能改参数、能对着标准条款核对的工程实现。
2. 基图与提升值 Zc:5G LDPC 编码链路的第一道分水岭
2.1 为什么 BG1 和 BG2 不能随便选
5G NR 的 LDPC 码没有采用单一校验矩阵,而是定义了两个基图:BG1 和 BG2。BG1 的维度是 46×68,信息列 22 列;BG2 是 42×52,信息列 10 列。标准里给的选择规则很明确:信息比特长度 K 大于 3840 时用 BG1,否则用 BG2;同时码率 R 大于 0.67 时也倾向 BG1。但实际写代码时,很多人会忽略一个细节——K 的计算不是原始信息比特数,而是经过 CRC 附着和码块分割后的长度。如果你在链路里加了 24 位 CRC,K 就变成信息位加 24,这个边界值会直接翻转基图选择结果。
我一般会在编码函数入口处先把 K 和 R 算清楚,再查表定基图。下面这段代码就是基图选择的核心逻辑,参数含义我写在注释里:
function bg = selectBaseGraph(K, R) % K: 信息比特长度(含 CRC) % R: 目标码率 % 返回 1 表示 BG1,2 表示 BG2 if K > 3840 bg = 1; elseif K <= 3840 && R <= 0.67 bg = 2; elseif K <= 3840 && R > 0.67 bg = 1; else bg = 2; end % 边界情况:K 恰好 3840 时按 BG2 处理,标准 Table 5.3.2-1 有明确 end这段逻辑看着简单,但坑在 K 的构成。如果你在调用前没把 CRC 算进去,K=3820 和 K=3860 会落到不同基图,仿真结果自然对不上。常见做法是封装一个getKWithCRC函数,把 CRC 长度作为参数传进去,避免硬编码。
2.2 提升值 Zc 的计算与移位系数查表
选定基图后,下一步是确定提升值 Zc。5G 标准定义了 51 个 Zc 值,从 2 到 384,分成 8 个集合。Zc 的选择依据是码块长度 K 和基图的信息列数:Zc 必须满足 K ≤ Zc × Kb,其中 Kb 对 BG1 是 22,对 BG2 是 10。实际选的时候取满足条件的最小 Zc,这样码长最短、复杂度最低。
但这里有个容易翻车的地方:Zc 不是随便取的,它必须落在标准定义的 51 个值里。比如 K=5000、BG1 时,Kb=22,5000/22≈227.3,你不能直接取 228,得找标准表里大于等于 227.3 的最小 Zc,也就是 240。这个查表动作如果用手写 if-else 很容易漏值,我一般直接建一个 Zc 候选数组,用find搞定:
Zc_table = [2:2:16, 18:2:32, 36:4:64, 72:8:128, 144:16:256, 288:32:384]; % 去重排序后共 51 个值 Kb = 22; % BG1 Zc = min(Zc_table(Zc_table * Kb >= K));拿到 Zc 后,还要从标准表里读对应的移位系数矩阵 V。BG1 和 BG2 各有一套 V 矩阵,每个 Zc 集合对应不同的偏移量。资源里通常会把 V 矩阵存成.mat文件或直接硬编码在函数里,调用时按 Zc 所属集合索引。这里的关键是:V 矩阵的读取不能只看 Zc 数值,还要看它属于哪个 iLS 集合(iLS=0 到 7),因为同一个 Zc 在不同集合下移位系数不同。我见过有人直接用 Zc 取模去索引,结果在 Zc=256 时对不上,就是因为忽略了集合划分。
2.3 编码矩阵的构造与循环移位实现
有了基图和 V 矩阵,接下来就是构造实际的校验矩阵 H。5G LDPC 的 H 是准循环结构,每个非零元素是一个 Zc×Zc 的循环移位单位阵,移位量由 V 矩阵给出。实现时不需要真的展开成稀疏矩阵,直接用循环移位操作就行。下面这段是编码核心:
function codeword = ldpcEncode(infoBits, bg, Zc, V) % infoBits: 信息比特列向量 % bg: 基图编号 % Zc: 提升值 % V: 移位系数矩阵 Kb = size(V, 2) - (bg == 1) * 46; % 信息列数 % 将信息比特按 Zc 分组,每组做循环移位后累加 numInfoCols = Kb; parityCols = size(V, 2) - Kb; % 前 Kb 列直接映射,后 parityCols 列通过双对角结构递推 % 具体递推公式参考 38.212 5.3.2 节 % 这里省略递推细节,资源中已封装为子函数 codeword = [infoBits; parityBits]; end这段代码里最容易被忽略的是双对角结构的递推顺序。5G LDPC 的校验部分前 4 列是特殊结构,不能直接套用普通循环移位,得按标准里的公式逐列算。资源里如果封装好了这个递推,你只需要传参调用;如果没封装,自己写的时候一定要注意第 0 列和第 1 列的依赖关系,搞反了校验方程不成立,译码端会直接崩。
3. 速率匹配与比特交织:从编码输出到可用码字的最后一公里
3.1 速率匹配的三步走:打孔、重复、交织
编码器输出的是母码,码长 N = Zc × (Kb + parityCols),但实际传输的码字长度受限于分配的资源粒子数。速率匹配就是干这个的:把母码通过打孔和重复调整到目标长度。5G 的速率匹配分三步——先打孔前 2×Zc 个比特(因为前两列是高列重,打掉对性能影响小),然后根据目标长度决定是重复还是截断,最后做比特交织。
我一开始以为打孔就是简单去掉前 2Zc 个比特,后来发现标准里还定义了冗余版本 RV0 到 RV3,不同 RV 的起始位置不同。如果你做 HARQ 仿真,RV 选错会导致重传增益完全出不来。下面这段是速率匹配的简化实现:
function out = rateMatch(codeword, targetLen, rv, Zc) % 打孔前 2*Zc punctured = codeword(2*Zc+1:end); % 根据 rv 确定起始位置 switch rv case 0 startPos = 0; case 1 startPos = floor(length(punctured) * 0.25); case 2 startPos = floor(length(punctured) * 0.5); case 3 startPos = floor(length(punctured) * 0.75); end % 循环读取直到填满 targetLen out = zeros(targetLen, 1); idx = startPos; for i = 1:targetLen out(i) = punctured(mod(idx, length(punctured)) + 1); idx = idx + 1; end % 比特交织按标准 5.4.2.2 节的行列规则 out = bitInterleave(out); end参数rv控制冗余版本,targetLen是分配到的比特数。注意打孔后的长度是母码减 2Zc,如果 targetLen 大于这个值,循环读取就会重复,这就是重复操作。资源里如果带了 HARQ 合并的示例,你可以直接改 rv 看四次重传的合并效果。
3.2 比特交织的行列规则与常见误用
比特交织在 5G 里不是可选项,标准规定必须做。规则是按行写入、按列读出,行数固定为调制阶数 Qm。比如 QPSK 时 Qm=2,就把序列排成 2 行,然后逐列读。这个操作看着简单,但坑在序列长度不是 Qm 整数倍时的填充处理。标准里说填充 null 比特,读出时再删掉,但如果你在代码里忘了删,解调端就会多出无效比特,误码率曲线会莫名其妙抬高。
我一般会在交织函数里加一个断言,检查输入长度和 Qm 的整除关系,不整除就补 null 并记录位置,读出后再按位置剔除。这个习惯帮我省过好几次调试时间。
3.3 与译码端的对接:软信息输入格式
编码和速率匹配做完,码字要送到译码端。如果你用的是 MATLAB 自带的comm.LDPCDecoder,它要求输入是软信息(LLR),而且对基图和 Zc 的配置有特定参数。资源里如果提供了完整的链路脚本,通常会包含一个ldpcDecode函数,内部调用comm.LDPCDecoder并设置BaseGraph、Zc、MaximumIterationCount等属性。这里要注意:comm.LDPCDecoder的输入 LLR 符号约定是「正数表示 0」,如果你从解调器出来的 LLR 符号反了,译码器会一直输出全 1,误码率恒为 0.5。这个坑我踩过,查了一下午才发现是符号约定问题。
4. 避坑与排查:5G LDPC MATLAB 实现里最容易翻车的五个点
4.1 现象:误码率曲线在 1e-2 附近出现平台
原因:基图选择边界算错,K 没有包含 CRC 长度,导致 BG1/BG2 选反。解决:在编码入口打印 K 和 R 的实际值,对照标准 Table 5.3.2-1 核对基图。如果 K 在 3840 附近,手动检查 CRC 是否计入。
4.2 现象:译码器输出全零或全一
原因:LLR 符号约定与译码器期望相反。解决:在译码前加一行llr = -llr测试,如果误码率恢复正常,说明符号反了。或者检查解调器输出的 LLR 定义,确保「正数对应比特 0」。
4.3 现象:速率匹配后码字长度对不上
原因:打孔后长度计算错误,或者 RV 起始位置用了绝对索引而非打孔后索引。解决:在速率匹配函数里打印length(punctured)和targetLen,确认循环读取的模运算基数是打孔后长度,不是母码长度。
4.4 现象:Zc 查表时索引越界或取到未定义值
原因:Zc 候选表不完整,或者 iLS 集合划分搞错。解决:直接用标准定义的 51 个 Zc 值建表,按 iLS 分组索引 V 矩阵。如果资源里 V 矩阵是硬编码的,检查 Zc=256 和 Zc=288 附近的边界。
4.5 现象:HARQ 重传没有增益
原因:RV 版本选择错误,或者重传时没有做软合并。解决:确认四次重传分别用 RV0、RV2、RV3、RV1(标准推荐顺序),并在译码前把多次接收的 LLR 按位相加再做译码。
5. 进阶验证:用误码率曲线和标准一致性检查锁死实现正确性
5.1 用 AWGN 链路跑一条可信的 BER 曲线
验证 LDPC 实现对不对,最直接的办法是跑 AWGN 信道下的 BER 曲线,看它是否落在理论值附近。我一般会固定码率 1/2、码长 8448、BG1、QPSK,SNR 从 0 扫到 3 dB,每个点至少 100 帧错误。如果曲线在 1e-5 处与文献偏差超过 0.3 dB,就得回头查编码或译码。下面是一个最小验证脚本的骨架:
snrRange = 0:0.5:3; ber = zeros(size(snrRange)); for i = 1:length(snrRange) errors = 0; totalBits = 0; while errors < 100 info = randi([0 1], 4000, 1); codeword = ldpcEncode(info, 1, 384, V); tx = rateMatch(codeword, 8000, 0, 384); rx = awgn(2*tx-1, snrRange(i), 'measured'); llr = 2*rx / (10^(snrRange(i)/10)); decoded = ldpcDecode(llr, 1, 384); errors = errors + sum(decoded ~= info); totalBits = totalBits + length(info); end ber(i) = errors / totalBits; end semilogy(snrRange, ber);这段脚本里V需要从资源里加载,ldpcDecode是封装好的译码函数。跑之前确认awgn的 SNR 定义是 Es/N0 还是 Eb/N0,两者差一个码率因子,搞混了曲线会平移。
5.2 标准一致性检查:用已知向量对拍
除了 BER 曲线,更硬核的验证是拿标准里的测试向量对拍。3GPP 38.212 的附录里有一些编码输入输出示例,你可以把信息比特和配置参数输进去,比对编码输出是否逐位一致。如果资源里带了testVectors文件夹,直接跑runTests就行。没有的话,自己构造一个 K=40、R=0.5 的小例子,手动按标准算一遍前 20 个比特,和代码输出对比。这个动作花不了十分钟,但能提前发现移位系数或递推顺序的错误。
5.3 一个让我少走弯路的习惯
从那以后我每次拿到新的 LDPC 实现,都强制走一遍「小码长对拍 + BER 曲线 + 边界 Zc 扫描」三步。小码长对拍看逻辑对不对,BER 曲线看性能有没有异常,边界 Zc 扫描看查表和索引有没有越界。这三步走完,基本能排除 90% 的翻车点。希望帮到你。
本文还有配套的精品资源,点击获取