单片机开发中常用的7种滤波算法
文章出处:未知 人气:发表时间:2025-07-09 17:58
在每一个嵌入式项目中,工程师都像一位在嘈杂环境中努力捕捉清晰声音的调音师。来自传感器的原始数据,就如同混杂着环境噪声
的初始音源,而滤波算法,正是我们手中那款功能各异的“调音台”。我们的挑战在于,这个“调音台”——微控制器(MCU)——性能并非无
限,它的计算速度和内存空间都极其宝贵,并且整个系统还要求我们做出近乎实时的响应。是在追求极致平滑的信号时耗尽MCU的算力,
还是选择一个轻量级方案以保证系统的流畅运行?这正是一门关于“权衡与取舍”的艺术。为了帮助您在这门艺术中游刃有余,我们精选了
7种嵌入式开发中最常用、最高效的滤波算法。接下来,让我们一同探索这些工具的特性,学习如何为您的项目搭配出最优的“滤波组合拳”。
1.限幅滤波法(Clipping Filter)
原理:设定一个允许的最大偏差阈值。当采集到新值时,将其与上一次的有效值比较,如果二者差值的绝对值超过该阈值,就认为新值
是无效的“野点”,并用上一次的值来代替它。
优点:实现非常简单,计算开销极小。能有效消除偶然出现的、幅度很大的脉冲干扰。
缺点:对于连续的、小幅度的噪声无能为力。如果信号本身变化就很快,可能会将正常的信号变化当作干扰滤除。
适用场景:测量值基本稳定,但偶尔会受到强干扰导致数据跳变。如:ADC采样、数字量输入检测。
#include"filter.h"
#define DEVIATION 10
float limit_filter(float new_value)
{
static int num=0;
static float value=0;//需要赋一个初值
num++;
if(num==1)
value=new_value;
else
{
if((new_value-value>DEVIATION)||(value-new_value>DEVIATION))
return value;
}
return new_value;
}
2.中位值滤波法(Median Filter)
原理:开辟一个N个元素的缓冲区,连续采集N个样本放入其中(N通常取奇数,如3,5,7)。将这N个样本进行排序,取最中间的那个值
作为本次滤波的输出。
优点:对椒盐噪声(随机出现的尖峰脉冲)有极佳的抑制效果。相比均值滤波,它能更好地保留信号的边缘细节,不易模糊。
缺点:需要一个缓冲区来存储N个样本,占用RAM。排序过程消耗CPU资源,在N较大时,计算量会明显增加。
适用场景:信号中存在不规则的尖峰干扰,且需要保留信号的跳变特性。如:有开关噪声干扰的传感器、图像处理领域。
#include"filter.h"
#define MIDDLE_FILTER_N 11
float middle_filter(float new_value)
{
static float value_buf[MIDDLE_FILTER_N];
float temp;
uint8_t count,i;
for(count=0;count<MIDDLE_FILTER_N-1;count++)
{
value_buf[count]=value_buf[count+1];
}
value_buf[MIDDLE_FILTER_N-1]=new_value;
for(i=MIDDLE_FILTER_N;i>0;i--)
{
#if 0
if(value_buf<i><value_buf[i-1])
{
temp=value_buf<i>;
value_buf<i>=value_buf[i-1];
value_buf[i-1]=temp;
}
#endif
if(value_buf<i>>0)
{
if(value_buf<i><value_buf[i-1])
{
temp=value_buf<i>;
value_buf<i>=value_buf[i-1];
value_buf[i-1]=temp;
}
}
else if(value_buf<i><0)
{
if(value_buf<i>>value_buf[i-1])
{
temp=value_buf<i>;
value_buf<i>=value_buf[i-1];
value_buf[i-1]=temp;
}
}
}
return value_buf[(MIDDLE_FILTER_N-1)/2];
}
3.算术平均滤波法(Arithmetic Mean Filter)
原理:连续采集N个样本,将这N个样本值求和,再除以N,得到的结果即为滤波输出。为了提高实时性和效率,通常使用“滑动平均”
(Moving Average)的方式实现。
优点:对周期性、符合高斯分布的随机噪声有很好的平滑效果。算法简单,N越大,信号越平滑。
缺点:对信号变化的响应迟钝,有明显的滞后。对偶然的脉冲干扰抑制效果差,一个坏点会拉偏整个平均值。
适用场景:信号变化缓慢、实时性要求不高的场合。如:测量温度、湿度、电压等慢变量。
#include"filter.h"
#define AVERAGE_N 12
float average_filter(float new_value)
{
static float average_value_buf[AVERAGE_N];
static float average_sum=0;
uint8_t count;
average_sum-=average_value_buf[0];
for(count=0;count<AVERAGE_N-1;count++)
{
average_value_buf[count]=average_value_buf[count+1];
}
average_value_buf[AVERAGE_N-1]=new_value;
average_sum+=average_value_buf[11];
return(average_sum/(AVERAGE_N*1.0));
}
4.消抖滤波法(Debounce Filter)
原理:此算法专门用于处理机械开关(如按键)的抖动。它不是平滑模拟信号,而是确认一个数字状态的改变。方法是检测到输入状态
变化后,等待一个短暂的延时(如20ms),再次确认输入状态是否与之前一致。如果一致,才认为状态真正发生了改变。
优点:能可靠地消除机械触点闭合与断开瞬间的电平抖动。是处理按键、开关等数字输入必不可少的环节。
缺点:会带来一个固定的响应延迟。不适用于模拟量的滤波。
适用场景:所有机械按键、开关、继电器等数字量输入信号的检测。
#include"filter.h"
#define SHAKE_N 12
float shake_filter(float new_value,float now_value)
{
static uint8_t count=0;
if(now_value!=new_value)
{
count++;
if(count>=SHAKE_N)
{
count=0;
return new_value;
}
}
return now_value;
}
5.一阶滞后滤波法(First-Order Lag Filter)
原理:也常被称为一阶低通滤波或RC滤波。它模拟了硬件RC电路的滤波效果。其核心是一个递推公式:本次输出=A*本次采样+(1-A)*
上次输出。系数A(0<A<1)决定了滤波的强度,A越小,滤波效果越平滑,但响应越慢。
优点:计算量极小,资源消耗低,只需存储上一次的输出值实时性好,平滑度可以通过调整系数A来灵活控制。
缺点:存在相位滞后。对脉冲干扰抑制能力一般。
适用场景:通用性极强,是MCU中最常用的滤波算法之一,适用于绝大多数需要平滑处理且对实时性有要求的模拟量。
#include"filter.h"
#define FIRST_LAG_PROPORTION 0.4
float first_order_lag_filter(float new_value)
{
static float first_order_value,first_order_last_value;
first_order_value=first_order_last_value;
first_order_last_value=new_value;
return(1-FIRST_LAG_PROPORTION)*first_order_value+
FIRST_LAG_PROPORTION*new_value;
}
5.加权递推平均滤波法(Weighted Recursive Average Filter)
-------------
原理:这是一阶滞后滤波法的一种延伸和别称。它强调了“递推”(Recursive,本次输出依赖于上次输出)和“加权”
(Weighted,对当前采样值和历史滤波结果赋予不同权重)这两个核心思想。一阶滞后滤波法是其最经典、最简单的实现形式。
优点:在平滑度和响应速度之间取得了很好的平衡。资源消耗小,实现高效。
缺点:相比简单的算术平均,理解上稍复杂一点。
适用场景:与一阶滞后滤波法完全相同,适用于需要平衡平滑度和灵敏度的各种场合。
#include"filter.h"
#define WEIGHT_AVERAGE_N 12
uint8_t coe[WEIGHT_AVERAGE_N]={1,2,3,4,5,6,7,8,9,10,11,12};
uint8_t sum_coe=1+2+3+4+5+6+7+8+9+10+11+12;
float weighted_filter(float new_value)
{
static float weight_average_buf[WEIGHT_AVERAGE_N];
uint8_t count;
float sum=0;
for(count=0;count<AVERAGE_N-1;count++)
{
weight_average_buf[count]=weight_average_buf[count+1];
}
weight_average_buf[AVERAGE_N-1]=new_value;
for(count=0;count<WEIGHT_AVERAGE_N;count++)
sum+=weight_average_buf[count]*coe[count];
return(sum/(sum_coe*1.0));
}
7.卡尔曼滤波(Kalman Filter)
原理:一种最优化的自回归数据处理算法。它不仅仅是“滤波”,更是一个“预测-校正”的循环过程。它会建立一个系统状态模型,
根据上一时刻的状态预测当前时刻的状态,再用当前的测量值来校正这个预测,从而得到一个最优的估计值。
优点:理论上是处理高斯白噪声下线型系统问题的最优滤波器。非常适合用于融合多种传感器数据
(如加速度计和陀螺仪融合姿态解算)。不仅能滤波,还能预测系统状态。
缺点:数学模型复杂,理解和实现难度大。计算量远大于前几种算法,对MCU性能要求高。需要对系统进行精确建模,模型不准会导致
效果变差。
适用场景:高精度系统,如飞行器姿态解算(IMU)、机器人定位导航、电池电量SOC估算等。
#include"filter.h"
//一维卡尔曼滤波的简化模型(估计一个恒定电压)
float x_hat=0;//状态的后验估计值(最优估计)
float P=1;//后验估计的协方差(不确定度)
float Q=0.01;//过程噪声协方差(预测模型本身的不确定度)
float R=0.1;//测量噪声协方差(传感器测量的误差)
float K;//卡尔曼增益
float kalman_filter(float measurement){
//1.预测(因为模型是恒定电压,预测值就是上一次的最优值)
float x_hat_minus=x_hat;
float P_minus=P+Q;
//2.更新(校正)
K=P_minus/(P_minus+R);//计算卡尔曼增益
x_hat=x_hat_minus+K*(measurement-x_hat_minus);//更新最优估计
P=(1-K)*P_minus;//更新不确定度
return x_hat;
}
下一篇::没有了 上一篇:为什么选择兆易创新GD32F105RET6?
推荐产品
同类文章排行
- 兆易创新/GD MCU应用实践
- GD32F303RGT6国产高性能MCU的全面突破
- 雅特力AT32F435/F437入门使用指南
- 国民技术N32G033系列MCU
- GD32H737VGT6兆易创新MCU重新定义高性能MCU的边界
- GD32C103—嵌入式创新的核心引擎
- APM32E030C8T6替代APM32F030C8T6/STM32F030C8T6
- GD32F307系列MCU国产高性能替代全面对标国际品牌
- N32G455CCL7国产高性能MCU驱动工业智能化与能源升级
- 雅特力AT32F405高速USB MCU荣获“年度最佳MCU”
最新资讯文章
- 兆易创新GD32F503/505系列高性能产品
- 极海APM32F425/427系列总线型低压伺服方案
- APM32F427Z TinyBoard开发板小体积也能扛起工业性能
- 兆易创新GD32F303的高频DC/DC变换器解决方案
- 雅特力AT32F422/426系列MCU,超值型重塑高性能MCU标
- 芯片产业全面涨价潮
- 兆易创新GD32H759嵌入式运动控制系统解决方案
- 兆易创新GD32F303热泵变频空调解决方案
- 极海GALT62120:12通道汽车高边LED驱动器
- 极海全新发布首款G32R430编码器专用MCU
- 内存涨价,对MCU有什么影响?会涨价或缺货吗?
- 兆易创新GD32H78D/77D系列MCU
- 极海APM32F427系列高性能拓展型MCU
- 极海推出G32A1425系列精简高效汽车通用MCU
- 雅特力科技通过ISO 26262汽车功能安全ASIL D认证
- 关于MSKSEMI美森科半导体
- 被动元件,涨涨涨!
- 国民技术:“MCU+安全”双引擎,为具身智能注
- 国民技术MCU-智能电池管理系统的丰富选择
- 国民技术MCU引领新国标电动车“芯”时代









