原文链接(相关文章合集):OFDM 802.11a的xilinx FPGA实现
1.前言
在之前已经完成了data域数据的处理,在构建整个802.11a OFDM数据帧的时候,还剩下前导码和signal域的数据帧,这两部分的内容。 PLCP的前导部分由一组重复10次的短训练序列和一组加了一个长型保护间隔与重复2次的有效OFDM符号组成的长训练序列组成。今天先来实现短训练序列。
2.原理
短训练序列的主要用途是进行信号的检测、AGC和粗频偏估计。短训练序列都是经过精心的设计,每个短训练序列的长度为0.8us,在802.11a的前导码当中一共有10个短训练序列。这些短训练序列符号占据每个OFDM符号的52个非零子载波当中的12个。如果用-26~26来标识非零子载波的话,那么短训练序列的子载波的序号为{-24, -20, -16, -12, -8, -4, 4, 8, 12, 16, 20, 24},其中传输的传输数据为一个固定的伪随机序列,采用的QPSK的映射方式。
由于短训练序列只用了52个子载波当中12个来传输符号,因此为了保证OFDM符号的功率稳定,需要乘以因子 。短训练序列的的选择可以是的在较大的范围内实现粗频率估计,通常对于周期为T的重复符号而言,最大可估计的频率偏差为,因此通过测量连续两个长度为0.8us的短训练序列符号的相位差,可以估计的频率偏差可达625KHz。 训练序列生成模块主要是提前将长、短序列的时域样值计算出并存入RAM中,需要时直接读取数据即可。
3.Matlab仿真
由于Data域数据在IFFT处理之前会扩大8倍,相应的长训练序列在进行IFFT处理之前也需要扩大8倍。同时长、短训练序列也是需要经过加窗处理的,即多输出一个样值,该值为第一个样值,同时将第一个样值与最后一个样值缩小一倍。Matlab生成短训练序列代码如下:
%产生长短训练序列、帧头
short_training =[0,0,0,0,-1-1i,0,0,0,-1-1i,0,0,0,1+1i,0,0,0,1+ ...
1i,0,0,0,1+1i,0,0,0,1+1i,0,0,0,0,0,0,0,0,0,0,0,0,0,...
0,0,1+1i,0,0,0,-1-1i,0,0,0,1+1i,0,0,0,-1-1i, ...
0,0,0,-1-1i,0,0,0,1+1i,0,0,0]; % short training sequence
sts_frq = (13/6)^0.5 .* short_training;
sts_time = 8*ifft(sts_frq,64); %对短训练序列进行ifft
%取16点,将该序列重复10次
sts16 = sts_time(1:16);
sts16_q = num2bin(q,sts16);%量化,存到FPGA的ROM
sts_rom = sts16;
for n = 1:9
sts_rom = [sts_rom,sts16];
end
q = quantizer('fixed','round','saturate',[8,6]);%复数以8位定点数形式进行输出,格式为:1位符号位,一位整数位,6位小数位,负数以补码形式表示。
sts_rom = [0.5*sts_rom(1),sts_rom(2:end),0.5*sts16(1)]; %加窗
生成的STS序列如下表所示,把它们存到FPGA的ROM里面:
地址 | 实部 | 虚部 | 地址 | 实部 | 虚部 |
---|---|---|---|---|---|
0 | 8'b00011000 | 8'b00011000 | 8 | 8'b00011000 | 8'b00011000 |
1 | 8'b10111100 | 8'b00000001 | 9 | 8'b00000001 | 8'b10111100 |
2 | 8'b11111001 | 8'b11011000 | 10 | 8'b11011000 | 8'b11111001 |
3 | 8'b01001001 | 8'b11111010 | 11 | 8'b11111010 | 8'b01001001 |
4 | 8'b00101111 | 8'b00000000 | 12 | 8'b00000000 | 8'b00101111 |
5 | 8'b01001001 | 8'b11111010 | 13 | 8'b11111010 | 8'b01001001 |
6 | 8'b11111001 | 8'b11011000 | 14 | 8'b11011000 | 8'b11111001 |
7 | 8'b10111100 | 8'b00000001 | 15 | 8'b00000001 | 8'b10111100 |
4.硬件实现
STS一个周期的16个时域样值被存入片内ROM中,ROM的具体内容如上面的表所示,该ROM共有16个地址空间,每个地址对应16位的字长,其中高8位存储STS样值的虚部,低8位存储STS样值的实部(与IFFT输出保持一致)。ROM的地址信号由一个模161的计数器生成。STS_din_rdy作为ROM的读使能信号,代表后面的模块准备好接收数据。当STS_din_rdy为高时,计数器以模161形式开始计数161个时钟,生成的地址信号为计数器的低4位,即cnt[3:0]控制ROM将其中存储的16个STS样值重复读取10个周期,形成标准所规定的短训练序列。 代码如下:
assign En_cnt = STS_din_rdy & ~cnt_last;
counter #(.CNT_NUM('d161),
.ADD(1'b1))
u_counter(
.clk (clk ),
.rst_n (rst_n ),
.En_cnt (En_cnt ),
.cnt (cnt ),
.cnt_last (cnt_last )
);
always @(posedge clk or negedge rst_n)
if(!rst_n)begin
STS_dout_last <= 1'b0;
STS_dout_Index <= 'd0;
end
else begin
STS_dout_last <= cnt_last;
STS_dout_Index <= cnt;
end
always @(posedge clk or negedge rst_n) begin
if(~rst_n) begin //时域样值Im Re
Short_Mem[0] <= {8'b00011000,8'b00011000};
Short_Mem[1] <= {8'b00000001,8'b10111100};
Short_Mem[2] <= {8'b11011000,8'b11111001};
Short_Mem[3] <= {8'b11111010,8'b01001001};
Short_Mem[4] <= {8'b00000000,8'b00101111};
Short_Mem[5] <= {8'b11111010,8'b01001001};
Short_Mem[6] <= {8'b11011000,8'b11111001};
Short_Mem[7] <= {8'b00000001,8'b10111100};
Short_Mem[8] <= {8'b00011000,8'b00011000};
Short_Mem[9] <= {8'b10111100,8'b00000001};
Short_Mem[10] <= {8'b11111001,8'b11011000};
Short_Mem[11] <= {8'b01001001,8'b11111010};
Short_Mem[12] <= {8'b00101111,8'b00000000};
Short_Mem[13] <= {8'b01001001,8'b11111010};
Short_Mem[14] <= {8'b11111001,8'b11011000};
Short_Mem[15] <= {8'b10111100,8'b00000001};
STS_dout <= 'd0;
STS_dout_vld <= 1'b0;
end
else if(STS_din_rdy & STS_dout_last)
STS_dout_vld <= 1'b0;
else if(cnt == 'd0 | cnt_last)begin
STS_dout <= {Short_Mem[0][15:8]>>1,Short_Mem[0][7:0]>>1};
STS_dout_vld <= 1'b1;
end
else begin
STS_dout <= Short_Mem[cnt[3:0]];
STS_dout_vld <= 1'b1;
end
end
此处的设计已经考虑了加窗处理(Windowing),该操作在硬件中的实现方法是:将要进行加窗处理的数据单元(STS)多输出一个样值(数据单元的第一个样值),同时将数据单元的第一个样值和最后一个样值缩小1倍。在传输时,一个数据单元的最后一个样值将与下一个数据单元的第一个样值进行相加,成为一个采样点。因此,本设计中计数161个而非160个时钟,它将控制ROM在第161个时钟周期内再输出一个样值(地址为0的第一个样值)。模块的输出部分会对第一个和最后一个样值执行右移1位(即除以2)的操作,从而最终完成加窗处理。
5.MosdelSim仿真
原文链接(相关文章合集):OFDM 802.11a的xilinx FPGA实现