HLS实现FIR低通滤波器+System Generator仿真

硬件:ZYNQ7010
软件:MATLAB 2019b、Vivado 2017.4、HLS 2017.4、System Generator 2017.4

1、MATLAB设计低通滤波器

  FPGA系统时钟 50MHz,也是采样频率。用 MATLAB 生成 1MHz 和 10MHz 的正弦波叠加的信号,并量化为 14bit 整数。把叠加信号输出到 txt 文件用于 HLS 的仿真。MATLAB 工作空间里的变量用于搭建 System Generator 模型。

N = 1024;
fs = 50e6; %50MHz
ts = 1/fs;
Q = 14;
A = 2;
t = (1:N)*ts;
f1 = 1e6; %1MHz
f2 = 10e6;%10MHz
s1 = A*sin(2*pi*f1*t);
s2 = A*sin(2*pi*f2*t);
s = s1+s2;
s = s./max(abs(s));
s = round(s.*(2^(Q-1)-1)); % quantize
% output for testbench
fid = fopen('.\data.txt','w');
for i = 1:length(s)fprintf(fid,'%d\n', s(i));
end
fclose(fid);

  用 MATLAB 的 fir1 函数设计一个归一化截止频率为 0.2 的 10 阶低通 FIR 滤波器,即截止频率为 5MHz,有 11 个滤波器系数。最后也将滤波器系数量化为 14bit 整数。

Q = 14;
b = fir1(10,0.2);
figure();
freqz(b,1);
b = b./max(abs(b));
b = round(b.*(2^(Q-1)-1)); % quantize

2、HLS编写FIR滤波器代码并优化、仿真

// fir.h
#ifndef _FIR_H_
#define _FIR_H_
#include <ap_int.h>
#define N 11
typedef ap_int<32> coef_t;
typedef ap_int<32> data_t;
typedef ap_int<32> acc_t;
void fir(acc_t *y,data_t x);
#endif
// fir.cpp
#include "fir.h"
void fir(acc_t *y,data_t x)
{const coef_t c[N] = {0,322,1644,4229,6989,8191,6989,4229,1644,322,0}; //low pass 0.2static data_t shift_reg[N];acc_t acc=0;
Shift_Accum_Loop:for(int i = N - 1;i >= 0;i--){if(i == 0){acc += x * c[0];shift_reg[0] = x;}else{shift_reg[i] = shift_reg[i - 1];acc += shift_reg[i] * c[i];}}*y = acc;
}
// tb_fir.cpp
#include "fir.h"
#include <fstream>
#include <iostream>
using namespace std;
int main()
{ifstream fp_strmi("data.txt");ofstream fp_strmo("..\\..\\..\\..\\fir_matlab\\fir_out.txt");int val;acc_t fir_out;if(!fp_strmi.is_open()){cerr << "Error! data.txt is not able to open.\n";}if(!fp_strmo.is_open()){cerr << "Error! fir_out.txt is not able to open.\n";}for(int i=0; i<1024; i++){fp_strmi >> val;fir(&fir_out, (data_t)val);fp_strmo << (int)fir_out << "\n";}fp_strmi.close();fp_strmo.close();return 0;
}

在这里插入图片描述
  首先编写一个没有经过任何优化的C语言代码,C Synthesis后得到的性能估计,见上图。Shift_Accum_Loop 循环了 11 次,每次循环用时两个时钟周期,这说明了这个循环是顺序执行的,没有充分发挥 FPGA 能够并行计算的特点。fir 函数的执行延时(Latency)是 23 个时钟周期,执行间隔(Interval)也是 23 个时钟这期。进行 C/RTL Cosimulation,输出的波形见下图,波形很奇怪,其实只有 y_V_ap_vld为高电平时的 y_V 数据是正确的,y_V_ap_vld 的相邻两个上升沿之间间隔了 24 个时钟周期(480ns)。ap_read 为高电平时,读入一个叠加信号数据到 x_V,可以看出整个系统的采样频率不是 50MHz,而是 (50/24)MHz。

在这里插入图片描述
  优化 FIR 滤波器的代码,将滤波器系数和输入信号的数据类型改为 ap_int<14>,shift_reg 指定用寄存器实现,Shift_Accum_Loop 循环中的寄存器移位操作(延时线,TDL)和乘累加(MAC)操作分开写到两个 for 循环里,再将这两个循环展开,Cpp 代码和directive 指令在下面列出。因为 TDL 的循环次数是 10 次,所以 factor 是 10,MAC 循环次数是 11 次, factor 填 11。

