精华内容
下载资源
问答
  • 维特比译码

    2016-03-21 23:58:47
    完整的维特比译码的教学资料,并结合详细的实例进行解释,看了就能完全掌握维特比译码的知识
  • 卷积编码及维特比译码-卷积编码及维特比译码.rar 卷积编码及维特比译码相关文献 1.bmp
  • 维特比译码器的Verilog设计(一)----维特比译码原理关于维特比译码1.编码过程中的状态转移和网格图表示如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、...

    近期由于需要,在学习实现一个维特比译码器,以便对卷积码进行解码。在学习过程中有些心得体会在这里记录一下。

    关于维特比译码

    首先,维特比译码算法是一种最大似然译码算法,是最初由Viterbi在1967年提出的,用于对卷积码进行译码,关于其译码的过程,也并不复杂,通过网格图的方法可以快速地理解,只不过在实际实现的过程中有些问题需要引起重视。我们主要从以下几个角度来进行。

    1. 编码过程中的状态转移和网格图
    2. 最大似然译码思路
    3. 硬判决与软判决的路径度量
    4. 译码过程
    5. 总结

    1.编码过程中的状态转移和网格图表示

    为了在之后借助网格图对译码过程进行理解,我们先以卷积码编码过程为例,简单回顾一下编码过程中的状态转移与网格图表示。
    一个简单的卷积码编码器如下图所示
    在这里插入图片描述
    如上图所示的一个(3,1,3)卷积码编码器,待编码的数据输入至移位寄存器,然后通过模二加法器,得到三位的输出数据。我们将b2和b3视作状态,每个信元时间内输入的b1作为状态转换条件,控制4个状态之间的转换;这样,由于共有4个状态,每个状态根据当前信元时间内输入的比特可以转换为另外两个状态,每次状态的转换对应着一次编码结果的输出,共有8种编码输出的可能。具体的状态转换图如下。
    在这里插入图片描述
    在使用状态图描述卷积码编码器时,一共需要2Nk12^{Nk-1}个状态,每个状态通过输入比特0或1来实现2Nk2^{Nk}种编码结果。
    此外,为了直观的了解整个编码过程,即每个信元时间内状态的转换情况与对应的编码,我们引入网格图,对于N*k=3的编码器来说,其状态只有4种,如下图所示。
    在这里插入图片描述
    在上图中,当最低位的移位寄存器依次输入比特"1 0 1"时,编码器经过了三次状态转换,依次输出了"100 101 110"编码结果,以此类推,我们只要得知了一个卷积编码器的结构参数和连接关系,就能够通过状态转换图判断编码情况。

    2.最大似然译码思路

    在了解了网格图在编码过程中的含义之后,我们仍然从网格图上的状态转移出发来理解最大似然译码。对于编码过程而言,我们可以根据输入的待编码的二进制序列来唯一的确定网格图上的一条路径;那么在译码的过程中,如果接收到接收码字之后,能在网格图上正确的得到路径编码时的路径,就能完成解码。那么对于这种译码方式,随之而来的我们需要解决两个问题
    1)如何在网格图上得到路径
    2)如何解决信道引入的差错
    那么接下来我们针对这两个问题进行讨论,首先,我们先假设信号经过理想信道,即传输的过程中没有出现差错,我们仍然以上图中的序列举例。在数据接收端,依次接收到了"100 101 110"三组码元,
    (1)在信元时刻1,从起始状态"00"开始有两种状态转移,各自对应的编码序列如下图所示。由于接收到的码元是100,因此该信元时刻对应的信息位为1
    在这里插入图片描述
    (2)在信元时刻2,从上一状态"10"开始有两种状态转移,各自对应的编码序列如下图所示。由于接收到的码元是101,因此该信元时刻对应的信息位为0
    在这里插入图片描述
    (3)在信元时刻3,从上一状态"01"开始有两种状态转移,各自对应的编码序列如下图所示。由于接收到的码元是110,因此该信元时刻对应的信息位为1

    在这里插入图片描述其实,整个译码的过程并不复杂,就是依次将每个接收码字在网格图中进行比较和选取。但是在实际的信道中,接收码字可能并不与当前状态的两条路径对应的编码码字相同,这时候,我们就需要引入对错误的度量,最终找到最小的错误的度量值所对应的路径,这条路径就是当前得出的最大似然路径,这条路径对应的信息位也最有可能正确,这就是最大似然译码的大致思路。对于“错误”的度量,我们通常有两种方式,即硬判决和软判决,它们对应着不同的接收机结构

    3.硬判决与软判决路径度量

    首先介绍一下硬判决和软判决,关于这两者最直接的区别在于,使用硬判决时,我们将接收到的电压信号通过一个固定的门限进行判定,得到离散的0和1的数字结果,直接进入译码器进行译码操作;而对于软判决而言,接收机将采样之后的电压信号进行量化,然后将结果送入译码器进行译码操作。这二者相比较而言,由于硬判决在将接收到的电压信号转化为离散的0和1的过程中,损失掉了一部分信息,所以会导致相同信道条件下的译码正确率的下降,或者说在同等正确率的情况下,硬判决对应的噪声门限会高一些,但是它的好处也显而易见,成本低,结构简单。

    首先对于硬判决而言,我们采取两个码组之间的汉明距离来作为译码过程中的度量,即两个码组之间不同码元的个数。在译码过程中,我们引入两个变量:PM(path metric 路径度量)和BM(branch metric 分支度量);BM指的是每个状态在下一信元时刻转换为另外两个状态对应的两个分支路径上,预测的监督比特和接收到的监督比特之间的汉明距离,而PM指的是从初始状态至当前时刻的最可能路径上的所有预测的监督比特和接收到的监督比特之间的汉明距离。在维特比算法中,通过当前状态的PM和BM可以计算得到下一状态的PM。

    在软判决中,由于输入译码器的是被量化的信号电压值,所以我们使用接收到的监督码元对应的电压和预测的监督码元对应的电压值之差的平方和作为度量。若某一时刻接收到的信号电压值为v1,v2,…,vn,对应的预测的监督码元的电压值为u1,u2,…,un,则每个状态的分支度量为
    BM=i=1n(uivi)2 BM=\sum_{i=1}^{n}(u_i-v_i)^2
    对于码长为n的码组,其分支度量相当于n维空间中的欧几里得距离(便于记忆)。

    4.译码过程

    在译码的过程中,每个信元时间内,每个状态需要完成以下操作:
    (1)将分支度量与上一时刻状态的路径度量相加。
    (2)每一状态比较达到该状态的所有路径(每时刻每个状态只有两条这样的路径进行比较,因为只有两条来自前一时刻状态的分支)。
    (3)每一状态删除其余到达路径,保留最小度量的路径(称为幸存路径),该路径对应于错误最少的路径。

    接下来,我们以硬判决为例,借助分支度量BM和路径度量PM来分析整个译码的过程。我们仍用之前的例子加以说明。在某一时刻,接收机接收到了"100 111 110"三组码元。图中方框内的数字是该路径上的累计度量PM
    (1)在初始时刻,状态从"00"开始,该状态的累计路径度量为0,其余状态的累计路径度量为无穷大。在这里插入图片描述

    (2)在信元时刻1,所有的四个状态都要比较到达该状态的两个分支路径对应的度量值,选取较小的,留下该路径,如下图中的箭头即为留下的路径,称作幸存路径。
    在这里插入图片描述
    (3)在信元时刻2和3,每个状态进行着类似的操作,具体过程如下两幅图所示。
    在这里插入图片描述
    在这里插入图片描述
    在完成了所有状态的路径度量计算和路径选择之后,我们得到了最终四个状态的累计路径度量,可以看到第三个状态“10”的累计路径度量最小,所以可以从三个状态开始向前回溯,依次得到每个信元时刻对应的路径,如下图所示,这条路径是所有的可能路径中,产生的监督比特和接收到的监督比特差错最小的一条路径,因此根据最大似然路径译码,我们得出译码结果即为“101”。
    在这里插入图片描述

    5.总结

    至此,关于维特比译码的基本概念和流程大致如此,接下来我们会从硬件实现的角度通过Verilog来实现维特比编码器,在最后的总结中会深入讨论维特比编码的纠错性能和误码率的问题。

    由于本人能力水平有限,在文章中出现了什么错误或者纰漏,欢迎大家指出,另外如果有什么想法也欢迎讨论。

    展开全文
  • 217维特比译码器的FPGA设计

    万次阅读 2019-08-10 15:23:03
    二:viterbi译码器 ...分支度量计算单元是用来计算输入信号序列与卷积码各个可能输出信号序列的似然度量,维特比的似然准则就是在寻找具有最小距离的路径。若译码器采用硬判决译码时,分支度量计算采用...

    二:viterbi译码器

       (2,1,7)卷积码译码过程的总体结构可分为4个子模块,分别是分支度量模块,加比选蝶形运算单元,幸存路径存储单元和回溯译码单元。

    译码器的结构框图如图3所示。

     

    ·分支度量计算单元

        分支度量计算单元是用来计算输入信号序列与卷积码各个可能输出信号序列的似然度量,维特比的似然准则就是在寻找具有最小距离的路径。若译码器采用硬判决译码时,分支度量计算采用汉明距离,而采用软判决译码时,则是采用欧氏距离,即计算

    采用这种方法,与采用欧氏距离相比,对译码器的性能影响不大,该译码器的性能与采用欧氏距离的译码器性能差仅有0.1~0.2dB。

    由上式可以看出,如果采用8电平量化软判决方式,则此时路径度量值扩展为0到14,所以分支度量单元的输入是3比特数据,而输出则是4比特数据,这样硬件实现比较简单,可以减少硬件开销。

    其硬件实现电路结构如图4所示。由于本设计中采用的是(2,1,7)卷积码,所以一级中共有64个结点,需要64个分支度量计算单元,在实现中,采用了全并行的结构,这样在一个时钟周期内,可以更新所有64个结点的分支度量值。

    图4  分支度量计算单元的硬件电路结构

         其代码如下所示:

     

     

    assign  I = (en) ? Iin : 0;           //软判决输出模块

    assign  Q = (en) ? Qin : 7;          //软判决输出模块

    assign  recom = reset &en | start;

    wire [3:0] bm0,bm1,bm2,bm3;

    assign bm0=bm00(I,Q);//BM模块的输出

    assign bm1=bm01(I,Q);//BM模块的输出

    assign bm2=bm10(I,Q);//BM模块的输出

    assign bm3=bm11(I,Q);//BM模块的输出

     

     

    其仿真结果如下所示:

     

     

    ·加比选模块

     

     

     

    图5 ACS蝶形运算单元框图

        通过对加比选过程的分析,可以发现每次分支度量值都是非负的,因此分支累计度量值是不断增加的,由于在硬件实现中不能不考虑分支累计度量值的位宽,因为在硬件实现时该值需要存储在有限位宽的寄存器,所以需要对累计度量值进行归一化运算,以防止在累加过程中发生数据溢出,常用的控制方法是在每一步运算后首先找出所有状态节点的累计度量值中最小的一个,最后要减去该最小值,这种方法的主要缺点是每次加比选运算后都要对更新后的累加结果进行大量的比较操作,以找出最小累计度量值并将其置0,其余累计度量值与该最小值相减后得到的结果存储下来,以供下一次加比选操作使用。维特比译码器的译码输出只与度量值的相对值有关,每一步的路径度量值的最大值与最小值满足下面的关系:

     

     

    在本设计中采用补码加法运算方法可以自动完成归一化中的求模运算,其电路结构如图6所示,其中比较器电路结构如图7所示。

     

     

    ACS模块的代码如下所示:

    module ACS(

              din_a,   //BM模块

              gama_a,  //前一时刻64个状态的路径量度

              din_b,   //BM模块

              gama_b,  //前一时刻64个状态的路径量度

              gama_out,//路径量度输出

              sel      //幸存选择

              );

    input [3:0] din_a;

    input [3:0] din_b;

    input [7:0] gama_a;

    input [7:0] gama_b;

    output [7:0] gama_out;

    output sel;

    wire [7:0] m1,m2;

    wire cmp;

    wire flag;

    assign m1=gama_a+{4'b0,din_a};

    assign m2=gama_b+{4'b0,din_b};

    assign cmp=(m1[6:0]>m2[6:0])?1:0;//比较选择

    assign flag=m1[7]^m2[7];

    assign sel=flag^cmp;

    assign gama_out=(sel)?m2:m1; 

    endmodule

     

    其中我们需要调用ACS模块64次。

    ACS ACS_u1(

              .din_a(bm1),

                    .gama_a(PM1),

                    .din_b(bm2),

                    .gama_b(PM33),

                    .gama_out(pp1),

                    .sel(sel1)

                    );

    …………………………………..

    ACS ACS_u64(

               .din_a(bm1),

                     .gama_a(PM32),

                     .din_b(bm2),

                     .gama_b(PM64),

                     .gama_out(pp64),

                     .sel(sel64)

                     );

     

    ·幸存路径存储单元

        (2,1,7)卷积码每向前译码一位要产生64位的幸存路径,所以我们用一个64位宽的RAM来存储ACS产生的幸存路径信息。在回溯的过程中,也就是从RAM中读出幸存路径值来决定回溯的路径。

    //最小路径量度状态选择

    assign  survival={

                                  sel1 ,sel2 ,sel3 ,sel4 ,sel5 ,sel6 ,sel7 ,sel8 ,sel9 ,sel10,sel11,sel12,sel13,sel14,sel15,

                      sel16,sel17,sel18,sel19,sel20,sel21,sel22,sel23,sel24,sel25,sel26,sel27,sel28,sel29,sel30,

                                  sel31,sel32,sel33,sel34,sel35,sel36,sel37,sel38,sel39,sel40,sel41,sel42,sel43,sel44,sel45,

                                  sel46,sel47,sel48,sel49,sel50,sel51,sel52,sel53,sel54,sel55,sel56,sel57,sel58,sel59,sel60,

                                  sel61,sel62,sel63,sel64

                                 };

    ·回溯译码单元

        回溯译码单元是本设计的重点,其回溯单元框图如图8所示:

     

     

    图8  回溯单元结构图

    在本设计中回溯译码单元如图9,回溯译码共用4块32*64bit的RAM,在回溯译码单元有两个计数器,其中模32加法计数器产生RAM的写地址add32,模32减法计数器产生回溯过程中RAM的读地址sub32。

    另外还有一个模4的计数器产生四块RAM的读写控制信号,当译码开始后,幸存路径首先存储在第一块RAM中,然后存储第二块RAM,当进行到第64个时钟周期时,第二块RAM存储完毕,然后开始存储第三块RAM,同时从第二块RAM中开始回溯,当运行到96个时钟周期时,第三块RAM存储完毕,第二块RAM也回溯完毕,然后开始存储第四块RAM,同时第一块RAM 开始回溯,这时回溯出的信息就是正确的信息,这样循环执行,可以保证四块RAM中有两块RAM在回溯过程中。

     

     

    一块RAM在存储幸存路径。其中四块RAM的输出对应一个64选1的MUX,并且它的输出还要经过一个2选1的MUX选择输出,然后再输入到回溯单元,回溯单元通过一个简单的移位操作,回溯到前一个状态,回溯输出通过一个4选1的MUX选择输出的就是译码输出,并写入到32bit的寄存器中,每32时钟周期一次输出32bit的回溯信息结果,我们这里存储下32bit的回溯信息后,然后每个时钟周期输出一个比特的译码信息。在设计中卷积码的译码回溯深度最小为32,最大为64。

    //幸存信息管理      

    sram sram_u1(

                   .address (add1),

                   .clock   (clk),

                   .data    (survival),

                   .wren    (wen[0]),

                   .q       (dout1)

                   );  

    sram sram_u2(

                   .address (add2),

                   .clock   (clk),

                   .data    (survival),

                   .wren    (wen[1]),

                   .q       (dout2)

                   );

    sram sram_u3(

                   .address (add3),

                   .clock   (clk),

                   .data    (survival),

                   .wren    (wen[2]),

                   .q       (dout3)

                   );

    sram sram_u4(

                   .address (add4),

                   .clock   (clk),

                   .data    (survival),

                   .wren    (wen[3]),

                   .q       (dout4)

                   );

       reg val_out;

       reg valid;

           always @(posedge clk or negedge reset)

           begin

               if(!reset)

               begin

                         val_out <= 0;

                         valid   <= 0;

                   end

           else

                   begin

                         val_out  <= val;

                         valid    <= val_out;

                   end      

           end

           reg [2:0] count1;

           always @(posedge clk or negedge reset)

           begin

                if(!reset)

                count1 <= 0;

           else if(val_out)

                   count1 <= count1 + 1;

           else

                count1 <= count1;

        end

           reg [2:0] count;

           always @(posedge clk or negedge reset)

           begin

                if(!reset)

                count <= 0;

           else if(val_out)

                begin

                        if((count<=3)&(count1==0))

                           count <= count + 1;

                   else if((count==4)&(count1==0))

                           count <= 1;

                   end

           else

                count <= count;

           end

           reg [31:0] decoke_out;

           always @(posedge clk or negedge reset)

           begin

                if(!reset)

                   decoke_out <= 0;

           else if((val_out)&(count==0)&(count1==0))

                decoke_out <= decoke;

           else if((val_out)&(count==4)&(count1==0))

                decoke_out <= decoke;

           else

                decoke_out <= decoke_out;

           end

       function [7:0] dout;

         input [31:0] dec;

         input [2:0] sel;

         begin

          case(sel)

            3'b001:dout=dec[31:24];

            3'b010:dout=dec[23:16];

            3'b011:dout=dec[15:8];

            3'b100:dout=dec[7:0];

            default:dout=0;

          endcase

         end

       endfunction       

       assign dataout=val_out?dout(decoke_out,count):0;

       assign dataout=val_out?dout(decoke_out,count):0;

     

    展开全文
  • 维特比译码

    2013-07-19 11:47:26
    维特比译码器程序,主要是基于FPGA的维特比译码器。包含顶层文件
  • hslogic算法仿真-维特比译码
  • % 将经过信道的编码序列转换为以需要译码的个数为行数,以n为列数的矩阵 survivor_state=zeros(number_of_states,depth_of_trellis+1); % 4行,7列 (初始化) % 开始无尾信道输出解码 for i=1:depth_of_trellis-L+1 ...

    213

    function [mybit,decoder_output_table,BER,right_channel_output,channel_output_table,cumulated_metric_table,survivor_state]=viterbi_2_1_3
    changdu=input('Please input the length of the code sequence\n\n');   
    mybit=fix(rand(1,changdu)+0.5);

    %  (2,1,3)卷积编码
    G=[1 1 1;1 0 1];                                                                          %  (2,1,3)生成矩阵G=[1 1 1;1 0 1]; 
    k=1;
    right_channel_output=cnv_encd(mybit);
    lgth=length(right_channel_output);
    BER=zeros(1,lgth);
    cumulated_metric_table=zeros(1,lgth);
    decoder_output_table=zeros(lgth,lgth/2-2);
    channel_output_table=zeros(lgth,lgth);

    %  模拟信道误码
    for z=1:lgth                                                                             % 产生随机误码                                                                           

    %    channel=zeros(1,lgth);                                                              % 通过改变lgth的值 ,调整误码个数                                                 
    %    for i=1:z:lgth
    %        channel(i)=1;
    %    end

    if z==1
       channel=zeros(1,lgth);  
    else
        channel=fix(rand(1,lgth)+0.2);                                                       % 0.5可改
    end
    channel_output=mod(right_channel_output+channel,2);
    channel_output_table(z,:)=channel_output;                                                % 数据转移
    n=size(G,1);                                                                             % n=G的行数     

    %  检查大小
    if rem(size(G,2),k)~=0
        error('Size of G and k do not agree')                                                % 存在合理的约束长度
    end
    if rem(size(channel_output,2),n)~=0
        error('channel output not of the right size')                                        % 经过信道后,进入译码器前,卷积编码的个数合理
    end
    L=size(G,2)/k;                                                                           % 约束长度=寄存器个数+1
    number_of_states=2^((L-1)*k);                                                            % 状态数

    %  产生状态转移矩阵、输出矩阵和输入矩阵
    for j=0:number_of_states-1                                                               % 对(2,1,3) j=0,1,2,3
        for l=0:2^k-1                                                                        % l=0,1
            [next_state,memory_contents]=nxt_stat(j,l,L,k);
            input(j+1,next_state+1)=l;
            branch_output=rem(memory_contents*G',2);                                         % 状态图上根据寄存器状态和input作出的编码
            nextstate(j+1,l+1)=next_state;                                                   % 生成矩阵,含有十进制表示的下一状态
            output(j+1,l+1)=bin2deci(branch_output);                                         % 生成矩阵,含有十进制表示的卷积编码
        end
    end
    state_metric=zeros(number_of_states,2);                                                  % 4行,2列 (初始化)
    depth_of_trellis=length(channel_output)/n;                                               % 需要译码的个数   设为6
    channel_output_matrix=reshape(channel_output,n,depth_of_trellis);                        % 将经过信道的编码序列转换为以需要译码的个数为行数,以n为列数的矩阵
    survivor_state=zeros(number_of_states,depth_of_trellis+1);                               % 4行,7列 (初始化)

    %  开始无尾信道输出解码
    for i=1:depth_of_trellis-L+1                                                             % i=1,2,3,4
        flag=zeros(1,number_of_states);                                                      % 1行,4列 (初始化)
        if i<=L
            step=2^((L-i)*k);                                                                % i=1,2,3  step= 4,2,1
        else
            step=1;                                                                          % i=4  step=1
        end
        for j=0:step:number_of_states-1                                                      % i=1 j=0;i=2 j=0, 2;i=3,4 j=0,1,2,3 
            for l=0:2^k-1                                                                    % l=0,1
                branch_metric=0;                                                             % 初始化
                binary_output=deci2bin(output(j+1,l+1),n);                                   % 将此时刻十进制的编码结果用二进制表示
                for ll=1:n                                                                   % ll=1,2
                    branch_metric=branch_metric+metric(channel_output_matrix(ll,i),...
                        binary_output(ll));                                                  % 将此时刻经过信道的编码与理论编码比较,得到分支度量值
                end
                if ((state_metric(nextstate(j+1,l+1)+1,2)>state_metric(j+1,1)...
                        +branch_metric)|flag(nextstate(j+1,l+1)+1)==0)
                    state_metric(nextstate(j+1,l+1)+1,2)=state_metric(j+1,1)+branch_metric;
                    survivor_state(nextstate(j+1,l+1)+1,i+1)=j;
                    flag(nextstate(j+1,l+1)+1)=1;
                end
            end
        end
        state_metric=state_metric(:,2:-1:1);
    end

    %  开始有尾信道输出解码
    for i=depth_of_trellis-L+2:depth_of_trellis
        flag=zeros(1,number_of_states);
        last_stop=number_of_states/(2^((i-depth_of_trellis+L-2)*k));
        for j=0:last_stop-1
            branch_metric=0;
            binary_output=deci2bin(output(j+1,1),n);
            for ll=1:n
                branch_metric=branch_metric+metric(channel_output_matrix(ll,i),binary_output(ll));
            end
            if ((state_metric(nextstate(j+1,1)+1,2)>state_metric(j+1,1)...
                    +branch_metric)|flag(nextstate(j+1,1)+1)==0)
                state_metric(nextstate(j+1,1)+1,2)=state_metric(j+1,1)+branch_metric;
                survivor_state(nextstate(j+1,1)+1,i+1)=j;
                flag(nextstate(j+1,1)+1)=1;
            end
        end
        state_metric=state_metric(:,2:-1:1);
    end

    %  从最佳路径中产生解码
    state_sequence=zeros(1,depth_of_trellis+1);
    state_sequence(1,depth_of_trellis)=survivor_state(1,depth_of_trellis+1);
    for i=1:depth_of_trellis
        state_sequence(1,depth_of_trellis-i+1)=survivor_state((state_sequence(1,depth_of_trellis+2-i)...
            +1),depth_of_trellis-i+2);
    end
    decoder_output_matrix=zeros(k,depth_of_trellis-L+1);
    for i=1:depth_of_trellis-L+1
        dec_output_deci=input(state_sequence(1,i)+1,state_sequence(1,i+1)+1);
        dec_output_bin=deci2bin(dec_output_deci,k);
        decoder_output_matrix(:,i)=dec_output_bin(k:-1:1)';
    end
    decoder_output=reshape(decoder_output_matrix,1,k*(depth_of_trellis-L+1));
    decoder_output_table(z,:)=decoder_output;                                                % 数据转移
    cumulated_metric=state_metric(1,1);
    cumulated_metric_table(z)=cumulated_metric;                                              % 数据转移
    BER(z)=Bit_Error_Rate(mybit,decoder_output);
    %  BER1(z)=Bit_Error_Rate(right_channel_output,channel_output)
    end

    %----------------------------------------subfunction Bit_Error_Rate-------------------------------------------------

    function y=Bit_Error_Rate(a,b)
    y=nnz(mod(a+b,2))/length(a);

    %-------------------------------------------subfunction cnv_encd----------------------------------------------------

    function the_output1=cnv_encd(mybit)       %  the_output1为完全正确译码,编码输出结果多出2*移位寄存器个数;  the_output2为不完全译码,译码结果与编码之前的原始信息差移位寄存器的个数
    g=[1 1 1 0 1 1];
    n=length(mybit);
    juzhen=zeros(n,(n-1)*2+6);                 %  多余个数=2*约束长度-2=2*移位寄存器个数
    for i=1:n
        juzhen(i,(i-1)*2+1:(i-1)*2+6)=g;
    end
    the_output=mybit*juzhen;
    the_output=mod(the_output,2);
    the_output1=the_output;                    %  需要时可以把分号去掉,看完全编码和不完全编码的结果
    the_output2=the_output(1,1:n*2);


    % survivor_state的每一行对应每一个状态,每一列对应每一个时刻,它的数值为从前一时刻到这一时刻、进入到所在的行状态所保留的幸存路径的来源状态   
    % cumulated_metric为译码结果所对应的编码序列与信道输入含误码序列的汉明距离
                   
     

    217

    clc;
    clear;
    close all

    mybit=fix(rand(1,215)+0.5)
    lgth = 215;
    %  (2,1,7)卷积编码 
    G=[1 1 1 1 0 0 1;1 0 1 1 0 1 1];                                                       %  (2,1,7)生成矩阵G=[1 1 1 1 0 0 1;1 0 1 1 0 1 1]; 
    k=1;
    right_channel_output=cnv_encd(mybit); 
    BER=zeros(1,lgth);
    cumulated_metric_table=zeros(1,lgth);
    decoder_output_table=zeros(lgth,lgth/2-6);
    channel_output_table=zeros(lgth,lgth);

    %  模拟信道误码
    for z=1:lgth                                                                             % 产生随机误码                                                                           

    %    channel=zeros(1,lgth);                                                              % 通过改变lgth的值 ,调整误码个数                                                 
    %    for i=1:z:lgth
    %        channel(i)=1;
    %    end

    if z==1
       channel=zeros(1,lgth);  
    else
        channel=fix(rand(1,lgth)+0.2);                                                       % 0.5可改
    end
    channel_output=mod(right_channel_output+channel,2);
    channel_output_table(z,:)=channel_output;                                                % 数据转移
    n=size(G,1);                                                                             % n=G的行数     

    %  检查大小
    if rem(size(G,2),k)~=0
        error('Size of G and k do not agree')                                                % 存在合理的约束长度
    end
    if rem(size(channel_output,2),n)~=0
        error('channel output not of the right size')                                        % 经过信道后,进入译码器前,卷积编码的个数合理
    end
    L=size(G,2)/k;                                                                           % 约束长度=寄存器个数+1
    number_of_states=2^((L-1)*k);                                                            % 状态数

    %  产生状态转移矩阵、输出矩阵和输入矩阵
    for j=0:number_of_states-1                                                               % 对(2,1,3) j=0,1,2,3
        for l=0:2^k-1                                                                        % l=0,1
            [next_state,memory_contents]=nxt_stat(j,l,L,k);
            input(j+1,next_state+1)=l;
            branch_output=rem(memory_contents*G',2);                                         % 状态图上根据寄存器状态和input作出的编码
            nextstate(j+1,l+1)=next_state;                                                   % 生成矩阵,含有十进制表示的下一状态
            output(j+1,l+1)=bin2deci(branch_output);                                         % 生成矩阵,含有十进制表示的卷积编码
        end
    end
    state_metric=zeros(number_of_states,2);                                                  % 4行,2列 (初始化)
    depth_of_trellis=length(channel_output)/n;                                               % 需要译码的个数   设为6
    channel_output_matrix=reshape(channel_output,n,depth_of_trellis);                        % 将经过信道的编码序列转换为以需要译码的个数为行数,以n为列数的矩阵
    survivor_state=zeros(number_of_states,depth_of_trellis+1);                               % 4行,7列 (初始化)

    %  开始无尾信道输出解码
    for i=1:depth_of_trellis-L+1                                                             % i=1,2,3,4
        flag=zeros(1,number_of_states);                                                      % 1行,4列 (初始化)
        if i<=L
            step=2^((L-i)*k);                                                                % i=1,2,3  step= 4,2,1
        else
            step=1;                                                                          % i=4  step=1
        end
        for j=0:step:number_of_states-1                                                      % i=1 j=0;i=2 j=0, 2;i=3,4 j=0,1,2,3 
            for l=0:2^k-1                                                                    % l=0,1
                branch_metric=0;                                                             % 初始化
                binary_output=deci2bin(output(j+1,l+1),n);                                   % 将此时刻十进制的编码结果用二进制表示
                for ll=1:n                                                                   % ll=1,2
                    branch_metric=branch_metric+metric(channel_output_matrix(ll,i),...
                        binary_output(ll));                                                  % 将此时刻经过信道的编码与理论编码比较,得到分支度量值
                end
                if ((state_metric(nextstate(j+1,l+1)+1,2)>state_metric(j+1,1)...
                        +branch_metric)|flag(nextstate(j+1,l+1)+1)==0)
                    state_metric(nextstate(j+1,l+1)+1,2)=state_metric(j+1,1)+branch_metric;
                    survivor_state(nextstate(j+1,l+1)+1,i+1)=j;
                    flag(nextstate(j+1,l+1)+1)=1;
                end
            end
        end
        state_metric=state_metric(:,2:-1:1);
    end

    %  开始有尾信道输出解码
    for i=depth_of_trellis-L+2:depth_of_trellis
        flag=zeros(1,number_of_states);
        last_stop=number_of_states/(2^((i-depth_of_trellis+L-2)*k));
        for j=0:last_stop-1
            branch_metric=0;
            binary_output=deci2bin(output(j+1,1),n);
            for ll=1:n
                branch_metric=branch_metric+metric(channel_output_matrix(ll,i),binary_output(ll));
            end
            if ((state_metric(nextstate(j+1,1)+1,2)>state_metric(j+1,1)...
                    +branch_metric)|flag(nextstate(j+1,1)+1)==0)
                state_metric(nextstate(j+1,1)+1,2)=state_metric(j+1,1)+branch_metric;
                survivor_state(nextstate(j+1,1)+1,i+1)=j;
                flag(nextstate(j+1,1)+1)=1;
            end
        end
        state_metric=state_metric(:,2:-1:1);
    end

    %  从最佳路径中产生解码
    state_sequence=zeros(1,depth_of_trellis+1);
    state_sequence(1,depth_of_trellis)=survivor_state(1,depth_of_trellis+1);
    for i=1:depth_of_trellis
        state_sequence(1,depth_of_trellis-i+1)=survivor_state((state_sequence(1,depth_of_trellis+2-i)...
            +1),depth_of_trellis-i+2);
    end
    decoder_output_matrix=zeros(k,depth_of_trellis-L+1);
    for i=1:depth_of_trellis-L+1
        dec_output_deci=input(state_sequence(1,i)+1,state_sequence(1,i+1)+1);
        dec_output_bin=deci2bin(dec_output_deci,k);
        decoder_output_matrix(:,i)=dec_output_bin(k:-1:1)';
    end
    decoder_output=reshape(decoder_output_matrix,1,k*(depth_of_trellis-L+1));
    decoder_output_table(z,:)=decoder_output;                                                % 数据转移
    cumulated_metric=state_metric(1,1);
    cumulated_metric_table(z)=cumulated_metric;                                              % 数据转移
     
    end

    %----------------------------------------subfunction Bit_Error_Rate-------------------------------------------------

     

    %-------------------------------------------subfunction cnv_encd----------------------------------------------------

    D30
                    
                    
                
        

     

    展开全文
  • 符号软判决维特比译码,郭桂竹,洪小斌,介绍符号软判决维特比译码原理,分析其性能,将其与传统软判决维特比译码对比并进行了仿真,符号软判决维特比译码误码率稍高于传
  • 维特比译码verilog程序

    2018-04-22 19:14:45
    (2,1,3)卷积码的维特比译码程序,verilog语言编写,模块可以直接使用
  • 本文在综合了国内外近年来在维特比译码算法以及相关实现技术研究进展的基础上,从降低复杂度和功耗的角度,自主独立完成了维特比译码器行为级设计,并下载到Xinlix公司的Virtxell系列xcZvl000器件中,经验证功能正确...
  • 维特比译码算法

    2014-04-03 20:49:56
    可用于卷积吗译码的维特比译码,参考的书上的,可以用于硬盘决也可以用于软判决
  • Edge系统维特比译码模块设计,吴强,胡春静,维特比译码作为卷积的逆过程,其设计及实现是物理层开发的不可或缺的一环。本文在基于picoChip这种芯片上介绍Edge系统维特比译码的模
  • 针对60 GHz无线个域网,提出了一种平衡加选延比式维特比译码架构,打破了原有维特比译码器的速率瓶颈。基于该推荐架构,实现了一种8路并行基-2(3,1,7)维特比译码器。在TSMC.13 CMOS工艺下,该译码器以0.104 nJ/bit和...
  • 维特比译码知识

    2012-05-11 09:41:56
    详细讲述了维特比译码的相关内容,讲述了卷积编码的基本方法。
  • 这是一个针对卷积码的维特比译码器.开发环境为MATLAB.
  • 针对维特比译码器译码过程中速度制约的问题,设计了一种结构优化的维特比译码器。该结构通过蝶形单元的直通互连,使得在状态转移过程中不需要对路径度量值进行大范围存储,简化了路径度量值的存储与读取逻辑。并且...
  • 卷积码编码 维特比译码 分组交织 去交织 编码输出至txt
  • 卷积码维特比译码

    2012-11-01 21:26:27
    卷积码的编码维特比译码算法,用malab写的
  • 卷积码译码之维特比译码算法(Viterbi decoding algorithm) 本文主要介绍了卷积码的一种译码方法——维特比译码(Viterbi decoding)。 关键词:卷积码译码 维特比译码算法 卷积码简介:点击打开链接 ==========...
    卷积码译码之维特比译码算法
    (Viterbi decoding algorithm)
           本文主要介绍了卷积码的一种译码方法——维特比译码(Viterbi decoding)。
           关键词:卷积码译码 维特比译码算法 

           卷积码简介:点击打开链接

           ============================================================== 

           目录结构:

           1、维特比译码简介

           2、维特比译码过程

            ==============================================================


    1、维特比译码简介

           Viterbi算法是由美国科学家Viterbi在1967年提出的卷积码的概率译码算法,后来学者深入研究中证明Viterbi算法是基于卷积码网格图的最大似然译码算法。何为最大似然译码?在这里我们可以进行以下简单的理解:即根据已经接收到的信息,得到最接近编码码字的一种译码码字。得到这种码字使用的译码准则为最大似然译码。(如果觉得繁琐,第1部分可先略过)
           定义以下信号如图1所示:
           (1)发送端
           信源:u
           编码器输出编码码字:v
           (2)接收端
           译码器输入信息:r
           译码器输出:u_dec
     
    图1、经典通信系统
           译码器输出序列u_dec是u的一个估计值。译码器根据一定的译码规则,由接收序列r产生u_dec序列。由于信息序列u与码字v有对应关系,所以等效于译码器产生一个码字v的估值v’。当v‘=v是,u_dec=u。所以,当v‘不等于v时,译码出现错误。
           译码器的条件错误概率定义为:
           译码器的错误概率定义如下:
           其中接收序列r是译码前产生的,所以p(r)与译码规则无关。为了是译码错误概率最小的最佳的译码准则必须满足对所有的r使p(E|r)最小。所以有
           根据以上公式可知,对于给定的接收序列r,如果选择适合的v’,使p(v’=v|r)最大,则一定是最佳的。
    根据贝叶斯公式:
           如果发送码字的概率p(v)相同,p(r)又与译码规则无关,则
           所以,译码器如果可以选择一个估计值使得上式最大,则这种译码器称为最大似然译码。p(r|v)称为似然函数。对数似然函数则如下:
           如果码字不是等可能的,最大似然译码不一定是最佳的。在这种情况下,在决定哪个码字能使p(v|r)最大时,必须以概率p(v)对条件概率log p(ri|vi)加权。但在许多系统的接收端不知道发送码字的概率,所以最佳译码是不可能的,最大似然译码就成了可行的译码规则。
           转移概率p<1/2的二进制对此信道(BSC),接收序列r是二元的。对于卷积码,对数似然函数如下:
           其中d(r,v)是r和v之间的汉明距离。由于对所有的v,log p/(1-p) < 0且N log(1-p)是常熟,因此,对于BSC而言,最大似然译码是选择使r和v之间距离最小的v‘作为码字v。

    2、维特比译码过程

           由于最大似然译码等效于最小距离译码,因此具有最小d(r,v)累积值的路径就是log p(r|v)的最大路径,该路径被称为幸存路径。定义BM=d(ri,vi),称为分支度量值。PM称为最小累积度量值,是对所有分支度量值的累积。
           卷积码的编码过程与网格图中的一条路径对应,即输入序列的编码过程与网格图中的路径一一对应。当序列长度为x时,网格中有2^x条不同的路径和编码器的2^x种输入序列对应。在网格图中,每个状态转移的过程中都会输出编码码字。由于译码过程也建立在网格图中,并且从全零状态开始,从全零状态结束。所以,在每个符合输入的分支中,都可以计算出分支度量值。
           维特比译码算法步骤如下:
           (1)在j=L-1个时刻前,计算每一个状态单个路径分支度量。
           (2)第x-1个时刻开始,对进入每一个状态的部分路径进行计算,这样的路径有2^k条,挑选具有最大部分路径值的部分路径为幸存路径,删去进入该状态的其他路径,然后,幸存路径向前延长一个分支。
           (3)重复步骤(2)的计算、比较和判决过程。若输入接收序列长为(x+L-1)k,其中,后L-1段是人为加入的全0段,则译码进行至(x+ L-1)时刻为止。
           若进入某个状态的部分路径中,有两条部分路径值相等,则可以任选其一作为幸存路径。
           该译码算法的核心思想在于“加、比、选”,务必牢记,
           指的是将每个路径的分支度量进行累积。度量的方法有汉明距或者欧式距离等方法。
           指的是将到达节点的两条路径进行对比。

           指的是选出到达节点的两条路径中度量值小的一条路径作为幸存路径。

           

           以(2,1,2)卷积码例子说明维特比译码过程:
           输入数据:u = [1 1 0 1 1]
           编码码字:V = [11 01 01 00 01]
           接收码字:R = [11 01 01 10 01]

           (2,1,2)卷积码在以上算法中的参数,x=5,L=3,k=1,j从0开始计时。


           该卷积码的编码结构如下图所示:
     
    图2.(2,1,2)卷积码编码结构图

     
    图3. 各个分支的编码输出如图所示

     
    图4. 解码步骤1

           解码步骤(1),j=0,1,2这3个时刻中计算出每个路径的分支度量值和,即汉明距离,在图中以蓝色的数字表示。比如接收序列R中的第一个符合“11”,与第一回合的两条路径中的“00”,“11”的汉明距分别为2和0,改数字被标注在每条线对应的下方或附近。
           在每个状态节点具有两条路径时,译码算法才开始根据分支度量的大小选择幸存路径,再删除其他路径。该步骤如下图所示。
     
    图5. 第一个节点的幸存路径选择

           图5. 第一个节点的幸存路径选择,由于进入状态S0的两条路径的度量值3<4,所以选择度量值为3的图中红色线为幸存路径。
     
    图6. 第二个节点的幸存路径选择

     
    图7. 第三个节点的幸存路径选择

     
    图8. 第四个节点的幸存路径选择

           至此,第一次幸存路径选择完成,现在删除其他路径,将接下来的路径的分支度量值都标注在图中,如下图示。
     
    图9. 剩余译码路径的分支度量值计算标注

           以上图中在每个节点进行比较分支度量值比较,胜出的分支度量值被标注在状态节点的上方。
           以上图中在最后一个符号的译码得出一条分支度量值最小的路径,如下图所示,该条路径即译码的最佳路径。
     
    图10. 最佳路径输出
           根据该路径得出的译码输出为【11 01 01 00 01】与例子中编码码字V相同。该码字对应的输入数据可以根据以上最佳路径实线或者虚线读出,即【1 1 0 1 1】。

           网格图中的每一条路径的编码输出matlab代码如下所示:

    clc;close all;clear
    fid = fopen('test.txt','wt');
    d1  = 0;
    d2  = 0;
    N   = 5;
    for i = 0:31
        data = dec2bin(i,N);
        for j = 1:N
            %output calculation
            x   = str2num(data(j)); 
            y1  = mod(x + d1 + d2,2);
            y2  = mod(x + d2,2);
            y   = [y1,y2];
            %shift
            d2 = d1;
            d1 = x;
            fprintf(fid,'%d%d ',y1,y2);
        end
        fprintf(fid,' %s\n',dec2bin(i,5));
        d1 = 0;
        d2 = 0;
    end
    fclose('all')



    展开全文
  • matlab 关于维特比译码的误码率的计算 并且有软硬判决两种方式 和未卷积的码
  • 卷积码的编码和维特比译码程序,使用C/C++编写,可在Ubuntu和Windows操作系统上运行,经过修改可在嵌入式系统中运行。适合新手学习卷积码编码和维特比译码算法,也可供工程师参考。
  • 维特比译码 加比选

    2011-04-04 11:14:20
    维特比译码的硬件实现方案,采用加比选算法
  • matlab实现的维特比译码,已用数字通信第二版实例验证通过
  • 基于matlab的卷积码编码程序 可直接运行 并有维特比译码程序 可以实现信道卷积码编译码过程
  • 维特比译码与MAP译码的比较

    千次阅读 2019-04-26 16:32:27
    维特比译码:Viterbi算法是由美国科学家Viterbi在1967年提出的卷积码的概率译码算法,后来学者深入研究中证明Viterbi算法是基于卷积码网格图的最大似然译码算法。接收到的符号首先经过解调器判决,输出0、1 码,然后...

空空如也

空空如也

1 2 3 4 5 ... 9
收藏数 179
精华内容 71
关键字:

维特比译码