# Usage

After installing the package, you can start using it with

`julia> using Measurements`

The module defines a new `Measurement`

data type. `Measurement`

objects can be created with the two following constructors:

`Measurements.measurement`

— Function```
measurement(val::Real, [err::Real]) -> Measurement
measurement(::Missing, [err::Union{Real,Missing}]) -> Missing
val ± err -> Measurement
```

Return a `Measurement`

object with `val`

as nominal value and `err`

as uncertainty. `err`

defaults to 0 if omitted.

The binary operator `±`

is equivalent to `measurement`

, so you can construct a `Measurement`

object by explicitly writing `123 ± 4`

.

If `val`

is `missing`

, `missing`

is returned.

where

`val`

is the nominal value of the measurement`err`

is its uncertainty, assumed to be a standard deviation.

They are both subtype of `AbstractFloat`

. Some keyboard layouts provide an easy way to type the `±`

sign, if your does not, remember you can insert it in Julia REPL with `\pm`

followed by `TAB`

key. You can provide `val`

and `err`

of any subtype of `Real`

that can be converted to `AbstractFloat`

. Thus, `measurement(42, 33//12)`

and `pi ± 0.1`

are valid.

`measurement(value)`

creates a `Measurement`

object with zero uncertainty, like mathematical constants. See below for further examples.

Every time you use one of the constructors above you define a *new independent* measurement. Instead, when you perform mathematical operations involving `Measurement`

objects you create a quantity that is not independent, but rather depends on really independent measurements.

Most mathematical operations are instructed, by operator overloading, to accept `Measurement`

type, and uncertainty is calculated exactly using analytic expressions of functions' derivatives.

It is also possible to create a `Complex`

measurement with

```
complex(measurement(real_part_value, real_part_uncertainty),
measurement(imaginary_part_value, imaginary_part_uncertainty))
```

In addition to making the code prettier, the fact that the `±`

sign can be used as infix operator to define new independent `Measurement`

s makes the printed representation of these objects valid Julia syntax, so you can quickly copy the output of an operation in the Julia REPL to perform other calculations. Note however that the copied number will not be the *same* object as the original one, because it will be a *new independent* measurement, without memory of the correlations of the original object.

This module extends many methods defined in Julia's mathematical standard library, and some methods from widespread third-party packages as well. This is the case for most special functions in SpecialFunctions.jl package, and the `quadgk`

integration routine from QuadGK.jl package.

Those interested in the technical details of the package, in order integrate the package in their workflow, can have a look at the technical appendix.

`Measurements.measurement`

— Method`measurement(string) -> Measurement{Float64}`

Parse the string and return a `Measurement{Float64}`

object.

Examples of valid strings and the resulting `Measurement{Float64}`

are:

```
julia> using Measurements
julia> measurement("-123.4(56)")
-123.4 ± 5.6
julia> measurement("+1234(56)e-1")
123.4 ± 5.6
julia> measurement("12.34e-1 +- 0.56e1")
1.2 ± 5.6
julia> measurement("(-1.234 ± 0.056)e2")
-123.4 ± 5.6
julia> measurement("1234e-1 +/- 5.6e0")
123.4 ± 5.6
julia> measurement("-1234e-1")
-123.4 ± 0.0
```

`measurement`

function has also a method that enables you to create a `Measurement`

object from a string.

The `±`

infix operator is a convenient symbol to define quantities with uncertainty, but can lead to unexpected results if used in elaborate expressions involving many `±`

s. Use parentheses where appropriate to avoid confusion. See for example the following cases:

```
julia> using Measurements
julia> 7.5±1.2 + 3.9±0.9 # This is wrong!
11.4 ± 1.2 ± 0.9 ± 0.0
julia> (7.5±1.2) + (3.9±0.9) # This is correct
11.4 ± 1.5
```

## Correlation Between Variables

The fact that two or more measurements are correlated means that there is some sort of relationship between them. In the context of measurements and error propagation theory, the term "correlation" is very broad and can indicate different things. Among others, there may be some dependence between uncertainties of different measurements with different values, or a dependence between the values of two measurements while their uncertainties are different.

