01 · Audit methodology

ECM library matching: the 50+ rules

Last updated 2026-04-21
Draft published
First-pass content live. Engineering review and Opnor-team validation in progress — see the "author backlog" callouts at the bottom.

The ECM library is a set of rules. Each rule examines an asset (or a system, or a whole plant) and decides whether a specific energy-saving measure applies. Multiplying the asset list by the rule set produces the candidate ECM list — typically 15–25 measures per audit. This article describes the rule architecture: what the engine does, what it doesn't, and why we've kept it deliberately rule-based instead of model-based.

What an ECM rule looks like

Every ECM rule has the same anatomy:

Trigger conditions
Predicates on asset fields (asset_type, nameplate_kw, load_factor, has_vfd, motor_efficiency_class, energy_domain, …). All must evaluate true for the rule to fire.
Savings formula
A closed-form expression with named variables. No black-box numerics — a P.Eng. can read the formula and recompute by hand.
Realization factor
A scalar haircut applied to the theoretical savings to align with measured post-implementation results. Tuned per ECM type, sometimes per industry.
Confidence weight
How much the asset's confidence score affects the recommended priority. Low-confidence assets generate ECMs flagged 'subject to field verification'.
Cost model hint
Pointer to the cost-engine reference data — equipment, material, labour for this ECM type at this asset size. Drives the AACE Class 4 estimate.

A specific example — the VFD retrofit rule on centrifugal pumps. This is verbatim what lives in energy_engine/ecm_library.py:

energy_engine/ecm_library.py
@ecm_rule(
    id="VFD_RETROFIT_CENTRIFUGAL",
    type="VFD",
    description="Variable-frequency drive retrofit on centrifugal load",
)
def vfd_retrofit(asset: Asset) -> Optional[EcmCandidate]:
    # ---- Trigger conditions
    if asset.asset_type not in (PUMP, FAN, BLOWER):
        return None
    if asset.has_vfd:
        return None
    if asset.nameplate_kw < 5:
        return None
    if asset.load_factor > 0.85:
        return None
    if asset.operating_hours < 3000:
        return None

    # ---- Savings formula (cube-of-speed affinity law)
    realization = REALIZATION_FACTORS.get(
        asset.industry, REALIZATION_FACTORS["DEFAULT"]
    )                                                # 0.80 default · 0.85 wood · 0.75 mining

    savings_kwh = (
        asset.nameplate_kw
        * asset.operating_hours
        * asset.qty
        * (1 - asset.load_factor ** 3)
        * realization
    )

    return EcmCandidate(
        asset=asset,
        savings_kwh=savings_kwh,
        confidence=asset.confidence_score,
        cost_model_hint="VFD_RETROFIT",
    )

The full library — all 50+ rules — is readable as data, not as ML weights. A reviewer can open the file, search for the rule that matched, and recompute by hand if they want.

How the matching engine runs

