Python 中的单位转换

发布于 2024-08-19 03:55:36 字数 379 浏览 7 评论 0原文

我正在开发一个项目,让用户随着时间的推移跟踪不同的数据类型。基本思想的一部分是用户应该能够使用他们需要的任何单位输入数据。我一直在研究这两个单元:

http://pypi.python.org/pypi/units/< /a>

和数量:

http://pypi.python.org/pypi/quantities/

但是我不确定最好的方法。据我所知,数量更复杂,但包含更好的初始单位列表。

I'm working on a project that lets users track different data types over time. Part of the base idea is that a user should be able to enter data using any units that they need to. I've been looking at both units:

http://pypi.python.org/pypi/units/

and quantities:

http://pypi.python.org/pypi/quantities/

However I'm not sure the best way to go. From what I can tell, quantities is more complex, but includes a better initial list of units.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

沙与沫 2024-08-26 03:55:36

我赞赏在科学计算应用中使用显式单位。使用明确的单位就像刷牙一样。它预先增加了一些乏味,但从长远来看,您获得的类型安全可以节省很多麻烦。比如说,不要将价值 1.25 亿美元的轨道飞行器撞向行星

您还应该查看其他两个 python 单位/数量包:

Unum

科学.物理。 PhysicalQuantity

我曾经研究过Scientific.Physics.PhysicalQuantity。它不能完全满足我的需求,但可能会满足你的需求。从您的简短描述中很难判断您需要哪些功能。

我最终编写了自己的用于单位转换和维度分析的 python 包,但它尚未正确打包以供发布。我们在 OpenMM 系统的 Python 绑定中使用我的单位系统来实现 GPU 加速分子力学。您可以浏览我的 python 单元代码的 svn 存储库:

SimTK python 单元

最终我打算将其打包分配。如果您觉得有趣,请告诉我。这可能会激励我更快地打包它。我在设计 SimTK python 单位系统时寻找的功能包括以下内容:

  1. 单位内部不一定以 SI 单位存储。这对我来说非常重要,因为对我们来说一个重要的应用领域是分子尺度。在内部使用 SI 单位可能会导致常用分子力计算中的指数溢出。在内部,所有单位系统在 SimTK 中都同样重要。
  2. 我想要与 Boost.Units 类似的功能和灵活性C++ 系统。既因为我熟悉该系统,也因为它是在一大群才华横溢的工程师的审查下设计的。 Boost.Units 是一个精心设计的第二代维度分析系统。因此,我可能会认为 SimTK 单位系统是第三代系统:)。请注意,虽然 Boost.Units 是一个没有运行时成本的“零开销”系统,但所有 Python 数量实现(包括 SimTK 单位)可能都会产生运行时成本。
  3. 我想要与 numpy 数组兼容的维度数量,但不一定需要 python numpy 包。换句话说,数量可以基于 numpy 数组或内置的 python 类型。

哪些功能对您来说很重要?

I applaud use of explicit units in scientific computing applications. Using explicit units is analogous brushing your teeth. It adds some tedium up front, but the type safety you get can save a lot of trouble in the long run. Like, say, not crashing $125 million orbiters into planets.

You should also probably check out these two other python unit/quantity packages:

Unum

Scientific.Physics.PhysicalQuantity

I once investigated Scientific.Physics.PhysicalQuantity. It did not quite meet my needs, but might satisfy yours. It's hard to tell what features you need from your brief description.

I ended up writing my own python package for unit conversion and dimensional analysis, but it is not properly packaged for release yet. We are using my unit system in the python bindings for our OpenMM system for GPU accelerated molecular mechanics. You can browse the svn repository of my python units code at:

SimTK python units

Eventually I intend to package it for distribution. If you find it interesting, please let me know. That might motivate me to package it up sooner. The features I was looking for when I was designing the SimTK python units system included the following:

  1. Units are NOT necessarily stored in terms of SI units internally. This is very important for me, because one important application area for us is at the molecular scale. Using SI units internally can lead to exponent overflow in commonly used molecular force calculations. Internally, all unit systems are equally fundamental in SimTK.
  2. I wanted similar power and flexibility to the Boost.Units system in C++. Both because I am familiar with that system, and because it was designed under the scrutiny of a large group of brilliant engineers. Boost.Units is a well crafted second generation dimensional analysis system. Thus I might argue that the SimTK units system is a third generation system :). Be aware that while Boost.Units is a "zero overhead" system with no runtime cost, all python quantity implementations, including SimTK units, probably exact a runtime cost.
  3. I want dimensioned Quantities that are compatible with numpy arrays, but do not necessarily require the python numpy package. In other words, Quantities can be based on either numpy arrays or on built in python types.

