当前位置: 首页 > news >正文

一阶低通滤波:从原理到实践,平滑数据的艺术

在信号处理、嵌入式系统甚至是数据处理中,我们常常会遇到一些包含“毛刺”或高频噪声的数据。直接使用这些数据可能会导致系统误动作、控制震荡或者绘图难看。这时,一阶低通滤波器(First-Order Low-Pass Filter, 1st-order LPF)就派上了用场。它犹如一个“数据平滑器”,允许低频信号通过,同时抑制高频干扰。今天,我们就来彻底搞懂它。

一、原理:它是如何“平滑”数据的?

想象一个场景:用一个笨重的水泥桶通过一个非常细的管子给另一个容器加水。即使你突然改变水泥桶的倾斜角度(输入信号突变),细管子也只能让水流缓慢地变化(输出信号缓慢跟随)。这个“细管子”就是低通滤波效应的来源。

1. 模拟世界的原理:
在模拟电路中,一个简单的RC电路(一个电阻 + 一个电容)就构成了一阶低通滤波器。

  • 电阻 R:阻碍电流的变化,相当于“不情愿”因子。
  • 电容 C:通过充放电来平滑电压的变化,相当于“惯性”因子。

这个电路有一个关键参数:截止频率 (Fc)。计算公式为:
Fc = 1 / (2π * R * C)
频率高于 Fc 的信号会被显著衰减,而低于 Fc 的信号则能较好地通过。

它的行为可以用一个一阶微分方程来描述,但我们更关心如何在数字世界中使用它。

二、公式:从连续到离散

我们要在单片机、Python、C++等程序中实现滤波,就必须将连续的模拟公式离散化

1. 微分方程到差分方程

模拟一阶低通滤波器的行为可以用以下微分方程描述:
τ * (dy(t)/dt) + y(t) = x(t)
其中,τ = R*C 是时间常数(τ = 1 / (2π * Fc)),x(t) 是输入,y(t) 是输出。

我们对它进行离散化处理,用差分近似微分:
dy(t)/dt ≈ (y[n] - y[n-1]) / ΔT
其中 ΔT 是采样周期(两次采样之间的时间间隔)。代入上面的方程:
τ * (y[n] - y[n-1])/ΔT + y[n] = x[n]

整理后,我们得到离散形式的一阶低通滤波公式:

2. 核心滤波公式

y[n] = α * x[n] + (1 - α) * y[n-1]

这就是我们编程实现的核心公式!

其中:

  • y[n]本次滤波后的输出值
  • y[n-1]上一次滤波后的输出值
  • x[n]本次采样到的输入值
  • α滤波系数,它是一个介于 0 到 1 之间的常数,是决定滤波平滑程度的关键。

3. 滤波系数 α 与截止频率 Fc 的关系

α 并不是凭空设定的,它与模拟世界中的截止频率 Fc 和采样周期 ΔT 密切相关:
α = ΔT / (τ + ΔT) = ΔT / (1/(2π * Fc) + ΔT)

更常用的简化形式(当 ΔT 远小于 τ 时):
α ≈ 2π * Fc * ΔT

如何理解 α?

  • α → 1(例如 α=0.9):(1-α) 很小,y[n] 几乎等于 x[n]。滤波器“信任”新数据,滞后小,但平滑效果差。
  • α → 0(例如 α=0.1):(1-α) 很大,y[n] 很大程度上是旧的 y[n-1] 的自我重复。滤波器“信任”历史数据,平滑效果好,但滞后非常严重。

编程时,通常直接根据想要的平滑效果来经验性地设置 α(如 0.1~0.3),或者通过已知的 FcΔT 计算出来。

三、程序应用与实现

这个公式的优点是极其高效,只涉及一次乘法和一次加法运算,非常适合在资源受限的微控制器(如Arduino, STM32)上运行。

程序步骤:

  1. 定义并初始化滤波系数 alpha 和上一次的输出值 lpf_prev_value
  2. 在定时采样中断或循环中,读取新的采样值 adc_value
  3. 应用公式:lpf_output = alpha * adc_value + (1 - alpha) * lpf_prev_value;
  4. 更新 lpf_prev_value = lpf_output;,为下一次计算做准备。
  5. 使用平滑后的 lpf_output 进行后续控制或显示。

