LDPC与64QAM联合仿真:从原理到Python可复现链路

发布时间:2026/10/18 20:51:09
LDPC与64QAM联合仿真:从原理到Python可复现链路 简介这份资源是面向通信工程、无线通信方向学生与研究人员的一套LDPC编码与64-QAM调制联合仿真程序用于在非理想信道条件下分析误码率与抗干扰性能帮助理解纠错编码与高阶调制如何协同提升频谱效率与传输可靠性。压缩包共8个文件约13KB以m脚本文件为主辅以mat数据文件和一份txt说明涵盖编码、调制、信道与解码等环节便于直接运行与二次修改。内容预览显示其中包含校验矩阵数据、64-QAM调制解调脚本以及基于软判决的LDPC解码实现可完整走通从编码到译码的仿真流程适合用来验证消息传递类译码算法、观察不同信噪比下的性能曲线。目前已有305人学习对需要动手复现LDPC与64-QAM交互过程、优化通信链路参数的读者具有参考价值。1. LDPC 与 64QAM 联合仿真从标题拆解到可复现链路如果你手头只有一个LDPC_64QAM.rar这样的压缩包名字或者正在搜「LDPC 64QAM 联合仿真怎么做」大概率你面对的是这样一个场景通信系统课程设计、毕设开题或者公司里要快速验证一套高阶调制加信道编码的链路性能。标题里的三个关键词——LDPC、64QAM、QAM 符号——其实指向一条完整的物理层链路信源比特经过 LDPC 编码再映射成 64QAM 符号过信道接收端做软解调、LDPC 译码最后统计误码率。这套东西在 5G NR 的数据信道、DVB-S2X、部分光通信标准里都是核心组合不是玩具。它适合谁适合已经懂一点 MATLAB 或 Python、知道 BPSK 和 QPSK 怎么回事、但没亲手把 LDPC 和 64QAM 接起来跑通过的人。也适合那些跑过现成脚本但 BER 曲线怎么都不对、怀疑是解调软信息给错的人。这篇笔记按「先立住原理、再动手复现、最后说坑」的顺序走中间给可直接抄的代码和参数不堆公式重点放在能跑通、能解释现象上。2. 为什么是 LDPC 加 64QAM选型逻辑与链路拆解2.1 这对组合到底解决了什么问题单独看 64QAM每个符号带 6 个比特频谱效率是 QPSK 的 3 倍但星座点间距小噪声容限差不加编码时误码率很难看。单独看 LDPC它是一类稀疏校验矩阵定义的线性分组码译码用置信传播能逼近香农限而且码长码率灵活。把两者接起来逻辑是64QAM 负责把频谱效率拉上去LDPC 负责把可靠性补回来。接收端不是硬判出 0/1 再译码而是把每个比特的软信息LLR对数似然比送给 LDPC 译码器译码器再迭代修正。软信息质量直接决定译码增益这也是后面最容易翻车的地方。常见做法是LDPC 码率选 1/2 或 2/3码长几千到几万比特64QAM 采用格雷映射。格雷映射的意义是相邻星座点只差一个比特这样某个符号判错时大概率只错一个比特LLR 不会整体崩掉。如果你用的映射表不是格雷的BER 曲线在中等信噪比会明显翘尾这是血泪经验。2.2 链路每一级的输入输出要盯死一条最小可复现链路长这样信源随机比特长度 码长 × 码率且要能被调制阶数整除。LDPC 编码用稀疏校验矩阵 H 生成码字输出码长 N。比特交织可选但建议打散连续比特避免深衰落或星座点相关性导致连续错误。64QAM 映射每 6 个比特映射成一个复数符号。信道AWGN 最基础先跑通再加瑞利。软解调对每个比特算 LLR注意是「每比特」不是「每符号」。LDPC 译码置信传播迭代输出硬判比特。误码统计和原始信源比算 BER。这里每一步的维度都要对得上。我一般会在代码里强制断言编码输出长度等于 N映射前比特数等于符号数乘 6解调输出 LLR 长度等于 N。维度错位是新手最常见的翻车点而且报错往往出现在译码器内部看起来像算法问题其实是数据没对齐。2.3 参数怎么定码长、码率、迭代次数参数常用取值影响LDPC 码长 N648、1296、1944、6480码长越长增益越好但译码耗时上升码率 R1/2、2/3、3/4码率越低冗余越多抗噪越好频谱效率下降译码迭代次数2050次数不够译码不收敛次数过多收益递减64QAM 映射格雷映射非格雷映射会导致 LLR 质量下降信噪比范围820 dBEs/N0低于 8 dB 基本译不出来高于 20 dB 无意义注意信噪比的定义。仿真里经常混用 Eb/N0 和 Es/N064QAM 下两者差10*log10(6)约 7.78 dB。如果你看别人的曲线在 12 dB 就瀑布下降自己跑到 20 dB 才降先检查是不是单位搞混了。这个坑我踩过不止一次。3. 用 Python 把 LDPC 加 64QAM 链路跑起来3.1 环境与依赖最小可用集合不依赖任何通信专用库也能跑核心只需要 numpy。LDPC 的校验矩阵可以自己构造一个规则码或者用现成的稀疏矩阵生成方式。下面这套代码是教学向的最小实现重点在链路结构清晰不追求工业级译码速度。# 建议 Python 3.9 以上只装 numpy 即可 pip install numpy如果你要用现成的 LDPC 库常见做法是找支持 5G NR LDPC 的包但那些包接口复杂初学阶段反而容易迷失。我一般先用自己写的规则 LDPC 跑通再换标准码。3.2 构造一个可用的 LDPC 校验矩阵规则 LDPC 的构造方式很多这里用最直观的 Gallager 随机构造思路固定每列 1 的个数和每行 1 的个数随机打散。虽然性能不如优化过的码但足够验证链路。import numpy as np def build_ldpc_matrix(n, dv3, dc6, seed42): 构造规则 LDPC 校验矩阵 H尺寸 (m, n) dv: 每列 1 的个数列重 dc: 每行 1 的个数行重 要求 m n * dv / dc 为整数 rng np.random.default_rng(seed) m n * dv // dc assert m * dc n * dv, 参数不满足规则码行列重约束 H np.zeros((m, n), dtypeint) # 按块构造每块行内 1 的位置循环移位保证列重均匀 block_rows m // dv for i in range(dv): for j in range(block_rows): row i * block_rows j cols [(j * dc k) % n for k in range(dc)] H[row, cols] 1 # 随机列置换打散结构 perm rng.permutation(n) H H[:, perm] return H H build_ldpc_matrix(648, dv3, dc6) print(H shape:, H.shape, 行重:, H.sum(axis1)[:5], 列重:, H.sum(axis0)[:5])这段代码的逻辑说明先按块保证每行有 dc 个 1再通过随机列置换打散避免规则结构导致译码性能差。参数 dv 和 dc 决定码率码率 R ≈ 1 - dv/dc这里 dv3、dc6 对应 R1/2。注意m * dc n * dv这个断言不满足就说明你选的参数构不成规则码得换。3.3 编码从校验矩阵到码字有了 H编码可以用高斯消元把 H 化成系统形式也可以直接用稀疏矩阵求解。教学场景下用高斯消元最直观。def ldpc_encode(H, msg_bits): 系统 LDPC 编码H [A | B]码字 [msg | parity] 通过高斯消元把 H 转为 [I | P] 形式求校验位 m, n H.shape k n - m assert len(msg_bits) k, f消息长度应为 {k} # 高斯消元求校验部分简化实现仅适用于小规模 H_mod H.copy() % 2 # 对前 m 列做消元目标是得到单位阵 for col in range(m): pivot None for r in range(col, m): if H_mod[r, col] 1: pivot r break if pivot is None: raise ValueError(矩阵不可逆换一组参数或种子) H_mod[[col, pivot]] H_mod[[pivot, col]] for r in range(m): if r ! col and H_mod[r, col] 1: H_mod[r] (H_mod[r] H_mod[col]) % 2 P H_mod[:, m:] # 校验部分 parity (P msg_bits) % 2 return np.concatenate([msg_bits, parity]).astype(int) msg np.random.randint(0, 2, 324) codeword ldpc_encode(H, msg) print(码字长度:, len(codeword), 校验通过:, np.all((H codeword) % 2 0))逻辑说明高斯消元把 H 的前 m 列变成单位阵剩下的部分就是校验生成矩阵。最后一行断言H codeword % 2 0是必须的如果不过说明消元过程有误后面所有仿真都白做。参数上消息长度 k n - m这里 n648、m324所以 k324。3.4 64QAM 格雷映射与软解调映射和软解调是整条链路最需要小心的地方。64QAM 星座图有 64 个点每个点对应 6 个比特。格雷映射下相邻点的比特标签只差一位。def qam64_gray_map(bits): 64QAM 格雷映射每 6 比特 - 一个复数符号 采用常见的 I/Q 各 8 电平格雷编码 bits bits.reshape(-1, 6) # 格雷码到电平的映射表3 比特 - 8 电平 gray_to_level np.array([-7, -5, -3, -1, 1, 3, 5, 7]) # 3 比特格雷码转二进制索引 def gray2bin(g): b g.copy() for i in range(1, len(g)): b[i] b[i] ^ b[i-1] return b symbols [] for row in bits: i_bits row[:3] q_bits row[3:] i_idx gray2bin(i_bits) q_idx gray2bin(q_bits) i_val gray_to_level[int(.join(map(str, i_idx)), 2)] q_val gray_to_level[int(.join(map(str, q_idx)), 2)] symbols.append((i_val 1j * q_val) / np.sqrt(42)) return np.array(symbols) def qam64_soft_demod(rx_symbols, noise_var): 64QAM 软解调对每个比特输出 LLR LLR log( P(b0|y) / P(b1|y) ) 用 max-log 近似简化 gray_to_level np.array([-7, -5, -3, -1, 1, 3, 5, 7]) levels gray_to_level / np.sqrt(42) llrs [] for y in rx_symbols: # 遍历所有 64 个星座点找每个比特的最优 for bit_pos in range(6): d0, d1 [], [] for i_idx in range(8): for q_idx in range(8): # 由电平反推格雷比特 point levels[i_idx] 1j * levels[q_idx] dist np.abs(y - point) ** 2 # 这里简化直接用电平索引的二进制位作为比特 bit_val (i_idx (2 - bit_pos)) 1 if bit_pos 3 else (q_idx (5 - bit_pos)) 1 if bit_val 0: d0.append(dist) else: d1.append(dist) llr (min(d1) - min(d0)) / (2 * noise_var) llrs.append(llr) return np.array(llrs)逻辑说明映射部分把 6 比特拆成 I 路 3 比特、Q 路 3 比特各自做格雷到二进制的转换再查电平表。归一化除以sqrt(42)是为了让平均符号功率为 142 是 64QAM 各电平平方的均值。软解调用 max-log 近似对每个比特找最近的距离LLR 的符号表示倾向幅度表示置信度。参数noise_var必须和信道加噪的方差一致否则 LLR 尺度不对译码器迭代会失效。3.5 置信传播译码与 BER 统计译码器用标准的和积算法迭代更新变量节点和校验节点的消息。def ldpc_decode(H, llr, max_iter30): 置信传播译码和积算法对数域 H: 校验矩阵 llr: 信道软信息 m, n H.shape # 初始化变量节点到校验节点的消息 L np.tile(llr, (m, 1)) * H for it in range(max_iter): # 校验节点更新 L_check np.zeros_like(L) for r in range(m): cols np.where(H[r] 1)[0] for c in cols: others [x for x in cols if x ! c] prod 1.0 for o in others: prod * np.tanh(L[r, o] / 2) prod np.clip(prod, -1 1e-12, 1 - 1e-12) L_check[r, c] 2 * np.arctanh(prod) # 变量节点更新 L_total llr L_check.sum(axis0) # 硬判 hard (L_total 0).astype(int) if np.all((H hard) % 2 0): return hard, it # 更新消息 for r in range(m): cols np.where(H[r] 1)[0] for c in cols: L[r, c] L_total[c] - L_check[r, c] return hard, max_iter def run_simulation(ebn0_db, n648, dv3, dc6, trials20): H build_ldpc_matrix(n, dv, dc) k n - H.shape[0] ber_total, bit_total 0, 0 for _ in range(trials): msg np.random.randint(0, 2, k) cw ldpc_encode(H, msg) # 补齐到 6 的倍数 pad (-len(cw)) % 6 cw_pad np.concatenate([cw, np.zeros(pad, dtypeint)]) tx qam64_gray_map(cw_pad) # Eb/N0 转 Es/N064QAM 每符号 6 比特码率 R R k / n esn0_db ebn0_db 10 * np.log10(6 * R) noise_var 10 ** (-esn0_db / 10) noise np.sqrt(noise_var / 2) * (np.random.randn(len(tx)) 1j * np.random.randn(len(tx))) rx tx noise llr qam64_soft_demod(rx, noise_var) llr llr[:len(cw)] hard, _ ldpc_decode(H, llr) ber_total np.sum(hard ! cw) bit_total len(cw) return ber_total / bit_total for ebn0 in [4, 6, 8, 10]: ber run_simulation(ebn0) print(fEb/N0{ebn0} dB, BER{ber:.2e})逻辑说明校验节点更新用 tanh 规则变量节点更新把信道 LLR 和校验消息相加。硬判后检查是否满足所有校验方程满足就提前退出。仿真里 Eb/N0 转 Es/N0 的公式是Eb/N0 10*log10(6*R)这一步错了曲线整体平移。参数max_iter30是折中迭代到 30 次还不收敛基本就是信噪比不够。跑出来的 BER 应该随 Eb/N0 单调下降如果出现平台或反弹先查 LLR 尺度和噪声方差是否匹配。4. 避坑与排查LDPC 64QAM 仿真里最容易翻车的五件事4.1 BER 曲线不下降一直停在 0.5 附近现象无论信噪比调到多高误码率都在 0.5 左右像没编码一样。原因通常是 LDPC 译码器根本没工作或者 LLR 符号反了。LLR 定义是log(P(0)/P(1))如果软解调输出的是log(P(1)/P(0))译码器会把所有比特判反BER 恒为 0.5。解决拿一个无噪声符号过一遍软解调看对应比特的 LLR 符号是否和原始比特一致不一致就把 LLR 整体取负。4.2 低信噪比下译码迭代不收敛高信噪比突然变好现象Eb/N0 低于某个值时 BER 几乎不降过了阈值突然瀑布下降。这本身是 LDPC 的正常阈值行为但如果阈值比理论值高很多就要查噪声方差。常见错误是加噪时用了noise_var但软解调里传了noise_var/2或者 Es/N0 和 Eb/N0 换算漏了码率。解决在加噪后统计实际符号误差功率和设定值对比偏差超过 10% 就说明换算有问题。4.3 64QAM 映射后符号功率不归一化现象BER 曲线整体偏移信噪比定义和实际不符。原因64QAM 电平是 ±1、±3、±5、±7平均功率是 42不归一化的话实际发射功率远大于 1等效信噪比比设定值高。解决映射后统一除以sqrt(42)并在文档里写清楚归一化方式。如果用了其他电平表重新算平均功率。4.4 比特补齐和截断导致维度错位现象译码器报数组维度错误或者 BER 统计时长度对不上。原因LDPC 码长不一定能被 6 整除映射前补零、解调后截断如果补零位置和截断位置不一致LLR 和码字就错位了。解决在编码后记录原始码长补齐只补在尾部解调后严格按原始码长截断。我一般会在代码里加断言len(llr_cut) len(codeword)。4.5 迭代次数设太小误以为算法不行现象高信噪比下 BER 还是比预期高一个数量级。原因max_iter设成 5 或 10LDPC 还没收敛就退出了。解决先把迭代次数拉到 50 看性能上限再逐步降到 2030 找折中。注意迭代次数增加带来的耗时是线性的仿真大规模 BER 曲线时要权衡。5. 进阶技巧用 EXIT 图快速判断 LDPC 与 64QAM 是否匹配跑完整 BER 曲线很耗时尤其码长上万、迭代几十次的时候。我一般先用 EXIT 图外信息转移图做快速筛查分别画 64QAM 软解调的互信息转移曲线和 LDPC 译码器的转移曲线两条曲线之间有开口就说明这套组合能收敛开口越大收敛越快。具体做法是扫一组先验互信息测软解调输出的后验互信息再扫 LDPC 译码器的输入输出互信息。def measure_mutual_info_awgn(snr_db, n_samples20000): 测量 64QAM 软解调在给定信噪比下的互信息 简化实现用直方图估计 bits np.random.randint(0, 2, n_samples * 6) tx qam64_gray_map(bits) esn0 10 ** (snr_db / 10) noise_var 1 / esn0 noise np.sqrt(noise_var / 2) * (np.random.randn(len(tx)) 1j * np.random.randn(len(tx))) rx tx noise llr qam64_soft_demod(rx, noise_var) # 用 LLR 和真实比特估计互信息简化 # 实际工程中会用直方图法或高斯近似 return np.mean(np.abs(llr)) # 这里仅示意真实互信息需分桶估计上面这段只是示意接口真实互信息估计要对 LLR 分桶、统计条件概率。工程上更常用的做法是直接跑几个关键信噪点的 BER看瀑布区位置是否符合预期。如果 EXIT 图开口很小说明码率或映射方式需要调整比如把码率从 3/4 降到 2/3或者换更优的 LDPC 矩阵。另一个实用技巧是固定译码器只换映射方式对比。把格雷映射换成非格雷其他不变你会看到 BER 曲线在中等信噪比明显恶化这就是映射方式对 LLR 质量的影响。反过来固定映射把 LDPC 码长从 648 加到 6480瀑布区会左移但译码耗时上升。这些对比做两三组你对参数边界的直觉就建立起来了。我自己在这类仿真里养成的习惯是每改一个参数先跑单信噪点、少次数确认 BER 量级合理再铺开跑曲线。直接上大规模仿真一旦链路有错浪费的是几小时甚至一整天的机时。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询