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. .. code-block:: python 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. .. code-block:: python 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. .. code-block:: python 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. .. code-block:: python 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. .. code-block:: python 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.