Python中的单位转换
SymPy 是一个很棒的工具,可以在 Python 中进行单位转换:
>>> from sympy.physics import units
>>> 12. * units.inch / units.m
0.304800000000000
你也可以很简单地自己实现:
>>> units.BTU = 1055.05585 * units.J
>>> units.BTU
1055.05585*m**2*kg/s**2
不过,我无法把这个功能放到我的应用里,除非我能把摄氏度(绝对值)转换成开尔文、华氏度和兰氏度,或者它们的任意组合。
我想也许可以用这样的方式来实现:
units.degC = <<somefunc of units.K>>
但显然,这不是正确的方向。有没有什么建议,能让我在 SymPy 中干净利落地实现“偏移”类型的单位转换?
注意:我愿意尝试其他的单位转换模块,但除了Unum,我不知道还有其他的,而且我觉得它用起来很麻烦。
编辑:好的,现在我明白我想做的事是,首先确定要比较的两个量是否在同一个坐标系统中。(就像时间单位参考不同的纪元或时区,或者分贝和直流幅度之间的转换),然后进行适当的转换,再进行单位转换。有没有什么通用的坐标系统管理工具?那就太好了。
我假设 °F 和 °C 在表达式中总是指 Δ°F 和 Δ°C,但单独提及时则指绝对值。我在想是否有办法把 units.degF
变成一个函数,并加上一个装饰器 property()
来处理这两种情况。
但现在,我会设定 units.C == units.K
,并在文档中尽量明确地说明在处理绝对单位时要使用函数 convertCtoK(...)
和 convertFtoR(...)
。(开个玩笑,实际上我不会这样做。)
4 个回答
举个例子,看看它是怎么运作的:
>>> T(0*F) + 10*C
T(265.37222222222221*K) # or T(47767/180*K)
>>> T(0*F + 10*C)
T(283.15*K)
>>> 0*F + T(10*C)
T(283.15*K)
>>> 0*F + 10*C
10*K
>>> T(0*F) + T(10*C)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'absolute_temperature' and \
'absolute_temperature'
>>> T(0*F) - T(10*C)
T(245.37222222222223*K) # or T(44167/180*K)
>>> 0*F - 10*C
-10*K
Unum的文档里有一段很不错的说明,讲了为什么这个问题很难解决:
Unum在摄氏度(°C)和开尔文(K)之间的转换上做得不够好。这个问题被称为“虚假原点问题”:0°C被定义为273.15 K。这是一个特别麻烦的情况,因为一般来说,数值0在单位转换中是不受影响的,比如0 [米] = 0 [英里] = ...。但在摄氏度和开尔文的转换中,涉及到一个乘以1的因子和一个273.15 K的偏移量。而这个偏移量在当前版本的Unum中是无法处理的。
而且,未来的版本可能也不会解决这个问题,因为还有一个概念上的问题:这个偏移量应该在表示绝对温度时使用,但在表示温度差时就不应该使用。例如,温度上升1°C等于上升1 K。在用户心中,究竟是绝对温度还是相对温度是无法猜测的。对于其他单位来说,绝对和相对的区别并不重要,因为这不会影响转换规则。但Unum无法区分这两种情况。
从概念上看,试图用符号表示绝对温度转换的问题其实很容易理解。对于任何正常的相对单位,(x unit) * 2 == (x * 2) unit
——单位的数学运算是可交换的。但对于绝对温度,这种情况就不成立了——除了简单的温度转换外,做更复杂的运算就很困难。你最好把所有的计算都保持在开尔文中,只在代码的输入和输出时进行其他温度单位的转换。
我个人很喜欢Quantities这个库,因为它可以和NumPy很好地结合使用。不过,它只能处理相对温度,而不能处理绝对温度。