一阶低通滤波器:从连续模型到数字实现的原理与工程实践
1. 从“平滑”说起:为什么我们需要一阶低通滤波?
在信号处理、控制系统、传感器数据采集乃至音频处理等众多领域,我们常常会遇到一个看似简单却至关重要的需求:如何从混杂着噪声的数据中,提取出我们真正关心的、变化相对缓慢的趋势信号?想象一下,你用一个精度一般的温度传感器测量室温,读数可能在24.5°C到25.5°C之间快速跳动,但你知道实际的室温不可能在一秒内变化1度。这些快速的跳动就是高频噪声,而真实的室温是低频的、缓慢变化的信号。你的直觉可能是“取个平均值”,这没错,但平均值是对过去一段时间数据的“一视同仁”,而我们常常希望越新的数据越重要,越老的数据影响力越小。这种能实现“平滑”且“侧重近期”的数学工具,就是一阶低通滤波器。
一阶低通滤波器的核心思想,是建立一个简单的动态系统,其输出会“跟随”输入变化,但不会“立刻跟上”。它像一个有惯性的系统,或者一个反应迟钝的“跟班”。当输入信号快速变化(高频)时,它跟不上,输出变化很小,这部分高频成分就被“滤除”了;当输入信号缓慢变化(低频)时,它能跟得上,输出能较好地复现输入,这部分低频成分就被“通过”了。这个“跟不上”的程度,由一个关键参数决定:截止频率。它定义了滤波器“反应速度”的边界,频率高于此值的信号成分会被显著衰减。
然而,我们生活在一个数字化的世界。传感器采样得到的是离散时间点上的数据,微处理器(MCU)、数字信号处理器(DSP)或计算机程序处理的也是离散的数值序列。我们在教科书或理论推导中看到的滤波器,通常是用连续时间的微分方程或拉普拉斯变换来描述的,比如那个经典的传递函数1/(τs + 1)。但计算机无法直接解微分方程,它只能处理差分方程。因此,我们必须将连续时间的滤波器模型,转化为离散时间的形式,这个过程就是离散化。离散化不是简单的“替换”,它涉及到采样周期、数值稳定性、频率响应畸变等一系列工程实践中的核心问题。一个设计不当的离散化滤波器,可能会引入额外的相位延迟、幅度失真,甚至变得不稳定。
所以,理解一阶低通滤波,绝不仅仅是记住一个公式。它关乎如何在数字系统中,优雅地实现“平滑”与“跟随”的权衡。本文将彻底拆解一阶低通滤波器的原理,并深入探讨几种主流的离散化方法(如前向欧拉、后向欧拉、双线性变换),分析它们各自的特性、适用场景以及在特定频率点(如w处)的幅值响应,最终给出可直接嵌入代码的实用公式和避坑指南。
2. 连续时间域的一阶低通滤波器:原理与模型
在连续时间域,一个一阶低通滤波器可以用一个一阶常系数线性微分方程来描述。这是所有分析的起点。
2.1 微分方程与传递函数
最直观的模型来源于一个简单的RC电路。一个电阻R和一个电容C串联,输入电压V_in(t)加在串联组合上,输出电压V_out(t)从电容两端取出。根据基尔霍夫电压定律和电容的电流-电压关系,我们可以得到:V_in(t) = R * C * dV_out(t)/dt + V_out(t)令时间常数τ = R * C,方程简化为:τ * dV_out(t)/dt + V_out(t) = V_in(t)这就是一阶低通滤波器的时域微分方程。τ的单位是秒,它直接决定了系统的动态特性。τ越大,电容充电放电越慢,系统惯性越大,滤波效果越“强”,输出对输入的响应越迟缓。
为了在频域分析,我们对上述微分方程两边取拉普拉斯变换(假设初始条件为零)。拉普拉斯变换将微分算子d/dt转换为复变量s。于是得到:τ * s * V_out(s) + V_out(s) = V_in(s)整理后,得到传递函数H(s):H(s) = V_out(s) / V_in(s) = 1 / (τs + 1)这就是一阶低通滤波器在s域(连续频域)的标准形式。
2.2 频率响应与截止频率
传递函数H(s)描述了系统对不同频率正弦输入的稳态响应。我们将s替换为jω(其中j是虚数单位,ω是角频率,单位 rad/s),就得到了频率响应函数H(jω):H(jω) = 1 / (jωτ + 1)这是一个复数,其模(绝对值)表示系统对频率为ω的信号的放大(或衰减)倍数,称为幅频特性;其辐角表示输出信号相对于输入信号的相位偏移,称为相频特性。
幅频特性|H(jω)|计算如下:|H(jω)| = 1 / sqrt((ωτ)^2 + 1)从这个公式我们可以清晰地看到滤波器的“低通”特性:
- 当
ω = 0(直流信号)时,|H(j0)| = 1,信号无衰减通过。 - 随着
ω增大,分母增大,|H(jω)|减小,高频成分被衰减。 - 当
ω = 1/τ时,|H(jω)| = 1 / sqrt(2) ≈ 0.707。在工程上,通常将幅度下降到直流增益的1/sqrt(2)(即-3dB点)所对应的频率定义为截止频率ω_c。因此:ω_c = 1 / τ(rad/s) 对应的普通频率f_c为:f_c = ω_c / (2π) = 1 / (2πτ)(Hz)
所以,时间常数τ直接决定了截止频率:τ越大,ω_c越小,滤波器带宽越窄,允许通过的频率成分越少,平滑效果越强。
相频特性∠H(jω) = -arctan(ωτ)。这表明低通滤波器会引入负的相位滞后(输出相位落后于输入),且频率越高,滞后越严重,在截止频率处滞后45度。
注意:这个-3dB截止频率的定义是通用的。但在一些对相位有严格要求的场合(如控制系统环路补偿),可能会使用其他定义,如幅值衰减到-1dB或相位滞后达到特定角度的频率。本文后续均采用-3dB定义。
2.3 阶跃响应:理解“惯性”
除了频域,时域的阶跃响应能让我们直观感受滤波器的“惯性”。假设输入V_in(t)是一个在t=0时刻从0跳变到1的阶跃信号。求解微分方程τ * dy/dt + y = 1(其中y=V_out),可得:y(t) = 1 - e^(-t/τ)这是一个指数上升曲线。τ是时间常数,当t = τ时,输出上升到稳态值(1)的1 - e^(-1) ≈ 63.2%。τ越大,上升到63.2%所需时间越长,系统响应越慢。这个特性是我们在离散化时选择采样周期的重要依据。
3. 从连续到离散:离散化的核心方法与推导
现在进入核心环节:如何让计算机实现H(s) = 1/(τs+1)?我们需要将s域的传递函数转化为适用于数字计算的z域传递函数或差分方程。这个过程就是离散化,主要有三种经典方法:前向欧拉、后向欧拉和双线性变换(又称Tustin变换)。每种方法都是对微分算子s的一种近似。
3.1 前向欧拉法
前向欧拉法是最直观的近似。它用前向差分来近似微分:dy/dt ≈ (y[n] - y[n-1]) / T其中,y[n]表示当前时刻(第n个采样点)的输出值,y[n-1]是上一时刻的输出值,T是采样周期。在z域,延迟一个采样周期对应于乘以z^{-1}。因此,(y[n] - y[n-1])/T的z变换是(Y(z) - z^{-1}Y(z))/T = (1 - z^{-1})Y(z)/T。而dy/dt的拉普拉斯变换是sY(s)。所以,前向欧拉法建立了s与z的近似关系:s ≈ (1 - z^{-1}) / T将这个替换关系代入连续传递函数H(s) = 1/(τs+1):H(z) = 1 / ( τ * ((1 - z^{-1})/T) + 1 ) = 1 / ( (τ/T)(1 - z^{-1}) + 1 )令a = τ / T,则:H(z) = 1 / ( a*(1 - z^{-1}) + 1 ) = 1 / ( a + 1 - a*z^{-1} )为了得到差分方程,我们写回时域关系。由H(z) = Y(z)/X(z),有:(a + 1 - a*z^{-1}) Y(z) = X(z)转换为时域差分方程:(a+1)y[n] - a*y[n-1] = x[n]最终得到前向欧拉法的递推公式:y[n] = (x[n] + a*y[n-1]) / (a + 1)其中,a = τ / T,x[n]是当前输入,y[n]是当前输出,y[n-1]是上一次的输出。
特点与问题:
- 优点:公式极其简单,计算量小。
- 缺点:稳定性差。对于这个一阶系统,只有当
a > 0(即τ/T > 0)时才稳定,这通常成立。但对于高阶系统或某些参数,前向欧拉法可能将稳定的连续系统映射为不稳定的离散系统。此外,其频率响应畸变较大。
3.2 后向欧拉法
后向欧拉法采用后向差分来近似微分:dy/dt ≈ (y[n] - y[n-1]) / T注意,这里微分近似用的是当前时刻和上一时刻的差分,但s域近似关系不同。实际上,后向差分对应的s与z关系是:s ≈ (1 - z^{-1}) / (T * z^{-1}) = (z - 1) / (Tz)另一种更常见的推导是从积分角度:y[n] = y[n-1] + T * f(y[n], t[n]),对于我们的方程τ * dy/dt + y = x,整理为dy/dt = (x - y)/τ,用后向欧拉(即用y[n]来近似右边的y):(y[n] - y[n-1]) / T = (x[n] - y[n]) / τ解这个方程更容易。整理上式:y[n] - y[n-1] = (T/τ) * (x[n] - y[n])y[n] + (T/τ)y[n] = y[n-1] + (T/τ)x[n]y[n] (1 + T/τ) = y[n-1] + (T/τ)x[n]令α = T / (τ + T) = T / (T + τ),我们可以得到更简洁的形式。由上式:y[n] = y[n-1] * (τ/(τ+T)) + x[n] * (T/(τ+T))令α = T/(τ+T),则τ/(τ+T) = 1 - α。因此,后向欧拉法的标准递推公式为:y[n] = (1 - α) * y[n-1] + α * x[n]其中,α = T / (T + τ),0 < α <= 1(当T>0, τ>0)。
特点与问题:
- 优点:无条件稳定。无论采样周期
T取多大(理论上),由稳定的连续系统离散化得到的离散系统也是稳定的。这是它最大的优点。 - 缺点:频率响应在高频段有严重畸变。当实际频率接近奈奎斯特频率(
f_s/2)时,后向欧拉法会将其映射到s域一个非常高的频率,导致过度衰减,这种现象称为“频率扭曲”。
3.3 双线性变换法
双线性变换是一种更精确的离散化方法,它通过将s平面的左半平面映射到z平面的单位圆内部来保证稳定性,同时通过预畸变来补偿频率扭曲。
双线性变换的公式是:s ≈ (2/T) * (1 - z^{-1}) / (1 + z^{-1})将这个关系代入H(s) = 1/(τs+1):H(z) = 1 / ( τ * (2/T) * (1 - z^{-1})/(1 + z^{-1}) + 1 )化简过程: 令K = 2τ / T。H(z) = 1 / ( K * (1 - z^{-1})/(1 + z^{-1}) + 1 ) = (1 + z^{-1}) / ( K*(1 - z^{-1}) + (1 + z^{-1}) ) = (1 + z^{-1}) / ( (K+1) + (1-K)z^{-1} )现在,令β = T / (T + 2τ)。我们可以建立联系。注意到K = 2τ/T,所以K+1 = (2τ/T)+1 = (2τ+T)/T,1-K = 1 - 2τ/T = (T-2τ)/T。 那么H(z)可以写为:H(z) = β * (1 + z^{-1}) / (1 - (1 - 2β) z^{-1}), 其中β = T / (T + 2τ)。 更常见的、直接可用的差分方程形式可以通过交叉相乘得到: 由H(z) = Y(z)/X(z) = (1 + z^{-1}) / ( (K+1) + (1-K)z^{-1} ),交叉相乘:[ (K+1) + (1-K)z^{-1} ] Y(z) = (1 + z^{-1}) X(z)转换为时域差分方程:(K+1) y[n] + (1-K) y[n-1] = x[n] + x[n-1]最终得到:y[n] = [ x[n] + x[n-1] - (1-K) y[n-1] ] / (K+1)其中K = 2τ / T。
特点与问题:
- 优点:具有频率预畸变特性,能保持频率响应的形状。它将s域的整个虚轴(
jω轴)映射到z域的单位圆上,因此频率响应匹配较好,尤其在中低频段。并且它也是无条件稳定的。 - 缺点:计算比前两种方法稍复杂,涉及当前输入、上一次输入和上一次输出。存在频率扭曲,但通过预畸变可以校正。对于给定的离散截止频率
ω_{d},需要先通过公式ω_{a} = (2/T) * tan(ω_{d}T/2)计算出一个“预畸变”的连续频率ω_{a},然后用ω_{a}来设计连续滤波器参数τ(τ = 1/ω_{a}),这样离散化后的滤波器在ω_{d}处才会有准确的-3dB衰减。
4. 方法对比与工程选型:何时用哪种?
了解了三种方法后,我们面临一个实际问题:在工程中如何选择?
前向欧拉法:由于其潜在的稳定性问题,在滤波器设计中很少被采用。除非你能严格保证T非常小(远小于系统时间常数τ),且系统简单。一般不推荐。
后向欧拉法:这是最常用、最推荐用于一阶低通滤波的实现方法。原因如下:
- 无条件稳定:这是最重要的工程属性。无论代码运行在1kHz还是100Hz的采样率下,滤波器都不会发散。
- 公式极其简单:
y[n] = (1 - α) * y[n-1] + α * x[n]。只有一个系数α需要计算和存储,一次乘法一次加法,计算效率极高,非常适合资源受限的嵌入式系统。 - 物理意义清晰:
α可以理解为“新采样值的权重”。α越大(T越大或τ越小),滤波器“惯性”越小,跟踪输入越快;α越小,平滑效果越强。 - 参数计算方便:已知期望的截止频率
f_c和采样频率f_s(T = 1/f_s),可以先计算连续时间常数τ = 1/(2πf_c),然后计算α = T / (T + τ)。或者,更直接地,利用α与f_c、f_s的关系:α = 2πf_cT / (2πf_cT + 1)。当2πf_cT << 1(即采样频率远高于截止频率)时,α ≈ 2πf_cT。
双线性变换法:在以下场景考虑使用:
- 对频率响应精度要求高:例如在音频处理、数字均衡器中,需要精确控制特定频率点的增益。
- 滤波器阶数较高:在设计高阶IIR滤波器时,双线性变换是标准方法,因为它能保持稳定性并可通过预畸变校正频响。
- 作为性能基准:当你需要验证后向欧拉法在特定应用中的失真程度时,可以用双线性变换的结果作为参考。
实操心得:对于99%的嵌入式传感器数据平滑(如陀螺仪、加速度计、温度、电流采样),后向欧拉法的简单性、稳定性和足够好的性能使其成为首选。我曾在多个电机控制、无人机飞控项目中用它来滤波电流环反馈和角速度信号,从未出过问题。关键是要根据信号特性和噪声频谱合理选择
α。
4.1 离散化后的频率响应分析
我们更关心离散化后的滤波器在实际数字频率ω_d(ω_d = 2πf / f_s,范围0到π)上的表现。以最常用的后向欧拉法为例,其传递函数为:H(z) = α / (1 - (1-α)z^{-1})将z = e^{jω_d}代入,可以计算其幅频响应|H(e^{jω_d})|。经过推导(过程略),在ω_d较小时,其-3dB截止角频率ω_{c_d}近似满足:tan(ω_{c_d}/2) ≈ (α/(2-α)) * (ω_{c_d}/2)当α很小时,近似有ω_{c_d} ≈ α。更精确的关系是:设计时,若期望的离散截止角频率为ω_{c_d},则所需的α约为α ≈ 2 sin(ω_{c_d}/2) / (cos(ω_{c_d}/2) + sin(ω_{c_d}/2))。但在工程中,更常用的方法是直接用连续频率来算:α = T/(T+τ) = 1/(1 + τ f_s)。
关于“一阶低通滤波在w处幅值”:这是一个很实际的测试点。假设我们想知道离散滤波器在某个特定数字频率ω处的增益。以双线性变换法为例,由于其频率扭曲,在ω_d处的响应对应于连续频率ω_a = (2/T) tan(ω_d/2)处的响应。所以,如果你设计时没有预畸变,那么你在ω_d处测得的幅值,实际上是连续滤波器在ω_a处的幅值1/sqrt(1+(ω_a τ)^2)。这解释了为什么有时离散滤波器的截止频率看起来“偏移”了。而后向欧拉法在高频段的衰减比理论连续滤波器更剧烈。
5. 实战:从理论到代码的完整实现与调试
理论最终要落地为代码。这里以最通用的后向欧拉法为例,展示完整的实现流程和注意事项。
5.1 确定设计指标
假设我们有一个传感器,采样频率f_s = 100 Hz(T = 0.01 s)。信号中有高频噪声,我们期望滤除50Hz以上的噪声成分。因此,设定滤波器的**-3dB截止频率f_c = 5 Hz**。这是一个比较典型的设计,截止频率远低于采样频率的一半(奈奎斯特频率50Hz),以避免混叠,同时也留出了足够的过渡带。
5.2 计算滤波器系数
- 计算连续时间常数
τ:τ = 1 / (2πf_c) = 1 / (2 * 3.1416 * 5) ≈ 0.03183秒。 - 计算权重系数
α:α = T / (T + τ) = 0.01 / (0.01 + 0.03183) ≈ 0.01 / 0.04183 ≈ 0.239。 或者用近似公式α ≈ 2πf_c T = 2*3.1416*5*0.01 = 0.314,这个近似值偏大,因为2πf_cT=0.314并不远小于1。在要求不高的场合可用,但精确设计建议用前一个公式。 - 计算
(1 - α):1 - α ≈ 1 - 0.239 = 0.761。
所以,我们的递推公式为:y[n] = 0.761 * y[n-1] + 0.239 * x[n]
5.3 C语言代码实现
// 一阶低通滤波器结构体 typedef struct { float alpha; // 系数 α float output_prev; // 上一次的输出值 y[n-1] } FirstOrderLPF; // 初始化滤波器 void LPF_Init(FirstOrderLPF *lpf, float cutoff_freq, float sample_freq) { float tau = 1.0f / (2.0f * 3.1415926535f * cutoff_freq); lpf->alpha = 1.0f / (1.0f + tau * sample_freq); // 因为 T = 1/sample_freq // 另一种等价计算:lpf->alpha = (1.0f/sample_freq) / ((1.0f/sample_freq) + tau); lpf->output_prev = 0.0f; // 初始输出通常设为0或第一次的输入值 } // 执行一次滤波计算 float LPF_Update(FirstOrderLPF *lpf, float input) { float output = (1.0f - lpf->alpha) * lpf->output_prev + lpf->alpha * input; lpf->output_prev = output; // 更新状态 return output; } // 使用示例 int main() { FirstOrderLPF my_filter; float sample_freq = 100.0f; // 100 Hz float cutoff_freq = 5.0f; // 5 Hz LPF_Init(&my_filter, cutoff_freq, sample_freq); // 模拟循环采样 while(1) { float raw_sensor_data = Read_Sensor(); // 假设的函数 float filtered_data = LPF_Update(&my_filter, raw_sensor_data); // 使用 filtered_data... Delay(10); // 延迟10ms,维持100Hz采样 } return 0; }5.4 关键实现细节与避坑指南
- 数据类型选择:在嵌入式系统中,根据精度和速度要求选择
float或fixed-point(定点数)。对于α这种介于0和1之间的小数,浮点数处理更方便。若用定点数,需仔细处理量化误差和溢出。 - 初始化:
output_prev的初始值会影响滤波器启动阶段的瞬态响应。通常有两种做法:- 设为0。滤波器需要一段时间(几个时间常数)才能达到稳定跟踪。
- 设为第一次的输入值
x[0]。这样输出从一开始就“跟得上”,但若第一个采样值是噪声尖峰,也会导致初始偏差。可以根据应用场景选择,或让滤波器空跑几个周期直到稳定后再使用输出。
- 系数
α的范围:理论上α ∈ (0, 1]。α=1时,y[n]=x[n],滤波器完全透明(无滤波)。α越接近0,平滑效果越强。切勿让α等于或小于0,否则滤波器会不稳定或行为异常。确保你的cutoff_freq和sample_freq都是正数,且cutoff_freq小于sample_freq/2(奈奎斯特频率)。 - 采样频率与截止频率的关系:这是一个常见的坑。截止频率
f_c必须显著小于采样频率f_s。经验法则是f_c < f_s / 10。如果f_c接近f_s/2,离散化误差会非常大,滤波器特性会严重偏离预期。在上例中,f_s=100Hz,f_c=5Hz,比例是20倍,是合理的。 - 实时性要求:
LPF_Update函数执行时间必须小于采样周期T。在高速采样场合(如f_s=10kHz),需优化计算(查表法计算α,使用更快的乘法指令等)。 - 抗溢出处理:在定点数实现或输入信号幅值很大的情况下,乘法操作可能导致溢出。需要评估中间变量的动态范围,必要时进行缩放。
5.5 性能验证与调试
如何验证你的滤波器工作正常?
- 阶跃响应测试:输入一个从0跳变到常数的信号,观察输出是否按指数曲线平滑上升,时间常数是否约为
τ(达到63.2%的时间)。 - 正弦扫频测试(如果条件允许):输入不同频率的正弦波,测量输出幅值与输入幅值的比值,绘制幅频特性曲线,看-3dB点是否在设计的
f_c附近。 - 观察实际数据:在真实系统中,将原始信号和滤波后信号同时绘制出来。你应该能看到高频毛刺被有效平滑,而真实的趋势变化得以保留。如果发现滤波后信号仍然噪声很大,可能需要降低
f_c;如果发现滤波后信号明显滞后于真实变化,可能需要适当提高f_c。
踩坑实录:我曾在一个电池电压采样的项目中,将
f_c设得过低(0.1Hz),α非常小。在MCU中,由于浮点数精度限制,(1-α)计算出来几乎是1.0,导致滤波器更新极其缓慢,几乎“冻住”了。后来改用双精度浮点数,并重新评估了必要的带宽,问题才解决。教训:在系数α极小时,要特别注意数据类型的精度是否足够。
6. 进阶话题:变参数滤波、非线性与多级串联
基础的一阶低通滤波已经能解决大部分问题。但在更复杂的场景下,我们需要一些变体。
6.1 变截止频率滤波
有时,我们希望滤波器的带宽能动态调整。例如,在运动检测中,静止时希望强滤波(小α)来抑制噪声,运动时希望弱滤波(大α)来快速跟踪。 实现很简单:根据某个条件(如加速度幅值)动态计算并更新α和(1-α)系数。注意,改变系数会改变滤波器的动态特性,可能会引入瞬态扰动。一种平滑的方法是让系数本身也通过一个低通滤波器缓慢变化。
6.2 非线性滤波:限幅与死区
纯粹的一阶低通滤波是线性的。有时我们需要引入非线性来应对特殊噪声。
- 限幅滤波:在更新公式前,先判断本次输入
x[n]与上一次输出y[n-1]的差值是否超过一个阈值delta_max。如果超过,则认为可能是脉冲干扰,不直接使用x[n],而是使用y[n-1] ± delta_max作为有效输入。这能有效抑制偶发的尖峰脉冲。 - 死区滤波:当
|x[n] - y[n-1]|小于一个很小的阈值dead_zone时,认为变化是噪声,不更新滤波器,即y[n] = y[n-1]。这可以消除传感器在零点附近的小幅抖动。
6.3 多级一阶低通滤波串联
将两个或多个一阶低通滤波器串联,可以得到更高阶的低通滤波效果,其滚降斜率更陡峭(每增加一阶,滚降率增加-20dB/decade)。例如,两个相同的、截止频率为f_c的一阶滤波器串联,其传递函数为[1/(τs+1)]^2。在-3dB点,总衰减是-6dB。这种方法的优点是:
- 仍然实现简单,只需重复调用一阶滤波函数。
- 相位滞后会比单级更大,这是代价。
- 离散化时,可以对每一级独立使用后向欧拉法。
实现时需要注意,串联滤波器的等效截止频率会发生变化。如果希望总体的-3dB截止频率是f_c,那么每一级的设计截止频率需要更高。对于两级相同滤波器,每级的截止频率f_c1约为f_c / sqrt(sqrt(2)-1) ≈ f_c / 0.643。更通用的方法是先确定目标的高阶传递函数,然后用双线性变换等方法来离散化,而不是简单串联离散一阶节。
7. 在具体场景中的应用实例
让我们看两个具体的例子,看看一阶低通滤波如何解决实际问题。
7.1 实例一:单片机读取模拟温度传感器
场景:STM32通过ADC读取NTC热敏电阻的电压来测算温度。ADC读数存在±3LSB的随机噪声,导致直接转换的温度值在±0.2°C范围内波动。目标:平滑温度读数,使得显示的温度值稳定,同时能跟上真实的环境温度变化(通常变化很慢)。设计:
- 采样频率
f_s:ADC设置为每秒采样10次(10Hz),T=0.1s。 - 截止频率
f_c:环境温度变化通常不超过0.1°C/分钟,即约0.0017 Hz。但为了兼顾一定的响应速度,我们可以设f_c = 0.05 Hz(时间常数约3秒)。这能滤除远高于0.05Hz的ADC噪声。 - 计算系数:
τ = 1/(2π*0.05) ≈ 3.183 sα = T / (T+τ) = 0.1 / (0.1+3.183) ≈ 0.03051-α ≈ 0.9695实现:在ADC中断服务程序或主循环中,调用filtered_temp = 0.9695 * filtered_temp_prev + 0.0305 * raw_temp_adc。效果:温度读数的跳动被有效抑制,显示值平滑。当环境温度真实变化时,滤波后的值会在几十秒内逐渐跟踪到新值,这对于温度监控来说是完全可以接受的。
7.2 实例二:平衡小车的陀螺仪角速度滤波
场景:MPU6050陀螺仪输出角速度,用于计算小车倾角。陀螺仪数据存在高频噪声,积分后会导致角度估计漂移。目标:滤除陀螺仪信号中的高频噪声,但尽量保留有用的低频信号(因为小车控制需要快速的角速度反馈)。设计:
- 采样频率
f_s:IMU数据读取和控制循环频率为500Hz,T=0.002s。 - 截止频率
f_c:需要分析。小车自身的机械振动噪声可能高达几十Hz,需要滤除。而控制环路带宽可能设计在20-30Hz。因此,将陀螺仪低通滤波的截止频率设为f_c = 30 Hz,可以抑制高频振动噪声,同时保留控制所需的有效带宽。 - 计算系数:
τ = 1/(2π*30) ≈ 0.005305 sα = T / (T+τ) = 0.002 / (0.002+0.005305) ≈ 0.002 / 0.007305 ≈ 0.2741-α ≈ 0.726实现:在500Hz的控制中断中,先读取原始陀螺仪数据gyro_raw,然后gyro_filtered = 0.726 * gyro_filtered_prev + 0.274 * gyro_raw,再用gyro_filtered进行角度积分和控制计算。效果:原始陀螺仪数据的毛刺被平滑,积分得到的角度曲线更干净,减少了因噪声积分导致的随机游走漂移,提升了控制稳定性。
一阶低通滤波及其离散化是信号处理中最基础、最实用的工具之一。它的魅力在于用最简单的数学形式,解决了工程中无处不在的噪声问题。理解其连续域的原理是根基,掌握后向欧拉离散化方法并将其转化为两三行代码是核心技能。在实际应用中,关键在于根据信号特性和系统需求,合理地选择截止频率与采样频率的比例,并注意数值实现的细节。希望这篇长文能帮你不仅记住公式y[n] = (1-α)y[n-1] + αx[n],更能透彻理解它背后的每一个为什么,从而在下次面对嘈杂的数据时,能够自信地应用这个强大的工具。
