benikigai/ec-1Public

EC-1 Wireless Controller

spreads.py · 2.2 KB · commit #1 · Nov 1, 2026

SHA-256 32bf63bee2bce758914e1290527c7818ae8c6f618deb03306f7df7efb8b48028

"""Rebuild every derived number in opd.yaml from raw/, and check they match.

Run from the OPD folder:  python analysis/spreads.py
Needs Python 3.10+ and pyyaml. Exits non-zero on any mismatch.

It checks three things:
1. Each feature spread (mean, sd, n) against raw/measurements.csv and raw/eol-sample.csv.
2. Baseline RTY against the product of station first-pass yields.
3. The BOM roll-up against bom/bom.csv.
"""
import csv, math, pathlib, statistics, sys
import yaml

HERE = pathlib.Path(__file__).resolve().parent.parent
doc = yaml.safe_load((HERE / "opd.yaml").read_text())
problems = []

raw = {}
with open(HERE / "raw" / "measurements.csv") as f:
    for row in csv.DictReader(f):
        raw.setdefault(row["feature"], []).append(float(row["value"]))

for part in doc["parts"]:
    for feat in part.get("features", []):
        vals = raw.get(feat["id"])
        if vals is None:
            problems.append(f"{feat['id']}: no raw values")
            continue
        got = dict(mean=round(statistics.mean(vals), 4), sd=round(statistics.stdev(vals), 4), n=len(vals))
        want = {k: feat["spread"][k] for k in got}
        if got != want:
            problems.append(f"{feat['id']}: raw gives {got}, opd.yaml says {want}")
        print(f"{feat['id']:<28} mean {got['mean']:>9} sd {got['sd']:>7} n {got['n']}")

base = doc["variants"]["baseline"]["scores"]["yield"]
rty = round(math.prod(s["value"] for s in base["fpy_by_station"].values()), 3)
if rty != base["rty"]["value"]:
    problems.append(f"RTY: stations multiply to {rty}, opd.yaml says {base['rty']['value']}")
print(f"baseline RTY from station FPY: {rty}")

with open(HERE / "bom" / "bom.csv") as f:
    rows = list(csv.DictReader(f))
total = sum(float(r["unit_cost_usd"]) * float(r["qty"]) for r in rows if r["unit_cost_usd"] and r["parent"] != "part:main-pcba")
print(f"BOM roll-up: {total:.2f} USD")

with open(HERE / "raw" / "eol-sample.csv") as f:
    eol = list(csv.DictReader(f))
fails = sum(r["result"] == "fail" for r in eol)
print(f"end-of-line sample: {len(eol)} units, {fails} failed ({fails / len(eol):.1%})")

if problems:
    print("\n".join(["", "MISMATCH:"] + problems))
    sys.exit(1)
print("\nEvery derived number matches raw/.")