我试图实现一个循环缓冲区,以平均由嵌入式控制器上运行的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。答案 0 :(得分:1)
我没有看到你的代码有任何明显的错误,但正如你所说,你没有提供所有这些,所以谁知道其余部分发生了什么(特别是,如何/如果你正在初始化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 %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)
您的代码也可能完全按预期工作。如果您使用此循环之外的典型值预加载数组,然后运行此代码,您将获得您描述的行为。如果您正在预加载阵列,请确保您正在预加载总和平均值,否则您实际上是在预加载值作为大气压力的情况下测量表压。