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, "kω":1e3, "m":1e6, "mohm":1e6, "mohms":1e6, "mω":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}"