基本概念
巴特沃斯滤波器由英国工程师 Stephen Butterworth 提出,属于 IIR 滤波器。
IIR:无限冲激响应,输出不仅依赖当前、历史输入,还依赖历史输出,存在反馈回路。FIR 无反馈,仅使用输入数据。
关键术语:
- 阶数 N:滤波器阶数,阶数越高阻带衰减越快,计算开销越大,相位失真越严重。
- 截止频率
:-3dB 截止频率,幅度下降到通带 0.707 倍处的频率点。
- 采样频率
:原始信号采样频率。
- 双线性变换:模拟滤波器转数字滤波器手段,会产生频率畸变,需要预畸变校正截止频率。
- 预畸变:补偿双线性变换带来的频率扭曲,保证实际截止频率和设计目标一致。
- a 系数、b 系数:IIR 滤波器差分方程分母、分子系数。
- 零相位滤波 filtfilt:正向滤波完成后反向再次滤波,抵消 IIR 带来相位偏移,适合离线数据,不可用于实时。
注意:巴特沃斯本身是滤波器设计算法,不是直接滤波函数;需要先算出 a、b 系数,再运行差分方程完成滤波计算。
历史背景
1930 年,Stephen Butterworth 在论文《On the Theory of Filter Amplifiers》首次提出巴特沃斯模拟滤波器。 在模拟电路时代使用电阻电容电感搭建;数字信号处理发展后,通过双线性变换把模拟原型转化为数字滤波器,广泛应用。 对比同期滤波器:切比雪夫 I/II、椭圆滤波器牺牲通带 / 阻带平坦换取更快衰减;贝塞尔滤波器优先保证线性相位。巴特沃斯选择通带最大平坦作为核心设计目标,折中衰减速度与波纹。
核心原理
模拟巴特沃斯幅度平方函数
模拟域幅度平方响应:
- N:滤波器阶数
:模拟角频率
:模拟截止角频率 (-3dB)
极点全部分布在 s 平面左半平面的单位圆上,取左半平面极点构造稳定传递函数。
双线性变换 & 预畸变
模拟 S 域转数字 Z 域,双线性变换公式:
采样周期。 双线性变换会压缩频率轴,必须做预畸变校正截止频率:
把目标数字截止频率映射回模拟域,再做变换,保证最终数字滤波器截止频率准确。
数字 IIR 传递函数
差分方程(滤波运算核心)
时域递归计算公式:
:输入原始信号
:滤波输出信号
:分子系数
:分母系数
实时滤波:只能正向递归,会产生相位滞后; 离线零相位滤波:正向滤波→将输出序列反转→再次滤波→再反转得到结果,相位偏移完全消除。
执行流程
完整巴特沃斯数字滤波完整流程:
- 输入参数:滤波器阶数 N,采样频率
,截止频率
,原始输入信号数组。
- 预畸变计算模拟截止角频率,校正双线性变换频率扭曲。
- 求解模拟巴特沃斯原型极点。
- 通过双线性变换将模拟极点映射为 Z 域极点。
- 计算得到数字滤波器分子系数 b、分母系数 a。
- 系数归一化,保证直流增益为 1。
- 滤波运算:
- 实时模式:正向递归差分方程计算输出;
- 离线模式:执行 filtfilt 双向零相位滤波。
- 返回滤波完成信号。
⚠️注意:阶数不要设置过大,一般工程 2~8 阶;阶数过高系数精度敏感,容易造成滤波器不稳定。
算法性能分析
-
时间复杂度
和 FIR 相比:达到同等阻带衰减,IIR 巴特沃斯需要阶数远小于 FIR,计算开销更低。
- 系数求解:
,N 为滤波器阶数;
- 滤波运算:每一个采样点运算量
;信号长度 M,总复杂度
。
- 系数求解:
-
空间复杂度 :
,存储 a、b 系数与历史输入输出缓存。
-
稳定性
- 只要极点全部落在 Z 平面单位圆内,滤波器稳定;
- 阶数过高、浮点精度不足会造成极点漂移,出现震荡发散。
-
相位特性
- 普通正向巴特沃斯:非线性相位,信号不同频率分量时间延迟不一致,波形会发生相位畸变;实时采集(传感器)场景要重视。
- filtfilt 双向滤波:零相位,但延迟等于全部信号长度,只适合离线。
-
频率特性
- ✅通带:幅度响应最大平坦,无波纹;
- ❌阻带衰减速度不如切比雪夫滤波器;阶数每提升 1 阶,阻带增加 20dB / 十倍频衰减。
C# 完整代码(无任何第三方库)
功能:巴特沃斯低通滤波器;包含:系数计算、正向实时滤波、filtfilt 零相位双向滤波。 仅使用.NET 原生 System,不引用信号处理库。
cs
using System;
using System.Collections.Generic;
namespace ButterworthFilter
{
/// <summary>
/// 巴特沃斯低通IIR滤波器,无第三方库
/// </summary>
public class ButterworthLowpass
{
/// <summary>
/// a系数 分母 a[0]=1
/// </summary>
public double[] A { get; private set; }
/// <summary>
/// b系数 分子
/// </summary>
public double[] B { get; private set; }
private readonly int _order;
private readonly double _fs;
private readonly double _fc;
/// <summary>
/// 构造巴特沃斯低通
/// </summary>
/// <param name="order">阶数,建议2~8</param>
/// <param name="fs">采样频率 Hz</param>
/// <param name="fc">-3dB截止频率 Hz</param>
public ButterworthLowpass(int order, double fs, double fc)
{
if (fc <= 0 || fs <= 0) throw new ArgumentException("频率必须大于0");
if (fc >= fs / 2) throw new ArgumentException("截止频率必须小于奈奎斯特频率 fs/2");
_order = order;
_fs = fs;
_fc = fc;
ComputeCoefficients();
}
/// <summary>
/// 计算巴特沃斯数字滤波器系数:双线性变换+预畸变
/// </summary>
private void ComputeCoefficients()
{
double T = 1.0 / _fs;
// ========== 1.预畸变截止频率 ==========
double wd = 2 * Math.PI * _fc;
double wa = (2.0 / T) * Math.Tan(wd * T / 2.0);
// ========== 2.模拟巴特沃斯极点 ==========
List<Complex> sPoles = new List<Complex>();
for (int k = 0; k < _order; k++)
{
double angle = Math.PI * (_order + 2 * k + 1) / (2 * _order);
double real = -wa * Math.Cos(angle);
double imag = wa * Math.Sin(angle);
sPoles.Add(new Complex(real, imag));
}
// ==========3.双线性变换 s→z ==========
List<Complex> zPoles = new List<Complex>();
foreach (var s in sPoles)
{
// z = (2/T + s) / (2/T - s)
Complex twoOverT = new Complex(2.0 / T, 0);
Complex z = (twoOverT + s) / (twoOverT - s);
zPoles.Add(z);
}
// ==========4.由极点构造分母多项式A ==========
Complex[] aPoly = { new Complex(1, 0) };
foreach (var p in zPoles)
{
aPoly = PolyMultiply(aPoly, new[] { new Complex(1, 0), -p });
}
// ==========5.低通分子多项式:全部零点位于 z=-1 ==========
Complex[] bPoly = { new Complex(1, 0) };
for (int i = 0; i < _order; i++)
{
bPoly = PolyMultiply(bPoly, new[] { new Complex(1, 0), new Complex(1, 0) });
}
// ==========转为double数组,归一化增益==========
A = Array.ConvertAll(aPoly, c => c.Real);
B = Array.ConvertAll(bPoly, c => c.Real);
// 直流增益归一化 z=1代入 H(z)
double gainB = 0;
double gainA = 0;
foreach (var v in B) gainB += v;
foreach (var v in A) gainA += v;
double gain = gainB / gainA;
for (int i = 0; i < B.Length; i++) B[i] /= gain;
}
/// <summary>
/// 多项式复数乘法
/// </summary>
private Complex[] PolyMultiply(Complex[] p1, Complex[] p2)
{
Complex[] res = new Complex[p1.Length + p2.Length - 1];
for (int i = 0; i < res.Length; i++) res[i] = new Complex(0, 0);
for (int i = 0; i < p1.Length; i++)
for (int j = 0; j < p2.Length; j++)
res[i + j] += p1[i] * p2[j];
return res;
}
/// <summary>
/// 正向滤波(实时可用,带相位延迟)
/// </summary>
/// <param name="input">输入信号数组</param>
/// <returns>滤波输出</returns>
public double[] FilterForward(double[] input)
{
int n = input.Length;
double[] output = new double[n];
int lenA = A.Length;
int lenB = B.Length;
for (int i = 0; i < n; i++)
{
double sumB = 0;
for (int k = 0; k < lenB; k++)
{
int idx = i - k;
if (idx >= 0) sumB += B[k] * input[idx];
}
double sumA = 0;
for (int k = 1; k < lenA; k++)
{
int idx = i - k;
if (idx >= 0) sumA += A[k] * output[idx];
}
output[i] = sumB - sumA;
}
return output;
}
/// <summary>
/// filtfilt 零相位双向滤波,仅适合离线数据
/// 正向滤波→反转→滤波→反转
/// </summary>
public double[] FilterFiltFilt(double[] input)
{
double[] y1 = FilterForward(input);
Array.Reverse(y1);
double[] y2 = FilterForward(y1);
Array.Reverse(y2);
return y2;
}
#region 内部复数结构体,不依赖System.Numerics
private struct Complex
{
public double Real { get; }
public double Imag { get; }
public Complex(double real, double imag)
{
Real = real;
Imag = imag;
}
public static Complex operator +(Complex a, Complex b)
{
return new Complex(a.Real + b.Real, a.Imag + b.Imag);
}
public static Complex operator -(Complex a, Complex b)
{
return new Complex(a.Real - b.Real, a.Imag - b.Imag);
}
public static Complex operator *(Complex a, Complex b)
{
double r = a.Real * b.Real - a.Imag * b.Imag;
double i = a.Real * b.Imag + a.Imag * b.Real;
return new Complex(r, i);
}
public static Complex operator /(Complex a, Complex b)
{
double den = b.Real * b.Real + b.Imag * b.Imag;
double r = (a.Real * b.Real + a.Imag * b.Imag) / den;
double i = (a.Imag * b.Real - a.Real * b.Imag) / den;
return new Complex(r, i);
}
}
#endregion
}
// 测试示例
class Program
{
static void Main(string[] args)
{
int fs = 1000; //采样频率1000Hz
double fc = 10; //截止频率10Hz
int order = 4; //4阶巴特沃斯低通
ButterworthLowpass filter = new ButterworthLowpass(order, fs, fc);
//构造测试信号:5Hz+50Hz高频噪声
List<double> signal = new List<double>();
for (int t = 0; t < 2000; t++)
{
double s1 = Math.Sin(2 * Math.PI * 5 * t / fs);
double s2 = 0.4 * Math.Sin(2 * Math.PI * 50 * t / fs);
signal.Add(s1 + s2);
}
double[] resForward = filter.FilterForward(signal.ToArray());
double[] resFiltFilt = filter.FilterFiltFilt(signal.ToArray());
Console.WriteLine("A系数:" + string.Join(",", filter.A));
Console.WriteLine("B系数:" + string.Join(",", filter.B));
Console.WriteLine("完成滤波");
}
}
}
代码说明
- 内置自定义
Complex复数结构体,不引入 System.Numerics,完全原生; - 实现双线性变换 + 预畸变,正确生成巴特沃斯低通 a、b 系数;
FilterForward:正向递归滤波,适合嵌入式、实时传感器数据流;FilterFiltFilt:零相位双向滤波,离线数据分析,消除相位偏移;- Main 函数提供测试案例:混合 5Hz 有效信号 + 50Hz 噪声演示滤波效果。
扩展提示:高通、带通、带阻可以在模拟原型完成频率变换后再执行双线性变换。
优缺点
优点
- ✅通带幅度最大平坦,通带无波纹,这是巴特沃斯最核心优势;
- ✅同等衰减条件下,对比 FIR 滤波器阶数低,计算量小;
- ✅设计直观:仅需要阶数、截止频率两个核心参数;
- ✅模拟电路历史积累成熟,数字实现工程普及度高。
缺点
- ❌IIR 固有非线性相位,实时滤波会造成波形相位畸变;
- ❌阻带衰减速率一般,同阶数衰减弱于切比雪夫滤波器;
- ❌阶数过高,浮点精度问题会带来滤波器不稳定风险;
- ❌filtfilt 零相位滤波不能用于实时流数据,需要完整全部输入序列;
- ❌瞬态响应差,信号起始位置会有暂态震荡。
适用场景
✅适合场景
- 传感器离线数据处理:加速度、压力、温度等信号降噪,使用 filtfilt 零相位;
- 对通带波纹要求严格,不希望通带内信号幅度起伏;
- 资源受限嵌入式设备,希望低计算开销实现滤波,能够接受相位滞后;
- 音频信号预处理。
❌不适合场景
- 需要严格线性相位的实时系统(推荐 FIR 滤波器);
- 需要陡峭阻带衰减、资源充足场景(优先切比雪夫);
- 高阶实时闭环控制,相位偏移会影响闭环稳定性。
总结
巴特沃斯滤波属于IIR 数字信号处理算法 ,分为滤波器系数设计算法与差分方程递归滤波运算两部分。核心设计目标是通带幅度最大平坦。工程选型权衡点:通带无波纹换取阻带衰减能力,同时牺牲相位线性度。 实时场景使用正向滤波,接受相位延迟;离线分析优先 filtfilt 双向零相位滤波;阶数工程推荐 2‑8 阶。C# 原生实现无需第三方库,可直接迁移到嵌入式仿真、上位机信号解析项目。