Quantity and derived classes

class picodaq.units.Quantity(value: float | ArrayLike | str, unit: str | None = None)

Representation of a value with associated units

Quantity(value, units), where value is a number and units a string, represents the given quantity. For instance:

Quantity(9.81, 'm/s^2')

For convenience,

Quantity('9.81 m/s^2')

also works.

Examples

Quantity(4, 'lbs').as_('kg') # -> 1.814
Quantity('3 V / 200 mA').as_('Ohm') # -> 15.0
Quantity('psi').definition() # -> '6894.7573 kg m^-1 s^-2'
(Quantity('2 nA') * Quantity('30 MOhm')).as_('mV') # -> 60
Quantity('kg m / s^2') # but you can also just say “newton”
Quantity('J / Hz^1|2') # Joules per root-Hertz

Notes

  • Within unit strings:

    • Multiplication is implicit; do not attempt to write ‘*’.

    • Fractions in exponents are written with ‘|’ rather than ‘/’.

    • Division marked by ‘/’ binds most loosely, so that, e.g., “kg / m s” is interpreted as kilograms per meter per second.

    • Spaces between units are required. “mN” is a millinewton, not a newton meter.

    • Syntax checking is not overly rigorous. Some invalid expressions may return meaningless values without a reported error.

  • Addition, subtraction, multiplication, and division of quantities with each other is supported. Also, multiplication and division with numbers.

  • Comparison between quantities is supported. Comparison for (in)equality between incompatible units returns false (true). Other comparisons between incompatible units raises an exception.

  • Dimensionless quantities can be converted back to plain numbers with the plain() method. For instance:

    (Quantity("10 kHz") * Quantity("10 ms")).plain() # -> 100
    

Technical details

The full syntax for unit specification is:

BASEUNIT =

m | s | g | A | mol

PREFIX =

m | u | n | p | f | k | M | G | T

ALTUNIT =

meter | meters | second | seconds | sec | secs | gram | grams | gm | amp | amps | ampere | amperes | Amp | Ampere | Amperes

ALTPREFIX =

milli | micro | μ | nano | pico | femto | kilo | mega | Mega | giga | Giga | tera | Tera

DERIVEDUNIT =

Hz | Hertz | hertz | cyc | cycles | V | volt | Volt | volts | Volts | W | watt | Watt | watts | Watts | N | newton | Newton | newtons | Newtons | Pa | pascal | Pascal | J | joule | joules | Joule | Joules | barn | Ohm | Ohms | ohm | ohms | mho | Mho | in | inch | bar | atm | torr | psi M | molar

UNIT =

(PREFIX | ALTPREFIX)? (BASEUNIT | ALTUNIT | DERIVEDUNIT)

DIGITS =

[0-9]

INTEGER =

(‘-’ | ‘+’)? DIGIT+

NUMBER =

(‘-’ | ‘+’)? DIGIT* (‘.’ DIGIT*)? (‘e’ (‘+’ | ‘-’) DIGIT*)?

POWFRAC =

INTEGER (‘|’ INTEGER)?

POWERED =

UNIT (‘^’ POWFRAC)?

FACTOR =

POWERED | NUMBER

MULTI =

FACTOR | (MULTI ‘ ‘ FACTOR)

FRACTION =

MULTI | (FRACTION ‘/’ MULTI)

definition(withoutvalue: bool = False) str

Definition of stored value in SI units

definition() returns the definition of the stored quantity in terms of SI base units.

definition(True) returns only the base units without multiplying the value into it.

__add__(other: Self) Self
__sub__(other: Self) Self
__ge__(other: Self) bool

Return self>=value.

__gt__(other: Self) bool

Return self>value.

__le__(other: Self) bool

Return self<=value.

__lt__(other: Self) bool

Return self<value.

__eq__(other: Self) bool

Return self==value.

__ne__(other: Self) bool

Return self!=value.

__neg__() Self
abs() Self
__mul__(other: Self | float | ArrayLike) Self
__rmul__(other)
__truediv__(other: Self | float | ArrayLike) Self
__rtruediv__(other: Self | float | ArrayLike) Self
__str__()
plain(warn: bool = False) float | ndarray

Convert to dimensionless

plain() returns a dimensionless quantity as a plain number.

An exception is raised if the units are incompatible. That is

(10 * kHz * 5 * ms).plain()

returns 50, whereas

(10 * V / s).plain()

raises an exception.

Optional argument warn, if True, causes a warning to be printed instead of an exception being raised.

as_(newunit: str | Self, warn: bool = False) float | ndarray

Convert to different units

as_(newunits) returns the numeric value of the stored quantity expressed in the new units.

An exception is raised if the units are incompatible. Optional argument warn, if True, turns that into a warning.

Note the underscore in the method name.

Examples:

Quantity("2 V").as_("mV") # -> 2000
Quantity("1 minute").as_("s") # -> 60
Quantity("5 V").as_("s") # raises exception
class picodaq.units.Time(value: float | ArrayLike | str, unit: str | None = None)

Representation of a quantity that has units of time.

The constructor checks that the constructed quantity does indeed have units of time. Other than that, this behaves just like the base class.

class picodaq.units.Voltage(value: float | ArrayLike | str, unit: str | None = None)

Representation of a quantity that has units of voltage.

The constructor checks that the constructed quantity does indeed have units of voltage. Other than that, this behaves just like the base class.

class picodaq.units.Frequency(value: float | ArrayLike | str, unit: str | None = None)

Representation of a quantity that has units of frequency.

The constructor checks that the constructed quantity does indeed have units of frequency. Other than that, this behaves just like the base class.

Example:

Frequency(10/ms) # -> 10 kHz
picodaq.units.V = 1*V

The unit volt

This allows passing expressions like 5 * V to definitions of stimuli instead of the more cumbersome Voltage(5, “V”).

picodaq.units.mV = 1*mV

The unit millivolt

Provided for convenience because 10 * mV is easier to read than 0.01 * V.

picodaq.units.s = 1*s

The unit second

This allows passing expressions like 1.5 * s to definitions of stimuli instead of the more cumbersome Time(15, "s").

picodaq.units.ms = 1*ms

The unit millisecond

Provided for convenience because 5 * ms is easier to read than 0.005 * s.

picodaq.units.Hz = 1*Hz

The unit hertz

picodaq.units.kHz = 1*kHz

The unit kilohertz

This allows passing expressions like 30 * kHz as a sampling rate instead of the more cumbersome Frequency("30 kHz").