Skip to content
This repository has been archived by the owner on Dec 10, 2024. It is now read-only.

Commit

Permalink
api picker: fix generate_si_values
Browse files Browse the repository at this point in the history
  • Loading branch information
iopapamanoglou committed Nov 15, 2024
1 parent c6cd2cb commit c0d979c
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 31 deletions.
4 changes: 1 addition & 3 deletions src/faebryk/libs/picker/api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from faebryk.core.module import Module

# TODO: replace with API-specific data model
from faebryk.libs.picker.common import SIvalue
from faebryk.libs.picker.jlcpcb.jlcpcb import Component, MappingParameterDB
from faebryk.libs.picker.lcsc import LCSC_NoDataException, LCSC_PinmapException
from faebryk.libs.picker.picker import PickError
Expand Down Expand Up @@ -104,9 +105,6 @@ def try_attach(
return False


type SIvalue = str


@dataclass_json
@dataclass(frozen=True)
class FootprintCandidate:
Expand Down
40 changes: 24 additions & 16 deletions src/faebryk/libs/picker/api/picker_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@

# re-use the existing model for components from the jlcparts dataset, but as the data
# schema diverges over time we'll migrate this to separate models
from faebryk.libs.picker.common import SIvalue, generate_si_values
from faebryk.libs.picker.jlcpcb.jlcpcb import Component
from faebryk.libs.picker.jlcpcb.picker_lib import _MAPPINGS_BY_TYPE
from faebryk.libs.picker.picker import DescriptiveProperties, PickError
from faebryk.libs.units import Quantity
from faebryk.libs.util import KeyErrorAmbiguous, KeyErrorNotFound

logger = logging.getLogger(__name__)
Expand All @@ -40,13 +40,6 @@
qty: int = 1


def generate_si_values(
param: Parameter, si_unit: str, e_series: E_SERIES
) -> list[Quantity]:
# FIXME: implement with new params
raise NotImplementedError()


def find_component_by_lcsc_id(lcsc_id: str, solver: Solver) -> Component:
def extract_numeric_id(lcsc_id: str) -> int:
match = re.match(r"C(\d+)", lcsc_id)
Expand Down Expand Up @@ -80,7 +73,7 @@ def find_and_attach_by_lcsc_id(module: Module, solver: Solver):

# TODO: pass through errors from API
try:
part = find_component_by_lcsc_id(lcsc_pn)
part = find_component_by_lcsc_id(lcsc_pn, solver)
except KeyErrorNotFound as e:
raise PickError(
f"Could not find part with LCSC part number {lcsc_pn}", module
Expand Down Expand Up @@ -133,7 +126,7 @@ def find_and_attach_by_mfr(module: Module, solver: Solver):
mfr_pn = properties[DescriptiveProperties.partno]

try:
parts = [find_component_by_mfr(mfr, mfr_pn)]
parts = [find_component_by_mfr(mfr, mfr_pn, solver)]
except KeyErrorNotFound as e:
raise PickError(
f"Could not find part with manufacturer part number {mfr_pn}", module
Expand Down Expand Up @@ -180,6 +173,13 @@ def _get_footprint_candidates(module: Module) -> list[FootprintCandidate]:
return []


def _generate_si_values(
value: Parameter, solver: Solver, e_series: E_SERIES | None = None
) -> list[SIvalue]:
candidate_ranges = solver.inspect_get_known_superranges(value)
return generate_si_values(candidate_ranges, e_series=e_series)


def find_resistor(cmp: Module, solver: Solver):
"""
Find a resistor with matching parameters
Expand All @@ -189,7 +189,9 @@ def find_resistor(cmp: Module, solver: Solver):

parts = client.fetch_resistors(
ResistorParams(
resistances=generate_si_values(cmp.resistance, "Ω", E_SERIES_VALUES.E96),
resistances=_generate_si_values(
cmp.resistance, solver, E_SERIES_VALUES.E96
),
footprint_candidates=_get_footprint_candidates(cmp),
qty=qty,
),
Expand All @@ -207,7 +209,9 @@ def find_capacitor(cmp: Module, solver: Solver):

parts = client.fetch_capacitors(
CapacitorParams(
capacitances=generate_si_values(cmp.capacitance, "F", E_SERIES_VALUES.E24),
capacitances=_generate_si_values(
cmp.capacitance, solver, E_SERIES_VALUES.E24
),
footprint_candidates=_get_footprint_candidates(cmp),
qty=qty,
),
Expand All @@ -225,7 +229,9 @@ def find_inductor(cmp: Module, solver: Solver):

parts = client.fetch_inductors(
InductorParams(
inductances=generate_si_values(cmp.inductance, "H", E_SERIES_VALUES.E24),
inductances=_generate_si_values(
cmp.inductance, solver, E_SERIES_VALUES.E24
),
footprint_candidates=_get_footprint_candidates(cmp),
qty=qty,
),
Expand Down Expand Up @@ -257,9 +263,11 @@ def find_diode(cmp: Module, solver: Solver):

parts = client.fetch_diodes(
DiodeParams(
max_currents=generate_si_values(cmp.max_current, "A", E_SERIES_VALUES.E3),
reverse_working_voltages=generate_si_values(
cmp.reverse_working_voltage, "V", E_SERIES_VALUES.E3
max_currents=_generate_si_values(
cmp.max_current, solver, E_SERIES_VALUES.E3
),
reverse_working_voltages=_generate_si_values(
cmp.reverse_working_voltage, solver, E_SERIES_VALUES.E3
),
footprint_candidates=_get_footprint_candidates(cmp),
qty=qty,
Expand Down
35 changes: 35 additions & 0 deletions src/faebryk/libs/picker/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@
from faebryk.core.module import Module
from faebryk.core.parameter import And, Is, Parameter, ParameterOperatable, Predicate
from faebryk.core.solver import Solver
from faebryk.libs.e_series import E_SERIES, e_series_intersect
from faebryk.libs.library import L
from faebryk.libs.picker.jlcpcb.jlcpcb import Component
from faebryk.libs.picker.lcsc import attach
from faebryk.libs.picker.picker import (
PickError,
has_part_picked,
has_part_picked_defined,
)
from faebryk.libs.units import Quantity, to_si_str
from faebryk.libs.util import ConfigFlagEnum

logger = logging.getLogger(__name__)
Expand All @@ -31,6 +34,7 @@ class PickerType(StrEnum):
DB_PICKER_BACKEND = ConfigFlagEnum(
PickerType, "PICKER", PickerType.API, "Picker backend to use"
)
type SIvalue = str


class StaticPartPicker(F.has_multi_picker.Picker, ABC):
Expand Down Expand Up @@ -139,3 +143,34 @@ def add_to_modules(modules: Iterable[Module], prio: int = 0):
picker = CachePicker()
for m in modules:
m.add(F.has_multi_picker(prio, picker))


class PickerUnboundedParameterError(Exception):
pass


class PickerESeriesIntersectionError(Exception):
pass


def generate_si_values(
value: L.Ranges[Quantity], e_series: E_SERIES | None = None
) -> list[SIvalue]:
if value.is_unbounded():
raise PickerUnboundedParameterError(value)

intersection = e_series_intersect(value, e_series)
if intersection.is_empty():
raise PickerESeriesIntersectionError(f"No intersection with E-series: {value}")
si_unit = value.units

def _get_single(single: L.Range):
assert single.min_elem() == single.max_elem()
return single.min_elem()

si_vals = [
to_si_str(_get_single(r), si_unit).replace("µ", "u").replace("inf", "∞")
for r in intersection
]

return si_vals
24 changes: 12 additions & 12 deletions src/faebryk/libs/picker/jlcpcb/jlcpcb.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,13 @@
from faebryk.core.solver import Solver
from faebryk.libs.e_series import (
E_SERIES,
e_series_intersect,
)
from faebryk.libs.library import L
from faebryk.libs.picker.common import (
PickerESeriesIntersectionError,
PickerUnboundedParameterError,
generate_si_values,
)
from faebryk.libs.picker.lcsc import (
LCSC_NoDataException,
LCSC_Part,
Expand All @@ -49,7 +53,6 @@
P,
Quantity,
UndefinedUnitError,
to_si_str,
)
from faebryk.libs.util import at_exit, cast_assert, once

Expand Down Expand Up @@ -442,21 +445,18 @@ def filter_by_si_values(
tolerance_requirement: float | None = None,
) -> Self:
assert self.Q
assert not self.results

if value.is_unbounded():
try:
si_vals = generate_si_values(value, e_series)
except PickerUnboundedParameterError:
return self
assert not self.results
intersection = e_series_intersect(value, e_series)
if intersection.is_empty():
raise ComponentQuery.ParamError(value, "No intersection with E-series")
si_unit = value.units
si_vals = [
to_si_str(r.min_elem(), si_unit).replace("µ", "u").replace("inf", "∞")
for r in intersection
]
except PickerESeriesIntersectionError as e:
raise ComponentQuery.ParamError(value, str(e)) from e

if tolerance_requirement:
self.filter_by_tolerance(tolerance_requirement)

return self.filter_by_description(*si_vals)

def hint_filter_parameter(
Expand Down

0 comments on commit c0d979c

Please sign in to comment.