⚡ How VoltCast works
Predicting how much electricity four US grid regions will need over the next 24 hours, the same way you'd forecast weather but for power demand.
← Back to the dashboardThe problem
Every hour, grid operators have to decide how much power to generate. Too little means blackouts. Too much wastes money and fuel. VoltCast looks at the last week of demand and predicts the next 24 hours for California, Texas (ERCOT), the Mid-Atlantic (PJM), and the Midwest (MISO).
The pipeline
Data flows one direction: from the government API to the chart you see. Each step hands off to the next.
- 1Pull the data. The EIA (US Energy Information Administration) publishes real hourly demand per region. We pull a rolling 5-year window into Parquet files.
- 2Validate it. A Pandera schema rejects bad rows: nulls, negative load, impossible spikes, gaps in time. Corrupt data never reaches the model.
- 3Engineer features. Raw megawatts plus context: sin/cos encodings of hour, day, and month (so hour 23 sits next to hour 0), lag features (load 1h, 24h, and 168h ago), rolling averages, and a weekend flag. Then z-score normalize, scaler fit on the training split only — no peeking at the future.
- 4Slide a window. The long time series becomes thousands of training examples: each is 168 hours of input mapped to the 24 hours that follow.
- 5Predict. The champion model takes the latest 168 real hours and outputs all 24 future hours in one shot. No feeding predictions back in.
- 6Publish. Forecasts land in S3 as JSON. This dashboard reads them through a server route that holds the AWS keys, so the bucket stays private and the browser never touches AWS.
The model
A Temporal Transformer, written from scratch in PyTorch. No HuggingFace, no Trainer abstractions. It learns which past hours matter most for each prediction. To forecast 9pm Friday, it can learn to look hard at 9pm last Friday.
- Input projection maps the 13 features into a 64-dim internal space.
- Positional encoding tells the model where each hour sits in the sequence, since attention has no built-in sense of order.
- Two attention layers (4 heads each) weigh the relationships between hours.
- Output head turns the last timestep into 24 predicted megawatt values.
To prove it earns its place, every region also trains an LSTM and a naive "tomorrow = today" baseline. If the Transformer can't beat copy-paste, something is broken. It beats the naive baseline by roughly 33%.
The serverless loop
Nothing runs 24/7. There is no API server. Compute is ephemeral GitHub Actions runners, storage is S3 and DagsHub, the dashboard is on Vercel. Cost is close to zero.
- Hourly: refresh data and regenerate every region's 24-hour forecast.
- Weekly: check for drift with Evidently. If the data distribution moved or the model went stale, retrain. A challenger only replaces the champion if it beats it by 1% on the untouched test set.
- Tracked: MLflow on DagsHub logs every run's hyperparameters, metrics, and model file, with a champion/challenger registry deciding what ships.
Reading the numbers
- MAE (mean absolute error) is the headline metric: on average, how many megawatts the forecast is off by. Lower is better.
- WAPE expresses that error as a percentage of total demand, so regions of different sizes compare fairly.
- All times are UTC. The dataset is UTC end to end, so the chart and table avoid any timezone guessing.