滑动窗口滤波
一、原理
通过对连续采样数据窗口内的数值进行算术平均,减少随机噪声。其核心是固定长度的队列,更新时替换最旧的数据,计算平均。
二、用途
主要用于实时检测线性数据----------平滑线性数据、去除噪声。
三、场景模拟
3.1、示例1
每10ms获取 一个 数据 ,存储到一个【Len =5】 的缓存数组里(也叫缓存池)
注意:Len 是 常量
3.2、解析步骤
以连续7笔数据为例。数据流是1-2-3-4-5-6-7,那么缓冲区的从最初始变化到最后:
初始状态: [0,0,0,0,0]
开始:
第一次加入数据1 → [0,0,0,0,1] → sum = (0+0+0+0+1) / 5 = 0.2
第二次加入数据2 → [0,0,0,1,2] → sum = (0+0+0+1+2) / 5 = 0.6
第三次加入数据3 → [0,0,1,2,3] → sum = (0+0+1+2+3) / 5 = 1.2
第四次加入数据4 → [0,1,2,3,4] → sum = (0+1+2+3+4) / 5 = 2
第五次加入数据5 → [1,2,3,4,5] → sum = (1+2+3+4+5) / 5 = 3
第六次加入数据6 → [2,3,4,5,6] → sum = (2+3+4+5+6) / 5 = 4
第七次加入数据7 → [3,4,5,6,7] → sum = (3+4+5+6+7) / 5 = 5
sum :表示 总和
/5 :表示 数组长度是5
sum/5 :表示 平均
四、补充知识点1
众所周知,程序上 使用 “除法”计算得出的结果都是省略 【小数】
为了 进一步 精确得出实际数值。我们数学上使用“约等于”也就是----【四舍五入】
4.1、四舍五入的数学原理
(1)若小数部分 ≥0.5,则结果进位(+1)
(2)若小数部分 <0.5,则结果舍去
这些都简单,那么如何运用在我们的程序里并去实现
4.2、思维导入
Q整数 / W整数 = 得出省略后小数的【E整数】
Q整数 % W整数 = 得出 余数
余数 > (W整数 / 2) 则【E整数】进位 即 最终结果【E整数 + 1】
余数 < (W整数 / 2) 则【E整数】不进位 即 最终结果【E整数】
4.3、示例
实例一:
7 / 5 ≈ 1 (实际值1.4,小数部分0.4 < 0.5 被丢弃-----四舍五入)
同理:
7 / 5 ≈ 1 (实际值1余2,【余数2】 小于 【5/2 = 2.5】被丢弃-----四舍五入)
实例二:
8 / 5 ≈ 2 (实际值1.6,小数部分0.6 > 0.5 进位+1-----四舍五入)
同理:
8 / 5 ≈ 2 (实际值1余3,【余数3】 大于 【5/2 = 2.5】进位+1-----四舍五入)
实例三:
5 / 12 ≈ 0 (实际值0.4,小数部分0.4 < 0.5 被丢弃-----四舍五入)
同理:
5 / 12 ≈ 0 (实际值0余5,【余数5】 小于 【12/2 = 6】被丢弃-----四舍五入)
实例四:
7 / 12 ≈ 1 (实际值0.58,小数部分0.58 > 0.5 进位+1-----四舍五入)
同理:
7 / 12 ≈ 1 (实际值0余7,【余数7】 大于 【12/2 = 6】进位+1-----四舍五入)
4.4、找规律
上述例子,我们发现:【余数 > (除数/2) 】 是 决定 【余数】 是否进位的
其次:
程序上 使用 “除法”计算得出的结果都是省略小数 不管大于 0.5 或者小于 0.5都是省略的特性
例子;
15 / 10 =1.5 = 1余5 数学上约等于 2 程序上得出:1
16 / 10 =1.6 = 1余6 数学上约等于 2 程序上得出:1
18 / 10 =1.8 = 1余8 数学上约等于 2 程序上得出:1
11 / 10 =1.1 = 1余1 数学上约等于 1 程序上得出:1
12 / 10 =1.2 = 1余2 数学上约等于 1 程序上得出:1
22 / 10 =2.2 = 2余2 数学上约等于 2 程序上得出:2
28 / 10 =2.8 = 2余8 数学上约等于 3 程序上得出:2
7 / 5 =1.4 = 1余2 数学上约等于 1 程序上得出:1
为了满足四舍五入 ;
我们可以在 【 [被除数]上先 加上 [ 除数/2 ] 】 再除 。
接着 根据 编程 【除法】 特性 省略小数,得出 四舍五入 值
例子: 数学上四舍五入值
15 / 10 =1.5 = 1余5 数学上约等于 2 (15+10/2) / 10 =2 程序上得出:2
16 / 10 =1.6 = 1余6 数学上约等于 2 (16+10/2) / 10 =2 程序上得出:2
18 / 10 =1.8 = 1余8 数学上约等于 2 (18+10/2) / 10 =2 程序上得出:2
11 / 10 =1.1 = 1余1 数学上约等于 1 (11+10/2) / 10 =1 程序上得出:1
12 / 10 =1.2 = 1余2 数学上约等于 1 (12+10/2) / 10 =1 程序上得出:1
22 / 10 =2.2 = 2余2 数学上约等于 2 (22+10/2) / 10 =2 程序上得出:2
28 / 10 =2.8 = 2余8 数学上约等于 3 (28+10/2) / 10 =3 程序上得出:3
7 / 5 =1.4 = 1余2 数学上约等于 1 (7 + 5/2) / 5 =1 程序上得出:1
我们不难发现 ,数学上的四舍五入值 与 【被除数上先 加上 [除数/2] 】 再除 】 得出的 四舍五入值 是一致的
C语言代码实现四舍五入:
( ( sum + WINDOW_SIZE / 2 ) / WINDOW_SIZE )
注意:负数运算可能不适用
注释:sum :被除数
WINDOW_SIZE:除数
( sum + WINDOW_SIZE / 2 ) ===== 被除数上先 加上 除数一半
五、补充知识点2
5.1、取模运算
当:WINDOW_SIZE 取偶数时
#define WINDOW_SIZE 64
则:
index = (index + 1) & (WINDOW_SIZE - 1); // 位运算代替取模
当:WINDOW_SIZE 取奇数时
#define WINDOW_SIZE 5
则:
index = (index + 1) & (WINDOW_SIZE); // 位运算代替取模
主要用途:循环定位 数组当前 第几位
六、C语言实现 滑动窗口滤波 ------------单通道数据
#define WINDOW_SIZE 5 //奇数
//全局变量
int32_tbuffer[WINDOW_SIZE] = {0};
int32_t sum = 0;
uint8_t index = 0;
uint8_t count = 0;
int32_t moving_average_filter_int(int32_t new_value)
{
/* 初始阶段:未填满窗口 */
if(count < WINDOW_SIZE)
{
sum += new_value;
buffer[index] = new_value;
index = (index + 1) % WINDOW_SIZE;
count++;
return (int32_t )(sum / count);
}
/* 稳定阶段:窗口已满 */
sum -= buffer[index]; // 移除旧数据
sum += new_value; // 加入新数据
buffer[index] = new_value; // 更新缓冲区
index = (index + 1) % WINDOW_SIZE;
// 四舍五入
return (int32_t )((sum + WINDOW_SIZE/2) / WINDOW_SIZE);
}