m基于FPGA的LDPC最小和译码算法verilog实现,包括testbench和matlab辅助验证程序

目录

1.算法仿真效果

2.算法涉及理论知识概要

3.MATLAB核心程序

4.完整算法代码文件


1.算法仿真效果

matlab2022a/vivado2019.2仿真结果如下:

matlab仿真:

0.5码率,H是4608×9216的矩阵。

FPGA仿真:

 对比如下:

2.算法涉及理论知识概要

         LDPC译码分为硬判决译码和软判决译码。

        硬判决译码又称代数译码,主要代表是比特翻转(BF)译码算法,它的实现比较简单,但是译码性能很差。硬判决译码的基本假设是当校验方程不成立时,说明此时必定有比特位发生了错误,而所有可能发生错误的比特中不满足检验方程个数最多的比特发生错误的概率最大。在每次迭代时翻转发生错误概率最大的比特并用更新之后的码字重新进行译码。

        软判决译码是一种基于概率论的译码算法,通常需要与迭代译码进行结合,才能体现成译码性能的优势,基本算法是置信传播(BP)译码算法,它的实现比代数译码方法的复杂度高很多,但译码性能非常好。

        为了解决BP译码算法实现困难问题,在学术界牵起了优化算法的浪潮,对数域置信传播译码(LLR BP)算法、最小和(Min-Sum)译码算法、Normalized Min-Sum译码算法、Offset Min-Sum译码算法等相继涌现。

        在迭代译码的过程中,信息调度方式分为两种:泛滥式调度和分层式调度。泛滥式调度的特点在于每一次译码迭代过程中,首先计算从变量节点到校验节点的所有软信息,然后计算从校验节点到变量节点的所有软信息。分层调度的特点是在计算每层软信息时,更新此次迭代中的相关的节点信息,用于下一层的软信息计算。

        最小和译码(MS,Min-Sum)算法是以LLR BP算法译码为基础,对校验节点信息更新的表达式进行的简化,其余步骤均与LLR BP译码算法一致。
        比较LLR BP译码算法和Min-Sum译码算法的校验节点信息更新过程,可以看到他们的主要区别在于LLR BP译码算法中的tanh(.)运算和加法运算在Min-Sum译码算法中被最小值和运算符号进行替换,MS译码简化了LLR BP译码算法,降低了译码算法的复杂度。


       将其均匀划分为256个子矩阵,分别表示为H0,H1,…,H255,每个子矩阵大小是18×36,H的其余部分同样按此划分,划分完后的结果如图1所示。

其中最小和算法的译码过程如下所示:

基于最小和算法的译码器设计的基本思想是:根据密度进化理论优化量化译码器参数,使量化译码器能达到最高的阈值。

整个算法的流程按如下步骤进行:

第一:初始化各个变量节点的值,赋初值;

第二:判断迭代次数是否已经超过了预设的最大迭代次数,如果超过,则迭代结束;

第三:每次迭代,变量节点的信息进行更新;

第四:计算每个变量节点Vn上的L值

第五:对每个变量节点Vn,对L值进行判决,输出序列Vk,从而结束译码;

最小和算法在本质上和BP译码算法相似,此外,整个算法采用对数域进行。

以上就是整个译码算法的基本流程。

       min-sum译码算法,和BP译码算法相似,即简化了原来的指数运算过程,从而减少译码器的计算量,min-sum算法来进行迭代更新, 此更新分为校验节点更新和变量节点更新。其迭代译码步骤分为两步。整个系统的总体结构如下所示:

3.MATLAB/Verilog核心程序

