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

news2024/12/28 5:55:42

硬件: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.2
	static 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.2
	static data_t shift_reg[N];
	acc_t acc=0;
	shift_reg[0] = x;
TDL: // time delay line
	for(int i = N - 1; i > 0; i--)
	{
		shift_reg[i] = shift_reg[i - 1];
	}
MAC: // multiple accumulate
	for(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) begin
    if(!resetn) begin
        fir_out_reg <= 32'd0;
    end
    else begin
        if(fir_out_vld) begin
            fir_out_reg <= fir_out;
        end
    end
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.coloradmin.cn/o/873554.html

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

相关文章

Word(1):文章页码设置

1.需求 在文档的封皮页不设置页码&#xff0c;在目录页页码设置为罗马数字&#xff0c;在正文使用阿拉伯数字。 2.解决方法 step1&#xff1a; 在封皮页的最后&#xff0c;点击”插入“-分隔符-分节符&#xff08;下一页&#xff09; step2&#xff1a;在目录页的最后&…

掌握这5本书,转行程序员不再难

后台收到读者提问&#xff1a; 我想转行程序员&#xff0c;请推荐几本可以帮助我转行成功的书。 我自己也是大学毕业后&#xff0c;自学转行程序员的&#xff0c;走了很多的弯路。下面几本书&#xff0c;给了我很多帮助。 &#xff11;、推荐图书 以下是5本可以帮助你转行成为…

24届近3年上海电力大学自动化考研院校分析

今天给大家带来的是上海电力大学控制考研分析 满满干货&#xff5e;还不快快点赞收藏 一、上海电力大学 学校简介 上海电力大学&#xff08;Shanghai University of Electric Power&#xff09;&#xff0c;位于上海市&#xff0c;是中央与上海市共建、以上海市管理为主的全日…

2023“钉耙编程”中国大学生算法设计超级联赛(5)

Typhoon 计算几何&#xff0c;点到线段距离 String Magic (Easy Version) Manacher可持久化线段树 Touhou Red Red Blue DP 模拟 Expectation (Easy Version) 签到&#xff0c;组合数学 Tree 树形DP Cactus Circuit 仙人掌图&#xff0c;tarjan找简单环 Counting Stars 暴力…

8.13 刷题记录(4道题)

8.13 刷题记录 6. 反转链表方法一&#xff1a; 迭代方法二&#xff1a;递归 7. 合并两个排序的链表8. 复杂链表的复刻9. 二叉搜索树与双向链表 6. 反转链表 原题链接 方法一&#xff1a; 迭代 1 -> 2 -> 3 -> 4 i j 1 <- 2 -> 3 -> 4 i j 就像这样迭代 /…

每日一题——旋转数组的最小数字(II)

旋转数组的最小数字——II 题目链接 注&#xff1a;此题是昨天旋转数组的最小数字——I的拓展延伸&#xff0c;昨天题目数组的条件是不会存在重复元素&#xff0c;而本题数组的元素可以重复&#xff0c;因此建议先做前面一题&#xff0c;进行思考&#xff0c;这样求解这一题的…

python print单引号和双引号区别

python中单引号和双引号有什么区别 942次阅读 没有评论 单引号和双引号 在Python中我们都知道单引号和双引号都可以用来表示一个字符串&#xff0c;比如 str1 python str2 "python" str1和str2是没有任何区别的。但是如果遇到需要转义字符的情况&#xff0c;来…

面试热题(反转字符串中的单词)

给你一个字符串 s &#xff0c;请你反转字符串中 单词 的顺序。 单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。 返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。 注意&#xff1a;输入字符串 s中可能会存在前导空格、尾随空格…

Skeleton-Aware Networks for Deep Motion Retargeting

Skeleton-Aware Networks for Deep Motion Retargeting解析 摘要1. 简介2. Related Work2.1 运动重定向&#xff08;Motion Retargeting&#xff09;2.2 Neural Motion Processing 3. 概述&#xff08;Overview&#xff09;4. 骨骼感知深度运动处理4.1 运动表征4.2 骨架卷积4.3…

