How Does a BESS Optimizer Decide What the Battery Should Do?

A practical introduction to BESS optimization, showing how an optimizer chooses when and how much to charge or discharge while respecting the battery’s physical and economic constraints.

The basic idea

We’ve now seen that battery arbitrage is more complicated than simply buying electricity when prices are low and selling when prices are high.

The battery has:

  • limited energy capacity
  • limited charging and discharging power
  • a changing state of charge
  • efficiency losses
  • a finite useful life
  • an economic cost associated with using that life

And electricity prices change over time.

So the battery needs to make a series of decisions:

When should I charge?

When should I discharge?

How much should I charge or discharge?

Should I preserve energy for a better opportunity later?

This is the problem that an optimizer is trying to solve.

1. Start with the decision

Take our: 100 MW / 200 MWh BESS

Suppose electricity is currently: $30/MWh

and is expected to reach: $100/MWh later.

The battery could charge now and discharge later.

But the optimizer can’t simply say:

“$30 is cheap. Charge.”

It needs to determine how much to charge.

It could choose:

  • 0 MW
  • 25 MW
  • 50 MW
  • 75 MW
  • 100 MW

depending on the model and operating constraints.

That is our first decision variable.

2. Decision variables

A decision variable is simply something the optimization model is allowed to choose.

For each hour, we might define:ChargetCharge_t

as the amount of power used to charge the battery, and:DischargetDischarge_t

as the amount of power used to discharge it.

For our battery:0Charget1000\leq Charge_t\leq100

and:0Discharget1000\leq Discharge_t\leq100

So the optimizer can choose the charging and discharging level, but it cannot exceed the battery’s 100 MW power limit.

Think of it like a tap:

The optimizer controls the tap, but the tap can only open as far as 100 MW.

3. But what is the optimizer trying to achieve?

We need to tell it what “good” means.

This is the objective function.

For a very simplified arbitrage problem, we might want to:

Maximize the value created by charging and discharging the battery.

One simplified formulation could be:Maximize t(PtsellDtPtbuyCt)\boxed{ \text{Maximize } \sum_t (P_t^{sell}D_t-P_t^{buy}C_t) }

where:

  • PtsellP_t^{sell} = electricity price when discharging
  • PtbuyP_t^{buy} = electricity price when charging
  • DtD_t = discharge amount
  • CtC_t = charge amount

The optimizer is effectively asking:

Which combination of charging and discharging decisions produces the highest value?

4. But we can’t let the optimizer do anything it wants

Suppose the optimizer discovers that it could make huge amounts of money by charging 500 MW at a cheap hour.

Our battery can’t do that.

It is only rated for:100 MW100\ MW

So we impose a constraint:Charget100Charge_t\leq100

Similarly:Discharget100Discharge_t\leq100

These are constraints.

They tell the optimizer:

You can choose the decision, but only within the physical limits of the battery.

5. Energy capacity is another constraint

The battery can only hold:200 MWh200\ MWh

So if the battery is already full, it can’t charge another 100 MWh.

We therefore need a constraint on stored energy:SOCt200 MWhSOC_t\leq200\ MWh

And it cannot have negative stored energy:SOCt0SOC_t\geq0

So:0SOCt200\boxed{0\leq SOC_t\leq200}

Now the optimizer understands that the battery has a finite tank.

6. SOC connects one hour to the next

This is where the problem becomes genuinely interesting.

Suppose the battery starts with:100 MWh100\ MWh

and discharges:50 MWh50\ MWh

during one hour.

Its stored energy falls to:10050=50 MWh100-50=50\ MWh

So the next hour doesn’t start with 100 MWh.

It starts with:50 MWh50\ MWh

In other words:SOCt+1SOC_{t+1}

depends on what happened at:SOCtSOC_t

A simplified equation is:SOCt+1=SOCt+ChargetDischargetSOC_{t+1} = SOC_t + Charge_t – Discharge_t

We’ll eventually modify this to include charging and discharging efficiency.

The important point is:

Today’s decision changes tomorrow’s available options.

7. Now the optimization problem starts looking different

Imagine these prices:

HourPrice
01:00$25
02:00$20
03:00$25
04:00$40
17:00$100
18:00$140
19:00$160
20:00$120

The optimizer isn’t simply looking for:

minimum price = $20

and:

maximum price = $160.

It has to work out:

  • how much to charge at $20
  • whether to charge at $25
  • whether there is enough capacity
  • how much energy to preserve
  • when to discharge
  • how much power to use
  • whether using energy at $140 is better than waiting for $160

Every decision affects the next one.

8. This is why we need an objective function

Imagine two possible strategies.

Strategy A

Charge aggressively at cheap prices and discharge whenever prices rise.

Strategy B

Preserve some energy for the highest-value hours.

Neither strategy is automatically correct.

The optimizer needs to compare the total value generated across the whole period.

That’s why the objective function matters.

It isn’t asking:

“What’s the best decision right now?”

It’s asking:

“What sequence of decisions produces the best overall outcome?”

That is the key conceptual jump from simple arbitrage to optimization.

9. Add efficiency

Now bring in what we learned in Round-trip Efficiency.

If the battery has losses, then charging 100 MWh doesn’t necessarily increase stored energy by 100 MWh.

A more realistic SOC relationship might look like:SOCt+1=SOCt+ηcCtDtηdSOC_{t+1} = SOC_t + \eta_c C_t – \frac{D_t}{\eta_d}

where:

  • ηc\eta_c = charging efficiency
  • ηd\eta_d = discharging efficiency
  • CtC_t = charging power
  • DtD_t = discharging power

Now the optimizer has to account for energy losses as it makes its decisions.

10. And then degradation

We can also introduce the idea from Section 4.

If using the battery has an economic cost, the objective isn’t simply:RevenueEnergy CostRevenue-Energy\ Cost

It becomes something closer to:RevenueEnergy CostBattery Use Cost\boxed{ Revenue – Energy\ Cost – Battery\ Use\ Cost }

Now the optimizer has another trade-off.

A particular discharge may generate revenue, but it also consumes some of the battery’s finite useful life.

So the optimizer needs to consider whether that additional revenue is worth the additional battery use.

11. We now have the basic architecture

At this point, we can describe the optimization problem using three fundamental components.

Objective function

What are we trying to maximize or minimize?

For example:

Maximize net value from operating the battery.

Decision variables

What can the optimizer choose?

For example:

Charge MW and discharge MW in each hour.

Constraints

What is the optimizer not allowed to violate?

For example:

Maximum power, energy capacity, SOC limits and operating requirements.

This gives us:Objective+Decision Variables+Constraints\boxed{ \text{Objective} + \text{Decision Variables} + \text{Constraints} }

That is the basic structure underneath a BESS optimization model.

The mental model

We started with a physical battery: 100 MW / 200 MWh

Then added:

  • SOC → how much energy is available
  • Efficiency → how much energy is lost
  • Degradation → what battery use costs
  • Prices → where economic opportunities exist

Now the optimizer sits on top of all of that.

It asks:

Given the prices, the battery’s current state, its physical limits and the economics of using it, what should the battery do at each point in time?

That’s the core of BESS dispatch optimization.

And now we can make the next step more concrete.

Next question

Can we actually solve this ourselves with a 24-hour price curve?

That’s where we can take our 100 MW / 200 MWh battery and manually build a 24-hour dispatch schedule, before introducing linear programming or an optimization solver.

Leave a Reply

Your email address will not be published. Required fields are marked *