Skip to content

Instantly share code, notes, and snippets.

@RavuAlHemio
Last active May 15, 2021 23:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RavuAlHemio/7d1dcb7fe42e90e851f026ef87787320 to your computer and use it in GitHub Desktop.
Save RavuAlHemio/7d1dcb7fe42e90e851f026ef87787320 to your computer and use it in GitHub Desktop.
# released under CC0: https://creativecommons.org/publicdomain/zero/1.0/
from decimal import Decimal
DEFAULT_TOLERANCE = "20"
COLOR_ALIASES = {
# alternative names/spellings
"grey": "gray",
"purple": "violet",
# shortcuts
# (black/blue/brown is annoying)
"pk": "pink",
"s": "silver",
"gd": "gold",
"bk": "black",
"br": "brown",
"bn": "brown",
"r": "red",
"o": "orange",
"y": "yellow",
"gn": "green",
"bu": "blue",
"be": "blue",
"v": "violet",
"pu": "violet", # purple
"gy": "gray",
"w": "white",
}
IMPRECISE_COLOR_ALIASES = {
"b": 'use "bk" for black, "br" or "bn" for brown, "bu" or "be" for blue',
"g": 'use "gn" for green, "gy" for gray, "gd" for gold',
"p": 'use "pu" for purple (or "v" for violet), "pk" for pink',
}
COLOR_TO_DIGIT = {
"black": 0,
"brown": 1,
"red": 2,
"orange": 3,
"yellow": 4,
"green": 5,
"blue": 6,
"violet": 7,
"gray": 8,
"white": 9,
}
COLOR_TO_POWER = {
"pink": -3,
"silver": -2,
"gold": -1,
"black": 0,
"brown": 1,
"red": 2,
"orange": 3,
"yellow": 4,
"green": 5,
"blue": 6,
"violet": 7,
"gray": 8,
"white": 9,
}
COLOR_TO_TOLERANCE = {
"silver": "10",
"gold": "5",
"brown": "1",
"red": "2",
"orange": "0.05",
"yellow": "0.02",
"green": "0.5",
"blue": "0.25",
"violet": "0.1",
"gray": "0.01",
}
INDEX_TO_BAND_ORDINAL = [
"1st",
"2nd",
"3rd",
"4th",
"5th",
]
SI_PREFIXES_POSITIVE = ["", "k", "M", "G", "T", "P", "E", "Z", "Y"]
SI_PREFIXES_NEGATIVE = ["", "m", "μ", "n", "p", "f", "a", "z", "y"]
def decode_resistor(spec: str) -> str:
# lowercase the input, split on spaces (removing empty words)
spec = spec.lower()
colors = [color for color in spec.split(" ") if color]
# map color aliases to their canonical name
for i, color in enumerate(colors):
unaliased_color = COLOR_ALIASES.get(color, None)
if unaliased_color is not None:
colors[i] = unaliased_color
continue
annoyed_message = IMPRECISE_COLOR_ALIASES.get(color, None)
if annoyed_message is not None:
raise ValueError(annoyed_message)
# ensure correct count (also handle single black band)
if len(colors) == 1 and colors[0] == "black":
return "0 Ω"
if len(colors) not in (4, 5):
raise ValueError("need 4 or 5 colors, got {0}".format(len(colors)))
# assemble the digits
value = Decimal(0)
for i, color in enumerate(colors[:-2]):
try:
digit = COLOR_TO_DIGIT[color]
except KeyError as ex:
msg = "{0} band (digit) has unknown color {1}".format(
INDEX_TO_BAND_ORDINAL[i], repr(color)
)
raise ValueError(msg) from ex
value *= Decimal(10)
value += Decimal(digit)
# multiply by the power of 10
try:
power = COLOR_TO_POWER[colors[-2]]
except KeyError as ex:
i = len(colors) - 2
msg = "{0} band (multiplier) has unknown color {1}".format(
INDEX_TO_BAND_ORDINAL[i], repr(colors[-2])
)
raise ValueError(msg) from ex
value *= Decimal(10) ** Decimal(power)
# get tolerance
try:
tolerance = COLOR_TO_TOLERANCE[colors[-1]]
except KeyError as ex:
i = len(colors) - 1
msg = "{0} band (tolerance) has unknown color {1}".format(
INDEX_TO_BAND_ORDINAL[i], repr(colors[-1])
)
raise ValueError(msg) from ex
# simplify to the nearest SI prefix
si_prefix = 0
if not value.is_zero:
thousand = Decimal(1000)
thousandth = Decimal("0.001")
while value >= thousand:
value /= thousand
si_prefix += 1
while value <= thousandth:
value *= thousand
si_prefix -= 1
# assemble the final text
return "{0} {1}Ω (± {2}%)".format(
value,
SI_PREFIXES_POSITIVE[si_prefix] if si_prefix >= 0 else SI_PREFIXES_NEGATIVE[-si_prefix],
tolerance,
)
if __name__ == "__main__":
import sys
for color_string in sys.argv[1:]:
try:
decoded = decode_resistor(color_string)
except ValueError as ex:
decoded = ex.args[0]
print("{0}: {1}".format(color_string, decoded))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment