Magnitude, a python library for computing with physical quantities
Magnitude implements efficient computation with physical quantities. It allows you to do mathematical operations with them as if they were numbers, taking care of the units behind the scenes.
A physical quantity is a number with a unit, like 10 km/h. Units are specified as strings. They can be any of the SI units, plus a bunch of non-SI, bits, dollars, and any combination of them. They can include the standard SI prefixes. Magnitude can operate with physical quantities, parse their units, and print them. You don't have to worry about unit consistency or conversions; everything is handled transparently.
By default output is done either in the unit with which the Magnitude object has been created, or in basic SI units, but you can specify any output unit, as long as it can be reduced to the basic units of the physical quantity.
All standard prefixes are understood, from yocto to yotta and from kibi to exbi.
Download
It is hosted at Github. Either clone it with git:
git clone git://github.com/juanre/magnitude.git
Installation
In the magnitude directory,
sudo python setup.py install
Examples
>>> from magnitude import mg >>> print mg(10, 'm/s') ** 2 100.0000 m2 / s2 >>> print (mg(10, 'm') * 2 / (10, 'm/s2')).sqrt() 1.4142 s >>> tsq = mg(10, 'm') * 2 / (10, 'm/s2') >>> print tsq ** 0.5 1.4142 s >>> print mg(1, "lightyear") / mg(1, "c") >>> 31557600.0000 s >>> y = mg(1, "lightyear") / (1, "c") >>> print y.ounit("year") 1.0000 year >>> print y.ounit('day') >>> print yd 365.2500 day >>> power = mg(100, 'kg') * (2, 'gravity') * (5, 'km/h') >>> print power 2724.0694 m2 kg / s3 >>> print power.ounit('mW') 2724069.4444 mW >>> print power.ounit('kW') 2.7241 kW
Reference
Available units
The basic units understood by the magnitude module are:
| indicator | meaning |
|---|---|
| $ | dollar ('dollar' is also acceptable) |
| A | ampere |
| b | bit |
| cd | candela |
| K | degrees Kelvin |
| kg | kilograms |
| m | meters |
| mol | amount of substance |
| s | seconds |
From these basic units you can derive many other units. The magnitude package predefines these derived units:
# Magnitudes for the base SI units new_mag('m', Magnitude(1.0, m=1)) new_mag('s', Magnitude(1.0, s=1)) new_mag('K', Magnitude(1.0, K=1)) new_mag('kg', Magnitude(1.0, kg=1)) new_mag('A', Magnitude(1.0, A=1)) new_mag('mol', Magnitude(1.0, mol=1)) new_mag('cd', Magnitude(1.0, cd=1)) new_mag('$', Magnitude(1.0, dollar=1)) new_mag('dollar', Magnitude(1.0, dollar=1)) new_mag('b', Magnitude(1.0, b=1)) # bit # Magnitudes for derived SI units new_mag('B', Magnitude(8.0, b=1)) new_mag('rad', Magnitude(1.0)) # radian new_mag('sr', Magnitude(1.0)) # steradian new_mag('Hz', Magnitude(1.0, s=-1)) # hertz new_mag('g', Magnitude(1e-3, kg=1)) # gram new_mag('N', Magnitude(1.0, m=1, kg=1, s=-2)) # newton new_mag('Pa', Magnitude(1.0, m=-1, kg=1, s=-2)) # pascal new_mag('J', Magnitude(1.0, m=2, kg=1, s=-2)) # joule new_mag('W', Magnitude(1.0, m=2, kg=1, s=-3)) # watt new_mag('C', Magnitude(1.0, s=1, A=1)) # coulomb new_mag('V', Magnitude(1.0, m=2, kg=1, s=-3, A=-1)) # volt new_mag('F', Magnitude(1.0, m=-2, kg=-1, s=4, A=2)) # farad, C/V new_mag('ohm', Magnitude(1.0, m=2, kg=1, s=-3, A=-2)) # ohm, V/A new_mag('S', Magnitude(1.0, m=-2, kg=-1, s=3, A=2)) # siemens, A/V, el cond new_mag('Wb', Magnitude(1.0, m=2, kg=1, s=-2, A=-1)) # weber, V.s, mag flux new_mag('T', Magnitude(1.0, kg=1, s=-2, A=-1)) # tesla, Wb/m2, mg flux dens new_mag('H', Magnitude(1.0, m=2, kg=1, s=-2, A=-2)) # henry, Wb/A, induct. new_mag('degC', Magnitude(1.0, K=1)) # celsius, !! new_mag('lm', Magnitude(1.0, cd=1)) # lumen, cd.sr (=cd)), luminous flux new_mag('lux', Magnitude(1.0, m=-2, cd=1)) # lux, lm/m2, illuminance new_mag('Bq', Magnitude(1.0, s=-1)) # becquerel, activity of a radionulide new_mag('Gy', Magnitude(1.0, m=2, s=-2)) # gray, J/kg, absorbed dose new_mag('Sv', Magnitude(1.0, m=2, s=-2)) # sievert, J/kg, dose equivalent new_mag('kat', Magnitude(1.0, s=-1, mol=1)) # katal, catalitic activity # Non-SI but almost: new_mag('b', Magnitude(8.0, b=1)) # byte, note that B is Bel, as in dB ### Other # length new_mag("'", Magnitude(0.3048, m=1)) # feet new_mag('ft', Magnitude(0.3048, m=1)) # feet new_mag('inch', Magnitude(0.0254, m=1)) # inch new_mag('"', Magnitude(0.0254, m=1)) # inch new_mag('lightyear', Magnitude(2.99792458e8 * 365.25 * 86400, m=1)) # volume new_mag('l', Magnitude(0.001, m=3)) # time # year is tropical year, "the mean interval between vernal # equinoxes. Differs from the sidereal year by 1 part in 26000 # due to precession of the earth about its rotational axis # combined with precession of the perihelion of the earth's orbit" # (from units.dat). new_mag('year', Magnitude(31556925.974678401, s=1)) new_mag('day', Magnitude(86400, s=1)) new_mag('h', Magnitude(3600, s=1)) new_mag('min', Magnitude(60, s=1)) # Resolution new_mag('dpi', Magnitude(1.0 / 0.0254, m=-1)) new_mag('lpi', Magnitude(1.0 / 0.0254, m=-1)) # Velocity new_mag('ips', Magnitude(0.0254, m=1, s=-1)) new_mag('c', Magnitude(2.99792458e8, m=1, s=-1)) # Acceleration new_mag('gravity', Magnitude(9.80665, m=1, s=-2))
Two magnitudes have no units, 'rad' (radian - unit of plane angle) and 'sr' (steradian - unit of solid angle).
Any of the above units can be augmented with the following set of scale prefixes:
_prefix = {'y': 1e-24, # yocto 'z': 1e-21, # zepto 'a': 1e-18, # atto 'f': 1e-15, # femto 'p': 1e-12, # pico 'n': 1e-9, # nano 'u': 1e-6, # micro 'm': 1e-3, # mili 'c': 1e-2, # centi 'd': 1e-1, # deci 'k': 1e3, # kilo 'M': 1e6, # mega 'G': 1e9, # giga 'T': 1e12, # tera 'P': 1e15, # peta 'E': 1e18, # exa 'Z': 1e21, # zetta 'Y': 1e24, # yotta # Binary prefixes, approved by the International # Electrotechnical Comission in 1998. Since then, kb means # 1000 bytes; for 1024 bytes use Kib (note the capital K in # the binary version, and the lower case for the b of byte, # see comment in byte definition below). 'Ki': 2 ** 10, # Kibi (<- kilo, 10^3) 'Mi': 2 ** 20, # Mebi (<- mega, 10^6) 'Gi': 2 ** 30, # Gibi (<- giga, 10^9) 'Ti': 2 ** 40, # Tebi (<- tera, 10^12) 'Pi': 2 ** 50, # Pebi (<- peta, 10^15) 'Ei': 2 ** 60 # Exbi (<- exa, 10^18) }
Exported symbols
- Magnitude [class] — Numbers with units; math operations are overloaded
- mg(number, unit, ounit='') — Construct a Magnitude
- ensmg(m, unit='') — Tries to build a Magnitude out of something
- newmag(indicator, mag) — Intern a new magnitude with its name
- MagnitudeError [class] — Magnitude error handling
Defining new magnitudes
You can define new magnitudes by instantiating the Magnitude class. Suppose you want to define pounds as a magnitude and associate with it the unit 'lb'. A pound is 0.45359237 kilograms, so we have
>>> lb = Magnitude(0.45359237, kg=1)
To make it recognized automatically you also have to
introduce it to the system with new_mag. You can then
use it as you would any other predefined physical quantity:
>>> new_mag('lb', lb) >>> me = mg(180, 'lb') >>> print me.ounit('kg').toval() 81.6466266 >>> new_mag('mile', mg(160934.4, 'cm')) >>> print mg(100, 'mile/h').ounit('km/h') 160.9344 km/h
Bits and bytes (2009-11-03)
A previous version of the library used "bit" for bit and "b" for byte, leaving B for Bel. Following Michael Scheper's suggestion we follow now IEEE 1541 and use "b" for bit and "B" for byte. If the need arises I'll implement ad-hoc esupport for dB, but for the time being there is none.
More on units
This code was very much inspired by http://www.cs.utexas.edu/users/novak/units.html and its associated paper, http://www.cs.utexas.edu/users/novak/units95.html
The following online references provide more detail about physical units and the SI system.
Alternative unit libraries for Python
I haven't tested them; I wrote these comments several years ago after looking at the documentation.
- Unum looks well finished and is thoroughly documented. Good: allows you to define arbitrary units (magnitude only supports user-defined units as long as they are a combination of the base units). Bad: it looks like it doesn't handle prefixes, and it clutters your namespace with all its unit definitions (you end up with variables named M, S, etc. in your namespace).
- Scalar looks very similar to Unum, maybe not as well documented. Looks like it has exactly the same problems and advantages, plus the ability of running with units disabled (which should be good for performance).
- PhyisicalQuantities, part of ScientificPython, is very similar to magnitude. Same approach, essentially the same functionality, very similar API. Looks like it also clutters your namespace with unit names.
Subscribe 
blog comments powered by Disqus