C语言实现的滑动平均滤波算法

    最近采集压力传感器的电压信号,采集到的数据波动挺大的,所以采用滤波的方法进行处理一下。

    因为在matlab中依靠matlab的画图函数很容易看到滤波后的数据图像,进而验证滤波效果。

    所以首先将采集到的原始数据保存到TXT文档里面,然后导入到matlab中,在matlab中对数据进行滤波。

    在matlab中采用了三种滤波方法:1、滑动平均滤波 2、中值滤波 3、卡尔曼滤波

    在对比了三种滤波之后的图像之后,选择了第一种滑动平均滤波的方法。在matlab中有专门的函数:smooth(变量),但是我们要用C语言实现这个功能。

    我依据滑动平均滤波的原理进行了程序编写,对于数据开始部分和结尾部分做了一些改变,得到的滤波效果还不错,与matlab的滤波效果差异很小。

    话不多说,上代码:

#define size 6000//数组大小
#define N 12//滑动平均滤波计算平均值时所取的点数
/*上面两句在使用下面这个函数的时候加到程序的开头*/
void Smooth(float data[])
{
    Sum1=0;
    for(int j=0;j
<think>我们已知用户想要一个滑动平均滤波器,但输入是单个数据点(即每次处理一个数据),而不是整个数组。因此,我们需要维护一个历史数据窗口(通常使用循环缓冲区)来存储最近的数据点。每次输入一个新数据点时,我们更新这个缓冲区,并计算当前窗口内的平均值。实现思路:1.定义一个结构体来管理滤波器的状态(包括缓冲区、当前索引、窗口大小等)。2.初始化滤波器:分配缓冲区,设置初始值(例如0),设置窗口大小。3.每次调用滤波函数时,输入一个新数据点,然后:a.将新数据点存入缓冲区的下一个位置(使用循环索引)。b.更新总和:减去被覆盖的旧值(如果是第一次填充,则不需要减,或者用新值覆盖0),加上新值。c.计算当前窗口内的平均值(如果窗口未满,则用实际数据个数计算)。4.返回平均值。注意:在窗口未满时,我们只计算当前已有数据的平均值。参考引用[4]中的代码是一个固定窗口大小的滑动平均滤波,但它每次需要整个数组移动,效率较低。我们将使用循环缓冲区来避免数据移动。以下是一种实现方式:步骤:1.定义结构体:-缓冲区数组(动态分配或固定大小)-窗口大小-当前数据计数(用于判断窗口是否已满)-当前索引(指示下一个数据存放的位置)-总和(当前窗口内所有数据的和)2.初始化函数:创建滤波器状态结构体,并初始化各成员。3.滤波函数:输入一个新数据,更新状态并返回当前平均值。4.销毁函数:释放分配的内存。代码实现如下:</think>### C语言实现滑动平均滤波算法(单点输入) 参考站内资料[^1][^3],滑动平均滤波的核心原理是用最近$N$个数据点的算术平均值作为当前输出值,能有效抑制随机噪声。以下是针对单点输入的实现方案: #### 核心实现原理 1. **循环缓冲区**:使用固定长度数组存储历史数据 2. **动态更新**:新数据覆盖最旧数据(先进先出) 3. **实时计算**:每次输入新点时重新计算窗口内平均值 4. **时间复杂度**:$O(1)$,通过维护累加值避免全量计算[^4] #### 完整实现代码 ```c #include <stdio.h> #define WINDOW_SIZE 5 // 滑动窗口大小 typedef struct { float buffer[WINDOW_SIZE]; // 数据缓冲区 int index; // 当前写入位置 int count; // 当前数据数量 float sum; // 窗口内数据总和 } MovingAverageFilter; // 初始化滤波器 void init_filter(MovingAverageFilter* filter) { for(int i = 0; i < WINDOW_SIZE; i++) { filter->buffer[i] = 0.0f; } filter->index = 0; filter->count = 0; filter->sum = 0.0f; } // 添加新数据点并返回滤波结果 float add_data_point(MovingAverageFilter* filter, float new_value) { // 更新总和:减去将被覆盖的值 if(filter->count == WINDOW_SIZE) { filter->sum -= filter->buffer[filter->index]; } else { filter->count++; } // 存储新值并更新总和 filter->buffer[filter->index] = new_value; filter->sum += new_value; // 更新索引(循环缓冲区) filter->index = (filter->index + 1) % WINDOW_SIZE; // 返回当前平均值 return filter->sum / filter->count; } int main() { MovingAverageFilter filter; init_filter(&filter); // 模拟实时数据输入 float test_data[] = {10.2, 11.5, 9.8, 12.1, 10.9, 11.2, 10.5}; int data_count = sizeof(test_data)/sizeof(test_data[0]); printf("原始数据\t滤波结果\n"); printf("--------\t--------\n"); for(int i = 0; i < data_count; i++) { float filtered = add_data_point(&filter, test_data[i]); printf("%.1f\t\t%.2f\n", test_data[i], filtered); } return 0; } ``` #### 输出示例: ``` 原始数据 滤波结果 -------- -------- 10.2 10.20 11.5 10.85 9.8 10.50 12.1 10.90 10.9 10.90 11.2 11.02 10.5 10.94 ``` #### 算法优化点 1. **动态窗口**:窗口未满时使用实际数据量计算 2. **和值维护**:每次只更新差值,避免全量求和[^4] 3. **循环索引**:使用取模运算实现高效缓冲区管理 4. **结构封装**:滤波器状态自包含,支持多实例[^2] #### 实时使用示例 ```c int main() { MovingAverageFilter sensor_filter; init_filter(&sensor_filter); while(1) { // 从传感器读取数据(示例) float raw_value = read_sensor(); // 应用滑动平均滤波 float filtered_value = add_data_point(&sensor_filter, raw_value); // 使用滤波后的值 printf("滤波值: %.2f\n", filtered_value); delay(100); // 采样间隔 } } ``` #### 参数调整建议 1. **窗口大小**:根据信号特性选择 - 快速响应:小窗口(3-5点) - 强降噪:大窗口(10-20点) 2. **数据类型**:噪声大时使用`double`提高精度 3. **初始值**:敏感应用可初始化为期望值 > **注意**:窗口越大,滤波效果越平滑,但信号延迟也越大[^3]。实际应用中需根据信号频率和噪声特性权衡选择。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值