目录
1.前言
在前面执行了卷积编码之后,得到了一个1/2编码速率的卷积编码,在实际的使用当中,802.11a支持不同的编码速率,比如2/3编码,3/4编码,为了能够得到对应的编码速率,需要将卷积编码之后的结构进行删除其中的一些bit。
不得不先吐槽下《基于XILINX FPGA的OFDM通信系统基带设计》这本书里面的设计思路,一旦输入数据和输出数据速率不一样他就跨时钟。记得作者大二才学FPGA的时候,接触一位大佬就说过,always里面最好都是一种时钟,除非是真的避免不了再考虑。我愿称这本书为始作俑者,网上大部分教程都是按照他的思路来进行设计。
2. 删余的原理
2.1 删余的作用
无线通信基带信号处理中,为了提高传输效率,在卷积编码后一般要进行删余(puncture)操作,即周期性的删除一些相对不重要的数据比特,引人了删余操作的卷积编码也称作删余卷积码。在编码时进行了删余操作后,需要在译码时进行depuncture,即在译码之前将删余比特位置加以填充。在IEEE 802.11a标准中推荐使用viterbi算法解密。删余的过程如下所示:
2.2 3/4编码速率的删余过程
2.3 2/3编码速率的删余过程
3.删余模块实现
3.1 模块接口
该模块如下所示:
数据传输和控制依然采用vaild-ready握手机制,串行输入,删余后串行输出。Rate_Con[3:0]是调制方式和码率控制信号。如下三个表所示,SymbolLen_Con[1:0]是输入调制方式和编码效率一个OFDM符号的长度,如下面第二个表的第4列所示。
3.2 FPGA实现(verilog代码)
由于卷积编码模块输出的是2bit并行的数据,先要使用前面的并串转换模块,再与删余模块连接进行删余操作。连接方式如下所示:
1/2直接输出即可,以模2计数器进行循环,输出标号为第0,1个;2/3需要循环删除第4个数据,以模4计数器进行循环输出标号为0,1,2;3/4码率的需要循环删除第4、5个数据,以模6计数器进行循环,输出标号为0,1,2,5。代码如下:
assign punt_dout_rdy = punt_din_rdy;
assign punt_en = punt_dout_rdy & punt_din_vld ;
counter_in #(.CNT_NUM(3'd6),
.ADD(1'b1))
u_counter(
.clk (clk ),
.rst_n (rst_n ),
.En_cnt (punt_en | cnt_last ),
.cnt_din (cnt_max ),
.cnt (cnt ),
.cnt_last (cnt_last )
);
//output count max
always@( posedge clk or negedge rst_n ) begin
if(!rst_n)
cnt_max <= 3'd1;
else begin
case ( Rate_Con )
4'b1101,4'b0101,4'b1001: begin //rate 1/2
cnt_max <= 3'd1;
end
4'b1111,4'b0111,4'b1011,4'b0011: begin //rate 3/4
cnt_max <= 3'd5;
end
4'b0001: begin //rate 2/3
cnt_max <= 3'd3;
end
default: cnt_max <= cnt_max;
endcase
end
end
always@( posedge clk or negedge rst_n ) begin
if(!rst_n)begin
punt_dout <= 1'b0;
punt_dout_vld <= 1'b0;
end
else if(punt_en)begin
case (cnt)
0,1,2,5 : begin
punt_dout <= punt_din;
punt_dout_vld <= 1'b1;
end
3,4 : begin
punt_dout <= 1'b0;
punt_dout_vld <= 1'b0;
end
default : begin
punt_dout <= punt_dout;
punt_dout_vld <= punt_dout_vld;
end
endcase
end
else if(punt_dout_vld & punt_din_rdy)
punt_dout_vld <= 1'b0;
end
//SymbolLen_Con
always@(posedge clk or negedge rst_n ) begin
if(!rst_n)
SymbolLen_Con <= 0;
else begin
case ( Rate_Con )
4'b1101,4'b1111: begin
SymbolLen_Con <= 2'b00; //Len==48
end
4'b0101,4'b0111: begin
SymbolLen_Con <= 2'b01; //Len ==96
end
4'b1001,4'b1011: begin
SymbolLen_Con <= 2'b10; //Len ==192
end
4'b0001,4'b0011: begin
SymbolLen_Con <= 2'b11; //Len ==288
end
default:SymbolLen_Con <= 2'b00;
endcase
end
end
3.3Matlab仿真
%% 删余
switch(code_rate) %卷积编码速率控制
case 12
conv_out = conv_in;%做卷积编码
case 8
puncpat = [1;1;1;0]; %打孔方式
trellis = poly2trellis(L,[133,171]);
conv_out = convenc(conv_in,trellis,puncpat);
case 6
puncpat = [1;1;1;1];
trellis = poly2trellis(L,[133,171]);
conv_out = convenc(conv_in,trellis,puncpat);
case 9
puncpat = [1;1;1;0;0;1];
trellis = poly2trellis(L,[133, 171]);
conv_out = convenc(conv_in,trellis,puncpat);
otherwise
disp('code_rate_error');
end
测试数据如下:
test_data =
列 1 至 25
0 1 0 0 0 0 0 1 1 0 0 0 0 1 0 1 0 1 1 0 0 0 1 1 1
列 26 至 50
1 1 0 0 1 0 0 1 1 1 1 1 1 1 0 1 0 1 1 0 1 1 0 1 0
列 51 至 75
0 0 1 0 1 1 1 1 0 1 0 1 1 0 1 1 1 0 0 1 0 0 0 0 1
列 76 至 100
0 0 1 0 0 0 0 1 0 1 0 1 0 0 1 0 1 1 1 1 1 0 1 0 1
列 101 至 125
1 1 0 1 0 1 1 0 1 1 1 1 0 1 0 0 1 1 1 0 1 0 1 0 0
列 126 至 144
0 0 1 0 0 0 0 1 0 0 1 1 0 0 0 1 0 0 1
16-QAM调制,3/4码率,编码删余后的数据如下:
conv_out =
列 1 至 25
0 0 0 1 0 1 0 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 1
列 26 至 50
1 1 0 1 1 0 1 1 1 0 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0
列 51 至 75
0 0 1 0 0 0 1 1 0 1 0 1 1 1 0 1 1 1 1 1 1 1 0 0 1
列 76 至 100
0 1 0 0 0 0 0 0 0 0 1 0 1 1 0 1 1 0 1 0 0 1 1 1 1
列 101 至 125
0 0 1 1 0 1 0 0 0 1 1 1 0 1 1 1 1 1 0 1 0 0 0 1 0
列 126 至 150
1 0 1 0 1 0 0 1 0 1 1 1 0 0 0 0 1 1 0 1 0 1 0 0 0
列 151 至 175
0 0 1 1 1 1 0 1 0 1 1 0 0 0 1 0 0 0 1 1 0 1 1 1 1
列 176 至 192
1 1 1 1 0 0 0 0 1 1 1 0 1 0 0 0 0
3.4 ModelSim仿真
仿真截图如下:
16-QAM调制,3/4码率,FPGA实现编码删余后的数据如下:
FPGA_punt_dout =
列 1 至 25
0 0 0 1 0 1 0 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 1
列 26 至 50
1 1 0 1 1 0 1 1 1 0 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0
列 51 至 75
0 0 1 0 0 0 1 1 0 1 0 1 1 1 0 1 1 1 1 1 1 1 0 0 1
列 76 至 100
0 1 0 0 0 0 0 0 0 0 1 0 1 1 0 1 1 0 1 0 0 1 1 1 1
列 101 至 125
0 0 1 1 0 1 0 0 0 1 1 1 0 1 1 1 1 1 0 1 0 0 0 1 0
列 126 至 150
1 0 1 0 1 0 0 1 0 1 1 1 0 0 0 0 1 1 0 1 0 1 0 0 0
列 151 至 175
0 0 1 1 1 1 0 1 0 1 1 0 0 0 1 0 0 0 1 1 0 1 1 1 1
列 176 至 192
1 1 1 1 0 0 0 0 1 1 1 0 1 0 0 0 0
和Matlab仿真结果对比起来太费眼睛,用如下代码进行比较:
clc;
%% 串并转换
test_data = load('D:/FPGA/OFDM_802.11a_my/TX/matlab/test_data.txt')';
display(test_data);
FPGA_S2P2S = load('D:/FPGA/OFDM_802.11a_my/TX/matlab/u2_data_out.txt')';
display(FPGA_S2P2S);
check_S2P = test_data == FPGA_S2P2S;
display(check_S2P);
%% 扰码
FPGA_scram_dout = load('D:/FPGA/OFDM_802.11a_my/TX/matlab/scram_data_out.txt')';
display(scram_out0);
display(FPGA_scram_dout);
check_scram = FPGA_scram_dout == scram_out0;
display(check_scram);
%% 卷积编码
FPGA_conv_dout = load('D:/FPGA/OFDM_802.11a_my/TX/matlab/conv_data_out.txt')';
display(conv_out0);
display(FPGA_conv_dout);
check_conv = FPGA_conv_dout == conv_out0;
display(check_conv);
%% 删余
FPGA_punt_dout = load('D:/FPGA/OFDM_802.11a_my/TX/matlab/punt_data_out.txt')';
display(conv_out);
display(FPGA_punt_dout);
check_punt = FPGA_punt_dout == conv_out;
display(check_punt);
验证结果如下:
check_punt =
1×192 logical 数组
列 1 至 38
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
列 39 至 76
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
列 77 至 114
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
列 115 至 152
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
列 153 至 190
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
列 191 至 192
1 1
输出显示192个逻辑‘1’表示FPGA得到的结果与Matlab仿真结果完全一致,经过测试其他7种调制和编码方式结果都是正确的,这里就不在进行赘述了。
4总结
结合上一节的卷积编码器,本模块用FPGA实现了1/2,3/4,2/3编码效率的卷积编码器的删余操作,需要回顾前面知识请点击链接:原文连接(相关文章合集):OFDM 802.11a的xilinx FPGA实现