十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Matlab模拟FPGA行为实现LDPC译码:定点量化与min-sum算法实践

Matlab模拟FPGA行为实现LDPC译码:定点量化与min-sum算法实践 简介一份面向通信算法与FPGA开发者的LDPC译码算法Matlab实现资源围绕码长960、码率0.5的典型配置完整实现了基于信念传播BP的迭代译码流程包括校验节点更新、变量节点更新、初始信度设置、停止准则判断与误码性能统计。资源特别模拟FPGA硬件实现风格并引入定点量化处理便于在Matlab环境中验证量化位宽对译码性能的影响降低硬件开发迭代成本。压缩包共16个文件以8个m源码文件为核心涵盖main主程序、DecodeLDPC译码主函数、check_update校验更新、find_min最小值搜索、阈值计算等模块另有4个asv备份、2个txt说明和2个mat数据文件预置H矩阵等参数整包仅21KB结构精炼。已有488人学习下载适合正在研究LDPC编译码原理、Matlab仿真建模或FPGA实现的工程师与高年级学生参考可直接运行、逐模块修改并对照误码率曲线评估算法性能。1. 在Matlab里模拟FPGA行为做LDPC译码和普通浮点仿真差在哪LDPC译码算法在Matlab里跑通浮点BP信念传播并不难难的是把同样的算法按FPGA的硬件节奏重写一遍。码长960、码率0.5意味着校验矩阵是480×960的稀疏矩阵每个迭代周期要更新480个校验节点和960个变量节点而FPGA上没有方便的double精度运算单元也不能容忍无限迭代。这个项目把译码器拆成check_update、find_min、thresh_hold几组函数用定点量化模拟RTL行为让Matlab仿真结果能直接指导FPGA实现。适合正在做LDPC译码器硬件化、或者需要评估定点位宽对误码率影响的通信工程师。2. 校验矩阵与BP消息传递码长960、码率0.5的稀疏图怎么搭2.1 行重列重选型与短环约束码长960、码率0.5的LDPC码校验位480、信息位480校验矩阵H的维度是480×960。行重代表每个校验方程参与的变量节点数量列重代表每个变量节点参与的校验方程数量。规则码取列重3、行重6时非零元总数是960×32880矩阵密度约2880/(480×960)0.625%低密度特性非常明显这也是LDPC能用消息传递算法高效译码的前提。FPGA实现通常偏好规则码。规则(3,6)码每个校验节点的输入数量一致硬件展开后所有处理单元结构相同流水线调度不需要动态负载均衡。不规则码在浮点仿真里能挤出零点几个dB的增益但每个节点的运算量不一致按最大规格设计会造成资源浪费做动态分配又会引入复杂的控制逻辑工程上很少选。配置列重行重矩阵密度每轮迭代消息更新数硬件友好度规则(3,6)360.625%2880高规则(4,8)480.833%3840中不规则2~55~15约0.5%不固定低比密度更关键的是围长girth。围长为4的短环意味着两个变量节点被两条校验路径同时连接迭代时外信息沿环路自我加强产生过置信错误比特很难被纠正。用Matlab随机生成校验矩阵后至少要做一次4环检查。实际工程中我更倾向于用PEG渐进边增长算法构造矩阵PEG能保证新增边时围长尽可能大对码长960这类中短码的性能改善很明显。2.2 构造校验矩阵并检查有效性% 构造规则(3,6)LDPC校验矩阵:码长960, 码率0.5 M 480; N 960; dc 6; dv 3; H zeros(M, N); for r 1:M col_idx randperm(N, dc); % 每行随机选dc个位置置1 H(r, col_idx) 1; end % 检查列重分布 fprintf(列重: min%d max%d\n, min(sum(H,1)), max(sum(H,1))); % 检查是否存在长度为4的环 for c1 1:N rows_c1 find(H(:, c1)); for c2 c11:N if length(intersect(rows_c1, find(H(:, c2)))) 2 warning(发现4环: col %d 与 col %d, c1, c2); end end endrandperm方式构造的H矩阵列重并不完全均匀4环检测也很费时这段代码只适合验证译码器功能。项目里H.mat是已经生成好的矩阵直接load(H.mat)即可。要说明的是列重不均衡会导致部分变量节点参与校验次数过少这些节点在迭代中得到的修正信息不足误码率曲线上会出现少量难以纠正的错误点。2.3 BP译码的两次半边更新BP译码是在二分图上传递消息。变量节点v把初始LLR沿边发给校验节点cc收集所有相邻节点消息后计算外信息回传v再把这些外信息与自身LLR累加做一次硬判决。一轮迭代包含校验节点更新、变量节点更新和硬判决尝试三部分。LLR域里校验节点更新的严格形式是tanh域的乘积tanh(m_v→c/2) ∏ tanh(m_c→v/2)这个公式在FPGA里计算成本非常高硬件实现普遍退化为min-sum近似输出消息的符号取所有输入符号的乘积幅度取除自身外的最小输入幅度。min-sum的性能损失通过归一化因子或偏移量补偿偏移量取值0.5左右时与log-BP非常接近这一点在后续check_update实现里会用到。3. BP译码的Matlab拆分check_update、find_min与thresh_hold3.1 LLR初始化与接收数据导入main.m是译码入口txx.mat存放经过信道后的接收符号H.mat是校验矩阵。BPSK调制、AWGN信道下LLR初始化按公式LLR2y/σ²计算。FPGA里做除法不划算噪声方差通常折算到量化尺度里初始化阶段只保留一个乘法系数。% main.m 初始化片段 clear; clc; load(H.mat); % 480x960 校验矩阵 load(txx.mat); % 接收符号序列, 长度960 sigma2 0.5; % 按仿真SNR设定的噪声方差 LLR 2 * txx / sigma2; LLR_q floor(LLR * 2^6); % 6bit小数量化, 模拟定点格式量化放到初始化之后做是因为浮点LLR的动态范围决定定点格式的整数位宽。码长960的LDPC码在误码率瀑布区LLR幅度通常不超过±84bit整数加6bit小数共10bit可以覆盖这个范围。如果信道条件更差LLR分布变宽就需要把整数位扩到5bit否则后续饱和截断会丢掉关键置信信息。3.2 校验节点更新min-sum与find_mincheck_update.m对应校验节点更新。min-sum回传时某个校验节点c发给变量节点v的消息不能包含v自己传来的信息所以每条输出边都要区分全局最小值和次小值。find_min.m就是为这个需求设计的。function [min1, min2, minpos] find_min(vals) % vals: 一行输入消息的绝对值 [min1, minpos] min(vals); vals(minpos) Inf; % 用Inf屏蔽最小值位置 min2 min(vals); % 得到次小值 endminpos记录最小值位置。回传时如果当前边对应的是最小值节点用min2作为幅度否则用min1。这样每条外信息都严格排除了自身干扰。Inf在这里只是个占位符表示这个位置不参与后续比较。function msg_c2v check_update(msg_v2c, H) % msg_v2c: M x N 消息矩阵, 无连接边位置填Inf [M, N] size(H); msg_c2v zeros(M, N); % 预分配, M480, N960 for c 1:M idx find(H(c, :)); % 该行连接的变量节点 msgs msg_v2c(c, idx); [min1, min2, minpos] find_min(abs(msgs)); signs sign(msgs); % 符号单独处理 prod_sign prod(signs); for k 1:length(idx) sg prod_sign * signs(k); % 去掉当前边符号 mag min1; if k minpos mag min2; % 最小值位置改用次小值 end msg_c2v(c, idx(k)) sg * mag * 0.75; % 0.75归一化补偿 end end end这段代码里0.75是归一化因子用来补偿min-sum相对log-BP的幅度损失取值0.7到0.8之间在大多数码型下性能接近。符号域与幅度域分开处理是硬件实现的标准做法因为FPGA里符号乘积就是异或门幅度比较才是资源消耗的主要部分。3.3 变量节点更新与thresh_hold判决变量节点更新只是加法当前消息等于初始LLR加上所有传入外信息的和。% DecodeLDPC.m 变量节点更新与硬判决 hard zeros(1, N); for v 1:N sum_msg LLR_q(v) sum(msg_c2v(:, v)); if sum_msg 0 hard(v) 0; % BPSK映射: 正LLR对应发送比特0 else hard(v) 1; end endthresh_hold1.m、thresh_hold2.m、thresh_hold3.m这三个文件从命名上判断是对不同量化判决阈值做对比实验。注意thresh_hold处理的是量化后的整数值阈值本身也要量化。我一般先统计浮点LLR在所有迭代轮次里的分布选覆盖95%样本的区间映射到定点范围再设定整数域阈值而不是在浮点里调好再随便取整。参数推荐值说明最大迭代次数20超过后放弃当前帧高SNR下影响很小归一化系数0.75定点实现为右移1位加右移2位LLR量化位宽10bit(4整数6小数)码长960的常用折中停止条件H*hard0满足则提前退出3.4 停止准则与迭代上限每轮硬判决后计算校正子全零说明当前估计满足所有校验方程可以提前退出。同时必须设最大迭代次数上限防止H矩阵含环时迭代在几个状态间震荡不收敛。for iter 1:max_iter % 校验节点更新... % 变量节点更新并计算hard... syndrome mod(H * hard., 2); if sum(syndrome) 0 fprintf(iter %d 收敛\n, iter); break; end endmod(H*hard.,2)就是校正子计算MATLAB里一行完成但FPGA里对应的是480个模2加法树。提前退出机制在低SNR时节省不了多少迭代但在高SNR区平均迭代次数会显著下降这直接影响译码器的吞吐率。4. 定量和FPGA映射从浮点BP到RTL的关键一跳4.1 为什么硬件实现必须定点化FPGA上的浮点加法器需要多个DSP级联延迟和面积开销是定点的5到10倍。LDPC译码器为了保证吞吐率通常会并行实例化十几个甚至几十个校验节点处理单元每个单元内部要做大量比较和加法如果全部用浮点DSP资源和布线拥塞都不可接受。定点化是所有硬件LDPC译码器绕不开的一步。4.2 量化位宽分配与饱和截断定点位宽分两部分整数位决定动态范围小数位决定精度。码长960的BP译码对精度要求不高6bit小数足够整数位太少则大LLR被饱和截断太多则浪费资源。位宽配置整数位小数位表示范围相对浮点损失8bit26±40.3~0.5dB10bit46±80.1~0.2dB12bit66±32小于0.1dB量化函数注意饱和处理而不是溢出回绕function y fixed_quant(x, int_bits, frac_bits) % 补偿码定点量化, 含饱和截断 scale 2^frac_bits; y round(x * scale); max_val 2^(int_bits frac_bits - 1) - 1; min_val -2^(int_bits frac_bits - 1); y max(min(y, max_val), min_val); end先乘scale把小数转成整数再做饱和。溢出回绕的问题在于一个大正数截断后变成负数LLR符号反转相当于把强置信的0判决变成了1判决这种错误在后续迭代里很难自我纠正误码率曲线上会直接出现错误平台。提示饱和上限要和补码位宽严格对应差一位就会引入直流偏置等价的浮点误码率会有明显偏移。4.3 归一化系数的定点实现min-sum的0.75归一化在浮点里是乘法在定点里是移位加。0.75 0.5 0.25即右移1位加右移2位两个移位器一个加法器就完成非常适合FPGA。% 定点域0.75乘法, 假设mag_q是整数 mag_q (mag_q 1) (mag_q 2); % 算术右移等价除以2和4算术右移保持了负数的符号位对补码表示直接适用。注意如果mag本身带符号Matlab的bitshift默认是逻辑移位需要先用idivide或自行处理符号这一小差异是定点仿真与RTL行为对不上的常见原因。4.4 Matlab函数到RTL模块的映射Matlab文件对应RTL模块核心运算FPGA资源估计check_update.m校验节点单元阵列符号异或、比较树、移位加每节点约60~80 LUTfind_min.m两级比较树最小值/次小值查找每节点约40 LUTthresh_hold1~3.m阈值比较器与常量比较每节点几个LUTDecodeLDPC.m变量节点处理阵列多输入加法树与量化位宽线性相关从Matlab到Verilog核心是把for循环展开成并行流水。Matlab里for c 1:480逐个处理校验节点RTL里可以按12个节点一组并行组内按比较树级联。吞吐率提升靠并行度而不是靠降低迭代次数。5. 误码率曲线与量化参数调优LDPCBER1.txt怎么读5.1 读结果文件画BER曲线LDPCBER1.txt是蒙特卡洛仿真输出的误码率记录通常每行包含信噪比、误码率、误帧率。写个短脚本直接画曲线data load(LDPCBER1.txt); snr data(:,1); ber data(:,2); fer data(:,3); semilogy(snr, ber, o-); grid on; xlabel(Eb/N0 (dB)); ylabel(BER);画图只是为了快速看趋势真正调参时统计的是每个SNR点的错误帧数和迭代次数分布这两项决定仿真时间是否够长。5.2 浮点与定点的性能对比调量化参数时把浮点BP和定点BP跑同一组SNR点两条BER曲线叠在一起看。如果定点曲线在低SNR区和浮点重合高SNR区出现平层问题基本出在消息表示范围不足或归一化系数偏小。把8bit换成10bit再跑平层通常会明显下移。5.3 快速定位量化问题的技巧一个实用的做法是抓迭代过程的内部消息分布在某一SNR下记录所有迭代轮次里校验节点输出消息的幅度直方图看饱和点占多少比例。如果超过5%的消息打到饱和值说明整数位不够扩一位再看。另一个技巧是跳过无效SNR点每个信噪比先跑20帧全对或全错的点直接跳过只把BER在1e-2到1e-4之间的区域均匀采点仿真时间能省下一大半。误码率曲线在8bit和10bit配置下出现明显分离时优先检查thresh_hold2.m里的判决阈值是否在定点域里同步更新这个文件里跑的是不同量化方案对照阈值和位宽不一致会造成跨配置对比失真。本文还有配套的精品资源点击获取
返回列表