在信号处理和数据分析领域,滤波算法扮演着至关重要的角色。它们帮助我们从嘈杂的数据中提取有用信息,平滑数据波动,预测未来趋势,甚至实现系统状态的精确估计。今天,我们将带您探索十大经典滤波算法,这些算法在工程实践和科学研究中都有着广泛的应用(获取案例程序的方法见文末)。
1. 限幅滤波:
方法:
如果新采样值与前一采样值之差小于或等于A,则认为本次采样有效。
如果新采样值与前一采样值之差大于A,则认为本次采样无效,用前一次的有效采样值替代本次采样值。
优点:
抗脉冲干扰: 能够有效识别并排除由于瞬时干扰造成的异常采样值,从而保持数据的稳定性。
缺点:
周期性干扰抑制不足: 对于具有周期性的干扰,该算法可能无法有效识别和抑制,可能导致数据中存在周期性的波动。
平滑度不足: 由于算法在遇到较大偏差时直接使用前一值替代,可能无法平滑处理数据中的波动,导致输出数据的平滑度不高。
//限幅滤波
//如果新采样值与前一采样值之差小于或等于A,则认为本次采样有效。
IF ABS(lrSignalIn - lrTemp) > lrDifference AND lrTemp <> 0 THEN
Filter_limit := lrTemp;
ELSE //如果新采样值与前一采样值之差大于A,则认为本次采样无效,用前一次的有效采样值替代本次采样值。
Filter_limit := lrSignalIn;
END_IF
lrTemp := lrSignalIn;
2. 算术平均滤波:
方法:
取样:连续采集数据N次,并对这些数据求平均值
求平均数:平均值的选取取决于N的大小
优点:
抗干扰能力: 适用于存在随机干扰的系统,通过多次采样求平均,能有效降低随机噪声的影响。
稳定性: 通过平滑处理,提高了数据的稳定性和可靠性。
缺点:
处理速度: 由于需要连续采集并处理多次数据,算法的执行速度较慢。
资源占用: 需要存储多次采样数据,因此占用较多的随机存取存储器(RAM)。
//算数平均滤波法
//连续采集数据N次,并对这些数据求平均值
FOR i := 0 TO iNumberOfSamples - 1 DO
aSampleBuffer[i] := lrSignalIn;
END_FOR
//输入值求和
FOR j := 0 TO iNumberOfSamples - 1 DO
lrTempSum := lrTempSum + aSampleBuffer[j];
END_FOR
//求平均值
Filter_average := lrTempSum / iNumberOfSamples;
3. 中位值滤波:
方法:
排序:将数据点按照大小顺序进行排序
选择中位值:从排序后的数据中选择位于中间位置的数值作为中位值。如果数据点数量是奇数,中位值就是正中间的数值;如果是偶数,则中位值通常是中间两个数值的平均值
替换异常值:用中位值替换所有异常值或离群点
优点:
对异常值不敏感:中位值滤波法对异常值具有很好的抵抗力,不会像均值滤波那样受到极端值的影响。
适用于非线性数据:对于非线性或非高斯分布的数据,中位值滤波法仍然有效。
缺点:
平滑能力有限:中位值滤波法主要用于去除异常值,对于平滑数据波动的能力有限。
对周期性噪声不敏感:中位值滤波法主要针对随机噪声有效,对于周期性或有结构的噪声可能不够有效。
//中值滤波法
//取样
FOR icount :=0 TO iN DO
aSampleBuffer[icount]:= lrSignalIn ;
END_FOR
//对样本缓冲区进行冒泡排序,以找到中位数
//外层循环控制排序的总轮数,每轮都会将最大的数移动到序列的末尾
FOR j:=0 TO iN-1 DO
//内层循环用于比较相邻元素并进行交换,以实现排序
FOR i:=0 TO iN-j DO
//如果当前元素大于下一个元素,则交换它们
IF aSampleBuffer[i]> aSampleBuffer[i+1] THEN
lrTemp := aSampleBuffer[i];
aSampleBuffer[i]:= aSampleBuffer[i+1];
aSampleBuffer[i+1]:= lrTemp ;
END_IF
END_FOR
END_FOR
//对于奇数个元素,直接取中间元素;对于偶数个元素,取中间两个元素的平均值,但这里只取了第一个中间值
Filter_mid := aSampleBuffer[TO_INT((iN-1)/2)];
4. 限幅平均滤波:
方法:
数据预处理:对每个采样点的信号值进行检查,如果超出限幅范围,则将其设置为限幅值(可以是上限或下限,取决于设计)。
累加限幅后的数据:将经过限幅处理后的信号值进行累加。
计算平均值:将累加的结果除以采样点的数量,得到限幅后的平均值
优点:
抑制异常值:有效抑制超出限幅范围的异常值或尖峰噪声。
平滑信号:通过算术平均的方式平滑信号,减少随机噪声的影响。
保持信号特征:在去除噪声的同时,能够较好地保持信号的原始特征
缺点:
可能引入失真:限幅处理可能会导致信号的部分信息丢失,引入一定程度的失真。
对限幅值敏感:限幅值的选择对滤波效果有很大影响,不适当的限幅值可能导致有效信号被错误地限幅。
对快速变化信号响应慢:由于平均的作用,滤波器对信号的快速变化响应较慢,可能无法及时跟踪信号的真实变化。
// 如果输入信号lrSignalIn与临时变量lrTemp的差的绝对值大于设定的阈值
IF ABS(lrSignalIn - lrTemp) > lrDifference AND lrTemp <> 0 THEN
aSampleBuffer[i] := lrSignalIn;//将当前的输入信号lrSignalIn存储到样本缓冲区aSampleBuffer的第i个位置。
i := i+1;
END_IF
IF i >= iN THEN
// 如果索引i达到或超过样本缓冲区的最大索引iN,
// 则将i重置为0,实现循环缓冲的效果。
i := 0;
END_IF
lrSum := 0;
FOR j:=0 TO iN DO
// 初始化求和变量lrSum为0,准备计算样本缓冲区所有元素的总和。
// 循环遍历样本缓冲区,从索引0到iN,累加每个元素的值到lrSum。
lrSum := lrSum + aSampleBuffer[j];
END_FOR
// 将当前的输入信号lrSignalIn赋值给临时变量lrTemp,准备用于下一次循环的比较。
lrTemp := lrSignalIn;
// 计算样本缓冲区所有样本的平均值
Filter_limitav := lrSum / iN;
5. 消抖滤波:
方法:
连续采样:对信号进行连续采样,获取一系列数据点。
记录有效变化:如果连续采样值之间的差异超过阈值,则记录这次变化,并更新滤波后的输出。
输出滤波结果:根据有效变化更新滤波后的信号输出。
优点:
抗干扰能力强:能有效滤除由于接触不良或传感器噪声引起的快速小幅度抖动。
保持信号边缘:由于只忽略小幅度变化,消抖滤波通常能保持信号的快速上升或下降边缘。
适用于开关信号:特别适用于处理开关信号或按钮输入,以消除误触发。
缺点:
参数选择关键:阈值的设定对滤波效果至关重要,不恰当的阈值可能导致有效信号被过滤掉或噪声被保留。
可能延迟响应:由于需要等待超过阈值的变化,滤波器可能会引入一定的延迟。
对大信号变化敏感:如果信号的实际变化超过阈值,可能会错误地认为是噪声而忽略,尤其是在信号变化复杂的情况下。
不适合高频信号:对于高频信号,消抖滤波可能无法有效工作,因为它主要针对小幅度的随机变化。
//消抖滤波
//// 如果当前信号值lrSignalIn不等于有效值lrValid
IF lrSignalIn <> lrValid THEN
//将索引i增加1,用于跟踪信号变化的次数或时间
i := i + 1;
IF i > iN THEN
i := 0;
Filter_ditel := lrSignalIn;
END_IF
ELSE // 如果当前信号值lrSignalIn等于有效值lrValid
i := 0;
// 将有效值lrValid赋值给滤波器
Filter_ditel := lrValid;
END_IF
6. 限幅消抖滤波:
方法:
限幅消抖滤波在消抖的基础上增加了限幅功能,通过设置上限和下限阈值来限制信号的波动范围。可以抑制更大范围的噪声,增强信号稳定性,适应性更强,有效防止信号失真,提高信号质量,应用场景更广泛。
//限幅消抖滤波
如果差值大于阈值,则将临时变量lrTemp设置为有效值lrValid
IF ABS(lrSignalIn - lrValid) > lrDifference THEN
lrTemp := lrValid;
ELSE
lrTemp := lrValid;
END_IF
如果计数器i超过设定的最大值iN,则重置i为0
IF lrTemp <> lrSignalIn THEN
i := i + 1;
IF i > iN THEN
i := 0;
Filter_limitditel := lrValid;
END_IF
END_IF
7. 递推平均滤波:
方法:
实时更新:对于每一个新的输入数据点,使用以下递推公式更新滤波结果:
连续应用:将上述递推公式连续应用于新的数据点,以实时更新滤波结果。
优点:
实时性:递推平均滤波法可以实时更新滤波结果,适合在线数据处理。
计算效率高:由于只需要保留前一个滤波值,计算量小,适用于资源受限的系统。
平滑效果:能够平滑数据中的随机噪声,使信号更加稳定。
缺点:
累积误差:长期应用递推公式可能导致误差累积,影响滤波精度。
对初值敏感:滤波器的初始值对最终结果有一定影响,需要合理选择。
无法处理突变:对于信号中的突变或跳变,递推平均滤波法可能无法及时响应。
//递推平均滤波
// 将当前的信号值lrSignalIn存储到样本缓冲区aSampleBuffer的当前索引i位置
aSampleBuffer[i]:= lrSignalIn;
// 将索引i增加1,用于准备下一次数据的存储位置
i:= i + 1;
// 这通常用于循环缓冲区,当达到末尾时重新开始
IF i>= iN THEN
i:= 0;
END_IF
// 遍历样本缓冲区aSampleBuffer中的所有样本
FOR j:= 0 TO iN DO
lrTemp := lrTemp + aSampleBuffer[j];
END_FOR
// 计算移动平均值,即将累加的样本值除以缓冲区大小iN
Filter_recav := lrTemp /iN ;
8.加权递推平均滤波:
特点:
每个数据点根据其时间重要性被赋予一个权重。权重通常随着时间的增长而递减,这种加权机制允许滤波器对新数据给予更多的关注。
//加权递推平均滤波
lrSumcoe :=0;
// 将当前索引i转换为长实数并存储在加权系数数组aSumcoe中
FOR i:= 0 TO iN DO
aSumcoe[i] :=TO_LREAL( i );
lrSumcoe :=lrSumcoe +i;
END_FOR
// 将信号值lrSignalIn赋值给样本缓冲区aSampleBuffer的每个位置
FOR i :=0 TO iN DO
aSampleBuffer[i]:= lrSignalIn;
END_FOR
lrSum :=0;
// 遍历样本缓冲区aSampleBuffer,计算每个样本值与其对应加权系数的乘积
FOR j:=0 TO iN DO
lrSum := lrSum + aSampleBuffer[i]*aSumcoe[i];
END_FOR
// 将加权后的样本值总和除以加权系数的总和,得到加权移动平均值
IF lrSumcoe <> 0 THEN
Filter_recavwei := lrSum / lrSumcoe ;
END_IF
9. 一阶滞后滤波法:
特点:
一阶滞后滤波法(First-Order Lag Filter),也称为指数移动平均滤波法(Exponential Moving Average, EMA),是一种常用的信号平滑技术。
优点:
简单高效:算法实现简单,计算效率高,适合实时数据处理。
平滑性能好:能够有效地平滑随机噪声,提供信号的平滑估计。
时间加权:对最近的数据赋予更高的权重,使得滤波结果更加反映近期趋势。
缺点:
对初值敏感:滤波器的初始值可能对最终结果有较大影响,特别是在数据序列的开始阶段。
延迟效应:由于滞后效应,滤波后的信号会有一定的延迟,无法即时反映信号的突变。
累积误差:在某些情况下,长时间使用可能导致误差累积,尤其是在信号特性发生变化时
//一阶滤波
// 确保lrAlpha的值在0和1之间
lrAlpha:=LIMIT(0,lrAlpha,1);
// 根据一阶低通滤波器的公式计算滤波后的信号
Filter_firstorder :=(1 - lrAlpha)* lrSignalIn + lrAlpha * lrTemp;
lrTemp:= Filter_firstorder;
10. 卡尔曼滤波法:
方法:
预测、更新:根据系统的动态模型预测下一状态,利用新的测量数据更新预测的状态。
卡尔曼增益:计算卡尔曼增益,它是一个权重,用于平衡预测值和观测值。
递推更新:使用卡尔曼增益,结合预测值和观测值,递推更新估计的状态。
优点:
最优性:在高斯噪声假设下,卡尔曼滤波提供了最小均方误差的最优估计。
递推性质:能够递推地更新状态估计,适合实时系统。
鲁棒性:对于系统模型的不确定性和测量噪声具有一定的鲁棒性。
通用性:适用于各种线性动态系统,也通过扩展(如扩展卡尔曼滤波和无迹卡尔曼滤波)用于非线性系统。
缺点:
高斯噪声假设:卡尔曼滤波基于高斯噪声的假设,对于非高斯噪声可能不是最优的。
线性系统模型:标准的卡尔曼滤波适用于线性系统和线性观测模型,对于高度非线性系统需要使用扩展版本。
敏感性:对初始状态估计和系统模型参数的准确性敏感,错误的参数可能导致次优的滤波性能。
计算复杂度:对于具有大量状态变量的系统,计算协方差矩阵的更新可能具有较高的计算复杂度。
稳定性问题:在某些情况下,如协方差矩阵非正定,卡尔曼滤波可能不稳定。
FUNCTION KalmanFilter2D : lreal
VAR_INPUT
z: REAL; // 测量值(位置)
intetime: REAL; // 时间间隔
Q_pos: REAL; // 位置过程噪声协方差
Q_vel: REAL; // 速度过程噪声协方差
R_pos: REAL; // 位置测量噪声协方差
END_VAR
VAR_OUTPUT
xHat: REAL; // 估计的位置
vHat: REAL; // 估计的速度
END_VAR
VAR
xHatPrev: REAL; // 上一次的位置估计
vHatPrev: REAL; // 上一次的速度估计
P_xx: REAL; // 位置估计误差协方差
P_xv: REAL; // 位置和速度估计误差协方差
P_vv: REAL; // 速度估计误差协方差
K_x: REAL; // 卡尔曼增益(针对位置)
K_v: REAL; // (本例中不使用,但为了完整性保留)
P_xx_pred: REAL;
RP_xv_pred: REAL;
P_vv_pred: REAL;
S1: REAL;
v: REAL;
A_mat: ARRAY[1..2, 1..2] OF REAL;
Q_mat: ARRAY[1..2, 1..2] OF REAL;
C_mat: ARRAY[1..1, 1..2] OF REAL;
END_VAR
// 初始化矩阵
A_mat[1,1] := 1; A_mat[1,2] := intetime;
A_mat[2,1] := 0; A_mat[2,2] := 1;
Q_mat[1,1] := Q_pos * intetime*intetime*intetime / 3 + Q_vel * intetime;
Q_mat[1,2] := Q_pos * intetime*intetime / 2;
Q_mat[2,1] := Q_pos * intetime*intetime / 2;
Q_mat[2,2] := Q_pos * intetime;
C_mat[1,1] := 1; C_mat[1,2] := 0;
// 预测步骤
xHatPrev := xHat;
vHatPrev := vHat + intetime * vHat; // 简化的速度预测(假设加速度为0)
// 协方差预测(这里简化了矩阵运算,实际中可能需要更复杂的处理)
P_xx_pred := P_xx + Q_mat[1,1];
RP_xv_pred := P_xv + Q_mat[1,2];
P_vv_pred := P_vv + Q_mat[2,2];
// 更新步骤(这里只更新位置相关的卡尔曼增益和状态)
S1 := P_xx_pred + R_pos;
K_x := P_xx_pred / S1;
xHat := xHatPrev + K_x * (z - xHatPrev);
vHat := v;