C 语言实现(适用于单片机/嵌入式)
// First order low pass filter implementation in C// 定义滤波器结构体,方便管理多个滤波器
typedef struct {float alpha;      // 滤波系数float prev_value; // 上一次的输出值
} FirstOrderLPF;// 初始化滤波器
// - alpha: 滤波系数
// - init_value: 滤波器的初始输出值(通常设为第一次的采样值)
FirstOrderLPF lpf_init(float alpha, float init_value) {FirstOrderLPF filter;filter.alpha = alpha;filter.prev_value = init_value;return filter;
}// 执行一步滤波计算
// - filter: 指向滤波器对象的指针
// - new_value: 新的采样值
float lpf_update(FirstOrderLPF* filter, float new_value) {// 应用公式: y[n] = α * x[n] + (1 - α) * y[n-1]float output = filter->alpha * new_value + (1.0f - filter->alpha) * filter->prev_value;// 更新上一次的输出值为本次结果filter->prev_value = output;return output;
}/****************** 使用示例 ******************/
#include <stdio.h>int main() {// 假设采样周期 ΔT = 0.01s (100Hz), 期望截止频率 Fc = 1Hz// α ≈ 2π * Fc * ΔT = 2*3.14*1*0.01 ≈ 0.0628float alpha = 0.0628f;// 初始化滤波器,假设初始采样值为 0.0FirstOrderLPF my_filter = lpf_init(alpha, 0.0f);// 模拟一些含噪声的输入数据(例如:正弦波 + 随机噪声)float input_samples[] = {0.1, 0.5, 0.8, 1.2, 0.9, 0.7, 0.3, ...};int num_samples = sizeof(input_samples) / sizeof(input_samples[0]);printf("Raw Data, Filtered Data\n");for (int i = 0; i < num_samples; i++) {float raw_data = input_samples[i];float filtered_data = lpf_update(&my_filter, raw_data);printf("%.3f, %.3f\n", raw_data, filtered_data);}return 0;
}
Python 实现(适用于数据分析、仿真)
# First order low pass filter implementation in Python
import numpy as np
import matplotlib.pyplot as pltdef first_order_lpf(new_value, prev_value, alpha):"""一阶低通滤波函数:param new_value: 本次采样值:param prev_value: 上一次的滤波输出值:param alpha: 滤波系数:return: 本次滤波输出值"""return alpha * new_value + (1 - alpha) * prev_value# 生成示例数据:一个干净的正弦波 + 高频噪声
sample_count = 500
t = np.linspace(0, 5, sample_count)
clean_signal = np.sin(2 * np.pi * 1 * t)  # 1Hz 正弦波
noise = 0.5 * np.random.normal(size=sample_count) # 随机噪声
raw_signal = clean_signal + noise# 滤波参数设置
alpha = 0.1  # 滤波系数,越小越平滑,滞后也越大# 初始化
filtered_signal = np.zeros_like(raw_signal)
filtered_signal[0] = raw_signal[0]  # 用第一个采样值初始化# 执行滤波
for i in range(1, sample_count):filtered_signal[i] = first_order_lpf(raw_signal[i], filtered_signal[i-1], alpha)# 绘图对比
plt.figure(figsize=(12, 6))
plt.plot(t, raw_signal, label='Raw Data (Noisy)', alpha=0.7)
plt.plot(t, clean_signal, label='Ground Truth (Clean Sin)')
plt.plot(t, filtered_signal, label=f'Filtered Data (α={alpha})', linewidth=2)
plt.legend()
plt.xlabel('Time [s]')
plt.ylabel('Amplitude')
plt.title('First Order Low Pass Filter Demo')
plt.grid(True)
plt.show()
四、应用场景与注意事项

典型应用场景:

  1. 传感器数据平滑:ADC读取的电压、陀螺仪/加速度计数据、温度传感器数据等。
  2. 按键消抖:虽然硬件消抖更常见,但软件滤波可以进一步确保稳定性。
  3. 控制系统:对反馈信号进行滤波,防止控制指令过于激进和高频震荡。
  4. 信号处理:作为更复杂滤波器的基础单元。

注意事项:

  1. 相位滞后:这是最大的缺点。滤波后的信号在时间上会滞后于原始信号,α 越小,滞后越严重。在闭环控制系统中,这可能影响稳定性,需要谨慎设计。
  2. 初始值:初始值 y[0] 的设置会影响滤波器开始一段时间的输出。通常设置为第一次的采样值。
  3. 选择 α:需要在平滑度响应速度之间做权衡。通过实际效果测试来选择最适合的 α 值。
http://www.xdnf.cn/news/1482913.html

相关文章:

  • 备份压缩与存储优化:智能数据管理全攻略
  • 读写锁 shared_mutex 共享互斥量介绍
  • Dart HashMap:不保证顺序的 Map 实现
  • (二).net面试(static)
  • MySQL--索引和事务
  • simd学习
  • esbuild入门
  • Cursor安装使用 与 Cursor网页端登录成功,客户端怎么也登陆不上
  • 解析噬菌体实验核心:从材料选择到功能验证的标准化操作框架
  • 数据结构——队列(Java)
  • 基于STM32单片机的酒驾检测设计
  • OpenAvatarChat项目在Windows本地运行指南
  • 【基础-单选】关于自定义组件的生命周期下列说法错误的是
  • 四款主流深度相机在Python/C#开发中的典型案例及技术实现方案
  • vant组件
  • 昇腾310i Pro固件说明
  • Vue3中SCSS的使用指南
  • 数据结构与算法1 第一章 绪论
  • AI工具深度测评与选型指南 - AI工具测评框架及方法论
  • Gitea:轻量级的自托管Git服务
  • 【左程云算法06】链表入门练习合集
  • GDAL 读取影像元数据
  • SQL-窗口函数
  • 单词分析与助记之数据建表(以production为例)
  • 鸡兔同笼问题求解
  • 手撕C++ list容器:从节点到完整双向链表实现
  • Ubuntu 22.04.1上安装MySQL 8.0及设置root密码
  • 贪心算法应用:柔性制造系统(FMS)刀具分配问题详解
  • 深度拆解OpenHarmony NFC服务:从开关到卡模拟掌握近场通信技术
  • 雷卯针对米尔MYC-YF13X开发板防雷防静电方案