A003-算法-滑动窗口队列(未测试)

一、 基础型


队列定义:

#define DATA_LIST_MAX  64

static uint8_t data_list[DATA_LIST_MAX] = {0};
static uint8_t data_index = 0;

数据进出:

uint8_t data_list_access(uint8_t data)
{
    uint8_t temp;
    data_index = (data_index >= _countof(data_list)) ? 0 : data_index;
    temp = data_list[data_index];
    data_list[data_index] = data;
    data_index++;
    return temp;
}

应用于均值滤波:

static uint8_t data_average = 0;

// ==========================================================================================================
// 初始化完成后,每次都将新值放入队列、并求出均值
// 
// 运算过程说明(假设队列长度为n = 8):
// 1、之前的均值age1 = (a0 + a1 + ... + a7) / n  // 包含ai
// 2、现在有了新值data_new,我们将它插入第i个位置、ai被替换成了data_new
//    那么此时的均值age2 = (a0 + a1 + ... + a7 + data_new) / n  // 不包含ai
//                       = (a0 + a1 + ... + a7 + data_new + ai - ai) / n
//                       = (a0 + a1 + ... + a7 + ai + data_new - ai) / n
//                       = age1 + (data_new- ai) / n
//    也就是说我们不需要每次都重新计算数据的和
// 3、有符号数不能用移位来优化除法,所以这里使用uint16_t 配合三目运算符来求差值
//    负数是以补码而不是原码的形式存储并参与运算,所以不能用移位替代除法
//    同时有符号数的操作也慢些
// 
// ==========================================================================================================
uint8_t data_list_average(uint8_t data)
{
    uint16_t data_old;
    uint16_t data_new = data;
    uint16_t average  = data_average;

    data_old  = data_list_access(data);
    if(data_new >= data_old)
    {
        average += (data_new - data_old) / _countof(data_list);  // 变大
    }
    else
    {
        average -= (data_old - data_new) / _countof(data_list);  // 变小(average遇到突然变得很小的数值怎么办。。。。。)
    }
    data_average = (uint8_t)average;
}


二、 公用型

多个环形队列公用同一组滑动窗口处理函数

队列定义:

typedef struct 
{
    uint8_t *list;  // 用于遍历队列
    uint8_t  size;
    uint8_t  index;
    uint8_t  average;
}T_DATA_LIST_ITEM, *pT_DATA_LIST_ITEM;

// 具体的某一个用户
#define DATA_LIST_USER01_MAX  64
static uint8_t ram_list_user01[DATA_LIST_USER01_MAX] = {0};

static T_DATA_LIST_ITEM list_user01 = { .list    = &ram_list_user01[0],  // 第一个元素
                                        .size    =  sizeof(ram_list_user01),
                                        .index   =  0, // 第一个元素
                                        .average =  0,
                                      };

数据进出:

uint8_t data_list_access(pT_DATA_LIST_ITEM p_list, uint8_t data)
{
    uint8_t temp;

    p_list->index = (p_list->index >= p_list->size) ? 0 : p_list->index;
    temp = *(p_list->list + p_list->index);
    *(p_list->list + p_list->index) = data;
    p_list->index++;
    return temp;
}

应用于均值滤波:

// ==========================================================================================================
// 初始化完成后,每次都将新值放入队列、并求出均值
// 
// 运算过程说明(假设队列长度为n = 8):
// 1、之前的均值age1 = (a0 + a1 + ... + a7) / n  // 包含ai
// 2、现在有了新值data_new,我们将它插入第i个位置、ai被替换成了data_new
//    那么此时的均值age2 = (a0 + a1 + ... + a7 + data_new) / n  // 不包含ai
//                     = (a0 + a1 + ... + a7 + data_new + ai - ai) / n
//                     = (a0 + a1 + ... + a7 + ai + data_new - ai) / n
//                     = age1 + (data_new- ai) / n
//    也就是说我们不需要每次都重新计算数据的和
// 3、avr gcc编译器不会优化有符号数的除法,所以这里使用uint8_t来求差值
//    负数是以补码而不是原码的形式存储并参与运算,所以不能用移位替代除法
//    同时有符号数的操作也慢些
// 
// ==========================================================================================================
vodi data_list_average(pT_DATA_LIST_ITEM p_list, uint8_t data)
{
    uint8_t data_old;
    uint8_t data_new = data;
    uint8_t average  = p_list->average;

    data_old  = data_list_access(p_list, data);
    if(data_new >= data_old)
    {
        average += (data_new - data_old) / p_list->size;  // 变大
    }
    else
    {
        average -= (data_old - data_new) / p_list->size;  // 变小(average遇到突然变得很小的数值怎么办。。。。。)
    }
    p_list->average = average;
}


使用举例:

data_list_average(&list_user01, get_data());


三、 普适型

struct中增加一个type参数来说明每个数据的长度,例如:type = sizeof(ram_list_user01[0])。
再使用void *list来指向任意类型的数据(类型强制转换:list = (void *)(&ram_list_user01[0])。
这样就可以处理任意类型的数据的滑动窗口了。
这属于面向对象的设计么……?


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值