简介这套MATLAB仿真资源围绕LDPC编码在三种调制方式下的误码率分析展开主要面向通信工程、电子信息类专业学生以及需要验证编码增益的算法工程师可解决LDPC仿真从编码、调制到误码率评估缺少完整流程的问题。代码完整实现了校验矩阵生成、LDPC编码与两种迭代译码算法并在BPSK、QPSK、QAM三种调制下加入高斯白噪声通过蒙特卡洛仿真绘制误码率与信噪比曲线同时支持观察迭代次数对译码性能的影响帮助使用者直观对比不同调制方案的抗噪声能力为选择编码参数和调制方式提供可靠的数据支撑。压缩包内共12个文件全部为.m脚本包含主程序、OOK/BPSK/QPSK/QAM等多种调制函数、LDPC编码与译码算法、校验矩阵生成器以及PPM相关模块包体约13KB模块划分清晰便于按流程调用和二次开发。这份资源已有297人学习下载适合具备MATLAB与通信原理基础的读者作为仿真模板可直接修改参数扩展实验也可用于课程设计或毕业设计中的性能对比环节。1. 把 LDPC 编码和三种调制放在一起看误码率到底在看什么做物理层仿真的人应该都有体会LDPC 编码单独测 BER 曲线曲线再漂亮一旦接上真实调制链路性能往往对不上预期。反过来只看调制不接信道编码得到的是未编码的误码率工程上参考价值有限。这个标题「LDPC编码三种调制下对误码率进行分析」要解决的是中间地带——在一套完整的编码调制链路里比较 BPSK、QPSK、8PSK 三种调制方式配合同一款 LDPC 码时的误码性能搞清楚频谱效率和信噪比门限之间的置换关系。适合正在做通信系统链路仿真、需要给方案选型提供曲线依据的研究生和算法工程师。这类仿真的坑不在 LDPC 本身而在信噪比换算、软解调 LLR 的方向和误码统计口径上稍不注意整条曲线就平移好几个 dB。2. LDPC 编码的误码率为什么值得专门仿真稀疏校验矩阵与迭代译码2.1 稀疏校验矩阵、Tanner 图和置信传播LDPC 逼近香农限的底层逻辑LDPC 的全称是低密度奇偶校验码核心是那个稀疏的校验矩阵 H。所谓稀疏指的是 H 里 1 的个数远少于 0行重和列重都很小。正因为稀疏译码时才能用 Tanner 图做迭代变量节点和校验节点之间来回传递概率信息这就是置信传播BP译码。每迭代一轮每个比特的置信度更新一次多轮之后判决就能逼近最大似然的性能但复杂度远低于最大似然。这个特性决定了 LDPC 的误码率曲线有一个明显的「瀑布区」随着信噪比升高误码率不是缓慢下降而是在某个门限附近急剧跌落。瀑布区之后还会出现一段误码率下降变缓的区域叫错误平台error floor。做三种调制下的误码率分析本质上是看不同调制方式把瀑布区推到了哪个 Eb/N0 位置以及错误平台是否落在了目标误码率之上。这是选型判断的关键依据仿真曲线必须把这两段都暴露出来才算完整。2.2 仿真用哪类 LDPC 码标准码优先自构矩阵做教学验证实际仿真里LDPC 码的来源基本分两种。第一种是直接采用标准里的码比如 DVB-S.2 的 LDPC 码码长 64800长帧或 16200短帧码率有 1/2、2/3、3/4、5/6 等。标准码的好处是经过精心设计性能可靠而且很多仿真工具直接提供了生成函数拿来就能用。第二种是自己构造校验矩阵比如用随机构造加环消除去掉 4 环的方法生成一个中小规模的 H再自己写 BP 译码。自构矩阵适合教学和理解原理但性能通常不如标准码容易因为矩阵里有短环导致误码率平台抬得很高。我的建议是仿真误码率分析优先用 DVB-S.2 标准码。原因很实际你的目的是对比三种调制对误码率的影响而不是验证自构矩阵的性能。用标准码可以把变量控制在调制方式上排除码本身质量问题带来的干扰。而且标准码的 H 矩阵规模大、稀疏性好译码迭代收敛稳定瀑布区特征清晰。自构矩阵可以留到后面做算法研究时再折腾。2.3 码率和帧长怎么选码率决定门限位置帧长决定仿真耗时码率对误码率曲线的影响比很多人直觉里以为的更大。码率越低冗余校验位越多纠错能力越强瀑布区出现在更低的 Eb/N0但代价是相同带宽下传输的有效信息变少频谱效率下降。在 LDPC 与调制联合分析里码率 R 还会直接参与 Eb/N0 到 SNR 的换算这个换算公式写错是最常见的翻车点我在后面避坑章节会专门展开。帧长码字长度主要影响两个东西性能和仿真时间。长码如 64800的纠错性能通常优于短码如 16200但每帧译码时间长跑一个 SNR 点需要更多时间。选择时要平衡如果只是为了对比三种调制的相对差距16200 短帧就够用瀑布区位置和长码差距在 0.2 dB 以内如果要出严谨的工程曲线用 64800 长帧。仿真时建议先用短帧粗扫一遍 SNR 范围确定瀑布区位置再在瀑布区附近用长帧细化可以节省大量等待时间。3. 搭一条完整的 LDPC 误码率仿真链路从编码到译码的可执行方案3.1 链路结构与关键参数表无论最后用哪种调制LDPC 误码率仿真的链路骨架是固定的。我一般按这个顺序搭随机信息比特 → LDPC 编码 → 调制映射 → AWGN 加噪 → 软解调计算 LLR→ LDPC 迭代译码 → 误码统计。整个链路的核心是 LLR 的质量因为 LDPC 译码器吃的是软信息LLR 算得准不准直接决定译码结果能逼近理论多少。仿真链路里需要先定下一批参数我常用的初始配置如下参数取值说明码率 R2/3DVB-S.2 常见码率均衡性能和频谱效率码字长度64800长帧瀑布区特征稳定调制阶数 M2 / 4 / 8对应 BPSK、QPSK、8PSK每符号比特数 k1 / 2 / 3k log2(M)译码迭代次数30太少会出现错误平台太多浪费时间每个 SNR 点最少误码数100保证误码率统计置信度SNR 范围0 ~ 8 dBEb/N0实际范围按调制方式调整这些参数不是死的。迭代次数如果用的是 MATLAB 通信工具箱的 ldpcDecode它内部还有提前终止机制实际平均迭代次数远小于设定值所以放心设 30 到 50。注意点信号功率归一化为 1这样噪声方差和 N0 的关系最简单不容易算错。3.2 生成校验矩阵并完成编码最小可运行代码仿真的第一步是拿到校验矩阵。MATLAB 通信工具箱提供的 dvbs2ldpc 函数可以直接生成 DVB-S.2 标准 LDPC 码的校验矩阵不需要自己构造这是最省事也最可靠的路径。% 生成 DVB-S.2 标准 LDPC 校验矩阵 rate 2/3; % 码率 H dvbs2ldpc(rate); % 返回稀疏校验矩阵 H [numParity, codeLen] size(H); % 矩阵维度校验位数 x 码字长度 infoLen codeLen - numParity; % 信息位长度 fprintf(校验矩阵维度: %d x %d, 信息位长度: %d\n, numParity, codeLen, infoLen); % 生成一帧随机信息比特并编码 bitsPerFrame infoLen; dataBits randi([0 1], bitsPerFrame, 1); % 随机信息比特 codeword ldpcEncode(dataBits, H); % 编码输出长度 codeLen这段代码里 dvbs2ldpc 只需要传入码率它会返回稀疏矩阵 H行数是校验位数、列数是码字长度。ldpcEncode 的输入必须是列向量长度等于 H 的信息位长度输出是列向量长度等于 H 的列数。如果输入长度不对函数会直接报维度错误这是排查编码问题最快的手段。更关键的是理解编码输出的比特和后面的调制怎么对接。codeword 是 0/1 序列长度是 64800长帧情况下调制时需要把每 k 个比特映射成一个符号。所以调制前要把 codeword reshape 成 k 行一组的矩阵每一列是一组比特。这个 reshape 操作我在后面的调制代码里会写清楚千万别漏。3.3 译码器调用与 LLR 输入格式软信息的方向必须先对齐译码是整条链路里最容易出玄学问题的地方。ldpcDecode 的输入是每比特的对数似然比 LLR而不是硬判决的 0/1。LLR 的绝对值大小表示置信度符号表示比特倾向。问题在于不同工具、不同实现里 LLR 的符号约定并不完全统一有的约定正值代表比特 1有的约定正值代表比特 0。方向反了译码器输出的误码率会接近 0.5而且是全错的——几乎每个比特都取反。我在仿真时处理这个问题的做法是在软解调函数里统一按「LLR 正值代表比特更可能为 1」来算译码后立刻比对一段已知的信息比特做校验。如果发现误码率接近 0.5第一反应不是去调迭代次数而是把 LLR 取反重跑。这一步能省掉大量排查时间。% LDPC 译码输入 LLR 软信息输出信息位估计 maxIter 30; % 最大迭代次数 estBits ldpcDecode(llr, H, maxIter); % llr 是连续值列向量长度 codeLen % 注意decode 输出包含所有信息位直接与 dataBits 比对这里有个使用细节ldpcDecode 输出的 estBits 长度等于信息位长度不需要再截取。但不同版本的通信工具箱对输出约定可能有差异有的返回整帧。稳妥的做法是保守判断长度必要时只取前 infoLen 个比特来比对。迭代次数 maxIter 设太小的典型症状是瀑布区出现但不陡峭误码率在某个值附近掉不下去这就是迭代不充分导致的错误平台。4. 三种调制下的实现BPSK、QPSK、8PSK 的映射、LLR 与参数差异4.1 三种调制在 LDPC 链路里的真实差异频谱效率与门限的置换在 LDPC 编码链路里讨论调制方式本质上是在讨论每个符号能扛多少比特、以及这些比特在噪声下能活下来多少。BPSK 每个符号扛 1 个比特抗噪能力最强QPSK 每个符号扛 2 个比特误码性能和 BPSK 几乎一致因为它可以分解成正交的两路 BPSK8PSK 每个符号扛 3 个比特频谱效率最高但星座点间距变小需要更高的信噪比才能达到同样的误码率。组合 LDPC 码率 R 之后三种调制的频谱效率分别是 1×R、2×R、3×R bit/s/Hz。做一个实际系统选型时这就是核心矛盾8PSK 能传最多数据但对信道要求最苛刻QPSK 在效率和可靠性之间最均衡。误码率仿真曲线存在的意义就是把这个矛盾量化出来——8PSK 比 QPSK 在同一误码率下要多付出多少 dB 的信噪比这个数字只有仿真能给。4.2 星座映射与软解调 LLR格雷映射是底线max-log 是近似调制实现上我用统一的思路处理三种星座把 0/1 比特按每 k 个一组转成十进制索引再做格雷映射得到星座点的复数坐标。格雷映射保证了相邻星座点之间只差 1 个比特在高信噪比下误码率不会被星座点间距离拖垮。8PSK 如果不用格雷映射即使 LDPC 译码再强硬判决的比特错误也会明显变多曲线尾部会翘起来。function map ldpc_constellation(modOrder) % 生成格雷映射的星座点 % modOrder2 - BPSK, 4 - QPSK, 8 - 8PSK idx (0:modOrder-1); grayIdx bitxor(idx, bitshift(idx, -1)); % 十进制转格雷码 map exp(1j * 2 * pi * grayIdx / modOrder); % 单位圆上的星座点 if modOrder 2 map [-1; 1]; % BPSK 统一为 {-1, 1}对应比特 1/0 end end星座映射做好后软解调是真正的重头戏。接收符号 y 到达后需要计算每个比特的 LLR。严格的做法是对所有星座点做指数求和但仿真工程上很少这么干max-log 近似性能损失在零点几个 dB 以内实现简单得多我一般直接用 max-log。function llr ldpc_soft_demod(rx, map, N0) % 通用 max-log 软解调适用于 BPSK/QPSK/8PSK % rx: 接收符号列向量复数 % map: 星座点列向量 % N0: 单边噪声功率谱密度 M length(map); k log2(M); nSym length(rx); llr zeros(nSym * k, 1); bitTable de2bi((0:M-1), k, left-msb); % 每个星座点对应的比特组合 for i 1:nSym d2 abs(rx(i) - map).^2; % 到所有星座点的距离平方 for b 1:k d0 min(d2(bitTable(:, b) 0)); % 该比特为 0 的最近星座点 d1 min(d2(bitTable(:, b) 1)); % 该比特为 1 的最近星座点 llr((i-1)*k b) (d0 - d1) / N0; % 正值为倾向比特 1 end end end这个函数的计算量不小但三种调制共用一套代码逻辑清晰不会因为调制方式切换引入实现差异。核心思想是某个比特位的 LLR等于接收符号到「该比特为 1 的星座点集合」最近距离减去到「该比特为 0 的星座点集合」最近距离再除以噪声功率谱密度 N0。距离差为正说明更靠近 1 的集合。除以 N0 的本质是把距离差归一化成对数似然比的量纲这样 LDPC 译码器才能正确理解置信度。N0 如果算错LLR 整体缩放过译码性能同样会下降这也是为什么信噪比换算那么重要。4.3 主仿真循环与误码统计仿真收敛条件决定曲线质量主循环的结构是固定的对每个 Eb/N0 点循环发帧直到累计误码数足够多再停。累计误码数太少误码率曲线会在小范围抖动太多仿真时间受不了。我一般设 100 个误码作为收敛条件同时再加一个最大比特数上限防止低信噪比时时间失控。% 主仿真参数 modOrder 4; % 2 / 4 / 8 k log2(modOrder); EbN0dB 0:0.5:8; rate 2/3; numParity size(H, 1); codeLen size(H, 2); infoLen codeLen - numParity; maxIter 30; minErrs 100; % 每个点最少误码数 maxBits 2e7; % 每个点最多仿真比特数 maxFrames 500; % 每点最多帧数 map ldpc_constellation(modOrder); ber zeros(size(EbN0dB)); for snrIdx 1:length(EbN0dB) EbN0 10^(EbN0dB(snrIdx)/10); N0 1 / (EbN0 * rate * k); % 信号功率归一化为 1 totalBits 0; totalErrs 0; for f 1:maxFrames if totalErrs minErrs || totalBits maxBits break; end dataBits randi([0 1], infoLen, 1); codeword ldpcEncode(dataBits, H); % 调制每 k 比特映射一个符号 cwMat reshape(codeword, k, []); symIdx bi2de(cwMat, left-msb); txSym map(symIdx 1); % AWGN 信道 noise sqrt(N0/2) * (randn(size(txSym)) 1j*randn(size(txSym))); rxSym txSym noise; % 软解调 译码 llr ldpc_soft_demod(rxSym, map, N0); estBits ldpcDecode(llr, H, maxIter); % 统计误码 errs sum(estBits ~ dataBits); totalErrs totalErrs errs; totalBits totalBits infoLen; end ber(snrIdx) totalErrs / totalBits; end semilogy(EbN0dB, ber, o-); grid on; xlabel(Eb/N0 (dB)); ylabel(BER);N0 那行是整个链路最需要盯住的换算信噪比 SNR Es/N0 Eb/N0 × R × k。因为信号功率归一化Es 1所以 N0 1 / (EbN0 × R × k)。噪声方差在复信道上每一维实部、虚部各是 N0/2所以 randn 生成了两组独立噪声。这里如果漏乘 R 或 k曲线整体会偏 1 到 5 个 dB而且三种调制偏移量还不一样对比结论直接报废。5. LDPC 误码率分析避坑五条必查的血泪经验与排查顺序5.1 现象三条 BER 曲线整体右移 2~4 dB且 QPSK 与 BPSK 不重合原因Eb/N0 到 N0 的换算关系没有乘码率 R 和每符号比特数 k。这是整个仿真里出现频率最高的失误我几乎每次帮人排查第一站都是这里。很多人习惯直接把 Eb/N0 当成 SNR 丢给加噪函数完全绕开了 Es 与 Eb 的区别。在编码系统里每个信息比特经过编码后变成 1/R 个编码比特再经过调制变成编码比特/k 个符号所以每个符号承载的信息比特数是 R×kNO 的换算必须带上这两个因子。解决统一用 N0 1 / (EbN0_linear × R × k)。建议写代码时把 R 和 k 定义在文件最前面并把换算公式注释在噪声生成那一行旁边避免改参数时遗忘。5.2 现象BPSK 和 QPSK 曲线在低信噪比区间分得很开高信噪比才靠拢原因星座映射没有做格雷映射或者映射表顺序与比特组合的对应关系错了。BPSK 只有两个点不存在这个问题但 QPSK 一旦把 00、01、11、10 按自然序摆在相邻星座点上相邻点的比特差异就可能达到 2 位一个符号判错直接错 2 个比特。LDPC 译码虽然有纠错能力但这种系统性错误会显著抬高误码率。解决用我上面给的格雷映射函数映射后立刻画星座图验证——相邻星座点之间必须只差 1 个比特。验证方式很简单scatterplot 画出 map 的散点图旁边标注每个点对应的比特组合肉眼检查一遍。5.3 现象译码输出几乎全错误码率接近 0.5原因LLR 的符号方向与译码器的约定相反。这是 LDPC 仿真的经典黑匣子坑——你的软解调逻辑完全正确距离差也算了但译码器不认。不同版本的通信工具箱或不同第三方 LDPC 实现对 LLR 「正代表 1 还是正代表 0」的约定并不统一。解决先用较小规模的帧跑一帧把发送比特、译码输出比对比对。如果几乎全错立刻把 LLR 向量取反重新译码。我习惯在 ldpcDecode 之后加一个校验如果单帧误码率超过 0.4就打印警告提示检查 LLR 方向。这个自检开发成本很低能省大量时间。5.4 现象瀑布区出现了但误码率掉到 1e-4 附近后不再下降原因两类原因最常见。一是迭代次数设太少比如只设了 5 次译码还没收敛就被迫终止二是 H 矩阵存在较多短环常见于自构矩阵标准码很少出现。前者是参数问题后者是码本身质量问题。解决先把迭代次数加到 50 跑一次对比如果平台下降明显说明是迭代不充分。如果迭代上去了平台依然存在就要怀疑矩阵的围长girth不足换标准码或重新构造矩阵。注意长帧场景下迭代次数增加会显著拉长仿真时间可以用 16200 短帧确认问题后再切回长帧。5.5 现象曲线在低信噪比端剧烈抖动最后一个点忽高忽低原因误码统计阈值设太低或者 SNR 点本身误码太少就提前结束了循环。低信噪比下误码率本来就高方差大高信噪比下误码率低统计不到足够的误码数单帧的偶然性被放大。解决统计条件改成「累计误码数达到 100 且至少跑了 10 帧」双条件同时设一个最大仿真比特数兜底。高信噪比端如果太慢可以适当放宽到 50 个误码但曲线尾部要标注置信度变化别拿一条虚线的尾部当结论。误码率低于 1e-6 的点位如果仿真时间过长我一般直接放弃该点工程上这个量级已经够用。6. 结果怎么读瀑布区、错误平台、频谱效率与验证技巧跑完三种调制后曲线解读有一套固定方法。先看瀑布区位置BPSK 和 QPSK 的理论误码率曲线几乎重合LDPC 编码后它们各自的门限位置也应该很接近差距通常不超过 0.2 dB。8PSK 的门限会比 QPSK 高 2~3 dB这是星座点间距变小导致的必然结果。如果仿真里 8PSK 只比 QPSK 差 1 dB 以内要先怀疑是不是 LLR 计算里归一化出了问题把置信度放大了。错误平台的位置要单独记录。三种调制的错误平台大概率不在同一个误码率量级8PSK 的平台通常比 QPSK 高。做系统设计时目标误码率如果正好落在某个调制的平台区要靠增加迭代次数或更换更长码字来压低平台而不是单纯加 SNR——因为平台区对 SNR 不敏感。我常用的一个验证技巧是先用未编码的 BPSK 理论公式校准链路理论上 BPSK 的误码率是 0.5×erfc(sqrt(EbN0_linear))。跑一遍无编码的 BPSK 仿真和这个理论曲线对比确认加噪和统计口径正确后再接入 LDPC。这个校准步骤只需要写一个几行的脚本但能帮你把上面所有参数坑一次性地暴露出来。% 未编码 BPSK 理论与仿真校准验证链路正确性 EbN0dB 0:0.5:8; EbN0lin 10.^(EbN0dB/10); berTheory 0.5 * erfc(sqrt(EbN0lin)); semilogy(EbN0dB, berTheory, k-, LineWidth, 1.5);仿真时我会先把调制阶数设为 BPSK、把 ldpcEncode/ldpcDecode 换成直通跑出未编码 BPSK 曲线与理论对比对上之后再加 LDPC再换 QPSK、8PSK。每一步只引入一个变量出了偏差立刻知道是哪个环节的问题。这个习惯帮我避开过无数次「整个链路哪里都在错但不知道从哪查」的困境。三种调制下的频谱效率对比也要放在结果旁边一起看BPSK 是 1×RQPSK 是 2×R8PSK 是 3×R bit/s/Hz。把门限和频谱效率列一张小表结论就非常直观——8PSK 用 2~3 dB 的门限代价换来了 50% 的频谱效率提升QPSK 则是性价比之王。选型时如果信道余量充足且对速率有硬要求8PSK 值得投入如果链路预算紧张QPSK 加 LDPC 是最稳的组合。最后提一个我自己的习惯仿真结束后把 H 矩阵的信息位长度、码率、迭代次数、星座映射方式连同曲线图一起存档文件名里带上这些参数。否则过两周回来看图经常会忘了这条曲线是什么参数跑出来的重跑一遍又得等一小时。这个习惯救过我很多次希望帮到你。本文还有配套的精品资源点击获取