Shifting electric load
Shifting electric load with BESS.

Reading time: 3 min.

Setup

Optimising cost of electric load by shifting via battery.

Variants including battery losses and max grid load pricing.

Deterministic base model

Time related stuff:

input NumPeriods in {1, 2, ...}
local Periods := {1, ..., NumPeriods}

unit Time

input PeriodLength in ]0, inf[ <Time>

Price and load forecasts as inputs.

unit ElectricPower
unit ElectricWork := ElectricPower * Time
unit Currency
unit WorkPrice := Valuation / ElectricWork

input Load[Periods] in ]-inf, inf[ <ElectricPower>
input PFC[Periods] in ]-inf, inf[ <WorkPrice>

Optimize for cost.

decision Cost[p in Periods] := 
  Load[p] * PFC[p] * PeriodLength
assert _ [p in Periods] unitof Cost[p] = Currency

minimize sum[p in Periods] Cost[p]

The optimimum is determistic.

With a battery

Battery parameters:

unit BatteryWork

input BatteryCapacity in [0, inf[ <BatteryWork>

input StartCharge in [0 <BatteryWork>, BatteryCapacity]
input EndCharge in [0 <BatteryWork>, BatteryCapacity]

input BatteryChargeFactor in ]0, 1] <BatteryWork/ElectricWork>
local BatteryChargeConversion := BatteryChargeFactor
input BatteryMaxCharge in [0, inf[ <ElectricPower>

input BatteryDischargeFactor in ]0, 1] <BatteryWork/ElectricWork>
local BatteryDischargeConversion := 1 / BatteryDischargeFactor
assert _ unitof BatteryDischargeConversion = <ElectricWork/BatteryWork>
input BatteryMaxDischarge in [0, inf[ <ElectricPower>

input BatteryStateLoss in [0, 1] <BatteryWork/BatteryWork/Time>
assert _ unitof BatteryStateLoss = <1/Time>

State of charge at beginning and end:

local Instants := {0, 1, ..., NumPeriods}

decision BatteryStateOfCharge[Instants] in [0 <BatteryWork>, BatteryCapacity]


constraint _ is 
  StartCharge = BatteryStateOfCharge[0]
constraint _ is 
  EndCharge = BatteryStateOfCharge[NumPeriods]
decision BatteryCharge[Periods] in [0 <ElectricPower>, BatteryMaxCharge]
decision BatteryDischarge[Periods] in [0 <ElectricPower>, BatteryMaxDischarge]

State of charge for periods:

constraint BatteryChargeBalance[p in Periods] is 
  BatteryStateOfCharge[p] 
  = 
  BatteryStateLoss * BatteryStateOfCharge[p - 1] * PeriodLength
  + BatteryChargeConversion * BatteryCharge[p] * PeriodLength
  - BatteryDischargeConversion * BatteryDischarge[p] * PeriodLength

assert _[p in Periods] unitof BatteryChargeBalance[p] = <BatteryWork>
decision GridLoad[p in Periods] := 
  Load[p] + BatteryCharge[p] - BatteryDischarge[p]

decision Cost[p in Periods] := 
  GridLoad[p] * PFC[p] * PeriodLength

minimize sum[p in Periods] Cost[p]

Max load pricing

Billing periods partition the periods.

input BillingPeriods is finite abstract set
input BillingPeriods[Periods] in BillingPeriods
local PeriodsOf[b in BillingPeriods] :=
  { p in Periods | BillingPeriods[p] = b }
local NumPeriodsOf[b in BillingPeriods] := card PeriodsOf[b]

Contiguity of periods within a meta-period is not relevant for modelling.

Extra penalizing objective term derived from the maximal grid load during a meta-period.

input MaxGridLoadPrice in [0, inf[ <Price>
input MaxAllowedGridLoad in [0, inf[ <Power>

Naive:

decision MaxGridLoad[BillingPeriods] := max[b in PeriodsOf[b]] abs(GridLoad[p])

Costs and objective

decision MaxGridLoadCost[b in BillingPeriods] := 
  MaxGridLoad * NumPeriodsOf[b] * PeriodLength * MaxGridLoadPrice

minimize sum[p in Periods] Cost[p] + sum[b in BillingPeriods] MaxGridLoadCost[mp]

LP-reformulated:

decision MaxGridLoad[BillingPeriods] in [0 <ElectricPower>, MaxAllowedGridLoad]

constraint _[b in BillingPeriods][p in PeriodsOf[b]] is
  MaxGridLoad[b] >= GridLoad[p]

constraint _[b in BillingPeriods][p in PeriodsOf[b]] is
  MaxGridLoad[b] >= - GridLoad[p]

Other extensions

Charge and discharge limits and exlusivity:

decision BatteryMode[Periods] in {0, 1}

constraint _[p in Periods] is 
  BatteryCharge[p] <= BatteryMode[p] * BatteryMaxCharge
constraint _[p in Periods] is 
  BatteryDischarge[p] <= (1 - BatteryMode[p]) * BatteryMaxDischarge