Examples

This page shows small, complete examples for common scuq workflows.

Quantities and Units

Quantity combines a numerical value with a physical unit. Arithmetic keeps track of the resulting unit.

from scuq.quantities import Quantity
from scuq.si import METER, SECOND, VOLT, AMPERE

voltage = Quantity(VOLT, 12.0)
current = Quantity(AMPERE, 0.25)
resistance = voltage / current

distance = Quantity(METER, 10.0)
time = Quantity(SECOND, 2.0)
speed = distance / time

print(resistance)  # 48.0 V*A^(-1)
print(speed)       # 5.0 m*s^(-1)

Custom Units and Strict Mode

Strict mode is enabled by default. In strict mode, compatible but different units are not converted implicitly for operations such as addition and explicit value access. Disable strict mode when automatic conversion is desired.

from scuq.quantities import Quantity, set_strict
from scuq.si import VOLT
from scuq.units import AlternateUnit

mV = AlternateUnit("mV", VOLT / 1000)

set_strict(False)
signal = Quantity(VOLT, 2.0) + Quantity(mV, 500.0)

print(signal)                 # 2.5 V
print(signal.get_value(mV))   # 2500.0

The result of an addition or subtraction is expressed in the unit of the left operand.

Uncertainty Propagation

Uncertain input values are modeled first. They can then be wrapped in Quantity objects. This keeps uncertainty propagation separate from unit handling while still preserving units in the final result.

from scuq.quantities import Quantity
from scuq.si import METER
from scuq.ucomponents import Context, UncertainInput

length = Quantity(METER, UncertainInput(2.0, 0.02))
width = Quantity(METER, UncertainInput(3.0, 0.03))

area = length * width

context = Context()
area_uncertainty = context.uncertainty(area)

print(area)              # 6.0 +/- 0.08485281374238571 [NC] m^(2)
print(area_uncertainty)  # 0.08485281374238571 m^(2)

The uncertainty result has the matching unit of the evaluated model. In this example, the uncertainty of the area is expressed in square meters.

The [NC] marker in the string representation means “no context”. It is shown when an uncertain expression depends on more than one input, but the object itself has no assigned Context for printing. In that case, __str__ evaluates the expression with a temporary default context and assumes no correlations. Explicit calls such as context.uncertainty(area) use the context supplied by the caller and therefore do not carry this marker.

Correlated Real Inputs

Use a Context to define correlations between uncertain input values. The same context is then used to evaluate the model uncertainty.

from scuq.ucomponents import Context, UncertainInput

context = Context()

voltage = UncertainInput(5.0, 0.05)
current = UncertainInput(0.1, 0.002)

context.set_correlation(voltage, current, -0.4)

resistance = voltage / current
print(resistance.get_value())          # 50.0
print(context.uncertainty(resistance))  # 1.2845232578665127

Complex Measurement Example

scuq also supports complex uncertainty propagation. The following compact example computes a complex impedance from voltage, current, and phase.

import numpy

from scuq import cucomponents
from scuq.quantities import Quantity
from scuq.si import AMPERE, OHM, RADIAN, VOLT
from scuq.units import ONE

context = cucomponents.Context()

j = Quantity(ONE, context.gaussian(1j, 0.0, 0.0))
voltage = Quantity(VOLT, context.gaussian(4.9990, 0.003209, 0.0))
current = Quantity(AMPERE, context.gaussian(19.661e-3, 0.00947e-3, 0.0))
phase = Quantity(RADIAN, context.gaussian(1.04446, 0.0007521, 0.0))

impedance = voltage / current * numpy.exp(j * phase)

assert impedance.get_default_unit().is_compatible(OHM)
print(impedance)
# Value = (127.73216992810208+219.8465119126384j) ; Uncertainty =
#  [[0.03784785 0.00220209]
#  [0.00220209 0.04035856]] [NC] V*A^(-1)
print(context.uncertainty(impedance))
# [[0.03784785 0.00220209]
#  [0.00220209 0.04035856]] V^(2)*A^(-2)

This pattern is useful for measurement models where the numerical model is ordinary Python or NumPy code, while scuq carries units and uncertainty information through the calculation.

As with real uncertain components, [NC] in the printed complex impedance marks a string conversion without an assigned context. The explicit context.uncertainty(impedance) call above evaluates the uncertainty with the given context.