首页 / 资讯中心 / 文章详情

LDPC与64QAM联合仿真:软信息LLR计算与量化避坑指南

LDPC与64QAM联合仿真:软信息LLR计算与量化避坑指南 ★ FEATURED ARTICLE
简介这是一份面向通信工程、信号处理方向学生与工程师的MATLAB仿真资源聚焦LDPC信道编码与64-QAM调制解调系统的联合性能验证。资源包共7个文件以5个.m脚本和2个.mat数据文件为主压缩包约13KB脚本承担编码、解码、调制映射与软判决解调等核心流程mat文件则保存校验矩阵与生成矩阵等关键参数便于直接加载复现。已有250人学习下载适合作为课程设计、毕业设计或算法入门的参考工程。读者可借助其中的迭代译码实现观察不同信道条件下误码率与解码复杂度的变化理解稀疏校验矩阵与高阶调制结合时的纠错表现并在此基础上调整参数、替换信道模型完成从理论公式到可运行代码的对照学习为后续优化编码解码策略提供可复用的实验框架。1. LDPC 与 64QAM 的联合仿真为什么通信链路里最容易被忽略的是软信息做基带仿真的工程师迟早会撞上同一个问题信道编码和调制如果分开验证各自指标都好看一旦串起来跑误码率曲线就是压不下去。LDPC 加 64QAM 就是最典型的组合——LDPC 靠软判决译码吃饭64QAM 每个符号承载 6 个比特星座点挤得密判决时给出的软信息质量直接决定译码器能不能收敛。很多人第一次搭这套链路把调制输出直接喂给解调再硬判成 0/1 丢给 LDPC结果 BER 曲线在 10⁻³ 附近就躺平了怎么加信噪比都不动。问题不在 LDPC 本身在于 64QAM 的软解调没做对LLR对数似然比算错了或者量化太粗。这篇笔记就围绕一套可复现的 MATLAB 仿真程序展开把 LDPC 编码、64QAM 映射、AWGN 信道、软解调和置信传播译码这条链路一步步搭起来重点讲清楚 LLR 怎么算、量化位宽怎么选、迭代次数怎么定以及那些让曲线玄学跑不动的坑。适合已经写过基础通信仿真、想把这套组合真正跑通的人。2. 链路搭建从 LDPC 编码到 64QAM 软解调的最小可跑框架2.1 为什么选 LDPC 64QAM 这个组合而不是 Turbo 或 16QAM先说选型。LDPC 在长码块、高码率场景下的纠错能力比 Turbo 更稳尤其是码长上千以后错误平层error floor出现得更晚这对 64QAM 这种高阶调制很关键——高阶调制本身就容易在低信噪比下产生大量突发错误译码器需要强纠错能力兜底。64QAM 相比 16QAM频谱效率从 4 bit/symbol 提到 6 bit/symbol代价是星座点最小欧氏距离缩小同样的噪声功率下误符号率更高。所以这套组合的本质是用 LDPC 的编码增益去换 64QAM 的频谱效率前提是软信息必须给足。常见做法是码率取 1/2 到 3/4 之间码长 648 到 1944 这个量级类似某类结构化 LDPC 的常用参数64QAM 每符号 6 比特映射方式用格雷码因为格雷码相邻星座点只差一个比特软解调时单比特 LLR 的可靠性更高。我一般会先把码率定在 1/2信噪比扫描范围从 8dB 到 16dB这样能完整看到瀑布区。2.2 用 MATLAB 生成 LDPC 校验矩阵与编码MATLAB 从 R2016b 之后自带ldpcEncoderConfig和ldpcDecode但如果你想自己控制校验矩阵结构比如做准循环 LDPC更稳的做法是手动构造或者用通信工具箱的dvbs2ldpc生成。下面这段是构造一个码长 648、码率 1/2 的准循环 LDPC 并编码的最小示例% 构造 DVB-S2 风格的 LDPC 校验矩阵码长 648码率 1/2 H dvbs2ldpc(1/2); % 返回稀疏校验矩阵 cfg ldpcEncoderConfig(H); % 生成编码器配置对象 K cfg.NumInformationBits; % 信息位长度 N cfg.BlockLength; % 码字长度 % 随机生成信息比特 rng(2024); % 固定种子保证可复现 infoBits randi([0 1], K, 1); % LDPC 编码 codeword ldpcEncode(infoBits, cfg); fprintf(信息位 %d码字长度 %d码率 %.2f\n, K, N, K/N);逻辑说明dvbs2ldpc返回的是标准结构化校验矩阵ldpcEncoderConfig把它包装成编码器对象ldpcEncode做实际编码。参数上1/2是码率改这个值会同时改变 K 和 N 的比例。注意rng固定种子这一步别省否则每次跑出来的 BER 曲线抖动你会以为是算法问题其实是随机数在作怪。2.3 64QAM 格雷映射与符号功率归一化编码完的比特流要按每 6 个比特一组映射到 64QAM 星座点。格雷映射的核心是让相邻星座点对应的比特组只差一位这样解调时单比特 LLR 不会因为符号判决错误而全盘崩掉。MATLAB 里可以用qammod配合UnitAveragePower参数% 每符号 6 比特64QAM M 64; bitsPerSym log2(M); % 把码字按列排成 6 行每列是一个符号的比特组 numSym length(codeword) / bitsPerSym; bitMatrix reshape(codeword, bitsPerSym, numSym).; % 格雷映射的 64QAM 调制归一化平均功率为 1 txSym qammod(bitMatrix, M, InputType, bit, ... UnitAveragePower, true); % 检查平均功率 fprintf(平均符号功率: %.4f\n, mean(abs(txSym).^2));逻辑说明reshape把一维比特流变成 6 行矩阵转置后每行是一个符号的 6 比特。qammod的InputType,bit表示输入是比特而不是整数索引UnitAveragePower,true把星座平均功率归一化到 1这一步很重要——后面加噪声时信噪比的定义依赖这个归一化不归一化的话你算出来的 SNR 和实际对不上。参数上M64固定改bitsPerSym会连锁改reshape的行数。2.4 AWGN 信道加噪与信噪比定义加噪这一步看似简单但 SNR 定义错了后面全白搭。通信里 SNR 通常指每符号信噪比或每比特信噪比两者差一个bitsPerSym的因子。我一般统一用 Es/N0每符号信噪比加噪时噪声功率按信号功率除以 10^(SNR/10) 来算snrList 8:1:16; % Es/N0单位 dB berResult zeros(size(snrList)); for idx 1:length(snrList) snrDb snrList(idx); % 信号平均功率已归一化为 1噪声功率 1 / 10^(snr/10) noisePower 1 / 10^(snrDb/10); noise sqrt(noisePower/2) * (randn(size(txSym)) 1j*randn(size(txSym))); rxSym txSym noise; % 后续解调与译码... end逻辑说明复高斯噪声的实部虚部各占一半功率所以sqrt(noisePower/2)这个系数不能漏。randn生成标准正态分布乘上系数后总功率等于noisePower。参数上snrList的范围根据码率调整码率越高需要的 SNR 越大1/2 码率下 8 到 16dB 足够看到瀑布区。3. 软解调与 LDPC 译码LLR 计算和置信传播的落地细节3.1 64QAM 软解调每个比特的 LLR 到底怎么算这是整条链路最容易翻车的地方。64QAM 每个符号 6 个比特每个比特的 LLR 定义为该比特为 0 和 1 的两个星座子集上的似然比对数。精确算法是遍历所有星座点做 max-log 近似function llr qam64SoftDemod(rxSym, noiseVar) M 64; bitsPerSym 6; % 生成所有星座点及其对应的 6 比特标签 constellation qammod(0:M-1, M, UnitAveragePower, true); bitLabels de2bi(0:M-1, bitsPerSym, left-msb); numSym length(rxSym); llr zeros(numSym, bitsPerSym); for s 1:numSym r rxSym(s); % 计算到每个星座点的距离 dist abs(r - constellation).^2; for b 1:bitsPerSym % 该比特为 0 和 1 的星座点索引 idx0 bitLabels(:,b) 0; idx1 bitLabels(:,b) 1; % max-log 近似取最小距离 d0 min(dist(idx0)); d1 min(dist(idx1)); llr(s,b) (d0 - d1) / noiseVar; end end llr llr.; % 转成列向量和码字顺序对齐 llr llr(:); end逻辑说明qammod(0:M-1,...)生成 64 个星座点de2bi生成每个点对应的 6 比特标签。对每个接收符号算它到所有星座点的平方距离然后对每个比特分别找该比特为 0 和 1 的星座点里距离最小的那个两者之差除以噪声方差就是 LLR。noiseVar是噪声功率不是标准差这个参数传错会让 LLR 整体缩放译码器表现异常。max-log 近似比精确 log-sum-exp 快很多性能损失在 0.1dB 以内工程上够用。3.2 LLR 量化位宽3 比特和 6 比特差在哪LLR 是浮点数实际硬件里要量化。仿真时如果不量化曲线好看但和硬件对不上量化太粗译码增益直接掉。我一般会对比 3 比特、4 比特、6 比特量化function llrQ quantizeLLR(llr, bits) maxVal 2^(bits-1) - 1; % 先归一化到最大量化值 scale maxVal / max(abs(llr)); llrScaled llr * scale; % 饱和截断 四舍五入 llrQ round(max(-maxVal, min(maxVal, llrScaled))); end逻辑说明先按最大绝对值归一化再饱和截断到量化范围。bits是量化位宽3 比特对应 -3 到 36 比特对应 -31 到 31。血泪经验是3 比特量化在码率 1/2 时损失约 0.3 到 0.5dB4 比特基本无损6 比特和浮点几乎重合。如果你只做算法验证用浮点如果要评估硬件可行性至少跑一遍 4 比特。3.3 LDPC 置信传播译码迭代次数和早停策略译码用 MATLAB 自带的ldpcDecode它内部实现的就是置信传播BP。关键参数是最大迭代次数和早停maxIter 50; decoded ldpcDecode(llr, cfg, maxIter, ... DecisionType, soft, ... OutputFormat, info);逻辑说明llr是解调输出的软信息列向量cfg是编码器配置译码器复用maxIter是最大迭代次数。DecisionType,soft表示输入是软信息OutputFormat,info表示只输出信息比特。迭代次数不是越大越好——50 次以后大部分码块要么已经收敛要么已经失败再迭代只是浪费时间。常见做法是设 50 次上限配合内部早停校验方程全满足就退出。参数上码长越长需要的迭代次数越多648 码长 30 到 50 次足够1944 码长可以到 80 次。3.4 完整链路串起来一次 BER 仿真循环把上面几步拼成一个完整循环统计误比特率berResult zeros(size(snrList)); for idx 1:length(snrList) snrDb snrList(idx); noisePower 1 / 10^(snrDb/10); errorCount 0; totalBits 0; for trial 1:100 % 每个 SNR 点跑 100 帧 infoBits randi([0 1], K, 1); codeword ldpcEncode(infoBits, cfg); bitMatrix reshape(codeword, bitsPerSym, numSym).; txSym qammod(bitMatrix, M, InputType, bit, ... UnitAveragePower, true); noise sqrt(noisePower/2) * ... (randn(size(txSym)) 1j*randn(size(txSym))); rxSym txSym noise; llr qam64SoftDemod(rxSym, noisePower); decoded ldpcDecode(llr, cfg, maxIter, ... DecisionType, soft, OutputFormat, info); errorCount errorCount sum(decoded ~ infoBits); totalBits totalBits K; end berResult(idx) errorCount / totalBits; fprintf(SNR %d dB, BER %.2e\n, snrDb, berResult(idx)); end semilogy(snrList, berResult, o-); xlabel(Es/N0 (dB)); ylabel(BER); grid on;逻辑说明每个 SNR 点跑 100 帧每帧重新生成信息比特、编码、调制、加噪、解调、译码累计错误比特数。semilogy画对数纵轴。参数上帧数 100 是折中低 SNR 时错误多统计够了高 SNR 时错误少可能需要更多帧才能看到准确 BER可以自适应增加帧数直到错误数超过 100 个。4. 避坑与排查让 BER 曲线跑不动的五个典型问题4.1 现象BER 曲线在 10⁻² 附近完全躺平加 SNR 无改善原因最常见的是 LLR 符号搞反了。LLR 为正表示该比特更可能是 0 还是 1取决于你的定义如果解调和译码器对符号的约定不一致译码器收到的全是反向信息等于在帮倒忙。解决用一个无噪声的符号单独测一次看解调出的 LLR 符号和原始比特是否对应不对就把llr (d0 - d1)/noiseVar改成(d1 - d0)/noiseVar。4.2 现象低 SNR 时 BER 正常下降高 SNR 时出现错误平层原因错误平层通常来自 LDPC 校验矩阵里的短环girth 太小置信传播在短环上消息会自我强化导致译码器卡在错误状态。解决换一个 girth 更大的校验矩阵或者增加迭代次数配合随机扰动。仿真层面可以先确认是不是矩阵问题——换dvbs2ldpc的不同码率试试如果平层位置变了就是矩阵结构问题。4.3 现象量化后 BER 比浮点差很多超过 1dB原因LLR 量化前没做归一化或者量化位宽太小。如果 LLR 动态范围很大固定量化步长会让小值全部变成 0软信息丢失。解决先做自适应归一化按每帧最大 LLR 缩放再量化位宽至少 4 比特。我一般会在量化前打印 LLR 的均值和方差确认动态范围合理。4.4 现象仿真跑得极慢一晚上跑不完一条曲线原因软解调里用了双重循环遍历星座点MATLAB 的 for 循环效率低。解决把星座点距离计算向量化用矩阵运算替代内层循环。比如把所有接收符号和所有星座点的距离一次算成矩阵再用逻辑索引取 min。另外译码迭代次数别设太大50 次足够。4.5 现象不同 SNR 点之间曲线抖动不单调原因每个 SNR 点跑的帧数太少高 SNR 时错误事件稀疏统计涨落大。解决自适应帧数——跑够至少 100 个错误比特再停或者设一个最大帧数上限。另外固定随机种子保证每次跑的条件一致否则调试时无法复现。5. 进阶技巧用 EXIT 图预估 LDPC 64QAM 的收敛门限跑完 BER 曲线只是第一步真正想做链路预算的人会关心收敛门限在哪、还有多少余量。EXIT extrinsic information transfer图是干这个的——它把译码器的输入互信息和输出互信息画成曲线和解调器的互信息曲线叠在一起两条线的交点就是迭代收敛的固定点。对 LDPC 64QAM 这套组合EXIT 图能告诉你当前码率和星座映射下理论门限大概在多少 dB和你仿真的 BER 瀑布区起点对不对得上。具体做法先测解调器的互信息曲线即在给定 SNR 下解调输出 LLR 和真实比特之间的互信息再测 LDPC 译码器的互信息传递曲线通常用蒙特卡洛跑不同输入互信息下的输出互信息。两条曲线之间的隧道越宽收敛越快。我一般会先固定码率 1/2扫 64QAM 在不同 SNR 下的解调互信息找到它和译码器曲线的交点那个 SNR 就是预估门限。如果仿真 BER 瀑布区起点比这个门限高 1dB 以上说明实现里有损失回去查 LLR 量化和迭代次数。一个具体技巧EXIT 图里解调器曲线在低互信息区往往很陡这意味着初始几次迭代主要靠译码器自己爬解调器贡献有限。所以迭代次数分配上前 10 次可以放宽后面再收紧。另外如果你把 64QAM 换成 16QAM解调器曲线整体左移门限会降 2 到 3dB这就是频谱效率和功率效率的取舍。我自己踩过的最大坑是一开始只看 BER 曲线觉得瀑布区够陡就行了后来做链路预算才发现门限比理论值差了 1.5dB回头查是 LLR 量化用了 3 比特。改成 4 比特后门限立刻对上。所以现在我的习惯是任何软信息链路先跑一遍浮点确认算法正确再跑量化确认硬件可行两步都过了才敢写结论。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站