二维FIR滤波器原理、系数设计与时序匹配的Verilog实现
二维FIR滤波器通过卷积核与图像的乘累加实现各种滤波效果。常见3x3核:均值模糊[1,1,1;1,1,1;1,1,1]/9、高斯[1,2,1;2,4,2;1,2,1]/16、拉普拉斯边缘[0,-1,0;-1,4,-1;0,-1,0]、锐化[0,-1,0;-1,5,-1;0,-1,0]。硬件架构:行缓冲+3x3窗口+9个乘法器+累加器+饱和截断。
| 滤波器 | 核 | 效果 |
|---|---|---|
| 均值 | [1,1,1;1,1,1;1,1,1]/9 | 模糊/平滑 |
| 高斯 | [1,2,1;2,4,2;1,2,1]/16 | 高斯模糊 |
| 拉普拉斯 | [0,-1,0;-1,4,-1;0,-1,0] | 边缘检测 |
| 锐化 | [0,-1,0;-1,5,-1;0,-1,0] | 锐化增强 |
// 第07课:2D FIR滤波器
module fir_2d_filter #(parameter DATA_W=8, COEF_W=9, IMG_W=640)(
input wire clk, rst_n,
input wire valid_in,
input wire [DATA_W-1:0] data_in,
input wire sof_in, eol_in,
input wire signed [COEF_W-1:0] k00,k01,k02,k10,k11,k12,k20,k21,k22,
output reg valid_out,
output reg [DATA_W-1:0] data_out
);
reg [DATA_W-1:0] lb0[0:IMG_W-1],lb1[0:IMG_W-1]; reg [11:0] col;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) col<=0; else if (valid_in) col<=(sof_in||col==IMG_W-1)?0:col+1;
end
reg [DATA_W-1:0] w00,w01,w02,w10,w11,w12,w20,w21,w22;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) {w00,w01,w02,w10,w11,w12,w20,w21,w22}<='0;
else if (valid_in) begin
lb1[col]<=lb0[col]; lb0[col]<=data_in;
w00<=w01;w01<=w02;w02<=lb1[col]; w10<=w11;w11<=w12;w12<=lb0[col];
w20<=w21;w21<=w22;w22<=data_in;
end
end
reg signed [DATA_W+COEF_W:0] p00,p01,p02,p10,p11,p12,p20,p21,p22;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) {p00,p01,p02,p10,p11,p12,p20,p21,p22}<='0;
else begin
p00<=$signed({1'b0,w00})*k00; p01<=$signed({1'b0,w01})*k01; p02<=$signed({1'b0,w02})*k02;
p10<=$signed({1'b0,w10})*k10; p11<=$signed({1'b0,w11})*k11; p12<=$signed({1'b0,w12})*k12;
p20<=$signed({1'b0,w20})*k20; p21<=$signed({1'b0,w21})*k21; p22<=$signed({1'b0,w22})*k22;
end
end
reg signed [DATA_W+COEF_W+2:0] acc; reg sv;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin acc<=0; sv<=0; end
else begin sv<=valid_in; acc<=p00+p01+p02+p10+p11+p12+p20+p21+p22; end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin valid_out<=0; data_out<=0; end
else begin valid_out<=sv;
if (acc<0) data_out<=0; else if (acc>255) data_out<=8'hFF; else data_out<=acc[DATA_W-1:0];
end
end
endmodule
✅Verilator验证通过 — 本课Verilog代码已通过 Verilator --lint-only 检查。
本节深入探讨2D FIR滤波在FPGA实现中的关键设计决策和优化策略。
视频处理模块的时序设计需要考虑以下因素:
FPGA资源有限,视频处理模块需要精心优化:
| 策略 | 适用场景 | 节省资源 |
|---|---|---|
| 时分复用乘法器 | 像素时钟远低于系统时钟 | DSP 4~8x |
| 移位替代乘法 | 系数为2的幂次 | DSP 1个/次 |
| CSD编码 | 固定系数乘法 | DSP全部 |
| 查表替代计算 | 非线性函数(sin,exp) | 逻辑大量 |
| 对称性利用 | FIR系数对称 | 乘法器减半 |
视频处理中定点运算的精度直接影响图像质量。分析方法:
8bit视频处理的经验法则:中间结果至少保留12bit,最终输出截断到8bit。
好的视频处理模块应该是参数化的:
视频模块的完整验证包括:
标准视频模块接口信号:
input wire clk, rst_n, // 时钟复位 input wire valid_in, // 输入有效 input wire [DATA_W-1:0] data_in, // 输入数据 input wire sof_in, eol_in, // 帧起始/行结束 output reg valid_out, // 输出有效 output reg [DATA_W-1:0] data_out, // 输出数据 output reg sof_out, eol_out // 帧起始/行结束
这种接口设计使模块可以自由级联,形成处理流水线。
视频处理是持续运行的,功耗优化很重要:
FIR滤波器的频率响应由系数决定。低通滤波器截止频率与核大小成正比:3x3核的截止频率约为Nyquist频率的1/3。FIR系数设计方法:窗函数法(矩形/Hamming/Hanning/Blackman)、频率采样法、最优等波纹法(Parks-McClellan)。对称FIR系数可减半乘法器数量。FIR的直流增益=所有系数之和,归一化为1.0保证恒值输入不变。
当像素时钟较高(如148.5MHz for 1080p)时,关键路径可能无法满足时序约束。优化方法:
当FPGA资源紧张时,可以牺牲吞吐率换取面积:
视频处理模块持续运行,功耗优化很重要:
| 术语 | 英文 | 说明 |
|---|---|---|
| 像素 | Pixel | 图像最小单元 |
| 帧 | Frame | 一帧完整图像 |
| 场 | Field | 隔行扫描的半帧 |
| 消隐 | Blanking | 非有效视频区域 |
| 流水线 | Pipeline | 多级并行处理架构 |
| 定点数 | Fixed-point | 有限精度数值表示 |
| 饱和截断 | Saturation | 超出范围钳位到边界 |
| 行缓冲 | Line Buffer | 缓存一行像素的存储器 |
| 帧缓冲 | Frame Buffer | 缓存一帧图像的存储器 |
| 时序 | Timing | 视频同步信号参数 |
| 错误现象 | 可能原因 | 解决方法 |
|---|---|---|
| 输出全零 | 复位未释放或valid未传播 | 检查rst_n和valid链 |
| 色彩偏移 | 系数位宽不足或溢出 | 增加中间结果位宽 |
| 行间错位 | 行缓冲地址不对齐 | 检查写地址和读地址 |
| 画面闪烁 | 时序违例或跨时钟域 | 添加同步器或约束 |
| 边缘伪影 | 边界处理不正确 | 添加边界检测和钳位 |
| 资源 | 估计使用量 | 说明 |
|---|---|---|
| LUT | 100~500 | 加法器、比较器、选择器 |
| FF | 50~200 | 流水线寄存器、状态机 |
| DSP | 0~9 | 乘法器(色彩转换9个) |
| BRAM(18K) | 0~6 | 行缓冲(2~4行)、帧缓冲、LUT |
| 延迟 | 2~5 cycles | 流水线级数 |
# 语法检查
verilator --lint-only verilog/lesson_07.v
# 带波形仿真(需要testbench)
verilator --trace --cc verilog/lesson_07.v --exe tb.cpp
make -C obj_dir -f Vlesson_07.mk
./obj_dir/Vlesson_07