Skip to content

Instantly share code, notes, and snippets.

@Vindaar
Created February 12, 2021 16:10
Show Gist options
  • Save Vindaar/9edc44510da24031c18c22ac1482fd8d to your computer and use it in GitHub Desktop.
Save Vindaar/9edc44510da24031c18c22ac1482fd8d to your computer and use it in GitHub Desktop.

Units

  • when multiplying or dividing units resulting units need to use same order always, e.g.
    let m: Meter
    let s: Second
    doAssert typeof(m * s) == typeof(s * m) == m•s
        

    We can do this by having a specific order of all units, like an importance ranking. Then when combining reflect that. Once we have more complex units it’s probably a good idea to bring back the idea of the SiUnit compile time object, which should abstract away many parts and result in simpler handling, because we don’t have to work with strings. Essentially should be able to define a comparison operator of units that solves this for us and a serialization procedure, which turns the SiUnit back into a distinct unit.

  • add remaining SI prefixes and automate their units, i.e. write a macro that generates all units with all prefixes
  • add combinatorical units
  • add remaining standard units
  • add natural units (how to best do it? Something like “NaturalLength” for full name?)
  • add imperial units
  • add physical constants
  • add support for affine unit conversions (Celsius -> Fahrenheit)
  • add parsing of english language units (“meterPerSecondSquared”); low priority
  • generate all common units as english language (low priority). But generation is much easier than parsing?

Sounds like a lot…

In no particular order things that either are or need to be supported:

## The following already work unless `TODO` (not all units implemented)
block:
  # defining simple units
  let mass = 5.kg
  let a = 9.81.m•s⁻²
block:
  # addition and subtraction of same units
  let a = 5.kg
  let b = 10.kg
  check typeof(a + b) == Kg
  check a + b == 15.kg
  check typeof(a - b) == Kg
  check a - b == 15.kg
block:
  # addition and subtraction of units of the same ``quantity`` but different scale
  let a = 5.kg
  let b = 500.g
  check typeof(a + b) == Kg
  check a + b == 5.5.kg
  # if units do not match, the SI unit is used!
block:
  # product of prefixed SI unit keeps same prefix unless multiple units of same quantity involved
  let a = 1.m•s⁻²
  let b = 500.g
  check typeof(a + b) == Gram•Meter•Second⁻²
  check typeof(a + b) == MilliNewton
  check a + b == 500.g•m•s⁻²
block:
  let mass = 5.kg
  let a = 9.81.m•s⁻²
  # unit multiplication has to be commutative
  let F: Newton = mass * a
  let F2: Newton = a * mass # TODO
  # unit division works as expected
  check typeof(F / mass) == Meter•Second⁻²
  check F / mass == a
block:
  # conversion between units of the same quantity
  let f = 10.N
  check typeof(f.to(kN)) == KiloNewton
  check f.to(kN) == 0.01.kN
block:
  # pre-defined physical constants
  let E_e⁻_rest: Joule = m_e * c^2 # math operations `*cannot*` use superscripts!
  # m_e = electron mass in kg
  # c = speed of light in vacuum in m/s
block:
  # automatic CT error if argument of e.g. sin, ln are not unit less
  let x = 5.kg
  let y = 10.kg
  discard sin(x / y) ## compiles gives correct result (~0.48)
  let x2 = 10.m
  # sin(x2 / y) ## errors at CT due to non unit less argument
block:
  # units using english language (using accented quotes)
  let a = 10.`meter per second squared`
  let b = 5.`kilogram meter per second squared`
  check typeof(a) == Meter•Second⁻²
  check typeof(b) == Newton
  check a == 10.m•s⁻²
  check b == 5.N
  
## Yet to be implemented
block:
  # imperial units
  let mass = 100.lbs
block:
  # mixing of non SI and SI units (via conversion to SI units)
  let m1 = 100.lbs
  let m2 = 10.kg
  check typeof(m1 + m2) == Kg
  check m1 + m2 == 55.3592.Kg
block:
  # natural unit support (c = 1, h = 1)
  let speed: NaturalVelocity = 0.1.UnitLess # fraction of c
  let m_e: NaturalMass = 511.keV
  # math between natural units remains natural
  let p: NaturalMomentum = speed * m_e
  check p == 51.1.keV
block:
  # auto conversion of natural units
  let a = 10.MeV
  let b = 200.eV
  check typeof(a / b) == UnitLess # `UnitLess` is 
  check a / b == 50_000.Unitless

Things to note:

  • real units use capital letters and are verbose
  • shorthands defined for all typical units
  • conversion of numbers to units done using `.` call and using shorthand names
  • `•` symbol is product of units to allow unambiguous parsing of units
  • no division of units, but negative exponents
  • exponents are in superscript
  • usage of `•` and superscript is to circumvent Nim’s identifier rules!
  • SI units are the base. If ambiguous operation that can be solved by unit conversion, SI units are used.
  • math operations cannot use superscripts!
  • physical units are defined
  • conversion from prefixed SI unit to non prefixed SI unit only happens if multiple prefixed units of same quantity involved
  • UnitLess is a distinct float unit that has a converter to float (such that UnitLess magically works with math functions expecting floats).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment