
简介压缩包围绕802.11n标准中LDPC码的仿真实现展开面向通信工程学生、研究人员及需要完成无线通信课程设计或毕业设计的开发者。内容涵盖校验矩阵构建、信道编码、概率域迭代译码等环节包含MATLAB源码与配套C语言模块既可用于理解MIMO与LDPC结合后的系统结构也能作为性能仿真的基础工具。资源共25个文件以.m脚本和.c源程序为主另有README说明文档、不同码长码率648、1296、1944的基矩阵参数文件、.mat数据文件以及临时备份文件对应构建基矩阵、计算节点消息、更新校验关系等关键步骤都有现成脚本压缩包整体仅22KB组织清晰适合直接导入MATLAB运行调试。这套文件已有338人学习或下载具备一定参考价值。通过阅读源码与仿真结果可清晰掌握GF(2)域上的LDPC编解码流程、并行解码思路及参数配置方法对系统理解802.11n物理层编码方案和后续扩展研究均有帮助。1. 802.11n LDPC 不是默认开启一个被藏起来的 2 dB 编码增益调 Wi-Fi 吞吐的时候大家第一反应往往是调天线、加功率、换信道很少有人先去翻 PHY 层的编码。实际上 802.11n LDPC 是 802.11n 引入的可选前向纠错码和强制使用的卷积码相比在高码率长包场景下能多拿到 2 dB 左右的编码增益。这个增益意味着同样的信号强度误包率能低一个数量级最终直接反映在 TCP/UDP 吞吐上。这篇文章写给三类人掉吞吐的驱动工程师、做 AP 固件定制的人、用 Python 或 MATLAB 仿真 802.11n 物理层的同学。我会把编码结构、驱动开关、最小可复现仿真和踩过的坑一次讲清楚照着做基本能把这个隐藏能力挖出来。2. 看懂 802.11n LDPC 的编码结构12 种码率码长组合与发射链路2.1 QC-LDPC 的 12 种模式648/1296/1944 码长与四种码率802.11n 的 LDPC 码属于准循环 LDPCQC-LDPC也就是校验矩阵 H 由若干个 z×z 的子块拼成。每个子块要么是全零矩阵要么是单位矩阵做循环移位。标准里一共定义了 12 种编码配置3 种码长乘以 4 种码率。码长分别是 648、1296、1944 比特码率是 1/2、2/3、3/4、5/6。选这些码长不是随意定的648 是 OFDM 符号字节长度的公倍数能让一个或几个码字刚好塞进整数个 OFDM 符号里省掉大量填充比特。码长 (N)子块大小 z码率 1/2码率 2/3码率 3/4码率 5/664827324 信息位432 信息位486 信息位540 信息位129654648 信息位864 信息位972 信息位1080 信息位194481972 信息位1296 信息位1458 信息位1620 信息位这里的子块大小 z 是码长除以 24 得到的因为所有 12 个基础矩阵base matrix都有 24 列。基础矩阵里每个元素是一个 0 到 z-1 的整数表示对应子块中单位矩阵循环右移的位数-1 就代表全零子块。拿到 base matrix展开成完整的 H 矩阵是后续仿真和实现的第一步也是最容易做错的一步后面第 4 章会详细写。2.2 一条 LDPC 帧的发射链路加扰、FEC、交织到映射在 802.11n 物理层里LDPC 不是独立存在的它嵌在完整的发射链路里。从上往下走MAC 层下来的 PSDU 先加扰然后填进服务字段接着就是 FEC 编码这一步。发送端要根据数据长度、MCS 速率和信道带宽算出需要多少个 OFDM 符号再反过来决定用多大的码长来切分数据块。这个「块长选择」是 802.11n LDPC 实现里最容易写坏的部分——符号数不够码字对不齐后面的打孔和重复全部跟着乱。编码完成后LDPC 码流不会像卷积码那样走传统的 BCC 交织器而是走一套独立的交织逻辑。这套逻辑包含频率交织和子载波旋转目的是把突发错误打散。然后码字经过打孔puncturing或重复repetition去匹配 OFDM 符号的容量最后映射成 QAM 符号。接收端解调后拿到软比特 LLR再用 BP 迭代译码还原数据。这里还有一个关键点802.11n 的 HT-SIG 字段里有一个 FEC Coding 位0 表示卷积码1 表示 LDPC。发送方在每帧里动态选择接收方用这个位决定解码路径。2.3 LDPC vs 强制卷积码编码增益、时延和长包的取舍既然 802.11n 强制支持卷积码为什么还要折腾 LDPC看一组工程数据就明白了在 AWGN 信道下码率 5/6 的 LDPC 比同码率卷积码大约有 2.5 dB 的编码增益码率 1/2 的增益大约 1.5 dB在衰落信道下差距拉得更大因为 LDPC 的校验结构对突发错误更不敏感。但这个增益不是白来的BP 译码要做几十次迭代解码延迟比维特比译码高一个量级功耗也高所以 802.11n 把它定位成可选特性。工程上的取舍很明确高 MCS比如 MCS6、MCS7、长数据包比如 1500 字节的 MTU、信号边缘的情况下用 LDPC 能实打实提升吞吐低 MCS、几十字节的短帧用 LDPC 反而吃亏因为编码增益还没大到能弥补解码延迟和打孔损耗。所以你会看到很多 AP 固件里 LDPC 的默认策略是「长包高 MCS 才启用」而不是一刀切全开。理解了这个前提后面调驱动参数和看测试数据时就不会被「开了 LDPC 反而变慢」这种表面现象带偏。3. 真机开启 LDPC 的三种姿势iw 查能力、驱动参数与 hostapd 配置3.1 先确认硬件支持用 iw phy 读 HT Capabilities动手改配置之前第一件事是确认无线网卡或者 AP 的射频芯片真的把 LDPC capability 暴露给了系统。Linux 下最常见的判断方法是读iw phy输出的 HT Capabilities 字段。这个字段是一串十六进制位图LDPC 编码能力在 bit 0值为 1 表示支持。不同网卡驱动对这个位的处理不太一样Intel 的 iwlwifi 会在驱动初始化时把这个位置上部分老款博通卡则会因为固件裁剪直接隐藏掉。iw phy phy0 info | grep -A 8 HT capabilities # 期望看到类似这样的输出 # HT capabilities: # Capabilities: 0x... # HT capabilities: 0x...如果输出里直接能看到LDPC coding capability: Yes字样说明驱动已经帮你解析好了如果只有十六进制数值自己算一下 bit 0。比如Capabilities: 0x0001二进制最低位是 1就说明支持。这里有个容易忽略的坑很多 USB 网卡在 monitor 模式下都不暴露 HT-SIG 的完整信息但 beacon 帧里的 capability 是驱动上报的所以即使抓不到数据帧的 FEC 字段也能从 beacon 确认芯片能力。3.2 iwlwifi 的模块参数与 hostapd 的 HT Capability 配置确认硬件支持后在 Linux 上开启 LDPC 有两种常见路径客户端网卡用驱动模块参数AP 侧用 hostapd 的 capability 宣告。先看 Intel 网卡的经典做法。iwlwifi 驱动里有一个ldpc模块参数很多定制系统默认是关闭的。用modinfo确认一下参数名再动手不同内核版本参数可能叫ldpc也可能被编译成固定开启。# 查看驱动是否暴露 ldpc 参数 modinfo iwlwifi | grep -i ldpc # 加载驱动时显式开启 sudo modprobe iwlwifi ldpc1 # 写进配置文件重启后依然生效 echo options iwlwifi ldpc1 | sudo tee /etc/modprobe.d/iwlwifi-ldpc.conf sudo update-initramfs -u参数说明ldpc1是让驱动在关联时向 AP 通告自己的 LDPC capability默认值在不同发行版上不一样有些内核 patch 直接把它写死成关闭。注意不是所有驱动都有这个开关ath9k、mt76 这些驱动通常由 mac80211 自动设置不需要也不支持模块参数。AP 侧的 hostapd 配置就直白很多在ht_capab里加一个[LDPC]标记即可interfacewlan0 ssidldpc-lab hw_modeg channel6 ieee80211n1 ht_capab[LDPC] # 如果同时开 40MHz 带宽LDPC 和带宽互不影响 # ht_capab[HT40][LDPC][SHORT-GI-20] wpa2 wpa_passphrasetestpass写完后重启 hostapd用iw dev或者扫描工具看 beacon 帧里的 HT Capabilities确认 LDPC 位已经置 1。这里要特别说明[LDPC]只是宣告支持实际每帧用不用 LDPC 是发送端基于 MCS、包长和信道质量动态决定的所以抓包看到 beacon 支持不代表数据帧里真的在用。3.3 抓包验证 LDPC 是否真正启用HT-SIG 与 Rx 统计验证 LDPC 真正跑起来比看 capability 要难一层。数据帧里的 FEC 信息在 802.11n 的 HT-SIG 字段中普通网卡在 monitor 模式下不一定把这个字段完整喂给上位机。我的习惯是分两步走先抓 beacon 确认双侧 capability再用驱动级统计和吞吐对照来间接验证。# 抓 beacon过滤宣告 LDPC 的 AP sudo tshark -i wlan0 -Y wlan.htcapabilities.ldpc_coding_capability1 \ -T fields -e wlan.ta -e wlan.htcapabilities.ldpc_coding_capability # 固定 MCS 后看链路速率用于对照实验 iw dev wlan0 set bitrates ht-mcs-6 iw dev wlan0 station dump | grep -E bitrate|signal在支持 802.11n 且驱动完整的网卡上tshark 能把wlan.htcapabilities解析出来但如果你的网卡在 monitor 模式下根本没有wlan.ht字段那就要换思路了。最靠谱的验证方式是做 A/B 测试固定同一个 MCS、同一个包长分别跑 LDPC 开和关的配置对比误包率或 TCP 吞吐。驱动开发圈子里的做法是看 AP 芯片提供的 RX 统计里有没有 LDPC 解码成功计数这条路不同芯片厂商接口差异很大但思路是一致的——看统计不要只看能力位。4. 用 Python 复现 802.11n LDPC 编码从 H 矩阵构造到码字校验4.1 把 base matrix 展开成校验矩阵 H子块循环移位的 NumPy 实现仿真的第一步是构造 802.11n 的校验矩阵 H。以码长 648、码率 1/2 为例基础矩阵是 12 行 24 列每个元素是一个移位值子块大小 z27。展开规则很机械非负元素 s 代表一个 27×27 单位阵循环右移 s 位-1 代表整个子块全零。下面这段代码可以直接放到工程里只需要把标准文档里的 base matrix 存成一个文本文件每行 24 个整数。import numpy as np Z 27 # 子块大小码长 648 除以 base matrix 列数 24 M_B, N_B 12, 24 # rate 1/2 的 base matrix 是 12 行、24 列 # base_matrix_rate12.txt 每行 24 个整数空格分隔-1 表示全零子块 bm np.loadtxt(base_matrix_rate12.txt, dtypeint).reshape(M_B, N_B) def expand_to_h(bm, Z): 把 base matrix 展开成完整校验矩阵 H H np.zeros((M_B * Z, N_B * Z), dtypenp.uint8) for r in range(M_B): for c in range(N_B): s bm[r, c] if s 0: continue for i in range(Z): H[r * Z i, c * Z (i s) % Z] 1 return H H expand_to_h(bm, Z) print(H shape:, H.shape) print(row weight range:, H.sum(axis1).min(), H.sum(axis1).max())逻辑说明双重循环遍历 base matrix 的每个子块位置找到非 -1 的元素后把单位阵的第 i 行循环右移 s 位放到目标子块中。H.sum(axis1)是行重检查802.11n LDPC 的行重一般在 7 到 10 左右如果算出来行重特别大或者特别小先怀疑 base matrix 的文本格式是不是读错了。参数说明里要留意Z它由码长和 base matrix 列数决定换成 1296 码长时 Z541944 码长时 Z81其他不用动。4.2 在 GF(2) 上求解校验位生成系统码形式的码字有了 H 矩阵下一步是把信息位编码成完整的 LDPC 码字。802.11n 的 LDPC 码是系统码码字由信息位和校验位拼接而成。编码的本质是解一个 GF(2) 上的线性方程H 乘以码字等于零向量。把 H 分解成信息列和校验列两块问题就变成求一个线性方程组的解。工程上直接用成熟的galois库最省心它支持 GF(2) 上的矩阵求逆和解方程。import galois GF2 galois.GF(2) k H.shape[1] - H.shape[0] # 信息位长度 324 n H.shape[1] # 码长 648 msg_bits np.random.default_rng(42).integers(0, 2, sizek) A_g GF2(H[:, k:]) # 校验列 B_g GF2(H[:, :k]) # 信息列 rhs B_g GF2(msg_bits) # 信息位对校验方程的贡献 # 解 GF(2) 线性方程组 A_g p rhs p_g np.linalg.solve(A_g, rhs) p np.asarray(p_g).reshape(-1).astype(np.uint8) cw np.concatenate([msg_bits, p]) check GF2(H) GF2(cw) print(satisfied:, bool(np.all(check 0)))逻辑说明H[:, :k]是信息位对应的列H[:, k:]是校验位对应的列。方程 H [msg | p]^T 0 展开后就是 A_g p rhs其中 rhs 是信息位列对每一行校验方程的贡献。galois库在 GF(2) 上做高斯消元求解比手写二进制消元稳得多。参数说明msg_bits用随机数生成实际仿真时应该从业务数据来np.all(check 0)是编码正确性的硬性判据这一步成立才说明 H 矩阵和编码逻辑是匹配的。如果在这一步 check 不为 0绝大多数情况不是数学问题而是 base matrix 文本里某一行数据错了——这是仿真里最常见的血泪经验。4.3 加 AWGN 验证码字合法性别只对比字符串先查校验方程编码正确后很多人会急着上完整的 BP 译码器结果译码不对也不知道是编码的问题还是译码的问题。我的建议是先把黑匣子拆开用 AWGN 信道做一道「硬判决自检」把码字映射成 BPSK 符号加噪声解调回硬比特再看 H 乘码字是否为零。这一步能快速暴露编码端和信道模型之间的映射错误。def awgn_hard_check(cw, snr_db, seed1): BPSK 调制 AWGN 硬判决 校验方程检查 rng np.random.default_rng(seed) noise_std 10 ** (-snr_db / 20) tx 1 - 2 * cw # bit 0 映射为 1bit 1 映射为 -1 rx tx rng.normal(0, noise_std, sizelen(tx)) hard (rx 0).astype(np.uint8) # 硬判决得到比特 return hard hard awgn_hard_check(cw, snr_db6.0) ok bool(np.all(GF2(H) GF2(hard) 0)) print(hard-decision check passed:, ok)跑这个脚本会看到一个有意思的现象SNR 在 6 dB 时硬判决后校验方程大概率还是成立的但把 SNR 降到 0 dB校验就开始失败。这不是 bug而是正常现象——LDPC 之所以需要迭代译码就是因为在低 SNR 下硬判决不可靠。你把链路做对之后再看 BP 译码器逻辑会清晰很多。参数说明noise_std 10^(-snr_db/20)是 BPSK 信号幅度为 1 时的噪声标准差换算如果你改用 QAM64映射方式和噪声功率都要按星座图重新算。5. 802.11n LDPC 落地避坑协商失败、矩阵错位与测试翻车5.1 开了 ldpc1 但 iw 仍显示不支持驱动固件版本背锅现象在 modprobe.d 里写了options iwlwifi ldpc1重启后iw phy显示 HT Capabilities 里 LDPC 位依然是 0。 原因模块参数存在但网卡固件版本太老FW 没有向驱动上报该 capability或者内核编译时把 iwlwifi 的相关宏裁剪了导致驱动直接忽略这个参数。 解决先modinfo iwlwifi | grep ldpc确认参数存在再用dmesg | grep iwlwifi看固件版本并升级到供应商推荐版本。如果确认是驱动裁剪只有重编内核或者换卡参数怎么改都没用。5.2 仿真里编码后 H 乘码字不为零base matrix 数据读错现象按照 4.1 的脚本展开 H用 4.2 的方法解校验位最后np.all(check 0)输出 False。 原因base matrix 文本文件多了一列、少了一列或者某行是负数时格式不对。展开时bm.reshape(M_B, N_B)吃掉了错误数据但 H 的行重分布异常也没被发现。 解决先检查bm.shape是不是 (12, 24)再打印bm.min()和bm.max()确认移位值范围在 -1 到 z-1 之间。把 check 失败的每一条校验方程单独打出来对比 H 矩阵对应行的非零列位置基本能定位到具体是哪个元素的问题。5.3 hostapd 宣告 [LDPC] 但终端始终不启用客户端不支持或链路自适应保守现象AP 的 beacon 里已经能看到 LDPC capability 位但用高端客户端连接后数据帧里 FEC 字段一直是 0吞吐没有任何变化。 原因客户端网卡的驱动没有通告 LDPC或者 AP 的固件发包策略只在信号质量低于某个阈值时才切 LDPC。链路自适应把编码方式当成和 MCS 一起调度的变量测试环境信号太好反而没用上。 解决用iw dev wlan0 set bitrates ht-mcs-6固定 MCS再用衰减器或者拉远距离把 RSSI 压到 -70 dBm 以下观察是否发生 FEC 切换。不要用 iperf 默认参数测容易被链路自适应的变化掩盖。5.4 通网卡 monitor 模式抓不到数据帧的 HT-SIGradiotap 信息被裁剪现象tshark 抓 802.11n 数据帧能看到 MCS但看不到 FEC 相关字段wiretap 显示 radiotap 里没有 HT-SIG。 原因很多 USB Wi-Fi 网卡的驱动在 monitor 模式下只上报部分 radiotap 字段LDPC 这种冷门信息在上位机接口层就被丢弃了。这不是抓包参数的问题是硬件和固件的限制。 解决换用驱动支持完整 radiotap 的网卡比如一些基于 Atheros 芯片的方案或者直接用 AP 芯片原厂提供的日志诊断工具导出发包记录。别在抓包工具上死磕项目交付里的血泪经验是花两天调 tshark 不如花十分钟问驱动供应商要固件日志。5.5 固定 MCS 后开 LDPC 吞吐反而下降短包和低码率掩盖了增益现象在 MCS3、包长 200 字节的条件下做 A/B 测试开 LDPC 后 UDP 吞吐掉了一半。 原因LDPC 的编码增益需要足够的码字长度来摊薄 BP 译码的迭代开销。802.11n LDPC 最短码长 648如果实际业务包只有 200 字节一个包要分成好几个码字每个码字的填充和打孔损耗直接把增益吃掉了。 解决测试时把 UDP 包长设为 1472 字节MCS 至少提到 5 以上关掉短包保护再看对比结果。真实场景里如果业务本来就是小包为主就不该开 LDPC这不是 bug是选型错误。6. 把 LDPC 增益测出来固定 MCS 的 UDP 回放与回归脚本6.1 用固定 MCS 的 UDP 回放看清编码增益验证 LDPC 值不值得开不能只跑一次 iperf。正确做法是固定 MCS 和包长用 UDP 灌 30 秒流量统计丢包率和吞吐中位数。iperf3 的 UDP 模式天生适合这种测试-b 0表示不限带宽让它全力打流。iw dev wlan0 set bitrates ht-mcs-6 iperf3 -u -c 192.168.4.1 -b 0 -l 1472 -t 30 -J ldpc_on_mcs6.json # 关闭 LDPC 后再跑一组 # 用中位数对比不要看单次最大值判读数据时注意一个原则如果链路 SNR 很高误包率本来就趋近于零LDPC 的增益是看不出差别的要测增益就制造一个临界信号环境把链路衰减到吞吐开始下滑的位置LDPC 的价值才会显现。我自己的习惯是至少跑三组取中位数Wi-Fi 信道波动大单次结果就是玄学。6.2 把这套验证做成回归脚本有了固定流程顺手就能写成一个回归脚本防止固件迭代后 LDPC 行为悄悄变了。脚本循环多个 MCS分别记录开 LDPC 和关 LDPC 的吞吐和丢包率输出成 JSON 方便对比。for mcs in 5 6 7; do iw dev wlan0 set bitrates ht-mcs-$mcs iperf3 -u -c 192.168.4.1 -b 0 -l 1472 -t 30 -J baseline_mcs${mcs}.json # 开启 LDPC 后再跑一次这里通过驱动参数切换 done这套脚本最大的价值不在于自动化而在于让每次改动都有可比较的基线。我早年调 LDPC 时只跑一次 iperf 就下结论差点以为 LDPC 在实测环境里没收益后来固定 MCS、连续打流、对比多组中位数才看到它在边缘信号下把误包率压掉了近一个数量级。希望帮到你以后提到 802.11n LDPC别再只把它当成一个 PPT 上的参数了。本文还有配套的精品资源点击获取