energykit.optimize
Provably-optimal battery and EV dispatch scheduling.
energykit.optimize — DER scheduling: battery, EV, solar dispatch.
- class energykit.optimize.BatteryScheduler(capacity_kwh: float, max_power_kw: float, efficiency: float = 0.9, initial_soc: float = 0.5, min_soc: float = 0.1, max_soc: float = 0.95, dt_hours: float = 1.0, index: DatetimeIndex | None = None)[source]
Bases:
objectOptimal battery charge/discharge scheduler.
Formulates a linear program to minimize total electricity cost over a planning horizon by choosing when to charge (buy cheap) and discharge (avoid buying expensive).
The LP is:
\[\min_{c_t, d_t} \sum_t p_t (c_t - d_t) \cdot \Delta t\]subject to:
SoC dynamics: \(SoC_{t+1} = SoC_t + \eta_c c_t \Delta t - (1/\eta_d) d_t \Delta t\)
Capacity: \(SoC_{\min} \le SoC_t \le SoC_{\max}\)
Power limits: \(0 \le c_t, d_t \le P_{\max}\)
No simultaneous charge/discharge (relaxed LP — typically satisfied at optimum)
- Parameters:
capacity_kwh (float) – Usable battery capacity in kWh.
max_power_kw (float) – Maximum charge and discharge power in kW.
efficiency (float, default 0.90) – Round-trip efficiency (0–1). Applied symmetrically to charge and discharge.
initial_soc (float, default 0.50) – Initial state of charge as a fraction of capacity (0–1).
min_soc (float, default 0.10) – Minimum allowed SoC (depth-of-discharge protection).
max_soc (float, default 0.95) – Maximum allowed SoC (overcharge protection).
dt_hours (float, default 1.0) – Timestep duration in hours. Use 0.5 for 30-minute data.
index (pd.DatetimeIndex or None) – Optional datetime index for the output schedule.
Examples
>>> batt = BatteryScheduler(capacity_kwh=10, max_power_kw=5) >>> result = batt.optimize(prices_array) >>> result.schedule_df[["charge_kw", "discharge_kw", "soc_kwh"]].plot()
- optimize(prices: ndarray, load_kw: ndarray | None = None) ScheduleResult[source]
Run the battery optimization.
- Parameters:
prices (array-like of shape (T,)) – Electricity import price at each timestep ($/kWh or any currency/kWh).
load_kw (array-like of shape (T,) or None) – Baseline load at each timestep (kW). Used only for baseline cost calculation. Does not affect the battery dispatch.
- Return type:
- class energykit.optimize.EVScheduler(battery_kwh: float, max_charge_kw: float, efficiency: float = 0.92, dt_hours: float = 1.0, index: DatetimeIndex | None = None)[source]
Bases:
objectSmart EV charging scheduler.
Charges an EV battery to a target SoC by a departure time while minimizing electricity cost. Models unidirectional (G1V) charging only.
- Parameters:
battery_kwh (float) – EV battery capacity (usable, kWh).
max_charge_kw (float) – Maximum AC charging power (e.g. 7.4 kW for Level 2 EVSE).
efficiency (float, default 0.92) – Charging efficiency (AC-to-DC).
dt_hours (float, default 1.0) – Timestep duration in hours.
index (pd.DatetimeIndex or None) – Optional datetime index for the output schedule.
Examples
>>> ev = EVScheduler(battery_kwh=75, max_charge_kw=11.0) >>> prices = np.tile([0.08, 0.10, 0.12, 0.25, 0.30], 5) # TOU prices >>> result = ev.optimize( ... prices=prices, ... initial_soc=0.20, ... target_soc=0.80, ... departure_step=22, # must be fully charged by step 22 ... ) >>> print(result.savings_usd)
- optimize(prices: ndarray, initial_soc: float, target_soc: float, departure_step: int | None = None) ScheduleResult[source]
Compute the cost-optimal EV charging schedule.
- Parameters:
prices (array-like, shape (T,)) – Electricity price over the planning horizon.
initial_soc (float) – Current SoC as fraction of capacity (0–1).
target_soc (float) – Required SoC at departure (0–1).
departure_step (int or None) – Timestep index by which
target_socmust be reached. Defaults to the last step.
- Return type:
DER Scheduler
energykit.optimize.der
Optimal scheduling of Distributed Energy Resources (DER) using Linear
Programming via scipy.optimize.linprog (no additional dependencies).
Classes
- BatteryScheduler
Minimize electricity cost by optimally scheduling battery charge / discharge given time-varying retail prices and technical constraints (capacity, max power, round-trip efficiency, SoC limits).
- EVScheduler
Smart EV charging scheduler. Charges the vehicle to a target state of charge by a departure time while minimizing electricity cost.
Both classes follow a simple optimize(prices) API that returns a
ScheduleResult dataclass.
Usage
>>> import numpy as np
>>> from energykit.optimize import BatteryScheduler
>>>
>>> # 24-hour time-of-use prices ($/kWh), hourly resolution
>>> prices = np.array([0.08]*8 + [0.22]*4 + [0.12]*4 + [0.28]*4 + [0.10]*4)
>>>
>>> battery = BatteryScheduler(
... capacity_kwh=13.5, # Tesla Powerwall 2
... max_power_kw=5.0,
... efficiency=0.90,
... initial_soc=0.20,
... )
>>> result = battery.optimize(prices)
>>> print(result.savings_usd)
1.84
>>> print(result.schedule_df)
- class energykit.optimize.der.BatteryScheduler(capacity_kwh: float, max_power_kw: float, efficiency: float = 0.9, initial_soc: float = 0.5, min_soc: float = 0.1, max_soc: float = 0.95, dt_hours: float = 1.0, index: DatetimeIndex | None = None)[source]
Bases:
objectOptimal battery charge/discharge scheduler.
Formulates a linear program to minimize total electricity cost over a planning horizon by choosing when to charge (buy cheap) and discharge (avoid buying expensive).
The LP is:
\[\min_{c_t, d_t} \sum_t p_t (c_t - d_t) \cdot \Delta t\]subject to:
SoC dynamics: \(SoC_{t+1} = SoC_t + \eta_c c_t \Delta t - (1/\eta_d) d_t \Delta t\)
Capacity: \(SoC_{\min} \le SoC_t \le SoC_{\max}\)
Power limits: \(0 \le c_t, d_t \le P_{\max}\)
No simultaneous charge/discharge (relaxed LP — typically satisfied at optimum)
- Parameters:
capacity_kwh (float) – Usable battery capacity in kWh.
max_power_kw (float) – Maximum charge and discharge power in kW.
efficiency (float, default 0.90) – Round-trip efficiency (0–1). Applied symmetrically to charge and discharge.
initial_soc (float, default 0.50) – Initial state of charge as a fraction of capacity (0–1).
min_soc (float, default 0.10) – Minimum allowed SoC (depth-of-discharge protection).
max_soc (float, default 0.95) – Maximum allowed SoC (overcharge protection).
dt_hours (float, default 1.0) – Timestep duration in hours. Use 0.5 for 30-minute data.
index (pd.DatetimeIndex or None) – Optional datetime index for the output schedule.
Examples
>>> batt = BatteryScheduler(capacity_kwh=10, max_power_kw=5) >>> result = batt.optimize(prices_array) >>> result.schedule_df[["charge_kw", "discharge_kw", "soc_kwh"]].plot()
- optimize(prices: ndarray, load_kw: ndarray | None = None) ScheduleResult[source]
Run the battery optimization.
- Parameters:
prices (array-like of shape (T,)) – Electricity import price at each timestep ($/kWh or any currency/kWh).
load_kw (array-like of shape (T,) or None) – Baseline load at each timestep (kW). Used only for baseline cost calculation. Does not affect the battery dispatch.
- Return type:
- class energykit.optimize.der.EVScheduler(battery_kwh: float, max_charge_kw: float, efficiency: float = 0.92, dt_hours: float = 1.0, index: DatetimeIndex | None = None)[source]
Bases:
objectSmart EV charging scheduler.
Charges an EV battery to a target SoC by a departure time while minimizing electricity cost. Models unidirectional (G1V) charging only.
- Parameters:
battery_kwh (float) – EV battery capacity (usable, kWh).
max_charge_kw (float) – Maximum AC charging power (e.g. 7.4 kW for Level 2 EVSE).
efficiency (float, default 0.92) – Charging efficiency (AC-to-DC).
dt_hours (float, default 1.0) – Timestep duration in hours.
index (pd.DatetimeIndex or None) – Optional datetime index for the output schedule.
Examples
>>> ev = EVScheduler(battery_kwh=75, max_charge_kw=11.0) >>> prices = np.tile([0.08, 0.10, 0.12, 0.25, 0.30], 5) # TOU prices >>> result = ev.optimize( ... prices=prices, ... initial_soc=0.20, ... target_soc=0.80, ... departure_step=22, # must be fully charged by step 22 ... ) >>> print(result.savings_usd)
- optimize(prices: ndarray, initial_soc: float, target_soc: float, departure_step: int | None = None) ScheduleResult[source]
Compute the cost-optimal EV charging schedule.
- Parameters:
prices (array-like, shape (T,)) – Electricity price over the planning horizon.
initial_soc (float) – Current SoC as fraction of capacity (0–1).
target_soc (float) – Required SoC at departure (0–1).
departure_step (int or None) – Timestep index by which
target_socmust be reached. Defaults to the last step.
- Return type:
- class energykit.optimize.der.ScheduleResult(schedule_df: DataFrame, total_cost_usd: float, baseline_cost_usd: float, savings_usd: float, status: str)[source]
Bases:
objectOptimization result from
BatterySchedulerorEVScheduler.- schedule_df
Hourly schedule with columns depending on optimizer type.
- Type:
pd.DataFrame