← Commit history

Resolve board18 via-planning counts separately from mandatory thermal qualification

John Lauer ·bc54ad25c2 ·18d ago ·parent 71b293f
3 files changed +78
design/step9-via-review.jsonadded+47
@@ -0,0 +1,47 @@+{+  "scope": "via-planning-review-only",+  "boardSha256": "8d6cd24149f7de061f125bf45a26b50ca5b70a6b01c62b96dc3cf92187a531f1",+  "specSha256": "4fa060d03263bc9ed43657386d80b9261e0e523e7e2e6762867d4ec80275bd60",+  "D1": {+    "decision": "retain",+    "qualifyingVias": 10,+    "heuristicTarget": 10+  },+  "Q1": {+    "decision": "case-heatsink-path; PCB-via heuristic not applicable as primary cooling design",+    "qualifyingVias": 0,+    "heuristicTarget": 16,+    "thermalAcceptance": false,+    "reason": "TO-220 tab is above PCB; primary proposed heat path is case/interface/external sink, not the drain pin and PCB vias. Additional drain-pin vias do not establish that path."+  },+  "RSH1": {+    "decision": "retain three locally qualifying vias, preserve Kelvin isolation and existing GND stitch",+    "qualifyingVias": 3,+    "heuristicTarget": 6,+    "watts": 0.18,+    "plannerRiseBudgetC": 35,+    "plannerViaAllocationC": 17.5,+    "sensitivity": [+      {+        "platingUmAssumed": 18,+        "threeViaThetaKPerW": 77.0350733894902,+        "barrelDropAt018W_C": 13.866313210108235+      },+      {+        "platingUmAssumed": 25,+        "threeViaThetaKPerW": 54.27061662540823,+        "barrelDropAt018W_C": 9.768710992573482+      }+    ],+    "assumptions": "Three 0.3mm finished holes through 1.6mm board, copper conductivity385W/mK, 18/25um assumed plating. Larger actual vias receive no additional credit. Equal sharing and ideal local copper assumed.",+    "limitations": "Barrel-only interlayer drop, not resistor-to-ambient rise. Plating is a sensitivity assumption, not verified fab capability. Copper necks/spreading/package/airflow remain in later current/thermal analysis."+  },+  "downstreamRequirements": [+    "Native pour connectivity and current review",+    "Same-input supported Fields solve",+    "Q1 package/interface/sink/airflow design and thermal screen",+    "Physical assembly/fault qualification before enabling production load"+  ],+  "thermalPass": false,+  "finishPass": false+}
docs/via-planning-review.mdadded+11
@@ -0,0 +1,11 @@+# Board 18 via-planning decision++This closes only the geometric via-planning review. It does not approve the full thermal design or fabrication release. The board, loss assumptions and temperature limits are unchanged.++D1 retains 10 qualifying vias, meeting its target. Q1's generic 16-via target does not model its proposed TO-220 case/interface/external-heatsink path; its tab is above the board, and drain-pin vias cannot establish that cooling path. Record this as a via-count exception while retaining Q1's 5 W loss and unresolved package cooling in the later thermal gate.++RSH1 retains three locally qualifying vias and the verified ground stitch, preserving its Kelvin connections. AIFlow's target function clamps every hot part to at least six vias. A conservative barrel sensitivity using three 0.3 mm holes through 1.6 mm FR4 gives approximately 13.9 C at 18 um assumed plating and 9.8 C at 25 um, with all 0.18 W routed through the barrels. Both are below the planner's 17.5 C interlayer allocation (half its 35 C budget). This is not a resistor-to-ambient result: equal sharing, ideal local copper and assumed plating require downstream review. No manufacturer minimum via count was supplied by this heuristic.++The native saved board has zero DRC errors and zero opens; the live board revision still matches the recorded board-18 checkpoint. No geometry is changed by these decisions. Later current and thermal gates still require a supported same-input Fields analysis, and the Q1 cooling assembly remains unresolved. A via-count acknowledgement is not a thermal-analysis pass.++[Machine-readable calculation and input hashes](design/step9-via-review.json). Reproduce with `python3 tools/review_step9_scope.py`.
tools/review_step9_scope.pyadded+20
@@ -0,0 +1,20 @@+"""Separate geometric via planning from unresolved complete thermal acceptance."""+import json,hashlib,math+from pathlib import Path+P=Path(__file__).resolve().parents[1]+b=P/'kicad/adom-custom-electronic-load.kicad_pcb';s=P/'design/spec.json'+rows=[]+for plating in [18,25]:+ area=math.pi*((.15+plating/1000)**2-.15**2)*1e-6+ theta=.0016/(385*area)/3+ rows.append({'platingUmAssumed':plating,'threeViaThetaKPerW':theta,'barrelDropAt018W_C':theta*.18})+r={'scope':'via-planning-review-only','boardSha256':hashlib.sha256(b.read_bytes()).hexdigest(),'specSha256':hashlib.sha256(s.read_bytes()).hexdigest(),+ 'D1':{'decision':'retain','qualifyingVias':10,'heuristicTarget':10},+ 'Q1':{'decision':'case-heatsink-path; PCB-via heuristic not applicable as primary cooling design','qualifyingVias':0,'heuristicTarget':16,'thermalAcceptance':False,'reason':'TO-220 tab is above PCB; primary proposed heat path is case/interface/external sink, not the drain pin and PCB vias. Additional drain-pin vias do not establish that path.'},+ 'RSH1':{'decision':'retain three locally qualifying vias, preserve Kelvin isolation and existing GND stitch','qualifyingVias':3,'heuristicTarget':6,'watts':.18,'plannerRiseBudgetC':35,'plannerViaAllocationC':17.5,'sensitivity':rows,+ 'assumptions':'Three 0.3mm finished holes through 1.6mm board, copper conductivity385W/mK, 18/25um assumed plating. Larger actual vias receive no additional credit. Equal sharing and ideal local copper assumed.',+ 'limitations':'Barrel-only interlayer drop, not resistor-to-ambient rise. Plating is a sensitivity assumption, not verified fab capability. Copper necks/spreading/package/airflow remain in later current/thermal analysis.'},+ 'downstreamRequirements':['Native pour connectivity and current review','Same-input supported Fields solve','Q1 package/interface/sink/airflow design and thermal screen','Physical assembly/fault qualification before enabling production load'],+ 'thermalPass':False,'finishPass':False}+(P/'design/step9-via-review.json').write_text(json.dumps(r,indent=2)+'\n')+print(json.dumps(rows,indent=2))