# Demo
```elixir
Mix.install([
{:measurements, path: "."},
{:vega_lite, "~> 0.1.6"},
{:kino_vega_lite, "~> 0.1.7"}
])
alias VegaLite, as: Vl
```
## Introduction
`measurements` is a package helping with manipulation of real physics quantities.
## Usage
A measurement is just a struct that can be easily created like so:
<!-- livebook:{"reevaluate_automatically":true} -->
```elixir
Measurements.new(4, :kilometer)
```
If desired, an associated error can be added onto that measurement
<!-- livebook:{"reevaluate_automatically":true} -->
```elixir
Measurements.new(300, :second) |> Measurements.add_error(4, :millisecond)
```
A measurement can be converted to another unit of the same dimension
<!-- livebook:{"reevaluate_automatically":true} -->
```elixir
Measurements.new(300, :second, 5) |> Measurements.best_convert(:microsecond)
```
The best unit is chosen to avoid loosing precision. If the target unit is not better than the current one, the conversion is simply ignored.
<!-- livebook:{"reevaluate_automatically":true} -->
```elixir
Measurements.new(300, :millisecond, 5) |> Measurements.best_convert(:second)
```
This allows to operate on measurements without knowing their precision, but remaining confident no precision in lost in various computations.
## Arithmetic
### Addition
`Measurements` support addition with automated conversion, provided the unit dimension matches.
<!-- livebook:{"reevaluate_automatically":true} -->
```elixir
m1 = Measurements.new(4, :millimeter)
m2 = Measurements.new(543, :micrometer, 2)
Measurements.sum(m1, m2)
```
Otherwise an explicit error with clean measurement representation is displayed:
<!-- livebook:{"reevaluate_automatically":true} -->
```elixir
m1 = Measurements.new(4, :second) |> Measurements.add_error(5, :millisecond)
m2 = Measurements.new(543, :micrometer)
Measurements.sum(m1, m2)
```
### Scaling
Scaling the `Measurement` by a constant is also supported. Note the scale also applies to the error.
<!-- livebook:{"reevaluate_automatically":true} -->
```elixir
m1 = Measurements.new(4, :second) |> Measurements.add_error(5, :millisecond)
Measurements.scale(m1, 60)
```
### Difference
Therefore difference of two measurements with unit of same dimension is also supported.
A more convenient `delta/2` function is provided for this purpose.
<!-- livebook:{"reevaluate_automatically":true} -->
```elixir
m1 = Measurements.new(4, :millimeter)
m2 = Measurements.new(543, :micrometer, 2)
Measurements.delta(m1, m2)
```
### Ratio
The ratio of two measurement is also supported.
The result will be a measurement, with its unit adjusted.
Therefore the `nil` Unit is just a constant, with potentially an error...
<!-- livebook:{"reevaluate_automatically":true} -->
```elixir
m1 = Measurements.new(4, :millimeter)
m2 = Measurements.new(543, :micrometer, 2)
Measurements.ratio(m1, m2)
```
We can verify this result, and maybe get an exact match, even if the value is a float:
```elixir
[
Measurements.ratio(m1, m2).value * 0.543 == 4,
# relative error recovery is a bit more involved.
# Refer to Error propagation theory when in doubt (TODO link?)
Measurements.ratio(m1, m2).error * 543 / 2 == Measurements.ratio(m1, m2).value
]
```
### TODO : Product
This will require more involved unit dimension manipulation...
## Discrete Calculus
With the capabilities in Measurements so far, we can already implement some basic discrete calculus on physical quantities.
<!-- livebook:{"break_markdown":true} -->
### Local Discrete Derivative
TODO
<!-- livebook:{"break_markdown":true} -->
### Local Discrete Integral
TODO
## Iterative Control