Arduino(浮点数)精度更高
Better precision with Arduino (floats)
我正在尝试在 Arduino 上进行 Steinhart-Hart 温度计算。等式是
我求解了 3 个方程组以获得 A、B 和 C 的值,它们是:
A = 0.0164872
B = -0.00158538
C = 3.3813e-6
当我将这些插入 WolframAlpha 以求解 T
时,我得到了一个有意义的开尔文值:
T=1/(0.0164872-0.00158538*log2(10000)+3.3813E-6*(log2(10000))^3) solve for T
T = 298.145 Kelvins = 77 Fahrenheit
然而,当我尝试在我的 Arduino 上使用这个等式时,我得到了一个非常错误的答案,我怀疑是因为双精度数不够精确。这是我正在使用的:
double temp = (1 / (A + B*log(R_therm) + C*pow(log(R_therm),3)));
取而代之的是 returns 222 开尔文,这太离谱了。
那么,我怎样才能在 Arduino 中进行这样的计算??非常感谢任何建议,谢谢。
是的,浮点运算在大多数 arduino 上的精度有限。
您是否考虑过使用固定精度?如果使用得当,这可能会给您带来更好的效果。然而,这样做的要求是具有相当窄的参数,并注意单位转换。
arduino 上的 unsigned long
也是 4 个字节,因此它最多可以包含 2^32-1
个数字。如果使用定点,您可能希望将此 1/T
替换为类似 100000/T
的内容,其中分子常数和 T 已根据所需精度进行缩放。
您还需要保留每个变量包含的小数位数的(心理或纸上)模型,以便优化运算顺序而不丢失精度。
对于 log2
函数,我怀疑它是开箱即用的整数。您可以转换结果或 reimplement it。这个问题有很多资源,甚至在 SO 上也是如此。
精度不是主要问题。甚至可以使用 float
和 powf()
。热敏电阻温度计算不 准确。毕竟温度肯定不比±0.1°C accurate。热敏电阻的自热是一个较大的因素。
OP 的 C 代码假定对数基数为 2,使用对数基数 e log()
因为常量是使用对数基数 2 导出的。
// double temp = (1 / (A + B*log(R_therm) + C*pow(log(R_therm),3)));
double temp = (1 / (A + B*log(R_therm)/log(2) + C*pow(log(R_therm)/log(2),3)));`
实施示例,可避免不必要的缓慢 pow()
调用。
static const inv_ln2 = 1.4426950408889634073599246810019;
double ln2_R = log(R_therm)*inv_ln2;
double temp = 1.0 / (A + ln2_R*(B + C*ln2_R*ln2_R));
我正在尝试在 Arduino 上进行 Steinhart-Hart 温度计算。等式是
我求解了 3 个方程组以获得 A、B 和 C 的值,它们是:
A = 0.0164872
B = -0.00158538
C = 3.3813e-6
当我将这些插入 WolframAlpha 以求解 T
时,我得到了一个有意义的开尔文值:
T=1/(0.0164872-0.00158538*log2(10000)+3.3813E-6*(log2(10000))^3) solve for T
T = 298.145 Kelvins = 77 Fahrenheit
然而,当我尝试在我的 Arduino 上使用这个等式时,我得到了一个非常错误的答案,我怀疑是因为双精度数不够精确。这是我正在使用的:
double temp = (1 / (A + B*log(R_therm) + C*pow(log(R_therm),3)));
取而代之的是 returns 222 开尔文,这太离谱了。
那么,我怎样才能在 Arduino 中进行这样的计算??非常感谢任何建议,谢谢。
是的,浮点运算在大多数 arduino 上的精度有限。
您是否考虑过使用固定精度?如果使用得当,这可能会给您带来更好的效果。然而,这样做的要求是具有相当窄的参数,并注意单位转换。
arduino 上的 unsigned long
也是 4 个字节,因此它最多可以包含 2^32-1
个数字。如果使用定点,您可能希望将此 1/T
替换为类似 100000/T
的内容,其中分子常数和 T 已根据所需精度进行缩放。
您还需要保留每个变量包含的小数位数的(心理或纸上)模型,以便优化运算顺序而不丢失精度。
对于 log2
函数,我怀疑它是开箱即用的整数。您可以转换结果或 reimplement it。这个问题有很多资源,甚至在 SO 上也是如此。
精度不是主要问题。甚至可以使用 float
和 powf()
。热敏电阻温度计算不 准确。毕竟温度肯定不比±0.1°C accurate。热敏电阻的自热是一个较大的因素。
OP 的 C 代码假定对数基数为 2,使用对数基数 e log()
因为常量是使用对数基数 2 导出的。
// double temp = (1 / (A + B*log(R_therm) + C*pow(log(R_therm),3)));
double temp = (1 / (A + B*log(R_therm)/log(2) + C*pow(log(R_therm)/log(2),3)));`
实施示例,可避免不必要的缓慢 pow()
调用。
static const inv_ln2 = 1.4426950408889634073599246810019;
double ln2_R = log(R_therm)*inv_ln2;
double temp = 1.0 / (A + ln2_R*(B + C*ln2_R*ln2_R));