component
MAL216099702E3 - 100 uF 80 V SMD Aluminium Electrolytic Capacitor, 150 C
Public Made by Adomby adom
Vishay BCcomponents MAL216099702E3 (160 CLA series): polarized SMD aluminium electrolytic capacitor, 100 uF +-20 %, 80 V, -55 C to +150 C, low impedance, AEC-Q200, 12.5 x 12.5 x 16 mm 4-pin case (1216). KiCad, Fusion and Altium libraries, 3D model and datasheet.
main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
#!/usr/bin/env python3
"""Pad-by-pad check of the MAL216099702E3 footprint against Vishay doc 28405 Table 3 / Fig. 4 (case 1216: a 6.3,
b 2.5, c 4.0, d 4.2, e 5.0, f 5.6), plus the 3D model's contacts (section at z = 0.01 mm) against the pads and the
polarity chain (anode terminal over pad 1, the bevelled plate corners on the pad-1 side, the cathode bar over pad 2).
Footprint frame: KiCad, Y down; model frame: Z up, Y up (y flipped for comparison).
usage: landcheck_cla.py fp.kicad_mod model.step out.json out.png (CadQuery python)"""
import re, sys, json
import cadquery as cq
from OCP.BRepAlgoAPI import BRepAlgoAPI_Section
from OCP.gp import gp_Pln, gp_Pnt, gp_Dir
import matplotlib; matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle, Polygon
fp, step, oj, op = sys.argv[1:5]
s = open(fp).read()
pads = [dict(n=m[0], x=float(m[1]), y=float(m[2]), w=float(m[3]), h=float(m[4]))
for m in re.findall(r'\(pad "(\w*)" smd \w+\s*\(at (\S+) (\S+)\)\s*\(size (\S+) (\S+)\)', s)]
a, b, c, d, e, f = 6.3, 2.5, 4.0, 4.2, 5.0, 5.6
ref = [dict(n="1", x=-(c / 2 + a / 2), y=0.0, w=a, h=b), dict(n="2", x=c / 2 + a / 2, y=0.0, w=a, h=b),
dict(n="MP", x=0.0, y=-(f / 2 + d / 2), w=e, h=d), dict(n="MP", x=0.0, y=f / 2 + d / 2, w=e, h=d)]
rows = []; ok = True
for r in ref:
p = next((p for p in pads if p["n"] == r["n"] and abs(p["x"] - r["x"]) < 1e-6 and abs(p["y"] - r["y"]) < 1e-6), None)
m = p is not None and abs(p["w"] - r["w"]) < 1e-6 and abs(p["h"] - r["h"]) < 1e-6
ok &= m; rows.append(dict(pad=r["n"], vishay=r, page=p, match=m))
# derived checks on the printed spacing
d_checks = {"main pad inner gap (c)": round(min(p["x"] - p["w"] / 2 for p in pads if p["n"] == "2") - max(p["x"] + p["w"] / 2 for p in pads if p["n"] == "1"), 4),
"MP pad gap (f)": round(min(p["y"] - p["h"] / 2 for p in pads if p["n"] == "MP" and p["y"] > 0) - max(p["y"] + p["h"] / 2 for p in pads if p["n"] == "MP" and p["y"] < 0), 4)}
shape = cq.importers.importStep(step)
shp = cq.Compound.makeCompound(shape.solids().vals())
sec = BRepAlgoAPI_Section(shp.wrapped, gp_Pln(gp_Pnt(0, 0, 0.01), gp_Dir(0, 0, 1))); sec.Build()
contacts = {}
for ed in cq.Shape.cast(sec.Shape()).Edges():
bb = ed.BoundingBox(); cx, cy = (bb.xmin + bb.xmax) / 2, -(bb.ymin + bb.ymax) / 2
key = ("L" if cx < -1.9 else "R" if cx > 1.9 else ("T" if cy < 0 else "B"))
C_ = contacts.setdefault(key, [9e9, 9e9, -9e9, -9e9])
C_[0] = min(C_[0], bb.xmin); C_[1] = min(C_[1], -bb.ymax); C_[2] = max(C_[2], bb.xmax); C_[3] = max(C_[3], -bb.ymin)
inside = {}
for k, (x0, y0, x1, y1) in contacts.items():
p = min(pads, key=lambda p: (p["x"] - (x0 + x1) / 2) ** 2 + (p["y"] - (y0 + y1) / 2) ** 2)
inside[k] = dict(contact=[round(v, 3) for v in (x0, y0, x1, y1)], pad=p["n"], pad_xy=[p["x"], p["y"]],
inside=bool(p["x"] - p["w"] / 2 - 1e-6 <= x0 and x1 <= p["x"] + p["w"] / 2 + 1e-6 and p["y"] - p["h"] / 2 - 1e-6 <= y0 and y1 <= p["y"] + p["h"] / 2 + 1e-6))
pol = {"anode_terminal_over_pad": inside.get("L", {}).get("pad"), "cathode_terminal_over_pad": inside.get("R", {}).get("pad"),
"bevelled_plate_corners_side": "-X (pad 1 side), from the model's plate outline and the footprint's F.Fab / silkscreen outline",
"cathode_bar_side": "+X (pad 2 side) on the can top", "silk_plus_next_to": "pad 1"}
res = dict(schema="adom/footprint-check@1", reference="Vishay doc 28405 rev. 20-Aug-2026, p.3 Fig. 4 and Table 3, case code 1216 (Fig. 4 drawn with the anode on the right; this footprint is that pattern turned 180 deg so pad 1 = anode is on the left, the KiCad CP_Elec convention)",
values_mm=dict(a=a, b=b, c=c, d=d, e=e, f=f), all_pads_match=ok, pads=rows, derived=d_checks,
model_contact=dict(method="section of the 3D model at z = 0.01 mm, bounding box per contact group", contacts=inside,
all_inside=all(v["inside"] for v in inside.values())),
polarity=pol, kicad_comparison="KiCad's standard library has no 12.5 mm CP_Elec footprint and no 4-pin (dummy pin) variant; nearest is CP_Elec_16x17.5, a different case. No KiCad comparison is possible.")
json.dump(res, open(oj, "w"), indent=1)
fig, ax = plt.subplots(figsize=(8, 7), dpi=120)
for p in pads:
ax.add_patch(Rectangle((p["x"] - p["w"] / 2, p["y"] - p["h"] / 2), p["w"], p["h"], fc="#00b8b1", alpha=0.45, ec="#00807a"))
ax.text(p["x"], p["y"], p["n"], ha="center", va="center", fontsize=10, weight="bold")
for k, (x0, y0, x1, y1) in contacts.items():
ax.add_patch(Rectangle((x0, y0), x1 - x0, y1 - y0, fc="#333", alpha=0.6))
h, bv = 6.4, 2.6
ax.add_patch(Polygon([(-h + bv, -h), (h, -h), (h, h), (-h + bv, h), (-h, h - bv), (-h, -h + bv)], fill=False, ec="#555"))
ax.text(-7.6, -2.6, "+", fontsize=14, ha="center", va="center", weight="bold")
ax.set_xlim(-9.5, 9.5); ax.set_ylim(8.5, -8.5); ax.set_aspect("equal"); ax.grid(alpha=0.2)
ax.set_title("MAL216099702E3 footprint check (KiCad frame, Y down, mm)", fontsize=10)
fig.text(0.02, 0.02, "teal: page pads = Vishay Fig. 4 / Table 3 case 1216 (turned 180 deg); dark: model terminal and dummy-pin contacts at z = 0.01 mm;\n"
"grey: base plate 12.8 mm with the bevelled corners on the anode (pad 1, +) side", fontsize=7.5, va="bottom")
fig.subplots_adjust(bottom=0.12); fig.savefig(op, bbox_inches="tight")
print(json.dumps({"all_pads_match": ok, "contacts_inside": res["model_contact"]["all_inside"], "derived": d_checks, "polarity": {k: pol[k] for k in list(pol)[:2]}}))