Here, for correlation we mean the most simple case of functional relationship: if $x = \bar{x} \pm \sigma_x$ is an independent measurement, a quantity $y = f(x) = \bar{y} \pm \sigma_y$ that is function of $x$ is not like an independent measurement but is a quantity that depends on $x$, so we say that $y$ is correlated with $x$. The package `Measurements.jl`

is able to handle this type of correlation when propagating the uncertainty for operations and functions taking two or more arguments. As a result, $x - x = 0 \pm 0$ and $x/x = 1 \pm 0$. If this correlation was not accounted for, you would always get non-zero uncertainties even for these operations that have exact results. Two truly different measurements that only by chance share the same nominal value and uncertainty are not treated as correlated.

## Propagate Uncertainty for Arbitrary Functions

`Measurements.@uncertain`

— Macro`@uncertain f(value ± stddev, ...)`

A macro to calculate `f(value) ± uncertainty`

, with `uncertainty`

derived from `stddev`

according to rules of linear error propagation theory.

Function `f`

can accept any number of real arguments.

Existing functions implemented exclusively in Julia that accept `AbstractFloat`

arguments will work out-of-the-box with `Measurement`

objects as long as they internally use functions already supported by this package. However, there are functions that take arguments that are specific subtypes of `AbstractFloat`

, or are implemented in such a way that does not play nicely with `Measurement`

variables.

The package provides the `@uncertain`

macro that overcomes this limitation and further extends the power of `Measurements.jl`

.

This macro allows you to propagate uncertainty in arbitrary functions, including those based on C/Fortran calls, that accept any number of real arguments. The macro exploits `derivative`

and `gradient`

functions from Calculus package in order to perform numerical differentiation.

## Derivative and Gradient

`Measurements.derivative`

— Function`derivative(x::Measurement, y::Measurement)`

Return the value of the partial derivative of `x`

with respect to the independent measurement `y`

, calculated on the nominal value of `y`

. Return zero if `x`

does not depend on `y`

.

Use `Measurements.derivative.(x, array)`

to calculate the gradient of `x`

with respect to an array of independent measurements.

In order to propagate the uncertainties, `Measurements.jl`

keeps track of the partial derivative of an expression with respect to all independent measurements from which the expression comes. For this reason, the package provides a convenient function, `Measurements.derivative`

, to get the partial derivative and the gradient of an expression with respect to independent measurements.

## Uncertainty Contribution

`Measurements.uncertainty_components`

— Function`Measurements.uncertainty_components(x::Measurement)`

Return the components to the uncertainty of the dependent quantity `x`

in the form of a `Dict`

for all the independent `Measurement`

s from which `x`

is derived.

The key of each entry of the dictionary is the triplet (value, uncertainty, tag) of an independent `Measurement`

, and the value is the absolute value of the product between its uncertainty and the partial derivative of `x`

with respect to this `Measurement`

.

You may want to inspect which measurement contributes most to the total uncertainty of a derived quantity, in order to minimize it, if possible. The function `Measurements.uncertainty_components`

gives you a dictionary whose values are the components of the uncertainty of `x`

.

## Standard Score

`Measurements.stdscore`

— Function`stdscore(measure::Measurement, expected_value::Real) -> standard_score`

Gives the standard score between a measure, with uncertainty, and its expected value:

`(measure.val - expected_value)/measure.err`

`stdscore(measure_1::Measurement, measure_2::Measurement) -> standard_score`

Gives the standard score between two measurements (both with uncertainty) computed as the standard score between their difference and 0:

`stdscore(measure_1 - measure_2, 0)`

The `stdscore`

function is available to calculate the standard score between a measurement and its expected value (not a `Measurement`

). When both arguments are `Measurement`

objects, the standard score between their difference and zero is computed, in order to test their compatibility.

## Weighted Average

`Measurements.weightedmean`

— Function`weightedmean(iterable) -> measurement(weighted_mean, standard_deviation)`

Return the weighted mean of measurements listed in `iterable`

, using inverse-variance weighting. NOTA BENE: correlation is not taken into account.

`weightedmean`