......................................................................
for iteration=1:50
    iteration
    %horizontal step
    %横向步骤:由信息节点的先验概率按置信传播算法得出各校验节点的后验概率。
    for i=1:h1num %计算概率差
        newh(h1i(i),h1j(i)).dqmn=newh(h1i(i),h1j(i)).qmn0-newh(h1i(i),h1j(i)).qmn1;
    end

    for i=1:rows
        colind=find(h1i==i);%统计与校验节点相联系的第i行的数据位个数
        colnum=length(colind);
        for j=1:colnum
            drmn=1;
            for k=1:colnum
                if k~=j
                    drmn=drmn*newh(i,h1j(colind(k))).dqmn;
                end
            end
            newh(i,h1j(colind(j))).rmn0=(1+drmn)/2;
            newh(i,h1j(colind(j))).rmn1=(1-drmn)/2;
        end
    end

    %vertical step
    %纵向步骤:由校验节点的后验概率推算出信息节点的后验概率。
    for j=1:cols
        rowind=find(h1j==j);
        rownum=length(rowind);
        for i=1:rownum
            prod_rmn0=1;
            prod_rmn1=1;
            for k=1:rownum
                if k~=j
                    prod_rmn0=prod_rmn0*newh(h1i(rowind(k)),j).rmn0;
                    prod_rmn1=prod_rmn1*newh(h1i(rowind(k)),j).rmn1;
                end
            end
            const1=pl0(j)*prod_rmn0;
            const2=pl1(j)*prod_rmn1;
            newh(h1i(rowind(i)),j).alphamn=1/( const1 + const2 ) ;
            newh(h1i(rowind(i)),j).qmn0=newh(h1i(rowind(i)),j).alphamn*const1;
            newh(h1i(rowind(i)),j).qmn1=newh(h1i(rowind(i)),j).alphamn*const2;
            %update pseudo posterior probability
            %更新伪后验概率
            const3=const1*newh(h1i(rowind(i)),j).rmn0;
            const4=const2*newh(h1i(rowind(i)),j).rmn1;
            alpha_n=1/(const3+const4);
            newh(h1i(rowind(i)),j).qn0=alpha_n*const3;
            newh(h1i(rowind(i)),j).qn1=alpha_n*const4;
            %tentative decoding
            %译码尝试,对信息节点的后验概率作硬判决
            if newh(h1i(rowind(i)),j).qn1>0.5
                vhat(j)=1;
            else
                vhat(j)=0;
            end
        end
    end
    
    if mul_GF2(vhat,H.')==zero
    %如果判决条件满足,译码结束,否则继续迭代
        break;
    end
end

uhat = extract_mesg(vhat,rearranged_cols);

end


function [C]=mul_GF2(A,B)

C=A*B;
C=mod(C, 2);

end
............................................................................
reg[12:0]cnt;
reg[35:0]o_read_select;
reg      o_read_enable;
reg[7:0] o_address;

reg[35:0]dout_tmp_r;


assign Max_lens = i_code_rate ? 13'd6911: 13'd4607;
assign finishs = (cnt == Max_lens);

always @(posedge i_sys_clk or negedge i_sys_rst)
begin 
     if(!i_sys_rst)
     cnt <=  13'h0;
else if(i_state[3])
     begin
	       if(finishs)
	       cnt <=  13'h0;
     else
	       cnt <=  cnt + 1'b1;
     end
end

llr_values llr_values_u(
								.i_clk    (i_sys_clk),
								.i_address(cnt),
								.o_values (dout_tmp)
							  );

always @(posedge i_sys_clk or negedge i_sys_rst)
begin
     if(!i_sys_rst)
     o_address <= 8'd0;
else
     o_address <= dout_tmp[13:6];	    
end

always @(posedge i_sys_clk or negedge i_sys_rst)
begin
     if(!i_sys_rst)
     o_read_select <= 36'd0;
else if(i_state[3])
	  o_read_select <= dout_tmp_r;
else
	  o_read_select <= 36'd0;
end

always @ (posedge i_sys_clk or negedge i_sys_rst)
begin
     if(!i_sys_rst)
     o_read_enable <= 1'b0;
else 
	  o_read_enable <= i_state[3];
end


always @(dout_tmp[5:0])
case(dout_tmp[5:0])
	6'd0  : dout_tmp_r = 36'b0000_0000_0000_0000_0000_0000_0000_0000_0001;	
	6'd1  : dout_tmp_r = 36'b0000_0000_0000_0000_0000_0000_0000_0000_0010;	
	6'd2  : dout_tmp_r = 36'b0000_0000_0000_0000_0000_0000_0000_0000_0100;	
	6'd3  : dout_tmp_r = 36'b0000_0000_0000_0000_0000_0000_0000_0000_1000;	
	
	6'd4  : dout_tmp_r = 36'b0000_0000_0000_0000_0000_0000_0000_0001_0000;		
	6'd5  : dout_tmp_r = 36'b0000_0000_0000_0000_0000_0000_0000_0010_0000;	
	6'd6  : dout_tmp_r = 36'b0000_0000_0000_0000_0000_0000_0000_0100_0000;		
	6'd7  : dout_tmp_r = 36'b0000_0000_0000_0000_0000_0000_0000_1000_0000;	
	
	6'd8  : dout_tmp_r = 36'b0000_0000_0000_0000_0000_0000_0001_0000_0000;	
	6'd9  : dout_tmp_r = 36'b0000_0000_0000_0000_0000_0000_0010_0000_0000;	
	6'd10 : dout_tmp_r = 36'b0000_0000_0000_0000_0000_0000_0100_0000_0000;	
	6'd11 : dout_tmp_r = 36'b0000_0000_0000_0000_0000_0000_1000_0000_0000;	
	
	6'd12 : dout_tmp_r = 36'b0000_0000_0000_0000_0000_0001_0000_0000_0000;	
	6'd13 : dout_tmp_r = 36'b0000_0000_0000_0000_0000_0010_0000_0000_0000;		
	6'd14 : dout_tmp_r = 36'b0000_0000_0000_0000_0000_0100_0000_0000_0000;	
	6'd15 : dout_tmp_r = 36'b0000_0000_0000_0000_0000_1000_0000_0000_0000;	
	
	6'd16 : dout_tmp_r = 36'b0000_0000_0000_0000_0001_0000_0000_0000_0000;	
	6'd17 : dout_tmp_r = 36'b0000_0000_0000_0000_0010_0000_0000_0000_0000;	
	6'd18 : dout_tmp_r = 36'b0000_0000_0000_0000_0100_0000_0000_0000_0000;	
	6'd19 : dout_tmp_r = 36'b0000_0000_0000_0000_1000_0000_0000_0000_0000;	
	
	6'd20 : dout_tmp_r = 36'b0000_0000_0000_0001_0000_0000_0000_0000_0000;	
	6'd21 : dout_tmp_r = 36'b0000_0000_0000_0010_0000_0000_0000_0000_0000;	
	6'd22 : dout_tmp_r = 36'b0000_0000_0000_0100_0000_0000_0000_0000_0000;	
	6'd23 : dout_tmp_r = 36'b0000_0000_0000_1000_0000_0000_0000_0000_0000;	
	
	6'd24 : dout_tmp_r = 36'b0000_0000_0001_0000_0000_0000_0000_0000_0000;	
	6'd25 : dout_tmp_r = 36'b0000_0000_0010_0000_0000_0000_0000_0000_0000;	
	6'd26 : dout_tmp_r = 36'b0000_0000_0100_0000_0000_0000_0000_0000_0000;	
	6'd27 : dout_tmp_r = 36'b0000_0000_1000_0000_0000_0000_0000_0000_0000;	
	
	6'd28 : dout_tmp_r = 36'b0000_0001_0000_0000_0000_0000_0000_0000_0000;	
	6'd29 : dout_tmp_r = 36'b0000_0010_0000_0000_0000_0000_0000_0000_0000;	
	6'd30 : dout_tmp_r = 36'b0000_0100_0000_0000_0000_0000_0000_0000_0000;	
	6'd31 : dout_tmp_r = 36'b0000_1000_0000_0000_0000_0000_0000_0000_0000;	
	
	6'd32 : dout_tmp_r = 36'b0001_0000_0000_0000_0000_0000_0000_0000_0000;	
	6'd33 : dout_tmp_r = 36'b0010_0000_0000_0000_0000_0000_0000_0000_0000;	
	6'd34 : dout_tmp_r = 36'b0100_0000_0000_0000_0000_0000_0000_0000_0000;	
	6'd35 : dout_tmp_r = 36'b1000_0000_0000_0000_0000_0000_0000_0000_0000;	
	
	default:dout_tmp_r = 36'b0000_0000_0000_0000_0000_0000_0000_0000_0000;	
endcase


endmodule
14_033_m

4.完整算法代码文件

V

猜你喜欢

转载自blog.csdn.net/hlayumi1234567/article/details/129625620
今日推荐