Energy storage trade-offs#

We consider the use of a storage device (say, a battery) to reduce the total cost of electricity consumed over one day. We divide the day into \(T\) time periods, and let \(p_t\) denote the (positive, time-varying) electricity price, and \(u_t\) denote the (nonnegative) usage or consumption, in period \(t\), for \(t = 1,\ldots, T\). Without the use of a battery, the total cost is \(p^Tu\). Let \(q_t\) denote the (nonnegative) energy stored in the battery in period \(t\). For simplicity, we neglect energy loss (although this is easily handled as well), so we have \(q_{t+1} = q_t + c_t\), \(t = 1, \ldots, T − 1\), where \(c_t\) is the charging of the battery in period \(t\); \(c_t < 0\) means the battery is discharged. We will require that \(q_1 = q_T + c_T\), i.e., we finish with the same battery charge that we start with. With the battery operating, the net consumption in period \(t\) is \(u_t + c_t\) ; we require this to be nonnegative (i.e., we do not pump power back into the grid). The total cost is then \(p^T(u + c)\). The battery is characterized by three parameters: The capacity \(Q\), where \(q_t \leq Q\); the maximum charge rate \(C\), where \(c_t \leq C\); and the maximum discharge rate \(D\), where \(c_t \geq −D\). (The parameters \(Q\), \(C\), and \(D\) are nonnegative.)

(a)#

Explain how to find the charging profile \(c \in \mathbf{R}^T\) (and associated stored energy profile \(q \in \mathbf{R}^T\)) that minimizes the total cost, subject to the constraints.

(b)#

Solve the problem instance with data \(p\) and \(u\), \(Q = 35\), and \(C = D = 3\). Plot \(u_t\), \(p_t\), \(c_t\), and \(q_t\) versus \(t\).

# Here we plot the demands u and prices p.
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(1)
T = 96
t = np.linspace(1, T, num=T).reshape(T)
p = np.exp(-np.cos((t - 15) * 2 * np.pi / T) + 0.01 * np.random.randn(T))
u = 2 * np.exp(
    -0.6 * np.cos((t + 40) * np.pi / T)
    - 0.7 * np.cos(t * 4 * np.pi / T)
    + 0.01 * np.random.randn(T)
)
p = p
u = u
plt.figure(1)
plt.plot(t / 4, p, "g", label=r"$p$")
plt.plot(t / 4, u, "r", label=r"$u$")
plt.ylabel("$")
plt.xlabel("t")
plt.legend()
plt.show()
# Solve for the minimum total cost.
import cvxpy as cp

Q = 35
C, D = 5, 5
q = cp.Variable(T)
c = cp.Variable(T)
# TODO: your code here
# Plot the optimal u and q against c and p.
plt.figure(2)
ts = np.linspace(1, T, num=T) / 4
plt.subplot(3, 1, 1)
plt.plot(ts, u, "r")
plt.plot(ts, c.value, "b")
plt.xlabel("t")
plt.ylabel("uc")
plt.legend(["u", "c"])
plt.subplot(3, 1, 2)
plt.plot(ts, p, "b")
plt.xlabel("t")
plt.ylabel("pt")
plt.subplot(3, 1, 3)
plt.plot(ts, q.value, "b")
plt.xlabel("t")
plt.ylabel("qt")
plt.ylim((0, 40))

(c) Storage trade-offs#

Plot the minimum total cost versus the storage capacity \(Q\), using \(p\) and \(u\) below, and charge/discharge limits \(C = D = 3\). Repeat for charge/discharge limits \(C = D = 1\). (Put these two trade-off curves on the same plot.) Give an interpretation of the endpoints of the trade-off curves.

# Plot the tradeoff curves
N = 31
Qs = np.linspace(0, 150, num=N)

q = cp.Variable(T)
c = cp.Variable(T)
Q = cp.Parameter()
C, D = cp.Parameter(), cp.Parameter()
# TODO: your code here


C.value = 1
D.value = 1
cost1 = np.zeros(N)

for i in range(N):
    Q.value = Qs[i]
    cost1[i] = prob.solve()

C.value = 3
D.value = 3
cost2 = np.zeros(N)
for i in range(N):
    Q.value = Qs[i]
    cost2[i] = prob.solve()

plt.figure(3)
plt.plot(Qs, cost2, "g--", label="C = D = 3")
plt.plot(Qs, cost1, "b.-", label="C = D = 1")
plt.xlabel("Q")
plt.ylabel("cost")
plt.legend()
plt.show()