2026-06-02 21:08:48 +08:00
|
|
|
from typing import Iterable
|
|
|
|
|
from pathlib import Path
|
2026-06-15 13:47:31 +08:00
|
|
|
from .common import LcrConnException
|
2026-06-02 21:08:48 +08:00
|
|
|
|
|
|
|
|
|
2026-06-15 13:47:31 +08:00
|
|
|
class Dataset:
|
|
|
|
|
"""
|
|
|
|
|
A list holding available standard values for resistor, capacitor or inductor.
|
2026-06-02 21:08:48 +08:00
|
|
|
|
2026-06-15 13:47:31 +08:00
|
|
|
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, ...]
|
2026-06-02 21:08:48 +08:00
|
|
|
"""A list of available device gauge values"""
|
|
|
|
|
|
2026-06-15 13:47:31 +08:00
|
|
|
def __init__(self, values: tuple[float, ...]):
|
|
|
|
|
# Check redundant parts
|
|
|
|
|
valueset = set(values)
|
|
|
|
|
if len(valueset) != len(values):
|
|
|
|
|
raise LcrConnException(f"Duplicate standard value")
|
|
|
|
|
# Ok, assign it
|
|
|
|
|
self.__values = values
|
|
|
|
|
|
2026-06-02 21:08:48 +08:00
|
|
|
@staticmethod
|
2026-06-15 13:47:31 +08:00
|
|
|
def from_iterable(stringfied_values: Iterable[str]) -> "Dataset":
|
|
|
|
|
return Dataset(
|
|
|
|
|
tuple(
|
|
|
|
|
from_human_readable_value(stringfied_value)
|
|
|
|
|
for stringfied_value in stringfied_values
|
|
|
|
|
)
|
|
|
|
|
)
|
2026-06-02 21:08:48 +08:00
|
|
|
|
|
|
|
|
@staticmethod
|
2026-06-15 13:47:31 +08:00
|
|
|
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":
|
2026-06-02 21:08:48 +08:00
|
|
|
with open(filename, "r", encoding="utf-8") as f:
|
|
|
|
|
legal_lines = filter(lambda line: line != "", (line.strip() for line in f))
|
2026-06-15 13:47:31 +08:00
|
|
|
return Dataset.from_iterable(legal_lines)
|
|
|
|
|
|
|
|
|
|
def get_values(self) -> tuple[float, ...]:
|
|
|
|
|
"""
|
|
|
|
|
Get the available standard values
|
|
|
|
|
|
|
|
|
|
:return: A tuple of available standard values
|
|
|
|
|
"""
|
|
|
|
|
return self.__values
|
2026-06-02 21:08:48 +08:00
|
|
|
|
|
|
|
|
|
2026-06-15 13:47:31 +08:00
|
|
|
class DatasetCollection:
|
|
|
|
|
"""
|
|
|
|
|
The collection holding all standard values for resistor, capacitor and inductor respectively.
|
|
|
|
|
"""
|
2026-06-02 21:08:48 +08:00
|
|
|
|
2026-06-15 13:47:31 +08:00
|
|
|
__resistor: Dataset
|
2026-06-02 21:08:48 +08:00
|
|
|
"""A list of available device gauge values for resistor"""
|
2026-06-15 13:47:31 +08:00
|
|
|
__capacitor: Dataset
|
2026-06-02 21:08:48 +08:00
|
|
|
"""A list of available device gauge values for capacitor"""
|
2026-06-15 13:47:31 +08:00
|
|
|
__inductor: Dataset
|
2026-06-02 21:08:48 +08:00
|
|
|
"""A list of available device gauge values for inductor"""
|
|
|
|
|
|
2026-06-15 13:47:31 +08:00
|
|
|
def __init__(self, resistor: Dataset, capacitor: Dataset, inductor: Dataset):
|
|
|
|
|
self.__resistor = resistor
|
|
|
|
|
self.__capacitor = capacitor
|
|
|
|
|
self.__inductor = inductor
|
|
|
|
|
|
2026-06-02 21:08:48 +08:00
|
|
|
@staticmethod
|
|
|
|
|
def from_iterable(
|
|
|
|
|
resistor: Iterable[str], capacitor: Iterable[str], inductor: Iterable[str]
|
2026-06-15 13:47:31 +08:00
|
|
|
) -> "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),
|
2026-06-02 21:08:48 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
2026-06-15 13:47:31 +08:00
|
|
|
def from_file(
|
|
|
|
|
resistor: Path, capacitor: Path, inductor: Path
|
|
|
|
|
) -> "DatasetCollection":
|
|
|
|
|
return DatasetCollection(
|
|
|
|
|
Dataset.from_file(resistor),
|
|
|
|
|
Dataset.from_file(capacitor),
|
|
|
|
|
Dataset.from_file(inductor),
|
2026-06-02 21:08:48 +08:00
|
|
|
)
|
2026-06-15 13:47:31 +08:00
|
|
|
|
|
|
|
|
def get_resistor_values(self) -> tuple[float, ...]:
|
|
|
|
|
"""
|
|
|
|
|
Get the available standard values for resistor
|
|
|
|
|
|
|
|
|
|
:return: A tuple of available standard values for resistor
|
|
|
|
|
"""
|
|
|
|
|
return self.__resistor.get_values()
|
|
|
|
|
|
|
|
|
|
def get_capacitor_values(self) -> tuple[float, ...]:
|
|
|
|
|
"""
|
|
|
|
|
Get the available standard values for capacitor
|
|
|
|
|
|
|
|
|
|
:return: A tuple of available standard values for capacitor
|
|
|
|
|
"""
|
|
|
|
|
return self.__capacitor.get_values()
|
|
|
|
|
|
|
|
|
|
def get_inductor_values(self) -> tuple[float, ...]:
|
|
|
|
|
"""
|
|
|
|
|
Get the available standard values for inductor
|
|
|
|
|
|
|
|
|
|
:return: A tuple of available standard values for inductor
|
|
|
|
|
"""
|
|
|
|
|
return self.__inductor.get_values()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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)
|