Quality & Process Control

What Is Cpk (Process Capability Index)

Cpk measures how much room a process has inside its specification limits. How to calculate it, what the values mean, and what invalidates it.

JJulien Buteau
beginner5 min readMarch 20, 2026

Cpk answers one question: given how much a measurement varies and where it sits between its limits, how much room does the process actually have? It is the standard way to say whether a test is likely to keep passing, or whether it is one small drift away from scrapping boards.

The Formula

Cpk is the worse of the two one-sided distances from the mean to each specification limit, measured in units of 3 standard deviations:

CPU = (USL - mean) / (3σ) CPL = (mean - LSL) / (3σ) Cpk = min(CPU, CPL)

Taking the minimum is what makes Cpk useful. A process centred perfectly between wide limits and a process hugging one limit can have the same spread, and only Cpk distinguishes them.

Worked Example

A 3.3 V rail with limits of 3.2 V and 3.4 V, from 200 production boards:

StatisticValue
Mean3.31 V
Standard deviation0.018 V
LSL3.2 V
USL3.4 V
CPU = (3.40 - 3.31) / (3 × 0.018) = 0.09 / 0.054 = 1.67 CPL = (3.31 - 3.20) / (3 × 0.018) = 0.11 / 0.054 = 2.04 Cpk = min(1.67, 2.04) = 1.67

The process is slightly high of centre, so the upper limit is the binding one. Cpk of 1.67 is comfortable.

Cp vs Cpk

Cp ignores where the process sits and measures only whether the spread could fit:

Cp = (USL - LSL) / (6σ)

In the example above, Cp is 0.2 / 0.108 = 1.85. The gap between Cp 1.85 and Cpk 1.67 is the cost of being off-centre. When Cp is much larger than Cpk, the fix is usually recentring rather than reducing variation, which is almost always the cheaper intervention.

See Cp, potential process capability.

Interpreting the Number

CpkDefects (approx, centred)Meaning
0.67~4.5 %Failing constantly
1.00~0.27 %Limits at exactly 3σ; marginal
1.33~63 ppmCommon minimum target
1.67~0.6 ppmComfortable
2.00~2 ppbSix-sigma capable

Most electronics manufacturers target Cpk of at least 1.33 on measurements that matter. Below 1.0, the test fails often enough that operators start treating failures as noise, which is its own problem.

A very high Cpk is worth a question rather than celebration: either the process is genuinely excellent, or the limits are so loose the test cannot fail, in which case it is spending cycle time without protecting anything.

What Invalidates Cpk

Cpk is easy to compute and easy to compute meaninglessly. Four conditions have to hold.

The process must be stable. Capability on an out-of-control process averages two or more distributions into one number describing none of them. Check the control chart first; if there are shifts or trends, fix those before calculating capability.

The data should be roughly normal. The defect-rate column above assumes normality. Heavily skewed or bimodal data makes those ppm figures fiction. Bimodal usually means two populations mixed, such as two fixtures or two component lots, and the fix is to separate them.

The measurement must have resolution. If the instrument resolves to 0.01 V and the real spread is 0.005 V, the computed sigma is an artefact. A sigma of zero is a resolution problem, never perfection.

The sample must be adequate. Thirty units is a rough minimum; fewer makes the sigma estimate unstable enough that the Cpk is noise.

Getting Data That Supports Cpk

Cpk requires the measured values. A pass/fail record cannot produce it at any sample size, which is the practical reason to store numbers rather than verdicts.

procedure.yaml
24 lines
name: PCBA Functional Testversion: 1.0.0unit:  serial_number:    default_value: "PCBA000001"  part_number:    default_value: "PCBA-100"plugs:  - name: dmm    python: plugs.dmm:Multimetermain:  - name: Power Rails    python: phases.power_rails    measurements:      - name: Rail 3V3        unit: V        validators:          - operator: ">="            expected_value: 3.2          - operator: "<="            expected_value: 3.4
phases/power_rails.py
def power_rails(measurements, dmm):    measurements.rail_3v3 = dmm.dc_voltage()
plugs/dmm.py
class Multimeter:    def dc_voltage(self) -> float:        return 3.31  # Replace with a real instrument read

Each run stores the value with its limits, so Cpk per measurement is computed from the data rather than a separate study.

Two habits that keep the number meaningful:

Keep measurement names stable. Renaming Rail 3V3 splits the distribution in two and the capability history with it.

Version the procedure. A limit change alters Cpk with no process change at all. Without the version on each run, that looks like a process event.

Calculating It Yourself

analysis/capability.py
22 lines
import statisticsdef cpk(values: list[float], lsl: float, usl: float) -> float:    """Process capability index for a two-sided specification."""    if len(values) < 30:        raise ValueError("Sample too small for a stable sigma estimate")    mean = statistics.mean(values)    sigma = statistics.stdev(values)    if sigma == 0:        raise ValueError("Zero variation; check measurement resolution")    cpu = (usl - mean) / (3 * sigma)    cpl = (mean - lsl) / (3 * sigma)    return min(cpu, cpl)def cp(values: list[float], lsl: float, usl: float) -> float:    """Potential capability, ignoring centring."""    sigma = statistics.stdev(values)    return (usl - lsl) / (6 * sigma)

Acting on a Low Cpk

SymptomLikely causeAction
Cp good, Cpk poorProcess off-centreRecentre; usually the cheapest fix
Cp and Cpk both poorToo much variationReduce variation, or widen limits if the design allows
Cpk fell without a process changeLimits were tightenedCheck the procedure version history
Bimodal distributionTwo populations mixedSplit by station, fixture or lot and recompute
Sigma near zeroInstrument resolution too coarseImprove the measurement first

Widening limits is a legitimate response only when the design genuinely tolerates it. Widening them because the process cannot hold them is how marginal product ships.

One-Sided Measurements

Leakage current has a maximum and no minimum; insulation resistance the reverse. Cpk is undefined for those, and the correct indices are CPU and CPL alone. Do not invent a second limit to make a Cpk appear. See CPL and CPU.

Short Term vs Long Term

Cpk conventionally uses short-term, within-subgroup variation. Ppk uses the overall long-term standard deviation. Ppk is usually lower, because it includes the drift between subgroups that Cpk excludes. See Cpk vs Ppk.

If You Already Run OpenHTF

fct.py
import openhtf as htffrom openhtf.util import unitsfrom tofupilot.openhtf import upload@htf.measures(    htf.Measurement("rail_3v3").in_range(3.2, 3.4).with_units(units.VOLT),)def phase_power(test):    test.measurements.rail_3v3 = 3.31test = htf.Test(phase_power, part_number="PCBA-100")test.add_output_callbacks(upload())test.execute(test_start=lambda: input("Scan serial: "))

Install with pip install "tofupilot[openhtf]", or skip the callback and run it with tofupilot run.

Common Mistakes

MistakeConsequenceFix
Computing Cpk on an unstable processA number describing no real distributionCheck the control chart first
Recording pass/fail onlyCpk cannot be computed at allStore the measured values
Ignoring bimodal dataCapability is an average of two populationsSplit by station, fixture or lot
Treating sigma of zero as perfectResolution artefact read as excellenceCheck instrument resolution
Reporting Cpk for a one-sided limitRequires a fabricated second limitUse CPU or CPL
Widening limits to fix a low CpkMarginal product shipsRecentre or reduce variation first

More Guides

Put this guide into practice