Skip to content

Commit a020f31

Browse files
jscott3201claude
andauthored
TPR sensor-bias campaign: +/-3C OAT bias, first detection-rate records (#33)
--bias/--reuse harness flags replay biased inputs against cached healthy runs. Both directions of the CLU-09 biased-OAT cascade confirmed: +3C caught by AHU-FC-062/002/068 (3/3 loops each, 2.3-28 h), -3C by AHU-FC-051 (3/3, ~40 min)/003/062, non-OAT rules correctly silent. simulation_tpr validation blocks on the five detecting cards (failures = missed detections; SCHEMA clarified). Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 5352510 commit a020f31

8 files changed

Lines changed: 70 additions & 5 deletions

File tree

SCHEMA.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ left to right.
107107

108108
**`validation:` (optional frontmatter block, adopted 2026-08-18).** Records
109109
empirical validation runs against the card's rule. A list; each entry:
110-
`kind` (`simulation_fpr` | `simulation_tpr`), `harness` (e.g.
110+
`kind` (`simulation_fpr` | `simulation_tpr` — for `simulation_tpr`, `failures` counts MISSED detections), `harness` (e.g.
111111
`simharness/v1`), `date`, `fleet` (one-line description of buildings ×
112112
climates × period), `scenarios` (count), `failures` (count), optional
113113
`notes` (one line, e.g. the finding a failure represents). Results are

faults/ahu/AHU-FC-002/card.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ emissions:
5050
scope: "1|2"
5151
method: QUALITATIVE_EMISSIONS
5252
validation:
53+
- kind: simulation_tpr
54+
harness: simharness/v1
55+
date: 2026-08-18
56+
fleet: "TPR: +/-3 degC OAT bias injected into replay inputs (faulted-sensor-as-seen-by-FDD), B2B OfficeMedium-4004 July week, 3 VAV loops; failures = missed detections; baseline-confounded rules excluded from attribution"
57+
scenarios: 3
58+
failures: 0
59+
notes: "+3 degC direction: detected 3/3 loops (~5-28 h); correctly silent at -3"
5360
- kind: simulation_fpr
5461
harness: simharness/v1
5562
date: 2026-08-18

faults/ahu/AHU-FC-003/card.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ emissions:
5050
scope: "1|2"
5151
method: QUALITATIVE_EMISSIONS
5252
validation:
53+
- kind: simulation_tpr
54+
harness: simharness/v1
55+
date: 2026-08-18
56+
fleet: "TPR: +/-3 degC OAT bias injected into replay inputs (faulted-sensor-as-seen-by-FDD), B2B OfficeMedium-4004 July week, 3 VAV loops; failures = missed detections; baseline-confounded rules excluded from attribution"
57+
scenarios: 3
58+
failures: 1
59+
notes: "-3 degC direction: detected 2/3 loops; correctly silent at +3"
5360
- kind: simulation_fpr
5461
harness: simharness/v1
5562
date: 2026-08-18

faults/ahu/AHU-FC-051/card.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,13 @@ emissions:
7171
scope: "2"
7272
method: DIRECT_EMISSIONS
7373
validation:
74+
- kind: simulation_tpr
75+
harness: simharness/v1
76+
date: 2026-08-18
77+
fleet: "TPR: +/-3 degC OAT bias injected into replay inputs (faulted-sensor-as-seen-by-FDD), B2B OfficeMedium-4004 July week, 3 VAV loops; failures = missed detections; baseline-confounded rules excluded from attribution"
78+
scenarios: 3
79+
failures: 0
80+
notes: "-3 degC direction: detected 3/3 loops within ~40 min of the first gated window; correctly silent at +3 (direction mirror of AHU-FC-068)"
7481
- kind: simulation_fpr
7582
harness: simharness/v1
7683
date: 2026-08-18

faults/ahu/AHU-FC-062/card.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ emissions:
5151
scope: "1|2"
5252
method: QUALITATIVE_EMISSIONS
5353
validation:
54+
- kind: simulation_tpr
55+
harness: simharness/v1
56+
date: 2026-08-18
57+
fleet: "TPR: +/-3 degC OAT bias injected into replay inputs (faulted-sensor-as-seen-by-FDD), B2B OfficeMedium-4004 July week, 3 VAV loops; failures = missed detections; baseline-confounded rules excluded from attribution"
58+
scenarios: 6
59+
failures: 1
60+
notes: "both directions: 3/3 at +3 degC (~4.5-28 h), 2/3 at -3 degC — empirical confirmation of the CLU-09 biased-OAT cascade"
5461
- kind: simulation_fpr
5562
harness: simharness/v1
5663
date: 2026-08-18

faults/ahu/AHU-FC-068/card.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,13 @@ emissions:
7373
scope: "2"
7474
method: DIRECT_EMISSIONS
7575
validation:
76+
- kind: simulation_tpr
77+
harness: simharness/v1
78+
date: 2026-08-18
79+
fleet: "TPR: +/-3 degC OAT bias injected into replay inputs (faulted-sensor-as-seen-by-FDD), B2B OfficeMedium-4004 July week, 3 VAV loops; failures = missed detections; baseline-confounded rules excluded from attribution"
80+
scenarios: 3
81+
failures: 0
82+
notes: "+3 degC direction: detected 3/3 loops ~2.3 h into the first gated window; correctly silent at -3 (direction mirror of AHU-FC-051)"
7683
- kind: simulation_fpr
7784
harness: simharness/v1
7885
date: 2026-08-18

tools/simharness/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,20 @@ fault by construction; excluded from FPR claims, useful as a
8484
known-positive. Reset-family rules are likewise excluded (constant-setpoint
8585
baselines read "reset absent" by construction).
8686

87+
## TPR: sensor-bias campaigns (`--bias point=delta`, `--reuse`)
88+
89+
Injects a bias into the replayed inputs of an already-simulated healthy run
90+
(the faulted-sensor-as-seen-by-FDD case; zero EnergyPlus time). FAILs are
91+
DETECTIONS; attribution requires differencing against the healthy baseline
92+
(rules that fail on the healthy run — the DCV pair — are confounded and
93+
excluded). First campaign, +/-3 degC OAT bias (OfficeMedium-4004, July):
94+
the envelope family and the direction-appropriate economizer rule catch the
95+
bias in both directions — +3: AHU-FC-062 (3/3), 002 (3/3), 068 (3/3,
96+
~2.3 h); -3: 051 (3/3, ~40 min), 003 (2/3), 062 (2/3) — while a dozen
97+
non-OAT rules stay correctly silent. Empirical demonstration of the CLU-09
98+
biased-OAT cascade; recorded as `simulation_tpr` validation blocks
99+
(failures = missed detections).
100+
87101
## Plant mode (DOE prototypes)
88102

89103
`--mode plant` maps CHW/HW plant loops instead of air loops: loop

tools/simharness/harness.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,11 @@ def main():
446446
runp.add_argument("--begin", default="7-6", help="run period start M-D")
447447
runp.add_argument("--end", default="7-12", help="run period end M-D")
448448
runp.add_argument("--mode", default="airloop", choices=["airloop", "plant"])
449+
runp.add_argument("--reuse", action="store_true",
450+
help="reuse an existing eplusout.csv instead of re-running EnergyPlus")
451+
runp.add_argument("--bias", default=None, metavar="POINT=DELTA",
452+
help="TPR mode: add DELTA to POINT in the replayed inputs "
453+
"(faulted-sensor-as-seen-by-FDD); FAILs are DETECTIONS")
449454
args = ap.parse_args()
450455

451456
bdir = Path(args.building)
@@ -464,8 +469,10 @@ def main():
464469
patched = patch_plant(b, pn, begin, end)
465470
pj = out / "patched.epjson"
466471
pj.write_text(json.dumps(patched))
467-
print(f"plant loops: {list(pn)}; running EnergyPlus…")
468-
csv_path = run_energyplus(pj, epw, out / "ep")
472+
csv_path = out / "ep" / "eplusout.csv"
473+
if not (args.reuse and csv_path.is_file()):
474+
print(f"plant loops: {list(pn)}; running EnergyPlus…")
475+
csv_path = run_energyplus(pj, epw, out / "ep")
469476
fams = extract_plant(csv_path, pn, b)
470477
rules = {}
471478
for fam in fams:
@@ -519,9 +526,18 @@ def main():
519526
patched = patch(b, loops, begin, end)
520527
pj = out / "patched.epjson"
521528
pj.write_text(json.dumps(patched))
522-
print(f"loops: {list(loops)}; running EnergyPlus…")
523-
csv_path = run_energyplus(pj, epw, out / "ep")
529+
csv_path = out / "ep" / "eplusout.csv"
530+
if not (args.reuse and csv_path.is_file()):
531+
print(f"loops: {list(loops)}; running EnergyPlus…")
532+
csv_path = run_energyplus(pj, epw, out / "ep")
524533
loops_pts = extract(csv_path, loops)
534+
if args.bias:
535+
pt, delta = args.bias.split("=")
536+
delta = float(delta)
537+
for pts in loops_pts.values():
538+
if pt in pts:
539+
pts[pt] = [round(v + delta, ROUND) for v in pts[pt]]
540+
print(f"TPR bias applied: {pt} += {delta} — FAILs below are DETECTIONS")
525541
rules = eligible_rules()
526542
print(f"eligible rules (points ⊆ mapped): {sorted(rules)}")
527543
log = emit_and_replay(bdir.name, loops_pts, rules, out)

0 commit comments

Comments
 (0)