原文链接(相关文章合集):OFDM 802.11a的xilinx FPGA实现
1.前言
在前面的博客当中,已经实现了星座图的映射和导频插入,得到了在频域上的点,接下来要做的就是将频域的信号,转换到时域,因为最终在信道中传输的信号都是实际存在的信号。
2.时序参数
根据信道间隔(channel spacing)的不同,可以计算出如下一些参数:
可以看到当信道间隔为20MHz时,一个OFDM的符号的有效数据周期是3.2us,一个OFDM的符号周期是4us。假设采样率是20M,那么该采样率下的采样周期是50ns,因此一个OFDM符号的有效周期需要64个采样点。所以我们只要保证IFFT的输出数据速率大于20MHz即可,后续在DAC输出的时候,再将数据速率降到20M,由于我们设计的时候数据流一直采用的是vaild-ready握手机制,DAC没有输出完当前数据会对前面的一系列处理形成反压,进而可以保证OFDM符号间不会存在间隙。
考虑到IFFT的输出需要满足20MHz的数据速率,使用最快的传输方案,64-QAM调制+3/4编码效率。编码前的数据速率应该为2063/4=90MHz;编码后的数据速率为20*6=120MHz。为了仿真方便,系统时钟选取125MHz。
书中在这个地方又用到了跨时钟域,其目的是为了要保证IFFT输出速率为20MHz。其实作者觉得要保证IFFT输出速率为20MHz不必这样处理,因为输出点数64点是确定的,后面一个OFDM的符号的有效数据周期3.2us,完全取决于DAC的时钟频率,也就是输出的采样率,保证他是20M就行。还有一点是,当DAC输出完一个符号周期后,能够再符号间隔内送来源源不断的数据就行。所以采用vaild-ready握手机制,可以完美解决这一问题。
3.IFFT
前面在插入导频时,已经调整了数据的顺序,使其映射到了适合的IFFT模块端口上(点此链接跳转到插入导频文章),如下图所示:
在设计上,直接利用Xilinx提供的IP核来实现FFT功能。本系统采样版本为FFT 9.1 ,该IP核核心功能强大,配置灵活,完全可以满足本系统的要求。
FFT处理随着点数和阶数的不同会有多级蝶形运算,比如64点Radix-4FFT就会包含3级运算。FFT核在处理时每级运算的原始数据和运算结果被放在相同的存储空间中,而通常运算结果的值会比原始数据有所增大,如Radix一4DITFFT的每级蝶形运算的增长比例为
4
2
≈
5.675
4\sqrt[]2\approx5.675
42≈5.675。因此,必须引人一种策略来匹配这种动态范围的增加。我们采用配置FFT核的 Scaling Schedule 来对此加以控制,每一级运算均可通过设定比例因子(值为1、2、4或8)来对结果进行按比例缩小,或者说是向右进行移位。当然,最终的处理结果也就相应地除以了一个系数s:
s
=
2
∑
i
=
0
log
2
N
b
i
s = 2^{\sum_{i=0} ^ {\log_2 N} b_i}
s=2∑i=0log2Nbi
其中,
b
i
b_i
bi为第
i
i
i级的移位比特数。通过适当设定每一级的b值可有效防止蝶形运算结果溢出(超出存储空间大小)的发生。
FFT IP核框图如下:
FFT IP核端口信号描述:
信号 | 方向 | 说明 |
---|---|---|
s_axis_config_tdata | in | 配置参数 |
s_axis_config_tvalid | in | 配置参数有效 |
s_axis_config_tready | out | FFT IP核配置参数准备好 |
s_axis_data_tdata | in | 输入数据。低16位为实数输入,高16位为虚数输入 |
s_axis_data_tvalid | in | 数据有效信号 |
s_axis_data_tready | out | 输入数据准备好 |
s_axis_data_tlast | in | 标识每帧的最后一个数据 |
m_axis_data_tdata | out | 数据输出(复数) |
m_axis_data_tuser | out | 输出数据的下标 |
m_axis_data_tvalid | out | 数据有效 |
m_axis_data_tready | in | 接收数据准备好 |
m_axis_data_tlast | out | 标识最后一个数据 |
event_frame_started | out | 当开始处理一个新帧时,该事件信号被断言为单个时钟周期 |
event_tlast_unexpected | out | 当没有接收到一帧的最后一个数据而s_axis_data_tlast拉高时,这表明输入数据的长度与IP核预设的数据不匹配 |
event_tlast_missing | out | 当接收到一帧的最后一个数据而s_axis_data_tlast没有拉高时,这表明输入数据的长度与IP核预设的数据不匹配 |
event_status_channel_halt | out | 每当核心需要向data Output通道写入数据,但由于通道中的缓冲区已满而无法写入时,都会断言此事件 |
event_data_in_channel_halt | out | 当IP核需要来自数据输入通道的数据但没有可用数据时,在每个周期断言此事件。 |
event_data_out_channel_halt | out | 每当核心需要向Status通道写入数据,但由于通道上的缓冲区已满而无法写入时,都会断言此事件。 |
对FFT 9.1 IP核信息配置为:
(1)Configuration:
Number of Channels(通道数)设置为:1;
Transform Length(FFT长度)设置为:64;
Target Clock Frequency(目标时钟频率)设置为:125MHz
Architecture Choice(FFT结构选择)设置为:Radix-4,基4的迭代算法,使用的资源比流水线结构多,相对于Radix-2时间相对更短;
(2)Implementation:
Data Format(数据格式)设置为:Fixed Point,定点数;
Scaling Options(缩放选项)设置为:Scaled,截断数据与输入数据位宽相同;
Rounding Modes(舍入模式)设置为:Truncation收敛截位,如果该数是奇数则向上舍入,如果该数是偶数则向下舍入;
Precision Options(精度选项)均设置为:16,为了提高FFT处理时中间步骤的运算精度,保证DAC变换的精度,需对输入I/Q两路数据进行放大处理,并将FFT IP核的输入位宽设置为16位;
Control Signal可选可不选;
Output Ordering(输出秩序)设置为:Natural Order自然顺序;
Optional Output Fields设置为: XK_INDEX, 输出数据的通道数,也即是XK 的下标;
Throttle Schemes设置为:Non Real Time;
(3)Detaild implementation:
Memory option,选择数据存储的存储器类型;Optimize options优化选项等默认即可。
**(4)s_axis_config_tdata: **\
参数FWD_INV表示变换方向,设置为0代表IFFT处理;SCALESCH被设置成101110,代表三级蝶形运算的结果将分别右移2位、3位和2位。
IFFT处理模块的输人数据为I/Q两个支路的8位复数信号,如果经过FFT处理之后输出数据还用这种格式表示的话数值会过小,从而影响DAC的变换精度。因此,需要对输人信号进行适当放大。通过对IFFT变换的结果进行大量分析,结果表明可以将放大比例确定为8倍,即左移3位。为此,将FFT核的输入、输出位宽设为16bits,只需将输人数据加至适当的端口即可实现移位操作,这样做同时也提高了FFT核在处理时中间步骤的运算精度。即对I/Q两路数据左移3位,再以高位填充符号位,低位补零形式,扩展为两路16bits数据输入到FFT中;而FFT输出的两路16bits数据直接曲低8bits作为模块输出数据即可。
4.Matlab仿真
以2个OFDM符号,16-QAM调制,编码效率为3/4,进行仿真,生成测试数据共计288个,如下:
test_data =
列 1 至 27
1 1 1 1 1 0 0 1 1 0 1 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0
列 28 至 54
1 1 1 1 0 0 0 0 0 1 1 1 0 1 0 1 1 0 1 1 1 1 0 0 0 0 1
列 55 至 81
0 0 1 1 1 1 0 0 0 1 1 0 0 0 0 1 1 1 1 1 1 0 0 1 0 1 1
列 82 至 108
0 0 1 0 0 1 0 0 0 1 0 1 0 0 0 0 1 0 1 1 0 1 1 0 1 1 1
列 109 至 135
1 1 1 1 0 1 1 0 1 0 0 0 0 0 0 1 0 1 1 1 0 0 1 0 1 1 0
列 136 至 162
0 0 0 1 0 1 1 1 1 0 1 1 1 0 1 0 1 1 1 1 1 0 0 1 0 1 0
列 163 至 189
0 0 1 0 0 0 0 0 0 0 0 1 1 0 0 1 0 1 1 1 1 0 1 0 0 0 1
列 190 至 216
1 0 0 1 0 1 1 1 1 0 1 1 0 1 0 1 0 1 0 1 0 0 0 0 0 1 1
列 217 至 243
0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 0 0 1 0 1 1 1 0 0 0 1 0
列 244 至 270
0 0 0 1 0 1 0 0 1 0 1 0 1 1 0 1 0 0 1 0 1 0 1 1 1 1 1
列 271 至 288
1 1 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 1
测试数据经过前面章节的扰码、编码、删余、交织、调制映射,插入导频然后进行IFFT变换:
%% IFFT
ifft_in = interFrq_out * 8;
ifft_out = zeros(1,k*64);
for m = 1:k
reg64 = ifft_in((m-1)*64+1:m*64);
figure;
subplot(2,1,1);
plot(real(reg64));title('频域实部',m);
subplot(2,1,2);
plot(imag(reg64));title('频域虚部',m);
reg_ifft = ifft(reg64);
ifft_out((m-1)*64+1:m*64) = reg_ifft;
figure;
subplot(2,1,1);
plot(real(reg_ifft));title('时域实部第',m);
subplot(2,1,2);
plot(imag(reg_ifft));title('时域虚部',m);
end
IFFT后归一化输出如下:
ifft_out =
列 1 至 8
-0.3253 - 0.1329i -0.2316 - 0.2906i 0.1008 - 0.1777i -0.1240 + 0.2668i -0.1403 + 0.2585i -0.3224 + 0.0718i -0.3029 - 0.2896i 0.8289 - 0.5594i
列 9 至 16
0.3061 - 0.0351i -0.3690 - 0.1068i 0.4054 - 0.2386i 0.5546 + 0.1421i 0.3318 - 0.0937i -0.2388 + 0.0225i -0.2653 + 0.2268i 0.1075 - 0.0491i
列 17 至 24
0.1003 - 0.1068i 0.2367 + 0.0368i -0.2025 + 0.3684i 0.0231 + 0.1027i 0.1485 - 0.3032i -0.4276 - 0.0716i -0.0256 - 0.0448i -0.1236 - 0.1565i
列 25 至 32
-0.0052 - 0.3379i 0.0740 - 0.3388i -0.3170 - 0.0126i 0.6578 + 0.1386i 0.3836 + 0.1129i -0.4203 - 0.1759i -0.0069 - 0.2119i -0.3956 - 0.2557i
列 33 至 40
-0.3367 - 0.2617i 0.0502 + 0.2798i -0.3106 - 0.0144i -0.0484 - 0.1600i 0.3848 + 0.3613i 0.0988 + 0.0377i -0.0468 - 0.0212i 0.2141 + 0.0445i
列 41 至 48
0.1586 + 0.0987i -0.0324 + 0.5606i -0.1890 - 0.1342i -0.1359 - 0.6221i 0.0824 + 0.1922i 0.2141 + 0.4071i 0.6705 + 0.1017i 0.4924 + 0.1139i
列 49 至 56
0.1671 + 0.1035i 0.3162 - 0.2573i -0.1159 - 0.3054i -0.0509 + 0.2168i 0.0016 + 0.0813i -0.2301 - 0.1296i 0.0017 + 0.3049i -0.3279 - 0.0587i
列 57 至 64
-0.3258 - 0.3909i -0.2772 + 0.1992i -0.4276 + 0.2471i 0.1038 + 0.2103i 0.1250 + 0.4537i -0.0319 + 0.2898i -0.0248 + 0.2016i -0.1846 + 0.0910i
列 65 至 72
0.2372 + 0.0668i 0.1863 - 0.5827i 0.3817 - 0.2669i -0.4475 - 0.1653i -0.4536 - 0.2257i -0.0419 + 0.0861i 0.0390 + 0.2386i 0.0201 + 0.0618i
列 73 至 80
-0.1721 + 0.0476i 0.1014 + 0.3963i 0.3862 + 0.2697i 0.2072 - 0.0501i -0.2653 + 0.0069i -0.2896 - 0.2644i 0.0475 - 0.0593i 0.1191 + 0.3279i
列 81 至 88
-0.1329 + 0.0293i -0.4137 + 0.3165i 0.4212 + 0.1766i 0.7382 - 0.3611i -0.0471 + 0.2495i -0.1248 + 0.4189i -0.0929 + 0.0596i 0.1798 - 0.0289i
列 89 至 96
0.0815 - 0.1434i 0.0336 + 0.0365i 0.6346 - 0.0886i 0.2034 - 0.3686i 0.4171 + 0.0965i 0.3726 + 0.5605i -0.7166 + 0.2806i -0.4805 + 0.2403i
列 97 至 104
-0.3693 + 0.3962i -0.2068 - 0.4212i 0.0333 - 0.5845i -0.3279 + 0.0463i -0.3120 - 0.1681i -0.6687 - 0.2213i -0.3431 - 0.1643i 0.4127 - 0.1145i
列 105 至 112
0.2406 + 0.0845i 0.0266 - 0.1756i -0.0883 - 0.0780i -0.0068 + 0.0625i -0.1025 + 0.2393i 0.0772 + 0.2905i 0.3543 - 0.4319i -0.0059 - 0.1502i
列 113 至 120
0.0008 + 0.1696i -0.0332 - 0.4500i 0.1706 - 0.2083i 0.2021 + 0.1370i -0.2504 + 0.0138i 0.0802 - 0.0244i 0.0015 + 0.1082i -0.1002 + 0.0407i
列 121 至 128
-0.1467 - 0.3832i -0.2225 + 0.1331i 0.4478 + 0.5125i -0.0403 - 0.0479i -0.3167 + 0.0551i 0.0668 - 0.0988i -0.0854 - 0.2990i 0.3832 + 0.3700i
5.ModelSim仿真
按照如下连接进行仿真:
仿真截图如下:
仿真的输出如下(归一化后):
FPGA_ifft_dout =
列 1 至 8
-0.3383 - 0.1431i -0.2473 - 0.2993i 0.0911 - 0.1952i -0.1431 + 0.2473i -0.1431 + 0.2473i -0.3253 + 0.0521i -0.3123 - 0.2993i 0.8198 - 0.5726i
列 9 至 16
0.2993 - 0.0390i -0.3774 - 0.1171i 0.4034 - 0.2473i 0.5466 + 0.1301i 0.3253 - 0.1041i -0.2473 + 0.0130i -0.2733 + 0.2212i 0.1041 - 0.0521i
列 17 至 24
0.0911 - 0.1171i 0.2342 + 0.0390i -0.2082 + 0.3644i 0.0130 + 0.0911i 0.1431 - 0.3123i -0.4294 - 0.0781i -0.0390 - 0.0521i -0.1301 - 0.1562i
列 25 至 32
-0.0130 - 0.3383i 0.0651 - 0.3514i -0.3253 - 0.0260i 0.6507 + 0.1301i 0.3774 + 0.1041i -0.4164 - 0.1822i -0.0130 - 0.2212i -0.4034 - 0.2603i
列 33 至 40
-0.3383 - 0.2603i 0.0390 + 0.2733i -0.3123 - 0.0130i -0.0521 - 0.1692i 0.3774 + 0.3514i 0.0911 + 0.0390i -0.0521 - 0.0260i 0.2082 + 0.0390i
列 41 至 48
0.1431 + 0.0911i -0.0390 + 0.5466i -0.1952 - 0.1431i -0.1431 - 0.6246i 0.0781 + 0.1822i 0.2082 + 0.4034i 0.6637 + 0.0911i 0.4815 + 0.1041i
列 49 至 56
0.1692 + 0.1041i 0.3123 - 0.2603i -0.1301 - 0.3123i -0.0521 + 0.2082i 0.0000 + 0.0781i -0.2342 - 0.1301i -0.0130 + 0.2993i -0.3383 - 0.0651i
列 57 至 64
-0.3383 - 0.3904i -0.2863 + 0.1952i -0.4425 + 0.2473i 0.0911 + 0.2082i 0.1041 + 0.4425i -0.0521 + 0.2863i -0.0390 + 0.1952i -0.1952 + 0.0781i
列 65 至 72
0.2212 + 0.0521i 0.1822 - 0.5986i 0.3774 - 0.2733i -0.4555 - 0.1822i -0.4555 - 0.2342i -0.0521 + 0.0651i 0.0260 + 0.2212i 0.0130 + 0.0521i
列 73 至 80
-0.1692 + 0.0390i 0.1041 + 0.3904i 0.3774 + 0.2603i 0.2082 - 0.0521i -0.2733 + 0.0000i -0.2993 - 0.2733i 0.0390 - 0.0651i 0.1171 + 0.3253i
列 81 至 88
-0.1431 + 0.0260i -0.4164 + 0.3123i 0.4164 + 0.1692i 0.7287 - 0.3644i -0.0521 + 0.2473i -0.1301 + 0.4034i -0.1041 + 0.0521i 0.1692 - 0.0390i
列 89 至 96
0.0651 - 0.1562i 0.0260 + 0.0260i 0.6246 - 0.0911i 0.1952 - 0.3774i 0.4034 + 0.0911i 0.3644 + 0.5466i -0.7157 + 0.2733i -0.4815 + 0.2342i
列 97 至 104
-0.3774 + 0.3904i -0.2082 - 0.4294i 0.0260 - 0.5856i -0.3383 + 0.0390i -0.3123 - 0.1692i -0.6767 - 0.2342i -0.3514 - 0.1692i 0.4034 - 0.1171i
列 105 至 112
0.2342 + 0.0781i 0.0130 - 0.1822i -0.0911 - 0.0781i -0.0130 + 0.0521i -0.1171 + 0.2342i 0.0651 + 0.2863i 0.3514 - 0.4425i -0.0130 - 0.1562i
列 113 至 120
0.0000 + 0.1692i -0.0390 - 0.4555i 0.1692 - 0.2212i 0.1952 + 0.1301i -0.2603 + 0.0130i 0.0651 - 0.0260i -0.0130 + 0.1041i -0.1041 + 0.0390i
列 121 至 128
-0.1562 - 0.3904i -0.2342 + 0.1301i 0.4294 + 0.5075i -0.0521 - 0.0521i -0.3253 + 0.0521i 0.0521 - 0.1041i -0.1041 - 0.3123i 0.3644 + 0.3644i
6.结果对比验证
因为Matlab使用的是浮点数计算IFFT,而Vivado的IP核使用的是定点数,两者计算结果肯定不会完全相同,有误差,我们做归一化之后画图进行比较,判断是否正确比较直观,代码如下:
%% IFFT
FPGA_ifft_dout = readlines('D:/FPGA/OFDM_802.11a_my/TX/matlab/ifft_data_out.txt','EmptyLineRule','skip')';
display(FPGA_ifft_dout);
FPGA_Im_ifft_dout = extractBefore(FPGA_ifft_dout,9);
FPGA_Re_ifft_dout = extractAfter(FPGA_ifft_dout,8);
display(FPGA_Re_ifft_dout);
display(FPGA_Im_ifft_dout);
q = quantizer('fixed','round','saturate',[8,6]);
FPGA_Re_ifft_dout = bin2num(q,FPGA_Re_ifft_dout);
FPGA_Im_ifft_dout = bin2num(q,FPGA_Im_ifft_dout);
FPGA_Re_ifft_dout = cell2mat(FPGA_Re_ifft_dout);
FPGA_Im_ifft_dout = cell2mat(FPGA_Im_ifft_dout);
FPGA_ifft_dout = FPGA_Re_ifft_dout + 1j*FPGA_Im_ifft_dout;
ifft_out = ifft_out / max(abs(ifft_out));
FPGA_ifft_dout = FPGA_ifft_dout /max(abs(FPGA_ifft_dout));%归一化
display(ifft_out);
display(FPGA_ifft_dout);
figure;
subplot(2,1,1);
plot(real(ifft_out));title('Matlab IFFT后实部');
subplot(2,1,2);
plot(real(FPGA_ifft_dout));title('FPGA IFFT后实部');
figure;
subplot(2,1,1);
plot(imag(ifft_out));title('Matlab IFFT后虚部');
subplot(2,1,2);
plot(imag(FPGA_ifft_dout));title('FPGA IFFT后虚部');
可以看到走势都是差不多,而且数值差异也不大,可以认为设计是没有问题的。
7.verilog代码
该模块的端口如下图所示:
代码链接:https://mp.weixin.qq.com/s/y4SmBKr0e7uJbiN1PI-Xyg
原文链接(相关文章合集):OFDM 802.11a的xilinx FPGA实现