// fir.h
#ifndef _FIR_H_
#define _FIR_H_
#include <ap_int.h>
#define N 11
typedef ap_int<14> coef_t;
typedef ap_int<14> data_t;
typedef ap_int<32> acc_t;
void fir(acc_t *y,data_t x);
#endif
// fir.cpp
#include "fir.h"
void fir(acc_t *y,data_t x)
{const coef_t c[N] = {0,322,1644,4229,6989,8191,6989,4229,1644,322,0}; //low pass 0.2static data_t shift_reg[N];acc_t acc=0;shift_reg[0] = x;
TDL: // time delay linefor(int i = N - 1; i > 0; i--){shift_reg[i] = shift_reg[i - 1];}
MAC: // multiple accumulatefor(int i = N - 1; i >= 0; i--){acc += shift_reg[i] * c[i];}*y = acc;
}
# directive 
set_directive_array_partition -type complete -dim 1 "fir" shift_reg
set_directive_unroll -skip_exit_check -factor 10 "fir/TDL"
set_directive_unroll -skip_exit_check -factor 11 "fir/MAC"
set_directive_interface -mode ap_ctrl_none "fir"

  C Synthesis后得到的性能估计如下图所示。fir 函数的执行延时(Latency)是 1 个时钟周期,执行间隔(Interval)也是 1 个时钟这期。进行 C/RTL Cosimulation,此时波形好看一点,依然是y_V_ap_vld为高电平时的 y_V 数据是正确的,y_V_ap_vld 的相邻两个上升沿之间间隔了 2 个时钟周期(40ns),整个系统的采样频率是 25MHz,输出的低频正弦信号频率是 500KHz。在后续System Generator 仿真时情况会发生变化,注意看。

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

3、搭建System Generator模型,导入HLS模块

  搭建一个如下图所示的 System Generator 模型,其中 counter 用于产生 ROM 的地址信号,ROM 中存着叠加信号的数据。这些模块都是高电平复位,而我的开发板按键按下去后是低电平,所以在 reset 后加了 not 模块翻转电平。HLS 模块导入了优化后的 fir 代码,并且将模块的端口协议改为了 ap_ctrl_none。
在这里插入图片描述
  下图给出了 System Generator 的仿真结果。可以看到滤波后的正弦信号不平滑,输出数据是 y_V_ap_vld 高电平时有效,y_V_ap_vld 的相邻两个上升沿之间间隔两个时钟周期,正弦信号的周期是 50 个时钟周期,正好对应 50MHz 时钟频率下的 1MHz。为什么和 HLS 中的 C/RTL Cosimulation 结果不一样呢?因为这里输入的叠加信号是按 50MHz 的采样频率输入到 HLS 模块的,但是 HLS 模块处理一个输入数据需要两个时钟周期,相当于对输入信号又进行了一次下采样,采样频率变成了 25MHz,同时采样点数也减少了,此时滤波器的截止频率为 0.2 × 25 / 2 = 2.5 0.2×25/2=2.5 0.2×25/2=2.5MHz,同样可以滤出 1MHz 的正弦信号。前面 C/RTL Cosimulation 时只是采样频率变小了,但是采样点数没有少,导致输出的正弦信号频率也减小。

在这里插入图片描述  把这个模型生成 IP 核,下载到开发板上进行验证。

4、上板验证

  创建一个 Vivado 工程,例化 System Generator 模型生成的 IP 核和一个 ila IP 核,写一个寄存器把 fir_out 根据 fir_out_vld 寄存一次,代码如下。

