Skip to content

Instantly share code, notes, and snippets.

@endolith
Last active February 5, 2021 21:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save endolith/1a74477fc1659cd6bf9d138e09c72672 to your computer and use it in GitHub Desktop.
Save endolith/1a74477fc1659cd6bf9d138e09c72672 to your computer and use it in GitHub Desktop.
Parse schematic component values
"""
Created on Wed Aug 24 2016
"""
prefixes = {
'Y': 1e24,
'Z': 1e21,
'E': 1e18,
'P': 1e15,
'T': 1e12,
'G': 1e9,
'M': 1e6,
'k': 1e3,
'K': 1e3, # Common but not standard
'm': 1e-3,
'u': 1e-6, # Common but not standard
'\u03bc': 1e-6, # GREEK SMALL LETTER MU
'\u00b5': 1e-6, # MICRO SIGN
'n': 1e-9,
'p': 1e-12,
'f': 1e-15,
'a': 1e-18,
'z': 1e-21,
'y': 1e-24,
}
infixes = prefixes.copy()
infixes.update({'R': 1})
units = {
'R': 'ohm',
'\u2126': 'ohm', # OHM SIGN
'\u03a9': 'ohm', # GREEK CAPITAL LETTER OMEGA
'ohm': 'ohm',
'F': 'farad',
'H': 'henry',
'V': 'volt',
'A': 'ampere',
# watts?
# hertz?
# coulomb?
# siemen?
}
def value_parser(value):
"""
Converts typical electronics schematics value labels into a float and a
unit string. Accepts things like '3000', '3k3', '3e3', '4 μF', etc.
"""
try:
value = float(value)
unit = None
except ValueError:
# Units
for test_unit in units:
if value.endswith(test_unit):
unit = units[test_unit]
value = value[:-len(test_unit)].strip()
break
else:
unit = None
if value[-1] in prefixes:
# Unit prefixes at end
mul = prefixes[value[-1]]
value = value[:-1]
else:
# Unit prefixes but infixed
# TODO: Could convert '3k3' to '3.3k' instead of testing this way
for test_inf in infixes:
if test_inf in value:
parts = value.split(test_inf)
value = parts[0] + '.' + parts[1]
mul = infixes[test_inf]
break
else:
mul = 1
value = float(value) * mul
return value, unit
# TODO: from nose.tools import assert_almost_equals
# instead of testing floats for equality
def test_unitless():
# Literals
assert value_parser(4700) == (4700, None)
assert value_parser(3.3) == (3.3, None)
assert value_parser(4.7e3) == (4.7e3, None)
assert value_parser(10e-6) == (10e-6, None)
# Strings
assert value_parser('3.3') == (3.3, None)
assert value_parser('3') == (3, None)
assert value_parser('3e3') == (3e3, None)
assert value_parser('10e-6') == (10e-6, None)
def test_trailing_prefix():
assert value_parser('3k') == (3000, None)
assert value_parser('3K') == (3000, None)
assert value_parser('3.3K') == (3300, None)
assert value_parser('10u') == (10 * 1e-6, None)
assert value_parser('10 u') == (10 * 1e-6, None) # almost_equal
assert value_parser('10μ') == (10 * 1e-6, None) # almost_equal
assert value_parser('10µ') == (10 * 1e-6, None) # almost_equal
def test_infix():
assert value_parser('3k3') == (3300, None)
assert value_parser('2M2') == (2.2e6, None)
assert value_parser('4n7') == (4.7 * 1e-9, None)
assert value_parser('3R3') == (3.3, None) # !!!
def test_units():
assert value_parser('10mA') == (10e-3, 'ampere')
assert value_parser('10 ohm') == (10, 'ohm')
assert value_parser('10 A') == (10, 'ampere')
assert value_parser('3kA') == (3e3, 'ampere')
assert value_parser('1 F') == (1, 'farad')
assert value_parser('3kohm') == (3e3, 'ohm')
assert value_parser('3 kΩ') == (3e3, 'ohm')
assert value_parser('10 uF') == (10 * 1e-6, 'farad')
assert value_parser('10 μF') == (10 * 1e-6, 'farad')
assert value_parser('100R') == (100, 'ohm')
assert value_parser('4.7kV') == (4.7 * 1e3, 'volt')
assert value_parser('4.7k\u2126') == (4.7 * 1e3, 'ohm')
assert value_parser('4.7k\u03a9') == (4.7 * 1e3, 'ohm')
assert value_parser('100 nH') == (100 * 1e-9, 'henry')
if __name__ == "__main__":
import pytest
pytest.main(['--tb=short', __file__])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment