3

Given inputs such as electricity consumption, generation from solar panel, price, (All at a given time t), we have a battery, and we want to evaluate how much it should (dis)/charge at any given time. The Problem can be formulated as follows:

Pt = price of electricity at time t

Lt = consumption of electricity at time t

Zt = charge of battery at time t (how much is in the battery)

St = Electricity generated from solar generator at time t

Qt = amount the battery (dis)/charges at time t

the function we are trying to optimise is Ct = Pt *(Lt - St - Qt)

This aims to minimise the amount of electricity purchased

With the following constraints:

Lt - St - Qt >= 0 (our demand has to be non-negative)

Qmin <= Qt <= Qmax ( the battery can only (dis)/charge between certain values at any given time)

Zmin <= Zt <= Zmax. (the battery has to be within its capacity, i.e. you can't discharge more than the battery holders, and you can charge more than the battery can hold)

Zt+1 = Zt + Qt+1 ( this means that the battery level at the next time step is equal to the battery level at the previous time step plus the amount that was (dis)/charged from the battery)

The problem I am having how to formulate in python (Scipy) the problem, particularly updating the battery levels.

I know other library's (Pyomo, Pulp) exist, solutions in that would be welcome.

usman Farooq
  • 151
  • 1
  • 12
  • You've done an excellent job of describing your problem. What have you tried to solve it and what problems are you running into? – kabdulla Jul 10 '19 at 21:14
  • Well I can save this problem using reinforcement learning, but the issue with that is, in a practical sense, related to security and proof of decision making. I am attempting to do this using a linear approach, using Scipy/pyomo/pulp. I know that people have used fmincon function from MATLAB, and used the Pyomo library from literature, but I am unsure how to actually formulate the problem so it fits into that formulation. the real issue is the battery update, because its dependent on the previous 'tilmestep'/variable – usman Farooq Jul 11 '19 at 07:51
  • I dont see the problem. Are you familiar with Lps? Linking your variables, "your problem", is natural when there is a linear dependency. The constraint looks exactl like presented. What did you try? Your function presented also allows to sell energy foe the same price to buy it seems. Not sure if you want that. – sascha Jul 11 '19 at 17:30
  • I am unsure/unable to reformulate the problem to be utilised in python. The constraints in LP require inequalities or equal to zero. The problem here is how write in LP form – usman Farooq Jul 14 '19 at 16:09

2 Answers2

4

You're in luck, I was motivated by Giorgio's answer to learn pyomo (I mostly user PULP), so used your question as a chance to make sure I understood all the interfaces. I'll post it here so I can find it again myself in the future:

import pyomo.environ as pyomo
import numpy as np

# create model
m = pyomo.ConcreteModel()

# Problem DATA
T = 24

Zmin = 0.0
Zmax = 2.0

Qmin = -1.0
Qmax = 1.0

# Generate prices, solar output and load signals
np.random.seed(42)
P = np.random.rand(T)*5.0
S = np.random.rand(T)
L = np.random.rand(T)*2.0

# Indexes
times = range(T)
times_plus_1 = range(T+1)

# Decisions variables
m.Q = pyomo.Var(times, domain=pyomo.Reals)
m.Z = pyomo.Var(times_plus_1, domain=pyomo.NonNegativeReals)

# objective
cost = sum(P[t]*(L[t] - S[t] - m.Q[t]) for t in times)
m.cost = pyomo.Objective(expr = cost, sense=pyomo.minimize)

# constraints
m.cons = pyomo.ConstraintList()
m.cons.add(m.Z[0] == 0.5*(Zmin + Zmax))

for t in times:
    m.cons.add(pyomo.inequality(Qmin, m.Q[t], Qmax))
    m.cons.add(pyomo.inequality(Zmin, m.Z[t], Zmax))
    m.cons.add(m.Z[t+1] == m.Z[t] - m.Q[t])
    m.cons.add(L[t] - S[t] - m.Q[t] >= 0)

# solve
solver = pyomo.SolverFactory('cbc')
solver.solve(m)

# display results
print("Total cost =", m.cost(), ".")

for v in m.component_objects(pyomo.Var, active=True):
    print ("Variable component object",v)
    print ("Type of component object: ", str(type(v))[1:-1]) # Stripping <> for nbconvert
    varobject = getattr(m, str(v))
    print ("Type of object accessed via getattr: ", str(type(varobject))[1:-1])

    for index in varobject:
        print ("   ", index, varobject[index].value)
kabdulla
  • 5,199
  • 3
  • 17
  • 30
  • There is an interesting situation here. The variable S cannot be a multiple (like you have multiplied L by 2). an error arises , could not initialize value Q[0]. Do you think this is linked to the solver being used? It seems that it is unable to find some optimal point and thus solution? – usman Farooq Jul 16 '19 at 08:33
  • Yes, that seems to be the message it gives when the problem is infeasible. By increasing the amount of solar generation, and maintaining the `m.cons.add(L[t] - S[t] - m.Q[t] >= 0)` constaint (i.e. no exports/selling of energy to grid), it seems that you would need a larger battery to make the problem feasible. It's irritating that a more descriptive error message is not given - anyone else know if this is normal for pyomo models? – kabdulla Jul 16 '19 at 18:52
  • 1
    So the best way to overcome is to allow the selling of excess electricity back to the grid. This was the next step in model complexity that I wanted to try, but I thought I'd start with the most basic case. – usman Farooq Jul 17 '19 at 21:23
3

In my experience (linear / MIP) optimization is a valid approach for this kind of applications. In my opinion (opinion, yeah), Pyomo is a great tool:

  • it's written in Python
  • the overall design is great
  • it has most common features from other modeling languages (AMPL, GAMS...)
  • it has simple interfaces for most solvers
  • it's very well maintained (check the Github page)

The documentation is quite extensive and is hosted here: https://pyomo.readthedocs.io/en/latest/index.html

You can find some more material here: https://pyomo.readthedocs.io/en/latest/tutorial_examples.html

Also, this is a link to a quite extensive introduction to Pyomo, which goes down to quite advanced topics such as stochastic optimization and bi-level problems.

Finally, the only specific issue to your case is the fact that you probably want to apply losses to charging and discharging the battery. As a heads up, it's probably a good idea to define two independent variables for charging and discharging (both of them being non-negative), so that you can write the energy balance of the battery as a constraint linking the State of Energy (SOE) at time t with the SOE at time t+1.

Good luck!