Files
2026-07-20 17:36:17 +02:00

143 lines
6.0 KiB
Python

load("../io.zen", "io")
load("../interfaces.zen", "Net")
load("../units.zen", "Capacitance", "Inductance", "Resistance", "Temperature", "Voltage")
load("../utils.zen", "capacitor_voltage_rating", "format_value")
Package = enum("01005", "0201", "0402", "0603", "0805", "1206", "1210", "1812", "1825", "2220", "2225", "3640")
Mount = enum("SMD")
Dielectric = enum("C0G", "NP0", "X5R", "X7R", "X7S", "X7T", "Y5V", "Z5U")
package = config(Package, default=Package("0603"))
value = config(Capacitance)
mpn = config(str, optional=True, help="Manufacturer Part Number")
manufacturer = config(str, optional=True, help="Manufacturer")
mount = config(Mount, default=Mount("SMD"), optional=True, help="Mounting type")
voltage = config(Voltage, optional=True, help="Maximum operating voltage")
dielectric = config(Dielectric, optional=True, help="Dielectric material type")
esr = config(Resistance, optional=True, help="Equivalent series resistance")
esl = config(Inductance, optional=True, help="Equivalent series inductance")
t_max = config(Temperature, optional=True, help="Maximum operating temperature")
t_min = config(Temperature, optional=True, help="Minimum operating temperature")
skip_bom = config(bool, default=False, help="Skip the BOM generation")
P1 = io(Net)
P2 = io(Net)
net_voltage_diff = P1.voltage.diff(P2.voltage) if P1.voltage and P2.voltage else None
default_voltage = capacitor_voltage_rating(Voltage(net_voltage_diff * 1.5)) if net_voltage_diff != None else None
if voltage and net_voltage_diff != None and voltage < net_voltage_diff:
warn(
f"Capacitor voltage rating ({voltage}) should be >= net voltage difference ({net_voltage_diff})",
kind="capacitor.voltage_rating",
)
effective_voltage = voltage if voltage else default_voltage
# Properties
properties = {
"value": format_value(value, effective_voltage, dielectric, esr),
"package": package,
"capacitance": value,
}
if effective_voltage:
properties["voltage"] = effective_voltage
if dielectric:
properties["dielectric"] = dielectric
if esr:
properties["esr"] = esr
def _symbol(mount: Mount, package: Package):
return "../kicad-symbols/Device.kicad_symdir/C_Small.kicad_sym"
def _footprint(mount: Mount, package: Package):
kicad_footprints = {
(Mount("SMD"), Package("01005")): "../kicad-footprints/Capacitor_SMD.pretty/C_01005_0402Metric.kicad_mod",
(Mount("SMD"), Package("0201")): "../kicad-footprints/Capacitor_SMD.pretty/C_0201_0603Metric.kicad_mod",
(Mount("SMD"), Package("0402")): "../kicad-footprints/Capacitor_SMD.pretty/C_0402_1005Metric.kicad_mod",
(Mount("SMD"), Package("0603")): "../kicad-footprints/Capacitor_SMD.pretty/C_0603_1608Metric.kicad_mod",
(Mount("SMD"), Package("0805")): "../kicad-footprints/Capacitor_SMD.pretty/C_0805_2012Metric.kicad_mod",
(Mount("SMD"), Package("1206")): "../kicad-footprints/Capacitor_SMD.pretty/C_1206_3216Metric.kicad_mod",
(Mount("SMD"), Package("1210")): "../kicad-footprints/Capacitor_SMD.pretty/C_1210_3225Metric.kicad_mod",
(Mount("SMD"), Package("1812")): "../kicad-footprints/Capacitor_SMD.pretty/C_1812_4532Metric.kicad_mod",
(Mount("SMD"), Package("1825")): "../kicad-footprints/Capacitor_SMD.pretty/C_1825_4564Metric.kicad_mod",
(Mount("SMD"), Package("2220")): "../kicad-footprints/Capacitor_SMD.pretty/C_2220_5750Metric.kicad_mod",
(Mount("SMD"), Package("2225")): "../kicad-footprints/Capacitor_SMD.pretty/C_2225_5664Metric.kicad_mod",
(Mount("SMD"), Package("3640")): "../kicad-footprints/Capacitor_SMD.pretty/C_3640_9110Metric.kicad_mod",
}
if (mount, package) not in kicad_footprints:
error("Invalid footprint: " + str(mount) + " " + str(package))
return kicad_footprints[(mount, package)]
def _spice_args(value, package, esr=None, esl=None):
"""Derive series RLC model parameters for a realistic capacitor.
ESL is estimated from package size (pad geometry determines loop inductance).
ESR uses the user-supplied value if available, otherwise a reasonable
default that scales with package size.
"""
# Typical ESL by package -- based on published MLCC measurements (nH)
esl_table = {
Package("01005"): Inductance("0.08nH"),
Package("0201"): Inductance("0.15nH"),
Package("0402"): Inductance("0.35nH"),
Package("0603"): Inductance("0.5nH"),
Package("0805"): Inductance("0.7nH"),
Package("1206"): Inductance("1.0nH"),
Package("1210"): Inductance("1.0nH"),
Package("1812"): Inductance("1.5nH"),
Package("1825"): Inductance("1.5nH"),
Package("2220"): Inductance("2.0nH"),
Package("2225"): Inductance("2.0nH"),
Package("3640"): Inductance("2.5nH"),
}
# Typical ESR by package -- larger bodies dissipate better
esr_table = {
Package("01005"): Resistance("50mOhm"),
Package("0201"): Resistance("30mOhm"),
Package("0402"): Resistance("10mOhm"),
Package("0603"): Resistance("5mOhm"),
Package("0805"): Resistance("3mOhm"),
Package("1206"): Resistance("2mOhm"),
Package("1210"): Resistance("2mOhm"),
Package("1812"): Resistance("1.5mOhm"),
Package("1825"): Resistance("1.5mOhm"),
Package("2220"): Resistance("1mOhm"),
Package("2225"): Resistance("1mOhm"),
Package("3640"): Resistance("1mOhm"),
}
return {
"CVAL": value,
"ESR": esr or esr_table.get(package, Resistance("50mOhm")),
"ESL": esl or esl_table.get(package, Inductance("0.5nH")),
}
Component(
name="C",
part=builtin.Part(mpn=mpn, manufacturer=manufacturer) if mpn and manufacturer else None,
prefix="C",
symbol=Symbol(_symbol(mount, package)),
footprint=File(_footprint(mount, package)),
properties=properties,
type="capacitor",
pins={
"1": P1,
"2": P2,
},
spice_model=SpiceModel(
"spice/Capacitor.lib",
"C",
nets=[P1, P2],
args=_spice_args(value, package, esr, esl),
),
skip_bom=skip_bom,
)