卷积码编码及译码算法的基本原理

引言
卷积码是一种信道纠错编码,在通信中具有广泛的应用。在发送端根据生成多项式进行卷积码编码,在接收端根据维特比(viterbi)译码算法进行译码,能够有效抵抗信道噪声的影响,在误码率门限之下可以对传输过程中发生的突发错误进行纠错。
1、编码及译码算法的基本原理
卷积码编码
       卷积码是一种纠错编码,它将输入的k个信息比特编成n个比特输出,特别适合以串行形式进行传输,时延小。卷积码编码器的一般形式如下图所示。
如下图所示为k=1时的编码框图,k=1也是最常用的一种编码器情形:
译码算法
      卷积码的译码方法有两类:一类是大数逻辑译码,又称门限译码;另一类是概率译码,概率译码又能分为维特比译码和序列译码两种。维特比(viterbi)译码和序列译码都属于概率译码。当卷积码的约束长度不太大时,与序列译码相比,维特比译码器比较简单,计算速度更快。接下来的译码算法采用的是概率译码中的维特比译码。采用概率译码的一种基本想法是:把已接收序列与所有可能的发送序列做比较,选择其中汉明码距最小的一个序列做为发送序列。
编码及译码算法的matlab实现
       根据如上所述的编译码基本原理,我们可以在matlab中进行很方便的仿真,matlab提供了集成化的函数可供调用,进行仿真,如下所示:
2、编码算法的fpga实现
根据卷积码编码的基本原理 ,我们可以根据相应的生成多项式来进行verilog编码,从而可以很方便的实现卷积码编码的fpga实现:
顶层代码
module  convenc(
//system signals
inputclk, 
inputrst_n,
inputdata_in,
outputreg [1:0] data_out     
);
reg [6:0] conv_reg;
always @(posedge clk or negedge rst_n) begin
  if (!rst_n) begin
  conv_reg <= 7'd0;
  end
  else begin
  conv_reg <= {data_in,conv_reg[6:1]};
  end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
data_out <= 2'd0;
end
else begin
    data_out[1] <= conv_reg[6]^conv_reg[5]^conv_reg[4]^conv_reg[3]^conv_reg[0];//o171
