Menu

UnitsOfMeasurement

Dave Brondsema

Units of Measurement

The [VehicleDatabases] can declare the exact unit of measurement (for example, degrees Celsius, kilometers per hour) for all values read from vehicle computers where the measurement unit is known. The units are labeled using the "case sensitive" syntax of the Unified Code for Units of Measure, which allows any UCUM-aware app to convert values into any unit the user chooses for display (degrees Fahrenheit or miles per hour, for example) while offering only units that make sense for the value to be displayed.

Tiny platforms, those that do not use the [VehicleDatabaseFormat] directly but are programmed in some other form generated from the database by an exporter, will generally not be UCUM aware, but the unit information can be used by the exporter to allow the user to select preferred units when generating the data to load on the tiny platform.

Notes for database writers

  • Be sure ucum attributes are written exactly. They are not just labels for humans to read, but exactly specify a physical unit. The syntax is strict. Look in the Tables of Terminal Symbols (using the case-sensitive column); know the lexical and syntax rules for combining them.
  • Some UCUM spellings are surprises, like Cel for degrees Celsius but [degF] for degrees Fahrenheit. The UCUM spelling of RPM is circ/min. Get used to it. :) It doesn't have to appear that way when displayed by an app; these are the unit tags in the database.
  • The UCUM web applet can be a good instant test of whether you have written a UCUM unit correctly and it converts to another unit the way you expect.
  • ucum attributes do not go directly on a field element, but on one or more of its contained calc elements. That's because it may be awkward or impossible to express in UCUM what the units are of the raw value in a field. It would be possible to say that the units of PID 0C engine speed in raw form are circ/4/min but that's a little puzzling to work out (checking it in the applet and re-reading the strict left-to-right rule should help). And the fact that PID 0F intake air is degrees Celsius plus 40 isn't expressible in UCUM at all. Instead, respectively, just use a calc that divides engine speed by 4 and declares the result to be circ/min, and one that subtracts 40 from intake air and calls the result Cel.
  • If multiple calcs appear for a field, and more than one has a ucum attribute, the ucum attributes have to be consistent. That is, if _calc_1 says it gives _unit_1 and _calc_2 says it gives _unit_2 then _calc_1 composed with (_calc_2)-1 composed with the conversion from _unit_1 to _unit_2 should be the identity function. Eventually we can have sanity code that checks that. Until then, please make sure it's so.
  • Misleading ucum attributes are worse than none; if it's doubtful what the units are for a value, better to omit any ucum attribute. (Or, another attribute could be added to indicate level of confidence in the unit.)
  • ucum attributes that aren't quite accurate are also bad. For some device with limited arithmetic it might be necessary to use a calc that only approximates a unit conversion (say, 5/8 instead of 15625/25146 for km to [mi_i], for example). That may be the best that device can do but in the database it should be flagged as an approximation. The options are to leave the ucum attribute off, or keep it and include a rel-err attribute saying how far the approximation is from exact: rel-err='6e-3' in this case.

Notes for application writers

  • Obtain a UnitFormatService implementation using ServiceLoader.load (developer.android.com)(org.unitsofmeasurement.service.UnitFormatService)
  • Call getUnitFormat() on the UnitFormatService to get the UCUM UnitFormat
  • Call parse on the UnitFormat to parse any ucum attribute from the database and get the corresponding Unit u.
  • If the user wants the data displayed in a different unit v, use u.getConverterToAny(v) to get the appropriate converter and use its convert methods to do the calculation. If v isn't a compatible unit (the user wanted degrees Fahrenheit for an engine torque?) an exception will be thrown by getConverterToAny. Or check first with isCompatible.
  • Or, just have the user choose from a menu of only compatible units. Pick a SystemOfUnits (after loading the SystemOfUnitsService), get the dimension of u, and use getUnits(Dimension) to get the set of compatible units in that system. If the user chooses unit v from that set, it's known to be compatible; use getConverterTo, which can't throw the exception.
  • Suppose you allow a user to choose a parameter giving rpm and a parameter giving torque, and create a gauge showing their product. When you multiply the numbers, what will be the unit of the result? Find out by multiplying the Units too. You can even use getUnits to show a menu of appropriate unit choices for the result (horsepower, watts, etc.), and getConverterTo for the correct conversion to the desired display.
  • All this depends on having a suitable service implementation as part of the app. UOMo appeared heavy in its dependencies to me, but Werner Keil assures me that a lot of them are in Android already and he's used it on Android already. Maybe one day he'll write up an example showing the steps needed to get it working.

Related

Wiki: VehicleDatabases

MongoDB Logo MongoDB