限幅滤波法
- 优点:能有效克服因偶然因素引起的脉冲干扰。
- 缺点:无法抑制周期性干扰,平滑度差。
- C语言实现:
#define A 10
unsigned char Value;
unsigned char AmplitudeLimiterFilter() {
unsigned char NewValue = GetAD(); // 假设GetAD()是ADC采集函数
unsigned char ReturnValue;
if (abs(NewValue - Value) > A)
ReturnValue = Value;
else
ReturnValue = NewValue;
return ReturnValue;
}
中位值滤波法
- 优点:能有效克服因偶然因素引起的波动干扰,对温度、液位等变化缓慢的参数有良好滤波效果。
- 缺点:对流量、速度等快速变化的参数滤波效果较差。
- C语言实现:
#define N 9 // 采样次数,需为奇数
unsigned char ArrDataBuffer[N];
void MiddleValueFilter() {
unsigned char i, j, temp;
for (i = 0; i < N; i++) {
ArrDataBuffer[i] = GetAD();
}
for (j = 0; j < N - 1; j++) {
for (int k = 0; k < N - 1 - j; k++) {
if (ArrDataBuffer[k] > ArrDataBuffer[k + 1]) {
temp = ArrDataBuffer[k];
ArrDataBuffer[k] = ArrDataBuffer[k + 1];
ArrDataBuffer[k + 1] = temp;
}
}
}
unsigned char ReturnValue = ArrDataBuffer[(N - 1) / 2];
// 使用ReturnValue
}
算术平均滤波法
- 优点:适用于对一般具有随机干扰的信号进行滤波。
- 缺点:存在滞后,对于要求数据计算速度较快或测量速度较慢的实时控制不适用。
- C语言实现:
#define N 5 // 采样次数
unsigned int sum = 0;
for (int i = 0; i < N; i++) {
sum += GetAD();
}
unsigned char average = sum / N;
// 使用average
滑动平均滤波法
- 优点:对周期性干扰有良好的抑制作用,平滑度高。
- 缺点:灵敏度低,不易消除脉冲干扰引起的采样值偏差。
- C语言实现:
unsigned int sum = 0; // 用于存储最近N个采样值的总和
unsigned char value_buf[N]; // 存储最近N个采样值的数组
// 假设GetAD()是一个从ADC获取最新采样值的函数
void UpdateFilter() {
unsigned int new_sum = 0; // 用于计算新的总和
for (int i = 0; i < N; i++) {
if (i > 0) {
sum -= value_buf[i - 1]; // 移除最老的采样值
}
value_buf[i] = GetAD(); // 获取并存储最新的采样值
new_sum += value_buf[i]; // 累加新采样值到总和
}
sum = new_sum; // 更新总和
unsigned char average = sum / N; // 计算新的平均值
// 使用average,例如将其作为滤波后的输出
}
int main() {
// 初始化代码,例如初始化ADC等
while(1) {
UpdateFilter(); // 定期更新滤波器
// 其他任务...
}
return 0;
}
可以使用结构体和数组来实现一个固定大小的队列,创建一个固定大小为5的队列,并计算其平均值,新值加入队列时,最老的值会被自动移除。
#include <stdio.h>
#define QUEUE_SIZE 5
// 队列结构体
typedef struct {
int data[QUEUE_SIZE];
int front; // 队列头部索引
int rear; // 队列尾部索引
} FixedSizeQueue;
// 初始化队列
void initQueue(FixedSizeQueue *q) {
q->front = 0;
q->rear = -1;
}
// 检查队列是否已满
int isFull(FixedSizeQueue *q) {
return (q->rear + 1) % QUEUE_SIZE == q->front;
}
// 检查队列是否为空
int isEmpty(FixedSizeQueue *q) {
return q->rear == -1;
}
// 入队操作
void enqueue(FixedSizeQueue *q, int value) {
if (isFull(q)) {
printf("Queue is full. Cannot add new value.\n");
return;
}
q->rear = (q->rear + 1) % QUEUE_SIZE;
q->data[q->rear] = value;
}
// 出队操作(移除最老的值)
void dequeue(FixedSizeQueue *q) {
if (isEmpty(q)) {
printf("Queue is empty.\n");
return;
}
q->front = (q->front + 1) % QUEUE_SIZE;
}
// 计算队列中的平均值
double calculateAverage(FixedSizeQueue *q) {
if (isEmpty(q)) {
return 0;
}
int sum = 0;
int count = 0;
for (int i = q->front; i != (q->rear + 1) % QUEUE_SIZE; i = (i + 1) % QUEUE_SIZE) {
sum += q->data[i];
count++;
}
return (double)sum / count;
}
int main() {
FixedSizeQueue queue;
initQueue(&queue);
// 添加一些值到队列
enqueue(&queue, 10);
enqueue(&queue, 20);
enqueue(&queue, 30);
printf("Current average: %.2f\n", calculateAverage(&queue));
// 添加新值,最老的值将被移除
enqueue(&queue, 40);
printf("New average after adding 40: %.2f\n", calculateAverage(&queue));
enqueue(&queue, 50);
printf("New average after adding 50: %.2f\n", calculateAverage(&queue));
return 0;
}
定义一个FixedSizeQueue
结构体,它包含一个整数数组data
来存储队列中的元素,以及两个整数front
和rear
来分别表示队列的头部和尾部索引。
initQueue
函数用于初始化队列,isFull
和isEmpty
函数用于检查队列是否已满或为空,enqueue
函数用于添加新元素到队列,如果队列已满则不添加并打印提示信息,dequeue
函数用于从队列中移除最老的元素,calculateAverage
函数用于计算队列中所有元素的平均值。
另一种实现方式,通过一个固定大小的数组来存储最近的五个数值,并在每次添加新值时,如果数组已满,就替换掉最老的值(即数组中的第一个值)。
#include <stdio.h>
#define ARRAY_SIZE 5
// 函数声明
void addValue(int *array, int value, int *index);
double calculateAverage(int *array, int size);
int main() {
int values[ARRAY_SIZE]; // 存储五个数值的数组
int index = 0; // 用于记录新值的插入位置
int i;
// 初始化数组
for (i = 0; i < ARRAY_SIZE; i++) {
values[i] = 0;
}
// 添加一些值
addValue(values, 10, &index);
addValue(values, 20, &index);
addValue(values, 30, &index);
printf("Current average: %.2f\n", calculateAverage(values, ARRAY_SIZE));
// 添加新值,最老的值将被移除
addValue(values, 40, &index);
printf("New average after adding 40: %.2f\n", calculateAverage(values, ARRAY_SIZE));
addValue(values, 50, &index);
printf("New average after adding 50: %.2f\n", calculateAverage(values, ARRAY_SIZE));
return 0;
}
// 添加新值到数组,并更新索引
void addValue(int *array, int value, int *index) {
array[*index] = value; // 添加新值
(*index) = (*index + 1) % ARRAY_SIZE; // 更新索引,如果达到数组末尾则回到开头
}
// 计算数组中所有数值的平均值
double calculateAverage(int *array, int size) {
int sum = 0;
for (int i = 0; i < size; i++) {
sum += array[i];
}
return (double)sum / size;
}
使用示例
/**************************.c文件*****************************/
#include "stdint.h"
#include "Filter.h"
Sliding_Mean_Filter Example_Filter = {{0}, 0, 0, 0};
void Sliding_Mean_Filter_Calc(Sliding_Mean_Filter *filter, double Data)
{
filter->sum -= filter->Filter_Buffer[filter->id]; //减去最旧的数
filter->sum += Data; //加进最新的数
filter->Filter_Buffer[filter->id] = Data; //将最新的数覆盖最旧的数
filter->average = filter->sum / Sliding_Mean_Filter_Buffer_Size; //求均值
if(++filter->id == Sliding_Mean_Filter_Buffer_Size)
filter->id = 0;
}
/**************************.h文件*****************************/
#ifndef Filter_H_
#define Filter_H_
#define Sliding_Mean_Filter_Buffer_Size 5
typedef struct
{
double Filter_Buffer[Sliding_Mean_Filter_Buffer_Size];
uint16_t id;
double sum;
double average;
}Sliding_Mean_Filter;
void Sliding_Mean_Filter_Calc(Sliding_Mean_Filter *filter, double Data);
extern Sliding_Mean_Filter Example_Filter;
#endif
一阶滞后滤波法(惯性滤波法)
- 优点:适用于波动频繁的被测量滤波,能很好地消除周期性干扰。
- 缺点:带来了相位滞后,且灵敏度不高。
- C语言实现:
float alpha = 0.1; // 滤波系数,0 < alpha <= 1
float last_value = 0; // 上一次滤波结果
float new_value = GetAD(); // 新采样值
float filtered_value = alpha * new_value + (1 - alpha) * last_value;
last_value = filtered_value; // 更新为下一次使用
// 使用filtered_value