module fir_hls_sysgen_top(input resetn,input clk);
wire [31:0] fir_out;
wire fir_out_vld;
fir_filter_0 fir_filter_inst (.reset(resetn),                // input wire [0 : 0] reset.clk(clk),                    // input wire clk.fir_out(fir_out),          // output wire [31 : 0] fir_out.fir_out_vld(fir_out_vld)  // output wire [0 : 0] fir_out_vld
);
reg [31:0] fir_out_reg;
always @(posedge clk or negedge resetn) beginif(!resetn) beginfir_out_reg <= 32'd0;endelse beginif(fir_out_vld) beginfir_out_reg <= fir_out;endend
end
ila_0 ila0_inst (.clk(clk), // input wire clk.probe0(fir_out), // input wire [31:0]  probe0  .probe1(fir_out_reg), // input wire [31:0]  probe1 .probe2(fir_out_vld) // input wire [0:0]  probe2
);
endmodule

  ila 抓取的波形如下图所示。可以看到 fir_out_vld 相邻两个上升沿间隔两个时钟周期,滤波输出的正弦信号周期为 50 个时钟周期,fir_out 波形和 simulink 仿真的是一样的,并且 fir_out_reg 的波形更平滑一些。

在这里插入图片描述完整工程下载地址:HLS设计FIR滤波器工程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/40462.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

css 用过渡实现,鼠标离开li时,背景色缓慢消息的样式

要实现鼠标悬停时背景颜色变为黄色&#xff0c;鼠标离开时背景颜色慢慢消失并变回白色的效果&#xff0c; 可以使用CSS的过渡&#xff08;transition&#xff09;属性 li {background: #fff;color: #000;transition: background 0.5s ease-out; }li:hover {background: #fbb31…

Web网页浏览器远程访问jupyter notebook服务器【内网穿透】

文章目录 前言1. Python环境安装2. Jupyter 安装3. 启动Jupyter Notebook4. 远程访问4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口 5. 固定公网地址 前言 Jupyter Notebook&#xff0c;它是一个交互式的数据科学和计算环境&#xff0c;支持多种编程语言&#xff0c;如…

Hyper-v导致Vmware window无法启动崩溃记录

最近有几次vmware启动window10直接崩溃情况&#xff0c;显示蓝屏报错。一开始没在意&#xff0c;以为是因为固态硬盘错了几个字节导致的&#xff1f; 但后来想想不对啊。vmware用了也有10来年了&#xff0c;稳得一笔&#xff0c;在仔细思考了一下后发现打不开的win10这三个虚拟…

Oracle/PL/SQL奇技淫巧之Lable标签与循环控制

在一些存储过程场景中&#xff0c;可能存在需要在满足某些条件时跳出循环的场景&#xff0c; 但是在PL/SQL中&#xff0c;不能使用break语句直接跳出循环, 但是可以通过lable标签的方式跳出循环&#xff0c;例&#xff1a; <<outer_loop>> FOR i IN 1..5 LOOPDBMS…

Python批量替换Excel和Word中的关键字

一、问题的提出 有时&#xff0c;我们手头上有多个Excel或者Word文件&#xff0c;但是领导突然要求对某几个术语进行批量的修改&#xff0c;你是不是有要崩溃的感觉。因为这么多文件&#xff0c;要一个一个地打开文件&#xff0c;再进行批量替换修改&#xff0c;几个文件还好&…

设计模式之构建器(Builder)C++实现

1、构建器提出 在软件功能开发中&#xff0c;有时面临“一个复杂对象”的创建工作&#xff0c;该对象的每个功能接口由于需求的变化&#xff0c;会使每个功能接口发生变化&#xff0c;但是该对象使用每个功能实现一个接口的流程是稳定的。构建器就是解决该类现象的。构建就是定…

【Java】项目管理工具Maven的安装与使用

文章目录 1. Maven概述2. Maven的下载与安装2.1 下载2.2 安装 3. Maven仓库配置3.1 修改本地仓库配置3.2 修改远程仓库配置3.3 修改后的settings.xml 4. 使用Maven创建项目4.1 手工创建Java项目4.2 原型创建Java项目4.3 原型创建Web项目 5. Tomcat启动Web项目5.1 使用Tomcat插件…

【CTF-web】备份是个好习惯(查找备份文件、双写绕过、md5加密绕过)

题目链接&#xff1a;https://ctf.bugku.com/challenges/detail/id/83.html 经过扫描可以找到index.php.bak备份文件&#xff0c;下载下来后打开发现是index.php的原代码&#xff0c;如下图所示。 由代码可知我们要绕过md5加密&#xff0c;两数如果满足科学计数法的形式的话&a…

模型预测笔记(一):数据清洗及可视化、模型搭建、模型训练和预测代码一体化和对应结果展示(可作为baseline)

