Files
PartDB_Helper_App/parsers/values.py

119 lines
4.8 KiB
Python

import re, math
from typing import Optional, List
RE_RES_SIMPLE = re.compile(r"(?i)^\s*(\d+(?:\.\d+)?)\s*(ohm|ohms|r|k|m|kohm|kohms|mohm|mohms|kΩ|mΩ|kOhm|kOhms|MOhm|MOhms)?\s*$")
RE_RES_LETTER = re.compile(r"(?i)^\s*(\d+)([rkm])(\d+)?\s*$")
RE_CAP_SIMPLE = re.compile(r"(?i)^(\d+(?:\.\d+)?)(p|n|u|m|pf|nf|uf|mf|f)?$")
RE_CAP_LETTER = re.compile(r"(?i)^(\d+)([pnu])(\d+)?$")
def round_sig(x: float, sig: int) -> float:
if x == 0: return 0.0
return round(x, sig - 1 - int(math.floor(math.log10(abs(x)))))
def e_series_values(E: int, rmin=1.0, rmax=1e7, sig_digits: Optional[int]=None) -> List[float]:
if sig_digits is None: sig_digits = 2 if E <= 24 else 3
base: List[float] = []
for i in range(E):
v = round_sig(10 ** (i / E), sig_digits)
if v not in base:
base.append(v)
out = set()
min_dec = int(math.floor(math.log10(rmin)))
max_dec = int(math.ceil(math.log10(rmax)))
for d in range(min_dec - 1, max_dec + 1):
scale = 10 ** d
for b in base:
val = round_sig(b * scale, sig_digits)
if rmin <= val <= rmax:
out.add(val)
return sorted(out)
def value_to_code(ohms: float) -> str:
if ohms == 0: return "0R"
if ohms < 1e3:
unit, n = "R", ohms
elif ohms < 1e6:
unit, n = "K", ohms / 1e3
else:
unit, n = "M", ohms / 1e6
s = f"{n:.3g}"
if "e" in s or "E" in s:
dec = max(0, 3 - 1 - int(math.floor(math.log10(abs(n)))))
s = f"{n:.{dec}f}".rstrip("0").rstrip(".")
return s.replace(".", unit) if "." in s else s + unit
def parse_resistance_to_ohms(value: str, unit: Optional[str]) -> Optional[float]:
if value is None: return None
s = str(value).strip().replace(" ", "").replace(",", "").replace("Ω","ohm").replace("Ω","ohm")
m = RE_RES_SIMPLE.fullmatch(s)
if m and unit is None:
num = float(m.group(1)); u = (m.group(2) or "").lower()
table = {"ohm":1.0, "ohms":1.0, "r":1.0, "k":1e3, "kohm":1e3, "kohms":1e3, "":1e3, "m":1e6, "mohm":1e6, "mohms":1e6, "":1e6}
return num * table.get(u, 1.0)
m = RE_RES_LETTER.fullmatch(s)
if m and unit is None:
lead = int(m.group(1)); letter = m.group(2).lower(); tail = m.group(3) or ""
frac = float(f"0.{tail}") if tail else 0.0
mul = {"r":1.0, "k":1e3, "m":1e6}[letter]
return (lead + frac) * mul
try:
num = float(s)
if unit is None: return num
u = str(unit).strip().lower()
table = {"ohm":1.0, "ohms":1.0, "r":1.0, "k":1e3, "kohm":1e3, "kohms":1e3, "m":1e6, "mohm":1e6, "mohms":1e6}
mul = table.get(u);
return num * mul if mul else None
except ValueError:
return None
def format_ohms_for_eda(ohms: float) -> str:
if ohms == 0: return "0"
if ohms < 1_000:
v = float(ohms);
if v.is_integer(): return f"{int(v)}R"
whole = int(v); frac = int(round((v - whole) * 10))
return f"{whole}R{frac}" if frac else f"{whole}R"
if ohms < 1_000_000:
v = float(ohms) / 1e3
if v.is_integer(): return f"{int(v)}K"
whole = int(v); frac = int(round((v - whole) * 10))
return f"{whole}K{frac}" if frac else f"{whole}K"
v = float(ohms) / 1e6
if v.is_integer(): return f"{int(v)}M"
whole = int(v); frac = int(round((v - whole) * 10))
return f"{whole}M{frac}" if frac else f"{whole}M"
def parse_capacitance_to_farads(value: str, unit: Optional[str]) -> Optional[float]:
if value is None: return None
s = str(value).strip().replace(" ", "").replace(",", "").replace("µ","u").replace("μ","u")
m = RE_CAP_SIMPLE.fullmatch(s)
if m and unit is None:
num = float(m.group(1)); su = (m.group(2) or "f").lower()
mul = {"f":1.0, "pf":1e-12, "p":1e-12, "nf":1e-9, "n":1e-9, "uf":1e-6, "u":1e-6, "mf":1e-3, "m":1e-3}.get(su,1.0)
return num * mul
m = RE_CAP_LETTER.fullmatch(s)
if m and unit is None:
lead = int(m.group(1)); letter = m.group(2).lower(); tail = m.group(3) or ""
frac = float(f"0.{tail}") if tail else 0.0
mul = {"p":1e-12,"n":1e-9,"u":1e-6}[letter]
return (lead + frac) * mul
try:
num = float(s)
if unit is None: return num
u = str(unit).strip().lower().replace("µ","u")
table = {"f":1.0, "farad":1.0, "pf":1e-12, "picofarad":1e-12, "nf":1e-9, "nanofarad":1e-9, "uf":1e-6, "microfarad":1e-6}
return num * table.get(u, 1.0)
except ValueError:
return None
def format_farads_for_eda(F: float) -> str:
if F >= 1e-6:
n = F * 1e6; unit = "u"
elif F >= 1e-9:
n = F * 1e9; unit = "n"
else:
n = F * 1e12; unit = "p"
if abs(n - round(n)) < 1e-6:
return f"{int(round(n))}{unit}"
n1 = round(n, 1); whole = int(n1); frac = int(round((n1 - whole) * 10))
return f"{whole}{unit}" if frac == 0 else f"{whole}{unit}{frac}"