我正在尝试实现一个循环缓冲区,以便平均由嵌入式控制器上运行的C语言压力传感器生成的数据流。 这个想法是将最后N个压力读数存储在缓冲液中,同时保持缓冲液的运行总和。 平均值 = 总和/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中的十进制读数。
显然,这不是从我的代码中直接剪切和粘贴,但我不希望任何人必须涉足整个事情,所以我将其限制为与计算平均值相关的东西,并更改变量名称以使其更具可读性。 尽管如此,我还是看不出我做错了什么。
感谢您的关注!
道格·
我认为您的代码没有任何明显的问题,但正如您所说,您没有提供所有代码,所以谁知道其余部分发生了什么(特别是,如何/是否正在初始化i
和Sum
),但以下内容对我来说很好用,这基本上与您拥有的算法相同:
#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 %fn", sum);
printf("Counted %zu pressuresn", count);
printf("Average is %fn", 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 以确保您可以缩小代码范围并实际隔离和重现问题很重要的原因。如果您尝试缩小代码范围并发现无法隔离和重现问题,那么几乎可以肯定您的问题不是由您认为导致它的原因引起的。
您的代码也可能完全按预期工作。如果在此循环之外使用典型值预加载数组,然后运行此代码,则会得到所描述的行为。如果要预加载阵列,请确保预加载总和和平均值,否则实质上是在测量表压,并将预加载值作为大气压。