from typing import Iterable from pathlib import Path from .common import LcrConnException class Dataset: """ A list holding available standard values for resistor, capacitor or inductor. Standard values is a collection of all possible values of specific device manufactured by electronic factory. In reality, it also can be replaced by all possible values of specific device provided by your laboratory. For example, your laboratory only provide resistor with 100 Ohm and 4.7k Ohm. This list will only contain 100 and 4.7k. """ __values: tuple[float, ...] """A list of available device gauge values""" def __init__(self, values: tuple[float, ...]): # Check redundant parts valueset = set(values) if len(valueset) != len(values): raise LcrConnException(f"Duplicate item in standard value list") if len(valueset) == 0: raise LcrConnException(f"Empty standard value list is not allowed") # Ok, assign it self.__values = values @staticmethod def from_iterable(stringfied_values: Iterable[str]) -> "Dataset": return Dataset( tuple( from_human_readable_value(stringfied_value) for stringfied_value in stringfied_values ) ) @staticmethod def from_text(text: str) -> "Dataset": lines = text.split("\n") legal_lines = filter(lambda line: line != "", (line.strip() for line in lines)) return Dataset.from_iterable(legal_lines) @staticmethod def from_file(filename: Path) -> "Dataset": with open(filename, "r", encoding="utf-8") as f: legal_lines = filter(lambda line: line != "", (line.strip() for line in f)) return Dataset.from_iterable(legal_lines) @property def values(self) -> tuple[float, ...]: """ Get the available standard values :return: A tuple of available standard values """ return self.__values class DatasetCollection: """ The collection holding all standard values for resistor, capacitor and inductor respectively. """ __resistor: Dataset """A list of available device gauge values for resistor""" __capacitor: Dataset """A list of available device gauge values for capacitor""" __inductor: Dataset """A list of available device gauge values for inductor""" def __init__(self, resistor: Dataset, capacitor: Dataset, inductor: Dataset): self.__resistor = resistor self.__capacitor = capacitor self.__inductor = inductor @staticmethod def from_iterable( resistor: Iterable[str], capacitor: Iterable[str], inductor: Iterable[str] ) -> "DatasetCollection": return DatasetCollection( Dataset.from_iterable(resistor), Dataset.from_iterable(capacitor), Dataset.from_iterable(inductor), ) @staticmethod def from_text(resistor: str, capacitor: str, inductor: str) -> "DatasetCollection": return DatasetCollection( Dataset.from_text(resistor), Dataset.from_text(capacitor), Dataset.from_text(inductor), ) @staticmethod def from_file( resistor: Path, capacitor: Path, inductor: Path ) -> "DatasetCollection": return DatasetCollection( Dataset.from_file(resistor), Dataset.from_file(capacitor), Dataset.from_file(inductor), ) @property def resistor_values(self) -> Dataset: """ Get the available standard values for resistor :return: A tuple of available standard values for resistor """ return self.__resistor @property def capacitor_values(self) -> Dataset: """ Get the available standard values for capacitor :return: A tuple of available standard values for capacitor """ return self.__capacitor @property def inductor_values(self) -> Dataset: """ Get the available standard values for inductor :return: A tuple of available standard values for inductor """ return self.__inductor def from_human_readable_value(strl: str) -> float: """ Convert human readable value to float :param strl: The human readable value :return: The parsed float value :raises ValueError: If the input string is not a valid number """ strl = strl.strip() if strl.endswith("n"): return float(strl[0:-1]) * 1e-12 if strl.endswith("p"): return float(strl[0:-1]) * 1e-9 if strl.endswith("u"): return float(strl[0:-1]) * 1e-6 if strl.endswith("m"): return float(strl[0:-1]) * 1e-3 if strl.endswith("k"): return float(strl[0:-1]) * 1e3 if strl.endswith("M"): return float(strl[0:-1]) * 1e6 if strl.endswith("G"): return float(strl[0:-1]) * 1e9 return float(strl) def to_human_readable_value(v: float) -> str: """ Convert float value to human readable value :param value: The float value :return: The human readable value """ if v / 1e-12 < 1e3: return "{:e} n".format(v / 1e-12) if v / 1e-9 < 1e3: return "{:.4f} p".format(v / 1e-9) if v / 1e-6 < 1e3: return "{:.4f} u".format(v / 1e-6) if v / 1e-3 < 1e3: return "{:.4f} m".format(v / 1e-3) if v < 1e3: return "{:.4f}".format(v) if v / 1e3 < 1e3: return "{:.4f} k".format(v / 1e3) if v / 1e6 < 1e3: return "{:.4f} M".format(v / 1e6) if v / 1e9 < 1e3: return "{:.4f} G".format(v / 1e9) return "{:e}".format(v)