使用循环缓冲区数组实现运行平均值

时间:2013-10-26 02:41:16

标签: c arrays

我试图实现一个循环缓冲区,以平均由嵌入式控制器上运行的C中的压力传感器生成的数据点流。想法是将最后N个压力读数存储在缓冲器中,同时保持缓冲器的运行总和。平均值= sum / N.应该是微不足道的。

但是,我看到的平均值是一个在压力读数附近开始的值(我用一个典型的值预加载缓冲寄存器),但随后趋向零。如果我也显示总和,它也会渐近地降为零。如果压力发生变化,平均值会在压力变化的方向上远离零点,但一旦压力稳定,就会恢复到零趋势。

如果有人能够发现我正在制作的错误,那将非常有用。

    #define ARRAYSIZE 100

    double Sum;                       // variable for running sum
    double Average;                   // variable for average
    double PressureValue[ARRAYSIZE];  // declare value array
    int i;                            // data array index

    int main(void) {

      while (1) 
      {
        if (i == ARRAYSIZE) i = 0;       // test index, reset if it reaches the upper boundary
        Sum = Sum - PressureValue[i];    // subtract the old datapoint from running sum
        PressureValue[i] = PRESSURE;     // replace previous loop datapoint with new data
        Sum = Sum + PressureValue[i];    // add back the new current value to the running sum
        Average = Sum / ARRAYSIZE;       // calculate average value = SUM / ARRAYSIZE
        ++i;                             // increment index
      }                                  // end while loop

    }                                    // end main

平均代码发生在中断处理程序中;我通过I2C读取压力传感器的数据,并在每个I2C通信阶段结束时触发中断。在最后阶段,在检索到包含压力数据的四个字节之后,将它们组合成一个完整的读数,然后转换为PRESSURE变量中包含的PSI中的十进制读数。

显然,这不是直接从我的代码剪切和粘贴,但我不希望任何人不得不涉及整个事情,所以我把它限制在相关的东西计算平均值,并将变量名称更改为更具可读性。不过,我无法发现我做错了什么。

感谢您的关注!

道格G。

2 个答案:

答案 0 :(得分:1)

我没有看到你的代码有任何明显的错误,但正如你所说,你没有提供所有这些,所以谁知道其余部分发生了什么(特别是,如何/如果你正在初始化iSum),但以下对我来说很好,这与您的算法基本相同:

#include <stdio.h>
#include <stddef.h>

double PressureValue[8];
double Pressures[800];

int main(void) {
    const size_t array_size = sizeof(PressureValue) / sizeof(PressureValue[0]);
    const size_t num_pressures = sizeof(Pressures) / sizeof(Pressures[0]);
    size_t count = 0, i = 0;
    double average = 0;


    /*  Initialize PressureValue to {0, 1, 2, 3, ...}  */

    for ( size_t n = 0; n < array_size; ++n ) {
        PressureValue[n] = n;
    }
    double sum = ((array_size - 1) / (double) 2) * array_size;

    /*  Initialize pressures to repeats of PressureValue  */

    for ( size_t n = 0; n < num_pressures; ++n ) {
        Pressures[n] = n % array_size;
    }

    while ( count < num_pressures ) {
        if ( i == array_size )
            i = 0;
        sum -= PressureValue[i];
        PressureValue[i] = Pressures[count++];
        sum += PressureValue[i++];
    }

    average = sum / array_size;

    printf("Sum is %f\n", sum);
    printf("Counted %zu pressures\n", count);
    printf("Average is %f\n", average);

    return 0;
}

输出:

paul@local:~/src/c/scratch$ ./pressure
Sum is 28.000000
Counted 800 pressures
Average is 3.500000
paul@local:~/src/c/scratch$

还有一种可能性,当你说它们“转换为PRESSURE变量中包含的PSI中的十进制读数”时,就此而言,确保你没有将事物截断为零因为整数除法。如果你增加更多的东西“趋势为零”,那就是我立即怀疑的东西。例如,将华氏温度转换为摄氏温度的典型错误是写c = (f - 32) * (5 / 9)(5 / 9)每次都会截断为零,并且总是留给您c == 0

另外,作为一般规则,我理解你“不希望任何人不得不涉及整个事情”,但是你会惊讶地发现真正的问题多少次都不在代码部分你认为它是。这就是为什么提供SSCCE以确保您可以缩小代码范围并实际隔离和重现问题的重要性。如果您尝试缩小代码范围并发现不能隔离并重现问题,那么几乎可以肯定您的问题不是由您认为导致它的问题引起的。

答案 1 :(得分:0)

您的代码也可能完全按预期工作。如果您使用此循环之外的典型值预加载数组,然后运行此代码,您将获得您描述的行为。如果您正在预加载阵列,请确保您正在预加载总和平均值,否则您实际上是在预加载值作为大气压力的情况下测量表压。