热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Vivado中FFTIP核的使用

FFT(快速傅里叶变换)作为数字信号处理的核心算法具有重要的研究价值,可应用于傅里叶变换所能涉及的任何领域,如图像处理、音频编码、频谱分析、雷达信号脉冲压缩等数字信号处理领域。FF



FFT(快速傅里叶变换)作为数字信号处理的核心算法具有重要的研究价值,可应用于傅里叶变换所能涉及的任何领域,如图像处理、音频编码、频谱分析、雷达信号脉冲压缩等数字信号处理领域。FFT的鲜明特征之一是计算离散傅里叶变换(DFT)的高效算法,把计算N点DFT的乘法运算量从N2次降低到N/2*log2N次。而采用FPGA实现FFT的缘由在于:FPGA具有并行处理、流水线处理、易编程、片上资源丰富等方面特点,用于实现高速、大点数的FFT优势明显。

本设计使用的软件编程环境是Xilinx公司的Vivado 2018.3,笔者将从FFT IP核的创建,模块文件的编写,波形仿真等方面来具体讲解FFT在Xilinx FPGA上的实现。


1.FFT IP核的创建

(1)在Vivado软件主界面,打开IP Catalog,在搜索框内输入FFT,然后找到Digital Signal Processing->Transforms->FFTs目录下的Fast Fourier Transform,双击进入配置界面。

在这里插入图片描述(2)进入到配置界面,左边是IP核的接口图、实现的一些细节信息和FFT的延迟,右边是Configuration、Implementation和Detailed Implementation三个标签卡。

Vivado的FFT IP核支持多通道输入(Number of Channels)和实时更改FFT的点数(Run Time Configurable Transform Length)。Configuration标签下可设置FFT的点数(Transform Length)和工作时钟(Target Clock Frequency),以及选择一种FFT结构。FFT的结构包括流水线Streaming、基4 Burst、基2 Burst和轻量级基2 Burst,它们的计算速度和消耗的资源依次减少,可根据工程实际进行选择。

在这里插入图片描述 Implementation标签卡下可设置FFT的数据格式为定点Fixed Point或浮点Float Point;输出截位方式选择:不截位(Unscaled),截位(Scaled),块浮点(Block Floating Point);设置输入数据的位宽和相位因子位宽。还有一些可选的附加信号,如时钟使能(ACLKEN),复位信号(ARESETn,低有效)等。“Output Ordering”用以选择FFT计算结果以自然顺序(Nature Order)或位倒序(Bit/Digit Reversed Order)输出。

在这里插入图片描述 Detailed Implementation里可设置优化方式、存储的类型。存储类型分为两种:Block RAM(块RAM)和Distributed RAM(分布式RAM);优化方式可选择资源最优或者速度最优。

在这里插入图片描述(3)配置完成后,可在Latency下看到计算fft所需的时间,可以以此衡量设计是否满足实时处理的要求。如不满足,可选择性能更好的FFT结构或选择可以提高运算速度的优化选项

在这里插入图片描述


2.模块文件的编写

(1)IP核工作必须要满足一定的时序要求,所以需要编写一个fft核的接口模块(FFT_interface.v),用于产生该IP核的时序控制信号并将输入的实部、虚部数据根据需要拼接成一个数据。和该IP核交互是用AXI-Stream接口,关于AXI-Stream接口的时序可自行查一些相关资料,这里不做详细介绍。

module FFT_interface
#( parameter Data_b0,H=1'b1
)
(
input clk,
input rst_n,
input tvalid_i,
input [Data_width-1:0] dati_in,
input [Data_width-1:0] datq_in,
output reg [(Data_width<<1)-1:0] dat_out,
output reg tlast_o,
output reg tvalid_o,
output wire local_rst
);
reg [Cnt_width-1:0] cnt;
reg tvalid_reg;
wire tvalid_cat;
always @(posedge clk) begin
tvalid_reg <= tvalid_i;
end
assign tvalid_cat = tvalid_reg | tvalid_i; //tvalid拉高一个时钟周期后tready才有效,故将valid信号多拉高一个时钟周期
always @(posedge clk) begin
if (!rst_n) cnt<=0;
else if(tvalid_i) cnt<=cnt+16'd1;
else if(cnt>=Frame_length&& cnt<=Frame_length+5) cnt<= cnt+16'd1;
else if(cnt==Frame_length+6) cnt<=0;
end

