Skip to main content

Semiconductor — yield & defect tracing

The problem. In a fab, yield is everything — and a yield drop is a detective story. A wafer lot passes through hundreds of process steps on dozens of tools; when lots start failing final test, the cause could be any one tool drifting out of spec. The killer question is: what do the failing lots have in common? Find the one tool or chamber that every bad lot passed through and you've found the culprit; miss it and you scrap wafers for weeks.

What we solve here is tracing a yield excursion back to its root tool before it costs a fortune in scrapped silicon.

Set up demo data

New workspace? Run this once (Python) to create two failing lots that both ran on tool_etch_07 (plus other tools) — so the intersection in step 2 finds the shared culprit. Safe to re-run.

import datahub_sdk

client = datahub_sdk.DataHubClient.from_env()

client.resources.create(
[datahub_sdk.Resource(external_id=x, name=x, labels=[lbl]) for x, lbl in
[("lot_22841", "Lot"), ("lot_22863", "Lot"), ("tool_etch_07", "Tool"),
("tool_litho_03", "Tool"), ("tool_cmp_05", "Tool")]],
[datahub_sdk.RelForm.by_external_ids("lot_22841", "tool_etch_07", "processed_on"),
datahub_sdk.RelForm.by_external_ids("lot_22841", "tool_litho_03", "processed_on"),
datahub_sdk.RelForm.by_external_ids("lot_22863", "tool_etch_07", "processed_on"),
datahub_sdk.RelForm.by_external_ids("lot_22863", "tool_cmp_05", "processed_on")])

1. Record process data exactly

Chamber pressure, temperature and gas flow are the process record, and they must be exact — use the NUMERIC value type so values store without floating-point drift.

var pressure = Timeseries.of("tool_etch_07_chamber_pressure_mtorr")
.name("Etch-07 chamber pressure")
.setValueType("numeric");
pressure.setUnit("mtorr");
client.timeseries().create(pressure);

client.timeseries().ingest(Map.of(
"tool_etch_07_chamber_pressure_mtorr",
List.of(Datapoint.of(Instant.now(), "12.0436"))));

2. Find the tool every failing lot shares

Each lot is connected to the tools it ran on (processed_on). Walk the graph from each failing lot and intersect: the tool common to all of them is the prime suspect — the same shared-node reasoning as alarm correlation, applied to process genealogy.

ResourceNetwork lotA = client.resources().fetchRelated("lot_22841", 6);
ResourceNetwork lotB = client.resources().fetchRelated("lot_22863", 6);

Set<String> toolsA = lotA.nodes().stream()
.map(Resource::getExternalId).filter(id -> id.startsWith("tool_")).collect(Collectors.toSet());
Set<String> suspect = lotB.nodes().stream()
.map(Resource::getExternalId).filter(toolsA::contains).collect(Collectors.toSet());

// suspect contains "tool_etch_07" → the chamber to pull and check

3. Confirm against the tool's process record

With the suspect tool identified, pull its exact process series around the failing lots' run times and compare to a known-good window — the drift that explains the excursion should be right there. See Query & aggregate.

See the result

The tools common to both failing lots:

suspect contains 'tool_etch_07' ← the chamber to pull and check

See also