Back to the portfolio

SolarCast

Predicts how much sunlight will reach a solar site 6 to 48 hours ahead, with 24% less error than the free weather forecast it starts from.

Python · XGBoost · TensorFlow · Optuna · Keras Tuner · pytest in CI · on-prem Linux + NVIDIA GPU

24% less error RMSE than the Open-Meteo weather forecast alone, 6 and 12 hours ahead, on a year of data the models never saw; the same in daylight hours only

The program

A solar farm needs to know how much sunlight is coming so it can plan how much power it will sell. Free weather forecasts already predict sunlight, so the question is whether a model can do better than just using them. SolarCast takes the Open-Meteo forecast, learns where it tends to be wrong, and corrects it, checking itself against satellite measurements of the sunlight that actually arrived (NREL's NSRDB).

The first version had a flaw: it learned from satellite data that isn't available in real time, so the live forecast fed it data it had never trained on. The rebuild trains on the same kind of forecast data it gets live. Two models (XGBoost and an LSTM neural network) each make a prediction and are averaged, with more weight on whichever did better in validation. The notebooks became a tested Python package: one command trains a new site from its latitude and longitude, and the tests run automatically on every change. This is a portfolio project, not a production deployment.

Autopsy

How it's scored: every model is tested on about a year of Bismarck, ND data (December 2023 to December 2024) that it never trained on, and compared with two baselines. The first is the plain Open-Meteo forecast, which is what you'd use without this project. The second is my old model, run the way it actually ran live. The score is root-mean-square error (RMSE) in watts per square metre, which counts a big miss more heavily than several small ones; full midday sun here is about 990 W/m².

Night hours are easy (the answer is zero), so scoring every hour flatters every model. Over all hours, 6 and 12 hours ahead, the RMSE is about 59 W/m² against 78 for the forecast alone: 24% less error. Counting daylight hours only, it is 83 against 110, still 24% less. The old model scored 98 to 103 over all hours, so the rebuild cut its error by about 40%. The models explain about 94% of the hour-to-hour variation in sunlight (R² 0.94), against 90% for the forecast alone.

1 and 2 days ahead the gain is smaller: 58 vs 60 W/m² for the forecast one day ahead (4% less error, close to noise) and 59 vs 69 two days ahead (14% less); in daylight only, 86 vs 90 and 88 vs 102. These use forecasts really issued a day or two earlier, but only cover August to December 2024, so they are less certain. Live error will also be somewhat higher than these archive scores, because the archive uses the newest forecast run for each hour.

Where it failed the baseline: forecasts 1 week to 48 weeks ahead are no better than simply guessing the average sunlight for that day of the year. The first version reported those models without making that comparison, so it looked better than it was.

If I keep going

Replace the long-range models with the day-of-year average unless they can beat it. And every number here comes from one site; the pipeline works anywhere, but I haven't yet shown the gain holds at a second one.

There's no automatic retraining or tracking of live accuracy. I'd log each live forecast against the satellite data that arrives later, which would measure the real live error instead of estimating it from the archive.

Read the code