data_out[0] <= conv_reg[6]^conv_reg[4]^conv_reg[3]^conv_reg[1]^conv_reg[0];//o133
end
end
endmodule
测试代码
`timescale 1ns/1ps;
module tb();
reg clk;
reg rst_n;
reg data_in;
wire [1:0] data_out;
reg bits[255:0];
integer out_file;
integer i;
convenc demo(
.clk(clk),
.rst_n(rst_n),
.data_in(data_in),
.data_out(data_out)
);
initial
begin
clk = 1'b1;
rst_n = 1'b1;
#5 rst_n = 1'b0;
#5 rst_n =1'b1;
$readmemb(f:/fpga_dsp/viterbi/bits.txt,bits);
out_file = $fopen(f:/fpga_dsp/viterbi/result.txt,w);//获取文件句柄
for(i = 0; i <= 255; i = i + 1)begin
        data_in = bits[i];
        #10;
        $fwrite(out_file,%b %b ,data_out[1],data_out[0]);
end
end
always #5 clk = ~clk;
endmodule
仿真结果
3、维特比译码(viterbi)算法的fpga实现
维特比译码(viterbi)算法在数学原理上是比较复杂的,从理解算法到实现需要做大量的工作,但是xilinx的vivado工具给我们提供了viterbi decoder ip核,我们可以很方便地调用这个ip核进行算法的fpga实现和落地。
viterbi decoder ip核输入输出数据格式
       viterbi decoder ip核的接口是基于axi-stream协议的,在之前的文章中已经有提及axi-stream协议的握手过程,如果有不懂的可以去看前面的文章,下面主要介绍一下该ip和输入输出数据的基本格式组成:
输入数据:
当ip核作为接收输入数据的时候,扮演的是从机的角色,输入数据的格式如下图所示,下图对应的是编码速率为2的情况。如果编码速率为n,那么数据的位宽相应为n*8。
当ip核配置为硬判决时,输入数据位宽为1,其余位用0补齐, 当ip核配置为软判决时,输入数据位宽为3-5,其余位用0补齐,data_in1对应高位,data_in0对应低位。
输出数据:
ip核的译码输出数据总是1位,格式如下图所示。
最低位为译码数据,其他数据可以不做深入了解。
另外除了待译码数据的输入端口和译码数据输出端口外,该ip核还可以进行误码率(ber)的计算,其余端口位误码率计算配置端口和结果输出端口,具体详情请参考官方手册pg027。
ip核生成流程
     vivado软件为我们提供了viterbi译码ip核,可以进行图形化配置然后进行调用和使用,配置参数要与编码过程中的相关参数严格对应,具体过程如下所示:
在图形化配置ip核完成后,我们提取相应的网表文件在modelsim环境下进行了仿真,如何在modelsim环境下仿真vivado ip核我们在前面也有提及,如有不懂的也可翻阅前面的文章进行学习,相关测试程序如下。
`timescale 1 ns / 1 ps
module dec_tb ();
glbl glbl();
reg  aclk;
reg aresetn;
reg [15:0]s_axis_data_tdata;
reg s_axis_data_tvalid;
wire s_axis_data_tready;
wire [7:0]m_axis_data_tdata;
wire m_axis_data_tvalid;
reg m_axis_data_tready;
reg [15:0] s_axis_dstat_tdata;
reg s_axis_dstat_tvalid;
wire s_axis_dstat_tready;
wire [15:0]m_axis_dstat_tdata;
wire m_axis_dstat_tvalid;
reg m_axis_dstat_tready;
reg codedata[511:0];
reg [9:0]i;
reg [9:0]j;
integer out_file;
initial begin
aclk = 1'b1;
aresetn = 1'b1;
#5 aresetn = 1'b0;
#5 aresetn = 1'b1;
$readmemb(f:/fpga_dsp/viterbi/codedata.txt,codedata);
out_file = $fopen(f:/fpga_dsp/viterbi/decodedata.txt,w);//获取文件句柄
end
always #5 aclk = ~aclk;
//送数据
always @(posedge aclk or negedge aresetn) begin
if (!aresetn) begin
s_axis_data_tvalid <= 1'b0;
s_axis_data_tdata <= 16'd0;
i <= 9'd0;
j <= 9'd1;
end
else if (s_axis_data_tready) begin
if(i <= 9'd510)begin
s_axis_data_tvalid <= 1'b1;
s_axis_data_tdata <= {7'd0,codedata[j],7'd0,codedata[i]};
i <= i + 2;
j <= j + 2;
end
else
s_axis_data_tvalid <= 1'b0;
end
end
//取数据
always @(posedge aclk or negedge aresetn) begin
if (!aresetn) begin
m_axis_data_tready <= 1'b1;
end
else if (m_axis_data_tvalid) begin
$fwrite(out_file,%b ,m_axis_data_tdata[0]);
end
end
//----------- begin cut here for instantiation template ---// inst_tag
viterbi_0 your_instance_name (
  .aclk(aclk),                                // input wire aclk
  .aresetn(aresetn),                          // input wire aresetn
  //接收数据时为从设备
  .s_axis_data_tdata(s_axis_data_tdata),      // input wire [15 : 0] s_axis_data_tdata
  .s_axis_data_tvalid(s_axis_data_tvalid),    // input wire s_axis_data_tvalid
  .s_axis_data_tready(s_axis_data_tready),    // output wire s_axis_data_tready
  //发送数据时为主设备
  .m_axis_data_tdata(m_axis_data_tdata),      // output wire [7 : 0] m_axis_data_tdata
  .m_axis_data_tvalid(m_axis_data_tvalid),    // output wire m_axis_data_tvalid
  .m_axis_data_tready(m_axis_data_tready),    // input wire m_axis_data_tready
  //ber测量
  .s_axis_dstat_tdata(s_axis_dstat_tdata),    // input wire [15 : 0] s_axis_dstat_tdata
  .s_axis_dstat_tvalid(s_axis_dstat_tvalid),  // input wire s_axis_dstat_tvalid
  .s_axis_dstat_tready(s_axis_dstat_tready),  // output wire s_axis_dstat_tready
  .m_axis_dstat_tdata(m_axis_dstat_tdata),    // output wire [15 : 0] m_axis_dstat_tdata
  .m_axis_dstat_tvalid(m_axis_dstat_tvalid),  // output wire m_axis_dstat_tvalid
  .m_axis_dstat_tready(m_axis_dstat_tready)  // input wire m_axis_dstat_tready
);
endmodule
仿真波形:
原文标题:卷积码编码及维特比译码(viterbi)算法的原理及其fpga实现
文章出处:【微信公众号:fpga设计论坛】欢迎添加关注!文章转载请注明出处。

选择运算放大器时的三个主要考虑因素
比亚迪将用电动化铺就绿色城市之梦
上海君屹李伟:PACK产线智能制造‘路在何方’
无人机在农业领域潜在的应用有哪些
鉴于乐视网目前面临的诸多问题,无法畅想乐视网未来
卷积码编码及译码算法的基本原理
2019春晚红包互动208亿次 百度APP日活破3亿
德国奥托博克公司依靠PADS生产能力制造产品
恒温恒湿试验箱的控温方式与特色功能
数字孪生编辑器为可视化应用开发提供哪些帮助?
启明信息连续入选国家规划布局内重点软件企业
爬虫实践:批量下载所有排行榜小说
支持烧录Geehy极海半导体的32位微控制器APM32F407RET6
可靠而高效的工业PCB连接,如何轻松实现?
联影智能推出一款基于摄像头实现360度人体3D建模的“智能之眼”
区块链能为广告行业做些什么
用普通元件构成的高精度极性转换电路
NAS与SAN的7大差异与使用案例
雷达三大应用原理:测距、测角和测速
Facebook AI系统可使机器为任何输入音乐生成舞蹈