Vivado Hls C流处理方式的FIR时域滤波
实验目的
用HDL、HLS C流程实现流处理方式的时域滤波(FIR),要求:
- 输入直流及2个频率分别为2kHz和10kHz的正弦实信号叠加,三个信号幅度为2.0、1.0、1.5
- 要求过滤掉0Hz和10kHz信号,仅剩2kHz正弦实信号
- 定点化,获得输入/输出信号和FIR系数的定点精度。要求与浮点实现的均方差不大于-40dB
- 生成的IP放入SysGen中验证
- 生成bit文件在板验证
滤波器算法
直接结构用到了多个移位寄存器,相乘后累加,思路简单但是效率较低,改变拓扑之后的转置结构有更高的效率;格形结构又较为复杂,因此在本实验的两个流程和定浮点实现方案中,均采用转置结构,保持前后统一。
滤波器及定点精度系数
在本实验中使用 sysgen 的 fdatool 工具对滤波器系数进行初步的构造,在后面的实验中发现得到的一组系数具有较好的性能。设计的滤波器为带通,窗函数为Hamming窗,阶数取68阶,截止频率为2.01kHz和4.49kHz。采样频率为奈奎斯特采样频率的4倍,即80kHz,滤波器波形以及具体系数如下。
代码与仿真分析
Directive的优化中,对函数使用了HLS PIPELINE II=1 (流水线处理) 和HLS INTERFACE ap_ctrl_none port = return;对din和dout使用了HLS INTERFACE ap_none port ;对循环操作使用HLS UNROLL进行展开,以谋求并行化处理提高系统运行速度。
#ifndef _FIR_1X_H
#define _FIR_1X_H
#include "hls_dsp.h"
#define FIR_TAP_NUM 69
#define RUN_LENGTH 1300
const unsigned SCALAR_ROUND_MODE = 0;//AP_TRN, etc;
const unsigned SCALAR_OVERFLOW_MODE = 2;//AP_WRAP, etc;
const unsigned SCALAR_SATURATION_BITS = 0;
// input data types
const unsigned INPUT_SCALAR_WIDTH = 16;
const unsigned INPUT_SCALAR_INTEGER_BITS = 4;
typedef ap_fixed<
INPUT_SCALAR_WIDTH,
INPUT_SCALAR_INTEGER_BITS,
(ap_q_mode)SCALAR_ROUND_MODE,
(ap_o_mode)SCALAR_OVERFLOW_MODE,
SCALAR_SATURATION_BITS> t_input_scalar;
// output data types
const unsigned OUTPUT_SCALAR_WIDTH = 32;
const unsigned OUTPUT_SCALAR_INTEGER_BITS = 8;
typedef ap_fixed<
OUTPUT_SCALAR_WIDTH,
OUTPUT_SCALAR_INTEGER_BITS,
(ap_q_mode)SCALAR_ROUND_MODE,
(ap_o_mode)SCALAR_OVERFLOW_MODE,
SCALAR_SATURATION_BITS> t_output_scalar;
void fir_1x ( const t_input_scalar& din, t_output_scalar& dout);
extern const t_input_scalar coe[FIR_TAP_NUM];
#endif
#include <stdio.h>
#include <stdlib.h>
#include "hls_stream.h"
#include "fir_1x.h"
using namespace hls;
const t_input_scalar coe[FIR_TAP_NUM] = {
#include "Yourdata.txt"
};
void fir_1x ( const t_input_scalar& din, t_output_scalar& dout)
{
#pragma HLS INTERFACE ap_none port=dout
#pragma HLS INTERFACE ap_none port=din
#pragma HLS PIPELINE II=1
#pragma HLS INTERFACE ap_ctrl_none port=return
static t_output_scalar product1[FIR_TAP_NUM+1]={t_output_scalar(0)};
#pragma HLS ARRAY_PARTITION variable=product1 complete dim=1
// output
dout = product1[FIR_TAP_NUM];
label_mulacc:
for (int gv_i=0;gv_i<FIR_TAP_NUM;gv_i++) {
#pragma HLS UNROLL
product1[FIR_TAP_NUM-gv_i] = din * coe[FIR_TAP_NUM-gv_i-1] + product1[FIR_TAP_NUM-gv_i-1];
}
};
首先对HLS C流程的定点实现方式和sysgen的FIR Compiler 7.2进行下比较
发现HLS C生成的IP 放入sysgen中与sysgen自带的FIR还是存在一定的差距(猜测是所采用的FIR结构并不一样),前者与后者相比存在一定的幅度衰减,但是处理时延较低,谱的纯度也较好,已经较好地滤除了0频分量和10kHz高频分量。接下来将HLS C的定浮点方式在sysgen中进行比较
发现浮点处理方式时延十分严重,但二者的幅度是相近的,另一个足以说明定点方式优于浮点方式的理由是,浮点方式占用的资源过多,在实际的上板操作中是难以实现的(下面两图分别为浮点和定点实现)
实验结论
在Matlab中对HLS C与HDL流程定浮点方案的差别进行比较,将各波形平移对齐后进行最小均方差计算,再将最小均方差用dB进行表示。假设两种信号
{
x
k
}
{
y
k
}
\{x_k\}\{y_k\}
{xk}{yk}所取得采样点数均为
K
K
K,我们取
{
x
k
}
\{x_k\}
{xk}作为基准信号,则均方差的计算公式为
ξ
=
∑
k
=
1
K
(
x
k
−
y
k
)
2
∑
k
=
1
K
x
k
2
ξ
(
d
B
)
=
10
∗
log
10
ξ
\begin{array}{l} \xi=\dfrac{\sum_{k=1}^{K}\left(x_{k}-y_{k}\right)^{2}}{\sum_{k=1}^{K} x_{k}^{2}} \\ \xi_{(d B)}=10 * \log _{10} \xi \end{array}
ξ=∑k=1Kxk2∑k=1K(xk−yk)2ξ(dB)=10∗log10ξ
有想要了解Vivado各个流程实现的朋友可以参考本链接