Unicon is a physical units conversion utility and a general purpose units handling library.
How To Obtain
Unicon is a simple well commented Python program. The single file, which contains the complete unit database and a test suite, is only 25kB. You can download it from this link:
The only dependency is Python 3.7+. No external libraries are used.
Quick Start For The Impatient
If you’re keen to play with this now and you want to try it without reading any of my boring prose, try this.
cd /tmp
wget http://xed.ch/p/unicon/unicon.py # Mac people can try curl.
python3 unicon.py 5_knot m/s
And that should produce something like this.
5_knot = 2.572222222222_m/s
Also consider running it with no arguments (or -h
or --help
) to
see the succinct integrated help.
There Are Better Alternatives
Yes I know. There are many utilities and resources that can convert units. Most people know, for example, that you can type stuff like "26.2 miles in km" into a Google search bar and it will tell you something pretty sensible and definitely usable; in this example it tells me 42.16481km. But a lot of times I’m writing software and I don’t need to sort out some immediate real problem but rather I need to know the best conversion factor to include in my program for an entire class of problems for all eternity. I am not doing high school chemistry homework and I do not need help controlling significant figure exuberance. I find this is also true on Wolfram Alpha which actually has a "More Digits" feature, uh, sometimes. (Thanks XKCD for making this point perfectly!)
Wolfram Alpha is pretty fancy and can do conversions and weird symbolic manipulations that are quite incredible. The problem I find with it is I do not know the canonical format to use to force it to suppress its fuzzy natural language processing interpretation and stick with an explicit well structured problem. These web services also are not private and they require bandwidth and time to generate answers.
Perhaps the best unit conversion system is the
GNU Units program. You can
usually obtain it with sudo apt install units
.
Here’s a web interface.
From its
documentation it
claims the following.
Beyond simple unit conversions, GNU Units can be used as a general-purpose scientific calculator that keeps track of units in its calculations. You can form arbitrary complex mathematical expressions of dimensions including sums, products, quotients, powers, and even roots of dimensions.
Wow. If you’re interested in the very state of the art in units omnipotence, this is it. Just a quick review of the units database will assure you that many pedantic nerds drank a lot of coffee working on this. The GNU Units system is indeed formidable and I recommend it for both very simple problems and especially complex problems. However, there is a middle range where I feel it falls slightly short due to its comprehensive functionality and concomitant complexity.
Why Reinvent This Wheel
Unicon provides almost the full set of features that GNU Units does. However, what it lacks it makes up for in simplicity. Although it can handle arbitrarily complex units, it can not handle arbitrarily messy forms of them. Obviously one could learn to use GNU Units in just such a constrained way and achieve a similar effect. However, I personally have a better reason to write my own.
While the arbitrary complexity of GNU Unit’s mathematical expressions is impressive, I already have a Turing complete system capable of arbitrary complexity. That is my programming language Geogad. Unicon is my way to add units handling. Making this stand-alone version of the software do algebraic heroics is not really aligned to my bigger goals.
And like Geogad in general, Unicon was heavily inspired by the HP calculators of the 1990s, especially the beloved HP48. I am trying to match the level of comprehensiveness pretty closely with that system. This puts a reasonable floor into the rabbit hole which otherwise can go pretty deep.
The first round of populating a units database came directly from transcribing Appendix E from the "HP 48G Series User’s Guide". Yes, there are more units in the world than that, but if you find this collection very insufficient, you have very strange problems.
How To Use
Specifying Units
Unlike many casual units conversion utilities and calculators, Unicon is not simply a giant list of obscure conversions. It can handle arbitrarily composed complex units. The units can have a value (and must in some contexts). The value is separated from the unit by an underscore. This is the same convention as the HP48 and looks like this.
1_unit
-3.141592653589793_unit
6.02214076e23_unit
The values can be any simple numerical value that can be added and multiplied, etc.
The unit part after the underscore is composed of unit terms. There is
a lot of flexibility for arbitrary compound units, but the main
simplifying rule is that there can only be one numerator and one
denominator. So instead of X/Y/Z, you need to think more like X/(Y*Z).
Each part of the fraction — the top and bottom — is separated by a
slash, /
. That means these are the possible forms.
value_numeratoronly
value_1/denominatoronly
value_numerator/denominator
Each compound part of the fraction can be composed of terms separated by "*". Here is how to specify ten Newton-meters of torque.
10_N*m
There are no limits to the number of components. You can do something like this to get cubic centimeter (a.k.a. CC).
1_cm*cm*cm
But the better format for such a value is to use ^
to specify an
exponent where that would be useful. Here is the same CC.
1_cm^3
Thus putting things together you can start to have complex units like this.
981_kg*m/s^2
The only other rule is that if you use multiple terms in the denominator, you need to put the whole denominator in parentheses. This is a way to express the units for conductivity.
1_A^2*s^3/(kg*m^2)
This is actually how the HP48 will refactor your units if you input an uglier mess. If you (or your shell) do not like the parentheses, you can put the whole term in quotes or write it like this.
1_A^2*s^3*kg^-1*m^-2
You should also be able to add any SI prefix where it would be unambiguous. These should be valid.
1_megaPa
1_kW*h
1_ml
Conversion
The normal usage is to supply a source unit which must include a value plus a second unit where the value is optional (and ignored). The program will convert the first quantity into the units of the second argument.
$ ./unicon.py 26.2_mi km
Prefix 'k' suspected in 'km^1' - converting to: 'm^1'
26.2_mi = 42.1648128_km
You can ignore the commentary about how it is interpreting the input. Here’s an even easier one. Imagine you need to fill up a 1 gallon milk bottle using only a tablespoon. How many spoonfuls?
$ ./unicon.py 1_gal tbsp
1_gal = 255.9999999991344_tbsp
Note that the digits are left as complete as possible which will often reveal the limitations of encoding fractional numbers in binary.
This more complex example converts 10 pound square inches per square Coulomb to milliHenry.
$ ./unicon.py 10_lb*in^2/C^2 mH
Prefix 'm' suspected in 'mH^1' - converting to: 'H^1'
10_lb*in^2/C^2 = 2.926396534292_mH
Sometimes there is no numerator.
$ ./unicon.py 20_1/min Hz
20_1/min = 0.3333333333333333_Hz
You can use full SI prefixes or the abbreviated forms. If I am 0.7 hectoinches tall, how tall am I in attoparsecs?
$ ./unicon.py .7_hin attopc
Prefix 'h' suspected in 'hin^1' - converting to: 'in^1'
ttopc^1 not in catalog, trying other interpretations
Prefix 'atto' suspected in 'attopc^1' - converting to: 'pc^1'
.7_hin = 57.62104448070371_attopc
Checking Availability Of Units
Say you want to check to see if the program even knows about the units
you’re interested in. There is an option that lists all of the units
that are known and usable. Of course reading a big long list of units
isn’t so helpful; grep
can be used to narrow the search.
$ ./unicon.py -l | grep -i slug
slug {'kg': 1}
The -i
is to make the search case insensitive. And with that the
presence of slugs is confirmed and shown to be a unit that is defined
in kilograms (simple kg with an exponent of 1).
Reducing
If you just include one argument, the program will assume the target units are SI base units and make that reduction. Here half a milliHenry, a unit of electrical induction.
$ ./unicon.py .5_mH
Prefix 'm' suspected in 'mH^1' - converting to: 'H^1'
Unit in SI base: 0.0005_kg*m^2/(A^2*s^2)
Limitations And Todo
-
Temperature - yes, the HP48 has two systems, one for the normal conversions Americans must do when interacting with normal people; the other system converts temperature deltas. I haven’t even attempted this yet. In Geogad, I usually just define these symbols to do quotidian temperature conversions.
-
to Celsius:
|[32 - 5 * 9 /::!] |2C sto
-
to Fahrenheit:
|[9 * 5 / 32 +::!] |2F sto
-
-
Yes, there are tons of units that are not included in the database. I am planning on allowing for good user defined augmentation.
-
I also need to sort out any changes that happened to the definition of some fundamental units during the 2019 redefinition of the SI base units. Which was totally a thing. That’s actually a sane reason why simply using an HP48 (or HP48 emulator) may not be sufficient in the 21st century.
-
The class does not handle addition and subtraction of compatible unit objects, nor multiplication and division of units. But that is planned. Same for inversion.
-
Same for comparisons where units are compatible.
-
Same for trigonometric functions on angles.
-
With this library, Geogad should be able to return a list for special conversions like
[1_° 2_arcmin 3_arcs]
and[1_h 2_min 3_s]
. DONE! This now works:-
44.9975 2dms -> [44.0 59.0 51.0::degrees arcminutes arcseconds]
-
[44 59 51] 2deg -> 44.9975
-
44.9975 2rad radmode 2dms -> [44.0 59.0 51.0::degrees arcminutes arcseconds]
-
-
I want to implement the HP48 "UFACT" function where L2 in L1’s units plus any needed SI. This could help with randomly generated unit, uh, unit testing.