1.前言
上一节实现了一级交织:分组交织器,这节接着进行第二级交织的实现。需要注意的是只有data域需要第二级交织,而signal域不需要。二级交织比较简单,作者直接调用了前面的模块来实现,这也体现了FPGA设计的模块化复用思想。当然重新写也是可以的,但是有现成的可以调用干嘛不用呢是不是?
第二次交织是在第一次交织的基础上进行的,交织基本过程是每24个比特为一单元,前12个顺序保持不变,后12个每相邻两位交换位置,这样就保证了相邻的编码比特被分别映射到星座图中的重要和次要位置,因此LSB长时间的低可靠性将被避免。
2.Verilog代码
二级交织模块的接口如下所示:
设计上,直接调用前面的串并转换模块和并串转换模块,设置位宽为2(不清楚的看之前的文章:基于valid-ready双向握手机制的串并和并串转换)。具体实现方式如下:
(1)首先数据进来使用串并转换,将串行变为2bit的并行。
(2)然后再例化两个并串转换模块一个设置为LSB优先,一个设置为MSB优先。
(3)例化一个模24的计数器(FPGA搭积木之计数器)
(4)当计数值小于12时,使用LSB优先的并串转换输出,否则使用MSB优先的并串转换输出。
代码如下:
assign intv2_dout_rdy = S2P_dout_rdy ;
assign intv2_dout = cnt < 12 ? u1_P2S_dout : u2_P2S_dout ;
assign intv2_dout_vld = cnt < 12 ? u1_P2S_dout_vld : u2_P2S_dout_vld ;
assign En_cnt = (u2_P2S_dout_vld & u2_P2S_din_rdy) | u1_P2S_dout_vld & u1_P2S_din_rdy;
counter #(.CNT_NUM('d24),
.ADD(1'b1))
u_counter(
.clk (clk ),
.rst_n (rst_n ),
.En_cnt (En_cnt ),
.cnt (cnt ),
.cnt_last (cnt_last )
);
assign S2P_din = intv2_din ;
assign S2P_din_vld = intv2_din_vld ;
assign S2P_din_rdy = u1_P2S_dout_rdy & u2_P2S_dout_rdy;
Ser2Par #( .WIDTH (2),
.LSB_FIRST (1'b1))
u_Ser2Par(
.clk (clk ),
.rst_n (rst_n ),
.din (S2P_din ),
.din_vld (S2P_din_vld ),
.din_rdy (S2P_din_rdy ),
.dout (S2P_dout ),
.dout_vld (S2P_dout_vld ),
.dout_rdy (S2P_dout_rdy )
);
assign u1_P2S_din = S2P_dout ;
assign u1_P2S_din_vld = S2P_dout_vld ;
assign u1_P2S_din_rdy = intv2_din_rdy ;
Par2Ser #( .WIDTH (2),
.LSB_FIRST (1))
u1_Par2Ser(
.clk (clk ),
.rst_n (rst_n ),
.din (u1_P2S_din ),
.din_vld (u1_P2S_din_vld ),
.din_rdy (u1_P2S_din_rdy ),
.dout (u1_P2S_dout ),
.dout_vld (u1_P2S_dout_vld),
.dout_rdy (u1_P2S_dout_rdy)
);
assign u2_P2S_din = S2P_dout ;
assign u2_P2S_din_vld = S2P_dout_vld ;
assign u2_P2S_din_rdy = intv2_din_rdy ;
Par2Ser #( .WIDTH (2),
.LSB_FIRST (0))
u2_Par2Ser(
.clk (clk ),
.rst_n (rst_n ),
.din (u2_P2S_din ),
.din_vld (u2_P2S_din_vld ),
.din_rdy (u2_P2S_din_rdy ),
.dout (u2_P2S_dout ),
.dout_vld (u2_P2S_dout_vld),
.dout_rdy (u2_P2S_dout_rdy)
);
//输出Map_Type,作为后面调制映射的输入,确定调制方式
always@(posedge clk or negedge rst_n ) begin
if(!rst_n) begin
Map_Type_o <= 0;
end
else if(u2_P2S_dout_vld | u1_P2S_dout_vld) begin
Map_Type_o <= Map_Type_i ;
end
end
3.Matlab仿真
%% 二级交织
int_lea_2_out = int_lea_1_out;
for index = 1:symbol_Len*k %数据前12个不变,接下来12个两两交换位置
if(mod((ceil(index/12)-1),2)==1) %判断数据是不是在后12个位置
if(mod(index,2) == 0) %在偶数位置时,将前一个位置的数据给他
int_lea_2_out(index) = int_lea_1_out(index-1);
else %在奇数位置时,将后一个位置的数据给他
int_lea_2_out(index) = int_lea_1_out(index+1);
end
else
int_lea_2_out(index) = int_lea_1_out(index);
end
end
4.ModelSim仿真
按照如下图所示方式进行连接仿真:
为了验证模块的正确性,仿真使用4个OFDM符号输入,调制方式位BPSK(其他调制方式数据太多,不方便展示),测试数据如下:
test_data =
列 1 至 27
0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 1 1 1 0 0 1 1 1
列 28 至 54
1 0 1 1 0 1 1 1 1 1 0 0 1 1 1 0 1 1 1 0 0 0 0 1 0 1 0
列 55 至 81
0 0 0 0 0 1 0 1 1 1 1 0 1 1 0 0 1 1 0 0 1 1 0 1 0 0 1
列 82 至 108
0 0 0 1 0 1 1 0 0 0 1 0 1 0 1 0 1 1 1 1 0 0 1 1 0 1 0
列 109 至 135
1 1 1 1 1 0 1 1 1 0 0 1 0 0 0 0 1 0 1 1 1 0 0 0 1 1 0
列 136 至 144
1 0 0 1 1 1 1 1 1
matlab仿真的二级交织结果如下:
int_lea_2_out =
列 1 至 27
0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 1 0 0 1 1 0
列 28 至 54
0 1 0 1 1 1 0 0 1 0 0 1 1 1 0 1 1 0 1 0 0 1 1 1 1 0 0
列 55 至 81
1 1 0 0 0 1 1 1 1 0 1 1 1 0 1 0 1 0 0 0 0 0 0 0 1 1 1
列 82 至 108
1 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 1 0 0 0 0 1 0 0 0 0
列 109 至 135
1 1 0 0 1 0 1 1 1 1 1 1 1 1 1 0 0 1 0 1 0 1 1 1 1 1 1
列 136 至 162
1 1 1 1 1 1 1 1 0 0 0 0 1 1 0 0 1 1 1 1 0 0 1 1 1 1 1
列 163 至 189
0 1 0 0 0 1 1 0 0 0 0 1 0 0 1 0 0 1 1 0 0 0 1 1 1 0 1
列 190 至 192
1 0 0
FPGA输出的二级交织结果如下:
FPGA_intv2_dout =
列 1 至 27
0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 1 0 0 1 1 0
列 28 至 54
0 1 0 1 1 1 0 0 1 0 0 1 1 1 0 1 1 0 1 0 0 1 1 1 1 0 0
列 55 至 81
1 1 0 0 0 1 1 1 1 0 1 1 1 0 1 0 1 0 0 0 0 0 0 0 1 1 1
列 82 至 108
1 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 1 0 0 0 0 1 0 0 0 0
列 109 至 135
1 1 0 0 1 0 1 1 1 1 1 1 1 1 1 0 0 1 0 1 0 1 1 1 1 1 1
列 136 至 162
1 1 1 1 1 1 1 1 0 0 0 0 1 1 0 0 1 1 1 1 0 0 1 1 1 1 1
列 163 至 189
0 1 0 0 0 1 1 0 0 0 0 1 0 0 1 0 0 1 1 0 0 0 1 1 1 0 1
列 190 至 192
1 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);
%% 一级交织
FPGA_intv1_dout = load('D:/FPGA/OFDM_802.11a_my/TX/matlab/intv1_data_out.txt')';
display(int_lea_1_out);
display(FPGA_intv1_dout);
check_intv1 = FPGA_intv1_dout == int_lea_1_out;
display(check_intv1);
%% 二级交织
FPGA_intv2_dout = load('D:/FPGA/OFDM_802.11a_my/TX/matlab/intv2_data_out.txt')';
display(int_lea_2_out);
display(FPGA_intv2_dout);
check_intv2 = FPGA_intv2_dout == int_lea_2_out;
display(check_intv2);
对比结果为:
check_intv2 =
1×192 logical 数组
列 1 至 40
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 1 1
列 41 至 80
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 1 1
列 81 至 120
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 1 1
列 121 至 160
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 1 1
列 161 至 192
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,说明设计是正确的。
原文连接(相关文章合集):OFDM 802.11a的xilinx FPGA实现