本文介紹Vivado中Fast Fourier Transform V9.1的使用方法。
參考資料:pg109
FFT理論
FFT是用于計(jì)算樣本大小為2的正整數(shù)冪的離散傅里葉變換(DFT)的高效計(jì)算方法。序列的DFT定義為
X
(
k
)
=
∑
n
=
0
N
?
1
x
(
n
)
e
?
j
n
k
2
π
/
N
??
k
=
0
,
…
N
?
1
X(k) = \sum_{n=0}^{N-1}x(n)e^{-jnk2\pi /N}\ \ k = 0,\dots N-1
X(k)=n=0∑N?1?x(n)e?jnk2π/N??k=0,…N?1
逆離散傅里葉變換(IDFT)定義為
x
(
n
)
=
1
N
∑
n
=
0
N
?
1
X
(
k
)
e
j
n
k
2
π
/
N
??
n
=
0
,
…
,
N
?
1
x(n)= \frac{1}{N} \sum_{n=0}^{N-1}X(k)e^{jnk2\pi /N}\ \ n=0,\dots,N-1
x(n)=N1?n=0∑N?1?X(k)ejnk2π/N??n=0,…,N?1
FFT IP核使用Radix-4核Radix-2分解來(lái)計(jì)算DFT。對(duì)于突發(fā)I/O體系結(jié)構(gòu),使用時(shí)間抽?。―IT)方法,而流水線式流式I/O體系結(jié)構(gòu)使用頻率抽?。―IF)方法。
IP核參數(shù)
Configuration選項(xiàng)卡
Number of Channels:變換的通道數(shù),支持1-12通道。
Transform Length:變換的數(shù)據(jù)長(zhǎng)度,支持8-65536的所有2次方。
Architecture Configuration:
Target Clock Frequency (MHz):目標(biāo)時(shí)鐘頻率。
Target Data Throughput(MSPS):目標(biāo)數(shù)據(jù)吞吐量。
注意:設(shè)定的時(shí)鐘頻率和設(shè)定的數(shù)據(jù)吞吐量?jī)H用于自動(dòng)選擇一個(gè)實(shí)現(xiàn)和計(jì)算延遲。不保證該核能以指定的目標(biāo)時(shí)鐘頻率或目標(biāo)數(shù)據(jù)吞吐量運(yùn)行。
Architecture Choice:
Automatically Select:選擇滿足指定數(shù)據(jù)吞吐量的最小實(shí)現(xiàn),前提是在FPGA上實(shí)現(xiàn)FFT核時(shí)達(dá)到指定的時(shí)鐘頻率。
Pipelined Streaming I/O::允許連續(xù)的數(shù)據(jù)處理。
Burst 1/O:使用迭代方法分別加載和處理數(shù)據(jù)。
四種架構(gòu)的資源與吞吐量對(duì)比如下。Run Time Configurable Transform Length:勾選可在IP核運(yùn)行時(shí)更改變換數(shù)據(jù)長(zhǎng)度。
Implementation選項(xiàng)卡
Data Format:輸入和輸出的數(shù)據(jù)格式,可選Fixed-Point和Floating-Point(IEEE-754單精度(32位)浮點(diǎn)格式)。
Scaling Options:輸出數(shù)據(jù)縮放選項(xiàng),可選Unscaled、Scaled、Block Floating-Point(由IP核決定縮放多少)。
Rounding Modes:舍入模式,可選Convergent Rounding或Truncated。Convergent Rounding,即當(dāng)一個(gè)數(shù)字的小數(shù)部分正好等于二分之一時(shí),如果數(shù)字是奇數(shù),收斂四舍五入就會(huì)向上舍入,如果數(shù)字是偶數(shù)就會(huì)向下舍入。Truncated即直接截?cái)唷?br>Precision Options:
Input Data Width:輸入數(shù)據(jù)位寬。
Phase Factor Width: 相位系數(shù)位寬。
Control Signals:
ACLKEN:IP核時(shí)鐘使能信號(hào),勾選時(shí)啟用。
ARESETn(active low):IP核復(fù)位信號(hào),勾選時(shí)為低電平有效。
Output Ordering Options:
Output Ordering:輸出數(shù)據(jù)排序,可選Bit/Digit Reversed Order 或Natural Order。即反轉(zhuǎn)順序或自然順序。
Cyclic Prefix Insertion:如果輸出排序?yàn)樽匀豁樞?,可以勾選循環(huán)前綴插入。
Optional Output Fields:
可選的輸出字段。XK_INDEX是數(shù)據(jù)輸出通道的一個(gè)可選字段。
OVFLO在數(shù)據(jù)輸出通道和狀態(tài)通道中都是一個(gè)可選字段。
Throttle Scheme:
節(jié)流方案??蛇xNon Real Time或Real Time。即非實(shí)時(shí)模式與實(shí)時(shí)模式。
Detailed Implementation選項(xiàng)卡
Memory Options:
選擇片內(nèi)RAM還是分布式RAM。
Optimize Options:
Complex Multipliers:復(fù)數(shù)乘法器的實(shí)現(xiàn),可選Use CLB logic、Use 3-multiplier structure (resource optimization)、Use 4-multiplier structure (performance optimization)。即使用可編程邏輯資源或使用DSP資源。
Butterfly Arithmetic:蝶形運(yùn)算的實(shí)現(xiàn),可選 Use CLB logic或Use XtremeDSP Slices。即使用可編程邏輯資源或使用DSP資源。
接口介紹
簡(jiǎn)單來(lái)說(shuō),AXI4-Stream接口主要就是一個(gè)Basic Handshake。
TVALID由主機(jī)驅(qū)動(dòng),TVALID表示載荷字段(TDATA、TUSER和TLAST)中的值是有效的。
TREADY由從機(jī)驅(qū)動(dòng),TREADY表示從機(jī)已準(zhǔn)備好接收數(shù)據(jù)。
當(dāng)TVALID和TREADY在一個(gè)周期內(nèi)同時(shí)為高電平,就會(huì)發(fā)生數(shù)據(jù)傳輸。
所有的TDATA和TUSER字段都以小端格式打包。所有的TDATA和TUSER向量都是8比特的倍數(shù)。當(dāng)TDATA或TUSER向量中的所有字段都被連接起來(lái)時(shí),整個(gè)向量被填充到8位邊界。
s_axis_config_tdata
s_axis_config_tdata總線包含如下字段:
- (optional) NFFT plus padding
- (optional) CP_LEN plus padding
- FWD/INV
- (optional) SCALE_SCH
其中,NFFT位寬為5,表示變換點(diǎn)的大小,NFFT的值等于 l o g 2 ( point?size ) log_2(\text{point size}) log2?(point?size),這個(gè)字段只存在于運(yùn)行時(shí)的變換點(diǎn)大小可變的配置。
CP_LEN,表示循環(huán)前綴長(zhǎng)度,位寬為 l o g 2 ( maximum?point??size ) log_2(\text{maximum\ point \ size}) log2?(maximum?point??size)。在整個(gè)變換輸出之前,從變換末端開(kāi)始作為循環(huán)前綴輸出的數(shù)據(jù)數(shù)量。CP_LEN可以是0到(point size-1)的任何數(shù)字。這個(gè)字段只在配置了循環(huán)前綴插入時(shí)出現(xiàn)。
FWD_INV,表示執(zhí)行正向FFT變換或逆向FFT變換,為1時(shí),將計(jì)算正向變換,為 0時(shí),則計(jì)算逆向變換。該字段包含每個(gè)FFT數(shù)據(jù)通道的1位,位0(LSB)代表通道0,位1代表通道1,…。
SCALE_SCH,表示縮放時(shí)刻表,每個(gè)通道的該字段沒(méi)有填充,但整個(gè)字段都有填充。該字段只在配置縮放時(shí)存在(unscaled、 block floating-point、single precision floating-point時(shí)不存在)。
對(duì)于Burst I/O架構(gòu),Radix-4有 l o g 4 ( point?size ) log_4(\text{point size}) log4?(point?size)個(gè)階段,Radix-2則有 l o g 2 ( point?size ) log_2(\text{point size}) log2?(point?size)個(gè)階段。在每個(gè)階段,數(shù)據(jù)可以被移位0、1、2或3位,對(duì)應(yīng)的SCALE_SCH值為00、01、10、11。
例如,對(duì)于Radix-4,當(dāng)N=1024時(shí),[01 10 00 11 10]轉(zhuǎn)換為階段0右移2位,階段1右移3位,階段2不移,階段3右移2位,階段4右移1位,總共有 l o g 4 ( 1024 ) = 5 log_4(1024)=5 log4?(1024)=5個(gè)階段,總共縮放了8位,縮放系數(shù)為 1 2 8 = 1 / 256 \frac{1}{2^8}=1/256 281?=1/256。
對(duì)于N=1024,Radix-4架構(gòu)下可設(shè)置SCALE_SCH = [10 10 10 10 11],縮放系數(shù)為1/2048,Radix-2架構(gòu)下可設(shè)置SCALE_SCH =[01 01 01 01 01 01 01 01 01 10],縮放系數(shù)為1/2048,則可避免溢出。
s_axis_data_tdata
該總線攜帶輸入數(shù)據(jù),其中XN_RE為實(shí)部分量,XN_IM為虛部分量,位寬
b
xn
\text b_{\text {xn}}
bxn?為8-34,采用二進(jìn)制補(bǔ)碼或單精度浮點(diǎn)格式。
注意,所有帶填充的字段如果沒(méi)有在8位邊界上結(jié)束,就應(yīng)該擴(kuò)展到下一個(gè)8位邊界,即輸入數(shù)據(jù)時(shí),需要手動(dòng)拓展至8位邊界。
m_axis_data_tdata
該總線攜帶輸出數(shù)據(jù),其中XK_RE為輸出數(shù)據(jù)實(shí)部分量,XK_IM為虛部分量,采用二進(jìn)制補(bǔ)碼或單精度浮點(diǎn)格式。對(duì)于縮放運(yùn)算和塊浮點(diǎn)運(yùn)算,位寬
b
xk
\text b_{\text {xk}}
bxk?等于輸入數(shù)據(jù)位寬
b
xn
\text b_{\text {xn}}
bxn?,對(duì)無(wú)縮放運(yùn)算,則
b
xk
=
b
xn
+
log
2
(
maximum?point?size
)
\text b_{\text {xk}} = \text b_{\text {xn}} + \text{log}_2(\text {maximum point size})
bxk?=bxn?+log2?(maximum?point?size),對(duì)于單精度浮點(diǎn)運(yùn)算,則
b
xk
=
32
\text b_{\text {xk}}=32
bxk?=32。
各字段采用符號(hào)拓展至8位邊界。
m_axis_data_tuser
該總線可攜帶XK_INDEX、BLK_EXP、OVFLO。
XK_INDEX,為輸出數(shù)據(jù)的索引(無(wú)符號(hào)二進(jìn)制補(bǔ)碼),位寬
log
2
(
maximum?point?size
)
\text{log}_2(\text {maximum point size})
log2?(maximum?point?size),采用零填。
BLK_EXP,為運(yùn)算中的縮放系數(shù)值(無(wú)符號(hào)二進(jìn)制補(bǔ)碼),位寬為8,采用零填充。該字段只在塊浮點(diǎn)運(yùn)算時(shí)可選。
OVFLO,為溢出指示位(單比特,高電平有效)。如果數(shù)據(jù)幀中的任何值溢出,OVFLO在結(jié)果卸載期間為高電平。該字段只在縮放運(yùn)算或單精度浮點(diǎn)運(yùn)算時(shí)可選。
m_axis_status_tdata
該總線可攜帶BLK_EXP、OVFLO。
詳細(xì)見(jiàn)m_axis_data_tuser總線介紹。
事件信號(hào)Event Signals
event_frame_started
當(dāng)IP核開(kāi)始處理一個(gè)新的幀時(shí),該信號(hào)會(huì)被拉高一個(gè)時(shí)鐘周期。
event_tlast_missing
當(dāng)s_axis_data_tlast在一個(gè)幀的最后一個(gè)輸入數(shù)據(jù)時(shí)刻為低時(shí),該信號(hào)會(huì)被拉高一個(gè)時(shí)鐘周期。該信號(hào)表明了IP核和輸入數(shù)據(jù)的幀大小不匹配,拉高時(shí)表明了輸入數(shù)據(jù)幀大于IP核配置的大小。
event_tlast_unexpected
當(dāng)IP核檢測(cè)到在任何輸入數(shù)據(jù)上s_axis_data_tlast為高電平,而這個(gè)數(shù)據(jù)不是幀中的最后一個(gè)。這表明IP核和輸入數(shù)據(jù)的幀大小不匹配,拉高時(shí)表明了輸入數(shù)據(jù)幀小于IP核配置的大小。
event_fft_overflow
當(dāng)m_axis_data_tdata上傳輸?shù)臄?shù)據(jù)出現(xiàn)溢出時(shí),該信號(hào)在每個(gè)時(shí)鐘周期內(nèi)都會(huì)被拉高。
只有在使用縮放運(yùn)算或單精度浮點(diǎn)運(yùn)算時(shí),才有可能出現(xiàn)溢出。在其他配置情況下,該引腳會(huì)被移除。
event_data_in_channel_halt
該信號(hào)在IP核需要數(shù)據(jù)輸入通道的數(shù)據(jù)而沒(méi)有數(shù)據(jù)的每個(gè)時(shí)鐘周期內(nèi)都會(huì)被拉高。
event_data_out_channel_halt
該信號(hào)在IP核需要向數(shù)據(jù)輸出通道寫入數(shù)據(jù),但由于通道中的緩沖區(qū)已滿而不能寫入時(shí),會(huì)被拉高一個(gè)時(shí)鐘周期。當(dāng)這種情況發(fā)生時(shí),IP核所有活動(dòng)停止,直到通道緩沖區(qū)有可用空間。該信號(hào)只在非實(shí)時(shí)模式下可用。
event_status_channel_halt
該信號(hào)在IP核需要向狀態(tài)通道寫入數(shù)據(jù),但由于通道上的緩沖區(qū)已滿而不能寫入時(shí),會(huì)被拉高一個(gè)時(shí)鐘周期。當(dāng)這種情況發(fā)生時(shí),IP核所有活動(dòng)停止,直到通道緩沖區(qū)有可用空間。該信號(hào)只在非實(shí)時(shí)模式下可用。
使用實(shí)例
前面已經(jīng)詳細(xì)講述了IP核的各項(xiàng)參數(shù),根據(jù)需要自行配置即可。
仿真參數(shù)配置如下。
本次仿真使用MATLAB生成輸入數(shù)據(jù)。信號(hào)生成代碼如下。
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:N
if (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
end
initial begin
aresetn = 1'b0;
# 40;
aresetn = 1'b1;
end
initial begin
s_axis_config_tdata = {7'b000_0000, 16'b_01_01_01_01_01_01_01_10, 1'b1};
s_axis_config_tvalid = 1'b1;
end
reg [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) begin
if(s_axis_data_tready == 1'b1) begin
s_axis_data_tvalid = 1'b1;
s_axis_data_tdata = {data_in[i], 16'd0};
if(i == 1024-1) begin
i = 0;
end
else begin
i = i+1;
end
end
else begin
s_axis_data_tvalid = 1'b0;
end
end
end
end
wire [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時(shí),該字段由m_axis_data_tuser攜帶。
根據(jù)上圖可知頻譜實(shí)部分量的第一個(gè)波峰出現(xiàn)在XK_INDEX = 13時(shí),XK_RE = 1191。由NFFT = 256,fs = 1e4Hz,可知XK_INDEX / NFFT * fs = 507.8 Hz。
仿真結(jié)果與MATLAB計(jì)算結(jié)果一致。需要注意的是,仿真時(shí)FFT IP核的SCALE_SCH = 16’b_01_01_01_01_01_01_01_10,對(duì)應(yīng)縮放系數(shù)為1/512。故MATLAB計(jì)算的FFT結(jié)果也需要除以512。
關(guān)于輸入數(shù)據(jù)流控制的補(bǔ)充
以輸入數(shù)據(jù)通道為例,其有s_axis_data_tdata、s_axis_data_tvalid、s_axis_data_tready、s_axis_data_tlast四組接口。
為了方便查看數(shù)據(jù),配置FFT IP核的運(yùn)算數(shù)據(jù)個(gè)數(shù)為16個(gè),縮放系數(shù)為1/16,運(yùn)行時(shí)鐘頻率為50MHz(周期20ns)。
輸入數(shù)據(jù)為16個(gè)9999,F(xiàn)FT的輸出數(shù)據(jù)應(yīng)為1個(gè)5000和15個(gè)0;
x = 9999*ones(1,16);
X = fft(x,16)/2^4;
時(shí)序1
此時(shí)s_axis_data_tdata和s_axis_data_tvalid的維持時(shí)間是320ns,即16個(gè)時(shí)鐘周期,s_axis_data_tlast在第16個(gè)數(shù)據(jù)輸入周期時(shí)同時(shí)也拉高一個(gè)時(shí)鐘周期。事件信號(hào)也無(wú)異常。
輸出數(shù)據(jù)如下,且與理論相符。
時(shí)序2
此時(shí)s_axis_data_tdata和s_axis_data_tvalid同樣維持16個(gè)時(shí)鐘周期,但是s_axis_data_tlast在第16個(gè)數(shù)據(jù)輸入周期時(shí)不拉高。則此時(shí)事件信號(hào)event_tlast_missing會(huì)被拉高一個(gè)時(shí)鐘周期。
輸出數(shù)據(jù)同時(shí)序1情況,正確。
時(shí)序3
此時(shí)s_axis_data_tdata和s_axis_data_tvalid同樣維持16個(gè)時(shí)鐘周期,但是s_axis_data_tlast在第13個(gè)數(shù)據(jù)輸入周期時(shí)拉高,即提前拉高。則此時(shí)事件信號(hào)event_tlast_unexpected和event_tlast_missing均會(huì)被拉高一個(gè)時(shí)鐘周期。
輸出數(shù)據(jù)同時(shí)序1情況,正確。
時(shí)序4
此時(shí)s_axis_data_tdata和s_axis_data_tvalid一共維持20個(gè)時(shí)鐘周期,其前16個(gè)時(shí)鐘周期數(shù)據(jù)為9999,后4個(gè)時(shí)鐘周期的數(shù)據(jù)為1000。s_axis_data_tlast一直保持為低。
輸出數(shù)據(jù)同時(shí)序1情況,正確。
時(shí)序5
此時(shí)s_axis_data_tdata和s_axis_data_tvalid一共維持20個(gè)時(shí)鐘周期,其前16個(gè)時(shí)鐘周期數(shù)據(jù)為9999,后4個(gè)時(shí)鐘周期的數(shù)據(jù)為1000。但是s_axis_data_tlast在第20個(gè)數(shù)據(jù)輸入周期時(shí)拉高。
輸出數(shù)據(jù)同時(shí)序1情況,正確。
小結(jié)
根據(jù)時(shí)序1-5的結(jié)果可知,
FFT IP核計(jì)算時(shí)取的是s_axis_data_tdata輸入數(shù)據(jù)流的前16個(gè)數(shù)據(jù)。
s_axis_data_tlast信號(hào)對(duì)于IP核的計(jì)算結(jié)果無(wú)影響,其只是起一個(gè)指示作用。
時(shí)序6
為了進(jìn)一步驗(yàn)證。
將輸入數(shù)據(jù)流改為10個(gè)9999和10個(gè)1000。s_axis_data_tlast仍然在第20個(gè)數(shù)據(jù)輸入周期時(shí)拉高。
數(shù)據(jù)輸出結(jié)果:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-414456.html
x = [9999*ones(1,10), 1000*ones(1,10)];
X = (fft(x,16)/2^4);
X_Re = round(real(X));
X_Im = round(imag(X));
可以看到此時(shí)輸出結(jié)果與Matlab仿真一致。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-414456.html
到了這里,關(guān)于Vivado_FFT IP核 使用詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!