Renewable Integration and DER Forecasting

The Business Problem: Balancing Variability from Renewable Energy

Renewable generation is rapidly reshaping power systems. Solar and wind resources reduce carbon emissions and fuel costs but also introduce variability and uncertainty. Unlike conventional plants, their output depends on weather conditions that can change hourly or even minute to minute.

This variability complicates grid operations. Large-scale solar can cause steep midday declines in net load, followed by sharp evening ramps as the sun sets. Wind farms can see output fluctuate significantly within hours. Operators must compensate by dispatching flexible generation, adjusting imports and exports, and sometimes curtailing renewables to preserve system stability.

At the distribution level, rooftop solar presents new challenges. High penetration can drive voltage beyond acceptable limits, especially on sunny days with low local demand. Managing these impacts requires accurate forecasts of DER output to anticipate when and where problems may arise.

Without precise renewable and DER forecasting, utilities risk inefficient operations, costly reserves, and reliability concerns. The transition to cleaner grids demands analytics that can predict renewable behavior and integrate it seamlessly into planning and operations.

The Analytics Solution: Forecasting Renewable and DER Output

Renewable integration relies on accurate forecasting of generation from both utility-scale and distributed sources. These forecasts combine meteorological data—irradiance, cloud cover, wind speed—with system-specific parameters such as panel orientation, inverter efficiency, and location.

For solar forecasting, tools like PVLib model photovoltaic output based on physical characteristics and weather inputs. These models can be combined with time series forecasting methods such as SARIMA to capture daily and seasonal patterns. For wind, similar physics-informed models translate wind speed forecasts into power curves.

DER forecasting extends these techniques to behind-the-meter systems. Utilities can estimate net load by subtracting predicted DER generation from gross demand forecasts, allowing better scheduling and voltage management. Advanced approaches integrate satellite imagery and sky cameras to predict short-term cloud cover impacts on solar output.

Operational Benefits

Improved renewable forecasting reduces the need for expensive spinning reserves and helps prevent over- or under-commitment of generation. It allows more efficient dispatch, minimizes renewable curtailment, and enhances market bidding strategies. For distribution utilities, accurate DER output estimates help avoid voltage violations and feeder overloads by informing inverter settings or reconfiguration actions.

Forecasting also enables new business models. Aggregators can bid aggregated DER resources into wholesale markets with confidence, and operators can use forecasts to design dynamic pricing programs that align demand with renewable availability.

Transition to the Demo

In this chapter’s demo, we will simulate a solar photovoltaic plant using PVLib and forecast its output using SARIMA. We will:

This demonstration ties renewable forecasting directly to operational challenges, showing how analytics enables utilities to integrate variable resources while maintaining reliability and efficiency.

pyfile shortcode: missing param 'file'. Example: {{< pyfile file="script.py" >}}

Code

"""
Chapter 8: Renewable Integration and DER Forecasting
Solar PV generation modeling using PVLib and forecasting with SARIMA.
"""

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pvlib import location, modelchain, pvsystem
from pvlib.temperature import TEMPERATURE_MODEL_PARAMETERS
from statsmodels.tsa.statespace.sarimax import SARIMAX

def simulate_solar_pv():
    """
    Simulate solar PV output using PVLib for a 1MW system in Texas.
    """
    site = location.Location(latitude=30.27, longitude=-97.74, tz="US/Central", altitude=149, name="Austin, TX")
    times = pd.date_range("2022-06-01", "2022-06-14", freq="H", tz=site.tz)

    # Clear-sky irradiance
    clearsky = site.get_clearsky(times)
    temp_air = np.random.normal(30, 3, len(times))
    wind_speed = np.random.uniform(1, 5, len(times))

    # PV system configuration
    temp_params = TEMPERATURE_MODEL_PARAMETERS["sapm"]["open_rack_glass_glass"]
    module = pvsystem.retrieve_sam("CECMod")["Canadian_Solar_CS5P_220M___2009_"]
    inverter = pvsystem.retrieve_sam("cecinverter")["ABB__MICRO_0_25_I_OUTD_US_208__208V_"]

    system = pvsystem.PVSystem(surface_tilt=25, surface_azimuth=180, module_parameters=module,
                               inverter_parameters=inverter, temperature_model_parameters=temp_params)

    mc = modelchain.ModelChain(system, site)
    weather = pd.DataFrame({
        "ghi": clearsky["ghi"],
        "dni": clearsky["dni"],
        "dhi": clearsky["dhi"],
        "temp_air": temp_air,
        "wind_speed": wind_speed
    }, index=times)

    mc.run_model(weather)
    ac_power = mc.results.ac
    df = pd.DataFrame({"timestamp": times, "AC_Power_kW": ac_power})
    return df

def plot_pv(df):
    """
    Plot PV output.
    """
    plt.figure(figsize=(12, 4))
    plt.plot(df["timestamp"], df["AC_Power_kW"], color="black")
    plt.xlabel("Time")
    plt.ylabel("AC Power (kW)")
    plt.title("Simulated Solar PV Output (Austin, TX)")
    plt.tight_layout()
    plt.savefig("chapter8_pv_output.png")
    plt.show()

def sarima_forecast(df):
    """
    Forecast PV output using SARIMA (Statsmodels).
    """
    df = df.set_index("timestamp")
    ts = df["AC_Power_kW"].asfreq("H")

    # Fit SARIMA model (daily seasonality: 24 hours)
    model = SARIMAX(ts, order=(1, 1, 1), seasonal_order=(1, 1, 0, 24), enforce_stationarity=False, enforce_invertibility=False)
    fit = model.fit(disp=False)

    forecast_steps = 24  # 1 day ahead
    forecast = fit.forecast(steps=forecast_steps)

    plt.figure(figsize=(12, 4))
    plt.plot(ts[-48:], label="Observed (Last 2 Days)", color="gray")
    plt.plot(forecast.index, forecast, label="SARIMA Forecast (Next 24h)", color="black")
    plt.xlabel("Time")
    plt.ylabel("AC Power (kW)")
    plt.title("SARIMA Forecast of Solar PV Output")
    plt.legend()
    plt.tight_layout()
    plt.savefig("chapter8_sarima_forecast.png")
    plt.show()

if __name__ == "__main__":
    df_pv = simulate_solar_pv()
    plot_pv(df_pv)
    sarima_forecast(df_pv)