Skip to content

Commit e641581

Browse files
authored
Merge pull request #91 from diodeinc/add-resistor-power-rating
Add power to Resistor, use it for matching
2 parents a285825 + 23cff55 commit e641581

File tree

3 files changed

+156
-37
lines changed

3 files changed

+156
-37
lines changed

bom/helpers.zen

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""BOM matching helper functions"""
22

33
load("../utils.zen", "e96", "e24")
4+
load("../units.zen", "ResistanceRange", "Voltage", "Power", "Capacitance")
45

56

67
def prop(c, names):
@@ -89,14 +90,15 @@ def iec60062_3digit(value):
8990
return sig_digits + str(mult)
9091

9192

92-
def resistor_series(series, min_val, max_val, max_v, tolerance, e_series, encode, suffix):
93+
def resistor_series(manufacturer, series, resistance_range, max_v, power, tolerance, e_series, encode, suffix):
9394
"""Helper to create resistor series entry.
9495

9596
Args:
97+
manufacturer: Manufacturer name (e.g., "Panasonic Electronic Components")
9698
series: Series prefix (e.g., "ERJ-2RKF")
97-
min_val: Min resistance (e.g., "10Ohm")
98-
max_val: Max resistance (e.g., "1MOhm")
99+
resistance_range: Resistance range (e.g., "10Ohm – 1MOhm")
99100
max_v: Max voltage (e.g., "50V")
101+
power: Power rating (e.g., "0.1W")
100102
tolerance: Tolerance string (e.g., "1%")
101103
e_series: List of E-series (e.g., ["e96", "e24"])
102104
encode: Encoding function (iec60062_3digit or iec60062_4digit)
@@ -106,17 +108,73 @@ def resistor_series(series, min_val, max_val, max_v, tolerance, e_series, encode
106108
Resistor series dictionary
107109
"""
108110
return {
111+
"manufacturer": manufacturer,
109112
"series": series,
110-
"min": min_val,
111-
"max": max_val,
112-
"max_v": max_v,
113+
"resistance_range": ResistanceRange(resistance_range),
114+
"max_v": Voltage(max_v),
115+
"power": Power(power),
113116
"tolerance": tolerance,
114117
"e_series": e_series,
115118
"encode": encode,
116119
"suffix": suffix,
117120
}
118121

119122

123+
def panasonic_erj(series, resistance_range, voltage, power, tolerance, e_series, suffix, encode):
124+
"""Shorthand for Panasonic ERJ resistor series.
125+
126+
Args:
127+
series: Series name (e.g., "ERJ-3EKF")
128+
resistance_range: Resistance range (e.g., "10Ohm – 1MOhm")
129+
voltage: Max voltage (e.g., "75V")
130+
power: Power rating (e.g., "0.333W")
131+
tolerance: Tolerance string (e.g., "1%")
132+
e_series: List of E-series (e.g., ["e96", "e24"])
133+
suffix: MPN suffix (e.g., "V")
134+
encode: Encoding function (iec60062_3digit or iec60062_4digit)
135+
136+
Returns:
137+
Resistor series dictionary
138+
"""
139+
return resistor_series(
140+
"Panasonic Electronic Components",
141+
series,
142+
resistance_range,
143+
voltage,
144+
power,
145+
tolerance,
146+
e_series,
147+
encode,
148+
suffix,
149+
)
150+
151+
152+
def discrete_resistor_series(manufacturer, series, max_v, power, tolerance, values_with_mpns):
153+
"""Helper to create discrete resistor series (non-E-series, exact values only).
154+
155+
Args:
156+
manufacturer: Manufacturer name (e.g., "Stackpole Electronics Inc")
157+
series: Series name (e.g., "CSNL2512")
158+
max_v: Max voltage (e.g., "170V")
159+
power: Power rating (e.g., "2W")
160+
tolerance: Tolerance string (e.g., "1%")
161+
values_with_mpns: List of tuples [(resistance_str, mpn), ...]
162+
e.g., [("0.5mOhm", "CSNL2512FTL500"), ("1mOhm", "CSNL2512FT1L00")]
163+
164+
Returns:
165+
Discrete resistor series dictionary
166+
"""
167+
return {
168+
"type": "discrete",
169+
"manufacturer": manufacturer,
170+
"series": series,
171+
"values": values_with_mpns,
172+
"max_v": Voltage(max_v),
173+
"power": Power(power),
174+
"tolerance": tolerance,
175+
}
176+
177+
120178
def murata_cap(dielectric, voltage, cap, base_mpn, suffixes, manufacturer="Murata Electronics"):
121179
"""Helper to create Murata capacitor entry with auto-generated packaging variants.
122180

@@ -135,8 +193,8 @@ def murata_cap(dielectric, voltage, cap, base_mpn, suffixes, manufacturer="Murat
135193

136194
return {
137195
"dielectric": dielectric,
138-
"voltage": voltage,
139-
"cap": cap,
196+
"voltage": Voltage(voltage),
197+
"cap": Capacitance(cap),
140198
"mpns": mpns,
141199
"manufacturer": manufacturer,
142200
}

bom/match_generics.zen

Lines changed: 84 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@
33
Automatically assigns house MPNs to resistors and capacitors.
44
"""
55

6-
load("../units.zen", "Voltage", "Resistance", "Capacitance")
6+
load("../units.zen", "Voltage", "Resistance", "ResistanceRange", "Capacitance", "Power")
77
load(
88
"helpers.zen",
99
"prop",
1010
"set_primary_and_alts",
1111
"find_e_series_match",
1212
"iec60062_3digit",
1313
"iec60062_4digit",
14-
"resistor_series",
14+
"panasonic_erj",
15+
"discrete_resistor_series",
1516
"murata_cap",
1617
)
1718

@@ -31,16 +32,50 @@ _DIELECTRIC_RANK = {
3132
# Resistor series by package
3233
SERIES_BY_PKG = {
3334
"0402": [
34-
resistor_series("ERJ-H2CF", "1Ohm", "10Ohm", "50V", "1%", ["e96", "e24"], iec60062_4digit, "X"),
35-
resistor_series("ERJ-2RKF", "10Ohm", "1MOhm", "50V", "1%", ["e96", "e24"], iec60062_4digit, "X"),
36-
resistor_series("ERJ-U02J", "1MOhm", "10MOhm", "50V", "5%", ["e24"], iec60062_3digit, "X"),
37-
resistor_series("ERJ-PA2F", "1Ohm", "1MOhm", "50V", "1%", ["e96", "e24"], iec60062_4digit, "X"),
35+
panasonic_erj("ERJ-H2CF", "1Ohm – 10Ohm", "50V", "0.1W", "1%", ["e96", "e24"], "X", iec60062_4digit),
36+
panasonic_erj("ERJ-2RKF", "10Ohm – 1MOhm", "50V", "0.1W", "1%", ["e96", "e24"], "X", iec60062_4digit),
37+
panasonic_erj("ERJ-U02J", "1MOhm – 10MOhm", "50V", "0.1W", "5%", ["e24"], "X", iec60062_3digit),
38+
panasonic_erj("ERJ-PA2F", "1Ohm – 1MOhm", "50V", "0.1W", "1%", ["e96", "e24"], "X", iec60062_4digit),
3839
],
3940
"0603": [
40-
resistor_series("ERJ-H3QF", "1Ohm", "10Ohm", "75V", "1%", ["e96", "e24"], iec60062_4digit, "V"),
41-
resistor_series("ERJ-3EKF", "10Ohm", "1MOhm", "75V", "1%", ["e96", "e24"], iec60062_4digit, "V"),
42-
resistor_series("ERJ-U03J", "1MOhm", "10MOhm", "75V", "5%", ["e24"], iec60062_3digit, "V"),
43-
resistor_series("ERJ-PA3F", "1Ohm", "1MOhm", "75V", "1%", ["e96", "e24"], iec60062_4digit, "V"),
41+
panasonic_erj("ERJ-H3QF", "1Ohm – 10Ohm", "75V", "0.333W", "1%", ["e96", "e24"], "V", iec60062_4digit),
42+
panasonic_erj("ERJ-3EKF", "10Ohm – 1MOhm", "75V", "0.333W", "1%", ["e96", "e24"], "V", iec60062_4digit),
43+
panasonic_erj("ERJ-U03J", "1MOhm – 10MOhm", "75V", "0.333W", "5%", ["e24"], "V", iec60062_3digit),
44+
panasonic_erj("ERJ-PA3F", "1Ohm – 1MOhm", "75V", "0.333W", "1%", ["e96", "e24"], "V", iec60062_4digit),
45+
],
46+
"2512": [
47+
# Stackpole CSNL series: Current sense resistors
48+
discrete_resistor_series(
49+
"Stackpole Electronics Inc",
50+
"CSNL2512",
51+
"170V",
52+
"2W",
53+
"1%",
54+
[
55+
("1mOhm", "CSNL2512FT1L00"),
56+
("2mOhm", "CSNL2512FT2L00"),
57+
("3mOhm", "CSNL2512FT3L00"),
58+
("4mOhm", "CSNL2512FT4L00"),
59+
("5mOhm", "CSNL2512FT5L00"),
60+
("10mOhm", "CSNL2512FT10L0"),
61+
],
62+
),
63+
# YAGEO PA_E series: AEC-Q200 current sense resistors
64+
discrete_resistor_series(
65+
"YAGEO",
66+
"PA_E",
67+
"170V",
68+
"2W",
69+
"1%",
70+
[
71+
("1mOhm", "PA2512FKF7W0R001E"),
72+
("2mOhm", "PA2512FKF7W0R002E"),
73+
("3mOhm", "PA2512FKF7W0R003E"),
74+
("4mOhm", "PA2512FKF7W0R004E"),
75+
("5mOhm", "PA2512FKF7W0R005E"),
76+
("10mOhm", "PA2512FKF7W0R01E"),
77+
],
78+
),
4479
],
4580
}
4681

@@ -104,34 +139,56 @@ def assign_house_resistor(c, series_by_pkg):
104139
resistance = Resistance(prop(c, ["resistance", "Resistance"]))
105140
pkg = prop(c, ["package", "Package"])
106141
v_req = prop(c, ["Voltage", "voltage"])
107-
voltage_constraint = Voltage(v_req).value if v_req else None
142+
voltage_constraint = Voltage(v_req) if v_req else None
143+
p_req = prop(c, ["Power", "power"])
144+
power_constraint = Power(p_req) if p_req else None
108145

109146
# Skip 0 ohm resistors - they can't be matched to E-series
110-
if resistance.value <= 0:
147+
if resistance.value <= 0.0:
111148
return
112149

113150
series_list = series_by_pkg.get(pkg, [])
114151
matches = []
152+
manufacturer = None
153+
115154
for spec in series_list:
116-
spec_min = Resistance(spec["min"]).value
117-
spec_max = Resistance(spec["max"]).value
118-
spec_max_v = Voltage(spec["max_v"]).value
155+
spec_type = spec.get("type", "e_series")
156+
spec_max_v = spec["max_v"]
157+
spec_power = spec["power"]
119158
spec_tol = float(spec["tolerance"].replace("%", "")) / 100.0
120159

121160
if voltage_constraint and voltage_constraint > spec_max_v:
122161
continue
123162

124-
matched = find_e_series_match(resistance, spec_tol, spec["e_series"])
125-
if not matched or matched.value < spec_min or matched.value > spec_max:
163+
if power_constraint and power_constraint > spec_power:
126164
continue
127165

128-
encoder = spec.get("encode", iec60062_4digit)
129-
code = encoder(matched.value)
130-
mpn = spec["series"] + code + spec.get("suffix", "X")
131-
matches.append(mpn)
166+
if spec_type == "discrete":
167+
# Discrete series: exact value match with tolerance
168+
r_with_tol = resistance.with_tolerance(spec_tol) if resistance.tolerance <= 0 else resistance
169+
170+
for val_str, mpn in spec["values"]:
171+
val_r = Resistance(val_str).with_tolerance(spec_tol)
172+
if val_r.within(r_with_tol):
173+
matches.append(mpn)
174+
if manufacturer == None:
175+
manufacturer = spec["manufacturer"]
176+
else:
177+
# E-series: standard matching logic
178+
spec_range = spec["resistance_range"]
179+
matched = find_e_series_match(resistance, spec_tol, spec["e_series"])
180+
if not matched or matched.value < spec_range.min or matched.value > spec_range.max:
181+
continue
182+
183+
encoder = spec.get("encode", iec60062_4digit)
184+
code = encoder(matched.value)
185+
mpn = spec["series"] + code + spec.get("suffix", "X")
186+
matches.append(mpn)
187+
if manufacturer == None:
188+
manufacturer = spec["manufacturer"]
132189

133190
if matches:
134-
set_primary_and_alts(c, matches[0], "Panasonic Electronic Components", matches[1:])
191+
set_primary_and_alts(c, matches[0], manufacturer, matches[1:])
135192
c.matcher = "assign_house_resistor"
136193
return
137194

@@ -156,7 +213,7 @@ def assign_house_capacitor(c, house_caps_by_pkg):
156213
pkg = prop(c, ["package", "Package"])
157214
req_diel = prop(c, ["dielectric", "Dielectric"])
158215
v_req = prop(c, ["voltage", "Voltage"])
159-
req_voltage = Voltage(v_req).value if v_req else None
216+
req_voltage = Voltage(v_req) if v_req else None
160217

161218
if cap.tolerance <= 0:
162219
cap = cap.with_tolerance(0.2)
@@ -165,8 +222,8 @@ def assign_house_capacitor(c, house_caps_by_pkg):
165222
matches = []
166223

167224
for p in parts:
168-
p_cap = Capacitance(p["cap"])
169-
p_voltage = Voltage(p["voltage"]).value
225+
p_cap = p["cap"]
226+
p_voltage = p["voltage"]
170227

171228
if req_diel:
172229
h_rank = _DIELECTRIC_RANK.get(p["dielectric"], 99)
@@ -180,9 +237,9 @@ def assign_house_capacitor(c, house_caps_by_pkg):
180237
if not p_cap.within(cap):
181238
continue
182239

183-
err = abs(p_cap.value - cap.value) / cap.value
240+
err = p_cap.diff(cap) / cap
184241
diel_rank = _DIELECTRIC_RANK.get(p["dielectric"], 99)
185-
score = (err, p_cap.tolerance, -p_voltage, diel_rank)
242+
score = (err, p_cap.tolerance, p_voltage * -1, diel_rank)
186243

187244
matches.append((score, p))
188245

generics/Resistor.zen

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
load("../config.zen", "config_unit")
2-
load("../units.zen", "Resistance", "Voltage")
2+
load("../units.zen", "Resistance", "Voltage", "Power")
33
load("../utils.zen", "format_value")
44

55
# -----------------------------------------------------------------------------
@@ -22,6 +22,7 @@ mpn = config("mpn", str, optional=True)
2222
manufacturer = config("manufacturer", str, optional=True)
2323
mount = config("mount", Mount, default=Mount("SMD"), optional=True)
2424
voltage = config_unit("voltage", Voltage, optional=True)
25+
power = config_unit("power", Power, optional=True)
2526
use_us_symbol = config("use_us_symbol", bool, default=False, optional=True)
2627

2728
do_not_populate = config("do_not_populate", bool, default=False)
@@ -34,12 +35,15 @@ if exclude_from_bom:
3435

3536
# Properties – combined and normalized
3637
properties = {
37-
"value": format_value(value, voltage),
38+
"value": format_value(value, voltage, power),
3839
"package": package,
3940
"resistance": value,
4041
"voltage": voltage,
4142
}
4243

44+
if power:
45+
properties["power"] = power
46+
4347
# -----------------------------------------------------------------------------
4448
# IO ports
4549
# -----------------------------------------------------------------------------

0 commit comments

Comments
 (0)