目录
Vivado HLS是一款强大的高层次综合工具,可将C/C++代码转换为硬件描述语言(HDL),显著提升FPGA开发效率。
1. FIR参数确定
FIR滤波器的设计,首先要明确其技术指标,这些指标对滤波器的性能和资源占用起着关键作用。以一个低通滤波器为例,其具体参数如下:
滤波器阶数设定为15。
采样频率是100MHz。
通带截止频率为20MHz。
阻带起始频率为30MHz。
通带波纹要求在0.1dB以内。
阻带衰减需达到60dB。
2. FIR系数计算
可以借助Python等工具来计算滤波器系数。下面是用Python计算系数的代码:
import numpy as np
from scipy import signal
import matplotlib.pyplot as plt
# 滤波器参数
order = 15 # 滤波器阶数
fs = 100e6 # 采样频率 (Hz)
f_pass = 20e6 # 通带截止频率 (Hz)
f_stop = 30e6 # 阻带起始频率 (Hz)
A_pass = 0.1 # 通带波纹 (dB)
A_stop = 60 # 阻带衰减 (dB)
# 归一化频率
nyquist = 0.5 * fs
wp = f_pass / nyquist
ws = f_stop / nyquist
# 计算FIR滤波器系数(使用 Parks-McClellan 算法)
h = signal.remez(order + 1, [0, wp, ws, 1.0], [1, 0], Hz=1.0)
# 打印系数(量化为16位定点数)
coeffs_q15 = [int(round(c * 32767)) for c in h]
print("FIR系数 (Q15格式):")
for i, c in enumerate(coeffs_q15):
print(f"h[{i}] = {c}, 即 {c/32768:.10f}")
# 绘制频率响应
w, h_freq = signal.freqz(h)
plt.figure()
plt.plot(0.5*fs*w/np.pi, 20*np.log10(np.abs(h_freq)))
plt.title('FIR滤波器频率响应')
plt.xlabel('频率 (Hz)')
plt.ylabel('幅度 (dB)')
plt.grid(True)
plt.axvline(f_pass, color='green') # 通带截止频率
plt.axvline(f_stop, color='red') # 阻带起始频率
plt.show()
3. C/C++代码实现
使用Vivado HLS特定的数据类型和指令:
#include "fir.h"
void fir(data_t *output, data_t input) {
// 定义FIR系数(Q15格式)
const coeff_t h[NUM_TAPS] = {
-10, -22, -32, -37, -26, 10, 72, 133,
171, 171, 133, 72, 10, -26, -37, -32, -22, -10
};
// 声明移位寄存器数组
static data_t shift_reg[NUM_TAPS];
// pragma指令,优化循环展开
#pragma HLS ARRAY_PARTITION variable=shift_reg complete dim=1
// 数据移位操作
for(int i = NUM_TAPS - 1; i > 0; i--) {
#pragma HLS UNROLL
shift_reg[i] = shift_reg[i-1];
}
shift_reg[0] = input;
// 执行乘法累加操作
acc_t acc = 0;
for(int i = 0; i < NUM_TAPS; i++) {
#pragma HLS UNROLL
acc += shift_reg[i] * h[i];
}
// 输出结果
*output = acc >> 15; // Q15格式转换
}
定义头文件:
#ifndef _FIR_H_
#define _FIR_H_
#include "ap_fixed.h"
// 定义数据类型
typedef ap_fixed<16, 1> data_t; // 16位定点数,1位整数,15位小数
typedef ap_fixed<16, 1> coeff_t; // 系数类型
typedef ap_fixed<32, 17> acc_t; // 累加器类型,防止溢出
// 定义滤波器抽头数
#define NUM_TAPS 19
// 函数原型
void fir(data_t *output, data_t input);
#endif
定义测试程序:
#include "fir.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define PI 3.14159265358979323846
int main() {
// 测试数据
data_t input[100];
data_t output[100];
// 生成测试信号(混合了5MHz和40MHz的正弦波)
for(int i = 0; i < 100; i++) {
// 5MHz信号(应该通过)
float sig1 = 0.5 * sin(2.0 * PI * 5e6 * i / 100e6);
// 40MHz信号(应该被衰减)
float sig2 = 0.5 * sin(2.0 * PI * 40e6 * i / 100e6);
// 混合信号
input[i] = sig1 + sig2;
}
// 应用FIR滤波器
for(int i = 0; i < 100; i++) {
fir(&output[i], input[i]);
}
// 输出结果到文件
FILE *fp_in = fopen("input_data.txt", "w");
FILE *fp_out = fopen("output_data.txt", "w");
for(int i = 0; i < 100; i++) {
fprintf(fp_in, "%f\n", (float)input[i]);
fprintf(fp_out, "%f\n", (float)output[i]);
}
fclose(fp_in);
fclose(fp_out);
printf("测试完成!数据已输出到input_data.txt和output_data.txt\n");
// 简单验证(检查高频分量是否被衰减)
float sum_input = 0, sum_output = 0;
for(int i = 80; i < 100; i++) {
sum_input += fabs((float)input[i]);
sum_output += fabs((float)output[i]);
}
if(sum_output < sum_input * 0.1) {
printf("验证通过:高频分量被有效衰减\n");
return 0;
} else {
printf("验证失败:高频分量衰减不足\n");
return 1;
}
}
4. Vivado HLS项目创建与配置
4.1 在Vivado HLS中创建新项目并配置
1.打开Vivado HLS工具。
2.执行 "File > New Project" 命令来创建一个新的项目。
3.为项目命名,例如 "FIR_Filter",并选择合适的存储位置。
4.添加源文件,即前面编写的fir.c
和fir.h
。
5.添加测试平台文件tb_fir.c
。
6.指定目标设备,比如xc7z020clg400-1
。
7.配置解决方案,设置时钟周期(例如 10ns)和复位类型。
4.2在Vivado HLS中执行C仿真
1.点击 "Project > Run C Simulation"。
2.确保仿真顺利完成,并且控制台显示 "Verification successful"。
3.可以使用 gnuplot 或 MATLAB 对输出文件进行分析。
4.3执行C综合以将C代码转换为RTL
1.选择 "Solution > Run C Synthesis > Active Solution"。
2.综合完成后,查看报告,重点关注:
资源利用率(DSP、LUT、FF 等)。
延迟(Latency)和吞吐量(Interval)。
关键路径分析。
4.4进行RTL级仿真验证
1.选择 "Solution > Run C/RTL Co-simulation"。
2.选择仿真工具(如VCS、ModelSim等)。
3.等待仿真完成,检查结果是否与C仿真一致。
4.5导出IP
将设计导出为IP核供Vivado使用:
1.选择 "Solution > Export RTL"。
2.保持默认设置,点击 "OK"。
3.导出完成后,IP 核会出现在项目目录的exported_ip
文件夹中。
4.6在Vivado中集成IP
1.打开 Vivado,创建新工程或打开已有工程。
2.点击 "Settings > IP > Repository",添加HLS导出的IP路径。
3.在Block Design中添加FIR滤波器IP核。
4.完成系统集成(添加时钟、复位等)。
5.生成比特流并下载到FPGA进行硬件验证。