我有一个功能(如下所示),我需要一些建议。该函数返回适合(通过最小二乘法)到n个数据点的线的斜率。为了给你一个背景,我的项目是一个基于气压的高度计,它使用这个功能根据n个最近的高度 - 时间对确定速度。这些高度 - 时间对存储在2个全局数组中(times[]
和alts[]
)。
我的问题不是这种方法不起作用。它通常会。但有时候我会运行高度计,这个函数会返回值'inf'
,其中散布着一堆其他错误的值(我也看到过#N; NaN'但这种情况更为罕见)。我现在有一些怀疑的领域,但我想要一个全新的视角。以下是一些可能使用或未使用的上下文信息:
times[]
数组的类型为unsigned long
alts[]
数组的类型为float
n
是const int
,在本例中为n = 9
在ATMEGA328上,double
与float
相同.. Arduino-double
float velF() { // uses the last n data points, fits a line to them,
// and uses the slope of that line as the velocity at that moment
float sumTY = 0, sumT = 0, sumY = 0, sumT2 = 0;
for (int i = 0; i < n; i++) {
sumTY += (float)times[i] * alts[i] / 1000;
sumT += (float)times[i] / 1000;
sumY += alts[i];
sumT2 += (float)times[i] * times[i] / 1000000;
}
return (n*sumTY - sumT*sumY) / (n*sumT2 - sumT*sumT);
}
非常感谢任何帮助或建议!
答案 0 :(得分:2)
代码肯定是按零进行分割。
由于各种原因,n*sumT2 - sumT*sumT
将为零。 @John Bollinger在大多数情况下,除法的顶部(被除数)也将为零,并且返回值为零是可接受的。
float velF(void) {
float sumTY = 0, sumT = 0, sumY = 0, sumT2 = 0;
for (size_t i = 0; i < n; i++) {
// insure values are reasoable
assert(alts[i] >= ALT_MIN && alts[i] <= ALT_MAX);
assert(times[i] >= TIME_MIN && times[i] <= TIME_MAX);
sumTY += (float)times[i] * alts[i] / 1000;
sumT += (float)times[i] / 1000;
sumY += alts[i];
sumT2 += (float)times[i] * times[i] / 1000000;
}
float d = n*sumT2 - sumT*sumT;
if (d == 0) return 0;
return (n*sumTY - sumT*sumY) / d;
}
旁注:可以将分割因素分解,以提高准确性和速度。建议将最后一次计算执行为double
。
float velF(void) {
float sumTY = 0, sumT = 0, sumY = 0, sumT2 = 0;
for (size_t i = 0; i < n; i++) {
float tf = (float) times[i];
sumTY += tf * alts[i];
sumT += tf;
sumY += alts[i];
sumT2 += tf * tf;
}
double nd = n;
double sumTd = sumT;
double d = nd*sumT2 - sumTd*sumTd;
if (d == 0) return 0;
return (nd*sumTY - sumTd*sumY)*1000 / d;
}