LDPC编码与MinSum译码:从原理到MATLAB仿真与定点实现

发布时间:2026/9/12 11:59:47
LDPC编码与MinSum译码:从原理到MATLAB仿真与定点实现 简介面向通信系统与信息论学习者的LDPC编码及MinSum译码算法仿真资源基于MATLAB实现旨在帮助读者从代码层面理解LDPC码的构造、编码和迭代译码全过程。资源覆盖H矩阵生成、信息位提取、BPSK调制、AWGN信道模拟、MinSum译码以及误码率统计等关键环节并包含参数设置与主程序调用示例适合课程实验、算法对比或课题预研时直接参考。压缩包共13个文件以11个.m脚本为主并含2个.asv自动备份整体仅9KB代码精简且模块划分清晰便于按模块逐段阅读和调试。已有395人学习说明该资源对入门LDPC编译码和MinSum算法实现具有一定实用性读者可直接运行主仿真脚本观察不同信噪比下的性能变化并按需调整码率、码长、迭代次数等参数从而加深对信道编码理论的理解也可将译码结果与理想性能对比进一步体会MinSum算法在复杂度与性能之间的取舍。1. 解压这个 rarLDPC 编码、MinSum 译码要解决什么问题从同事或技术分享里拷来的 rar 包解压后是一堆.m文件和一张误码率曲线图文件名里的MinSum指的就是译码算法核心。LDPC 是信道编码的一种发射端把信息比特编码成带校验关系的码字接收端在 AWGN 噪声里通过迭代消息传递把比特捞回来而 MinSum 是这种迭代里最实用的近似——把经典置信传播BP中计算量最大的双曲正切运算换成求最小值和符号相乘让整套编解码仿真能在 MATLAB 脚本里跑完也能平滑迁移到 FPGA。这个包的价值在于它给出了一条可复现的 LDPC 编解码仿真链路用来验证码长、码率、迭代次数和信噪比对误码率的影响。适合刚接触信道编码的学生也适合要在软件无线电或硬件里落地 LDPC 译码但没有现成 IP 的工程师。2. MinSum 译码算法原理LLR 域的 BP 近似与修正策略2.1 消息传递与 LLR 初始化BP 在迭代里交换什么LDPC 译码建立在 Tanner 图上变量节点对应码字比特校验节点对应校验方程。迭代过程中两类节点互相传递消息消息的物理含义是「对方告诉我这个比特更可能是 0 还是 1」的置信度。BPSK 调制下接收符号r的对数似然比初始化为LLR(初始) 2 * r / σ²其中 σ² 是噪声方差。这个初始值直接决定迭代起点写仿真时最容易出错的地方是把1-r或者硬判决直接当作 LLR 喂给译码器。消息符号代表硬判决方向幅度代表置信度大小。一次迭代分两个半步校验节点更新CN 更新和变量节点更新VN 更新仿真里通常还附带一个提前退出判断——硬判决结果满足全部校验方程就停。列的权重决定一个变量节点汇集多少外部信息行重则决定一次校验能融合多少比特的证据这两项在构造校验矩阵 H 时会反过来约束性能。2.2 校验节点更新的 MinSum 近似BP 的校验节点更新公式是m(c→v) 2 * atanh( Π tanh( m(v→c) / 2 ) )其中 v 是该校验节点除 v 以外的所有邻居变量节点。这个公式的物理含义是校验节点告诉 v 的信息把所有其他邻居的可信度按「tanh 乘法」合并再映射回 LLR 域。问题在于连续做 atanh 和 tanh 在浮点仿真里还能接受在硬件里就要做大查找表资源消耗很明显。MinSum 的近似思路很直接把tanh乘法展开后幅度最小的一项决定了乘积的主导地位其余项的影响可以忽略于是 CN 更新变成m(c→v) ( Π sign(m(v→c)) ) * min( |m(v→c)| )也就是「所有邻居消息的符号取乘积幅度取最小绝对值」。计算量从三角函数退化成了比较和符号异或这就是 MinSum 名义的来源。代价是消息幅度被系统性高估因为 min 操作丢弃了其他消息的约束贡献导致译码器比 BP 更乐观表现为性能损失和收敛行为变激进。2.3 归一化与偏移两种修正方式针对过估计问题实际工程里几乎不会用裸 MinSum而是在 CN 更新后加修正。最常见的两种方案是归一化 MinSum 和偏移 MinSum算法校验节点消息额外开销浮点下相对 BP 的性能差BP2*atanh(Π tanh(m/2))三角函数 LUT基准MinSum(Π sign(m)) * min(m)归一化 MinSumalpha * (Π sign(m)) * min(m)偏移 MinSummax((Π sign(m))*min(m) - beta, 0)归一化因子alpha小于 1典型起点取 0.75。偏移量beta的典型起点取 0.5。从硬件角度看偏移 MinSum 只需要减法和饱和比乘法更省但从调参角度看归一化因子的扫描更直观一维搜索就能找到接近最优的取值。这也就是为什么 rar 包的仿真代码里MinSum 相关参数往往只有alpha、max_iter、frames三四个。3. 在 MATLAB 里复现 LDPC 编码与 MinSum 译码的核心流程3.1 从 rar 包的文件名反推内部结构解压后先不要急着跑大概率会看到这些文件H_matrix.m或H.mat、ldpc_encode.m、minsum_decode.m、main_sim.m运气好还有一张BER.fig。我一般的处理顺序是先打开H相关的文件因为整个链路的地基是校验矩阵 H没有它后面全是空谈。接着找入口脚本看它是把 H 当作全局变量还是函数参数传入这决定了后续改参数时改哪里。如果包里只有 C 文件没有.m文件重点看解码循环里有没有整型变量——那是在定点化需要关注位宽和饱和处理。3.2 校验矩阵 H 的生成QC-LDPC 的最小可运行版5G NR 和 Wi-Fi 里的 LDPC 都是 QC-LDPC结构上由基矩阵和扩展因子 Z 决定。基矩阵里的每个元素表示一个 Z×Z 循环移位子块负数表示全零块。自己构造 H 时一个最简洁的版本是这样function H qc_ldpc_H(base, Z) % 基矩阵扩展为校验矩阵 H % base(i,j) 0: Z×Z 单位阵循环右移 base(i,j) 位 % base(i,j) 0: Z×Z 全零块 [mB, nB] size(base); H false(mB*Z, nB*Z); for i 1:mB for j 1:nB p base(i,j); if p 0 continue; end rb (i-1)*Z (1:Z); % 行块索引 cb (j-1)*Z (1:Z); % 列块索引 for s 0:Z-1 H(rb(s1), cb(mod(sp, Z)1)) true; end end end H double(H); end基矩阵里的每个非负元素p表示单位阵循环右移p位。这个循环移位结构让 H 矩阵天然稀疏并且硬件实现时可以用循环移位寄存器代替完整矩阵存储这也是仿真包普遍采用 QC 构造的原因。实际项目中基矩阵的行数在 4 到 12 之间列数在 24 到 96 之间Z 取 27 或 81 这类值很常见。手写这个函数只是为了理解结构跑仿真时可以直接用工具箱里的 QC 构造函数或者加载现成的H.mat。3.3 MinSum 译码主循环下面这段是教学版 MinSum 译码器用双层循环写便于逐步打印中间消息和排查逻辑错误。它在学术界和工程教学中非常常见能直接放进main_sim.m里跑function [u_hat, it] minsum_decode(H, llr, max_iter, alpha) % H : m×n 校验矩阵 % llr : 信道 LLR, 1×n % max_iter: 最大迭代次数 % alpha : 归一化因子, 0.5~1.0, 典型 0.75 [m, n] size(H); v2c zeros(m, n); % 变量节点 - 校验节点 c2v zeros(m, n); % 校验节点 - 变量节点 L llr(:).; % 后验 LLR for it 1:max_iter % ---- 校验节点更新 ---- for c 1:m nbrs find(H(c,:)); for vidx 1:numel(nbrs) v nbrs(vidx); others nbrs([1:vidx-1, vidx1:end]); if isempty(others) c2v(c,v) L(v); % 单邻居边界, 实际很少触发 continue; end msg v2c(c, others); c2v(c,v) alpha * prod(sign(msg)) * min(abs(msg)); end end % ---- 变量节点更新 ---- for v 1:n nbrs find(H(:,v)); S llr(v) sum(c2v(nbrs, v)); for cidx 1:numel(nbrs) c nbrs(cidx); v2c(c, v) S - c2v(c, v); % 外信息: 总后验减去自身 end L(v) S; end % ---- 硬判决与提前退出 ---- c_hat double(L 0); if mod(H * c_hat, 2) 0 break; end end u_hat c_hat(1:n-m); % 满秩 H 下信息位在前 n-m 位 end校验节点更新里的prod(sign(msg))是求所有邻居消息的符号乘积min(abs(msg))取最小幅度。变量节点更新里的S是当前比特的全部证据之和v2c(c,v) S - c2v(c,v)表示传给某个校验节点的消息要排除来自该校验节点自身的信息否则会产生正反馈环导致仿真发散。提前退出条件mod(H * c_hat, 2) 0是校验方程的矩阵写法满足时说明硬判决已经是一个合法码字可以停止迭代。3.4 参数与复杂度说明这一段实现跑 1000 帧没问题但速度不能指望。两个find在每次迭代都会重新扫描 H边数多时开销明显。工程上要提速有三个方向第一把每个节点的邻居列表预先存成 cell 数组避免迭代内find第二对每个校验节点只维护前二小的abs(msg)这样min不用每次遍历全部邻居第三换成 C MEX 或直接向量化。复杂度上单次迭代与 H 矩阵的非零元个数成正比也就是约等于n × 列重。取n648、列重 3、30 次迭代时运算量很小卡顿基本都是 MATLAB 循环本身的解释执行开销。要注意u_hat c_hat(1:n-m)的前提是 H 满秩且编码采用系统形式信息位在码字前段如果 rar 包里的编码器把校验位放前面这里就要改索引。4. 仿真链路调参迭代次数、归一化因子与误码率分析4.1 完整 BER 仿真链路的骨架拿到一个能跑的译码函数后下一步是搭完整的蒙特卡洛仿真链路。标准结构是随机信源 → 系统编码 → BPSK 映射 → 加噪 → LLR 初始化 → MinSum 译码 → 统计误码。常见做法是这样组织主循环function ber run_ldpc_ber(H, K, ebno_db, max_iter, alpha, frames) % K : 信息位长度 % ebno_db: 单个 Eb/N0 点, 单位 dB % frames : 该点仿真帧数 n size(H, 2); rate K / n; sigma2 1 / (2 * rate * 10^(ebno_db/10)); % BPSK 下由 Eb/N0 换算噪声方差 err 0; tot 0; for f 1:frames y randi([0 1], K, 1); c ldpc_sys_encode(y, H); % 系统编码, 输出 1×n x 1 - 2*c; % 0 → 1, 1 → -1 r x sqrt(sigma2) * randn(1, n); llr 2 * r / sigma2; % 信道 LLR [y_hat, ~] minsum_decode(H, llr, max_iter, alpha); err err sum(y ~ y_hat(:)); tot tot K; end ber err / tot; end噪声方差换算里rate不能漏。BPSK 下每个符号携带 1 bit加上码率折损后Eb/N0和符号信噪比的关系是Es/N0 Eb/N0 10*log10(rate)。漏掉码率会导致曲线向左偏移观感上「性能变好」但那是假象。LLR 初始化写2*r/sigma2时注意 r 是接收符号而不是解映射后的比特值这两个东西差的不是一个符号那么简单。4.2 影响曲线的四个参数参数浮点仿真常用范围说明max_iter10 ~ 50高 SNR 段误码平台主要由它决定30 次迭代是通用起点alpha0.5 ~ 1.0先取 0.75再用 0.05 步进扫描frames100 ~ 1000低于 1e-3 的误码率至少需要 100 个错误比特做统计LLR 初始化2r/σ²QAM 调制下还要先做软解映射不能沿用 BPSK 公式max_iter的隐含作用是决定译码延迟。硬件场景里迭代次数直接对应时钟周期数和功耗所以仿真阶段就应该扫描「迭代次数 vs 误码率」的关系找到一个增益不再下降的拐点。frames的选取有个经验法则想要在误码率 1e-4 处可信至少累计 100 个错误比特也就是帧数不低于100/(K*1e-4)。帧数太少时曲线的尾部会突然掉到零看起来性能极好实际是统计样本不够。4.3 归一化因子 α 的扫描方法alpha是 MinSum 里最值得调的参数。固定信噪比和迭代次数扫一遍 αalpha_range 0.5:0.05:1.0; ber_alpha zeros(size(alpha_range)); for idx 1:numel(alpha_range) ber_alpha(idx) run_ldpc_ber(H, K, 3.0, 30, alpha_range(idx), 500); end semilogy(alpha_range, ber_alpha, o-); xlabel(alpha); ylabel(BER);在固定 Eb/N0 下BER 最低点对应的 α 就是这一组码字和迭代次数下的最优值。通常最低点出现在 0.7 到 0.8 之间若最低点偏向两端先检查 LLR 初始化是否正确再检查 H 的列重分布。α 对性能的影响在高 SNR 段比低 SNR 段更明显因为高 SNR 时错误主要由短环和过估计引起。4.4 仿真发散怎么定位从曲线形状反推参数问题曲线画出来以后形状本身就能说明问题曲线现象常见原因先检查什么低 SNR 区 BER 高于无编码 BPSKα 偏大导致过估计放大把 α 降到 0.6 重跑高 SNR 段停在平台下不去H 存在 4-cycle 或列重过小检查 H 的围长换基矩阵曲线抖动剧烈、不平滑帧数不足错误比特太少增加帧数到累计 100 错误增大迭代次数无改善LLR 初始化错误或 α 不匹配复查2r/σ²和系统位索引仿真发散这个词最容易让人误解成数值溢出实际在浮点 MinSum 里更常见的发散是硬判决在校验空间来回跳。用mod(H*c_hat, 2)检查迭代轨迹可以很容易看出这一点。另外也别忽略编码器和译码器对系统位位置的定义是否一致很多 rar 包的问题不是算法本身而是编码输出比特顺序和译码器取信息位的索引对不上。5. 定点化 MinSum 的位宽选择与译码验证技巧浮点仿真跑通后往硬件走第一步是定点化 LLR 和消息位宽。MinSum 比 BP 适合定点的原因在于校验更新只比较幅度符号和幅值分开处理时比较器比乘法器便宜得多。常见经验是总位宽 8 bit其中 1 bit 符号、4 bit 整数、3 bit 小数LLR 饱和范围设在 ±16 附近。若位宽压到 6 bit需接受约 0.2 dB 的损失适合高吞吐场景12 bit 以上基本与浮点无差异但存储和比较开销随位宽线性增长。α 的定点实现可以不引入乘法器0.75写作右移两位减右移四位两个移位加一次减法就完成。验证定点实现有个很实用的技巧把浮点和定点译码器放在同一个驱动脚本里固定同一帧数据、同一个 H逐步对比 v2c 消息的符号和幅度。理想情况下符号完全一致幅度差异随迭代累积但不翻转符号若某些位置的符号在两次迭代间反复跳变优先怀疑 H 存在 4-cycle而不是位宽不够。另一个低成本的检查是用全零码字跑单帧此时 LLR 全为正合法码字下译码器应在 1 到 2 次迭代内直接满足校验方程退出如果出现符号振荡或迭代不收敛说明更新顺序或边界条件有误。完整验证时在固定 Eb/N0 下扫一遍 α把浮点与定点的 BER 曲线画在同一张图上两者差距稳定在 0.2 dB 以内且误码平台趋势一致这一版 MinSum 从算法到定点就都落地了。本文还有配套的精品资源点击获取