模拟到数字的映射——频率预畸变与双线性变换
双线性变换(Bilinear Transform)是将模拟滤波器转换为数字滤波器的标准方法。它通过s→z的映射,将s平面的虚轴映射为z平面的单位圆,保持频率响应形状:
双线性变换的核心优势:(1)保持稳定性——s左半平面映射到z单位圆内;(2)无频率混叠——整个jΩ轴映射到单位圆;(3)代数变换——直接替换s即可得到H(z)。
但也有一个重要缺点:频率扭曲(frequency warping)。模拟频率Ω与数字频率ω的关系是非线性的:
这意味着需要预畸变(prewarping)来补偿:设计时先将关键频率按反方向扭曲,再进行双线性变换。
预畸变是双线性变换的关键步骤,确保数字滤波器在指定频率处的响应与模拟原型一致:
对于每个关键频率(通带边沿、阻带边沿),都需要进行预畸变。这样双线性变换后,数字滤波器在这些频率点的响应与原始设计目标一致。
从s到z的映射推导:
当s=jΩ时:z = (1+jΩT/2)/(1-jΩT/2),|z|=1(在单位圆上)
当Ω=0时z=1,当Ω=∞时z=-1,当Ω=2/T时z=j。整个jΩ轴[0,∞)映射到单位圆的[0,π)。
这种一一映射保证了无混叠,但也引入了非线性频率扭曲。低频处扭曲小(Ω≈ω/T),高频处扭曲严重。
//=============================================
// dsp_bilinear.v
// 双线性变换IIR滤波器
// 预畸变 + 系数映射
//=============================================
module dsp_bilinear #(
parameter DATA_WIDTH = 16,
parameter COEFF_WIDTH = 16,
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] b0, b1, b2, // 分子系数
input wire signed [COEFF_WIDTH-1:0] a1, a2, // 分母系数
output reg signed [OUT_WIDTH-1:0] data_out,
output reg out_valid
);
// 二阶IIR(双二阶)
reg signed [DATA_WIDTH-1:0] x1, x2; // 输入延迟
reg signed [OUT_WIDTH-1:0] y1, y2; // 输出延迟
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
x1 <= 0; x2 <= 0; y1 <= 0; y2 <= 0;
data_out <= 0; out_valid <= 1'b0;
end else if (data_valid) begin
// y[n] = b0*x[n] + b1*x[n-1] + b2*x[n-2]
// - a1*y[n-1] - a2*y[n-2]
data_out <= b0*data_in + b1*x1 + b2*x2
- a1*y1 - a2*y2;
x2 <= x1; x1 <= data_in;
y2 <= y1; y1 <= data_out;
out_valid <= 1'b1;
end else out_valid <= 1'b0;
end
endmodule
//=============================================
// dsp_prewarp.v
// 频率预畸变计算模块
// Ω = (2/T)*tan(ω*T/2)
//=============================================
module dsp_prewarp #(
parameter PHASE_WIDTH = 16,
parameter DATA_WIDTH = 16,
parameter SAMPLE_RATE = 48000
)(
input wire [PHASE_WIDTH-1:0] omega_d, // 数字角频率
output reg signed [DATA_WIDTH-1:0] omega_a // 预畸变模拟角频率
);
// 预畸变:Ω = 2*fs*tan(ω/(2*fs))
// 使用查表法近似tan函数
reg signed [DATA_WIDTH-1:0] tan_lut [0:255];
initial begin
integer i;
for (i = 0; i < 256; i = i + 1)
tan_lut[i] = $rtoi((2.0**(DATA_WIDTH-1)-1) *
$tan(3.14159265*i/512));
end
always @(*) begin
omega_a <= tan_lut[omega_d[PHASE_WIDTH-1:PHASE_WIDTH-8]];
end
endmodule
//=============================================
// tb_bilinear.v
// 双线性变换IIR测试台
//=============================================
`timescale 1ns/1ps
module tb_bilinear;
parameter DW=16, CW=16, OW=32;
reg clk, rst_n, dv;
reg signed [DW-1:0] x_in;
reg signed [CW-1:0] b0, b1, b2, a1, a2;
wire signed [OW-1:0] y_out;
wire ov;
dsp_bilinear #(.DATA_WIDTH(DW),.COEFF_WIDTH(CW),.OUT_WIDTH(OW))
uut(.clk(clk),.rst_n(rst_n),.data_valid(dv),.data_in(x_in),
.b0(b0),.b1(b1),.b2(b2),.a1(a1),.a2(a2),
.data_out(y_out),.out_valid(ov));
initial clk = 0; always #5 clk = ~clk;
initial begin
$dumpfile("bilinear.vcd"); $dumpvars(0, tb_bilinear);
// 设置二阶低通系数(示例值)
b0 = 16'sd2076; b1 = 16'sd4153; b2 = 16'sd2076;
a1 = -16'sd5956; a2 = 16'sd3754;
rst_n = 0; dv = 0; x_in = 0; #50; rst_n = 1;
// 脉冲响应测试
dv = 1; x_in = 32767;
@(posedge clk); x_in = 0;
repeat(100) @(posedge clk);
dv = 0;
$display("双线性变换IIR测试完成");
$finish;
end
endmodule
| 特性 | 双线性变换 | 脉冲响应不变法 |
|---|---|---|
| 频率混叠 | 无 | 有(高频折叠到低频) |
| 频率扭曲 | 有(需预畸变) | 无 |
| 稳定性 | 保持 | 保持 |
| 适用滤波器 | 低通/带通/高通/带阻 | 仅低通/带通 |
| 频率响应保真 | 形状保持但扭曲 | 高频失真 |
脉冲响应不变法的优势是频率不扭曲,缺点是有混叠。对于低通和带通滤波器且阻带衰减足够时,两种方法都可使用。对于高通和带阻,必须用双线性变换。
双线性变换得到的IIR通常分解为二阶节(双二阶)级联。一个双二阶的系统函数为:
双二阶是IIR的基本构建模块,所有高阶IIR都可分解为双二阶级联或并联。其系数计算步骤:(1)设计模拟原型;(2)预畸变频率;(3)双线性变换得到数字系数;(4)量化为定点。
数字低通:ωp=0.2π,ωs=0.3π,T=1/48000。计算预畸变后的Ωp和Ωs。
一阶模拟H(s)=1/(s+1),用双线性变换求H(z)(T=1)。
用双线性变换设计二阶Butterworth低通:fc=1kHz,fs=8kHz。写出数字系数b0,b1,b2,a1,a2。
上述系数分别量化为8位和16位,分析极点位置偏移。
✅ 理解了双线性变换的数学原理
✅ 掌握了频率预畸变的方法
✅ 实现了双二阶IIR滤波器
✅ 理解了双线性变换vs脉冲响应不变法
✅ 掌握了IIR系数量化的影响与对策
双线性变换在进阶应用中还有以下重要主题值得深入研究:
本课内容在整个DSP课程体系中处于承上启下的位置:
在实际工程中,双线性变换的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。
在实际工程中,双线性变换的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。
在实际工程中,双线性变换的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。
在实际工程中,双线性变换的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。
在实际工程中,双线性变换的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。
在实际工程中,双线性变换的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。
在实际工程中,双线性变换的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。
在实际工程中,双线性变换的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。
在实际工程中,双线性变换的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。
在实际工程中,双线性变换的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。
在实际工程中,双线性变换的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。
在实际工程中,双线性变换的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。
在实际工程中,双线性变换的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。
在实际工程中,双线性变换的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。