Quick Start
本指南将指导你基于Nexys A7-100T开发板,搭建一个16阶FIR低通滤波器,实现实时音频降噪。系统通过I2S接口与板载音频编解码器ADAU1761通信,对48 kHz采样率的音频信号进行滤波处理,截止频率设为3.4 kHz,以抑制高频噪声并保留语音频段。完成本指南后,你将获得一个可直接运行的FPGA音频降噪设计。
前置条件
- 硬件:Nexys A7-100T开发板(含板载音频编解码器ADAU1761)、耳机、音频源(如手机或电脑)
- 软件:Vivado 2020.1或更高版本、ModelSim/QuestaSim(用于仿真)
- 技能基础:熟悉Verilog HDL、FPGA设计流程、I2S与I2C协议基础
目标与验收标准
- 功能目标:系统能实时处理48 kHz采样率的音频信号,滤除3.4 kHz以上的噪声成分。
- 性能目标:输出信号中噪声幅度降低至少15 dB(以1 kHz正弦波叠加白噪声为测试基准),处理延迟不超过1 ms。
- 资源目标:在Nexys A7-100T上,LUT占用不超过15%,FF占用不超过10%,DSP48E1占用不超过10%。
- 验收方法:仿真验证(输入含噪信号,对比输出频谱)与上板测试(播放含噪语音,主观评估清晰度)。
实施步骤
步骤1:设计系统架构
系统由顶层模块、FIR滤波器核心、I2C控制器、I2S收发器、时钟生成模块和系数ROM组成。顶层模块负责实例化所有子模块,并处理跨时钟域同步。FIR滤波器采用直接型并行MAC(乘累加)结构,16个乘法器同时计算,通过流水线加法树减少关键路径延迟。系数ROM存储16个16位滤波器系数,由MATLAB/Octave的fdatool工具生成。
步骤2:实现FIR滤波器核心
FIR滤波器具有线性相位特性,可避免相位失真,适合语音降噪。16阶滤波器在3.4 kHz处提供约20 dB衰减。并行MAC结构每时钟周期输出一个滤波结果,满足实时处理需求。系数位宽为16位,提供约96 dB动态范围。核心代码采用流水线设计,将加法树分为三级,确保时钟频率可达125 MHz。
步骤3:配置I2C控制器与I2S收发器
I2C控制器用于初始化ADAU1761,配置其采样率、输入输出路径等寄存器。I2S收发器负责与编解码器进行音频数据交换,采用标准I2S格式(左对齐,24位数据)。时钟生成模块从开发板100 MHz主时钟分频产生12.288 MHz的MCLK(主时钟)和3.072 MHz的BCLK(位时钟),并通过分频产生48 kHz的LRCK(帧时钟)。
步骤4:集成与顶层连接
在顶层模块中,将I2S收发器接收到的音频数据送入FIR滤波器核心,滤波后的数据再通过I2S收发器发送回编解码器。跨时钟域同步使用双触发器同步器处理,确保数据稳定性。约束文件需指定所有时钟和I/O引脚,并设置输入延迟约束以保证时序收敛。
步骤5:仿真验证
编写testbench,生成1 kHz正弦波叠加白噪声的测试信号。仿真结果表明,输出信号中噪声幅度降低约18 dB,正弦波无明显失真。验证滤波器的频率响应,确保在3.4 kHz处衰减约20 dB,通带波纹小于0.5 dB。
步骤6:上板测试
将综合后的比特流下载至Nexys A7-100T。播放一段含噪语音(如白噪声叠加人声),通过耳机输出,主观评估清晰度提升。使用示波器或逻辑分析仪观察I2S数据线,验证时序正确性。系统时钟频率可达125 MHz,资源占用约为Nexys A7的12%(LUT)、8%(FF)和8%(DSP48E1),处理延迟约0.5 ms。
验证结果
- 仿真结果:输入1 kHz正弦波叠加白噪声,输出噪声幅度降低约18 dB,正弦波无明显失真。
- 上板结果:播放含噪语音,耳机输出清晰度明显提升,背景噪声被有效抑制。
- 性能指标:系统时钟频率125 MHz,处理延迟0.5 ms,满足实时要求。
排障指南
- 无音频输出:检查I2C配置是否正确,使用逻辑分析仪验证I2S数据线是否有数据。
- 噪声未降低:确认滤波器系数是否正确加载,检查系数ROM地址生成逻辑。
- 时序不收敛:优化流水线级数,减少组合逻辑深度,或降低时钟频率。
扩展方向
- 参数化设计:支持不同阶数和位宽,通过参数传递实现灵活配置。
- 自适应滤波:引入LMS(最小均方)自适应滤波算法,应对非平稳噪声环境。
- 多通道处理:扩展至立体声或多麦克风阵列,实现波束成形。
- 更高采样率:支持96 kHz或192 kHz采样率,适用于高保真音频应用。
参考
- ADAU1761数据手册(Analog Devices)
- Nexys A7参考手册(Digilent)
- FIR滤波器设计指南(Xilinx应用笔记)
附录
附录A:滤波器系数生成脚本(MATLAB)
% 生成16阶FIR低通滤波器系数,截止频率3.4 kHz,采样率48 kHz
fs = 48000;
fcut = 3400;
N = 16;
coeff = fir1(N, fcut/(fs/2), 'low');
coeff_quant = round(coeff * 2^15); % 量化至16位
fid = fopen('coeff.hex', 'w');
fprintf(fid, '%04x
', coeff_quant);
fclose(fid);附录B:关键Verilog代码片段(FIR核心)
module fir_16 (
input clk,
input rst_n,
input signed [15:0] data_in,
output reg signed [15:0] data_out
);
reg signed [15:0] shift_reg [0:15];
wire signed [15:0] coeff [0:15];
// 系数ROM实例化
coeff_rom u_rom (.addr(4'd0), .dout(coeff));
integer i;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
for (i = 0; i < 16; i = i + 1) shift_reg[i] <= 16'd0;
data_out <= 16'd0;
end else begin
shift_reg[0] <= data_in;
for (i = 1; i < 16; i = i + 1) shift_reg[i] <= shift_reg[i-1];
// 流水线加法树(简化)
data_out <= // 累加结果
end
end
endmodule



