卷积编码的原理与MATLAB及FPGA实现
2016-05-22 18:35
465 查看
卷积编码是现代数字通信系统中常见的一种前向纠错码,区别于常规的线性分组码,卷积编码的码字输出不仅与当前时刻的信息符号输入有关,还与之前输入的信息符号有关。下面,笔者将简要分析一下卷积编码的原理以及相应的实现方法。忽然想起笔者开始写CSDN博客的初衷,一者为了总结之前做过的东西,记录一些关键点,防止以后遗忘,依稀记得老师曾言,好记性比不过烂笔头,道理如是;二者,碰到同样问题的读者,倘若能够侥幸看到这些博客,从中有所收获,这对笔者来说是非常值得高兴的事了。闲话少说,唠正经的。
上图是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加运算。
% 卷积编码
% 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);
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
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
相关文章推荐
- C#实现子窗体与父窗体通信方法实例总结
- java和c#使用hessian通信的方法
- win32下进程间通信(共享内存)实例分析
- WinForm实现跨进程通信的方法
- C#中使用UDP通信实例
- 解析在main函数之前调用函数以及对设计的作用详解
- ASP.NET UserControl 通信的具体实现
- 详解Matlab中 sort 函数用法
- 浅析iOS应用开发中线程间的通信与线程安全问题
- java和matlab画多边形闭合折线图示例讲解
- C#调用Matlab生成的dll方法的详细说明
- PHP多线程编程之管道通信实例分析
- flex与js通信与彼此之间的互调整理(一)
- Perl的Mail::POP3Client模块和Gmail通信实例
- 使用DNode实现php和nodejs之间通信的简单实例
- 嵌入式iframe子页面与父页面js通信的方法
- Android单片机与蓝牙模块通信实例代码
- Android Socket通信详解
- Android 进程间通信实现原理分析
- Web通信 分析工具 [推荐]