pulse2percept.units

Physical units.

A deliberately small unit system, inspired by Brian2, that lets p2p’s public API accept unitful values:

import pulse2percept.units as u

pulse = BiphasicPulse(50 * u.uA, 0.45 * u.ms)
implant = Orion(x=15 * u.mm)

For just a few units, importing them directly is also convenient:

from pulse2percept.units import uA, ms

Three rules describe the whole system:

  1. Bare numbers keep working, and keep their documented meaning. p2p never warns about them.

  2. Unitful values are dimension-checked and rescaled to the unit the code expects, so 50 * uA and 0.05 * mA are the same input (up to floating-point precision).

  3. Units are stripped at the API boundary, before any numerical work. Cython kernels and NumPy arrays never see a Quantity.

Available units

Quantity

Units

time

s, ms, us, ns

frequency

Hz, kHz

length

m, cm, mm, um, nm

current

A, mA, uA, nA

voltage

V, mV, uV

charge

C, mC, uC, nC

visual angle

dva

dimensionless

dimensionless

base

Dimension, Unit, Quantity, DimensionMismatchError, as_value()

pulse2percept.units.as_value(value, unit, name=None)[source]

Convert a value to a bare number expressed in unit

This is p2p’s standard Python-to-numerics boundary. A Quantity is dimension-checked and rescaled to unit; a bare number is assumed to already be expressed in unit and is passed through untouched (including None).

Parameters:
  • value (float, array_like, Quantity, or None) – The value to normalize.

  • unit (Unit) – The unit the numerical code expects.

  • name (str, optional) – Name of the parameter, used to make the error message point at the offending argument.

Returns:

value – The bare numerical value, expressed in unit.

Return type:

float, np.ndarray, or None

Examples

>>> from pulse2percept.units import as_value, ms, s
>>> as_value(20, ms)
20
>>> as_value(0.02 * s, ms)
20.0
class pulse2percept.units.Dimension(**exponents)[source]

Physical dimensionality of a unit or quantity

A dimension is a vector of integer exponents over the primitive dimensions in BASE_DIMENSIONS. Dimensions are immutable, hashable, and support multiplication, division, and integer powers.

Added in version 0.10.0.

Parameters:

**exponents (int) – Exponent for each primitive dimension, e.g. Dimension(current=1, length=-2) for a current density. Omitted dimensions have exponent 0.

Examples

>>> from pulse2percept.units import Dimension
>>> Dimension(current=1) * Dimension(time=1)
Dimension('charge')
>>> Dimension(time=-1).name
'frequency'
property exponents

Tuple of exponents, aligned with BASE_DIMENSIONS

property is_dimensionless

Whether all exponents are zero

property name

Human-readable name, e.g. 'electric current'

exception pulse2percept.units.DimensionMismatchError[source]

Raised when quantities of incompatible dimensions are combined

Subclasses TypeError because a dimension mismatch is a type error in the physical sense: microamps are simply not a kind of millisecond.

Added in version 0.10.0.

add_note()

Exception.add_note(note) – add a note to the exception

with_traceback()

Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.

class pulse2percept.units.Quantity(magnitude, unit)[source]

A number (or array of numbers) with a unit

Quantities are what users build by multiplying a number by a unit, and they exist to be checked and converted at p2p’s public API boundaries. They are deliberately not NumPy arrays: p2p strips units before any numerical work, so quantities never reach a Cython kernel and never impose per-element overhead on a simulation.

For the same reason, np.asarray(5 * uA) does not silently yield 5. Removing a unit is something you write down, using to_value().

Equivalent unit choices convert consistently up to floating-point precision, and quantities compare accordingly: 0.0041 * mA == 4.1 * uA is True even though rescaling the former gives 4.1000000000000005.

Added in version 0.10.0.

Parameters:
  • magnitude (float or array_like) – The numerical value(s), expressed in unit.

  • unit (Unit) – The unit of magnitude.

Examples

>>> from pulse2percept.units import uA, mA
>>> 500 * uA == 0.5 * mA
True
>>> (500 * uA).to(mA)
0.5 mA
>>> (500 * uA).to_value(mA)
0.5
property magnitude

The numerical value(s), expressed in self.unit

property unit

The Unit of this quantity

property dimension

The Dimension of this quantity

to(unit, name=None)[source]

Convert to another unit of the same dimension

Parameters:
  • unit (Unit) – The target unit.

  • name (str, optional) – Name of the parameter being converted, used to make the error message point at the offending argument.

Returns:

quantity – The same physical quantity expressed in unit.

Return type:

Quantity

to_value(unit, name=None)[source]

Convert to another unit and return the bare number(s)

This is the explicit way to remove a unit: after calling it you have an ordinary float or NumPy array, expressed in unit.

Parameters:
  • unit (Unit) – The target unit.

  • name (str, optional) – Name of the parameter being converted, used to make the error message point at the offending argument.

Returns:

value – The magnitude of this quantity expressed in unit.

Return type:

float or np.ndarray

class pulse2percept.units.Unit(dimension, scale, symbol)[source]

A unit of measurement

A unit is a dimension plus a scale factor relative to the base unit of that dimension (seconds, meters, amperes, volts, or degrees of visual angle) plus a symbol used for display.

Multiplying a number, list, or NumPy array by a unit produces a Quantity. Multiplying, dividing, or exponentiating units produces another unit, so derived units such as uA / mm ** 2 need not be predefined.

Units are immutable. p2p does not maintain a unit registry, parse unit strings, or generate SI prefixes automatically: the vocabulary exported by pulse2percept.units is the whole of it.

Added in version 0.10.0.

Parameters:
  • dimension (Dimension) – The dimensionality of the unit.

  • scale (float) – Size of the unit relative to the base unit of its dimension. For example, ms has scale=1e-3 because the base unit of time is the second.

  • symbol (str) – Short symbol used when printing quantities, e.g. 'uA'.

Examples

>>> from pulse2percept.units import uA, mm, ms
>>> uA / mm ** 2
uA/mm^2
>>> 50 * uA
50 uA
property dimension

The Dimension of this unit

property scale

Size of this unit relative to the base unit of its dimension

property symbol

Short symbol used for display