HLS实现FIR低通滤波器并上板验证

硬件: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滤波器工程

### 回答1: HLS(High-Level Synthesis)和PYNQ(Python Productivity for Zynq)在FIR滤波器设计中都有重要的应用。 首先,HLS是一种高级综合工具,可以将高级语言(如C/C++)代码转换为硬件描述语言(如VHDL或Verilog),从而实现对程序的高层次综合。在FIR滤波器设计中,HLS可以极大地简化设计流程。设计者只需使用C/C++编写FIR滤波器的算法实现,然后使用HLS工具将其转换为硬件描述语言。这样可以大幅缩短开发时间,同时减少设计错误的风险。HLS还可以优化生成的硬件代码,以提高性能和减少资源消耗。 PYNQ是一个基于Python的开发环境,用于Zynq系列FPGA的快速原型开发。在FIR滤波器设计中,PYNQ提供了一个易用的Python编程界面,使设计者可以通过编写Python脚本来实现滤波器算法。PYNQ还提供了丰富的库和工具,以便进行硬件加速。通过利用PYNQ的高级API和硬件加速功能,可以使FIR滤波器FPGA上运行更快且更高效。 综上所述,HLS和PYNQ在FIR滤波器设计中发挥着重要作用。HLS可以将高级语言代码转换为硬件描述语言,从而简化设计流程并提高设计效率。而PYNQ则提供了具有高级API和硬件加速功能的Python开发环境,使FIR滤波器设计更加灵活和高效。两者结合使用,可以在滤波器设计中获得更好的性能和更快的开发速度。 ### 回答2: HLS(High-Level Synthesis)和PYNQ(Python productivity for Zynq)在fir滤波器设计中有着重要的应用。 HLS是一种高级综合工具,它允许使用高级语言(例如C、C++或SystemC)来描述硬件设计,并自动生成硬件描述语言(HDL)代码,如Verilog或VHDL。HLS可以大大减少编写和调试HDL代码的工作量,提高硬件设计开发效率。 在fir滤波器设计中,可以使用HLS快速生成滤波器的硬件描述代码。通过将滤波器的算法实现为C或C++代码,然后使用HLS工具进行综合,可以将其转化为效率高且对资源利用率优化的硬件描述代码。使用HLS工具可以方便地对滤波器进行功能验证和性能评估,同时也能够快速优化设计,使其满足滤波器设计的需求。 PYNQ是一个基于Python的开发环境,它为Zynq系列的FPGA提供了更高的生产力和易用性。PYNQ结合了Python的简洁和可读性,以及FPGA强大的并行计算能力,能够使用Python编程语言轻松地进行FPGA开发。在fir滤波器设计中,可以使用PYNQ构建滤波器的控制逻辑和数据流控制。通过调用PYNQ提供的库函数和API,可以使用Python语言轻松地控制Zynq的FPGA进行滤波器数据的输入、处理和输出。 使用PYNQ进行fir滤波器设计,可以实现高度灵活的开发流程。Python的高级编程语言特性使得fir滤波器的调试、测试和性能优化更加易于理解和操作。此外,PYNQ还提供了丰富的示例代码和开发工具,加速滤波器设计开发过程。 综上所述,HLS和PYNQ在fir滤波器设计中的应用可以显著提高硬件设计的效率和可读性,简化了设计过程,并为开发人员提供了更多的工具和资源进行优化和测试。 ### 回答3: HLS和Pynq在FIR滤波器设计中有着重要的应用。 HLS(High-Level Synthesis)是一种用于高级语言(如C/C++)描述硬件功能并自动生成硬件电路的技术。在FIR滤波器设计中,HLS可以将滤波器算法的高级描述转化为硬件电路。它可以将复杂的计算任务分解为并行任务,并通过合理的调度和资源分配生成高效的硬件。与传统的手动硬件设计相比,HLS可以大大缩短设计周期并提高设计的可重用性。 Pynq是一种基于Python的可编程逻辑(PL)和处理系统(PS)的开发平台。在FIR滤波器设计中,Pynq可以用于快速原型开发和系统集成。通过使用Python和Pynq,可以实现对硬件功能的快速控制和配置,而无需深入了解硬件设计的细节。Pynq还提供了各种可编程逻辑的高级库和示例代码,使得滤波器开发更加方便和高效。 结合HLS和Pynq可以实现高效的FIR滤波器设计。首先,使用HLSFIR滤波器算法转化为硬件电路,通过并行化和资源分配使得硬件电路性能更佳。其次,通过Pynq进行快速原型开发,借助Python轻松控制和配置硬件功能,便于系统集成和功能验证。这种组合使用可以提高滤波器设计的效率和效果,同时降低设计的复杂性和风险。 总之,HLS和Pynq在FIR滤波器设计中的应用使得滤波器设计更加高效和灵活,提高了开发者的生产效率和设计质量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值