function gives the weighted mean of a set of measurements using inverses of variances as weights. Use `mean`

for the simple arithmetic mean.

## Access Nominal Value and Uncertainty

`Measurements.value`

— Function```
Measurements.value(x::Measurement)
Measurements.value(x::Complex{Measurement})
Measurements.value(x::Missing)
```

Return the nominal value of measurement `x`

.

`Measurements.uncertainty`

— Function```
Measurements.uncertainty(x::Measurement)
Measurements.uncertainty(x::Complex{Measurement})
Measurements.uncertainty(x::Missing)
```

Return the uncertainty of measurement `x`

.

As explained in the technical appendix, the nominal value and the uncertainty of `Measurement`

objects are stored in `val`

and `err`

fields respectively, but you do not need to use those fields directly to access this information. Functions `Measurements.value`

and `Measurements.uncertainty`

allow you to get the nominal value and the uncertainty of `x`

, be it a single measurement or an array of measurements. They are particularly useful in the case of complex measurements or arrays of measurements.

## Calculating the Covariance and Correlation Matrices

`Measurements.cov`

— Function`Measurements.cov(x::AbstractVector{<:Measurement})`

Returns the covariance matrix of a vector of correlated `Measurement`

s.

`Measurements.cor`

— Function`Measurements.cor(x::AbstractVector{<:Measurement})`

Returns the correlation matrix of a vector of correlated `Measurement`

s.

The covariance matrix of multiple measurements can be calculated using the `cov`

function by supplying a vector of `Measurement`

s. Likewise, the correlation matrix can be calculated using the `cor`

function with the same signature.

## Creating Correlated Measurements from their Nominal Values and a Covariance Matrix

`Measurements.correlated_values`

— Function```
Measurements.correlated_values(
nominal_values::AbstractVector{<:Real},
covariance_matrix::AbstractMatrix{<:Real}
)
```

Returns correlated `Measurement`

s given their nominal values and their covariance matrix.

```
Measurements.correlated_values(
nominal_values::AbstractVector{<:Real},
standard_deviations::AbstractVector{<:Real},
correlation_matrix::AbstractMatrix{<:Real}
)
```

Returns correlated `Measurement`

s given their nominal values, their standard deviations and their correlation matrix.

Given some nominal values with an associated covariance matrix, you can construct measurements with a correlated uncertainty. Providing both an `AbstractVector{<:Real}`

of nominal values and a covariance matrix of type `AbstractMatrix{<:Real}`

.

## Error Propagation of Numbers with Units

`Measurements.jl`

does not know about units of measurements, but can be easily employed in combination with other Julia packages providing this feature. Thanks to the type system of Julia programming language this integration is seamless and comes for free, no specific work has been done by the developer of the present package nor by the developers of the above mentioned packages in order to support their interplay. They all work equally good with `Measurements.jl`

, you can choose the library you prefer and use it. Note that only algebraic functions are allowed to operate with numbers with units of measurement, because transcendental functions operate on dimensionless quantities. In the Examples section you will find how this feature works with a couple of packages.

## Representation of `Measurement`

s

`Measurement`

s in the REPL

When working in the Julia REPL, `Measurement`

objects are shown truncated in order to present two significant digits for the uncertainty:

`julia> using Measurements`

`julia> -84.32 ± 5.6`

`-84.3 ± 5.6`

`julia> 7.9 ± 18.6`

`7.9 ± 19.0`

Note that truncation only affects the numbers shown in the REPL:

`julia> using Measurements`

`julia> Measurements.value(7.9 ± 18.6)`

`7.9`

`julia> Measurements.uncertainty(7.9 ± 18.6)`

`18.6`

### Printing to TeX and LaTeX MIMEs

You can print `Measurement`

objects to TeX and LaTeX MIMES (`"text/x-tex"`

and `"text/x-latex"`

), the `±`

sign will be rendered with `\pm`

command:

`julia> using Measurements`

`julia> repr("text/x-tex", 5±1)`

`"5.0 \\pm 1.0"`

`julia> repr("text/x-latex", pi ± 1e-3)`

`"3.1416 \\pm 0.001"`