今日学习一下 一阶惯性数字低通滤波 一阶惯性数字高通滤波

目录
[为什么叫 "一阶":](#为什么叫 “一阶”:)
为什么叫 "一阶":
因为公式里只用到上一时刻的值,没有更复杂的历史数据。
低通:只依赖 上一次输出
高通:只依赖 上一次输出 + 上一次输入
没有二阶、三阶那种多阶记忆,所以叫 一阶。
适用场景与优势:
一阶滤波适用场景:
一阶数字滤波适用于温度、湿度、压力、直流电压、液位 等变化缓慢、易受高频噪声干扰的物理量采集场景。低通滤波可有效去除采样噪声,使数据平滑稳定;高通滤波可去除信号基线漂移,提取动态变化量。
低通 = 显示当前值(平滑后)
高通 = 只显示变化幅度(变了多少)
优势:算法简单,计算量小,适合单片机等嵌入式平台实时运行。
稳定性高,不易受数据异常影响(除初始值外)。
对于慢变物理量,一阶滤波即可满足降噪与平滑需求。
实时性好,无明显信号延迟。
初值毛刺的影响与解决:
如果第一个值就是毛刺(极大 / 极小)
低通是:起点错了 → 慢慢修正 前面一大段数据全废
那么低通滤波会从这个错误值开始,慢慢往正确值靠近过程会很慢、很歪,
前面一大段数 据全废。
高通是:起点错了 → 整条路都歪了! 波形基线整体偏移 整条波形报废
高通输出会整体往上飘 / 往下沉,再也回不到 0 基线!
高通滤波会认为:"整个信号的基准就是 100,不是 0"
于是它把所有数据都减去 100最终整条波形整体下沉 / 偏移 基线永远歪了!
解决办法:方法 1:跳过前 N 个数据(最简单,实验最常用)
方法 2:初始值不用第一个数据,用手动设定值
方法 3:先采样多次求平均,再开始滤波(最稳)用平均值当起点,毛刺就被平均掉了。
测试代码贴出:
C语言:
cpp#include <stdio.h> // 滤波参数(alpha 越小,滤波越强) #define ALPHA 0.05f /* 1. 一阶低通滤波(去噪、平滑) 输入:当前原始数据,上一次滤波结果 输出:本次滤波后数据 新值 = 一小部分当前值 + 一大部分上一次的值 新值 = 0.05 * 当前采样 + 0.95 * 上一次结果 只相信当前数据 5%,95% 相信过去的稳定值 低通滤波的目的:去掉噪声,保留趋势 噪声 = 快速跳变(要去掉) 真实信号 = 缓慢变化(要保留) 低通滤波确实会改变数据 作用就是抑制突变、减小剧烈变化 让数据从 "乱跳" 变成 "平稳顺滑" */ float low_pass_filter(float current_data, float last_filtered) { float filtered; // 公式:本次输出 = alpha * 当前值 + (1-alpha) * 上一次输出 filtered = ALPHA * current_data + (1 - ALPHA) * last_filtered; return filtered; } // ============================== // 2. 一阶高通滤波(去漂移、提变化) // 输入:当前原始数据,上一次输入,上一次输出 // 输出:本次滤波后数据 // ============================== float high_pass_filter(float current_data, float last_data, float last_filtered) { float filtered; // 公式:本次输出 = (1-alpha) * (上一次输出 + 当前输入 - 上一次输入) filtered = (1 - ALPHA) * (last_filtered + current_data - last_data); return filtered; } // 测试主函数 int main() { // 模拟一组带漂移+噪声的原始数据(模拟传感器信号) float raw_data[] = {10.2, 10.3, 10.8, 10.1, 10.5, 11.2, 11.1, 11.6, 11.0, 11.3}; int data_len = sizeof(raw_data) / sizeof(raw_data[0]); // 滤波变量初始化 float last_low = raw_data[0]; // 低通上一帧结果 float last_high = 0; // 高通上一帧结果 float last_in = raw_data[0]; // 高通上一帧输入 printf("序号\t原始数据\t低通滤波\t高通滤波\n"); printf("---------------------------------------------\n"); for (int i = 0; i < data_len; i++) { // 低通滤波 float out_low = low_pass_filter(raw_data[i], last_low); last_low = out_low; // 高通滤波 float out_high = high_pass_filter(raw_data[i], last_in, last_high); last_in = raw_data[i]; last_high = out_high; // 打印结果 printf("%d\t%.2f\t\t%.2f\t\t%.2f\n", i, raw_data[i], out_low, out_high); } return 0; }
C运行结果:
数据绘图展示(Python):
先装库:
cpppip install matplotlib再输代码运行:
pythonimport matplotlib.pyplot as plt # 修复中文显示问题 plt.rcParams["font.family"] = ["SimHei", "Microsoft YaHei", "Arial Unicode MS"] plt.rcParams["axes.unicode_minus"] = False # 修复负号显示 # C程序原始数据 & 对应滤波结果 x = [0,1,2,3,4,5,6,7,8,9] raw = [10.2, 10.3, 10.8, 10.1, 10.5, 11.2, 11.1, 11.6, 11.0, 11.3] low = [10.20, 10.21, 10.24, 10.23, 10.25, 10.30, 10.34, 10.40, 10.43, 10.47] high = [0.00, 0.10, 0.57, -0.14, 0.27, 0.94, 0.85, 1.31, 0.70, 0.97] plt.figure(figsize=(11,7)) # 1.原始信号 plt.subplot(3,1,1) plt.plot(x, raw, color="#666666", marker="o", linewidth=2, label="原始传感器数据") plt.title("原始信号(含波动+缓慢漂移)", fontsize=12) plt.grid(True, alpha=0.3) plt.legend() # 2.低通滤波 plt.subplot(3,1,2) plt.plot(x, low, color="#0066ff", marker="o", linewidth=2, label="一阶低通滤波(平滑去噪)") plt.title("低通滤波结果:抑制毛刺、保留缓慢趋势", fontsize=12) plt.grid(True, alpha=0.3) plt.legend() # 3.高通滤波 plt.subplot(3,1,3) plt.plot(x, high, color="#ff2200", marker="o", linewidth=2, label="一阶高通滤波(提取变化量)") plt.axhline(y=0, color='black', linestyle='--', alpha=0.5) plt.title("高通滤波结果:去除基线、只保留信号变化幅度", fontsize=12) plt.grid(True, alpha=0.3) plt.legend() plt.tight_layout() plt.show()