《论文阅读12》RandLA-Net: Efficient Semantic Segmentation of Large-Scale Point Clouds

一、论文 研究领域&#xff1a;全监督3D语义分割&#xff08;室内&#xff0c;室外RGB&#xff0c;kitti&#xff09;论文&#xff1a;RandLA-Net: Efficient Semantic Segmentation of Large-Scale Point Clouds CVPR 2020 牛津大学、中山大学、国防科技大学 论文链接论文gi…

pyqt5多线程(子线程执行将结果返回到主线程上,提示对话框)

pyqt5多线程&#xff08;子线程执行将结果返回到主线程上&#xff0c;提示对话框&#xff09; 1.为什么要多线程执行 在主线程ui界面点击登录后&#xff0c;加延时10s,&#xff08;模拟调用接口登录&#xff0c;假设耗时10s&#xff09;,ui主线程在等待请求返回结果&#xff…

Es、kibana安装教程-ES(二)

上篇文章介绍了ES负责数据存储&#xff0c;计算和搜索&#xff0c;他与传统数据库不同&#xff0c;是基于倒排索引来解决问题的。Kibana是es可视化工具。 分布式搜索ElasticSearch-ES&#xff08;一&#xff09; 一、ElasticSearch安装 官网下载地址&#xff1a;https://www…

Kotlin runBlocking launch多个协程读写mutableListOf时序

Kotlin runBlocking launch多个协程读写mutableListOf时序 import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.runBlockingfun main(args: Array<String>) {var lists mutableListOf<String>()runBlocking {launch {r…

jsoup解析html之table表格

jsoup解析html之table表格 jsoup说明 一款Java 的HTML解析器 jsoup 是一款Java 的HTML解析器&#xff0c;可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API&#xff0c;可通过DOM&#xff0c;CSS以及类似于jQuery的操作方法来取出和操作数据。 主要功能 从一…

Mac M2 Pro安装使用Cocoapods

Mac Pro M2安装使用Cocoapods 在新公司要做iOS开发&#xff0c;所以在新电脑上安装Cocoapods 在升级gem&#xff0c;sudo gem update --system&#xff0c;和安装cocoapods时都遇到如下的提示&#xff1a; ERROR: While executing gem ... (Errno::EPERM)Operation not per…

【MybatisPlus】LambdaQueryWrapper和QueryWapper的区别

个人主页&#xff1a;金鳞踏雨 个人简介&#xff1a;大家好&#xff0c;我是金鳞&#xff0c;一个初出茅庐的Java小白 目前状况&#xff1a;22届普通本科毕业生&#xff0c;几经波折了&#xff0c;现在任职于一家国内大型知名日化公司&#xff0c;从事Java开发工作 我的博客&am…

input 设置type=“number“,鼠标悬停关闭提示语

一、问题 最近刚发现input 设置type"number"之后&#xff0c;鼠标悬停会出现提示语&#xff1a;请输入有效值。两个最接近的有效值分别为xx和xx。想要输入的值确实为number格式&#xff0c;又可以输入小数&#xff0c;不限制小数位&#xff0c;所以要把这讨厌的提示去…

最小路径和——力扣64

文章目录 题目描述动态规划题目描述 动态规划 class Solution {public:int minPathSum(vector<vector<int>>

WebAPIs 第四天

1.日期对象 2.节点操作 3.M端事件 4.JS插件 一.日期对象 实例化时间对象方法时间戳 日期对象&#xff1a;用来表示时间的对象 作用&#xff1a;可以得到当前系统时间 1.1 实例化 ① 概念&#xff1a;在代码中发现了new关键字时&#xff0c;一般将这个操作称为实例化 …

Controller是线程安全吗?如何实现线程安全

测试是否是线程安全 RequestMapping("/test") RestController public class TestController {//1、定义num&#xff0c;判断不同线程访问的时候&#xff0c;num的返回结果是否一致private Integer num0;/*** 2、定义两个方法*/GetMapping("/count1")publi…