assign local_rst=(rst_n)&&(( tvalid_i&&(cnt==1))||(( tvalid_i&&(cnt==2)))?L:H);
always @(posedge clk)begin
if(!rst_n) tlast_o<=L;
else if(cnt==Frame_length+4) tlast_o=H;
else tlast_o=L;
end
reg valid_temp1, valid_temp2;
reg valid_temp3, valid_temp4;
reg [(Data_width<<1)-1:0] dat_temp1, dat_temp2;
reg [(Data_width<<1)-1:0] dat_temp3, dat_temp4;
always @(posedge clk)begin
if(!rst_n) begin
valid_temp1<=L; valid_temp2<=L;
valid_temp3<=L; valid_temp4<=L; tvalid_o<=L;
dat_temp1<=0; dat_temp2<=0;
dat_temp3<=0; dat_temp4<=0; dat_out<=0;
end
else begin
valid_temp1<= tvalid_cat; valid_temp2<= valid_temp1;
valid_temp3<= valid_temp2; valid_temp4<= valid_temp3; tvalid_o<= valid_temp4;
dat_temp1<={ datq_in , dati_in }; dat_temp2<= dat_temp1;
dat_temp3<= dat_temp2; dat_temp4<= dat_temp3; dat_out <=dat_temp4;
end
end
endmodule

(2)接口模块编写完成后就可在顶层模块(FFT_TOP)进行调用,并将其输出端口连接到FFT IP核上,以实现对IP核的时序控制。

module FFT_TOP
#( parameter Din_b0,H=1'b1
)
(
input clk,
input rst_n,
input tvalid_i,
input [Din_width-1:0] dati_in,
input [Din_width-1:0] datq_in,
output [Dout_width-1:0] dati_out,
output [Dout_width-1:0] datq_out,
output tvalid_o
);
wire [Din_width*2-1:0] fft_dat_in;
wire fft_last_i;
wire fft_valid_i;
wire fft_local_rst;
FFT_interface #(16,16,128,1'b0,1'b1) u_FFT_interfence(
.clk(clk),
.rst_n(rst_n),
.tvalid_i(tvalid_i),
.dati_in(dati_in),
.datq_in(datq_in),
.dat_out(fft_dat_in),
.tlast_o(fft_last_i),
.tvalid_o( fft_valid_i),
.local_rst(fft_local_rst)
);

