FPGA數字訊號處理(27)卷積編碼器與Viterbi譯碼器設計

FPGADesigner發表於2018-09-18

卷積編碼與譯碼

訊號在通道間傳輸主要會受到三個方面的影響:

  1. 通道本身對訊號產生衰落,這是由於通道本身的頻率響應特性就不理想,對訊號造成破壞;
  2. 通道中的各種噪聲,疊加在訊號上改變了訊號的幅度、相位、頻率,造成解調錯誤;
  3. 多徑效應,訊號在傳輸過程中的反射、折射、沿不同路徑傳播造成的疊加效應。

通常會採用通道編碼,在傳送端插入一些冗餘碼元,接收端利用這些冗餘碼元檢測並糾正訊號在傳輸過程中產生的錯誤。目前常用的有卷積碼Turbo碼LDPC碼,本文先介紹卷積碼的編碼和譯碼方式。

卷積碼通常稱作非分組碼,其含義是每個碼組的校驗位不僅與本碼組中的資訊位有關,而且還和之前的m(通常稱作約束長度)段碼組的資訊位有關。與之相對地,分組碼的含義是每個碼組中的校驗位只與本碼組中的資訊位有關。卷積碼通常用(n,k,m)表示,k表示編碼前位寬,n表示編碼後位寬,通常稱k/n為編碼效率。如一個(3,1,7)卷積編碼結構如下:
在這裡插入圖片描述

卷積碼的每一個輸出通常用生成多項式來表示,如上圖中A、B、C對應的生成多項式分別為g1=(133)8、g2=(165)8、g3(171)8。通常用8進位制或2進製表示,為1表示該移位暫存器中的對應位置與異或門相連;為0表示不相連。另外還有其它的狀態圖、網格圖等卷積碼錶示方式,本設計中不會用到,因此不予描述。

輸出資料A、B、C可以序列或並行地輸出,如果是序列輸出還涉及到時鐘速率的轉換,如上圖中輸出時鐘速率應是輸入時鐘的3倍。接收端需要作相應的譯碼,卷積譯碼不像第26篇中介紹的加擾、解擾那樣採用逆運算即可,卷積譯碼還要考慮修復傳輸過程中產生的錯誤,因此是個相當複雜的過程。

目前應用最為廣泛的是一種概率譯碼方法,Viterbi譯碼,是基於最大似然準則實現的。該演算法原理也很複雜,如果想要自己設計Verilog實現,很耗費時間,本文設計採用現成的IP核實現。《基於OFDM的卷積編譯碼與自適應傳輸技術的研究_孫婷》這篇論文中給出了詳細的Viterbi譯碼原理,以及Verilog實現方法,供各位參考研究。


MATLAB設計

使用MATLAB模擬卷積編碼和Viterbi譯碼的過程,MATLAB提供了現成的函式convenc和vitdec,生成多項式採用網格trellis結構表述,可以用poly2trellis函式將多項式轉換為trellis結構。本設計模擬時和第26篇中的加擾器、解擾器結合,資料流為:原始序列->加擾器->卷積編碼->Viterbi譯碼->解擾器。與卷積編譯碼相關的核心程式碼如下:

%----------------------------------------%
%%% -------  (3,1,7)卷積編碼  -------- %%%
%----------------------------------------%
%將生成多項式轉換為網格表示式,g1=o133,g2=o165,g3=o171
% trellis = poly2trellis(7,{'1+x^2+x^3+x^5+x^6', ...
%         '1+x^1+x^2+x^4+x^6','1+x^1+x^2+x^3+x^6'});
 trellis = poly2trellis(7,[133 165 171]);
%上面給出了兩種轉換方式,7為約束長度
 
codeData = convenc(y_scrambler,trellis); %對加擾後資料卷積編碼

%----------------------------------------%
%%% ---------  Viterbi譯碼  ---------- %%% 
%----------------------------------------%
decodeData = vitdec(receive,trellis,34,'trunc','hard');

