脉冲滤波算法
本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明.
说明:
有一些传感器采集的数据基本准确,但有偶发性的错误。本文设计的脉冲滤波算法可以过滤掉这些脉冲干扰。
算法原理:
建一个数组保存数据,每个数据都有一个有效性标志。有新数据时,跟前一个有效数据比较差值,小于阈值则有效,大于阈值则无效。如果无效数据过多,则算法失效,认为所有数据都有效。
算法提供读取接口,可以返回最新的有效数据。
算法优势:
实时性很高,数据正确时是0延时,数据错误或者剧烈变化时会造成延时。算法适用于采集的数据可靠性很高,仅有偶发性错误的场景。
源码:
pulse_filter.h:
/**
* Copyright (c), 2015-2025
* @file pulse_filter.c
* @brief 脉冲过滤器模块头文件
* @verbatim
* Change Logs:
* Date Author Notes
* 2017-10-27 jdh 新建
* 2018-10-09 jdh 时间校准用周期数的机制进行处理
* 2019-02-26 jdh 标准化
* @endverbatim
*/
#ifndef _PULSE_FILTER_H_
#define _PULSE_FILTER_H_
#include "stdlib.h"
#include "stdio.h"
/**
* @brief 创建脉冲滤波器
* @param num_filter_pulse: 过滤的脉冲数
* @param max_delta: 最大偏差值
* @param cycle: 键值周期.如果为0表示没有周期
* @return 过滤器索引
*/
int pulse_filter_create(int num_filter_pulse, int max_delta, int cycle);
/**
* @brief 写入数据
* @note 针对本项目进行定制.输入的数是一个周期数
* @param key: 键值
* @param cycle: 周期
*/
void pulse_filter_write(int filter_index, int key);
/**
* @brief 读取数据
*/
int pulse_filter_read(int filter_index);
/**
* @brief 是否包含数据
* @retval true:有.false:没有
*/
bool pulse_filter_is_contain_data(int filter_index);
/**
* @brief 打印过滤器
*/
void pulse_filter_print(int filter_index);
#endif
pulse_filter.c:
/**
* Copyright (c), 2015-2025
* @file pulse_filter.c
* @brief 脉冲过滤器模块主文件
* @verbatim
* Change Logs:
* Date Author Notes
* 2017-10-27 jdh 新建
* 2018-10-09 jdh 时间校准用周期数的机制进行处理
* 2019-02-26 jdh 标准化
* @endverbatim
*/
#include "pulse_filter.h"
/**
* @brief 滤波器结构
*/
typedef struct
{
// 过滤连续脉冲数
int num_filter_pulse;
// 周期
int cycle;
// 最大偏差值
int max_delta;
// 缓存节点数
int num_node;
// key数组.基于key进行滤波
int *key;
// 数据有效标志数组
bool *valid;
} Filter;
static void append(Filter *filter, int key, bool is_valid);
/**
* @brief 得到最近的有效数据下表
* @note 不考虑第一个节点.因为第一个节点需要被删除
* @param filter: 滤波器
* @return -1:无有效数据.其他:下标
*/
static int get_newest_valid_index(Filter *filter);
static void pop_first(Filter *filter);
static void set_all_node_valid(Filter *filter);
static bool key_is_valid(Filter *filter, int valid_index, int key);
/**
* @brief 计算两个周期数的最小差值
* @note 比如两个数1, 9.都是在周期10以内循环的。所以最小差值应该为2而不是8
* @param x: 数1
* @param y: 数2
* @return 差值
*/
int calc_min_delta_in_cycle(int x, int y, int cycle);
/**
* @brief 创建脉冲滤波器
* @param num_filter_pulse: 过滤的脉冲数
* @param max_delta: 最大偏差值
* @param cycle: 键值周期.如果为0表示没有周期
* @return 过滤器索引
*/
int pulse_filter_create(int num_filter_pulse, int max_delta, int cycle)
{
Filter *filter = (Filter *)malloc(sizeof(Filter));
filter->num_filter_pulse = num_filter_pulse;
filter->max_delta = max_delta;
filter->cycle = cycle;
int item_num = filter->num_filter_pulse + 2;
filter->key = (int *)malloc(item_num * sizeof(int));
filter->valid = (bool *)malloc(item_num * sizeof(bool));
filter->num_node = 0;
return (int)filter;
}
/**
* @brief 写入数据
* @note 针对本项目进行定制.输入的数是一个周期数
* @param key: 键值
* @param cycle: 周期
*/
void pulse_filter_write(int filter_index, int key)
{
Filter *filter = (Filter *)filter_index;
int item_num = filter->num_filter_pulse + 2;
if (filter->num_node < item_num)
{
append(filter, key, true);
return;
}
pop_first(filter);
int index = get_newest_valid_index(filter);
if (index == -1)
{
append(filter, key, true);
set_all_node_valid(filter);
return;
}
append(filter, key, key_is_valid(filter, index, key));
}
static void append(Filter *filter, int key, bool is_valid)
{
int item_num = filter->num_filter_pulse + 2;
if (filter->num_node < item_num)
{
filter->key[filter->num_node] = key;
filter->valid[filter->num_node] = is_valid;
filter->num_node++;
return;
}
}
/**
* @brief 得到最近的有效数据下表
* @note 不考虑第一个节点.因为第一个节点需要被删除
* @param filter: 滤波器
* @return -1:无有效数据.其他:下标
*/
static int get_newest_valid_index(Filter *filter)
{
for (int i = 0; i < filter->num_node; i++)
{
if (filter->valid[filter->num_node - 1 - i])
{
return filter->num_node - 1 - i;
}
}
return -1;
}
static void pop_first(Filter *filter)
{
int item_num = filter->num_filter_pulse + 2;
for (int i = 0; i < item_num - 1; i++)
{
filter->key[i] = filter->key[i + 1];
filter->valid[i] = filter->valid[i + 1];
}
filter->num_node--;
}
static void set_all_node_valid(Filter *filter)
{
int item_num = filter->num_filter_pulse + 2;
for (int i = 0; i < item_num; i++)
{
filter->valid[i] = true;
}
}
/**
* @brief 计算两个周期数的最小差值
* @note 比如两个数1, 9.都是在周期10以内循环的。所以最小差值应该为2而不是8
* @param x: 数1
* @param y: 数2
* @return 差值
*/
int calc_min_delta_in_cycle(int x, int y, int cycle)
{
if (cycle == 0)
{
if (x > y)
{
return x - y;
}
else
{
return y - x;
}
}
int a = (x - y + cycle) % cycle;
int b = cycle - a;
if (a > b)
{
return b;
}
else
{
return a;
}
}
static bool key_is_valid(Filter *filter, int valid_index, int key)
{
return (calc_min_delta_in_cycle(filter->key[valid_index], key, filter->cycle) <= filter->max_delta);
}
/**
* @brief 读取数据
*/
int pulse_filter_read(int filter_index)
{
Filter *filter = (Filter *)filter_index;
if (filter->num_node == 0)
{
return 0;
}
int index = get_newest_valid_index(filter);
if (index == -1)
{
return 0;
}
return filter->key[index];
}
/**
* @brief 是否包含数据
* @retval true:有.false:没有
*/
bool pulse_filter_is_contain_data(int filter_index)
{
Filter *filter = (Filter *)filter_index;
return (filter->num_node > 0);
}
/**
* @brief 打印过滤器
*/
void pulse_filter_print(int filter_index)
{
Filter *filter = (Filter *)filter_index;
printf("--------------\n");
for (int i = 0; i < filter->num_node; i++)
{
printf("key = %d valid = %d\n", filter->key[i], filter->valid[i]);
}
}
测试代码:
#include "pulse_filter.h"
int main()
{
int filter = pulse_filter_create(2, 10, 0);
int data[10] = {205, 205, 206, 207, 250, 238, 209, 210, 210, 211};
printf("最大过滤2个脉冲, 限幅为10\n");
int output = 0;
for (int i = 0; i < 10; i++)
{
pulse_filter_write(filter, data[i]);
output = pulse_filter_read(filter);
if (data[i] == output)
{
printf("input:%d output:%d\n", data[i], output);
}
else
{
printf("input:%d -->filter output:%d\n", data[i], output);
}
}
printf("-----------------------\n");
int data1[10] = {205, 205, 206, 207, 250, 245, 240, 242, 243, 242};
output = 0;
for (int i = 0; i < 10; i++)
{
pulse_filter_write(filter, data1[i]);
output = pulse_filter_read(filter);
if (data1[i] == output)
{
printf("input:%d output:%d\n", data1[i], output);
}
else
{
printf("input:%d -->filter output:%d\n", data1[i], output);
}
}
getchar();
return 0;
}
测试输出:
最大过滤2个脉冲, 限幅为10
input:205 output:205
input:205 output:205
input:206 output:206
input:207 output:207
input:250 -->filter output:207
input:238 -->filter output:207
input:209 output:209
input:210 output:210
input:210 output:210
input:211 output:211
-----------------------
input:205 output:205
input:205 output:205
input:206 output:206
input:207 output:207
input:250 -->filter output:207
input:245 -->filter output:207
input:240 -->filter output:207
input:242 output:242
input:243 output:243
input:242 output:242
创建滤波器时需要写入一个周期值:
/**
* @brief 创建脉冲滤波器
* @param num_filter_pulse: 过滤的脉冲数
* @param max_delta: 最大偏差值
* @param cycle: 键值周期.如果为0表示没有周期
* @return 过滤器索引
*/
int pulse_filter_create(int num_filter_pulse, int max_delta, int cycle);
cycle用于周期数时使用。比如在一个周期为8s的校时系统中,则1s和7s的最小差值是2s而不是6s。当cycle为0时,表示周期无效。