Skip to content

Frequenz Quantities Library¤

Types for holding quantities with units.

This library provide types for holding quantities with units. The main goal is to avoid mistakes while working with different types of quantities, for example avoiding adding a length to a time.

It also prevents mistakes when operating between the same quantity but in different units, like adding a power in Joules to a power in Watts without converting one of them.

Quantities store the value in a base unit, and then provide methods to get that quantity as a particular unit. They can only be constructed using special constructors with the form Quantity.from_<unit>, for example Power.from_watts(10.0).

Internally quantities store values as floats, so regular float issues and limitations apply, although some of them are tried to be mitigated.

Quantities are also immutable, so operations between quantities return a new instance of the quantity.

This library provides the following types:

  • ApparentPower: A quantity representing apparent power.
  • Current: A quantity representing an electric current.
  • Energy: A quantity representing energy.
  • Frequency: A quantity representing frequency.
  • Percentage: A quantity representing a percentage.
  • Power: A quantity representing power.
  • ReactivePower: A quantity representing reactive power.
  • Temperature: A quantity representing temperature.
  • Voltage: A quantity representing electric voltage.

There is also the unitless Quantity class. All quantities are subclasses of this class and it can be used as a base to create new quantities. Using the Quantity class directly is discouraged, as it doesn't provide any unit conversion methods.

Example
from datetime import timedelta
from frequenz.quantities import Power, Voltage, Current, Energy

# Create a power quantity
power = Power.from_watts(230.0)

# Printing uses a unit to make the string as short as possible
print(f"Power: {power}")  # Power: 230.0 W
# The precision can be changed
print(f"Power: {power:0.3}")  # Power: 230.000 W
# The conversion methods can be used to get the value in a particular unit
print(f"Power in MW: {power.as_megawatt()}")  # Power in MW: 0.00023 MW

# Create a voltage quantity
voltage = Voltage.from_volts(230.0)

# Calculate the current
current = power / voltage
assert isinstance(current, Current)
print(f"Current: {current}")  # Current: 1.0 A
assert current.isclose(Current.from_amperes(1.0))

# Calculate the energy
energy = power * timedelta(hours=1)
assert isinstance(energy, Energy)
print(f"Energy: {energy}")  # Energy: 230.0 Wh
print(f"Energy in kWh: {energy.as_kilowatt_hours()}") # Energy in kWh: 0.23

# Invalid operations are not permitted
# (when using a type hinting linter like mypy, this will be caught at linting time)
try:
    power + voltage
except TypeError as e:
    print(f"Error: {e}")  # Error: unsupported operand type(s) for +: 'Power' and 'Voltage'

This library also provides an experimental module with marshmallow fields and a base schema to serialize and deserialize quantities using the marshmallow library. To use it, you need to make sure to install this package with the marshmallow optional dependencies (e.g. pip install frequenz-quantities[marshmallow]).