What features are important to you?

只有影子陪我不离不弃 2024-08-26 03:55:36

Pint 最近进入了这个领域。有人愿意分享他们的经验吗?看起来不错。仅供参考:看起来 Pint 将在不久的将来与 Uncertainties 集成

Pint has recently come onto the field. Anybody care to share their experiences? Looks good. FYI: It looks like Pint will be integrated with Uncertainties in the near future.

九厘米的零° 2024-08-26 03:55:36

yt-project 中还有另一个名为 unyt 的包。 unyt 的作者承认 Pint 和 astropy.units 的存在。支持与这些其他包之间的转换。

unyt 的卖点是速度。它比其他两个要快。这篇论文中对单元包的几个基准进行了比较。

对于那些痴迷于性能的人来说,这些基准测试令人失望。 :-( 使用任何这些单位系统的计算速度都会大大减慢。对于具有 1000 个条目的数组,速度减慢系数为 6-10(对于较小的数组更糟)。

免责声明:我不隶属于 unyt ,我只是想分享一下我学到的关于单位系统的知识。

There is another package called unyt from the yt-project. The authors of unyt acknowledge the existence of Pint and astropy.units. Conversions from and to these other packages is supported.

The selling point of unyt is speed. It is faster than the other two. The unit packages are compared in several benchmarks in this paper.

The benchmarks are disappointing for anyone obsessed with performance. :-( The slowdown of calculations with any of these unit systems is large. The slowdown factor is 6-10 for arrays with 1000 entries (worse for smaller arrays).

Disclaimer: I am not affiliated with unyt, I just want to share what I learned about unit systems.

一口甜 2024-08-26 03:55:36

请注意,数量 对温度的支持非常差:

>>> (100 * pq.degC).rescale(pq.degF)
array(179.99999999999997) * degF
>>> (0 * pq.degC).rescale(pq.degF)
array(0.0) * degF

0 摄氏度不是 0 华氏度。他们的框架不支持任何类型的转换,而不仅仅是乘以一个因子。

Note that quantities has very bad support for temperature:

>>> (100 * pq.degC).rescale(pq.degF)
array(179.99999999999997) * degF
>>> (0 * pq.degC).rescale(pq.degF)
array(0.0) * degF

0 degrees Celsius isn't 0 degrees Fahrenheit. Their framework doesn't support any kind of conversion that isn't just multiplying by a factor.

甲如呢乙后呢 2024-08-26 03:55:36

我很惊讶还没有人提到 SymPy。 SymPy 是一个成熟且维护良好的 Python 符号数学库,而且还是一个NumFOCUS 赞助的项目。

它有一个 Physics 模块,其中包含许多有用的类和函数,用于“解决问题”在物理学中”。与您最相关的是,它有一个 Unit 子模块我认为包含您需要的一切;只需阅读优秀的文档即可。

I am surprised that nobody mentioned SymPy yet. SymPy is a mature and well-maintained symbolic mathematics library for Python that is moreover a NumFOCUS-sponsored project.

It has a Physics module with many useful classes and functions for "solving problems in physics". Most relevant for you, it has a Unit sub-module that contains everything you need, I think; just read the excellent documentation.

凉栀 2024-08-26 03:55:36

您可能想查看一个名为 natu 的新软件包。它解决了@ChristopherBruns 列出的三个问题。它可以在 PyPI 中找到。

我是该软件包的作者,非常感谢任何意见或建议。

You may want to look at a new package called natu. It addresses the three issues that @ChristopherBruns listed. It's available in PyPI.

I'm the author of that package, and I'd appreciate any comments or suggestions.

旧情勿念 2024-08-26 03:55:36

看起来另一个包也可以做到这一点,由 web2py 的 Massimo DiPierro 编写,名为 Buckingham

另外值得注意的是,Brian 遇到这样的事情已经有一段时间了。

It looks like another package has come out for doing this as well, written by Massimo DiPierro of web2py fame, called Buckingham.

Also of note, Brian has had something like this for some time.

|煩躁 2024-08-26 03:55:36

想要提及 units 包,它是 Astropy 包的一部分。

它维护良好,易于使用,并具有所有基本单位(以及天体物理学相关单位)。
它提供了单位和数量的工具。还有一个用于物理常量的模块。

Thought to mention the units package which is part of the Astropy package.

It's well maintained, easy to use, and has all the basic units (as well as astrophysics-related units).
It provides tools for both units and quantities. And there's also a module for physical constants.

樱花细雨 2024-08-26 03:55:36

我想指出一个单独的库来处理单位: Barril

https://github.com/ESSS/ barril

文档位于:https://barril.readthedocs.io/en/latest/< /a>

虽然它确实支持通过计算创建“随机”单位(例如 Pint、unum 等),但它更适合拥有单位数据库(库默认具有该数据库 - 请参阅:https://barril.readthedocs.io/en/latest/units.html 和实现: https://github.com/ESSS/barril /blob/master/src/barril/units/posc.py),然后就可以根据相关单位进行查询和转换。

它支持的一件事在这方面有很大不同,那就是处理“无量纲”的单位转换——例如 m3/m3(即:每卷的体积),然后转换为 < code>cm3/m3 并保持尺寸。

即:品脱:

>>> import pint
>>> ureg = pint.UnitRegistry()
>>> m = ureg.meter
>>> v = 1 \* (m\*3)/(m\*3)
>>> v
<Quantity(1.0, 'dimensionless')>

然后,在那之后(据我所知),在知道它是 m3/m3 的情况下,实际上不可能正确地进行额外的单位转换。

在 barril: 中,

>>> from barril.units import Scalar
>>> a = Scalar(3, 'm3/m3')
>>> a.GetValue('cm3/m3')
3000000.0
>>> a.category
'volume per volume'
>>> a.unit
'm3/m3'

诸如 a.GetValue('m3') (具有无效值)会给出错误,表明转换实际上无效。

单位数据库(最初基于 POSC 计量单位词典)更适合石油和天然气行业。气场,不过在气场之外应该也能用。

I'd like to point to a separate library for dealing with units: Barril

https://github.com/ESSS/barril

Docs at: https://barril.readthedocs.io/en/latest/

While it does have support for creating "random" units from computation (such as Pint, unum, etc), it's more tailored to having a database of units (which the library has by default -- see: https://barril.readthedocs.io/en/latest/units.html and the implementation: https://github.com/ESSS/barril/blob/master/src/barril/units/posc.py) and then you can query and transform based on the related units.

One thing it supports that does a lot of difference in that regard is dealing with unit conversions which would be "dimentionless" -- such as m3/m3 (i.e.:volume per volume) and then converting to cm3/m3 and keeping the dimension.

i.e.: in pint:

>>> import pint
>>> ureg = pint.UnitRegistry()
>>> m = ureg.meter
>>> v = 1 \* (m\*3)/(m\*3)
>>> v
<Quantity(1.0, 'dimensionless')>

And then, after that (as far as I know), it's not really possible to do additional unit conversions properly knowing that it was m3/m3.

In barril:

>>> from barril.units import Scalar
>>> a = Scalar(3, 'm3/m3')
>>> a.GetValue('cm3/m3')
3000000.0
>>> a.category
'volume per volume'
>>> a.unit
'm3/m3'

and something as a.GetValue('m3') (with an invalid value) would give an error saying that the conversion is actually invalid.

The unit database (which was initially based on the POSC Units of Measure Dictionary) is a bit more tailored for the Oil & Gas field, but should be usable outside of it too.

给不了的爱 2024-08-26 03:55:36

我认为您应该使用数量,因为数量有一些与之关联的单位。

例如,压力是可以输入并转换为不同单位(Pa、psi、atm 等)的量。也许您可以为您的应用程序创建新的数量细节。

I think you should use quantities, because a quantity has some units associated with it.

Pressure, for example, will be a quantity that could be entered and converted in and to different units (Pa, psi, atm, etc). Probably you could create new quantities specifics for your application.

未央 2024-08-26 03:55:36

我首选的软件包是 QuantiPhy。它采用了与大多数其他包不同的方法。对于 QuantiPhy,单位只是字符串,并且该包主要在读取或写入数量时使用。因此,将其合并到您的软件中要容易得多。 QuantiPhy 在创建数量以及将其渲染为字符串时都支持单位和比例因子转换。下面是一个读取并写入时间和温度表的示例,在传入时将分钟/°F 转换为秒/K,并在传出时转换回原始单位:

>>> from quanitphy import Quantity

>>> rawdata = '0 450, 10 400, 20 360'
>>> data = []
>>> for pair in rawdata.split(','):
...     time, temp = pair.split()
...     time = Quantity(time, 'min', scale='s')
...     temp = Quantity(temp, '°F', scale='K')
...     data += [(time, temp)]

>>> for time, temp in data:
...     print(f'{time:9q} {temp:9q}')
      0 s  505.37 K
    600 s  477.59 K
   1.2 ks  455.37 K

>>> for time, temp in data:
...     print(f"{time:<7smin} {temp:s°F}")
0 min   450 °F
10 min  400 °F
20 min  360 °F

My preferred package is QuantiPhy. It takes a different approach than most other packages. With QuantiPhy the units are simply strings, and the package is largely used when reading or writing quantities. As such, it much easier to incorporate into your software. QuantiPhy supports unit and scale factor conversion both when creating quantities and when rendering them to strings. Here is an example that reads and then writes a table of times and temperatures, converting from minutes/°F to seconds/K on the way in and back to the original units on the way out:

>>> from quanitphy import Quantity

>>> rawdata = '0 450, 10 400, 20 360'
>>> data = []
>>> for pair in rawdata.split(','):
...     time, temp = pair.split()
...     time = Quantity(time, 'min', scale='s')
...     temp = Quantity(temp, '°F', scale='K')
...     data += [(time, temp)]

>>> for time, temp in data:
...     print(f'{time:9q} {temp:9q}')
      0 s  505.37 K
    600 s  477.59 K
   1.2 ks  455.37 K

>>> for time, temp in data:
...     print(f"{time:<7smin} {temp:s°F}")
0 min   450 °F
10 min  400 °F
20 min  360 °F
笨笨の傻瓜 2024-08-26 03:55:36

我发现单位套餐超出了我的预期。不需要太多代码就可以开始构建自己的函数来引用很少的基本数字。此外,它还强制您进行尺寸分析以防止错误。

def FtoC(Tf):
    return (Tf-32)*5/9
def CtoF(Tc):
    return 9*Tc/5+32
def CtoK(Tc):
    return Tc+273.15
def INCHtoCM(Inch):
    return 2.54 * Inch
def CMtoINCH(cm):
    return cm / INCHtoCM(1)
def INCHtoMETER(inch):
    return .01*INCHtoCM(inch)
def FOOTtoMETER(foot):
    return INCHtoMETER(12*foot)
def METERtoINCH(Meter):
    return CMtoINCH(100 * Meter)
def METERtoFOOT(Meter):
    return METERtoINCH(Meter)/12
def M3toINCH3(M3):
    return (METERtoINCH(M3))**3
def INCH3toGALLON(Inch3):
    return Inch3 / 231
def M3toGALLON(M3):
    return INCH3toGALLON(M3toINCH3(M3))
def KG_M3toLB_GALLON(KGperM3):
    return KGtoLBM(KGperM3) / M3toGALLON(1)
def BARtoPASCAL(bar):
    return 100000 * bar
def KGtoLBM(kilogram):
    return kilogram * 2.20462262185
def LBMtoKG(lbm):
    return lbm/KGtoLBM(1)
def NEWTONtoLBF(newton):
    return newton * KGtoLBM(1) * METERtoFOOT(1) / STANDARD_GRAVITY_IMPERIAL()
def LBFtoNEWTON(lbf):
    return lbf * STANDARD_GRAVITY_IMPERIAL() * LBMtoKG(1) * FOOTtoMETER(1)
def STANDARD_GRAVITY_IMPERIAL():
    return 32.174049
def STANDARD_GRAVITY_SI():
    return 9.80665
def PASCALtoPSI(pascal):
    return pascal * NEWTONtoLBF(1) / METERtoINCH(1)**2
def PSItoPASCAL(psi):
    return psi * LBFtoNEWTON(1) / INCHtoMETER(1)**2

然后假设您想要绘制 1,3 丁二烯 @44 F 的静态水头压力并使用 PSI 计量表,因为您住在美国,但密度表采用 SI 单位,因为它们应该是...... ......................

# butadiene temperature in Fahrenheit
Tf = 44

# DIPPR105 Equation Parameters (Density in kg/m3, T in K)
# valid in temperature 165 to 424 Kelvin
A=66.9883
B=0.272506
C=425.17
D=0.288139

# array of pressures in psi
Pscale = np.arange(0,5,.1, dtype=float)
Tk = CtoK(FtoC(44))
Density = A / (B**(1+(1-Tk/C)**D)) # KG/M3
Height = [PSItoPASCAL(P) / (Density * STANDARD_GRAVITY_SI()) for P in Pscale]
Height_inch =  METERtoINCH(1) * np.array(Height, dtype=np.single)

I find the units packages to be more than what want. It doesn't take much code to start building your own functions that refer back to the very few basic fundamental numbers. Also, It forces you to do the dimensional analysis to prevent errors.

def FtoC(Tf):
    return (Tf-32)*5/9
def CtoF(Tc):
    return 9*Tc/5+32
def CtoK(Tc):
    return Tc+273.15
def INCHtoCM(Inch):
    return 2.54 * Inch
def CMtoINCH(cm):
    return cm / INCHtoCM(1)
def INCHtoMETER(inch):
    return .01*INCHtoCM(inch)
def FOOTtoMETER(foot):
    return INCHtoMETER(12*foot)
def METERtoINCH(Meter):
    return CMtoINCH(100 * Meter)
def METERtoFOOT(Meter):
    return METERtoINCH(Meter)/12
def M3toINCH3(M3):
    return (METERtoINCH(M3))**3
def INCH3toGALLON(Inch3):
    return Inch3 / 231
def M3toGALLON(M3):
    return INCH3toGALLON(M3toINCH3(M3))
def KG_M3toLB_GALLON(KGperM3):
    return KGtoLBM(KGperM3) / M3toGALLON(1)
def BARtoPASCAL(bar):
    return 100000 * bar
def KGtoLBM(kilogram):
    return kilogram * 2.20462262185
def LBMtoKG(lbm):
    return lbm/KGtoLBM(1)
def NEWTONtoLBF(newton):
    return newton * KGtoLBM(1) * METERtoFOOT(1) / STANDARD_GRAVITY_IMPERIAL()
def LBFtoNEWTON(lbf):
    return lbf * STANDARD_GRAVITY_IMPERIAL() * LBMtoKG(1) * FOOTtoMETER(1)
def STANDARD_GRAVITY_IMPERIAL():
    return 32.174049
def STANDARD_GRAVITY_SI():
    return 9.80665
def PASCALtoPSI(pascal):
    return pascal * NEWTONtoLBF(1) / METERtoINCH(1)**2
def PSItoPASCAL(psi):
    return psi * LBFtoNEWTON(1) / INCHtoMETER(1)**2

Then let's say you want to plot the static head pressure of 1,3 Butadiene @44 F and use gauges in PSI because you live in the US but the density tables are in SI units as they should be........................

# butadiene temperature in Fahrenheit
Tf = 44

# DIPPR105 Equation Parameters (Density in kg/m3, T in K)
# valid in temperature 165 to 424 Kelvin
A=66.9883
B=0.272506
C=425.17
D=0.288139

# array of pressures in psi
Pscale = np.arange(0,5,.1, dtype=float)
Tk = CtoK(FtoC(44))
Density = A / (B**(1+(1-Tk/C)**D)) # KG/M3
Height = [PSItoPASCAL(P) / (Density * STANDARD_GRAVITY_SI()) for P in Pscale]
Height_inch =  METERtoINCH(1) * np.array(Height, dtype=np.single)
你怎么这么可爱啊 2024-08-26 03:55:36

另一个值得一提的软件包是 Axiompy

安装:pip install axiompy

from axiompy import Units
units = Units()
print(units.unit_convert(3 * units.metre, units.foot))
>>> <Value (9.84251968503937 <Unit (foot)>)>

Another package to mention is Axiompy.

Installation: pip install axiompy

from axiompy import Units
units = Units()
print(units.unit_convert(3 * units.metre, units.foot))
>>> <Value (9.84251968503937 <Unit (foot)>)>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文