Viterbi譯碼有硬決策hard和軟決策soft兩種譯碼方式,後者由於會採用額外的位寬描述訊號強度,因此效能更好,具體可以參考MATLAB文件,這裡就不再展開。卷積編碼與Viterbi譯碼結果對比如下(無噪聲情況下),可以看到編碼前資料與譯碼後資料完全一致:
在這裡插入圖片描述
MATLAB幫助文件的Convenc和Vitdec函式說明中還有更多的例項,包括不同編解碼方式在不同數字通訊訊雜比Eb/No下的誤位元速率測試,各位可以自行查閱。


FPGA設計

在Vivado中完成演算法設計及模擬。卷積編碼的設計很簡單,僅僅包含移位暫存器和異或門,和第25篇中加擾器、解擾器的設計非常相似。另外Xilinx還提供了Convolution Encoder這個IP核用於完成卷積編碼。本文設計採用自行設計Verilog程式碼,程式碼如下:

`timescale 1ns / 1ps
//-------------------------------------------------------------------------
//    (3,1,7)卷積編碼器設計,written by劉奇,2018.09.16
//-------------------------------------------------------------------------
module Convenc
(
    input clk,
    input rst_n,
    input din,
    output [2:0]dout
);

//-------------------------------------------------------------------------
//    移位暫存器部分
//-------------------------------------------------------------------------
reg [6:0] conv_reg;  

always @ (posedge clk or negedge rst_n)
    if (!rst_n) conv_reg <= 7'b0000000;
    else conv_reg <= {din,conv_reg[6:1]};

//-------------------------------------------------------------------------
//    模2加法器設計
//-------------------------------------------------------------------------  
reg [2:0] dout_reg;
always @ (posedge clk or negedge rst_n)
    if (!rst_n) dout_reg <= 3'b000;
    else begin
        dout_reg[2] <= conv_reg[6]^conv_reg[4]^conv_reg[3]^conv_reg[1]^conv_reg[0]; //o133
        dout_reg[1] <= conv_reg[6]^conv_reg[5]^conv_reg[4]^conv_reg[2]^conv_reg[0]; //o165
        dout_reg[0] <= conv_reg[6]^conv_reg[5]^conv_reg[4]^conv_reg[3]^conv_reg[0]; //o171
    end

assign dout = dout_reg;

endmodule

Viterbi譯碼過程相當複雜,理解原理和完成Verilog程式碼設計都需要不少的時間,本設計採用Vivado提供的Viterbi Decoder IP核。這個IP核可以實現的功能非常強大,本設計只使用了最基本的功能。IP核配置介面如下:
在這裡插入圖片描述

Viterbi Type選擇Standard,即標準的Viterbi演算法結構。約束長度設定為7(與編碼方式相同),回溯長度設定為42(越高譯碼正確率越高,Latency和消耗資源也增加)。Viterbi結構可以選擇並行Parallell(更高的資料吞吐量,每個時鐘可以得到一個輸出)和Serial(佔用更少的資源,每N個時鐘得到一個輸出)。

在這裡插入圖片描述

State標籤下選擇Hard Coding方式。Convolution 0標籤下設定編碼速率和生成多項式,如上圖所示,應與編碼方式對應。Viterbi譯碼採用並行輸入方式,如編碼速率設定為3,則輸入資料訊號為[23:0]共3*8位元位寬,每8個位元為一路編碼的輸入,例項化時注意輸入的訊號要與設定的生成多項式順序對應。

模擬時與MATLAB中相同,按加擾器->卷積編碼->Viterbi譯碼->解擾器的順序級聯在一起。原始序列由MATLAB生成並儲存在txt檔案中,在testbench中讀取呼叫。模擬結果如下圖所示,看到加擾後資料scrambler_out(即卷積編碼的輸入資料)和Viterbi譯碼後輸出deconv_out完全一致;加擾前資料din與解擾後資料descrambler_out也完全一致,只是輸入與輸出之間有計算導致的延遲:
在這裡插入圖片描述

相關文章