インパルスフィルタリングアルゴリズム
この記事のブログリンク:http://blog.csdn.net/jdh99、著者:jdh、転載を指定してください。
説明:
一部のセンサーによって収集されたデータは基本的に正確ですが、時折エラーが発生します。この論文で設計されたインパルスフィルタリングアルゴリズムは、これらのインパルス干渉をフィルタリングすることができます。
アルゴリズムの原則:
データを格納する配列を作成します。各データには有効性フラグがあります。新しいデータがある場合は、以前の有効なデータとの差を比較します。しきい値未満の場合は有効になり、しきい値を超える場合は無効になります。無効なデータが多すぎる場合、アルゴリズムは無効であり、すべてのデータが有効であると見なされます。
アルゴリズムは読み取りインターフェースを提供し、最新の有効なデータを返すことができます。
アルゴリズムの利点:
リアルタイムのパフォーマンスは非常に高く、データが正しい場合は遅延がゼロであり、データが間違っているか大幅に変更されている場合は遅延が発生します。このアルゴリズムは、収集されたデータの信頼性が高く、エラーが発生することがあるシナリオに適しています。
ソースコード:
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);
サイクルは、サイクル数が使用される場合に使用されます。たとえば、周期が8秒のタイミングシステムでは、1秒と7秒の最小差は6秒ではなく2秒です。サイクルが0の場合、サイクルが無効であることを意味します。