3

我正在尝试实现一个循环缓冲区,以便对在嵌入式控制器上运行的 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。

4

2 回答 2

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以确保您可以缩小代码范围并实际隔离和重现问题的重要性。如果您尝试缩小代码范围并发现您无法隔离和重现问题,那么几乎可以肯定您的问题不是由您认为导致它的事情引起的。

于 2013-10-26T03:21:39.257 回答
0

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

于 2016-07-18T16:25:40.820 回答