For each audit, after the asset hierarchy is loaded:

  • Iterate every asset in the hierarchy.
  • For each asset, evaluate every rule's trigger conditions.
  • When a rule fires, compute the savings formula. Multiply by the realization factor.
  • Tag the candidate ECM with: asset reference, rule reference, raw savings, monetized savings (using carrier rates), confidence (inherited from the asset's confidence score), industry (for downstream cost adjustments).
  • After all assets are processed, group candidates by ECM type and by area. Sum savings within groups.
  • Apply de-duplication: an asset that fires both VFD-retrofit and motor-upgrade rules generates one combined ECM if the rules are paired; otherwise both are reported separately with a note that capex assumes one-or-other implementation.
  • Rank by absolute savings, by payback, and by confidence. Output to the ECM Suggestions panel.

On a typical 500-asset plant the entire matching pass runs in under 200ms. That's the speed unlock that makes interactive ECM analysis possible — change a load factor in the asset hierarchy, the engine re-runs, the suggested ECM list updates live.

Why rules, not ML

ML-based ECM identification is a reasonable-sounding pitch — "train a model to discover savings opportunities from your utility data." In industrial energy auditing, it's the wrong architecture for two reasons:

Defensibility. Every ECM recommended in an audit goes into a deliverable that gets reviewed by Hydro-Québec, signed off by a P.Eng., and used to authorize capital. The reviewer needs to see the formula. A model that can't produce a closed-form savings calculation traceable to physics fails review on principle, regardless of how good its predictions are.

Data sparsity. A given audit has 12 months of utility bills, a partial sub-meter dataset, and an asset list. That's not enough data to train a model — it's barely enough to evaluate one. ML applied to industrial energy looks impressive on aggregate datasets across many plants but performs poorly on a single plant's data, which is what auditors actually have.

Rule-based matching gives up some flexibility in exchange for full defensibility, fast execution, and direct traceability from a recommended ECM back to the engineering principle behind it. Every match comes with a formula a reviewer can recompute on a whiteboard. That's the gold standard for an audit deliverable.

Where AI does help
AI accelerates other parts of the audit — see Why we don't lead with AI. Data ingestion, normalization, baseline regression, and report drafting are all AI-assisted. ECM matching specifically is not, because the value of having a defensible engineering rule outweighs the value of any ML uplift on prediction accuracy in this context.

The library: 4 engine types

The 50+ rules in the Opnor library cluster into four ECM-type families:

Variable-frequency drive retrofits
Centrifugal load identification, affinity-law savings, system-curve corrections. VFD article.
Motor upgrades
IE-class delta calculations, replacement-vs-spare logic, sizing checks. Motor article.
Heat recovery
Source-temperature thresholds, sink-co-location checks, exchanger effectiveness assumptions. Heat-recovery article.
Compressed air optimization
Leak-program savings, demand-side controls, supply-side bundling. Compressed-air article.

Within each family, rules differ by industry, by asset size band, and by operating profile. The full rule count expands roughly as: 4 base types × 5 industries × 3 size bands × 2–3 operating profiles ≈ 60–90 rules. About 50 are in the public library; the rest are sector-specific niches that only fire on particular industry/asset combinations.

What the matching produces

For every audit, the matching engine outputs:

  • Total identified savings: aggregate kWh and CAD across all candidates
  • Per-ECM-type rollup: total savings, candidate count, average payback
  • Per-area rollup: which process areas have the deepest opportunity pockets
  • Per-asset detail: ECM(s) matched, savings, confidence, ECM-specific notes (e.g. 'requires harmonic filter', 'co-located thermal sink confirmed by walk-through')
  • Verification recommendations: low-confidence candidates flagged for field measurement before commitment

A single ECM candidate from the matching pass looks like:

ECM candidate · output
{
  "id":             "ECM-VFD-M42",
  "rule_id":        "VFD_RETROFIT_CENTRIFUGAL",
  "type":           "VFD",
  "asset_tag":      "M-42",
  "asset_name":     "Centrifugal Pump (Main Loop)",
  "area":           "Cooling",

  "savings_kwh":    51,879,
  "savings_cad":    3632,
  "confidence":     0.72,

  "capex_band":     "$8,000 – $14,000  (AACE Class 4)",
  "payback_years":  2.6,

  "notes": [
    "Centrifugal pump confirmed via asset_type field",
    "Load factor 0.68 estimated · field verification recommended",
    "No harmonic filter required (motor < 30 kW)"
  ]
}

The ECM Suggestions panel in the auditor app renders all of these. The 2-week deep-dive deliverable includes the per-asset detail as an appendix.

What the engine doesn't do

  • It doesn't identify novel ECMs. The library is a fixed catalog. New ECM types are added by engineering, not learned from data.
  • It doesn't size capex precisely. Cost estimates are AACE Class 4 — directional. ECMs that pass screening go to Class 3 estimation as a separate engagement.
  • It doesn't replace engineering judgement on edge cases. Sub-150-kW assets at unusual operating profiles, retrofits with substantial integration risk, ECMs requiring co-located demand verification — all get a flag, not an automatic recommendation.
  • It doesn't predict realization for new technologies (e.g. hydrogen-based industrial heating, novel electrolytic processes). The rule library is calibrated against established ECM types with measured post-implementation history.
🚧 Author backlog (Opnor team to fill)
  • Pull and document the full current rule list from energy_engine/ecm_library.py — currently the article references '50+' generically
  • Document the per-industry rule overrides — sawmill rules, mining rules, etc.
  • Add a rule-version-history note: what gets added, what gets retired, on what cadence