模型预测 一、导入关键包二、如何载入、分析和保存文件三、修改缺失值3.1 众数3.2 平均值3.3 中位数3.4 0填充 四、修改异常值4.1 删除4.2 替换 五、数据绘图分析5.1 饼状图5.1.1 绘制某一特征的数值情况&#xff08;二分类&#xff09; 5.2 柱状图5.2.1 单特征与目标特征之间的…

OpenCV基本操作——算数操作

目录 图像的加法图像的混合 图像的加法 两个图像应该具有相同的大小和类型&#xff0c;或者第二个图像可以是标量值 注意&#xff1a;OpenCV加法和Numpy加法之间存在差异。OpenCV的加法是饱和操作&#xff0c;而Numpy添加的是模运算 import numpy as np import cv2 as cv imp…

[数据集][目标检测]钢材表面缺陷目标检测数据集VOC格式2279张10类别

数据集格式&#xff1a;Pascal VOC格式(不包含分割路径的txt文件和yolo格式的txt文件&#xff0c;仅仅包含jpg图片和对应的xml) 图片数量(jpg文件个数)&#xff1a;2279 标注数量(xml文件个数)&#xff1a;2279 标注类别数&#xff1a;10 标注类别名称:["yueyawan",&…

Qt 窗口随鼠标移动效果

实现在窗口任意位置按下鼠标左键都可以移动窗口的效果&#xff0c;完整代码如下&#xff1a; mainwindow.h&#xff1a; #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include <QMouseEvent>QT_BEGIN_NAMESPACE namespace Ui { class MainW…

PHP混淆加密以及常用的一些加密工具

PHP混淆加密是一种将源代码转换为难以理解和阅读的方式&#xff0c;以保护代码的安全性。以下是一些常见的PHP混淆加密方法&#xff1a; 代码压缩&#xff1a;使用代码压缩工具&#xff08;如UglifyJS&#xff09;将PHP代码压缩为一行&#xff0c;去除空格、换行符等可读性的字…

jenkins 连接服务器,提示Can‘t connect to server

在Jenkins 添加服务器时&#xff0c;提示 Cant connect to server&#xff0c;如图 搞了好久&#xff0c;不知道为什么不行~原来是行的&#xff0c;现在删了 新建一个也不行。

2023牛客暑期多校训练营8-C Clamped Sequence II

2023牛客暑期多校训练营8-C Clamped Sequence II https://ac.nowcoder.com/acm/contest/57362/C 文章目录 2023牛客暑期多校训练营8-C Clamped Sequence II题意解题思路代码 题意 解题思路 先考虑不加紧密度的情况&#xff0c;要支持单点修改&#xff0c;整体查询&#xff0…

axios同一个接口,同时接收 文件 或者 数据

1、前端代码 const service axios.create({baseURL: "http://192.168.2.200:8080/api",timeout: 180000 })// 响应拦截 service.interceptors.response.use(async response > {if(response){// 请求时设置返回blob, 但是实际上可能返回的是json的情况if (respon…

[C++]笔记 - 知识点积累

一.运算符的优先级 一共15个级别 最高优先级 : () []最低优先级 :逗号表达式倒数第二低优先级 : 赋值和符合赋值(,,-...) ! >算术运算符 > 关系运算符 > && >> || >赋值运算符 二.数据类型转换 隐式类型转换 算数转换 char int long longlong flo…

解决Java中的“Unchecked cast: java.lang.Object to java.util.List”问题

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

搜索二叉树

目录 搜索二叉树的性质 搜索二叉树的实现、 插入 删除 代码 在以前我们学过二叉树,但是在对二叉树的学习中发现,似乎二叉树并没有什么作用,要论增删它比不上链表,论随机访问也没法和顺序表比,对于当时的我们是一头雾水,那么现在它的功能终于是体现出来了,这里就是我们要讲的…

[Go版]算法通关村第十一关白银——位运算的高频算法题

目录 专题1&#xff1a;位移的妙用题目&#xff1a;位1的个数&#xff08;也被称为汉明重量&#xff09;解法1&#xff1a;遍历所有位&#xff0c;判断每个位的数字是否是1Go代码 解法2&#xff1a;依次消除每个1的位 numnum&(num-1)Go代码 题目&#xff1a;比特位计数思路…