本文介绍Vivado中Fast Fourier Transform V9.1的使用方法。
参考资料:pg109
FFT是用于计算样本大小为2的正整数幂的离散傅里叶变换(DFT)的高效计算方法。序列的DFT定义为
X(k)=∑n=0N−1x(n)e−jnk2π/Nk=0,…N−1X(k) = \sum_{n=0}^{N-1}x(n)e^{-jnk2\pi /N}\ \ k = 0,\dots N-1X(k)=n=0∑N−1x(n)e−jnk2π/N k=0,…N−1
逆离散傅里叶变换(IDFT)定义为
x(n)=1N∑n=0N−1X(k)ejnk2π/Nn=0,…,N−1x(n)= \frac{1}{N} \sum_{n=0}^{N-1}X(k)e^{jnk2\pi /N}\ \ n=0,\dots,N-1x(n)=N1n=0∑N−1X(k)ejnk2π/N n=0,…,N−1
FFT IP核使用Radix-4核Radix-2分解来计算DFT。对于突发I/O体系结构,使用时间抽取(DIT)方法,而流水线式流式I/O体系结构使用频率抽取(DIF)方法。
Configuration选项卡
Number of Channels:变换的通道数,支持1-12通道。
Transform Length:变换的数据长度,支持8-65536的所有2次方。
Architecture Configuration:
Target Clock Frequency (MHz):目标时钟频率。
Target Data Throughput(MSPS):目标数据吞吐量。
注意:设定的时钟频率和设定的数据吞吐量仅用于自动选择一个实现和计算延迟。不保证该核能以指定的目标时钟频率或目标数据吞吐量运行。
Architecture Choice:
Automatically Select:选择满足指定数据吞吐量的最小实现,前提是在FPGA上实现FFT核时达到指定的时钟频率。
Pipelined Streaming I/O::允许连续的数据处理。
Burst 1/O:使用迭代方法分别加载和处理数据。
四种架构的资源与吞吐量对比如下。
Run Time Configurable Transform Length:勾选可在IP核运行时更改变换数据长度。
Implementation选项卡
Data Format:输入和输出的数据格式,可选Fixed-Point和Floating-Point(IEEE-754单精度(32位)浮点格式)。
Scaling Options:输出数据缩放选项,可选Unscaled、Scaled、Block Floating-Point(由IP核决定缩放多少)。
Rounding Modes:舍入模式,可选Convergent Rounding或Truncated。Convergent Rounding,即当一个数字的小数部分正好等于二分之一时,如果数字是奇数,收敛四舍五入就会向上舍入,如果数字是偶数就会向下舍入。Truncated即直接截断。
Precision Options:
Input Data Width:输入数据位宽。
Phase Factor Width: 相位系数位宽。
Control Signals:
ACLKEN:IP核时钟使能信号,勾选时启用。
ARESETn(active low):IP核复位信号,勾选时为低电平有效。
Output Ordering Options
Output Ordering:输出数据排序,可选Bit/Digit Reversed Order 或Natural Order。即反转顺序或自然顺序。
Cyclic Prefix Insertion:如果输出排序为自然顺序,可以勾选循环前缀插入。
Optional Output Fields:
可选的输出字段。XK_INDEX是数据输出通道的一个可选字段。
OVFLO在数据输出通道和状态通道中都是一个可选字段。
Throttle Scheme:
节流方案。可选Non Real Time或Real Time。即非实时模式与实时模式。
Detailed Implementation选项卡
Memory Options:
选择片内RAM还是分布式RAM。
Optimize Options:
Complex Multipliers:复数乘法器的实现,可选Use CLB logic、Use 3-multiplier structure (resource optimization)、Use 4-multiplier structure (performance optimization)。即使用可编程逻辑资源或使用DSP资源。
Butterfly Arithmetic:蝶形运算的实现,可选 Use CLB logic或Use XtremeDSP Slices。即使用可编程逻辑资源或使用DSP资源。
简单来说,AXI4-Stream接口主要就是一个Basic Handshake。
TVALID由主机驱动,TVALID表示载荷字段(TDATA、TUSER和TLAST)中的值是有效的。
TREADY由从机驱动,TREADY表示从机已准备好接收数据。
当TVALID和TREADY在一个周期内同时为高电平,就会发生数据传输。
所有的TDATA和TUSER字段都以小端格式打包。所有的TDATA和TUSER向量都是8比特的倍数。当TDATA或TUSER向量中的所有字段都被连接起来时,整个向量被填充到8位边界。
s_axis_config_tdata总线包含如下字段:
该总线携带输入数据,其中XN_RE为实部分量,XN_IM为虚部分量,位宽bxn\text b_{\text {xn}}bxn为8-34,采用二进制补码或单精度浮点格式。
注意,所有带填充的字段如果没有在8位边界上结束,就应该扩展到下一个8位边界,即输入数据时,需要手动拓展至8位边界。
该总线携带输出数据,其中XK_RE为输出数据实部分量,XK_IM为虚部分量,采用二进制补码或单精度浮点格式。对于缩放运算和块浮点运算,位宽bxk\text b_{\text {xk}}bxk等于输入数据位宽bxn\text b_{\text {xn}}bxn,对无缩放运算,则bxk=bxn+log2(maximum point size)\text b_{\text {xk}} = \text b_{\text {xn}} + \text{log}_2(\text {maximum point size})bxk=bxn+log2(maximum point size),对于单精度浮点运算,则bxk=32\text b_{\text {xk}}=32bxk=32。
各字段采用符号拓展至8位边界。
该总线可携带XK_INDEX、BLK_EXP、OVFLO。
XK_INDEX,为输出数据的索引(无符号二进制补码),位宽log2(maximum point size)\text{log}_2(\text {maximum point size})log2(maximum point size),采用零填。
BLK_EXP,为运算中的缩放系数值(无符号二进制补码),位宽为8,采用零填充。该字段只在块浮点运算时可选。
OVFLO,为溢出指示位(单比特,高电平有效)。如果数据帧中的任何值溢出,OVFLO在结果卸载期间为高电平。该字段只在缩放运算或单精度浮点运算时可选。
该总线可携带BLK_EXP、OVFLO。
详细见m_axis_data_tuser总线介绍。
当IP核开始处理一个新的帧时,该信号会被拉高一个时钟周期。
当s_axis_data_tlast在一个帧的最后一个输入数据时刻为低时,该信号会被拉高一个时钟周期。该信号表明了IP核和输入数据的帧大小不匹配,拉高时表明了输入数据帧大于IP核配置的大小。
当IP核检测到在任何输入数据上s_axis_data_tlast为高电平,而这个数据不是帧中的最后一个。这表明IP核和输入数据的帧大小不匹配,拉高时表明了输入数据帧小于IP核配置的大小。
当m_axis_data_tdata上传输的数据出现溢出时,该信号在每个时钟周期内都会被拉高。
只有在使用缩放运算或单精度浮点运算时,才有可能出现溢出。在其他配置情况下,该引脚会被移除。
该信号在IP核需要数据输入通道的数据而没有数据的每个时钟周期内都会被拉高。
该信号在IP核需要向数据输出通道写入数据,但由于通道中的缓冲区已满而不能写入时,会被拉高一个时钟周期。当这种情况发生时,IP核所有活动停止,直到通道缓冲区有可用空间。该信号只在非实时模式下可用。
该信号在IP核需要向状态通道写入数据,但由于通道上的缓冲区已满而不能写入时,会被拉高一个时钟周期。当这种情况发生时,IP核所有活动停止,直到通道缓冲区有可用空间。该信号只在非实时模式下可用。
前面已经详细讲述了IP核的各项参数,根据需要自行配置即可。
仿真参数配置如下。
本次仿真使用MATLAB生成输入数据。信号生成代码如下。
clc;clear;close all;
fs = 1e4;
f1 = 5e2;
N = 1024;
t = 0:1/fs:(N-1)/fs;
x = sin(2*pi*f1*t);
x = mapminmax(x).* (2^15-1);
fid = fopen('fft_test_signal.txt', 'wt');
for i = 1:Nif (x(i) >= 0)fprintf(fid, '%s\n', dec2bin(x(i),16));else fprintf(fid, '%s\n', dec2bin(2^16 + x(i), 16));end
end
fclose(fid);
y = fft(x(1:256)) / 2^9;
y_re = real(y);
y_im = imag(y);
plot(y_re);
figure;
plot(y_im);
仿真代码如下。
module FFT_sim;
reg aclk;
reg aresetn;
reg [23:0] s_axis_config_tdata;
reg s_axis_config_tvalid;reg [31:0] s_axis_data_tdata;
reg s_axis_data_tvalid;
reg s_axis_data_tlast;
reg m_axis_data_tready;wire [31:0] m_axis_data_tdata;
wire [7:0] m_axis_data_tuser;
wire m_axis_data_tlast;
wire m_axis_data_tvalid;wire s_axis_config_tready;
wire s_axis_data_tready;
wire event_frame_started;
wire event_tlast_unexpectedl;
wire event_tlast_unexpected;
wire event_tlast_missing;
wire event_status_channel_halt;
wire event_data_in_channel_halt;
wire event_data_out_channel_halt;initial begin aclk = 1'b0;forever begin#2.5; aclk = ~aclk;end
endinitial begin aresetn = 1'b0;# 40;aresetn = 1'b1;
endinitial begins_axis_config_tdata = {7'b000_0000, 16'b_01_01_01_01_01_01_01_10, 1'b1};s_axis_config_tvalid = 1'b1;
endreg [15:0] data_in[0:1024-1];
integer i;
initial begin $readmemb("D:/Xilinx2/Vivado/2018.3/user_projects/ip_fft/fft_test_signal.txt", data_in);i = 0;s_axis_data_tdata = 32'd0;s_axis_data_tlast = 1'b0;m_axis_data_tready = 1'b1;# 10;forever begin@(negedge aclk) beginif(s_axis_data_tready == 1'b1) begins_axis_data_tvalid = 1'b1;s_axis_data_tdata = {data_in[i], 16'd0};if(i == 1024-1) begini = 0;endelse begini = i+1;endendelse begins_axis_data_tvalid = 1'b0;end endend
endwire [15:0] Xk_Re, Xk_Im;
assign Xk_Re = m_axis_data_tdata[31:16];
assign Xk_Im = m_axis_data_tdata[15:0];FFT your_instance_name (.aclk(aclk), // input wire aclk.aresetn(aresetn), // input wire aresetn.s_axis_config_tdata(s_axis_config_tdata), // input wire [23 : 0] s_axis_config_tdata.s_axis_config_tvalid(s_axis_config_tvalid), // input wire s_axis_config_tvalid.s_axis_config_tready(s_axis_config_tready), // output wire s_axis_config_tready.s_axis_data_tdata(s_axis_data_tdata), // input wire [31 : 0] s_axis_data_tdata.s_axis_data_tvalid(s_axis_data_tvalid), // input wire s_axis_data_tvalid.s_axis_data_tready(s_axis_data_tready), // output wire s_axis_data_tready.s_axis_data_tlast(s_axis_data_tlast), // input wire s_axis_data_tlast.m_axis_data_tdata(m_axis_data_tdata), // output wire [31 : 0] m_axis_data_tdata.m_axis_data_tuser(m_axis_data_tuser), // output wire [7 : 0] m_axis_data_tuser.m_axis_data_tvalid(m_axis_data_tvalid), // output wire m_axis_data_tvalid.m_axis_data_tready(m_axis_data_tready), // input wire m_axis_data_tready.m_axis_data_tlast(m_axis_data_tlast), // output wire m_axis_data_tlast.event_frame_started(event_frame_started), // output wire event_frame_started.event_tlast_unexpected(event_tlast_unexpected), // output wire event_tlast_unexpected.event_tlast_missing(event_tlast_missing), // output wire event_tlast_missing.event_status_channel_halt(event_status_channel_halt), // output wire event_status_channel_halt.event_data_in_channel_halt(event_data_in_channel_halt), // output wire event_data_in_channel_halt.event_data_out_channel_halt(event_data_out_channel_halt) // output wire event_data_out_channel_halt
);endmodule
仿真波形如下。
启用XK_INDEX时,该字段由m_axis_data_tuser携带。
根据上图可知频谱实部分量的第一个波峰出现在XK_INDEX = 13时,XK_RE = 1191。由NFFT = 256,fs = 1e4Hz,可知XK_INDEX / NFFT * fs = 507.8 Hz。
仿真结果与MATLAB计算结果一致。需要注意的是,仿真时FFT IP核的SCALE_SCH = 16’b_01_01_01_01_01_01_01_10,对应缩放系数为1/512。故MATLAB计算的FFT结果也需要除以512。
上一篇:如何恰当地对孩子进行死亡教育
下一篇:如何争取孩子的抚养权?