sn-triage

A daily fault-triage classifier for solar PV plants: given a 24-number shape summary of one plant-day (performance index vs baseline, clear-sky ratios, plateau/dead runs, temperature tracking, snow trail, seasonality), it labels the day as one of nine classes:

healthy, outage, weather, snow, snow_shedding, cloud_intermittent, clipping, curtailment, thermal.

The model is a scikit-learn HistGradientBoostingClassifier distilled from a rules-plus-referee pipeline over 32 public PVDAQ systems and one SolarNetwork node. It was built to generalize to plants it has never seen: every feature is a ratio or a fraction of plant capacity, and missing values (no temperature sensor, short history, no weather feed) are tolerated as NaN. It runs day-level, per site, on a single meter stream β€” sub-metering is not required at inference time.

Usage

model.joblib is a self-describing bundle (a plain dict), pickled with joblib under scikit-learn 1.9.0 / Python 3.11:

import joblib

bundle = joblib.load("model.joblib")
model    = bundle["model"]      # HistGradientBoostingClassifier
features = bundle["features"]   # ordered list of 24 column names
classes  = bundle["classes"]    # the 9 labels
# bundle["trained_at"] = "2026-08-01T03:44:37+00:00"
# bundle["version"]    = "20260801T034437Z"

X = day_frame[features]         # one row per day; NaN allowed
labels = model.predict(X)
proba  = model.predict_proba(X)

Feature definitions and the training data are in the companion dataset: hoodsy/sn-triage-dataset. The 24 features, in bundle order: pi_rel, csr, model_csr, chop, plateau_run_h, peak_frac, expected_peak_frac, dead_run_h, morning_ratio, midday_ratio, tmax_c, temp_corr, snow_3d, snow_7d, snow_30d, pi_slope_14d, pi_drop_share, unit_count, unit_dist, doy_sin, doy_cos, pi, coverage, rain_mm.

This is a joblib pickle β€” load it only from this repository or another source you trust.

Training

  • 67,987 trainable site-days (nine classes; data_gap and unclassified days excluded) across 33 sites, of which 6,141 are gold: days graded against per-inverter data by a fleet-relative referee. Sample weights = class balance Γ— 5 for gold.
  • Labels come from an evidence-backed rule classifier, overruled by the referee where sub-metering proved it wrong. The published dataset holds 67,782 of these 67,987 trainable rows: the difference is exactly the 205 trainable days of the one non-PVDAQ training site (a SolarNetwork node excluded from the dataset for licensing reasons).

Evaluation

Faults are multi-day events; all protocols split by event or by site, never by row.

  • Leave-one-site-out macro-F1 0.92 (headline): train on 32 sites, score the held-out site, rotate. All classes β‰₯ 0.86 except curtailment (0.69).
  • Event-holdout macro-F1 0.959.
  • On the 1,552 days where the referee overruled the rules, this model β€” never trained on the site being scored β€” sides with the referee 77% of the time and with the overruled rule label 0%.
  • True held-out-site test: two Santa Ana, CA systems (PVDAQ 14695/14697) were onboarded after training and scored against the frozen model: 98.4% day-level agreement over 1,710 labeled days, 88.5% on the 208 referee-graded days, zero false alarms across 1,383 healthy days. Both sites were folded into training afterward, and this published model is the retrain; the numbers above describe its frozen predecessor on data that model had never seen.

Edge deployment

This exact bundle (20260801T034437Z) also runs at the edge as a SolarQuant plugin (Ecosuite's spec: a container on the plant's SolarNode ingests live datums, closes each local day, computes the same 24 features β€” Open-Meteo weather when available, clear-sky fallback β€” and posts a daily fault-class datum). Replaying a 7-month window of the SolarNetwork training node through the containerized plugin at production streaming cadence reproduced the batch pipeline's final labels on 92.4% of 211 days, including 88/88 outage days (a real 77-day outage) and 44/44 weather days. The residual is the plugin's online trailing-median baseline vs the batch two-pass baseline on marginal healthy/weather days, plus days the batch left unclassified (a label this model deliberately does not have β€” it predicts over them).

Limitations

  • Curtailment is the hard class (F1 0.69). Its residual confusion is asymmetric partial outage (one inverter of two down) vs curtailment β€” from a single meter stream both look like a bright, smooth, scaled-down day. Separating them reliably requires sub-metering.
  • Trained on fixed-tilt systems only; tracker plants are out of scope.
  • Day-level granularity: it labels days, not intervals, and won't catch sub-daily transients.
  • Weather features assume Open-Meteo/ERA5-like inputs where used; they are NaN-tolerant but the model performs best with them present.

Attribution

Trained on data derived from NREL's PVDAQ public datasets (DOE Open Energy Data Initiative, CC BY 4.0):

Deline, C., Perry, K., Deceglie, M., Muller, M., Sekulic, W., & Jordan, D. (2021). Photovoltaic Data Acquisition (PVDAQ) Public Datasets [Data set]. Open Energy Data Initiative (OEDI). NREL. https://doi.org/10.25984/1846021

Weather data by Open-Meteo.com (CC BY 4.0); contains modified Copernicus Climate Change Service information (ERA5). One additional training site (a residential Auckland node) comes from the SolarNetwork public API.

Downloads last month
-
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Dataset used to train hoodsy/sn-triage

Evaluation results

  • leave-one-site-out macro-F1 on PVDAQ daily solar fault triage (leave-one-site-out)
    self-reported
    0.920