您的位置:首页 > 编程语言 > MATLAB

卷积编码的原理与MATLAB及FPGA实现

2016-05-22 18:35 465 查看
        卷积编码是现代数字通信系统中常见的一种前向纠错码,区别于常规的线性分组码,卷积编码的码字输出不仅与当前时刻的信息符号输入有关,还与之前输入的信息符号有关。下面,笔者将简要分析一下卷积编码的原理以及相应的实现方法。忽然想起笔者开始写CSDN博客的初衷,一者为了总结之前做过的东西,记录一些关键点,防止以后遗忘,依稀记得老师曾言,好记性比不过烂笔头,道理如是;二者,碰到同样问题的读者,倘若能够侥幸看到这些博客,从中有所收获,这对笔者来说是非常值得高兴的事了。闲话少说,唠正经的。

1. 卷积编码的原理

        卷积码的编码分为两类:前馈和反馈,在每类中又可分为系统和非系统形式。我们这里只考虑非系统形式的前馈编码器。



        上图是WLAN 802.11a协议中采用的卷积编码器结构,输入比特k=1,输出n=2,存储器长度m=6,编码输出不仅与当前输入有关,还与存储器存储的之前的输入数据有关,具体由之前的哪些数据得到编码输出呢,由生成多项式确定其连接关系。这里,生成多项式为g0=133(八进制)和g1=171(八进制)(右边是最高位),输出数据A的生成多项式为:



        输出数据B的生成多项式为:



        生成多项式确定了卷积编码器输出的连接关系。根据多项式的系数,在相应项进行连接。生成多项式写成二进制序列的形式分别为:g0 = [1 0 1 1 0 1 1]和g1 = [1 1 1 1 0 0 1](右边是最高位)。我们假设信息序列u,两个编码器输出序列分别为v(0)和v(1),编码器可以看成一个线性系统,系统的信道响应脉冲最多持续m+1个时间单元,编码输出可以写成编码输入与信道脉冲响应的卷积(即生成多项式),即



        其中需要注意的是,所有的加法都是模2加运算。

2. MATLAB实现

function coded_bits = tx_conv_encoder(in_bits, ConvCodeGenPoly)
% 卷积编码
% in_bits: 输入未经编码的信息比特
% ConvCodeGenPoly: 卷积编码的生成多项式
% coded_bits: 编码后的比特

number_rows = size(ConvCodeGenPoly, 1);  % 编码输出的路数n
number_bits = size(ConvCodeGenPoly, 2) + length(in_bits) - 1; %编码输出单路的比特数

coded_bits = zeros(number_rows, number_bits);

for row = 1:number_rows
    coded_bits(row, :) = rem(conv(in_bits, ConvCodeGenPoly(row, :)), 2);
end

%多路输出并成一路(并转串)
coded_bits = coded_bits(:);

        这里将卷积编码封装成了一个函数,可以在调用时才确定生成多项式,对于上面给的情况,matlab调用代码如下:
        ConvCodeGenPoly = [1 0 1 1 0 1 1;1 1 1 1 0 0 1];  % 生成多项式:133和171
        uncoded_bits = [1 0 1 0];
        coded_bits = tx_conv_encoder(uncoded_bits, ConvCodeGenPoly);

3. FPGA实现

        这里,采用verilog语言对编码过程进行描述。通过状态机控制编码的过程,设置有三种状态:IDLE,ENCODING,CLEAR。通常卷积编码以数据块为单元,逐块进行编码的。当待编码的数据块未到达编码单元时,状态机处于IDLE态,即空闲状态,不做任何处理。当数据块到来时,存在一个触发信号,让状态机开始进入ENCODING状态,即编码状态,编码状态持续的时间为输入的数据块的长度。此外,状态机还设置有CLEAR态,因为在卷积编码中,还有尾比特需要输出,这时输入看做全0输入,存储器逐渐清空,持续时间为尾比特的长度。这一步完成后,状态机重新回到IDLE态,等待下一个数据块的到来。代码如下:
conv_encoder(
    input                    clk,
    input                    rst_n,
    input                    e_start_i,           //数据起始信号,比数据uncoded_bits第一个符号早一个时钟,作为编码状态机的启动信号
    input                    uncoded_bits,
    output reg           e_start_o,
    output reg [1:0]   coded_bits
);

% 常量定义
parameter UNCODED_BLOCK_LEN = 100;  //未编码的数据块长度
parameter CODED_BLOCK_LEN = 106; //编码后的单路数据块长度

% 状态机定义
parameter IDLE = 3'b001;
parameter ENCODING = 3'b010;
parameter CLEAR = 3'b100;
reg [2:0] state;

//
reg [7:0] datain_cnt;
reg [5:0] shift_reg;

//
wire encoder_clear_start;
wire encoder_end;
wire encoder_enable;

assign encoder_clear_start = (datain_cnt == UNCODED_BLOCK_LEN -1);
assign encoder_end = (datain_cnt == CODED_BLOCK_LEN -1);
assign encoder_enable = (state != IDLE);

/*********************************************************************/
// 卷积编码状态机
/*********************************************************************/

always @(posedge clk)
    begin
        if(!rst_n)
            state <= IDLE;
        else begin
            case(state)
                IDLE:  state <= e_start_i ? ENCODING : IDLE;
                ENCODING:  state <= encoder_clear_start ? CLEAR : ENCODING;
                CLEAR:  state <= encoder_end ? IDLE : CLEAR;
                default:  state <= IDLE;
            endcase
        end
    end

/*********************************************************************/

// 符号计数器
/*********************************************************************/

always @(posedge clk)
    begin
        if(!rst_n)
            datain_cnt <= 8'd0;
        else
            datain_cnt <= encoder_enable ? (datain_cnt + 1'b1) : 8'd0;
    end

/*********************************************************************/

// 移位寄存器更新
/*********************************************************************/

always @(posedge clk)
    begin
        if(!rst_n)
            shift_reg <= 6'd0;
        else
            shift_reg <= encoder_enable ? {shift_reg[4:0], uncoded_bits} : 6'd0;
    end

/*********************************************************************/

// 编码结果输出
/*********************************************************************/

always @(posedge clk)
    begin
        if(!rst_n)
            coded_bits <= 2'd0;
         else begin
             case(state)
                 IDLE:
                      coded_bits <= 2'd0;
                  CODING:
                       begin
                           coded_bits[0] <= shift_reg[5] ^ shift_reg[4] ^ shift_reg[2] ^ shift_reg[1] ^ uncoded_bits;
                           coded_bits[1] <= shift_reg[5] ^ shift_reg[2] ^ shift_reg[1] ^ shift_reg[0] ^uncoded_bits;
                       end
                  CLEAR:
                       begin
                           coded_bits[0] <= s
9ef8
hift_reg[5] ^ shift_reg[4] ^ shift_reg[2] ^ shift_reg[1];
                           coded_bits[1] <= shift_reg[5] ^ shift_reg[2] ^ shift_reg[1] ^ shift_reg[0];

                       end
                  default:
                       coded_bits <= 2'd0;
             endcase
         end
    end

/*********************************************************************/

// 启动信号输出
/*********************************************************************/

always @(posedge clk_fpga)

    begin

        if(!rst_n)

            e_start_o <= 1'b0;

        else begin

            e_start_o <= e_start_i;

        end

    end
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  fpga 通信 matlab