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.
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.