"""Типизированные описания реальных, продающихся в розницу компонентов.""" from dataclasses import dataclass from typing import Literal @dataclass(frozen=True) class WireSpec: part_id: str material: Literal["copper", "aluminum"] gauge_mm: float insulation_od_mm: float resistivity_ohm_m: float max_current_a: float price_per_m: float source: str url: str | None = None # прямая ссылка на магазин, где купить @dataclass(frozen=True) class CapacitorSpec: part_number: str capacitance_uf: float voltage_v: float esr_ohm: float max_current_a: float price: float source: str url: str | None = None @dataclass(frozen=True) class CapacitorBank: """Батарея из одинаковых конденсаторов: n_series (напряжение) × n_parallel (ток/ёмкость). Последовательное соединение складывает напряжение и ESR, делит ёмкость; параллельное — складывает ёмкость, максимальный ток и делит ESR. Итоговая батарея выставляет те же поля, что и одиночный конденсатор (`capacitance_uf`, `voltage_v`, `esr_ohm`, `max_current_a`, `price`), поэтому используется как drop-in замена `CapacitorSpec` в StageConfig. """ base_part_number: str n_series: int n_parallel: int capacitance_uf: float voltage_v: float esr_ohm: float max_current_a: float price: float url: str | None = None @property def count(self) -> int: return self.n_series * self.n_parallel @classmethod def from_spec(cls, spec: "CapacitorSpec", n_series: int, n_parallel: int) -> "CapacitorBank": n_series = max(1, int(n_series)) n_parallel = max(1, int(n_parallel)) return cls( base_part_number=spec.part_number, n_series=n_series, n_parallel=n_parallel, capacitance_uf=spec.capacitance_uf * n_parallel / n_series, voltage_v=spec.voltage_v * n_series, esr_ohm=spec.esr_ohm * n_series / n_parallel, max_current_a=spec.max_current_a * n_parallel, price=spec.price * n_series * n_parallel, url=spec.url, ) @dataclass(frozen=True) class SwitchSpec: part_number: str kind: Literal["SCR", "MOSFET", "IGBT"] max_current_a: float max_voltage_v: float on_resistance_ohm: float | None on_voltage_drop_v: float | None turn_on_time_ns: float price: float source: str url: str | None = None @dataclass(frozen=True) class SensorSpec: part_number: str kind: Literal["inductive", "optical", "hall"] propagation_delay_ns: float price: float source: str sensitivity_v_per_mps: float | None = None threshold_v: float | None = None url: str | None = None @dataclass(frozen=True) class ProjectileMaterialSpec: name: str density_kg_m3: float mu_r: float b_sat_tesla: float price_per_kg: float source: str # электрическое удельное сопротивление — для расчёта вихревых потерь в снаряде # (сплошной проводник в импульсном поле). Дефолт ~ конструкционная сталь. resistivity_ohm_m: float = 1.6e-7 url: str | None = None