Make ppt on solder join from bdc
What does "BDC" refer to here? I want to pull the right source content for the solder joint presentation.
ls -la /tmp/workspace/ 2>/dev/null || mkdir -p /tmp/workspace
~/attachments
~/solder_joint_ppt/build_ppt.py
from pptx import Presentation
from pptx.util import Inches, Pt, Emu
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.enum.shapes import MSO_SHAPE
# ---------- Palette ----------
NAVY = RGBColor(0x0B, 0x2B, 0x4A)
BLUE = RGBColor(0x1F, 0x6F, 0xB2)
LIGHT_BLUE = RGBColor(0xE8, 0xF1, 0xF8)
ORANGE = RGBColor(0xE8, 0x7A, 0x1E)
GREY = RGBColor(0x4A, 0x4A, 0x4A)
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
RED = RGBColor(0xC0, 0x39, 0x2B)
GREEN = RGBColor(0x27, 0xAE, 0x60)
prs = Presentation()
prs.slide_width = Inches(13.333)
prs.slide_height = Inches(7.5)
SW, SH = prs.slide_width, prs.slide_height
blank = prs.slide_layouts[6]
def add_slide():
return prs.slides.add_slide(blank)
def rect(slide, x, y, w, h, color, line=False):
shp = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, x, y, w, h)
shp.fill.solid()
shp.fill.fore_color.rgb = color
if line:
shp.line.color.rgb = color
shp.line.width = Pt(0.5)
else:
shp.line.fill.background()
shp.shadow.inherit = False
return shp
def textbox(slide, x, y, w, h, text, size=18, color=GREY, bold=False, align=PP_ALIGN.LEFT,
font="Calibri", italic=False, anchor=MSO_ANCHOR.TOP, wrap=True, line_spacing=1.0):
tb = slide.shapes.add_textbox(x, y, w, h)
tf = tb.text_frame
tf.word_wrap = wrap
tf.vertical_anchor = anchor
tf.margin_left = 0
tf.margin_right = 0
tf.margin_top = 0
tf.margin_bottom = 0
lines = text.split("\n")
for i, line in enumerate(lines):
p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
p.text = line
p.alignment = align
p.line_spacing = line_spacing
for r in p.runs:
r.font.size = Pt(size)
r.font.color.rgb = color
r.font.bold = bold
r.font.italic = italic
r.font.name = font
return tb
def bullets(slide, x, y, w, h, items, size=16, color=GREY, bold_first=False, font="Calibri",
space_after=8, bullet_color=BLUE, line_spacing=1.05):
tb = slide.shapes.add_textbox(x, y, w, h)
tf = tb.text_frame
tf.word_wrap = True
tf.margin_left = 0
tf.margin_right = 0
tf.margin_top = 0
tf.margin_bottom = 0
for i, item in enumerate(items):
if isinstance(item, tuple):
txt, lvl = item
else:
txt, lvl = item, 0
p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
p.space_after = Pt(space_after)
p.line_spacing = line_spacing
prefix = "• " if lvl == 0 else "- "
p.text = prefix + txt
p.level = 0
r = p.runs[0]
r.font.size = Pt(size - (2 if lvl else 0))
r.font.color.rgb = color
r.font.name = font
if lvl:
tb2 = None
return tb
def footer(slide, num, total=13, title="Solder Joints"):
rect(slide, 0, SH - Inches(0.35), SW, Inches(0.35), NAVY)
textbox(slide, Inches(0.4), SH - Inches(0.33), Inches(6), Inches(0.3), title,
size=10, color=WHITE, font="Calibri")
textbox(slide, SW - Inches(1.2), SH - Inches(0.33), Inches(0.8), Inches(0.3),
f"{num}/{total}", size=10, color=WHITE, align=PP_ALIGN.RIGHT)
def header(slide, kicker, title_text, title_color=NAVY):
rect(slide, 0, 0, SW, Inches(1.15), NAVY)
rect(slide, 0, Inches(1.15), SW, Inches(0.06), ORANGE)
textbox(slide, Inches(0.55), Inches(0.15), Inches(11), Inches(0.35), kicker.upper(),
size=13, color=ORANGE, bold=True, font="Calibri")
textbox(slide, Inches(0.55), Inches(0.5), Inches(12), Inches(0.6), title_text,
size=30, color=WHITE, bold=True, font="Calibri")
TOTAL = 13
# ============================================================
# SLIDE 1 - TITLE
# ============================================================
s = add_slide()
rect(s, 0, 0, SW, SH, NAVY)
rect(s, 0, Inches(5.0), SW, Inches(0.08), ORANGE)
textbox(s, Inches(0.9), Inches(2.5), Inches(11.5), Inches(0.5), "SOLDER JOINTS",
size=20, color=ORANGE, bold=True, font="Calibri")
textbox(s, Inches(0.9), Inches(3.0), Inches(11.5), Inches(1.4),
"Formation, Types, Quality Criteria & Inspection",
size(44) if False else 40, color=WHITE, bold=True, font="Calibri")
textbox(s, Inches(0.9), Inches(5.3), Inches(11), Inches(0.5),
"A Technical Overview for Electronics Assembly", size=18, color=RGBColor(0xC9,0xD9,0xEA), font="Calibri", italic=True)
textbox(s, Inches(0.9), Inches(6.8), Inches(6), Inches(0.4), "Reference: IPC-A-610 Acceptability Standards",
size=13, color=RGBColor(0x9A,0xB6,0xD1))
prs.save("/tmp/workspace/solder_joint_ppt/Solder_Joints.pptx")
print("draft saved slide 1")
mkdir -p /tmp/workspace/solder_joint_ppt
Quick answer
Where is my ppt
~/solder_joint_ppt/build_ppt.py
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.enum.shapes import MSO_SHAPE
NAVY = RGBColor(0x0B, 0x2B, 0x4A)
BLUE = RGBColor(0x1F, 0x6F, 0xB2)
LIGHT_BLUE = RGBColor(0xE8, 0xF1, 0xF8)
ORANGE = RGBColor(0xE8, 0x7A, 0x1E)
GREY = RGBColor(0x4A, 0x4A, 0x4A)
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
RED = RGBColor(0xC0, 0x39, 0x2B)
GREEN = RGBColor(0x27, 0xAE, 0x60)
LIGHT_GREY = RGBColor(0xF2, 0xF4, 0xF6)
prs = Presentation()
prs.slide_width = Inches(13.333)
prs.slide_height = Inches(7.5)
SW, SH = prs.slide_width, prs.slide_height
blank = prs.slide_layouts[6]
TOTAL = 12
def add_slide():
return prs.slides.add_slide(blank)
def rect(slide, x, y, w, h, color, line_color=None):
shp = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, x, y, w, h)
shp.fill.solid()
shp.fill.fore_color.rgb = color
if line_color:
shp.line.color.rgb = line_color
shp.line.width = Pt(1)
else:
shp.line.fill.background()
shp.shadow.inherit = False
return shp
def textbox(slide, x, y, w, h, text, size=18, color=GREY, bold=False, align=PP_ALIGN.LEFT,
font="Calibri", italic=False, anchor=MSO_ANCHOR.TOP, wrap=True, line_spacing=1.0):
tb = slide.shapes.add_textbox(x, y, w, h)
tf = tb.text_frame
tf.word_wrap = wrap
tf.vertical_anchor = anchor
tf.margin_left = 0
tf.margin_right = 0
tf.margin_top = 0
tf.margin_bottom = 0
lines = text.split("\n")
for i, line in enumerate(lines):
p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
p.text = line
p.alignment = align
p.line_spacing = line_spacing
for r in p.runs:
r.font.size = Pt(size)
r.font.color.rgb = color
r.font.bold = bold
r.font.italic = italic
r.font.name = font
return tb
def bullets(slide, x, y, w, h, items, size=16, color=GREY, font="Calibri",
space_after=8, line_spacing=1.05):
tb = slide.shapes.add_textbox(x, y, w, h)
tf = tb.text_frame
tf.word_wrap = True
tf.margin_left = 0
tf.margin_right = 0
tf.margin_top = 0
tf.margin_bottom = 0
for i, item in enumerate(items):
if isinstance(item, tuple):
txt, lvl = item
else:
txt, lvl = item, 0
p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
p.space_after = Pt(space_after)
p.line_spacing = line_spacing
prefix = "• " if lvl == 0 else "- "
p.text = (" " * lvl) + prefix + txt
r = p.runs[0]
r.font.size = Pt(size - (2 if lvl else 0))
r.font.color.rgb = color
r.font.name = font
r.font.bold = (lvl == 0 and False)
return tb
def footer(slide, num, title="Solder Joints"):
rect(slide, 0, SH - Inches(0.35), SW, Inches(0.35), NAVY)
textbox(slide, Inches(0.4), SH - Inches(0.33), Inches(6), Inches(0.3), title,
size=10, color=WHITE, font="Calibri")
textbox(slide, SW - Inches(1.2), SH - Inches(0.33), Inches(0.8), Inches(0.3),
f"{num}/{TOTAL}", size=10, color=WHITE, align=PP_ALIGN.RIGHT)
def header(slide, kicker, title_text):
rect(slide, 0, 0, SW, Inches(1.15), NAVY)
rect(slide, 0, Inches(1.15), SW, Inches(0.06), ORANGE)
textbox(slide, Inches(0.55), Inches(0.15), Inches(11), Inches(0.35), kicker.upper(),
size=13, color=ORANGE, bold=True, font="Calibri")
textbox(slide, Inches(0.55), Inches(0.5), Inches(12), Inches(0.6), title_text,
size=28, color=WHITE, bold=True, font="Calibri")
def card(slide, x, y, w, h, title, body_lines, title_color=BLUE, num=None):
rect(slide, x, y, w, h, LIGHT_GREY)
rect(slide, x, y, Inches(0.08), h, title_color)
ty = y + Inches(0.15)
if num:
textbox(slide, x + Inches(0.25), ty, w - Inches(0.4), Inches(0.4), num,
size=22, color=title_color, bold=True)
ty += Inches(0.42)
textbox(slide, x + Inches(0.25), ty, w - Inches(0.4), Inches(0.4), title,
size=16, color=NAVY, bold=True)
bullets(slide, x + Inches(0.25), ty + Inches(0.42), w - Inches(0.45), h - Inches(0.9),
body_lines, size=12.5, color=GREY, space_after=3)
# ============================================================
# SLIDE 1 - TITLE
# ============================================================
s = add_slide()
rect(s, 0, 0, SW, SH, NAVY)
rect(s, 0, Inches(5.0), SW, Inches(0.08), ORANGE)
textbox(s, Inches(0.9), Inches(2.4), Inches(11.5), Inches(0.5), "SOLDER JOINTS",
size=20, color=ORANGE, bold=True, font="Calibri")
textbox(s, Inches(0.9), Inches(2.9), Inches(11.5), Inches(1.4),
"Formation, Types, Quality Criteria\n& Inspection", size=40, color=WHITE, bold=True, font="Calibri")
textbox(s, Inches(0.9), Inches(4.6), Inches(11), Inches(0.5),
"A Technical Overview for Electronics Assembly", size=18, color=RGBColor(0xC9, 0xD9, 0xEA),
font="Calibri", italic=True)
textbox(s, Inches(0.9), Inches(6.8), Inches(8), Inches(0.4),
"Reference: IPC-A-610 Acceptability of Electronic Assemblies", size=13,
color=RGBColor(0x9A, 0xB6, 0xD1))
# ============================================================
# SLIDE 2 - AGENDA
# ============================================================
s = add_slide()
header(s, "Overview", "Agenda")
agenda = [
"1. What Is a Solder Joint?",
"2. The Soldering Process",
"3. Types of Solder Joints",
"4. Anatomy of a Good Joint",
"5. IPC-A-610 Classifications",
"6. Common Solder Defects",
"7. Cold Joints & Dry Joints",
"8. Inspection Methods",
"9. Reflow vs Wave Soldering",
"10. Best Practices",
"11. Summary",
]
bullets(s, Inches(0.9), Inches(1.6), Inches(10.5), Inches(5.2), agenda, size=20, color=NAVY, space_after=14)
footer(s, 2)
# ============================================================
# SLIDE 3 - WHAT IS A SOLDER JOINT
# ============================================================
s = add_slide()
header(s, "Fundamentals", "What Is a Solder Joint?")
textbox(s, Inches(0.55), Inches(1.5), Inches(6.3), Inches(0.5),
"Definition", size=18, color=BLUE, bold=True)
bullets(s, Inches(0.55), Inches(2.0), Inches(6.3), Inches(4.5), [
"A solder joint is a metallurgical bond formed when molten solder wets and adheres to two or more metal surfaces (e.g. a component lead and a PCB pad), then solidifies into a permanent electrical and mechanical connection.",
"Unlike a weld, the base metals are not melted -- only the solder liquefies and forms an intermetallic compound (IMC) layer with the base metals.",
"A properly formed joint provides:",
("Low-resistance electrical continuity", 1),
("Mechanical strength to withstand vibration/thermal cycling", 1),
("Environmental sealing against corrosion", 1),
], size=16, space_after=10)
rect(s, Inches(7.2), Inches(1.55), Inches(5.6), Inches(5.0), LIGHT_BLUE)
textbox(s, Inches(7.5), Inches(1.75), Inches(5.0), Inches(0.4), "Key Materials", size=16, color=NAVY, bold=True)
bullets(s, Inches(7.5), Inches(2.25), Inches(5.0), Inches(4.0), [
"Solder alloy: SAC305 (Sn96.5/Ag3.0/Cu0.5) -- lead-free standard",
"Sn63/Pb37 -- eutectic leaded (legacy/military/aerospace)",
"Flux: removes oxides, improves wetting (rosin, no-clean, water-soluble)",
"Base metals: Cu pads/traces, component leads (Cu, Sn, Ni-plated, etc.)",
"Substrate: FR-4 PCB with copper pads/plating",
], size=14.5, space_after=10)
footer(s, 3)
# ============================================================
# SLIDE 4 - SOLDERING PROCESS
# ============================================================
s = add_slide()
header(s, "Fundamentals", "The Soldering Process")
steps = [
("1", "Surface Prep", "Clean pad/lead surfaces; remove oxides and contaminants."),
("2", "Flux Application", "Flux applied to reduce surface tension and promote wetting."),
("3", "Heating", "Heat via iron, hot air, or reflow oven raises joint above solder liquidus temp."),
("4", "Wetting", "Molten solder flows and spreads across the base metal surfaces."),
("5", "Metallurgical Bond", "Intermetallic compound (IMC) layer forms between solder and base metal."),
("6", "Cooling & Solidification", "Joint cools undisturbed to form a solid, shiny, concave fillet."),
]
x0 = Inches(0.55)
w = Inches(1.95)
gap = Inches(0.15)
y0 = Inches(1.6)
h = Inches(2.6)
for i, (num, title, desc) in enumerate(steps):
x = x0 + i * (w + gap)
rect(s, x, y0, w, h, LIGHT_BLUE)
rect(s, x, y0, w, Inches(0.5), BLUE)
textbox(s, x, y0 + Inches(0.02), w, Inches(0.46), num, size=20, color=WHITE, bold=True,
align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE)
textbox(s, x + Inches(0.1), y0 + Inches(0.6), w - Inches(0.2), Inches(0.5), title, size=13.5,
color=NAVY, bold=True, align=PP_ALIGN.CENTER)
textbox(s, x + Inches(0.1), y0 + Inches(1.1), w - Inches(0.2), Inches(1.4), desc, size=11,
color=GREY, align=PP_ALIGN.CENTER)
textbox(s, Inches(0.55), Inches(4.6), Inches(12.2), Inches(0.6),
"Typical peak reflow temperature: 235-250°C (lead-free) or 210-225°C (leaded); time above liquidus ~30-90 seconds.",
size=14, color=GREY, italic=True)
rect(s, Inches(0.55), Inches(5.4), Inches(12.2), Inches(1.3), LIGHT_GREY)
textbox(s, Inches(0.75), Inches(5.55), Inches(11.8), Inches(1.0),
"Golden Rule: Heat the joint (pad + lead together), not just the solder. Apply solder to the heated joint so it flows by capillary action -- never melt solder directly on the iron tip and drip it on.",
size=14.5, color=NAVY, bold=True)
footer(s, 4)
# ============================================================
# SLIDE 5 - TYPES OF SOLDER JOINTS
# ============================================================
s = add_slide()
header(s, "Classification", "Types of Solder Joints")
cardw = Inches(3.9)
cardh = Inches(2.5)
gapx = Inches(0.25)
x0 = Inches(0.55)
y0 = Inches(1.55)
data = [
("Through-Hole (THT)", ["Lead inserted through plated via/hole", "Solder forms fillet on top & bottom", "High mechanical strength", "Used: connectors, power parts"]),
("Surface-Mount (SMT)", ["Component pad soldered flat to PCB pad", "No hole; smaller footprint", "Dominant in modern electronics", "Used: resistors, ICs, QFN/BGA"]),
("Gull-Wing / J-Lead", ["SMT lead types on ICs (SOIC, QFP)", "Toe, heel, and side fillets checked", "Visual inspection of lead shape", "Used: SOIC, TSOP, QFP packages"]),
]
for i, (title, items) in enumerate(data):
x = x0 + i * (cardw + gapx)
card(s, x, y0, cardw, cardh, title, [(it, 0) for it in items], title_color=BLUE)
data2 = [
("BGA (Ball Grid Array)", ["Solder balls under package, hidden joints", "Reflow forms balls into joints", "Inspected via X-ray only", "Used: CPUs, high-density ICs"]),
("Wire/Lead Splice", ["Two wires or a wire-to-terminal joint", "Solder wicks into stranded wire", "Common in cable harnesses", "Used: repairs, hand assemblies"]),
("Press-Fit / Hybrid", ["Mechanical press-fit + solder for sealing", "Combines mechanical & solder bond", "Used in connectors, power modules", "Higher vibration resistance"]),
]
y1 = y0 + cardh + Inches(0.2)
for i, (title, items) in enumerate(data2):
x = x0 + i * (cardw + gapx)
card(s, x, y1, cardw, cardh, title, [(it, 0) for it in items], title_color=ORANGE)
footer(s, 5)
# ============================================================
# SLIDE 6 - ANATOMY OF A GOOD JOINT
# ============================================================
s = add_slide()
header(s, "Quality", "Anatomy of a Good Solder Joint")
textbox(s, Inches(0.55), Inches(1.5), Inches(6.2), Inches(0.4), "Visual Hallmarks of Acceptance",
size=17, color=BLUE, bold=True)
bullets(s, Inches(0.55), Inches(2.0), Inches(6.3), Inches(4.6), [
"Shiny / smooth surface (satin finish acceptable for matte lead-free alloys)",
"Concave fillet shape -- smoothly tapered, wetting both surfaces",
"Complete wetting -- solder covers the entire pad and the lead/component termination",
"Homogeneous -- no visible graininess, cracks, or pinholes",
"Adequate fillet height -- lead/termination outline should still be discernible through solder",
"No excess solder bridging to adjacent pads/leads",
"No sharp peaks, icicles, or solder balls nearby",
], size=15.5, space_after=11)
rect(s, Inches(7.1), Inches(1.55), Inches(5.7), Inches(5.0), LIGHT_BLUE)
textbox(s, Inches(7.4), Inches(1.75), Inches(5.1), Inches(0.4), "Quick Check Criteria", size=16, color=NAVY, bold=True)
checks = [
("Wetting angle", "< 90° (ideally 20-30°) between solder and pad"),
("Fillet", "Concave, continuous, no voids"),
("Coverage", "Solder wets minimum 75% of terminal per IPC-A-610"),
("Color/texture", "Consistent -- shiny for SnPb, may be dull/matte for SAC alloys"),
("Alignment", "Component seated flat, not tombstoned or lifted"),
]
yy = Inches(2.3)
for label, desc in checks:
textbox(s, Inches(7.4), yy, Inches(5.1), Inches(0.3), label, size=14, color=ORANGE, bold=True)
textbox(s, Inches(7.4), yy + Inches(0.3), Inches(5.1), Inches(0.5), desc, size=12.5, color=GREY)
yy += Inches(0.85)
footer(s, 6)
# ============================================================
# SLIDE 7 - IPC-A-610 CLASSIFICATIONS
# ============================================================
s = add_slide()
header(s, "Standards", "IPC-A-610 Acceptability Classes")
classes = [
("Class 1", "General Electronics", "Consumer products where cosmetic imperfections are not important; only function matters. Lowest reliability requirement."),
("Class 2", "Dedicated Service", "Continued/extended service life required; uninterrupted service is desirable but not critical. Most industrial/commercial electronics."),
("Class 3", "High Performance", "Continued/high reliability performance is critical; equipment must function on demand (medical, aerospace, military). Tightest acceptance criteria."),
]
x0 = Inches(0.55)
w = Inches(4.0)
gap = Inches(0.15)
y0 = Inches(1.55)
h = Inches(3.0)
colors = [GREEN, BLUE, RED]
for i, (cls, name, desc) in enumerate(classes):
x = x0 + i * (w + gap)
rect(s, x, y0, w, h, LIGHT_GREY)
rect(s, x, y0, w, Inches(0.7), colors[i])
textbox(s, x, y0 + Inches(0.08), w, Inches(0.55), cls, size=22, color=WHITE, bold=True,
align=PP_ALIGN.CENTER)
textbox(s, x + Inches(0.2), y0 + Inches(0.85), w - Inches(0.4), Inches(0.4), name, size=15,
color=NAVY, bold=True, align=PP_ALIGN.CENTER)
textbox(s, x + Inches(0.25), y0 + Inches(1.3), w - Inches(0.5), Inches(1.6), desc, size=12.5,
color=GREY, align=PP_ALIGN.CENTER, line_spacing=1.1)
textbox(s, Inches(0.55), Inches(4.85), Inches(12.2), Inches(1.6),
"IPC-A-610 defines three visual acceptance conditions for each defect type:", size=15, color=NAVY, bold=True)
bullets(s, Inches(0.9), Inches(5.3), Inches(11.5), Inches(1.4), [
"Target Condition -- the ideal, defect-free result",
"Acceptable Condition -- meets minimum requirements, joint is reliable",
"Defect Condition -- fails to meet minimum requirements; must be reworked or rejected",
], size=14, space_after=6)
footer(s, 7)
# ============================================================
# SLIDE 8 - COMMON DEFECTS
# ============================================================
s = add_slide()
header(s, "Quality Control", "Common Solder Joint Defects")
defects = [
("Cold / Dry Joint", "Insufficient heat during formation. Dull, grainy, cracked surface; poor/no wetting.", RED),
("Solder Bridging", "Excess solder connects two adjacent pads/leads, causing a short circuit.", RED),
("Insufficient Solder", "Too little solder; fillet doesn't fully cover the pad/lead, weak joint.", ORANGE),
("Solder Balls", "Small spherical solder particles left near a joint after reflow, can cause shorts.", ORANGE),
("Tombstoning", "Small SMT component lifts on one end during reflow due to uneven wetting/heating.", ORANGE),
("Voids", "Gas pockets trapped inside the joint (common in BGA), reduce mechanical/thermal integrity.", BLUE),
("Dewetting", "Solder flows onto pad then recedes, leaving thin/no coverage on part of the surface.", BLUE),
("Non-wetting", "Solder never adheres to a surface at all -- base metal remains exposed.", BLUE),
]
x0 = Inches(0.55)
w = Inches(3.0)
gap = Inches(0.15)
y0 = Inches(1.5)
h = Inches(2.65)
for i, (name, desc, color) in enumerate(defects):
col = i % 4
row = i // 4
x = x0 + col * (w + gap)
y = y0 + row * (h + Inches(0.15))
rect(s, x, y, w, h, LIGHT_GREY)
rect(s, x, y, w, Inches(0.08), color)
textbox(s, x + Inches(0.15), y + Inches(0.2), w - Inches(0.3), Inches(0.6), name, size=14,
color=NAVY, bold=True, line_spacing=1.0)
textbox(s, x + Inches(0.15), y + Inches(0.85), w - Inches(0.3), Inches(1.7), desc, size=11.5,
color=GREY, line_spacing=1.1)
footer(s, 8)
# ============================================================
# SLIDE 9 - COLD / DRY JOINTS DEEP DIVE
# ============================================================
s = add_slide()
header(s, "Quality Control", "Cold Joints & Dry Joints -- Root Causes")
textbox(s, Inches(0.55), Inches(1.5), Inches(6.2), Inches(0.4), "Why They Happen", size=17, color=BLUE, bold=True)
bullets(s, Inches(0.55), Inches(2.0), Inches(6.3), Inches(4.6), [
"Insufficient heat -- iron temperature too low or contact time too short",
"Component or joint moved before the solder fully solidified",
"Contaminated or oxidized surfaces prevent proper wetting",
"Insufficient or expired flux, so oxides are not removed during heating",
"Heat sink effect -- large pad/plane pulls heat away faster than it's supplied",
], size=15.5, space_after=12)
textbox(s, Inches(0.55), Inches(5.1), Inches(6.3), Inches(0.4), "Risk", size=17, color=RED, bold=True)
bullets(s, Inches(0.55), Inches(5.55), Inches(6.3), Inches(1.5), [
"Intermittent connections -- works initially, fails under vibration/thermal cycling",
"Increased electrical resistance and heat buildup at the joint",
], size=14.5, space_after=8, color=GREY)
rect(s, Inches(7.1), Inches(1.55), Inches(5.7), Inches(5.5), LIGHT_BLUE)
textbox(s, Inches(7.4), Inches(1.75), Inches(5.1), Inches(0.4), "Identification & Fix", size=16, color=NAVY, bold=True)
bullets(s, Inches(7.4), Inches(2.25), Inches(5.1), Inches(4.6), [
"Look for: dull grey/frosted surface, granular texture, hairline cracks, uneven surface",
"Test: mechanically probe or flex the lead gently; cold joints often show micro-movement",
"Fix: reheat the entire joint (pad + lead) above liquidus, add a small amount of fresh flux-cored solder, allow to cool undisturbed",
"Prevent: correct iron temperature (315-370°C typical), adequate dwell time, clean/tinned tips, fresh flux, hold parts still until solidified",
], size=14, space_after=12)
footer(s, 9)
# ============================================================
# SLIDE 10 - INSPECTION METHODS
# ============================================================
s = add_slide()
header(s, "Quality Control", "Inspection Methods")
methods = [
("Visual / Magnified Inspection", "Operator or loupe/microscope check against IPC-A-610 criteria. Fast, low-cost, but subjective and can't see hidden joints."),
("Automated Optical Inspection (AOI)", "Camera-based system compares joint images to a known-good library. Fast, consistent, catches bridging, tombstoning, missing components."),
("X-Ray Inspection", "Penetrates the package to reveal hidden joints (BGA, QFN). Detects voids, opens, insufficient solder under the package."),
("In-Circuit Test (ICT) / Functional Test", "Electrically probes the board to confirm continuity and function. Confirms the joint works electrically, even if it can't see it."),
]
y0 = Inches(1.55)
h = Inches(1.28)
for i, (title, desc) in enumerate(methods):
y = y0 + i * (h + Inches(0.08))
rect(s, Inches(0.55), y, Inches(12.2), h, LIGHT_GREY if i % 2 == 0 else WHITE)
rect(s, Inches(0.55), y, Inches(0.08), h, BLUE)
textbox(s, Inches(0.85), y + Inches(0.12), Inches(3.8), Inches(1.0), title, size=15,
color=NAVY, bold=True, anchor=MSO_ANCHOR.MIDDLE)
textbox(s, Inches(4.8), y + Inches(0.12), Inches(7.7), Inches(1.0), desc, size=13, color=GREY,
anchor=MSO_ANCHOR.MIDDLE, line_spacing=1.1)
footer(s, 10)
# ============================================================
# SLIDE 11 - REFLOW VS WAVE
# ============================================================
s = add_slide()
header(s, "Process Comparison", "Reflow vs. Wave Soldering")
colw = Inches(5.9)
x0 = Inches(0.55)
gap = Inches(0.35)
y0 = Inches(1.55)
h = Inches(5.3)
tables = [
("Reflow Soldering", [
"Used primarily for Surface-Mount (SMT) components",
"Solder paste pre-applied via stencil printing",
"Board passes through a multi-zone oven (preheat, soak, reflow, cool)",
"Precise temperature profile controls joint formation",
"Enables fine-pitch, high-density assemblies (BGA, QFN)",
], BLUE),
("Wave Soldering", [
"Used primarily for Through-Hole (THT) components",
"Board passes over a standing wave of molten solder",
"Flux applied and board preheated before contact with wave",
"Bottom-side leads/pads soldered in a single pass",
"Cost-effective for high-volume THT and mixed assemblies",
], ORANGE),
]
for i, (title, items, color) in enumerate(tables):
x = x0 + i * (colw + gap)
rect(s, x, y0, colw, h, LIGHT_GREY)
rect(s, x, y0, colw, Inches(0.6), color)
textbox(s, x, y0 + Inches(0.08), colw, Inches(0.45), title, size=18, color=WHITE, bold=True,
align=PP_ALIGN.CENTER)
bullets(s, x + Inches(0.35), y0 + Inches(0.9), colw - Inches(0.7), h - Inches(1.1),
[(it, 0) for it in items], size=14.5, space_after=14)
footer(s, 11)
# ============================================================
# SLIDE 12 - BEST PRACTICES / SUMMARY
# ============================================================
s = add_slide()
header(s, "Wrap-Up", "Best Practices & Summary")
textbox(s, Inches(0.55), Inches(1.5), Inches(6.2), Inches(0.4), "Best Practices", size=17, color=BLUE, bold=True)
bullets(s, Inches(0.55), Inches(2.0), Inches(6.3), Inches(4.6), [
"Keep tips clean, tinned, and at the correct temperature for the alloy in use",
"Use fresh, appropriate flux-cored solder; avoid excessive dwell time",
"Heat both surfaces (pad and lead) before feeding solder -- never melt solder onto a cold joint",
"Hold parts still until the joint fully solidifies (avoid movement/cold joints)",
"Follow IPC-A-610 class requirements matched to the product's reliability needs",
"Combine AOI/X-ray with sampled visual inspection for full defect coverage",
], size=15, space_after=11)
rect(s, Inches(7.1), Inches(1.55), Inches(5.7), Inches(5.0), LIGHT_BLUE)
textbox(s, Inches(7.4), Inches(1.75), Inches(5.1), Inches(0.4), "Key Takeaways", size=16, color=NAVY, bold=True)
bullets(s, Inches(7.4), Inches(2.25), Inches(5.1), Inches(4.2), [
"A solder joint is a metallurgical bond, not a weld -- formed via wetting and IMC formation",
"Joint quality is judged by fillet shape, wetting coverage, and surface texture",
"IPC-A-610 Classes 1-3 define acceptance criteria by reliability need",
"Cold joints, bridging, voids, and tombstoning are the most common defects",
"Visual, AOI, X-ray, and electrical test together ensure full quality coverage",
], size=14, space_after=12)
footer(s, 12)
prs.save("/tmp/workspace/solder_joint_ppt/Solder_Joints.pptx")
print("DONE")
rm -f /tmp/workspace/solder_joint_ppt/build_ppt.py
~/solder_joint_ppt/build_ppt.py
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.enum.shapes import MSO_SHAPE
NAVY = RGBColor(0x0B, 0x2B, 0x4A)
BLUE = RGBColor(0x1F, 0x6F, 0xB2)
LIGHT_BLUE = RGBColor(0xE8, 0xF1, 0xF8)
ORANGE = RGBColor(0xE8, 0x7A, 0x1E)
GREY = RGBColor(0x4A, 0x4A, 0x4A)
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
RED = RGBColor(0xC0, 0x39, 0x2B)
GREEN = RGBColor(0x27, 0xAE, 0x60)
LIGHT_GREY = RGBColor(0xF2, 0xF4, 0xF6)
prs = Presentation()
prs.slide_width = Inches(13.333)
prs.slide_height = Inches(7.5)
SW, SH = prs.slide_width, prs.slide_height
blank = prs.slide_layouts[6]
TOTAL = 12
def add_slide():
return prs.slides.add_slide(blank)
def rect(slide, x, y, w, h, color, line_color=None):
shp = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, x, y, w, h)
shp.fill.solid()
shp.fill.fore_color.rgb = color
if line_color:
shp.line.color.rgb = line_color
shp.line.width = Pt(1)
else:
shp.line.fill.background()
shp.shadow.inherit = False
return shp
def textbox(slide, x, y, w, h, text, size=18, color=GREY, bold=False, align=PP_ALIGN.LEFT,
font="Calibri", italic=False, anchor=MSO_ANCHOR.TOP, wrap=True, line_spacing=1.0):
tb = slide.shapes.add_textbox(x, y, w, h)
tf = tb.text_frame
tf.word_wrap = wrap
tf.vertical_anchor = anchor
tf.margin_left = 0
tf.margin_right = 0
tf.margin_top = 0
tf.margin_bottom = 0
lines = text.split("\n")
for i, line in enumerate(lines):
p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
p.text = line
p.alignment = align
p.line_spacing = line_spacing
for r in p.runs:
r.font.size = Pt(size)
r.font.color.rgb = color
r.font.bold = bold
r.font.italic = italic
r.font.name = font
return tb
def bullets(slide, x, y, w, h, items, size=16, color=GREY, font="Calibri",
space_after=8, line_spacing=1.05):
tb = slide.shapes.add_textbox(x, y, w, h)
tf = tb.text_frame
tf.word_wrap = True
tf.margin_left = 0
tf.margin_right = 0
tf.margin_top = 0
tf.margin_bottom = 0
for i, item in enumerate(items):
if isinstance(item, tuple):
txt, lvl = item
else:
txt, lvl = item, 0
p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
p.space_after = Pt(space_after)
p.line_spacing = line_spacing
prefix = "• " if lvl == 0 else "- "
p.text = (" " * lvl) + prefix + txt
r = p.runs[0]
r.font.size = Pt(size - (2 if lvl else 0))
r.font.color.rgb = color
r.font.name = font
return tb
def footer(slide, num, title="Solder Joints"):
rect(slide, 0, SH - Inches(0.35), SW, Inches(0.35), NAVY)
textbox(slide, Inches(0.4), SH - Inches(0.33), Inches(6), Inches(0.3), title,
size=10, color=WHITE, font="Calibri")
textbox(slide, SW - Inches(1.2), SH - Inches(0.33), Inches(0.8), Inches(0.3),
f"{num}/{TOTAL}", size=10, color=WHITE, align=PP_ALIGN.RIGHT)
def header(slide, kicker, title_text):
rect(slide, 0, 0, SW, Inches(1.15), NAVY)
rect(slide, 0, Inches(1.15), SW, Inches(0.06), ORANGE)
textbox(slide, Inches(0.55), Inches(0.15), Inches(11), Inches(0.35), kicker.upper(),
size=13, color=ORANGE, bold=True, font="Calibri")
textbox(slide, Inches(0.55), Inches(0.5), Inches(12), Inches(0.6), title_text,
size=28, color=WHITE, bold=True, font="Calibri")
def card(slide, x, y, w, h, title, body_lines, title_color=BLUE):
rect(slide, x, y, w, h, LIGHT_GREY)
rect(slide, x, y, Inches(0.08), h, title_color)
ty = y + Inches(0.15)
textbox(slide, x + Inches(0.25), ty, w - Inches(0.4), Inches(0.4), title,
size=16, color=NAVY, bold=True)
bullets(slide, x + Inches(0.25), ty + Inches(0.42), w - Inches(0.45), h - Inches(0.6),
body_lines, size=12.5, color=GREY, space_after=3)
# ============================================================
# SLIDE 1 - TITLE
# ============================================================
s = add_slide()
rect(s, 0, 0, SW, SH, NAVY)
rect(s, 0, Inches(5.0), SW, Inches(0.08), ORANGE)
textbox(s, Inches(0.9), Inches(2.4), Inches(11.5), Inches(0.5), "SOLDER JOINTS",
size=20, color=ORANGE, bold=True, font="Calibri")
textbox(s, Inches(0.9), Inches(2.9), Inches(11.5), Inches(1.4),
"Formation, Types, Quality Criteria\n& Inspection", size=40, color=WHITE, bold=True, font="Calibri")
textbox(s, Inches(0.9), Inches(4.6), Inches(11), Inches(0.5),
"A Technical Overview for Electronics Assembly", size=18, color=RGBColor(0xC9, 0xD9, 0xEA),
font="Calibri", italic=True)
textbox(s, Inches(0.9), Inches(6.8), Inches(8), Inches(0.4),
"Reference: IPC-A-610 Acceptability of Electronic Assemblies", size=13,
color=RGBColor(0x9A, 0xB6, 0xD1))
# ============================================================
# SLIDE 2 - AGENDA
# ============================================================
s = add_slide()
header(s, "Overview", "Agenda")
agenda = [
"1. What Is a Solder Joint?",
"2. The Soldering Process",
"3. Types of Solder Joints",
"4. Anatomy of a Good Joint",
"5. IPC-A-610 Classifications",
"6. Common Solder Defects",
"7. Cold Joints & Dry Joints",
"8. Inspection Methods",
"9. Reflow vs Wave Soldering",
"10. Best Practices & Summary",
]
bullets(s, Inches(0.9), Inches(1.6), Inches(10.5), Inches(5.2), agenda, size=20, color=NAVY, space_after=14)
footer(s, 2)
# ============================================================
# SLIDE 3 - WHAT IS A SOLDER JOINT
# ============================================================
s = add_slide()
header(s, "Fundamentals", "What Is a Solder Joint?")
textbox(s, Inches(0.55), Inches(1.5), Inches(6.3), Inches(0.5),
"Definition", size=18, color=BLUE, bold=True)
bullets(s, Inches(0.55), Inches(2.0), Inches(6.3), Inches(4.5), [
"A solder joint is a metallurgical bond formed when molten solder wets and adheres to two or more metal surfaces (e.g. a component lead and a PCB pad), then solidifies into a permanent electrical and mechanical connection.",
"Unlike a weld, the base metals are not melted -- only the solder liquefies and forms an intermetallic compound (IMC) layer with the base metals.",
"A properly formed joint provides:",
("Low-resistance electrical continuity", 1),
("Mechanical strength to withstand vibration/thermal cycling", 1),
("Environmental sealing against corrosion", 1),
], size=16, space_after=10)
rect(s, Inches(7.2), Inches(1.55), Inches(5.6), Inches(5.0), LIGHT_BLUE)
textbox(s, Inches(7.5), Inches(1.75), Inches(5.0), Inches(0.4), "Key Materials", size=16, color=NAVY, bold=True)
bullets(s, Inches(7.5), Inches(2.25), Inches(5.0), Inches(4.0), [
"Solder alloy: SAC305 (Sn96.5/Ag3.0/Cu0.5) -- lead-free standard",
"Sn63/Pb37 -- eutectic leaded (legacy/military/aerospace)",
"Flux: removes oxides, improves wetting (rosin, no-clean, water-soluble)",
"Base metals: Cu pads/traces, component leads (Cu, Sn, Ni-plated, etc.)",
"Substrate: FR-4 PCB with copper pads/plating",
], size=14.5, space_after=10)
footer(s, 3)
# ============================================================
# SLIDE 4 - SOLDERING PROCESS
# ============================================================
s = add_slide()
header(s, "Fundamentals", "The Soldering Process")
steps = [
("1", "Surface Prep", "Clean pad/lead surfaces; remove oxides and contaminants."),
("2", "Flux Application", "Flux applied to reduce surface tension and promote wetting."),
("3", "Heating", "Heat via iron, hot air, or reflow oven raises joint above solder liquidus temp."),
("4", "Wetting", "Molten solder flows and spreads across the base metal surfaces."),
("5", "Metallurgical Bond", "Intermetallic compound (IMC) layer forms between solder and base metal."),
("6", "Cooling & Solidification", "Joint cools undisturbed to form a solid, shiny, concave fillet."),
]
x0 = Inches(0.55)
w = Inches(1.95)
gap = Inches(0.15)
y0 = Inches(1.6)
h = Inches(2.6)
for i, (num, title, desc) in enumerate(steps):
x = x0 + i * (w + gap)
rect(s, x, y0, w, h, LIGHT_BLUE)
rect(s, x, y0, w, Inches(0.5), BLUE)
textbox(s, x, y0 + Inches(0.02), w, Inches(0.46), num, size=20, color=WHITE, bold=True,
align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE)
textbox(s, x + Inches(0.1), y0 + Inches(0.6), w - Inches(0.2), Inches(0.5), title, size=13.5,
color=NAVY, bold=True, align=PP_ALIGN.CENTER)
textbox(s, x + Inches(0.1), y0 + Inches(1.1), w - Inches(0.2), Inches(1.4), desc, size=11,
color=GREY, align=PP_ALIGN.CENTER)
textbox(s, Inches(0.55), Inches(4.6), Inches(12.2), Inches(0.6),
"Typical peak reflow temperature: 235-250°C (lead-free) or 210-225°C (leaded); time above liquidus ~30-90 seconds.",
size=14, color=GREY, italic=True)
rect(s, Inches(0.55), Inches(5.4), Inches(12.2), Inches(1.3), LIGHT_GREY)
textbox(s, Inches(0.75), Inches(5.55), Inches(11.8), Inches(1.0),
"Golden Rule: Heat the joint (pad + lead together), not just the solder. Apply solder to the heated joint so it flows by capillary action -- never melt solder directly on the iron tip and drip it on.",
size=14.5, color=NAVY, bold=True)
footer(s, 4)
# ============================================================
# SLIDE 5 - TYPES OF SOLDER JOINTS
# ============================================================
s = add_slide()
header(s, "Classification", "Types of Solder Joints")
cardw = Inches(3.9)
cardh = Inches(2.5)
gapx = Inches(0.25)
x0 = Inches(0.55)
y0 = Inches(1.55)
data = [
("Through-Hole (THT)", ["Lead inserted through plated via/hole", "Solder forms fillet on top & bottom", "High mechanical strength", "Used: connectors, power parts"]),
("Surface-Mount (SMT)", ["Component pad soldered flat to PCB pad", "No hole; smaller footprint", "Dominant in modern electronics", "Used: resistors, ICs, QFN/BGA"]),
("Gull-Wing / J-Lead", ["SMT lead types on ICs (SOIC, QFP)", "Toe, heel, and side fillets checked", "Visual inspection of lead shape", "Used: SOIC, TSOP, QFP packages"]),
]
for i, (title, items) in enumerate(data):
x = x0 + i * (cardw + gapx)
card(s, x, y0, cardw, cardh, title, [(it, 0) for it in items], title_color=BLUE)
data2 = [
("BGA (Ball Grid Array)", ["Solder balls under package, hidden joints", "Reflow forms balls into joints", "Inspected via X-ray only", "Used: CPUs, high-density ICs"]),
("Wire/Lead Splice", ["Two wires or a wire-to-terminal joint", "Solder wicks into stranded wire", "Common in cable harnesses", "Used: repairs, hand assemblies"]),
("Press-Fit / Hybrid", ["Mechanical press-fit + solder for sealing", "Combines mechanical & solder bond", "Used in connectors, power modules", "Higher vibration resistance"]),
]
y1 = y0 + cardh + Inches(0.2)
for i, (title, items) in enumerate(data2):
x = x0 + i * (cardw + gapx)
card(s, x, y1, cardw, cardh, title, [(it, 0) for it in items], title_color=ORANGE)
footer(s, 5)
# ============================================================
# SLIDE 6 - ANATOMY OF A GOOD JOINT
# ============================================================
s = add_slide()
header(s, "Quality", "Anatomy of a Good Solder Joint")
textbox(s, Inches(0.55), Inches(1.5), Inches(6.2), Inches(0.4), "Visual Hallmarks of Acceptance",
size=17, color=BLUE, bold=True)
bullets(s, Inches(0.55), Inches(2.0), Inches(6.3), Inches(4.6), [
"Shiny / smooth surface (satin finish acceptable for matte lead-free alloys)",
"Concave fillet shape -- smoothly tapered, wetting both surfaces",
"Complete wetting -- solder covers the entire pad and the lead/component termination",
"Homogeneous -- no visible graininess, cracks, or pinholes",
"Adequate fillet height -- lead/termination outline should still be discernible through solder",
"No excess solder bridging to adjacent pads/leads",
"No sharp peaks, icicles, or solder balls nearby",
], size=15.5, space_after=11)
rect(s, Inches(7.1), Inches(1.55), Inches(5.7), Inches(5.0), LIGHT_BLUE)
textbox(s, Inches(7.4), Inches(1.75), Inches(5.1), Inches(0.4), "Quick Check Criteria", size=16, color=NAVY, bold=True)
checks = [
("Wetting angle", "< 90° (ideally 20-30°) between solder and pad"),
("Fillet", "Concave, continuous, no voids"),
("Coverage", "Solder wets minimum 75% of terminal per IPC-A-610"),
("Color/texture", "Consistent -- shiny for SnPb, may be dull/matte for SAC alloys"),
("Alignment", "Component seated flat, not tombstoned or lifted"),
]
yy = Inches(2.3)
for label, desc in checks:
textbox(s, Inches(7.4), yy, Inches(5.1), Inches(0.3), label, size=14, color=ORANGE, bold=True)
textbox(s, Inches(7.4), yy + Inches(0.3), Inches(5.1), Inches(0.5), desc, size=12.5, color=GREY)
yy += Inches(0.85)
footer(s, 6)
# ============================================================
# SLIDE 7 - IPC-A-610 CLASSIFICATIONS
# ============================================================
s = add_slide()
header(s, "Standards", "IPC-A-610 Acceptability Classes")
classes = [
("Class 1", "General Electronics", "Consumer products where cosmetic imperfections are not important; only function matters. Lowest reliability requirement."),
("Class 2", "Dedicated Service", "Continued/extended service life required; uninterrupted service is desirable but not critical. Most industrial/commercial electronics."),
("Class 3", "High Performance", "Continued/high reliability performance is critical; equipment must function on demand (medical, aerospace, military). Tightest acceptance criteria."),
]
x0 = Inches(0.55)
w = Inches(4.0)
gap = Inches(0.15)
y0 = Inches(1.55)
h = Inches(3.0)
colors = [GREEN, BLUE, RED]
for i, (cls, name, desc) in enumerate(classes):
x = x0 + i * (w + gap)
rect(s, x, y0, w, h, LIGHT_GREY)
rect(s, x, y0, w, Inches(0.7), colors[i])
textbox(s, x, y0 + Inches(0.08), w, Inches(0.55), cls, size=22, color=WHITE, bold=True,
align=PP_ALIGN.CENTER)
textbox(s, x + Inches(0.2), y0 + Inches(0.85), w - Inches(0.4), Inches(0.4), name, size=15,
color=NAVY, bold=True, align=PP_ALIGN.CENTER)
textbox(s, x + Inches(0.25), y0 + Inches(1.3), w - Inches(0.5), Inches(1.6), desc, size=12.5,
color=GREY, align=PP_ALIGN.CENTER, line_spacing=1.1)
textbox(s, Inches(0.55), Inches(4.85), Inches(12.2), Inches(0.4),
"IPC-A-610 defines three visual acceptance conditions for each defect type:", size=15, color=NAVY, bold=True)
bullets(s, Inches(0.9), Inches(5.3), Inches(11.5), Inches(1.4), [
"Target Condition -- the ideal, defect-free result",
"Acceptable Condition -- meets minimum requirements, joint is reliable",
"Defect Condition -- fails to meet minimum requirements; must be reworked or rejected",
], size=14, space_after=6)
footer(s, 7)
# ============================================================
# SLIDE 8 - COMMON DEFECTS
# ============================================================
s = add_slide()
header(s, "Quality Control", "Common Solder Joint Defects")
defects = [
("Cold / Dry Joint", "Insufficient heat during formation. Dull, grainy, cracked surface; poor/no wetting.", RED),
("Solder Bridging", "Excess solder connects two adjacent pads/leads, causing a short circuit.", RED),
("Insufficient Solder", "Too little solder; fillet doesn't fully cover the pad/lead, weak joint.", ORANGE),
("Solder Balls", "Small spherical solder particles left near a joint after reflow, can cause shorts.", ORANGE),
("Tombstoning", "Small SMT component lifts on one end during reflow due to uneven wetting/heating.", ORANGE),
("Voids", "Gas pockets trapped inside the joint (common in BGA), reduce mechanical/thermal integrity.", BLUE),
("Dewetting", "Solder flows onto pad then recedes, leaving thin/no coverage on part of the surface.", BLUE),
("Non-wetting", "Solder never adheres to a surface at all -- base metal remains exposed.", BLUE),
]
x0 = Inches(0.55)
w = Inches(3.0)
gap = Inches(0.15)
y0 = Inches(1.5)
h = Inches(2.65)
for i, (name, desc, color) in enumerate(defects):
col = i % 4
row = i // 4
x = x0 + col * (w + gap)
y = y0 + row * (h + Inches(0.15))
rect(s, x, y, w, h, LIGHT_GREY)
rect(s, x, y, w, Inches(0.08), color)
textbox(s, x + Inches(0.15), y + Inches(0.2), w - Inches(0.3), Inches(0.6), name, size=14,
color=NAVY, bold=True, line_spacing=1.0)
textbox(s, x + Inches(0.15), y + Inches(0.85), w - Inches(0.3), Inches(1.7), desc, size=11.5,
color=GREY, line_spacing=1.1)
footer(s, 8)
# ============================================================
# SLIDE 9 - COLD / DRY JOINTS DEEP DIVE
# ============================================================
s = add_slide()
header(s, "Quality Control", "Cold Joints & Dry Joints -- Root Causes")
textbox(s, Inches(0.55), Inches(1.5), Inches(6.2), Inches(0.4), "Why They Happen", size=17, color=BLUE, bold=True)
bullets(s, Inches(0.55), Inches(2.0), Inches(6.3), Inches(4.6), [
"Insufficient heat -- iron temperature too low or contact time too short",
"Component or joint moved before the solder fully solidified",
"Contaminated or oxidized surfaces prevent proper wetting",
"Insufficient or expired flux, so oxides are not removed during heating",
"Heat sink effect -- large pad/plane pulls heat away faster than it's supplied",
], size=15.5, space_after=12)
textbox(s, Inches(0.55), Inches(5.1), Inches(6.3), Inches(0.4), "Risk", size=17, color=RED, bold=True)
bullets(s, Inches(0.55), Inches(5.55), Inches(6.3), Inches(1.5), [
"Intermittent connections -- works initially, fails under vibration/thermal cycling",
"Increased electrical resistance and heat buildup at the joint",
], size=14.5, space_after=8, color=GREY)
rect(s, Inches(7.1), Inches(1.55), Inches(5.7), Inches(5.5), LIGHT_BLUE)
textbox(s, Inches(7.4), Inches(1.75), Inches(5.1), Inches(0.4), "Identification & Fix", size=16, color=NAVY, bold=True)
bullets(s, Inches(7.4), Inches(2.25), Inches(5.1), Inches(4.6), [
"Look for: dull grey/frosted surface, granular texture, hairline cracks, uneven surface",
"Test: mechanically probe or flex the lead gently; cold joints often show micro-movement",
"Fix: reheat the entire joint (pad + lead) above liquidus, add a small amount of fresh flux-cored solder, allow to cool undisturbed",
"Prevent: correct iron temperature (315-370°C typical), adequate dwell time, clean/tinned tips, fresh flux, hold parts still until solidified",
], size=14, space_after=12)
footer(s, 9)
# ============================================================
# SLIDE 10 - INSPECTION METHODS
# ============================================================
s = add_slide()
header(s, "Quality Control", "Inspection Methods")
methods = [
("Visual / Magnified Inspection", "Operator or loupe/microscope check against IPC-A-610 criteria. Fast, low-cost, but subjective and can't see hidden joints."),
("Automated Optical Inspection (AOI)", "Camera-based system compares joint images to a known-good library. Fast, consistent, catches bridging, tombstoning, missing components."),
("X-Ray Inspection", "Penetrates the package to reveal hidden joints (BGA, QFN). Detects voids, opens, insufficient solder under the package."),
("In-Circuit Test (ICT) / Functional Test", "Electrically probes the board to confirm continuity and function. Confirms the joint works electrically, even if it can't see it."),
]
y0 = Inches(1.55)
h = Inches(1.28)
for i, (title, desc) in enumerate(methods):
y = y0 + i * (h + Inches(0.08))
rect(s, Inches(0.55), y, Inches(12.2), h, LIGHT_GREY if i % 2 == 0 else WHITE)
rect(s, Inches(0.55), y, Inches(0.08), h, BLUE)
textbox(s, Inches(0.85), y + Inches(0.12), Inches(3.8), Inches(1.0), title, size=15,
color=NAVY, bold=True, anchor=MSO_ANCHOR.MIDDLE)
textbox(s, Inches(4.8), y + Inches(0.12), Inches(7.7), Inches(1.0), desc, size=13, color=GREY,
anchor=MSO_ANCHOR.MIDDLE, line_spacing=1.1)
footer(s, 10)
# ============================================================
# SLIDE 11 - REFLOW VS WAVE
# ============================================================
s = add_slide()
header(s, "Process Comparison", "Reflow vs. Wave Soldering")
colw = Inches(5.9)
x0 = Inches(0.55)
gap = Inches(0.35)
y0 = Inches(1.55)
h = Inches(5.3)
tables = [
("Reflow Soldering", [
"Used primarily for Surface-Mount (SMT) components",
"Solder paste pre-applied via stencil printing",
"Board passes through a multi-zone oven (preheat, soak, reflow, cool)",
"Precise temperature profile controls joint formation",
"Enables fine-pitch, high-density assemblies (BGA, QFN)",
], BLUE),
("Wave Soldering", [
"Used primarily for Through-Hole (THT) components",
"Board passes over a standing wave of molten solder",
"Flux applied and board preheated before contact with wave",
"Bottom-side leads/pads soldered in a single pass",
"Cost-effective for high-volume THT and mixed assemblies",
], ORANGE),
]
for i, (title, items, color) in enumerate(tables):
x = x0 + i * (colw + gap)
rect(s, x, y0, colw, h, LIGHT_GREY)
rect(s, x, y0, colw, Inches(0.6), color)
textbox(s, x, y0 + Inches(0.08), colw, Inches(0.45), title, size=18, color=WHITE, bold=True,
align=PP_ALIGN.CENTER)
bullets(s, x + Inches(0.35), y0 + Inches(0.9), colw - Inches(0.7), h - Inches(1.1),
[(it, 0) for it in items], size=14.5, space_after=14)
footer(s, 11)
# ============================================================
# SLIDE 12 - BEST PRACTICES / SUMMARY
# ============================================================
s = add_slide()
header(s, "Wrap-Up", "Best Practices & Summary")
textbox(s, Inches(0.55), Inches(1.5), Inches(6.2), Inches(0.4), "Best Practices", size=17, color=BLUE, bold=True)
bullets(s, Inches(0.55), Inches(2.0), Inches(6.3), Inches(4.6), [
"Keep tips clean, tinned, and at the correct temperature for the alloy in use",
"Use fresh, appropriate flux-cored solder; avoid excessive dwell time",
"Heat both surfaces (pad and lead) before feeding solder -- never melt solder onto a cold joint",
"Hold parts still until the joint fully solidifies (avoid movement/cold joints)",
"Follow IPC-A-610 class requirements matched to the product's reliability needs",
"Combine AOI/X-ray with sampled visual inspection for full defect coverage",
], size=15, space_after=11)
rect(s, Inches(7.1), Inches(1.55), Inches(5.7), Inches(5.0), LIGHT_BLUE)
textbox(s, Inches(7.4), Inches(1.75), Inches(5.1), Inches(0.4), "Key Takeaways", size=16, color=NAVY, bold=True)
bullets(s, Inches(7.4), Inches(2.25), Inches(5.1), Inches(4.2), [
"A solder joint is a metallurgical bond, not a weld -- formed via wetting and IMC formation",
"Joint quality is judged by fillet shape, wetting coverage, and surface texture",
"IPC-A-610 Classes 1-3 define acceptance criteria by reliability need",
"Cold joints, bridging, voids, and tombstoning are the most common defects",
"Visual, AOI, X-ray, and electrical test together ensure full quality coverage",
], size=14, space_after=12)
footer(s, 12)
prs.save("/tmp/workspace/solder_joint_ppt/Solder_Joints.pptx")
print("DONE")
cd /tmp/workspace/solder_joint_ppt && python build_ppt.py
ls -la /tmp/workspace/solder_joint_ppt/
Solder Joints
Presentation · PPTX