Skip to content

OSTEC Simple Module

Type: OSTEC_SIMPLE Category: Local Optimization Maturity: PRODUCTION (v2.0.0)

OSTEC Simple uses Mixed Integer Linear Programming (MILP) to optimize a community's flexible resources — batteries, EVs, and electric water heaters — over a rolling horizon.

What It Optimizes

The optimizer minimizes the total energy cost for the community by deciding:

  • Battery storage: when to charge and when to discharge
  • EV charging: optimal charging schedule given connection forecasts
  • EWH: when to heat water based on tariff periods

Input Data

Input Source Description
Energy forecasts External (pushed via API) Predicted consumption/production per meter
OMIE prices OMIE router Day-ahead market prices (€/kWh)
Grid tariffs ERSE tariffs Time-of-use network charges
Storage state Database Current battery state of charge (SOC)
EV connection forecast Database Predicted EV connection windows
Opportunity costs Database Resource-level cost overrides

Optimization Horizon

Controlled by the configuration:

Parameter Description
horizon Number of hours to optimize (e.g., 24 for day-ahead)
delta_t Time step size in hours (1.0 = hourly, 0.5 = 30-minute)

Decision Variables

For each resource r and time step t:

Variable Type Description
p_charge[r,t] Continuous Charge power (kW)
p_discharge[r,t] Continuous Discharge power (kW)
soc[r,t] Continuous State of charge (kWh)
u_charge[r,t] Binary Charging active (1/0)
u_discharge[r,t] Binary Discharging active (1/0)

Objective Function

Minimize total energy cost across all meters and time steps:

minimize  Σ_{m,t} [ l_grid[m,t] · p_grid_import[m,t]
                  - l_lem[m,t]  · p_lem_sell[m,t]
                  + l_market_buy · p_market_buy[t]
                  - l_market_sell · p_market_sell[t]
                  + l_extra · slack[m,t] ]

Where:

  • l_grid — grid import price (tariff + OMIE) (€/kWh)
  • l_lem — LEM selling price (€/kWh)
  • l_market_buy/sell — penalty bounds for market imbalance
  • l_extra — penalty for constraint relaxation

Key Constraints

  • Power balance: at each timestep, generation + discharge + grid_import = consumption + charge + grid_export
  • SOC continuity: soc[t] = soc[t-1] + charge_eff·p_charge[t]·Δt - p_discharge[t]·Δt/discharge_eff
  • Capacity bounds: soc_min ≤ soc[t] ≤ capacity_kwh
  • Power bounds: 0 ≤ p_charge[t] ≤ power_kw · u_charge[t]
  • Mutual exclusion: u_charge[t] + u_discharge[t] ≤ 1
  • EV availability: p_charge[t] = 0 when EV is not connected

Supported Solvers

Solver Open Source Notes
CPLEX No Best performance; requires IBM license
CBC Yes Good for small/medium instances
GLPK Yes Slower; fallback option

Output

For each resource and time step, the module writes an EnergySetpoint record to the database:

  • setpoint_value — the commanded power (kW)
  • setpoint_typeSTORAGE_CHARGE, STORAGE_DISCHARGE, EV_CHARGE, EWH_HEATING
  • calculation_metadata — solver status, objective value, solve time

Configuration Schema

{
  "l_extra": 10.0,
  "l_market_buy": 500.0,
  "l_market_sell": -500.0,
  "solver": "CPLEX"
}
Field Default Description
l_extra 10.0 Penalty cost for slack variables (€/kWh)
l_market_buy 500.0 Upper bound on market buy price (€/kWh)
l_market_sell -500.0 Lower bound on market sell price (€/kWh)
solver "CPLEX" MILP solver to use