Question and scope
The target is mean AC power across reporting inverters at a timestamp, estimated from weather observed at that same time. This is retrospective, contemporaneous estimation. It is not next-day forecasting, panel diagnosis or validation of Solar Revitalizer™ routing.
Method in brief
- Aggregate generation to mean inverter AC power per plant and timestamp; join weather one-to-one.
- Retain complete 22-inverter coverage, finite matched weather and irradiation above 0.01 in native source units. This sample restriction can introduce selection bias.
- Keep complete dates in chronological training, validation and final-test partitions. Fit each plant separately.
- Compare a linear-through-origin irradiation baseline, quadratic irradiation ridge regression, and ridge regression with temperature interactions. Choose regularization on validation MAE, then refit using training plus validation.
- Exclude contemporaneous DC power, yield counters and inverter identifiers from model features. Constrain predictions to nonnegative values.
Inspect the time split and data-quality checks
Later dates make the final comparison.
Model selection used an earlier validation period. The final seven days were held out for the reported comparison.
- Training20 calendar days2020-05-15 → 2020-06-03
- Validation7 calendar days2020-06-04 → 2020-06-10
- Final test7 calendar days2020-06-11 → 2020-06-17
| Partition | Plant 1 | Plant 2 |
|---|---|---|
| Training | 941 | 506 |
| Validation | 343 | 349 |
| Final test | 341 | 349 |
What the comparison shows
Both flexible models reduced final-week error relative to the linear irradiation baseline. The temperature-interaction model gave little additional improvement for Plant 1 and had higher error than the quadratic model for Plant 2.
This is evidence for checking complexity against a useful baseline in this dataset and time window. It does not establish a causal temperature effect or broad transfer to other plants.
Does the added complexity help?
Test nMAE (% of training AC-power 95th percentile). Lower is better. Common visual scale: 0–16%.
The temperature model offers little additional benefit for Plant 1 and has higher error than the quadratic model for Plant 2.
| Model | Plant 1 nMAE | Plant 2 nMAE |
|---|---|---|
| Linear irradiation baseline | 3.26% | 14.10% |
| Quadratic irradiation ridge | 1.97% | 7.28% |
| Ridge + temperature interactions | 1.94% | 7.57% |
Final-test observations: 341 timestamps for Plant 1; 349 for Plant 2. Each model is evaluated on the same retained observations within a plant. nMAE = 100 × mean absolute error ÷ training AC-power 95th percentile. This denominator is not rated capacity.
Inspect the evaluation code
The excerpt shows the chronological data split and training-only normalization used to calculate model error. Dataset credit: Ani Kannal, Solar Power Generation Data.
# Chronological evaluation and training-set error normalization.
# Input preparation and model fitting are described in the case methods.
train_dates, val_dates, test_dates = all_dates[:20], all_dates[20:27], all_dates[27:]
full = merged.inverter_count.eq(expected_inverters)
weather_valid = np.isfinite(merged[["IRRADIATION", "AMBIENT_TEMPERATURE", "MODULE_TEMPERATURE"]].to_numpy()).all(axis=1)
daylight = merged.IRRADIATION.gt(0.01)
clean = merged.loc[full & weather_valid & daylight].copy().sort_values("DATE_TIME")
clean["date"] = clean.DATE_TIME.dt.date
train = clean.loc[clean.date.isin(train_dates)].copy()
val = clean.loc[clean.date.isin(val_dates)].copy()
test = clean.loc[clean.date.isin(test_dates)].copy()
assert train.DATE_TIME.max() < val.DATE_TIME.min() < test.DATE_TIME.min()
assert not set(train.date) & set(test.date)
if min(len(train), len(val), len(test)) < 30:
raise ValueError("Insufficient retained observations in a time partition")
xtrain, xval = features(train), features(val)
ytrain, yval = train.AC_POWER.to_numpy(), val.AC_POWER.to_numpy()
scale = float(np.quantile(ytrain, 0.95))
def metrics(y, pred, scale):
return {"mae_reported_kw": float(np.mean(np.abs(y-pred))),
"rmse_reported_kw": float(np.sqrt(np.mean((y-pred)**2))),
"nmae_percent_train_p95": float(100*np.mean(np.abs(y-pred))/scale)}
Save the code excerpt Limits and next tests
- Two plants and one seven-day final evaluation window limit generalization.
- nMAE is normalized by each plant’s training AC-power 95th percentile, not rated capacity. Power values use the dataset’s reported units, which have not been independently verified.
- Complete-case and daylight filtering can change the population represented.
- Independent plants and periods, source metadata checks, distribution-shift tests and uncertainty calibration remain future work.
- Module-level disposition research requires separate condition, safety, performance and reference-outcome data.
Continue into the architecture.
See how this work informs the next research question.
Follow traceable evidence