多相分解FIR——高效多采样率滤波的核心
多相分解将N抽头FIR分解为M个子滤波器,每个处理不同相位分量:
Noble恒等式:↓M·H(z) ≡ H(zᴹ)·↓M,H(z)·↑L ≡ ↑L·H(zᴸ)
//=============================================
// dsp_fir_polyphase.v
// M路多相FIR滤波器
//=============================================
module dsp_fir_polyphase #(
parameter DATA_WIDTH = 16,
parameter COEFF_WIDTH = 16,
parameter PHASES = 4,
parameter TAP_PER_PHASE = 8,
parameter OUT_WIDTH = 32
)(
input wire clk,
input wire rst_n,
input wire data_valid,
input wire signed [DATA_WIDTH-1:0] data_in,
input wire signed [COEFF_WIDTH-1:0] coeffs [0:PHASES-1][0:TAP_PER_PHASE-1],
output reg signed [OUT_WIDTH-1:0] data_out,
output reg out_valid
);
reg [$clog2(PHASES)-1:0] phase_cnt;
reg signed [DATA_WIDTH-1:0] phase_delay [0:PHASES-1][0:TAP_PER_PHASE-1];
integer p,k;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin phase_cnt<=0; data_out<=0; out_valid<=1'b0;
for (p=0;p<PHASES;p=p+1) for (k=0;k<TAP_PER_PHASE;k=k+1) phase_delay[p][k]<=0;
end else if (data_valid) begin
phase_delay[phase_cnt][0] <= data_in;
for (k=1;k<TAP_PER_PHASE;k=k+1) phase_delay[phase_cnt][k]<=phase_delay[phase_cnt][k-1];
data_out <= 0;
for (p=0;p<PHASES;p=p+1) data_out <= data_out+phase_mac(p);
out_valid <= 1'b1; phase_cnt <= phase_cnt+1'b1;
end else out_valid <= 1'b0;
end
function signed [OUT_WIDTH-1:0] phase_mac;
input integer phase;
reg signed [OUT_WIDTH-1:0] acc;
reg signed [DATA_WIDTH+COEFF_WIDTH-1:0] prod;
integer j;
begin acc=0;
for (j=0;j<TAP_PER_PHASE;j=j+1) begin
prod=phase_delay[phase][j]*coeffs[phase][j]; acc=acc+prod;
end
phase_mac=acc;
end
endfunction
endmodule
//=============================================
// dsp_decimator_polyphase.v
// 多相抽取滤波器:先分相后滤波
// 计算量降为1/M
//=============================================
module dsp_decimator_polyphase #(
parameter DATA_WIDTH = 16,
parameter COEFF_WIDTH = 16,
parameter DECIM_FACTOR = 4,
parameter TAP_TOTAL = 32,
parameter OUT_WIDTH = 32
)(
input wire clk,
input wire rst_n,
input wire data_valid,
input wire signed [DATA_WIDTH-1:0] data_in,
output reg signed [OUT_WIDTH-1:0] data_out,
output reg out_valid
);
localparam TAP_PER_PHASE = TAP_TOTAL/DECIM_FACTOR;
reg signed [COEFF_WIDTH-1:0] phase_coeffs [0:DECIM_FACTOR-1][0:TAP_PER_PHASE-1];
reg signed [DATA_WIDTH-1:0] phase_buf [0:DECIM_FACTOR-1][0:TAP_PER_PHASE-1];
reg [$clog2(DECIM_FACTOR)-1:0] phase_cnt;
integer p,k;
initial begin
for (p=0;p<DECIM_FACTOR;p=p+1) for (k=0;k<TAP_PER_PHASE;k=k+1)
phase_coeffs[p][k] = 16'sd1024;
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin phase_cnt<=0; data_out<=0; out_valid<=0;
for (p=0;p<DECIM_FACTOR;p=p+1) for (k=0;k<TAP_PER_PHASE;k=k+1) phase_buf[p][k]<=0;
end else if (data_valid) begin
phase_buf[phase_cnt][0] <= data_in;
for (k=1;k<TAP_PER_PHASE;k=k+1) phase_buf[phase_cnt][k]<=phase_buf[phase_cnt][k-1];
if (phase_cnt==DECIM_FACTOR-1) begin
data_out <= 0;
for (p=0;p<DECIM_FACTOR;p=p+1) begin
for (k=0;k<TAP_PER_PHASE;k=k+1)
data_out <= data_out+phase_buf[p][k]*phase_coeffs[p][k];
end
out_valid <= 1;
end else out_valid <= 0;
phase_cnt <= phase_cnt+1'b1;
end
end
endmodule
将16抽头FIR h[n]={1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4}分解为4相,写出E₀-E₃。
32抽头FIR,4倍抽取。比较直接法和多相法的每输出乘法次数。
证明↓M·H(z)=H(zᴹ)·↓M,并解释其工程意义。
修改dsp_decimator_polyphase.v为内插版本。
✅ 理解了多相分解的数学原理
✅ 掌握了Noble恒等式及其应用
✅ 实现了多相FIR和抽取滤波器
✅ 理解了多相内插与滤波器组
✅ 掌握了多相分解如何减少计算量
多相分解同样适用于内插(升采样),结构恰好是抽取的"镜像":
多相内插步骤:(1)输入信号同时送入L个子滤波器;(2)每个子滤波器独立计算;(3)输出按相位顺序交织:E₀→E₁→...→E_{L-1}→E₀→...;(4)等效于内插后在L倍速率下滤波,但计算量仅为1/L。
多相分解与DFT结合构成滤波器组,用于子带编码和频分复用:
对于大比率抽取(如M=64),单级实现阶数过高。采用多级结构:M=M₁×M₂×...,每级做小比率抽取,总计算量显著降低。例如64=4×4×4,三级4倍抽取,每级阶数大幅减少。
| 方案 | 总乘法/输出 | 存储需求 | 设计复杂度 |
|---|---|---|---|
| 单级64倍 | 640×2=1280 | 1280字 | 简单 |
| 3级4×4×4 | 30×2+22×2+18×2=140 | 140字 | 中等 |
多相分解同样适用于内插(升采样),结构恰好是抽取的"镜像":
多相内插步骤:(1)输入信号同时送入L个子滤波器;(2)每个子滤波器独立计算;(3)输出按相位顺序交织;(4)等效于内插后在L倍速率下滤波,但计算量仅为1/L。
多相分解与DFT结合构成滤波器组:
对于大比率抽取(如M=64),单级实现阶数过高。采用多级结构:M=M₁×M₂×...,每级做小比率抽取。
| 方案 | 总乘法/输出 | 存储 | 复杂度 |
|---|---|---|---|
| 单级64倍 | 1280 | 1280字 | 简单 |
| 3级4×4×4 | 140 | 140字 | 中等 |
设计规格:fs=48kHz,输出12kHz,通带0-4kHz,过渡4-6kHz,阻带>50dB
多相滤波器的几个进阶设计主题:
多相FIR在进阶应用中还有以下重要主题值得深入研究:
本课内容在整个DSP课程体系中处于承上启下的位置:
在实际工程中,多相FIR的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。
在实际工程中,多相FIR的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。
在实际工程中,多相FIR的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。
在实际工程中,多相FIR的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。
在实际工程中,多相FIR的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。
在实际工程中,多相FIR的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。
在实际工程中,多相FIR的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。
在实际工程中,多相FIR的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。