原文链接(相关文章合集):OFDM 802.11a的xilinx FPGA实现
1.前言
前面一篇文章完成了星座图的映射,今天继续设计后面的模块。在接收机当中,虽然利用接收到的短/长训练序列,能够进行信道均衡,频偏校正,但符号还会存在一定的剩余频率偏差,并且偏差会随着时间的积累而累积,会造成所有子载波产生一定的剩余相位偏转。因此,还需要不断的对参考相位进行跟踪。要实现这一功能,需要在 52 个非零子载波中插入 4 个导频符号。
2.插入导频原理
Data 域的数据经过星座图映射后形成对应的复数值,每个 OFDM 符号周期可以通过 48 个子信道发出 48 个调制后的数据,所以把这些值每 48 个分成一组,每一组将对应一个 OFDM 符号。
子载波的数量一共有 53 个,每个子载波的标号为-26,-25,…,-1,0,1,…,26。其中 48 个复数数据分别对应到-26 至-22,-20 至-8,-6至-1,1 至 6,8 至 20,以及 20 至 26 这些子载波上,四个导频子信道分别对应到-21,-7,7 和 21 这 4 个子载波上。0 号子载波上填充零值(直流)。
导频所处位置的值,是根据一个循环的导频的极性控制序列来完成的,该极性控制序列如下:
每个导频极性对应一个OFDM符号,比如第一个OFDM符号也就是signal域的符号,其导频极性控制为1,那么其输出导频位置所给的值就位1 1 1 -1,又比如第5个OFDM符号,也就是第4个data域的OFDM符号,其极性控制为-1,那么其导频位置所给的值就位-1 -1 -1 1。依此类推。当p为“一1”时,对应的OFDM符号的导频符号需要改变极性(-1→+1;+1→-1);当p 为“1”时,对应的OFDM符号的导频符号不需要改变极性。p可以通过标准中所规定的扰码器(Scrambler)来产生。
只不过,此模块扰码器的初始状态设为{1,1,1,1,1,1,1}。
3.硬件实现
图中,SPI_DIN为导频模块输入数据,INDEX_IN为输入数据标号,从0到47。扰码器(Scrambler)产生导频的极性控制信号,扰码器初始状态设为7’b1111111。4个导频依次为1,1,1,-1。输入数据标号INDEX_IN通过LUT模块进行变换生成写入RAM 的地址,输入计数0到47映射为52个子载波,中间插入4个导频符号。因为导频插入模块输出到一个64位的 IFFT模块,一个模64的计数器用来生成输出地址。双口 RAM 暂时存放输入的信号。
由于导频插入模块之后是IFFT模块,因此本模块在具体实现时通过ROM 进行了数据顺序变换,使得数据输出时顺序变为符合IFFT输入的要求。例如,当使用64点的IFFT时,输入的48个数据(标号为0至47)的标号首先按照如下公式进行变换,映射为-26至26,其中标号-21,-7,7,21即为插入导频处(k为输入数据标号):
M
(
k
)
=
{
k
−
26
,
0
≤
k
≤
4
k
−
25
,
5
≤
k
≤
17
k
−
24
,
18
≤
k
≤
23
k
−
23
,
24
≤
k
≤
29
k
−
22
,
30
≤
k
≤
42
k
−
21
,
43
≤
k
≤
47
M(k) = \begin{cases} k-26,0 \leq k \leq 4 \\ \\k-25 ,5\leq k\leq 17\\ \\k-24 ,18\leq k\leq 23\\ \\k-23 ,24\leq k\leq 29\\ \\k-22 ,30\leq k\leq 42\\ \\k-21 ,43\leq k\leq 47 \end{cases}
M(k)=⎩
⎨
⎧k−26,0≤k≤4k−25,5≤k≤17k−24,18≤k≤23k−23,24≤k≤29k−22,30≤k≤42k−21,43≤k≤47
根据协议中对IFFT输入端口映射的规定,将变换后M(k)为1至26的子载波映射到IFFT的输入端口1至26,M(k)为一26至一1的子载波映射到IFFT的端口38到63,而剩下的端口27至37和0则置为零值。此映射的描述如下图所示。
相应的,插入导频的位置-21,-7,7,21分别对应到IFFT的输入端口43,57,21,7。编程实现时,根据导频极性,在这4个位置上插入导频。因此,结合上述两步,写入RAM中的数据标号的变换可直接用下式实现:
M
(
k
)
=
{
k
+
38
,
0
≤
k
≤
4
k
+
39
,
5
≤
k
≤
17
k
+
40
,
18
≤
k
≤
23
k
−
23
,
24
≤
k
≤
29
k
−
22
,
30
≤
k
≤
42
k
−
21
,
43
≤
k
≤
47
M(k) = \begin{cases} k+38,0 \leq k \leq 4 \\ \\k+39 ,5\leq k\leq 17\\ \\k+40 ,18\leq k\leq 23\\ \\k-23 ,24\leq k\leq 29\\ \\k-22 ,30\leq k\leq 42\\ \\k-21 ,43\leq k\leq 47 \end{cases}
M(k)=⎩
⎨
⎧k+38,0≤k≤4k+39,5≤k≤17k+40,18≤k≤23k−23,24≤k≤29k−22,30≤k≤42k−21,43≤k≤47
在设计上,采用乱序写,顺序读的方式。先定义1个位宽为16的RAM,对输入数据的实数和虚数按Index序号通过上面公式变换后,存入RAM中。再通过扰码器产生的极性控制信号,对导频是否极性变换做处理,极性处理后,将导频信号写入对应RAM地址空间中。最后,以顺序方式从RAM中读取数据。为保证流水线处理,以及写入写出不发生冲突,RAM的深度需设置为2个OFDM符号的长度,使用乒乓缓存操作(前面文章乒乓缓存操作的链接)。
在对数据域进行调制的时候,导频控制序列是从地址1开始累加,直到处理完126个OFDM符号是,这是导频控制序列读取到第126个,然后才会回到0,然后从0~126循环,因为在802.11a当中,第一个OFDM符号是signal域的符号,data域是从第二个符号开始。
插入导频模块的输入输出如下图所示:
4.Matlab仿真
以2个OFDM符号,16-QAM调制,编码效率为3/4,进行仿真,生成测试数据共计288个,如下:
test_data =
列 1 至 27
0 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 0 0 1 1 1 1 0 0 0 0 1
列 28 至 54
0 1 1 1 0 0 1 0 0 1 0 1 1 0 0 1 1 0 0 1 0 1 0 1 0 1 0
列 55 至 81
1 0 0 0 1 0 1 1 1 0 1 0 0 1 1 1 1 0 1 1 1 0 1 1 0 0 0
列 82 至 108
0 0 1 1 0 0 1 0 0 1 1 1 1 0 0 1 1 0 1 0 1 0 0 1 1 0 0
列 109 至 135
1 0 1 1 0 1 0 1 1 1 0 0 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1
列 136 至 162
1 0 0 0 0 1 1 0 0 0 1 0 1 1 1 0 1 0 0 1 1 1 1 0 1 0 0
列 163 至 189
0 1 0 0 0 0 0 1 0 1 0 0 1 1 1 1 1 0 1 1 1 0 0 1 0 1 1
列 190 至 216
1 1 1 1 0 0 0 0 0 1 0 1 1 0 0 1 0 1 0 1 0 1 1 1 1 0 0
列 217 至 243
1 1 1 1 0 0 1 0 0 1 1 1 0 1 0 0 0 0 1 1 1 0 0 0 1 1 1
列 244 至 270
1 1 0 1 1 0 1 1 0 0 1 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 1
列 271 至 288
0 0 0 0 0 1 1 0 0 1 1 1 0 0 1 1 1 0
测试数据经过前面章节的扰码、编码、删余、交织、调制映射,然后进行如下的插入导频:
%% 插入导频到7,21,43,57,由于matlab下标从1开始,这里插入导频位置为8,22,44,58
%插入导频极性控制,扰码
scram_seed2 = [1,1,1,1,1,1,1];
scram_reg = scram_seed2;
scram_out = zeros(1,k);
for m = 1:k
scram_out(m) = mod(scram_reg(1) + scram_reg(4), 2);
scram_reg(:,1:end) = [scram_reg(:,2:end), mod(scram_reg(1) + scram_reg(4), 2)]; %扰码寄存器移位,最低位为7+4
if(m==127)
scram_reg = scram_seed2;%127个OFDM符号之后,扰码器恢复初始状态
end
end
rx_interFrq = mod_out;
interFrq_out = zeros(1,64*k);
for m = 1:k
reg48 = rx_interFrq((m-1)*48+1:m*48);
reg_pn = scram_out(m);
if(reg_pn) %当 scram_out== 0 时,不需要极性取反, 当 scram_out==1 时,需要极性取反。
reg_interFrq = [-1,1,-1,-1];%极性取反
else
reg_interFrq = [1,-1,1,1];
end
reg64 = zeros(1,64);
%端口映射为IFFT输入
reg64(1+38:5+38) = reg48(1:5);
reg64(6+39:18+39) = reg48(6:18);
reg64(19+40:24+40) = reg48(19:24);
reg64(25-23:30-23) = reg48(25:30);
reg64(31-22:43-22) = reg48(31:43);
reg64(44-21:48-21) = reg48(44:48);
%剩下的1,28-38端口置0
reg64(28:38) = 0;
reg64(1) = 0;
%插入导频8,22,44,58
reg64(8) = reg_interFrq(1);
reg64(22) = reg_interFrq(2);
reg64(44) = reg_interFrq(3);
reg64(58) = reg_interFrq(4);
interFrq_out((m-1)*64+1:m*64) = reg64;
end
插入导频之后输出如下:
interFrq_out =
列 1 至 8
0.0000 + 0.0000i -0.9531 - 0.9531i -0.3125 + 0.9531i 0.9531 - 0.9531i 0.3125 + 0.3125i 0.9531 + 0.3125i 0.9531 - 0.3125i 1.0000 + 0.0000i
列 9 至 16
-0.9531 + 0.9531i 0.3125 - 0.9531i -0.3125 + 0.9531i -0.9531 + 0.9531i 0.3125 - 0.9531i -0.9531 - 0.9531i 0.3125 + 0.3125i 0.9531 + 0.9531i
列 17 至 24
-0.3125 - 0.9531i -0.3125 + 0.3125i -0.3125 + 0.3125i -0.3125 + 0.9531i 0.9531 - 0.9531i -1.0000 + 0.0000i 0.9531 + 0.9531i 0.9531 + 0.3125i
列 25 至 32
-0.3125 - 0.3125i 0.9531 - 0.3125i -0.9531 - 0.3125i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i
列 33 至 40
0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i -0.9531 + 0.9531i 0.9531 + 0.3125i
列 41 至 48
0.3125 + 0.9531i -0.9531 + 0.3125i -0.9531 + 0.9531i 1.0000 + 0.0000i 0.3125 + 0.3125i 0.9531 + 0.9531i 0.9531 + 0.3125i -0.3125 + 0.9531i
列 49 至 56
-0.9531 + 0.9531i 0.9531 + 0.9531i -0.9531 - 0.3125i 0.9531 + 0.9531i -0.3125 + 0.3125i 0.9531 + 0.3125i -0.9531 - 0.9531i 0.3125 + 0.9531i
列 57 至 64
0.3125 + 0.3125i 1.0000 + 0.0000i -0.9531 + 0.9531i -0.9531 - 0.3125i -0.9531 + 0.3125i -0.3125 + 0.9531i 0.9531 + 0.9531i -0.3125 + 0.3125i
列 65 至 72
0.0000 + 0.0000i -0.9531 - 0.9531i 0.3125 + 0.3125i -0.9531 - 0.9531i 0.3125 + 0.3125i -0.9531 - 0.3125i -0.3125 - 0.9531i 1.0000 + 0.0000i
列 73 至 80
-0.3125 + 0.3125i 0.3125 + 0.3125i -0.3125 + 0.3125i -0.3125 + 0.3125i 0.9531 - 0.9531i -0.3125 - 0.3125i -0.9531 - 0.9531i 0.3125 - 0.3125i
列 81 至 88
-0.9531 + 0.3125i 0.9531 + 0.3125i 0.3125 - 0.9531i 0.3125 - 0.9531i -0.9531 + 0.9531i -1.0000 + 0.0000i -0.9531 - 0.3125i 0.3125 - 0.9531i
列 89 至 96
0.3125 - 0.9531i -0.9531 - 0.3125i -0.3125 + 0.3125i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i
列 97 至 104
0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i -0.9531 + 0.9531i 0.9531 + 0.9531i
列 105 至 112
-0.3125 + 0.3125i -0.9531 - 0.3125i -0.3125 + 0.9531i 1.0000 + 0.0000i -0.3125 - 0.3125i -0.9531 + 0.3125i -0.3125 - 0.3125i 0.3125 - 0.9531i
列 113 至 120
-0.9531 - 0.3125i -0.9531 + 0.9531i 0.9531 + 0.9531i -0.9531 + 0.9531i 0.3125 - 0.3125i -0.3125 + 0.3125i -0.3125 + 0.9531i 0.9531 - 0.9531i
列 121 至 128
0.9531 + 0.9531i 1.0000 + 0.0000i 0.3125 + 0.9531i 0.9531 - 0.3125i 0.9531 + 0.3125i -0.3125 - 0.3125i -0.9531 + 0.3125i 0.9531 - 0.3125i
5.ModelSim仿真
硬件按照如下图所示连接进行仿真:
将前面提到的测试数据作为输入,对硬件进行测试,仿真结果如下图:
如上图所示,在没有数据输入的空隙,将导频写入RAM对应位置。
如上图所示,输入数据根据标号,进行乱序写入RAM。
如上图所示,输出数据从RAM中顺序输出,并且另外一个缓存区可以进行数据输入,实现了乒乓缓存,以保证流水线操作。
6.结果对比验证
将ModelSim仿真结果存为txt文件,在Matlab里面读出来与Matlab的仿真结果进行比较,代码如下:
%% 插入导频
FPGA_pilot_dout = readlines('D:/FPGA/OFDM_802.11a_my/TX/matlab/pilot_data_out.txt','EmptyLineRule','skip')';
display(FPGA_pilot_dout);
FPGA_Re_pilot_dout = extractBefore(FPGA_pilot_dout,9);
FPGA_Im_pilot_dout = extractAfter(FPGA_pilot_dout,8);
display(FPGA_Re_pilot_dout);
display(FPGA_Im_pilot_dout);
q = quantizer('fixed','round','saturate',[8,6]);
FPGA_Re_pilot_dout = bin2num(q,FPGA_Re_pilot_dout);
FPGA_Im_pilot_dout = bin2num(q,FPGA_Im_pilot_dout);
FPGA_Re_pilot_dout = cell2mat(FPGA_Re_pilot_dout);
FPGA_Im_pilot_dout = cell2mat(FPGA_Im_pilot_dout);
FPGA_pilot_dout = FPGA_Re_pilot_dout + 1j*FPGA_Im_pilot_dout;
display(interFrq_out);
display(FPGA_pilot_dout);
check_pilot = FPGA_pilot_dout == interFrq_out;
display(check_pilot);
FPGA插入导频之后的输出如下:
FPGA_pilot_dout =
列 1 至 8
0.0000 + 0.0000i -0.9531 - 0.9531i -0.3125 + 0.9531i 0.9531 - 0.9531i 0.3125 + 0.3125i 0.9531 + 0.3125i 0.9531 - 0.3125i 1.0000 + 0.0000i
列 9 至 16
-0.9531 + 0.9531i 0.3125 - 0.9531i -0.3125 + 0.9531i -0.9531 + 0.9531i 0.3125 - 0.9531i -0.9531 - 0.9531i 0.3125 + 0.3125i 0.9531 + 0.9531i
列 17 至 24
-0.3125 - 0.9531i -0.3125 + 0.3125i -0.3125 + 0.3125i -0.3125 + 0.9531i 0.9531 - 0.9531i -1.0000 + 0.0000i 0.9531 + 0.9531i 0.9531 + 0.3125i
列 25 至 32
-0.3125 - 0.3125i 0.9531 - 0.3125i -0.9531 - 0.3125i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i
列 33 至 40
0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i -0.9531 + 0.9531i 0.9531 + 0.3125i
列 41 至 48
0.3125 + 0.9531i -0.9531 + 0.3125i -0.9531 + 0.9531i 1.0000 + 0.0000i 0.3125 + 0.3125i 0.9531 + 0.9531i 0.9531 + 0.3125i -0.3125 + 0.9531i
列 49 至 56
-0.9531 + 0.9531i 0.9531 + 0.9531i -0.9531 - 0.3125i 0.9531 + 0.9531i -0.3125 + 0.3125i 0.9531 + 0.3125i -0.9531 - 0.9531i 0.3125 + 0.9531i
列 57 至 64
0.3125 + 0.3125i 1.0000 + 0.0000i -0.9531 + 0.9531i -0.9531 - 0.3125i -0.9531 + 0.3125i -0.3125 + 0.9531i 0.9531 + 0.9531i -0.3125 + 0.3125i
列 65 至 72
0.0000 + 0.0000i -0.9531 - 0.9531i 0.3125 + 0.3125i -0.9531 - 0.9531i 0.3125 + 0.3125i -0.9531 - 0.3125i -0.3125 - 0.9531i 1.0000 + 0.0000i
列 73 至 80
-0.3125 + 0.3125i 0.3125 + 0.3125i -0.3125 + 0.3125i -0.3125 + 0.3125i 0.9531 - 0.9531i -0.3125 - 0.3125i -0.9531 - 0.9531i 0.3125 - 0.3125i
列 81 至 88
-0.9531 + 0.3125i 0.9531 + 0.3125i 0.3125 - 0.9531i 0.3125 - 0.9531i -0.9531 + 0.9531i -1.0000 + 0.0000i -0.9531 - 0.3125i 0.3125 - 0.9531i
列 89 至 96
0.3125 - 0.9531i -0.9531 - 0.3125i -0.3125 + 0.3125i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i
列 97 至 104
0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i -0.9531 + 0.9531i 0.9531 + 0.9531i
列 105 至 112
-0.3125 + 0.3125i -0.9531 - 0.3125i -0.3125 + 0.9531i 1.0000 + 0.0000i -0.3125 - 0.3125i -0.9531 + 0.3125i -0.3125 - 0.3125i 0.3125 - 0.9531i
列 113 至 120
-0.9531 - 0.3125i -0.9531 + 0.9531i 0.9531 + 0.9531i -0.9531 + 0.9531i 0.3125 - 0.3125i -0.3125 + 0.3125i -0.3125 + 0.9531i 0.9531 - 0.9531i
列 121 至 128
0.9531 + 0.9531i 1.0000 + 0.0000i 0.3125 + 0.9531i 0.9531 - 0.3125i 0.9531 + 0.3125i -0.3125 - 0.3125i -0.9531 + 0.3125i 0.9531 - 0.3125i
FPGA输出与Matlab仿真结果进行对比结果如下:
check_pilot =
1×128 logical 数组
列 1 至 41
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 1
列 42 至 82
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 1
列 83 至 123
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 1
列 124 至 128
1 1 1 1 1
两个OFDM符号插入导频之后为128个输出,对比逻辑结果全为‘1’,说明FPGA该模块设计完全正确,作者测试了其他调制方案和数据速率都是正确的,这里不再重复赘述。感兴趣的可以自行进行测试。
原文连接(相关文章合集):OFDM 802.11a的xilinx FPGA实现