Skip to content
Test Data & Analytics

Track Rolled Throughput Yield

Learn how to measure Rolled Throughput Yield (RTY) across multi-step manufacturing processes and track it in TofuPilot's dashboard.

JJulien Buteau
intermediate6 min readMarch 14, 2026

Final yield only tells you whether a unit passed at the end of the line. Rolled Throughput Yield (RTY) tells you the probability that a unit passes every step without rework or retesting. It's the metric that exposes hidden factory losses.

Why RTY Matters More Than Final Yield

Final yield counts a unit as "pass" even if it failed three times before someone reworked it. RTY doesn't. It multiplies the first-pass yield of every process step together:

RTY = FPY₁ x FPY₂ x ... x FPYₙ

Consider a five-step process where each step has 95% FPY. Final yield might show 99% because rework catches most failures. But RTY tells the real story:

RTY = 0.95 x 0.95 x 0.95 x 0.95 x 0.95 = 77.4%

That means nearly 1 in 4 units needed rework somewhere. Each rework event costs time, labor, and materials that final yield hides completely.

RTY Interpretation

RTY RangeWhat It Means
> 95%Process is well-controlled, minimal hidden rework
85-95%Some steps need attention, review failure Pareto
70-85%Significant hidden losses, prioritize worst FPY steps
< 70%Process is unstable, rework costs are likely substantial

The power of RTY is that it pinpoints which step drags down the whole line. If Step 3 has 88% FPY while others sit at 98%, you know exactly where to focus.

Structuring Your Tests for RTY Tracking

Each process step should be a separate test procedure in TofuPilot. This gives you per-step FPY that feeds directly into RTY calculations. Here's a multi-phase OpenHTF test that represents a PCB assembly process with distinct steps:

test_smt_placement.py
# Step 1: SMT component placement verification
import openhtf as htf
from openhtf.util import units
from tofupilot.openhtf import TofuPilot

@htf.measures(
    htf.Measurement("placement_offset_x")
        .in_range(minimum=-0.05, maximum=0.05)
        .with_units(units.MILLIMETRE),
    htf.Measurement("placement_offset_y")
        .in_range(minimum=-0.05, maximum=0.05)
        .with_units(units.MILLIMETRE),
    htf.Measurement("component_rotation")
        .in_range(minimum=-2.0, maximum=2.0),
)
def smt_placement_check(test):
    test.measurements.placement_offset_x = 0.02
    test.measurements.placement_offset_y = -0.01
    test.measurements.component_rotation = 0.5

def main():
    test = htf.Test(smt_placement_check)
    with TofuPilot(test):
        test.execute(test_start=lambda: "PCB-2024-0042")

if __name__ == "__main__":
    main()
test_reflow_solder.py
# Step 2: Reflow soldering thermal profile check
import openhtf as htf
from openhtf.util import units
from tofupilot.openhtf import TofuPilot

@htf.measures(
    htf.Measurement("peak_temperature")
        .in_range(minimum=235, maximum=250)
        .with_units(units.DEGREE_CELSIUS),
    htf.Measurement("time_above_liquidus")
        .in_range(minimum=60, maximum=120),
    htf.Measurement("cooling_rate")
        .in_range(maximum=3.0),
)
def reflow_profile_check(test):
    test.measurements.peak_temperature = 242
    test.measurements.time_above_liquidus = 85
    test.measurements.cooling_rate = 2.1

def main():
    test = htf.Test(reflow_profile_check)
    with TofuPilot(test):
        test.execute(test_start=lambda: "PCB-2024-0042")

if __name__ == "__main__":
    main()
test_functional.py
# Step 3: Functional test after assembly
import openhtf as htf
from openhtf.util import units
from tofupilot.openhtf import TofuPilot

@htf.measures(
    htf.Measurement("supply_voltage")
        .in_range(minimum=4.9, maximum=5.1)
        .with_units(units.VOLT),
    htf.Measurement("quiescent_current")
        .in_range(maximum=15.0)
        .with_units(units.AMPERE),
    htf.Measurement("clock_frequency")
        .in_range(minimum=7.99, maximum=8.01)
        .with_units(units.HERTZ),
)
def functional_check(test):
    test.measurements.supply_voltage = 5.02
    test.measurements.quiescent_current = 0.0113
    test.measurements.clock_frequency = 8003000

def main():
    test = htf.Test(functional_check)
    with TofuPilot(test):
        test.execute(test_start=lambda: "PCB-2024-0042")

if __name__ == "__main__":
    main()

Each test procedure runs independently and uploads results to TofuPilot with the same serial number. TofuPilot links all three procedures to the same unit, giving you a complete process history.

Tracking RTY in TofuPilot

Once your test procedures upload results, TofuPilot's dashboard gives you what you need to compute and track RTY:

  • Per-procedure FPY trends show first-pass yield for each process step over time. You can spot degradation in a single step before it affects final yield.
  • Failure Pareto charts break down which measurements fail most often within each step, so you can prioritize root cause analysis.
  • Unit history shows the complete journey of any serial number across all procedures, including retests. This is the ground truth for whether a unit passed first time at every step.

You don't need to build RTY calculations in Python. Structure your tests as separate procedures, upload results with consistent serial numbers, and TofuPilot gives you the per-step visibility that makes RTY actionable.

Key Practices for Accurate RTY

  1. One procedure per process step. Don't combine SMT placement and reflow soldering into a single test. Separate procedures give you separate FPY numbers.

  2. Use consistent serial numbers. Every procedure for the same unit must reference the same serial number. This is how TofuPilot links the full process chain.

  3. Don't filter out retests. Upload every test execution, including failures and retests. RTY only works when you have the complete picture.

  4. Set measurement limits in code. Limits defined in OpenHTF flow directly into TofuPilot's analytics. Don't rely on post-hoc analysis to determine pass/fail.

More Guides

Put this guide into practice