Impulse filtering algorithm

Impulse filtering algorithm
 

This article blog link: http://blog.csdn.net/jdh99 , Author: jdh, reprint please specify.


Description:

The data collected by some sensors is basically accurate, but there are occasional errors. The impulse filtering algorithm designed in this paper can filter out these impulse interference.

Algorithm principle:

Create an array to store data, and each data has a validity flag. When there is new data, compare the difference with the previous valid data. If it is less than the threshold, it will be valid, and if it is greater than the threshold, it will be invalid. If there are too many invalid data, the algorithm is invalid and all data is considered valid.

The algorithm provides a read interface and can return the latest valid data.

Algorithm advantages:

The real-time performance is very high. When the data is correct, there is zero delay, and when the data is wrong or drastically changed, it will cause a delay. The algorithm is suitable for scenarios where the collected data has high reliability and only occasional errors.

 

Source code:


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]);
    }
}

 

Test code:

#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;
}

Test output:

最大过滤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

You need to write a period value when creating a filter:

/**
* @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 is used when the number of cycles is used. For example, in a timing system with a period of 8s, the minimum difference between 1s and 7s is 2s instead of 6s. When the cycle is 0, it means that the cycle is invalid.

 


 

Guess you like

Origin blog.csdn.net/jdh99/article/details/88113350