Skip to content

Advisory system optimization (ASO)

FDD tells you what's wrong; camber.aso maps an actionable finding to a suggested corrective action — a setpoint or sequence change an operator can review and apply.

Advisory and read-only by construction. ASO returns structured recommendations; it never issues a command to the BAS/OT. Closed-loop write-back stays a roadmap Horizon item — a human stays in the loop. Each recommendation is grounded: it names the source finding + rule and cites the sequence-of-operations guidance (ASHRAE Guideline 36 / PNNL Re-tuning) behind the correction, and targets come from documented, override-able defaults (no fabricated site-specific values).

flowchart LR
  finding["actionable finding"] --> recommend["recommend / recommend_findings"]
  rule["source rule + archetype"] --> recommend
  params["DEFAULT_PARAMS (override-able targets)"] --> recommend
  g36["G36 / PNNL Re-tuning guidance"] --> recommend
  recommend --> rec["Recommendation (action, suggested, standard, advisory=True)"]
  rec --> operator["operator reviews (human in the loop)"]
  operator -. "never auto-writes" .-> bas["BAS / OT"]
Advisory only: a grounded Recommendation reaches an operator, never a BAS command.

Use

from camber.aso import recommend, recommend_findings

recs = recommend_findings(findings, min_severity="warn")  # worst-first, skips ok/info + unmapped
for r in recs:
    print(r.severity, r.equip, r.rule, "→", r.title)
    print("   ", r.action, "| target:", r.suggested, "| cite:", r.standard)

recommend(finding) returns a single Recommendation (or None for a non-actionable finding or a rule with no recommender). A Recommendation carries: title, action, parameter, suggested (the target, possibly qualitative), expected_effect, confidence (high/medium/low), standard (the citation), caveats, references, cause and advisory=True (always). It is JSON-friendly via as_dict(). cause (0.98, #88) names the finding's cause in a short phrase ("Outdoor-air damper not modulating (stuck low)", "Low chilled-water loop ΔT (40% of running hours)"), built from the same metrics the advice follows; title stays the action. The RCx report heads each issue with the cause.

Targets & flags

DEFAULT_PARAMS holds the tunable targets (H/C changeover deadband, economizer high limit, SAT-reset schedule, minimum airflow fraction, unoccupied setback, CHW/CW reset, tower approach, …); override per call with params= (shallow-merged). recommend_findings flags: min_severity ("warn" or "fault"), params, frame (optional role-frame for context).

Coverage

Recommenders map the main FDD archetypes: simultaneous heat/cool (lockout + deadband), SAT reset, economizer/OA, reheat minimization (G36), overcooling, unoccupied setback, chiller kW/ton (CW/CHW reset + staging), loop resets (CHW/HW/pump-ΔP, trim-and-respond), cooling-tower approach, boiler short-cycle, leaking valve (maintenance), and DCV. Rules without a recommender yield no recommendation rather than a fabricated one.

Outside-air advice follows the finding's failure mode, not just its rule name. An outdoor_air_fraction under-ventilation finding (it records failure_mode; older findings are inferred from their metrics) gets "restore minimum outside air": check the minimum-OA damper position, actuator and linkage, the min-OA setpoint against design, and the outdoor airflow. Excess OA and economizer_high_limit get lockout advice at the rule's configured high limit, and free_cooling_missed gets "enable economizer free cooling", unless the finding shows the damper was commanded open and outside air did not arrive (missed_cause: damper_not_delivering, 0.98): then it gets "repair the outdoor-air damper or actuator", a mechanical fix, "stuck low" or "stuck part open" by the OA fraction delivered while commanded open (commanded_open_oaf_median_pct against stuck_low_oaf_pct, default 30 %, DEFAULT_PARAMS["econ_stuck_low_oaf_pct"]).

Every recommender follows the cause (0.96, #78). Advice is keyed to the reason a finding fired, read from its metrics, never only to its rule name:

Rule Cause (metric) Action
dcv_verification, dcv_system_verification DCV works, OA above its floor at low demand (status: functioning, excess_at_low_demand_pct) Lower the minimum outdoor air at low demand (to the Ra·Az floor)
OA static / not following demand (status) Enable / repair DCV; tie outdoor air to demand
under-ventilation (below_floor_pct, co2_breach_at_min_pct, unventilated_high_co2_hours) Restore the OA floor; make OA respond to high CO₂; restore ventilation while occupied
chw_plant_reset low loop ΔT (low_deltaT_pct; not on a constant-flow plant, flow_mode) / CHWST rising with OAT (chwst_reset_direction: reverse) / flat CHWST (chwst_reset_present) Fix low loop ΔT / find why the chilled-water supply warms in hot weather / reset the CHW supply temperature
chw_pump_dp_reset, hw_pump_dp_reset at the VFD minimum / near full with a reset / near full without Right-size the pump / find the valve driving the reset / reset the DP setpoint
boiler_summer_lockout, hw_pump_summer_lockout (0.103) running above the lockout (summer_run_pct, lockout_oat_f); for the pump, with the boiler off (boiler_off_pct at least 50 %) Lock the boiler / the hot-water pump out above the heating lockout; find the override or the call for heat
supply_air_reset the setpoint already resets (sp_behaviour) / SAT rises with load (reset_direction) Widen the reset range / check cooling capacity
cooling_tower_approach wide approach at full fan (effort_gated) Restore tower capacity (fill, distribution, flow)
reheat_minimization_g36 reheat above the minimum airflow Implement the dual-maximum heating sequence
overcooling_min_flow, overcooling_severity at minimum flow / depth below setpoint Lower min flow or raise SAT (never a higher cooling setpoint)
free_cooling_missed damper commanded open, OA not delivered (missed_cause) / economizer not commanded Repair the OA damper or actuator / enable economizer free cooling

The dispatch thresholds mirror the rules' defaults (DEFAULT_PARAMS: dcv_*, chw_low_dt_warn_pct, pump_near_*_warn_pct); a finding's severity and metrics are never changed. The DCV system rule reads the cause from the air handler that set its severity (metrics["per_ahu"]).

Learn more. Each Recommendation carries references: the ids of the PNNL Re-tuning guides behind it, most specific first (an under-ventilation outdoor_air_fraction finding points at the minimum-OA guide, excess OA at the economizer guide). Reports turn them into links.

Pairs with camber.fault_economics (what a fault is worth) and camber.soo (conformance to the intended sequence).