wire fft_s_config_tready;
wire fft_s_data_tready;
wire [Dout_width*2-1:0] fft_m_data_tdata;
wire fft_m_data_tvalid;
wire fft_m_data_tlast;
wire fft_event_frame_started;
wire fft_event_tlast_unexpected;
wire fft_event_tlast_missing;
wire fft_event_status_channel_halt;
wire fft_event_data_in_channel_halt;
wire fft_event_data_out_channel_halt;
fft_16 u_fft_16(
.aclk(clk),
.aresetn(fft_local_rst),
.s_axis_config_tdata(8'd1),
.s_axis_config_tvalid(H),
.s_axis_config_tready(fft_s_config_tready),
.s_axis_data_tdata(fft_dat_in),
.s_axis_data_tvalid(fft_valid_i),
.s_axis_data_tready(fft_s_data_tready),
.s_axis_data_tlast(fft_last_i),
.m_axis_data_tdata(fft_m_data_tdata),
.m_axis_data_tvalid(fft_m_data_tvalid),
.m_axis_data_tready(H),
.m_axis_data_tlast(fft_m_data_tlast),
.event_frame_started(fft_event_frame_started),
.event_tlast_unexpected(fft_event_tlast_unexpected),
.event_tlast_missing(fft_event_tlast_missing),
.event_status_channel_halt(fft_event_status_channel_halt),
.event_data_in_channel_halt(fft_event_data_in_channel_halt),
.event_data_out_channel_halt(fft_event_data_out_channel_halt)
);
assign dati_out=fft_m_data_tdata[Dout_width-1:0];
assign datq_out=fft_m_data_tdata[Dout_width*2-1: Dout_width];
assign tvalid_o=fft_m_data_tvalid;
endmodule

(3)此工程的RTL视图:该视图下,可清楚直观的显示各模块间的连线关系以及输入输出端口信息。

在这里插入图片描述


3.功能仿真

模块编写完成后,需要通过功能仿真来验证我们设计逻辑的正确性。进行仿真之前,我们需要编写仿真测试文件(testbench)。

module testbench;
reg clk;
reg rst_n;
reg tvalid_i;
reg [15:0] dati_in;
reg [15:0] datq_in;
wire [23:0] dati_out;
wire [23:0] datq_out;
wire tvalid_o;
reg [15:0] dataI [127:0];
initial begin
clk=0;
rst_n=0;
tvalid_i=0;
dati_in=0;
datq_in=0;
$readmemb("C:/Users/radar/Desktop/y1.txt",dataI);
#100
rst_n=1;
end
always #5 clk=~clk;
reg [7:0] count=0;
always @(posedge clk) begin
if (rst_n) begin
if(count==128) begin
tvalid_i=1'b0;
count<=count;
end
else begin
dati_in<= dataI[count];
datq_in<=16'd0;
tvalid_i=1'b1;
count<=count+1;
end
end
end
FFT_TOP U_FFT_TOP(
.clk(clk),
.rst_n(rst_n),
.tvalid_i(tvalid_i),
.dati_in(dati_in),
.datq_in(datq_in),
.dati_out(dati_out),
.datq_out(datq_out),
.tvalid_o(tvalid_o)
);
wire [47:0] fft_abs;
assign fft_abs=$signed(dati_out)* $signed(dati_out)+ $signed(datq_out)* $signed(datq_out);
endmodule

testbench中输入的时域波形数据是我们通过matlab生成的,在matlab中我们仿真的是采样率为2kHz情况下,频率分别为50Hz和200Hz的两正弦波叠加后的信号。

N=128;
n=1:N;
f0=50;
f1=200;
fs=2e3;
y=sin(2*pi*f0.*n/fs)+2*sin(2*pi*f1.*n/fs);
figure;
plot(y);
Y=fft(y);
figure;
plot(abs(Y));
y1=y';
q=quantizer([16 12]);
y2=num2bin(q,y1);
fid1=fopen('C:/Users/radar/Desktop/y1.txt','wt');
for i=1:N
fwrite(fid1,y2(i,:));
fprintf(fid1,'\n');
end
fclose(fid1);

进行功能仿真时我们将仿真时长设置为11us。为了直观验证fft是否正确,可将输入的时域数据和做完fft后信号功率值的数据格式均设置为anolog(模拟),如下图,可以看到fft后的功率谱为两根独立的谱线,分别代表50Hz和200Hz两个频率点,和matlab仿真结果一致。

在这里插入图片描述在这里插入图片描述

对于该IP核更复杂的应用,大家可以阅读Xilinx官方提供的文档,根据自己的实际需要进行设计。限于笔者水平有限,文章内难免会有错误,希望大家不吝赐教,批评指正。




推荐阅读
  • 优化Vite 1.0至2.0升级过程中遇到的某些代码块过大问题解决方案
    本文详细探讨了在将项目从 Vite 1.0 升级到 2.0 的过程中,如何解决某些代码块过大的问题。通过具体的编码示例,文章提供了全面的解决方案,帮助开发者有效优化打包性能。 ... [详细]
  • DVWA学习笔记系列:深入理解CSRF攻击机制
    DVWA学习笔记系列:深入理解CSRF攻击机制 ... [详细]
  • 体积小巧的vsftpd与pureftpd Docker镜像在Unraid系统中的详细配置指南:支持TLS加密及IPv6协议
    本文详细介绍了如何在Unraid系统中配置体积小巧的vsftpd和Pure-FTPd Docker镜像,以支持TLS加密和IPv6协议。通过这些配置,用户可以实现安全、高效的文件传输服务,适用于各种网络环境。配置过程包括镜像的选择、环境变量的设置以及必要的安全措施,确保了系统的稳定性和数据的安全性。 ... [详细]
  • PHP预处理常量详解:如何定义与使用常量 ... [详细]
  • 解决针织难题:R语言编程技巧与常见错误分析 ... [详细]
  • 数字图书馆近期展出了一批精选的Linux经典著作,这些书籍虽然部分较为陈旧,但依然具有重要的参考价值。如需转载相关内容,请务必注明来源:小文论坛(http://www.xiaowenbbs.com)。 ... [详细]
  • PTArchiver工作原理详解与应用分析
    PTArchiver工作原理及其应用分析本文详细解析了PTArchiver的工作机制,探讨了其在数据归档和管理中的应用。PTArchiver通过高效的压缩算法和灵活的存储策略,实现了对大规模数据的高效管理和长期保存。文章还介绍了其在企业级数据备份、历史数据迁移等场景中的实际应用案例,为用户提供了实用的操作建议和技术支持。 ... [详细]
  • 如何将TS文件转换为M3U8直播流:HLS与M3U8格式详解
    在视频传输领域,MP4虽然常见,但在直播场景中直接使用MP4格式存在诸多问题。例如,MP4文件的头部信息(如ftyp、moov)较大,导致初始加载时间较长,影响用户体验。相比之下,HLS(HTTP Live Streaming)协议及其M3U8格式更具优势。HLS通过将视频切分成多个小片段,并生成一个M3U8播放列表文件,实现低延迟和高稳定性。本文详细介绍了如何将TS文件转换为M3U8直播流,包括技术原理和具体操作步骤,帮助读者更好地理解和应用这一技术。 ... [详细]
  • 基于Net Core 3.0与Web API的前后端分离开发:Vue.js在前端的应用
    本文介绍了如何使用Net Core 3.0和Web API进行前后端分离开发,并重点探讨了Vue.js在前端的应用。后端采用MySQL数据库和EF Core框架进行数据操作,开发环境为Windows 10和Visual Studio 2019,MySQL服务器版本为8.0.16。文章详细描述了API项目的创建过程、启动步骤以及必要的插件安装,为开发者提供了一套完整的开发指南。 ... [详细]
  • 本文详细解析了使用C++实现的键盘输入记录程序的源代码,该程序在Windows应用程序开发中具有很高的实用价值。键盘记录功能不仅在远程控制软件中广泛应用,还为开发者提供了强大的调试和监控工具。通过具体实例,本文深入探讨了C++键盘记录程序的设计与实现,适合需要相关技术的开发者参考。 ... [详细]
  • 本文详细介绍了在MySQL中如何高效利用EXPLAIN命令进行查询优化。通过实例解析和步骤说明,文章旨在帮助读者深入理解EXPLAIN命令的工作原理及其在性能调优中的应用,内容通俗易懂且结构清晰,适合各水平的数据库管理员和技术人员参考学习。 ... [详细]
  • 该大学网站采用PHP和MySQL技术,在校内可免费访问某些外部收费资料数据库。为了方便学生校外访问,建议通过学校账号登录实现免费访问。具体方案可包括利用学校服务器作为代理,结合身份验证机制,确保合法用户在校外也能享受免费资源。 ... [详细]
  • Python 程序转换为 EXE 文件:详细解析 .py 脚本打包成独立可执行文件的方法与技巧
    在开发了几个简单的爬虫 Python 程序后,我决定将其封装成独立的可执行文件以便于分发和使用。为了实现这一目标,首先需要解决的是如何将 Python 脚本转换为 EXE 文件。在这个过程中,我选择了 Qt 作为 GUI 框架,因为之前对此并不熟悉,希望通过这个项目进一步学习和掌握 Qt 的基本用法。本文将详细介绍从 .py 脚本到 EXE 文件的整个过程,包括所需工具、具体步骤以及常见问题的解决方案。 ... [详细]
  • 在Linux系统中,网络配置是至关重要的任务之一。本文详细解析了Firewalld和Netfilter机制,并探讨了iptables的应用。通过使用`ip addr show`命令来查看网卡IP地址(需要安装`iproute`包),当网卡未分配IP地址或处于关闭状态时,可以通过`ip link set`命令进行配置和激活。此外,文章还介绍了如何利用Firewalld和iptables实现网络流量控制和安全策略管理,为系统管理员提供了实用的操作指南。 ... [详细]
  • 本指南详细介绍了在Linux环境中高效连接MySQL数据库的方法。用户可以通过安装并使用`mysql`客户端工具来实现本地连接,具体命令为:`mysql -u 用户名 -p 密码 -h 主机`。例如,使用管理员账户连接本地MySQL服务器的命令为:`mysql -u root -p pass`。此外,还提供了多种配置优化建议,以确保连接过程更加稳定和高效。 ... [详细]
author-avatar
Ax珊
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有