A solder joint with a crack, a crimp with missing strands or a partial short on a power rail dissipates more power than its neighbors when current flows through it. Learn how to pass a known DC current through a board, capture an infrared image, extract the maximum temperature of each region of interest as a measurement, and compare it to a golden unit with TofuPilot.
What Thermal Imaging Detects
A joint on a current path behaves as a resistor. The power it dissipates is:
P = I² × RExample values, 20 A through a power joint: good joint, R = 0.5 mΩ -> P = 20² × 0.0005 = 0.2 W cracked joint, R = 5 mΩ -> P = 20² × 0.005 = 2.0 WThe example values are illustrative, but the ratio holds: a joint with ten times the resistance dissipates ten times the power at the same current, and it runs measurably hotter than the good joints beside it. An infrared camera sees the whole board at once, so one image checks every joint on the current path.
| Defect | Thermal signature under DC current |
|---|---|
| Cracked, cold or insufficient solder joint on a current path | Hot spot at the joint, hotter than the matching joints on the golden unit |
| Crimp with missing strands, undersized wire | Hot section along the wire or at the crimp barrel |
| Partial short between rails | Hot spot at the short location, with supply current above nominal |
| Missing or wrong-value shunt or trace | Abnormal temperature distribution along the path |
| Power component with a poor thermal attach | Component hotter than on the golden unit at the same dissipation |
Thermal imaging complements the electrical measurement of the same joint. A 4-wire voltage drop gives the resistance of the path as a single number. The image shows which joint on that path is responsible.
Prerequisites
- An infrared camera that delivers radiometric data (a temperature per pixel) through a Python SDK or API, not only a colorized JPEG
- A fixture that holds the camera and the board at a fixed distance and orientation, so each region of interest is always at the same pixel coordinates
- A programmable DC power supply with current limiting, or a supply and an electronic load, to set a known current through the path
- A golden unit: a board with verified joints, used to set the reference temperatures
- A way to fix emissivity on the measured surfaces (Step 1)
Step 1: Control Emissivity
An infrared camera computes temperature from radiated energy, assuming an emissivity for the surface. Bare metal (solder, tinned copper, nickel-plated terminals) has a low emissivity and reflects its surroundings: the camera then reads the reflection of the operator, the lamp or the ceiling as much as the joint itself. Two joints at the same temperature can read several degrees apart because one is shinier.
| Surface | Emissivity | Reading on the camera |
|---|---|---|
| Bare or shiny solder, tinned copper | Low, varies with finish | Unreliable, dominated by reflections |
| Solder mask, epoxy component bodies, wire insulation | High | Usable |
| Matte black paint or high-emissivity tape | High, known | Usable and repeatable |
Three ways to get a usable reading, in order of preference for production:
- Measure a high-emissivity surface next to the joint. The solder mask around a pad or the insulation next to a crimp heats by conduction. The reading is lower than the joint itself, but consistent from unit to unit.
- Apply a matte black coating or high-emissivity tape where the process allows it, for example on a terminal that is covered later in assembly.
- Paint the golden unit and development samples to characterize the true joint temperatures, then correlate them with the reading on the high-emissivity surface used in production.
The comparison to the golden unit only cancels the emissivity error if both units present the same surface. A shiny joint on one unit and a dull one on another is a measurement difference, not a defect.
Step 2: Set the Current and the Timing
Use a moderate, known current. The purpose is to make a resistive joint visible, not to stress it: a current high enough to damage a weak joint also degrades good ones. Choose a current that produces a temperature rise of a few degrees on the good joints, well inside their rating.
Temperature then rises toward a steady state with a time constant τ set by the thermal mass of the board and its heat paths. After a time t, the rise has reached a fraction 1 - e^(-t/τ) of its final value:
t = 3τ -> 1 - e^-3 = 95.0 % of the final riset = 5τ -> 1 - e^-5 = 99.3 % of the final riseMeasure τ on the golden unit: log the temperature of a region every second after the current is switched on, and fit the curve. Two strategies follow:
| Strategy | Capture time | Trade-off |
|---|---|---|
| Steady state | About 5τ after current on | Highest contrast between good and bad joints, longest cycle time |
| Fixed transient | A fixed time shorter than steady state | Shorter cycle time; contrast is lower and the timing must be identical on every unit |
Either works if the timing is the same on the golden unit and every production unit. Ambient temperature shifts all readings, so record the rise above ambient rather than the absolute temperature.
Step 3: Define the Regions of Interest
With the board in a fixed position, each joint occupies the same rectangle of pixels in every image. Define one region of interest (ROI) per joint or per group of identical joints, as pixel bounds [x0, y0, x1, y1]. Take the maximum temperature in each ROI: a hot spot is a peak, and an average over the region dilutes it.
Include one ROI on an area that does not carry current, such as an unpowered corner of the board, as the ambient reference.
Step 4: Write the Camera Plug
The camera plug grabs a radiometric frame, computes the maximum of each ROI, saves a false-color image for the report, and returns only the numbers. The frame itself stays in the plug process, because plug method arguments and results are serialized between processes and a full radiometric frame is a large array.
plugs/ir_camera.py22 lines
import matplotlib.pyplot as pltimport numpy as npclass IRCamera: def __init__(self, serial): self.serial = serial # Open the camera with the vendor SDK here and set the emissivity # used for the high-emissivity surfaces you measure. def _grab_frame(self): # Replace with the vendor SDK call that returns one radiometric frame # as a 2D array of temperatures in degrees Celsius. raise NotImplementedError("connect the camera SDK") def capture(self, rois, image_path): frame = np.asarray(self._grab_frame(), dtype=float) plt.imsave(image_path, frame, cmap="inferno") maxima = {} for name, (x0, y0, x1, y1) in rois.items(): maxima[name] = float(frame[y0:y1, x0:x1].max()) return maximaStep 5: Write the Phase and the Procedure
The phase sets the current, waits the settling time, captures, switches the current off, attaches the image and records one measurement per ROI.
procedure.yaml57 lines
name: Power Path Thermal Inspectionversion: 1.0.0plugs: - name: IR Camera key: ir_camera python: plugs.ir_camera:IRCamera scope: station with: serial: "{config.IR_CAMERA_SERIAL}" - name: Power Supply key: psu python: plugs.psu:PowerSupply with: address: "{config.PSU_ADDRESS}"config: IR_CAMERA_SERIAL: required: true PSU_ADDRESS: required: truemain: - name: Thermal Image Under DC Current python: phases.thermal_image:thermal_image timeout: 5m with: current_a: 10 settle_s: 90 rois: ambient: [10, 10, 40, 40] battery_pad_pos: [120, 200, 160, 240] battery_pad_neg: [120, 260, 160, 300] phase_pad_a: [400, 180, 430, 210] measurements: - name: Supply Current unit: A validators: - operator: ">=" expected_value: 9.8 - operator: "<=" expected_value: 10.2 - name: Battery Pad Pos Rise unit: °C validators: - operator: "<=" expected_value: 8.0 - name: Battery Pad Neg Rise unit: °C validators: - operator: "<=" expected_value: 8.0 - name: Phase Pad A Rise unit: °C validators: - operator: "<=" expected_value: 6.0The current, settling time, pixel bounds and limits above are example values for one board and one fixture. Set them from the golden unit and from production data.
phases/thermal_image.py23 lines
import osimport tempfileimport timedef thermal_image(ir_camera, psu, measurements, attach, log, current_a, settle_s, rois): psu.set_current(current_a) psu.output_on() try: time.sleep(settle_s) measurements.supply_current = psu.read_current() image_path = os.path.join(tempfile.gettempdir(), "thermal_image.png") maxima = ir_camera.capture(rois, image_path) finally: psu.output_off() attach.file(image_path, "thermal_image.png") ambient = maxima.pop("ambient") log.info(f"Ambient reference: {ambient:.1f} C") for name, temperature in maxima.items(): # battery_pad_pos -> measurements.battery_pad_pos_rise setattr(measurements, f"{name}_rise", temperature - ambient)The try/finally block switches the current off even if the capture fails. The image is attached to the run, so an engineer reviewing a failed unit sees where the hot spot is, not only which ROI exceeded its limit.
Step 6: Compare to the Golden Unit
Run the golden unit several times at the start of each shift or after any change to the fixture, the camera or the current. Its readings verify the station: if the golden unit drifts, the setup changed, not the product.
Set the first limits from the golden unit's rise plus a margin, then refine them from the distribution of production units once enough runs are recorded. In TofuPilot, each ROI measurement has a control chart and a Cpk across units, so a joint that runs consistently close to its limit shows up before it starts failing. For the method, see how to set measurement limits using production data and what SPC is.
A unit that fails one ROI, with a normal supply current, points to a resistive joint at that location. A unit with a high supply current and a hot spot outside the expected path points to a short.
Common Pitfalls
Measuring shiny metal. Low and variable emissivity turns reflections into temperature readings. Measure a high-emissivity surface or coat the measured area.
Using a high current to make defects obvious. A current that heats a weak joint enough to damage it also stresses the good ones. Use the lowest current that gives a clear rise on the golden unit.
Inconsistent timing. A capture taken 60 s after current on is not comparable to one taken at 90 s. Fix the settling time in the procedure.
Averaging over the ROI. A hot spot occupies a few pixels. Use the maximum.
Absolute temperature limits. Ambient changes over the day and between stations. Limit the rise above an ambient reference ROI.
Moving fixture or camera. If the board shifts, the ROIs no longer cover the joints. Use locating pins and check the golden unit image after any mechanical change.
Key Points
- Under a known DC current, a resistive joint dissipates more power (P = I² × R) and shows as a hot spot.
- Emissivity is the main source of error: measure high-emissivity surfaces or apply a matte coating.
- Capture at a fixed time, ideally near steady state (about 5τ), and record the rise above ambient.
- Extract the maximum temperature per ROI as a measurement, and attach the image to the run.
- Keep the radiometric frame in the plug and return only the ROI values.
- Verify the station with a golden unit, then set limits from production data.
