@ElectricalDocument Mathematical Programming for Power Systems O
@ElectricalDocument Mathematical Programming for Power Systems O
Telegram: @ElectricalDocument
Telegram: @ElectricalDocument
Mathematical Programming for Power
Systems Operation
Alejandro Garcés
Technological University of Pereira
Pereira, Colombia
Telegram: @ElectricalDocument
This edition first published 2022
© 2022 by The Institute of Electrical and Electronics Engineers, Inc. All rights reserved.
No part of this publication may be reproduced, stored in a retrieval system, or transmitted in any
form or by any means, electronic, mechanical, photocopying, recording, scanning, or otherwise,
except as permitted under Section 107 or 108 of the 1976 United States Copyright Act, without
either the prior written permission of the Publisher, or authorization through payment of the
appropriate per-copy fee to the Copyright Clearance Center, Inc., 222 Rosewood Drive, Danvers,
MA 01923, (978) 750-8400, fax (978) 750-4470, or on the web at www.copyright.com. Requests to
the Publisher for permission should be addressed to the Permissions Department, John Wiley &
Sons, Inc., 111 River Street, Hoboken, NJ 07030, (201) 748-6011, fax (201) 748-6008, or online at
http://www.wiley.com/go/permission.
Limit of Liability/Disclaimer of Warranty: While the publisher and author have used their best
efforts in preparing this book, they make no representations or warranties with respect to the
accuracy or completeness of the contents of this book and specifically disclaim any implied
warranties of merchantability or fitness for a particular purpose. No warranty may be created or
extended by sales representatives or written sales materials. The advice and strategies contained
herein may not be suitable for your situation. You should consult with a professional where
appropriate. Neither the publisher nor author shall be liable for any loss of profit or any other
commercial damages, including but not limited to special, incidental, consequential, or other
damages.
For general information on our other products and services or for technical support, please contact
our Customer Care Department within the United States at (800) 762-2974, outside the United
States at (317) 572-3993 or fax (317) 572-4002.
Wiley also publishes its books in a variety of electronic formats. Some content that appears in print
may not be available in electronic formats. For more information about Wiley products, visit our
web site at www.wiley.com.
Set in 9.5/12.5pt STIXTwoText by Integra Software Services Pvt. Ltd, Pondicherry, India
10 9 8 7 6 5 4 3 2 1
Telegram: @ElectricalDocument
v
Contents
Acknowledgment ix
Introduction xi
Telegram: @ElectricalDocument
vi Contents
3 Convex optimization 39
3.1 Convex sets 39
3.2 Convex functions 45
3.3 Convex optimization problems 47
3.4 Global optimum and uniqueness of the solution 50
3.5 Duality 52
3.6 Further readings 56
3.7 Exercises 58
5 Conic optimization 85
5.1 Convex cones 85
5.2 Second-order cone optimization 85
5.2.1 Duality in SOC problems 90
5.3 Semidefinite programming 92
5.3.1 Trace, determinant, and the Shur complement 92
5.3.2 Cone of semidefinite matrices 95
5.3.3 Duality in SDP 97
5.4 Semidefinite approximations 98
5.5 Polynomial optimization 102
5.6 Further readings 105
5.7 Exercises 106
Telegram: @ElectricalDocument
Contents vii
Telegram: @ElectricalDocument
viii Contents
Bibliography 271
Index 281
Telegram: @ElectricalDocument
ix
Acknowledgment
Throughout the writing of this book, I have received a great deal of support and
assistance from many people. I would first like to thank my friends Lucas Paul
Perez at Welltec, Adrian Correa at Universidad Javeriana in Bogotá-Colombia,
Ricardo Andres Bolaños at XM (the transmission system operator in Colom-
bia), Raymundo Torres at Sintef-Norway, and Juan Carlos Bedoya at the Pacific
Northwest National Laboratory (USA), who, in 2020 (during the COVID-19
pandemic), agreed to discuss some practical aspects associated to power sys-
tem operation problems. The discussions during these video conferences were
invaluable to improve the content of the book. I am also very grateful to my
students, who are the primary motivation for writing this book. Special thanks
to my former Ph.D. students, Danilo Montoya and Walter Julian Gil. Finally, I
want to thank the Department of Electric Power Engineering at the Universi-
dad Tecnológica de Pereira in Colombia and the Von Humbolt Foundation in
Germany for the financial support required to continue my research about the
operation and control of power systems.
Alejandro Garcés
Telegram: @ElectricalDocument
Telegram: @ElectricalDocument
xi
Introduction
min 𝑓(𝑥)
subject to 𝑥 ∈ Ω (0.1)
Telegram: @ElectricalDocument
xii Introduction
This book will focus on stages two and three, associated with power system
operations models. In particular, we are interested in models with a geometric
characteristic called convexity, that present several advantages, namely:
● We can guarantee the global optimum and unique solution under well-
defined conditions. This aspect is interesting from both theoretical and prac-
tical points of view. In general, a global optimum advisable in real operation
problems.
● There are efficient algorithms for solving convex problems. In addition, we
can guarantee convergence of these algorithms. This is a critical aspect for
operation problems where the algorithm requires to be solved in real-time.
● There are commercial and open-source packages for solving convex opti-
mization models. In particular, we are going to use CvxPy, a free Python-
embedded modeling language for convex problems.
● Many power system operations problems are already convex; for example,
the economic and environmental dispatches, the hydrothermal coordination,
and the load estimation problem. Besides, it is possible to find efficient convex
approximations to non-convex problems such as the optimal power flow.
Telegram: @ElectricalDocument
Introduction xiii
Telegram: @ElectricalDocument
Telegram: @ElectricalDocument
1
Learning outcomes
Telegram: @ElectricalDocument
1.2 Continuous models 3
𝑝min ≤ 𝑝𝑖 ≤ 𝑝max
where 𝑝𝑖 is the power generated by each thermal unit, and 𝑑 is the total
demand. Environmental dispatch introduces quadratic or exponential func-
tions in the objective function, but the problem’s structure is the same.
Moreover, power flow constraints can be introduced into the model, although,
in that case, it is more precise to name the problem as an optimal power flow
(OPF). Chapter 7 presents the economic and environmental dispatches, while
Chapter 10 presents the OPF problem.
Another problem closely related to the economic dispatch of thermal units
is the unit commitment. This problem considers not only the operating
costs but also the start-up and shut-down costs of thermal units. There-
fore, the problem becomes binary and dynamic. This problem is studied in
Chapter 8.
Telegram: @ElectricalDocument
4 1 Power systems operation
Telegram: @ElectricalDocument
1.2 Continuous models 5
Figure 1.3 Economic dispatch by areas considering network constraints with the
transport model.
Telegram: @ElectricalDocument
6 1 Power systems operation
where 𝑠𝑘 = 𝑝𝑘 +𝑞𝑘 represents the active and reactive power in node 𝑘; 𝒩 repre-
sents the set of nodes of the grid; 𝑦𝑘𝑚 is the entry 𝑘𝑚 of the 𝑌bus matrix; 𝑣𝑘 and
𝑣𝑘 are the voltages at nodes 𝑘 and 𝑚, respectively, both represented as complex
variables; and 𝑠𝑘∗ and 𝑣𝑘∗ are the complex conjugate of the respective variables.
This representation on the complex number can be splitted into real and imag-
inary parts. However, as presented in Chapter 10, a complex representation is
suitable both for modeling and implementation purposes.
These constraints can be introduced into the economic dispatch, as well as
in an optimization model that minimizes total power loss (𝑝loss ). In both cases,
we named the problem as OPF. The basic model has the following structure:
This problem is highly complex due to the non-linear and non-convex nature
of the power flow equations. Therefore, it is required to review different
approximations that simplify the model. Chapter 10 presents three of these
approximations. These are linearization, second-order cone approximation,
and semidefinite programming approximation.
Linearization is, perhaps, the most straightforward way to solve the prob-
lem. Although the concept of linearization is well-known in real numbers, in
this case, we do a linearization on the complex domain. This linearization uses
Wirtinger’s calculus since Equation (1.3) is non-holomorphic (i.e., it does not
have a derivative in the complex numbers). Chapter 10 and Appendix B study
this aspect in detail.
We also solve the optimal power flow using second-order cone and semidef-
inite programming. These approximations demand a basic understanding of
conic optimization. Therefore, we present a general background of conic opti-
mization in Chapter 5, and its application to the optimal power flow problem
in Chapter 10, including a complete discussion about their advantages and
disadvantages.
An optimal power flow may optimize both power systems and power distri-
bution grids. However, the latter case presents some particularities that deserve
Telegram: @ElectricalDocument
1.2 Continuous models 7
an independent study. Moreover, both solar and wind energy require power
electronic converters connected at power distribution level. These converters
are capable of controlling reactive power, and therefore, it is possible to for-
mulate an OPF wherein the decision variables are the power factor of each
converter. The problem can be deterministic for real-time operation or stochas-
tic for the day ahead planning. In both cases, the model has, at least, the same
complexity as the basic OPF.
Telegram: @ElectricalDocument
8 1 Power systems operation
0 ≤ 𝑝𝑖𝑡 ≤ 𝑝̄ 𝑖𝑡
where 𝑝̄ 𝑖𝑡 is the power required by the load 𝑖 at time 𝑡; 𝑝𝑖𝑡 is the amount of
power that is reduced due to the demand-side management model; 𝑐𝑖𝑡 is the
cost of disconnecting one unit of power; and 𝑑𝑡 is the minimum demand. This
is only the basic optimization model, which can be modified, in order to include
more type of loads and other aspects of the operation of the system.
Some loads can be moved in time, for example, the washing machine in a resi-
dential user. These loads, known as shifting loads, can be optimized by defining
the load’s optimal starting time. This optimization model is binary but tractable
as presented in Chapter 13.
A demand-side management model can also include a model for tertiary con-
trol in microgrids or a model for charging electric vehicles. The latter is usually
called vehicle-to-grid or V2G. In these cases, the optimization model requires
to be executed in real-time by an aggregator as depicted in Figure 1.4.
An aggregator is a crucial component in modern smart distribution net-
works. This device receives information of the final users – in this case, the
electric vehicles – and gives the control actions in order to obtain a smart oper-
ation. However, the intelligent part of this system is not in the hardware but
in the optimization required to solve the problem efficiently and in real-time;
therein lies the importance of understanding the optimization model.
A V2G strategy can be unidirectional or bidirectional. In unidirectional V2G,
an aggregator controls the electric vehicles’ charge similarly as shifting loads.
Telegram: @ElectricalDocument
1.2 Continuous models 9
In bidirectional, the electric vehicle can inject power into the grid if required for
improving the operation. In any case, the model can become stochastic since
the state of charge of the vehicles can be unknown, and the aggregator does
not control the arrival/departing time of the vehicles1 . The aggregator can also
incorporate economic dispatch and OPF models to manage other distributed
resources such as local batteries, solar panels, and wind turbines. Chapter 11
examines these problems.
Telegram: @ElectricalDocument
10 1 Power systems operation
𝐼 = 𝑌𝑉 (1.6)
𝐼min ≤ 𝐼 ≤ 𝐼max
𝑉min ≤ 𝑉 ≤ 𝑉max
1 2
min 𝑓(𝑌) = ‖𝐼 − 𝑌𝑉‖𝐹 (1.7)
𝑌 2
The decision variable is the nodal admittance matrix 𝑌, and the objective
function is the norm of error between measurements and estimations2 .
The model can include information about the structure of the matrix 𝑌. For
example, we already know that the matrix is symmetric and, some of its entries
are zero. In that case, the optimization model is the following:
1
min 𝑓(𝑌) = ‖𝐼 − 𝑌𝑉‖𝐹
𝑌 2
𝑦𝑖𝑗 = 𝑦𝑗𝑖 , ∀𝑖, 𝑗 (1.8)
𝑦𝑖𝑗 = 0, if 𝑖 is not connected to𝑗
Telegram: @ElectricalDocument
1.3 Binary problems in power systems operation 11
Both AC and DC grids may handle this type of estimation. In this case, we
only presented the DC case because it is easier to develop. The entire model
must be implemented in an aggregator structure, as depicted in Figure 1.5.
Telegram: @ElectricalDocument
12 1 Power systems operation
for this task, although there are plenty of options available. Binary operation
problems include unit commitment and phase balancing in power distribution
networks.
Telegram: @ElectricalDocument
1.3 Binary problems in power systems operation 13
Telegram: @ElectricalDocument
14 1 Power systems operation
networks; for example, a microgrid with 10 nodes will have 6 × 107 possible
configurations.
Phase-balancing problems appear in many applications such as aircraft elec-
tric systems [4], and in power distribution grids with high penetration of
electric vehicles [5]. Due to its combinatorial nature, the problem necessitates
the use of heuristics [6], and meta-heuristics [7] as well as expert systems
[8]. Modern approaches include the uncertainty associated to the load and
generator [9].
min 𝑓(𝑥, 𝛼)
𝑥∈Ω (1.10)
Optimization Forecast
model module
State Power
estimation system
Telegram: @ElectricalDocument
1.5 Using Python 15
In many cases, the forecast has an error that introduces uncertainty in the
model. Either stochastic or robust optimization is a suitable option to face this
uncertainty. Chapter 6 presents the latter option.
min 𝑐⊤ 𝑥
∑
𝑥𝑖 = 1 (1.11)
𝑖
𝑥𝑖 ≥ 0
Without much effort, we can identify variables, the objective function, and con-
straints. This neat code feature is an essential aspect of Python and CvxPy.
After the problem is solved, we can make additional analyses using the same
platform. This combination of tools is, of course, a great advantage; however,
we must avoid any fanaticism for software. There are many programming
Telegram: @ElectricalDocument
16 1 Power systems operation
Telegram: @ElectricalDocument
17
Part I
Mathematical programming
Telegram: @ElectricalDocument
Telegram: @ElectricalDocument
19
Learning outcomes
max
min
Notice that 𝑓min and 𝑓max are numbers whereas 𝑥min and 𝑥max are vectors. The
following example shows the difference between min and argmin (the same
applies for max and argmax).
Example 2.1. Let us consider four simple optimization problems and their
respective solution, namely1 :
min(𝑥 − 5)2 = 0, argmin(𝑥 − 5)2 = 5 (2.3)
min(𝑥 − 5)2 = 25, argmin(𝑥 − 5)2 = 10 (2.4)
𝑥≥10 𝑥≥10
1 At this point, the only tool we have to check these results is plotting the function and locating
the optimum.
Telegram: @ElectricalDocument
2.1 About sets and functions 21
the active power losses belongs to the real numbers; however, the input may be
represented as a vector (𝑣, 𝜃) ∈ ℝ2×𝑛 or as a set of phasors (𝑣𝑒𝑗𝜃 ∈ ℂ𝑛 ). The
former is an ordered set, whereas the latter is non-ordered. Other possible rep-
resentations can be the set of positive definite matrices or positive polynomials,
as presented in Chapter 10. In conclusion, the objective function must point to
an ordered set, but the input set (i.e., the set of feasible solutions) can be any
arbitrary set.
We usually compare values in the output set since our objective is to mini-
mize or maximize the objective function. It is also possible to compare values
in Ω when it is an ordered set. However, a comparison between elements of the
input set may be different in the output set. A function 𝑓 is monotone (or mono-
tonic) increasing, if 𝑥 ≤ 𝑦 implies that 𝑓(𝑥) ≤ 𝑓(𝑦), that is to say, the function
preserves the inequality. Similarly, a function is monotone decreasing if 𝑥 ≤ 𝑦
implies that 𝑓(𝑥) ≥ 𝑓(𝑦), that is to say, the function reverses the identity.
Example 2.2. The function 𝑓(𝑥) = 𝑥2 is not monotone; for example −3 ≤ 1
but 𝑓(−3) ≰ 𝑓(1). Nevertheless, the function is monotone increasing in ℝ+ . In
this set, 4 ≤ 8 implies that 𝑓(4) ≤ 𝑓(8) since both 4 and 8 belong to ℝ+ .
An ordered set Ω ∈ ℝ𝑛 admits the following definitions:
The supreme and the infimum are closely related to the maximum and the
minimum of a set. They are equal in most practical applications. The main
difference is that the infimum and the supreme can be outside the set. For
example, the supreme of the set Ω = {𝑥 ∶ 3 ≤ 𝑥 < 5} is 5 whereas its maximum
does not exists. It may seem like a simple difference, but several theoretical
analyzes require this differentiation.
Some properties of the supreme and the infimum are presented below:
Telegram: @ElectricalDocument
22 2 A brief introduction to mathematical optimization
That is to say, the value of 𝑥 that minimizes the function 𝑓(𝑥) + 𝛼 is the same
value that minimizes 𝑓(𝑥); for this reason, it is typical to neglect the constant
𝛼 in practical problems.
Example 2.3. Table 2.1 shows some examples of maximum, minimum,
supreme, and infimum.
Ω1 = {1, 2, 3, 4} 4 4 1 1
Ω2 = {𝑥 ∈ ℝ ∶ 1 ≤ 𝑥 ≤ 2} 2 2 1 1
Ω3 = {𝑥 ∈ ℝ ∶ 3 < 𝑥 ≤ 8} 8 8 3 -
Ω4 = {𝑥 ∈ ℝ ∶ 2 ≤ 𝑥 < 9} 9 - 2 2
Ω5 = {𝑥 ∈ ℝ ∶ 4 < 𝑥 < 7} 7 - 4 -
2.2 Norms
In many practical problems, we may be interested in measuring the objects
in a set, either as an objective function or as a way of analyzing solutions. A
norm is a geometric concept that allows us to make this measurement. The
most common norm is the Euclidean distance given by Equation (2.12)
√
‖𝑥‖ = 𝑥12 + 𝑥22 + … 𝑥𝑛2 (2.12)
However, this function is not the only way to measure a distance. In general,
we can define a norm as a function ‖⋅‖ ∶ Ω → ℝ that fulfills the following
conditions:
{ }
‖𝑥‖ > 0 ∀𝑥 ∈ Ω − 0⃗ (2.13)
‖𝑥‖ = 0 → 𝑥 = 0⃗ (2.14)
‖𝛼𝑥‖ = |𝛼| ‖𝑥‖ (2.15)
‖𝑥 + 𝑦‖ ≤ ‖𝑥‖ + ‖𝑦‖ (2.16)
The first two conditions indicate that a norm must return a positive value,
except when the input is the vector 0⃗. The third condition indicates that it is
scalable; for example, the norm must be twice the original vector’s norm if we
multiply all the vector entries by 2. The last condition, known as the triangle
inequality, is a generalization of the triangles’ property (therein lies its name).
Telegram: @ElectricalDocument
2.2 Norms 23
The sum of any two sides’ lengths is greater (or equal) to the remaining side’s
length. This property is intuitive for the Euclidean norm, but surprisingly it is
general for many other functions, such as Equation (2.17):
1∕𝑝
∑
‖𝑥‖𝑝 = ( 𝑝
|𝑥𝑖 | ) (2.17)
𝑖
ℬ = {𝑥 ∈ ℝ𝑛 ∶ ‖𝑥‖ ≤ 𝑟} (2.21)
This set is known as a ball of radius 𝑟. Figure 2.3 shows the shape of unit balls
(i.e., balls of radius 1), generated by each of the three previously mentioned
norms.
Figure 2.2 Three ways to measure the vector 𝑣 = (3, 2) in ℝ2 : a) 2-norm or Euclidean
norm, b) 1-norm or Manhattan distance, c) infinity-norm or uniform norm.
Telegram: @ElectricalDocument
24 2 A brief introduction to mathematical optimization
Figure 2.3 Comparison among unit balls defined by norm-2, norm-1, and norm-∞.
Notice that a ball is not necessarily round, at least with this definition. All
balls share a common geometric property known as convexity that is studied in
Chapter 3.
Telegram: @ElectricalDocument
2.4 Maximum and minimum values of continuous functions 25
Figure 2.4 Example of local and global optima: a) function with two local minima
and their respective neighborhoods, b) function with a unique global minimum (the
neighborhood is the entire domain of the function).
𝑓(𝑥̃ ± 𝑡) ≥ 𝑓(𝑥)
̃ (2.23)
where 𝑡 can be positive or negative. If 𝑡 > 0, then Equation (2.23) can be divided
by 𝑡 without modifying the direction of the inequality, to then take the limit
Telegram: @ElectricalDocument
26 2 A brief introduction to mathematical optimization
Telegram: @ElectricalDocument
2.5 The gradient method 27
encompass power systems operation and machine learning. Let us consider the
following unconstrained optimization problem:
𝑥 ← 𝑥 − 𝑡∇𝑓(𝑥) (2.30)
The gradient method consists in applying this iteration until the gradient is
small enough, i.e., until ‖∇𝑓(𝑥)‖ ≤ 𝜖. It is easier to understand the algorithm
by considering concrete problems and their implementation in Python, as given
in the next examples.
Example 2.4. Consider the following optimization problem:
20𝑥 + exp (𝑥 + 𝑦)
∇𝑓(𝑥, 𝑦) = ( ) (2.32)
30𝑦 + exp (𝑥 + 𝑦)
We require to find a value (𝑥, 𝑦) such that this gradient is zero. Therefore, we
use the gradient method. The algorithm starts from an initial point (for example
𝑥 = 10, 𝑦 = 10) and calculate new points as follows:
𝜕𝑓
𝑥 ←𝑥−𝑡 (2.33)
𝜕𝑥
𝜕𝑓
𝑦 ←𝑦−𝑡 (2.34)
𝜕𝑦
This step can be implemented in a script in Python, as presented below:
import numpy as np
x = 10
y = 10
t = 0.03
for k in range(50):
dx = 20*x + np.exp(x+y)
dy = 30*y + np.exp(x+y)
x += -t*dx
y += -t*dy
print(’grad:’,np.abs([dx,dy]))
print(’argmin:’,x,y)
Telegram: @ElectricalDocument
28 2 A brief introduction to mathematical optimization
In the first line, we import the module NumPy with the alias np. This mod-
ule contains mathematical functions such as sin, cos, exp, ln among others.
The gradient introduces two components dx and dy, which are evaluated in
each iteration and added to the previous point (x,y). We repeat the process 50
times and print the value of the gradient each iteration. Notice that all the
indented statements belong to the for-statement, and hence the gradient is
printed in each iteration. In contrast, the argmin is printed only at the end of the
process.
Example 2.5. Python allows calculating the gradient automatically using the
module AutoGrad. It is quite intuitive to use. Consider the following script,
which solves the same problem presented in the previous example:
import autograd.numpy as np
from autograd import grad # gradient calculation
def f(x):
z = 10.0*x[0]**2 + 15*x[1]**2 + np.exp(x[0]+x[1])
return z
Example 2.6. Consider a small photovoltaic system formed by three solar pan-
els 𝐴, 𝐵, and 𝐶, placed as depicted in Figure 2.6. Each solar system has a power
electronic converter that requires to be connected to a common point 𝐸 before
transmitted to the final user in 𝐷. The converters and the user’s location are
fixed, but the common point 𝐸 can be moved at will. The coordinates of the
solar panels and the final user are 𝐴 = (0, 40), 𝐵 = (20, 70), 𝐶 = (30, 0), and
𝐷 = (100, 50), respectively.
The cost of the cables is different since each cable carries different current.
Our objective is to find the best position of 𝐸 in order to minimize the total cost
Telegram: @ElectricalDocument
2.5 The gradient method 29
where cost𝑖𝑗 is the unitary cost of the cable that connects the point 𝑖 and 𝑗, and
‖‖ ‖‖
‖‖𝑖𝑗 ‖‖ is the corresponding length.
‖ ‖
The costs of the cables are cost𝐴𝐸 = 12, cost𝐵𝐸 = 13, cost𝐶𝐸 = 11, and
cost𝐷𝐸 = 18. The distance between any two points 𝑈 = (𝑢0 , 𝑢1 ) and 𝑉 = (𝑣0 , 𝑣1 )
is given by the following expression:
√
dist = (𝑢0 − 𝑣0 )2 + (𝑢1 − 𝑣1 )2 (2.36)
import numpy as np
A = (0,40)
B = (20,70)
C = (30,0)
D = (100,50)
def dist(U,V):
return np.sqrt((U[0]-V[0])**2 + (U[1]-V[1])**2)
P = [31,45]
f = 12*dist(P,A) + 13*dist(P,B) + 11*dist(P,C) + 18*dist(P,D)
print(f)
Telegram: @ElectricalDocument
30 2 A brief introduction to mathematical optimization
The function is evaluated in a point 𝑃 = (10, 10) to see its usage2 . The value
of the objective function is easily calculated as function of dist(𝑈, 𝑉). Likewise,
the gradient of 𝑓 is defined as function of the gradient of dist(𝑈, 𝑉) with 𝑉 fixed,
as presented below:
1 𝑢 − 𝑣0
∇ dist(𝑈, 𝑉) = ( 0 ) (2.37)
dist(𝑈, 𝑉) 𝑢1 − 𝑣1
then,
def g_d(U,V):
"gradient of the distance"
return [U[0]-V[0],U[1]-V[1]]/dist(U,V)
def grad_f(E):
"gradient of the objective function"
return 12*g_d(E,A)+13*g_d(E,B)+11*g_d(E,C)+18*g_d(E,D)
t = 0.5
E = np.array([10,10])
for iter in range(50):
E = E -t*grad_f(E)
f = 12*dist(E,A) + 13*dist(E,B) + 11*dist(E,C) + 18*dist(E,D)
print("Position:",E)
print("Gradient",grad_f(E))
print("Cost",f)
In this case, 𝑡 = 0.5 and a initial point 𝐸 = (10, 10) with 50 iterations were
enough to find the solution. The reader is invited to try with other values and
analyze the effect on the algorithm’s convergence.
The step 𝑡 is very important for the convergence of the gradient method. It can
be constant or variable, according to a well-defined update rule. There are many
variants of this algorithm, most of them with sophisticated ways to calculate
this step3 . A plot of ‖∇𝑓‖ versus the number of iterations may be useful for
2 Notice 𝑃 is defined in a line outside the function definition. Recall that 𝑥 2 is represented as
x**2 in Python (see Appendix C)
3 A complete discussion about the calculation of 𝑡 is beyond this book’s objectives. Interested
readers can consult the work of Nesterov and Nemirovskii, in [11] and [12].
Telegram: @ElectricalDocument
2.5 The gradient method 31
determining the optimal value of 𝑡 and showing the convergence rate of the
algorithm, as presented in the next example. We expect a linear convergence
for the gradient method, although the algorithm can lead to oscillations and
even divergence if the parameter 𝑡 is not selected carefully. Fortunately, there
are modules in Python that make this work automatically.
Example 2.7. The convergence of the algorithm can be visualized by using the
module MatplotLib as follows:
The result of the script is shown in Figure 2.7. As expected, the convergence
rate is linear; that is to say, the convergence plot describes almost a line in
a semi-logarithmic scale. The value of 𝜖 can be used as convergence criteria
(a gradient ‖∇𝑓‖ ≤ 10−4 can be considered as the local optimum for this
problem).
Notice that addition was simplified by the statement +=. In general, an state-
ment such as x=x+1 is equivalent to x+=1. More details about this aspect are
presented in Appendix C.
Telegram: @ElectricalDocument
32 2 A brief introduction to mathematical optimization
min 𝑓(𝑥)
𝑔(𝑥) = 𝑎 (2.39)
This new function depends on the original decision variables 𝑥 and a new
variable 𝜆, known as Lagrange multiplier or dual variable. By means of the
lagrangian function, a constrained optimization problem was transformed
into an unconstrained optimization problem that can be solved numerically,
namely:
𝜕ℒ 𝜕𝑓 𝜕𝑔
= −𝜆 =0 (2.41)
𝜕𝑥 𝜕𝑥 𝜕𝑥
𝜕ℒ
= 𝑎 − 𝑔(𝑥) = 0 (2.42)
𝜕𝜆
by a small abuse of notation, 𝜕𝑓∕𝜕𝑥 is used instead of ∇𝑓, which is the formal
representation for the n-dimentional case, (the same for ℒ and 𝑔). Notice that
the optimal conditions of ℒ imply optimal solution in 𝑓 but also feasibility in
terms of the constraint.
The first condition implies that the gradient of the objective function must
be parallel to the gradient of the constraint and, the Lagrange multiplier is
the proportionality constant. Besides this geometrical interpretation, Lagrange
multipliers have another interesting interpretation. Suppose a local optimum
𝑥̃ is found for a constrained optimization problem, and we want to know the
sensibility of this optimum with respect to 𝑎. The following derivative can
be calculated, relating the change of the objective function with respect to a
change in the constrain:
𝜕ℒ 𝜕𝑓 𝜕𝑥 𝜕𝜆 𝜕𝑔 𝜕𝑥
= ( ) ( ) + ( ) (𝑎 − 𝑔(𝑥)) + 𝜆 (1 − )( ) (2.43)
𝜕𝑎 𝜕𝑥 𝜕𝑎 𝜕𝑎 𝜕𝑥 𝜕𝑎
𝜕𝑓 𝜕𝑔 𝜕𝑥 𝜕𝜆
=( − 𝜆 ) ( ) + (𝑎 − 𝑔(𝑥)) ( ) + 𝜆 (2.44)
𝜕𝑥 𝜕𝑥 𝜕𝑎 𝜕𝑎
=𝜆 (2.45)
Telegram: @ElectricalDocument
2.7 The Newton’s method 33
The first two terms in the right-hand side of the equation vanishes, in view of
̃ thus, the following expresion is obtained:
the optimal conditions of 𝑥;
𝜕ℒ
𝜆= (2.46)
𝜕𝑎
this means that 𝜆 is the variation of the lagrangian (and hence the objective
function), for a small variation on the parameter 𝑎 (see Chapter 3 for more
details about dual variables).
Example 2.8. Consider the following optimization problem
min 𝑥 2 + 𝑦 2
𝑥+𝑦 =1 (2.47)
2𝑥 − 𝜆 = 0 (2.49)
2𝑦 − 𝜆 = 0 (2.50)
1−𝑥−𝑦 =0 (2.51)
4 Again, a classic method that became more important with the advent of the computer.
Telegram: @ElectricalDocument
34 2 A brief introduction to mathematical optimization
⎧ 20𝑥 + exp(𝑥 + 𝑦) − 𝜆 = 0 ⎫
𝑆(𝑥, 𝑦, 𝜆) =30𝑦 + exp(𝑥 + 𝑦) − 𝜆 = 0 (2.57)
⎨ ⎬
5−𝑥−𝑦 =0
⎩ ⎭
The corresponding Jacobian is the following matrix:
⎛ 20 + exp(𝑥 + 𝑦) exp(𝑥 + 𝑦) −1 ⎞
𝒥=⎜ exp(𝑥 + 𝑦) 30 + exp(𝑥 + 𝑦) −1 ⎟ (2.58)
⎜ ⎟
−1 −1 0
⎝ ⎠
It is possible to formulate Newton’s method using the information described
above. The algorithm implemented in Python is presented below:
import numpy as np
def Fobj(x,y):
"Objective funcion"
return 10*x**2 + 15*y**2 + np.exp(x+y)
def Grad(x,y,z):
"Gradient of Lagrangian"
dx = 20*x + np.exp(x+y) + z
Telegram: @ElectricalDocument
2.9 Exercises 35
dy = 30*y + np.exp(x+y) + z
dz = x + y - 5
return np.array([dx,dy,dz])
def Jac(x,y,z):
"Jacobian of Grad"
p = np.exp(x+y)
return np.array([[20+p,p,1],[p,30+p,1],[1,1,0]])
2.9 Exercises
1. Find the highest and lowest point, of the set given by the intersection of the
cylinder 𝑥2 + 𝑦 2 ≤ 1 with the plane 𝑥 + 𝑦 + 𝑧 = 1, as shown in Figure 2.8.
Telegram: @ElectricalDocument
36 2 A brief introduction to mathematical optimization
2. What is the new value of 𝑧max and 𝑧min , if the cylinder increases its radius
in a small value, that is, if the radius changes from (𝑟 = 1) to (𝑟 = 1 + ∆𝑟)
(Consider the interpretation of the Lagrange multipliers).
3. The following algebraic equation gives the mechanical power in a wind
turbine:
1
𝑃 = 𝜌𝐴𝐶𝑝 (𝜆)𝑣 3 (2.59)
2
where 𝑃 is the power extracted from the wind; 𝜌 is the air density; 𝐶𝑝 is
the performance coefficient or power coefficient; 𝜆 is the tip speed ratio;
𝑣 is the wind velocity, and 𝐴 is the area covered by the rotor (see [15] for
details). Determine the value of 𝜆 that produce maximum efficiency if the
performance coefficient is given by Equation (2.60):
151 −18.4
𝐶𝑝 = 0.73 ( − 13.2) exp ( ) (2.60)
𝜆 𝜆
Use the gradient method, starting from 𝜆 = 10 and a step of 𝑡 = 0.1. Hint:
use the module SymPy to obtain the expression of the gradient.
4. Solve the following optimization problem using the gradient method:
Depart from the point (0, 0) and use a fixed step 𝑡 = 0.8. Repeat the problem
with a fixed step 𝑡 = 1.1. Show a plot of convergence.
5. Solve the following optimization problem using the gradient method.
1
min 𝑓(𝑥) = (𝑥 − 1𝑛 )⊤ 𝐻(𝑥 − 1𝑛 ) + 𝑏⊤ 𝑥 (2.62)
2
where 1𝑛 is a column vector of size 𝑛, with all entries equal to 1; 𝑏 is a
column vector such that 𝑏𝑘 = 𝑘𝑛2 ; and 𝐻 is a symmetric matrix of size
𝑛 × 𝑛 constructed in the following way: ℎ𝑘𝑚 = (𝑚 + 𝑘)∕2 if 𝑘 ≠ 𝑚 and
Telegram: @ElectricalDocument
2.9 Exercises 37
Telegram: @ElectricalDocument
Telegram: @ElectricalDocument
39
Convex optimization
Learning outcomes
Example 3.1. Equations and inequalities usually define sets. Let us consider,
for instance, the following three sets, related to the 2-norm:
{ }
Ω𝐴 = (𝑥, 𝑦) ∶ 𝑥 2 + 𝑦 2 ≤ 1 (3.1)
{ }
Ω𝐵 = (𝑥, 𝑦) ∶ 𝑥 2 + 𝑦 2 = 1 (3.2)
{ 2 2
}
Ω𝐶 = (𝑥, 𝑦) ∶ 𝑥 + 𝑦 ≥ 1 (3.3)
The set Ω𝐴 is convex since any pair of points 𝑚, 𝑛 generates a line whose points
belong to the set. The set Ω𝐵 is not convex since it is defined only in the ball’s
boundary, and hence, any line segment will have points outside the set. The set
Ω𝐶 is also non-convex since several points leave the set if we draw, for instance,
a line that passes the point (0, 0). Figure 3.2 shows a graphical representation
of each of these situations. Notice that we can be misled if we carelessly see the
equation.
Figure 3.2 Example of three different sets with a similar definition. Only the first set
is convex.
Telegram: @ElectricalDocument
3.1 Convex sets 41
(1 − 𝜆)𝑥 + 𝜆𝑦 ∈ Ω (3.4)
for any 𝜆 ∈ ℝ, 0 ≤ 𝜆 ≤ 1.
This definition allows determining if a set is convex in a general and system-
atic way. We only require to select two general points 𝑥 and 𝑦 that belong to the
set, and demonstrate that any point 𝑧 in the segment 𝑥𝑦 also belongs to the set
too. Let us perform this calculation algebraically, as presented in the following
example.
𝐴𝑥 = 𝑏 (3.5)
𝐴𝑦 = 𝑏 (3.6)
(1 − 𝜆)𝐴𝑥 + 𝜆𝐴𝑦 = (1 − 𝜆)𝑏 + 𝜆𝑏 (3.7)
𝐴𝑧 = 𝑏 (3.8)
The last equation implicates that 𝑧 ∈ Ω and hence, Ω is a convex set. Notice
that we do not select a particular point 𝑥 or 𝑦. Our demonstration was general
for any pair of points.
∩ (convex) ∪ (non-convex)
Telegram: @ElectricalDocument
42 3 Convex optimization
min 𝑓(𝑥)
𝑔(𝑥) ≤ 0 (3.9)
ℎ(𝑥) ≤ 0
where
{ }
Ω = Ω𝑔 ∩ Ω ℎ (3.11)
Ω𝑔 = {𝑥 ∈ ℝ𝑛 ∶ 𝑔(𝑥) ≤ 0} (3.12)
𝑛
Ωℎ = {𝑥 ∈ ℝ ∶ ℎ(𝑥) ≤ 0} (3.13)
𝒫 = {𝑥 ∈ ℝ𝑛 ∶ 𝐴𝑥 ≤ 𝑏} (3.14)
𝐴𝑥 ≤ 𝑏 (3.15)
𝐴𝑦 ≤ 𝑏 (3.16)
Telegram: @ElectricalDocument
3.1 Convex sets 43
Example 3.5. The following set forms a polytope, as depicted in Figure 3.4:
2𝑥 + 5𝑦 ≤ 10
2𝑦 − 2𝑥 ≤ 1
𝑥≥0 (3.19)
𝑦≥0
This is a convex set that is represented as Equation (3.14) with the following
parameters:
⎛ 2 5 ⎞
⎜ 2 −2 ⎟
𝐴=⎜ (3.20)
−1 0 ⎟
⎜ ⎟
0 −1
⎝ ⎠
and,
Example 3.6. A unit ball with center in zero is a set ℬ0 , defined as follows:
ℬ0 = {𝑥 ∈ ℝ𝑛 ∶ ‖𝑥‖ ≤ 1} (3.22)
‖𝑥‖ ≤ 1 (3.23)
‖𝑦‖ ≤ 1 (3.24)
Telegram: @ElectricalDocument
44 3 Convex optimization
where 𝐴 is a symmetric positive definite matrix (i.e., all its eigenvalues are
positive). A set of this form is equivalent to a unit ball, as follows:
{ }
ℬ = 𝑥 ∈ ℝ𝑛 ∶ ‖𝑥‖𝐴 ≤ 1 (3.29)
where ‖⋅‖ represents the 2-norm; 𝐴 is a square matrix; 𝑏 and 𝑐 are vectors
in ℝ𝑛 ; and 𝑑 is a scalar. Second-order cones play a crucial role in the convex
approximations for the optimal power flow, as presented in Chapter 10.
1 We used the properties of the norm, already explained in the previous chapter.
Telegram: @ElectricalDocument
3.2 Convex functions 45
a) b)
( 1) (
1 1 1)
( 2 2)
( 2 2)
There are three properties that are useful for defining and identifying convex
functions, especially in the general case of ℝ𝑛 .
2 This type of functions ensures uniqueness of the solution as will be presented in Section 3.4.
Telegram: @ElectricalDocument
46 3 Convex optimization
Property 1: The sum of two or more convex functions is also a convex func-
tion. However, the rest of convex functions is not necessarily
convex.
Property 2: The composition of a convex and an affine function is also a convex
function, e.g., 𝑓(𝐴𝑥 + 𝑏) is convex if 𝑓 is convex.
Property 3: The composition of a convex function with a convex non-
decreasing function is also a convex function (see Figure 3.7).
Let us demonstrate the third property (the reader is invited to demonstrate the
first two properties). Consider a convex function 𝑓 ∶ ℝ𝑛 → ℝ, then it fulfills
Jensen’s inequality:
Telegram: @ElectricalDocument
3.3 Convex optimization problems 47
Telegram: @ElectricalDocument
48 3 Convex optimization
A function is convex if and only if its epigraph is convex. This property is very
useful to identify convex sets and convex functions. For instance, the set Ω𝐴
in Example 3.1 is convex since the function 𝑓(𝑥, 𝑦) = 𝑥2 + 𝑦 2 is a convex
function.
min 𝑡
𝑓(𝑥) ≤ 𝑡 (3.45)
Recall that the intersection of convex sets is also a convex set. Equality con-
straints of the form 𝐴𝑥 = 𝑏 (affine) may complement the model. Hence,
the canonical representation of a convex optimization problem is presented
below:
min 𝑓(𝑥)
𝑔(𝑥) ≤ 0 (3.47)
𝐴𝑥 = 𝑏
where 𝑓 and 𝑔 are convex functions. It is important to notice that equality con-
straints must be affine and inequality constraints must be convex. A constraint
of the form 𝑓(𝑥) = 0 or 𝑓(𝑥) ≥ 0 does not define a convex set, even if 𝑓 is convex
(recall the case of Ω𝐵 and Ω𝐶 in Figure 3.2). Below we present some common
examples of convex optimization problems.
Telegram: @ElectricalDocument
3.3 Convex optimization problems 49
min 𝑐⊤ 𝑥
𝐴𝑥 = 𝑏 (3.48)
𝑥≥0
This type of problem is convex since affine functions are also convex. The fea-
sible set is a polytope and the optimum is usually a vertex. Several problems in
power systems operation can be represented a linear programming models, for
example, the economic dispatch and the demand-side management.
1 ⊤
min 𝑥 𝐻𝑥 + 𝑐⊤ 𝑥
2
𝐴𝑥 = 𝑏 (3.49)
𝑥≥0
This problem is convex if 𝐻 positive semidefinite. The feasible set is also a poly-
tope but the optimum could be inside the set, or in the boundary. The economic
dispatch of thermal units is a common example of quadratic programming
problems.
1 ⊤
min 𝑥 𝐻𝑥 + 𝑐⊤ 𝑥
2
𝐴𝑥 ≤ 𝑏 (3.50)
1 ⊤
𝑥 𝑀𝑥 + 𝑠⊤ 𝑥 ≤ 𝑡
2
This problem is convex if both 𝐻 and 𝑀 are positive semidefinite. It is very
important to emphasize in direction of the sign ≤ in Equation (3.50). Notice
that the following constraints are not convex even if 𝑀 is semidefinite:
1 ⊤
𝑥 𝑀𝑥 + 𝑠⊤ 𝑥 = 𝑡 (3.51)
2
1 ⊤
𝑥 𝑀𝑥 + 𝑠⊤ 𝑥 ≥ 𝑡 (3.52)
2
Telegram: @ElectricalDocument
50 3 Convex optimization
𝐴𝑥 ≤ 𝑏 (3.53)
̃ = inf {𝑓(𝑥) ∶ 𝑥 ∈ 𝒩}
𝑓(𝑥) (3.54)
𝒩 = {𝑥 ∈ Ω, ‖𝑥 − 𝑥‖
̃ < 𝑟} (3.55)
𝑥 = 𝛼𝑥̃ + 𝛽𝑦 (3.56)
̃ + 𝛽𝑓(𝑦)
𝑓(𝑥) ≤ 𝛼𝑓(𝑥) (3.57)
̃ ≤ 𝑓(𝑥) ≤ 𝛼𝑓(𝑥)
𝑓(𝑥) ̃ + 𝛽𝑓(𝑦) (3.58)
Telegram: @ElectricalDocument
3.4 Global optimum and uniqueness of the solution 51
̃ ≤ 𝛽𝑓(𝑦)
(1 − 𝛼)𝑓(𝑥) (3.59)
̃ ≤ 𝛽𝑓(𝑦)
𝛽𝑓(𝑥) (3.60)
̃ ≤ 𝑓(𝑦)
𝑓(𝑥) (3.61)
̃ = 𝑓(𝑦)
𝑓(𝑥) ̃ ≤ 𝑓(𝑧) (3.62)
but 𝑓(𝑧) < 𝑓(𝑥) ̃ contradicts our initial assumption. Therefore, there is no way
that 𝑥̃ ≠ 𝑦̃ for a strictly convex function (i.e., 𝑥̃ = 𝑦̃ and optimum is unique).
One way to identify a strictly convex function is by defining a new function
𝑔 as follows:
2
𝑔(𝑥) = 𝑓(𝑥) − 𝜇 ‖𝑥‖ (3.64)
with 𝜇 > 0. If 𝑔 is convex, then 𝑓 is not only convex but also strictly con-
vex. The relation among strongly, strictly, and convex functions is depicted in
Figure 3.9:
Figure 3.9 Relation among the concepts of strict and strong convexity. All strongly
convex functions are strictly convex. Both are, of course, convex.
Telegram: @ElectricalDocument
52 3 Convex optimization
3.5 Duality
In this section, we briefly study duality theory for convex optimization prob-
lems. We can associate a complementary optimization problem called a dual
problem for any optimization problem, convex or not convex. Let us con-
sider a convex optimization problem as Equation (3.47), then we can define
a Lagrangian function as follows:
Notice the dual function depends on 𝜆 and 𝜇 but not on 𝑥 as is the case of ℒ.
Since 𝜇 ≥ 0 then for any feasible point 𝑥, we have that,
Since the point is feasible, then 𝐴𝑥 − 𝑏 = 0 and 𝑔(𝑥) ≤ 0, therefore the term
𝜇⊤ 𝑔(𝑥) is negative and Equation (3.67) is clearly met. This property is known
as weak duality and is general for any feasible point, even in the minimum.
Therefore, we have also that
max 𝒲(𝜆, 𝜇)
𝜇≥0 (3.69)
The relation between the primal and the dual problem is depicted in
Figure 3.10. The Primal problem search for a minimum point in the feasible
set while the dual problem search for a maximum point in its own feasible set.
The maximum point of 𝒟 constitutes a low boundary of the problem since any
Telegram: @ElectricalDocument
3.5 Duality 53
feasible point in the Primal returns a higher value than the value given by any
feasible point at the dual problem.
{ }
𝒲(𝜇) = inf 𝑐⊤ 𝑥 + 𝜇⊤ (𝐴𝑥 − 𝑏) (3.70)
𝑥
min 𝑏⊤ 𝜇
𝑐 + 𝐴⊤ 𝜇 = 0 (3.71)
𝜇≥0
𝑛
∑ 𝑎𝑘 2
min 𝑝 + 𝑏𝑘 𝑝𝑘
𝑘=1
2 𝑘
𝑚
∑
𝑝𝑘 = 𝑑 (3.72)
𝑘=1
𝑝𝑘 ≥ 0
Telegram: @ElectricalDocument
54 3 Convex optimization
𝑛 𝑚 𝑚
∑ 𝑎 ∑ ∑
𝒲(𝜇, 𝜆) = inf { ( 𝑘 𝑝𝑘2 + 𝑏𝑘 𝑝𝑘 ) + 𝜆 (𝑑 − 𝑝𝑘 ) + 𝜇𝑘 (−𝑝𝑘 )}
𝑝
𝑘=1
2 𝑘=1 𝑘=1
(3.73)
and hence, the dual problem is the following:
𝑛
∑ 1
max 𝜆𝑑 − (𝜆 + 𝜇𝑘 − 𝑏𝑘 )2
𝑘=1
2𝑎 𝑘
𝜇𝑘 ≥ 0 (3.74)
In general, the dual of a quadratic programming problem is another quadratic
programming problem.
The dual function is concave, even if the Primal problem is non-convex.
Remember that a function 𝒲 is concave if −𝒲 is convex. Therefore, we must
check if −𝒲 holds Jensen’s inequality. Let us take two points in the dual
function, (𝜆1 , 𝜇1 ) and (𝜆2 , 𝜇2 ) with two real values 𝛼 ≥ 0, 𝛽 ≥ 0 with 𝛼 =
1 − 𝛽; then, let us evaluate the function in a generic midpoint, as presented
below 4 :
−𝒲(𝛼𝜆1 + 𝛽𝜆2 , 𝛼𝜇1 + 𝛽𝜇2 ) = −inf {ℒ(𝑥, 𝛼𝜆1 + 𝛽𝜆2 , 𝛼𝜇1 + 𝛽𝜇2 )}
𝑥
Telegram: @ElectricalDocument
3.5 Duality 55
Figure 3.11 Example of a primal non-convex problem and its corresponding dual
function.
Weak duality allows finding a lower limit of the primal problem by maxi-
mizing the dual. However, very often, the dual is equal to the primal. In that
case, we say the problem fulfills the strong duality conditions. There is a sim-
ple criterion for strong duality in convex optimization problems. Informally,
the primary condition to guarantee strong duality is that the feasible region
must have a non-empty relative interior. This criterion is named as Slater’s
conditions [17].
Let us consider the feasible set Ω, of a primal convex optimization problem,
namely:
Ω = {𝑥 ∈ ℝ𝑛 ∶ 𝐴𝑥 − 𝑏 = 0, 𝑔(𝑥) ≤ 0} (3.77)
Notice the only difference between Ω and relint(Ω) is in the inequality con-
straint. Slater’s condition state that relint(Ω) ≠ ∅ , that is to say, there is at
least one point that fulfills equality and the inequality constraints strictly. Let
us analyze these concepts in the following example:
Example 3.21. Consider the following optimization problem
min 𝑥 2
𝑥≥3 (3.79)
There is no 𝜆 because the model has only inequality constraints. The dual
function is calculated taking the minimum of this function (i.e., when
2𝑥 − 𝜇 = 0):
Telegram: @ElectricalDocument
56 3 Convex optimization
Figure 3.12 Comparison between the primal and the dual problems.
Dual variables represent the change in the objective function for a change in
the constrain. Let us consider an optimization problem as
min 𝑓(𝑥)
𝐴𝑥 = 𝑏 (3.82)
𝑔(𝑥) ≤ 𝑡
Let us suppose we know the optimum 𝑥̃ and the corresponding dual variables
𝜆̃ and 𝜇,
̃ then we have that:
̃
∆𝑓(𝑥)
𝜆̃ = (3.83)
∆𝑏
̃
∆𝑓(𝑥)
𝜇̃ = (3.84)
∆𝑡
This interpretation of the dual variables is vital in common practical prob-
lems. These variables can be used to define new investments, as explained in
Chapter 7.
Telegram: @ElectricalDocument
3.6 Further readings 57
constraints are convex, and the equality constraints are affine. Once we have
checked these conditions, we can conclude that the optimum is global. Therein
lies the importance of identifying convex functions in an optimization model.
In this chapter, we presented common examples of convex functions. More
exotic functions can be studied in [17]. Another type of convex functions such
as second-order cone (SOC) and semidefinite programming (SDP) will be stud-
ied in Chapter 5. Uniqueness can be guaranteed by using the concepts of strong
and strict convexity; usually, it is simpler to identify a strongly convex func-
tion. More details about these types of functions can be studied in [18]. The
concept of duality can be studied in more detail in [19]. We only presented
the most basic concept of duality and some conditions to interpret results. The
interpretation of the dual variables is critical in many practical problems. Other
concepts such as the Karush–Kuhn–Tucker conditions can be studied in [20].
Finally, it is recommended to review general concepts of linear algebra; two
excellent references are [21] and [16]. We avoided solving optimization prob-
lems by hand since our objective is to solve large optimization problems. All
repetitive calculations must be made by the computer, as presented in the next
chapter.
Definition Consequence
Convex problem
min 𝑓(𝑥), convex global optimum
𝐴𝑥 = 𝑏, affine
𝑔(𝑥) ≤ 0, convex
Strictly convex function
𝑓(𝛼𝑥 + 𝛽𝑦) < 𝛼𝑓(𝑥) + 𝛽𝑓(𝑦) unique solution
Strongly convex function
2
𝑓(𝑥) − 𝜇 ‖𝑥‖ also convex strictly convex
Dual function
{ }
𝒲(𝜇, 𝜆) = inf 𝑓(𝑥) + 𝜆⊤ (𝐴𝑥 − 𝑏) + 𝜇⊤ 𝑔(𝑥) concave
Dual problem weak duality
max 𝒲(𝜇, 𝜆) with 𝜇 ≥ 0 max 𝒲 ≤ min 𝑓
Slater conditions
There exists at least one 𝑥 such that strong duality
𝐴𝑥 + 𝑏 = 0, and 𝑔(𝑥) < 0 max 𝒲 = min 𝑓
Dual variables change of the objective function
𝜆, 𝜇 for a change in the constraint
Telegram: @ElectricalDocument
58 3 Convex optimization
3.7 Exercises
1. Show that the following set is convex:
{ }
Ω = (𝑥, 𝑦) ∈ ℝ2 ∶ 𝑥 ≥ 0, 𝑦 ≥ 0, 𝑥𝑦 ≥ 1 (3.85)
2. Show that the sum of two convex functions is also a convex function.
3. Show that the composition of a convex function and an affine function,
results in an convex function.
4. Demonstrate that a function is convex if and only if its epigraph is convex.
5. Identify which of these functions are convex:
𝑓(𝑥) = 𝑥⊤ 𝐴𝑥, with 𝐴 ≻ 0 (3.86)
𝑓(𝑥) = exp((𝐵𝑥 + 𝑐)⊤ 𝐴(𝐵𝑥 + 𝑐)), with 𝐴 ⪰ 0 (3.87)
⊤
𝑓(𝑥) = − ln((𝐵𝑥 + 𝑐) 𝐴(𝐵𝑥 + 𝑐)), with 𝐴 ⪰ 0 (3.88)
6. Show the following relation using Jensen’s inequality (use the fact that
− ln(𝑥) is convex and monotone).
𝑛 𝑛
∏ 1∕𝑛 ∑ 1
𝑥𝑘 ≤ 𝑥𝑘 (3.89)
𝑘=1 𝑘=1
𝑛
7. Show the Lagrangian and the dual function associated to the following
optimization problem:
min 𝑓(𝑥) = (𝑥 − 1)2
𝑥2 ≤ 0 (3.90)
Show the feasible space of both the dual and the primal problems. Analyze
the conditions of weak and strong duality.
8. Determine the dual problem associated to a quadratically constrained
quadratic programme presented below:
1 ⊤
min 𝑥 𝐻𝑥 + 𝑏𝑥
2
1 ⊤
𝑥 𝐴𝑥 + 𝑐𝑥 ≤ 𝑑 (3.91)
2
9. Consider the following optimization problem
min 𝑥2 + 1
(𝑥 − 2)(𝑥 − 4) ≤ 0 (3.92)
Show the set of feasible solutions and find the optimum. Plot the objective
function vs 𝑥; on the same graph, plot the Lagrangian function ℒ(𝑥, 𝜇) for
different values of 𝜇 (for example 𝜇 = 1, 𝜇 = 5, and 𝜇 = 10). Formulate
Telegram: @ElectricalDocument
3.7 Exercises 59
the dual problem and solve it. Analyze the conditions of strong and weak
duality.
10. Solve the following problem using both the primal and the dual formulations
(use graphs of the function and the feasible set in order to find the optimum)
min 𝑥 + 𝑦
𝑥2 + 𝑦2 ≤ 1 (3.93)
Telegram: @ElectricalDocument
Telegram: @ElectricalDocument
61
Learning outcomes
min 𝑐⊤ 𝑥
𝐴𝑥 = 𝑏 (4.1)
𝑥≥0
Telegram: @ElectricalDocument
4.2 Linear programming 63
max 3𝑥 − 2𝑦
𝑥+𝑦 ≤5 (4.2)
𝑥, 𝑦 ≥ 0
min − 3𝑥 + 2𝑦
𝑥+𝑦+𝑧 =5 (4.3)
𝑥, 𝑦, 𝑧 ≥ 0
The set of feasible solutions for this problem is shown in Figure 4.2. The direc-
tion of the gradient of the objective function is represented as ∇obj; using this
direction, we can easily identify the optimum. As expected, the optimum is in
a vertex, in this case in 𝑑 = (8∕3, 2∕3).
2 We already studied this object in Example 3.4 (Chapter 3) and concluded that it is convex.
Telegram: @ElectricalDocument
64 4 Convex Programming in Python
Figure 4.2 Set of feasible solutions for the linear programming problem in
Example 4.2.
import numpy as np
import cvxpy as cvx
x = cvx.Variable()
y = cvx.Variable()
obj = cvx.Maximize(3*x-2*y)
res = [x+y <= 5, x>=0, y>=0]
Model = cvx.Problem(obj,res)
Model.solve()
print(np.round(obj.value),np.round(x.value,2),
np.round(y.value,2))
The code is intuitive; it starts by defining decision variables with the command
cvx.Variable; then, the objective function and the set of constraints are
determined; the set of constraints are stored in a vector named res; after that,
the model is solved, and results are printed, rounded to two decimal places.
Notice that we did not require to change the problem to a canonical form;
instead, the problem was represented as was raised.
Telegram: @ElectricalDocument
4.2 Linear programming 65
We can use different solvers and see the iterations on each solver as shown
below. The complete list of solvers is available in [23].
Model.solve(solver=cvx.OSQP,verbose=True)
print(obj.value,x.value,y.value)
Model.solve(solver=cvx.ECOS,verbose=True)
print(obj.value,x.value,y.value)
Model.solve(solver=cvx.SCS,verbose=True)
print(obj.value,x.value,y.value)
The script is quite similar to the previous example. The only difference was
in the definition of the variables 𝑥, which is a vector in ℝ2+ . Therefore, we
defined the size of the variable and a condition no no-negativity (i.e., nonneg=
True).
Telegram: @ElectricalDocument
66 4 Convex Programming in Python
Figure 4.3 Oriented graph for a transportation problem with four sources (s) and
three destinations (d). The numbers in the arrows corresponds to the unit costs for
each route.
𝑚 𝑛
∑ ∑
min 𝑐𝑖𝑗 𝑥𝑖𝑗
𝑖 𝑗
𝑛
∑
𝑥𝑖𝑗 = 𝑠𝑖
𝑗
𝑚
∑
𝑥𝑖𝑗 = 𝑑𝑗 (4.5)
𝑖
𝑥𝑖𝑗 ≥ 0
Telegram: @ElectricalDocument
4.3 Quadratic forms 67
Model.solve()
print(np.round(x.value,2))
𝑞(𝑥) = 𝑥 ⊤ 𝐴𝑥 + 𝑏⊤ 𝑥 + 𝑐 (4.6)
It is important to note that not all quadratic forms are convex. In this case, the
form is convex since it describes a paraboloid, as may be easily demonstrated
by plotting the function.
The main properties of a quadratic form are determined by the matrix 𝐴.
Two interesting cases are when this matrix is symmetric and when it is skew-
symmetric. A matrix 𝐴 is symmetric when 𝐴 = 𝐴⊤ and skew-symmetric when
𝐴 = −𝐴⊤ . Let us analyze the latter case.
Telegram: @ElectricalDocument
68 4 Convex Programming in Python
Therefore, 𝑞(𝑥) = −𝑞(𝑥) for any value of 𝑥 and hence, 𝑞(𝑥) = 0. In conclusion,
a quadratic form 𝑞(𝑥) = 𝑥 ⊤ 𝑁𝑥 is zero if 𝑁 is skew-symmetric.
Any square matrix 𝐴 can be written in terms of a symmetric and a skew-
symmetric matrix, as follows:
1 1
𝐴= (𝐴 + 𝐴) + (𝐴⊤ − 𝐴⊤ ) (4.15)
2 2
1 1
= (𝐴 + 𝐴 ) + (𝐴 − 𝐴⊤ )
⊤
(4.16)
2 2
1 1
= 𝑀+ 𝑁 (4.17)
2 2
𝑞(𝑥) = 𝑥⊤ 𝐴𝑥 (4.18)
1 ⊤ 1
= 𝑥 𝑀𝑥 + 𝑥 ⊤ 𝑁𝑥 (4.19)
2 2
1 ⊤
= 𝑥 𝑀𝑥 (4.20)
2
In other words, any quadratic form 𝑞(𝑥) can be written in terms of a symmetric
matrix.
Example 4.7. The quadratic form given in Equation (4.7) can be written in
terms of a symmetric matrix as given below:
⊤ ⊤
1 𝑥 10 2 𝑥 8 𝑥
𝑞(𝑥0 , 𝑥1 ) = ( 0 ) ( ) ( 0 ) + ( ) ( 0 ) + 15 (4.21)
2 𝑥1 2 6 𝑥1 4 𝑥1
Telegram: @ElectricalDocument
4.4 Semidefinite matrices 69
where
5 10 1 5 10 5 −8 1 10 2
( ) = (( )+( )) = ( )
−8 3 2 −8 3 10 3 2 2 6
(4.22)
Any quadratic form 𝑞(𝑥) given by Equation (4.6) is continuous and has
derivative. Its gradient is given by Equation (4.23):
∇𝑄 = (𝐴 + 𝐴⊤ )𝑥 + 𝑏 (4.23)
2 1
𝐴=( ) (4.24)
1 1
Telegram: @ElectricalDocument
70 4 Convex Programming in Python
since its eigenvalues are both positive, i.e., 𝜆 = {0.3819, 2.61803}, and have
Cholesky factorization4 :
√ √ ⊤ √ √
2 1 2 2∕2 2 2∕2
𝐴=( )=( √ ) ( √ ) (4.25)
1 1 0 2∕2 0 2∕2
This matrix defines the following quadratic form, which is evidently positive
for any 𝑥 ≠ 0:
Example 4.9. We can define a function in Python that identify positive def-
inite matrices using the eigenvalues. The code for this function is presented
below:
import numpy as np
def IsSD(M):
Lmin = min(np.linalg.eigvals(M))
if (Lmin==0):
print(’Positive semidefinite’)
if (Lmin>0):
print(’Positive definite’)
if (Lmin<0):
print(’It is not positive semidefinte’)
# usage
A = [[2,1],[1,1]]
IsSD(A)
4 The command in Python for Cholesky factorization is np.linalg.cholesky(A) and the com-
mand for calculating the eigenvalues is np.linalg.eigvals(A), where np comes form the NumPy
module.
Telegram: @ElectricalDocument
4.5 Solving quadratic programming problems 71
Figure 4.4 Example of two quadratic functions, 𝑞1 (left) is convex whereas 𝑞2 (right)
is not.
In this case, the eigenvalues of the matrix associated to 𝑞1 are 𝜆 = {1.25, 0.75}
whereas the eigenvalues of the matrix associated to 𝑞2 are 𝜆 = {1.03, −1.03}.
Clearly, 𝑞1 is convex whereas 𝑞2 is not (see Figure 4.4).
min 𝑞0 (𝑥)
𝑞1 (𝑥) ≤ 0 (4.30)
where both 𝑞0 and 𝑞1 are convex quadratic forms. It is important to remark that
the constraint must be an inequality of the type ≤ 0, otherwise the problem is
non-convex. Consider the following optimization problem:
min 𝑞0 (𝑥)
𝑞1 (𝑥) ≥ 0 (4.31)
𝑞2 (𝑥) = 0
Telegram: @ElectricalDocument
72 4 Convex Programming in Python
This problem is not convex, even if 𝑞1 and 𝑞2 were a convex quadratic form,
because equality constraints must be affine and inequality constraints must
be of the type ≤ (see Example 3.1 in Chapter 3). In the following sections, we
present a series of simple examples to familiarize ourselves with the functions
available in CvxPy, for solving quadratic problems.
Example 4.11. An unconstrained quadratic-convex optimization prob-
lem is trivial and can be solved directly. Let us consider the following
problem:
1 ⊤
min 𝑞(𝑥) = 𝑥 𝐻𝑥 + 𝑏⊤ 𝑥 + 𝑐 (4.32)
2
where 𝐻 = 𝐻 ⊤ ≻ 0 (symmetric and positive definite), then we have the
following:
∇𝑞(𝑥) = 𝐻𝑥 + 𝑏 = 0 (4.33)
−1
𝑥 = −𝐻 𝑏 (4.34)
import numpy as np
import cvxpy as cvx
A = np.matrix([[5,2],[0,3]])
H = 1/2*(A+A.T)
IsSD(H)
b = np.array([7,1])
c = 10
x = cvx.Variable(2, nonneg = True)
q = cvx.quad_form(x,H)+b.T@x + c
Telegram: @ElectricalDocument
4.5 Solving quadratic programming problems 73
obj = cvx.Minimize(q)
res = [x[0]+x[1]==1]
Model = cvx.Problem(obj,res)
Model.solve()
print(x.value)
First, we define a matrix for the quadratic form and build a symmetric equiv-
alent (see Example 4.7). Then, we determine if it is semidefinite using the
function created in Example 4.8; the quadratic form is then represented by the
function quad_form that is part of the module CvxPy. The rest of the model
is intuitive.
Example 4.13. Let us define the unitary ball in ℝ2 with center in 𝑎 = (𝑎0 , 𝑎1 )
as ℬ𝑎 , given by Equation (4.37),
{ }
ℬ𝑎 = (𝑥0 , 𝑥1 ) ∶ (𝑥0 − 𝑎0 )2 + (𝑥1 − 𝑎1 )2 ≤ 1 (4.37)
min 𝑥0 + 𝑥1
(𝑥0 , 𝑥1 ) ∈ ℬ𝑎 ∩ ℬ𝑏 (4.38)
This problem is convex since unit balls are convex sets. Moreover, each ball can
be represented as quadratic forms as presented below:
{ }
ℬ𝑎 = 𝑥 ∈ ℝ𝑛 ∶ (𝑥 − 𝑎)⊤ 𝐼(𝑥 − 𝑎) ≤ 1 (4.39)
import numpy as np
import cvxpy as cvx
x = cvx.Variable(2, nonneg = True)
a = np.array([1,1])
q_a = cvx.quad_form(x-a,np.identity(2))
q_b = cvx.quad_form(x,np.identity(2))
obj = cvx.Minimize(x[0]+x[1])
res = [q_a <= 1, q_b <= 1]
Model = cvx.Problem(obj,res)
Model.solve()
print(x.value)
The student is invited to plot this problem and analyze the results.
Telegram: @ElectricalDocument
74 4 Convex Programming in Python
min 𝑓(𝑧)
𝑔(𝑧) ≤ 0
ℎ(𝑧) = 0 (4.40)
𝑧 ∈ ℂ𝑛
min 𝑓(𝑥, 𝑦)
𝑔(𝑥, 𝑦) ≤ 0
real (ℎ(𝑥, 𝑦)) = 0 (4.41)
imag (ℎ(𝑥, 𝑦)) = 0
𝑥, 𝑦 ∈ ℝ𝑛
Telegram: @ElectricalDocument
4.7 What is inside the box? 75
min 𝑓(𝑥)
𝑔(𝑥) ≤ 0 (4.43)
0 if 𝑔(𝑥) ≤ 0
𝐼𝑔 (𝑥) = { } (4.44)
∞ otherwise
This function returns zero when the 𝑥 is a feasible solution of the problem.
Now, we can define a new function 𝐵 given by Equation (4.45):
Figure 4.5 shows the indicator function and the corresponding logarithmic
barrier. The barrier function approximates the indicator function as 𝜇 → 0.
The idea is to solve the problem using the approximated function using a
Telegram: @ElectricalDocument
76 4 Convex Programming in Python
continuous method (for example, Newton’s method) and decrease the value
of 𝜇 iterative until achieving convergence.
Although this is oversimplification of the algorithm implemented in practice,
it is useful to understand the concept. There are several variants to the interior
point algorithm. Interested readers can refer to [17] for more details.
min 𝑓(𝑥)
𝑥𝑖 ∈ 𝔹 (4.47)
min 𝑓(𝑥)
0 ≤ 𝑥𝑖 ≤ 1 (4.48)
𝑥𝑖 ∈ ℝ
Telegram: @ElectricalDocument
4.8 Mixed-integer programming problems 77
we would be lucky if this solution turns out to be binary. Most probably, the
solution would be real values such as 𝑥𝑖 = 0.8 or 𝑥𝑖 = 0.3. This solution is
obviously not feasible from the point of view of the binary problem. However,
it is a lower bound 𝑓 lower of the problem. A binary upper bound is also required
and marked as 𝑓 upper .
The B&B algorithm departs from 𝑓 lower and evaluates different problem
instances using a branching rule. For example, we evaluate the solution with
𝑥𝑖 = 0 and the solution with 𝑥𝑖 = 1. If one of these branching problems results
to be binary and higher than 𝑓 upper , then the solution is discarded as well as the
branching stages below this instance. If the solution is lower than 𝑓 upper , then
we have a new 𝑓 upper and continue the algorithm. The main drawback of this
algorithm is the high computational load associated with evaluating each node,
as the tree is built. Therefore, we require efficient branching rules to reduce the
number of nodes that are evaluated. Most of the commercial solvers have addi-
tional techniques to accelerate the process. The following example shows how
the algorithm works in practice.
Example 4.15. Consider the following optimization problem:
min 𝑓(𝑥) = 𝑥⊤ 𝐻𝑥
∑
𝑥𝑖 = 3 (4.49)
𝑥𝑖 ∈ 𝔹
with 𝐻 = diag(0.41, 0.51, 0.32, 0.20, 0.31, 0.21) and 𝑖 ∈ {0, 1, … , 6}. First, we
relax the binary constraint obtaining the following convex model:
⎧ min 𝑥⊤ 𝐻𝑥 ⎫
∑
𝐴= 𝑥𝑖 = 3 (4.50)
⎨ ⎬
0 ≤ 𝑥𝑖 ≤ 1
⎩ ⎭
If the solution of this problem is binary, then our problem is solved. However,
this is not the case, so 𝐴 is just a lower bound. Then we generate new instances
of the problem with 𝑥0 = 0 and 𝑥1 = 1, namely
⎧ min 𝑥⊤ 𝐻𝑥 ⎫
⎪ ∑𝑥 = 3 ⎪
𝑖
𝐵= (4.51)
⎨ 0 ≤ 𝑥𝑖 ≤ 1 ⎬
⎪ ⎪
𝑥0 = 0
⎩ ⎭
and
⎧ min 𝑥⊤ 𝐻𝑥 ⎫
⎪ ∑𝑥 = 3 ⎪
𝑖
𝐶= (4.52)
⎨ 0 ≤ 𝑥𝑖 ≤ 1 ⎬
⎪ ⎪
𝑥0 = 1
⎩ ⎭
Telegram: @ElectricalDocument
78 4 Convex Programming in Python
Example 4.16. There are efficient solvers for binary problems available in
CvxPy, so we do not require generating the enumeration tree by hand. The code
for the previous example is presented below:
import numpy as np
import cvxpy as cvx
x = cvx.Variable(6, boolean=True)
H = np.diag([0.41,0.51,0.32,0.20,0.31,0.21])
f = cvx.Minimize(cvx.quad_form(x,H))
res = [ 0<= x, x<=1, cvx.sum(x)==3]
BinaryProblem = cvx.Problem(f,res)
BinaryProblem.solve()
print(’Optimal value’,np.round(f.value,4),np.round(x.value,4))
Telegram: @ElectricalDocument
4.9 Transforming MINLP into MILP 79
Table 4.1 Details of the node generated by the branch and bound
problem.
Node f(x) x0 x₁ x₂ x₃ x₄ x5
A 0.4388 0.3567 0.2868 0.4570 0.7313 0.4718 0.6964
B 0.4980 0 0.3255 0.5187 0.8299 0.5354 0.7904
C 0.6313 1 0.2170 0.3458 0.5533 0.3570 0.5269
D 0.5586 0 0 0.5818 0.9309 0.6006 0.8866
E 0.7583 0 1 0.3879 0.6206 0.4004 0.5911
F 0.6583 1 0 0.3879 0.6206 0.4004 0.5911
G 0.9821 1 1 0.1939 0.3103 0.2002 0.2955
H 0.7200 0 0 0 1 1 1
𝑦 = 𝑢𝑥
𝑥low ≤ 𝑥 ≤ 𝑥up (4.53)
𝑢 ∈ 𝔹,𝑥 ∈ ℝ, 𝑦 ∈ ℝ
Telegram: @ElectricalDocument
80 4 Convex Programming in Python
𝑢𝑥low ≤ 𝑦 ≤ 𝑢𝑥up
𝑥 − (1 − 𝑢)(𝑥up − 𝑥low ) ≤ 𝑦 ≤ 𝑥 + (1 − 𝑢)(𝑥up − 𝑥low )
𝑥low ≤ 𝑥 ≤ 𝑥up (4.54)
𝑢 ∈ 𝔹,𝑥 ∈ ℝ, 𝑦 ∈ ℝ
Notice that if 𝑢 = 0 then the first constraint is reduced to 𝑦 = 0, whereas if
𝑢 = 1 the two fist constraints result in 𝑥low ≤ 𝑦 ≤ 𝑥up and 𝑦 = 𝑥, respectively.
These conditions are equivalent to 𝑦 = 𝑢𝑥 with 𝑢 ∈ 𝔹.
Example 4.18. Mixed-integer quadratic programming problems as the one
given in Equation (4.49) can be easily transformed into a MILP problem. First,
we write the quadratic in polynomial form as follows:
∑∑
𝑓(𝑥) = ℎ𝑘𝑚 𝑥𝑘 𝑥𝑚 (4.55)
𝑘 𝑚
Next, the bi-linear terms 𝑥𝑘 𝑥𝑚 are replaced by a new binary variable 𝑦𝑘𝑚 , that
is to say:
∑ ∑∑
𝑓(𝑥) = ℎ𝑘 𝑘𝑥𝑘 + ℎ𝑘𝑚 𝑦𝑘𝑚 (4.57)
𝑘 𝑘 𝑚≠𝑘
Telegram: @ElectricalDocument
4.11 Exercises 81
4.11 Exercises
1. Solve the following linear programming problem:
min 𝑐⊤ 𝑥
∑
𝑥𝑖 = 1 (4.59)
𝑖
𝑥𝑖 ≥ 0
where 𝑐, 𝑥 ∈ ℝ𝑛 and 𝑐𝑖 = 𝑖 + 1. Solve the problem for 𝑛 = 2, 𝑛 = 10 and
100.
2. Solve the transportation problem with six sources and eight demands
described in Table 4.2
3. Solve the following problem in Python using the module CvxPy.
min 3𝑥 2 + 2𝑦 2 + 5𝑧2
𝑥+𝑦+𝑧 =1 (4.60)
𝑥, 𝑦, 𝑧 ≥ 0
4. Solve the following problem similar to Example 4.13 for 𝑛 = 4 and 𝑛 = 5.
𝑛−1
∑
min 𝑥𝑖
𝑖=0
𝑥 ∈ ℬ𝑎 ∩ ℬ𝑏 (4.61)
where 𝑎 = 1𝑛 (i.e., a vector with all entries equal to 1) and 𝑏 = 0𝑛 (i.e., a
vector of zeros).
Telegram: @ElectricalDocument
82 4 Convex Programming in Python
cij 0 1 2 3 4 5 si
0 43 90 10 58 95 60 175
1 49 41 65 75 25 17 62
2 33 41 26 64 72 29 118
3 16 49 84 26 36 91 118
4 8 95 82 66 2 17 58
5 90 92 28 32 55 66 175
6 95 90 71 87 69 72 173
7 66 87 29 40 37 52 122
𝑑𝑖 212 144 92 168 201 184 total = 1001
5. Solve the following optimization problem using Python and the module
CvxPy
min 𝑥2 + 𝑦 2
(𝑥 − 1)2 + (𝑦 − 1)2 ≤ 1 (4.62)
(𝑥 − 1)2 + (𝑦 + 1)2 ≤ 1
1
min (𝑥 − 1𝑛 )⊤ 𝐻(𝑥 − 1𝑛 )
2
∑
𝑥𝑖 = 1 (4.63)
min 𝑥2
𝑥≥5 (4.64)
Telegram: @ElectricalDocument
4.11 Exercises 83
Show that every dominant diagonal matrix is positive semidefinite, but the
opposite is not true.
9. Define a function in Python that generates a random positive definite
matrix of size 𝑛 × 𝑛. Use this function to generate random matrices 𝐴 and
𝐵; evaluate numerically each of the properties given in Section 4.4.
10. Finish Example 4.15 and compare the solution with Example 4.16.
Telegram: @ElectricalDocument
Telegram: @ElectricalDocument
85
Conic optimization
Learning outcomes
Figure 5.2 Representation of the second order cone Ω = {‖𝑥‖ ≤ 𝑧} with 𝑥 ∈ ℝ2 and
𝑧 ∈ ℝ.
‖𝛼𝑥‖ ≤ 𝛼𝑧 (5.3)
Telegram: @ElectricalDocument
5.2 Second-order cone optimization 87
In other words, the point (𝛼𝑥, 𝛼𝑧) ∈ 𝒞SOC . Therefore, 𝒞SOC is a cone. It is
straightforward to demonstrate that this cone is also convex using the properties
of the norm (Section 2.2) and the Jensen’s inequality.
On the other hand, both sides of the inequality in Equation (5.1) can be com-
posed by affine spaces obtaining a general representation of an SOC constraint,
as given below:
‖𝐴𝑥 + 𝑏‖ ≤ 𝑐⊤ 𝑥 + 𝑑 (5.4)
min ℎ⊤ 𝑥
‖𝐴𝑥 + 𝑏‖ ≤ 𝑐⊤ 𝑥 + 𝑑 (5.5)
𝑥 ⊤ 𝑀𝑥 − 𝑛⊤ 𝑥 − 𝑠 ≤ 0 (5.6)
𝑢⊤ 𝑢 ≤ 𝑧 (5.9)
Telegram: @ElectricalDocument
88 5 Conic optimization
𝑧2 𝑧 1 𝑧2 𝑧 1
𝑢⊤ 𝑢 + − + ≤𝑧+ − + (5.10)
4 2 4 4 2 4
2 2
𝑧−1 1+𝑧
𝑢⊤ 𝑢 + ( ) ≤( ) (5.11)
2 2
‖‖ ‖‖
‖‖ 𝑢 ‖ 1+𝑧
‖‖( 𝑧−1 )‖‖‖ ≤ (5.12)
‖‖ ‖‖ 2
‖ 2 ‖
Returning to the original variables, we have the following expression:
‖‖ ‖
⎞‖‖‖ 1 + 𝑛⊤ 𝑥 + 𝑠
1
‖‖⎛ 𝑀2𝑥
‖‖ ‖
‖‖⎜ 𝑛⊤ 𝑥+𝑠−1 ⎟‖‖‖ ≤ 2
(5.13)
‖‖ ‖
‖⎝ 2 ⎠‖‖
By using this method, any convex-quadratic model can be transformed into an
SOC problem.
𝑥𝑦 ≥ 𝑤⊤ 𝑤
𝑥≥0 (5.14)
𝑦≥0
𝑥𝑦 ≥ 𝑤 ⊤ 𝑤 (5.16)
1 1
(𝑥 + 𝑦)2 − (𝑥 − 𝑦)2 ≥ 𝑤 ⊤ 𝑤 (5.17)
4 4
(𝑥 + 𝑦)2 ≥ (𝑥 − 𝑦)2 + 4𝑤⊤ 𝑤 (5.18)
Telegram: @ElectricalDocument
5.2 Second-order cone optimization 89
This example shows that SOC is a very general way to represent many non-
linear problems.
𝑧 = 𝑥𝑦
0≤𝑥≤1 (5.20)
0≤𝑦≤1
𝑧≥0
𝑥≤𝑧
𝑦≤𝑧 (5.21)
𝑧 ≥𝑥+𝑦−1
This linearization works in most of the cases. However, for a constraint of the
form 𝑧2 = 𝑥𝑦, it is more precise to use a SOC approximation. We transform the
equality into an inequality, and use Equation (5.19) as follows:
‖‖ ‖‖
‖‖ 2𝑧 ‖
‖‖( )‖‖‖ ≤ 𝑥 + 𝑦
‖‖ 𝑥 − 𝑦 ‖‖
‖ ‖
0≤𝑥≤1 (5.22)
0≤𝑦≤1
𝑧≥0
The SOC approximation maintains the non-linear nature of the problem, mak-
ing it convex. Notice the point (1∕2, 1∕2, 1∕4) is feasible in both the original
problem and the SOC approximation. However, it is infeasible in linearization.
Example 5.4. The function 𝑓(𝑥) = − ln(𝑥) is convex and hence the following
set is also convex:
− ln(𝑥 + 1) ≤ 𝑧
1 1
− ≤𝑥≤ (5.23)
2 2
Telegram: @ElectricalDocument
90 5 Conic optimization
The key function in this example, is the SOC constraint presented in the
penultimate line. As always, the reader is invited to experiment with this
code.
Telegram: @ElectricalDocument
5.2 Second-order cone optimization 91
min ℎ⊤ 𝑥
‖𝑢‖ ≤ 𝑐⊤ 𝑥 + 𝑑 (5.27)
𝑢 = 𝐴𝑥 + 𝑏
with 𝑦 ≥ 0. Now, we take the infimum in 𝑥 and 𝑢, in order to obtain the dual
function. Fortunately, the problem is separable as presented below:
( )
inf ℒ = inf ℎ⊤ 𝑥 + 𝑦(‖𝑢‖ − 𝑐⊤ 𝑥 − 𝑑) + 𝑧⊤ (𝑢 − 𝐴𝑥 − 𝑏) (5.29)
𝑥,𝑢 𝑥,𝑢
( )
= inf (−𝑦𝑑 − 𝑏⊤ 𝑧) + (ℎ⊤ − 𝑦𝑐⊤ − 𝑧⊤ 𝐴)𝑥 + (𝑦 ‖𝑢‖ + 𝑧⊤ 𝑢) (5.30)
𝑥,𝑢
ℎ − 𝑦𝑐 − 𝐴⊤ 𝑧 = 0 (5.32)
If we are using the Euclidean norm, then the Cauchy inequality is valid:
and consequently
The infimum in both the right and the left-hand side of this inequality is zero
as long as 𝑦 − ‖𝑧‖ ≥ 0. Combining all these results, we have the following dual
problem:
Telegram: @ElectricalDocument
92 5 Conic optimization
min 𝑦𝑑 + 𝑏⊤ 𝑧
𝑦𝑐 + 𝐴⊤ 𝑧 = ℎ (5.38)
‖𝑧‖ ≤ 𝑦
Telegram: @ElectricalDocument
5.3 Semidefinite programming 93
The determinant is another operator that takes a square matrix and returns
a scalar. It has the following properties:
These are useful properties of the determinant, which is a complex and inter-
esting operator2 . The following example shows a geometric interpretation of
the determinant.
Example 5.7. As we have seen, a quadratic form 𝑥⊤ 𝐻𝑥 with 𝐻 ≻ 0 may have
different interpretations. For instance, it can generate an ellipsoid ℰ defined as
follows:
{ }
ℰ = 𝑥 ∈ ℝ𝑛 ∶ 𝑥 ⊤ 𝐻𝑥 ≤ 1 (5.41)
2 We suppose the student is familiar with the ways as the determinant is calculated. A student
interested in a formal definition can refer to [21] pg 632.
Telegram: @ElectricalDocument
94 5 Conic optimization
1
that allows to define the following linear transformation 𝑦 = 𝐻 2 𝑥 that in turns,
{ }
transforms the ellipsoid as follows ℬ = 𝑦 ∈ ℝ𝑛 ∶ 𝑦 ⊤ 𝑦 ≤ 1 . This is a unitary
ball of which we know its hypervolume3 . The determinant allows to calculate
the volume of the ellipsoid as shown in Figure 5.3.
To end this review of matrix algebra, let us define the Shur complement.
Consider the following block matrix
𝐴 𝐵
𝑀=( ) (5.43)
𝐵⊤ 𝐶
𝐴 − 𝐵𝐶 −1 𝐵⊤ (5.44)
𝐶 − 𝐵⊤ 𝐴−1 𝐵 (5.45)
3 The hypervolume is the generalization of measurements such as length, area, and volume
for ℝ𝑛 . The hypervolume of a unitary ball in ℝ2 is the area, i.e., 𝜋12 .
Telegram: @ElectricalDocument
5.3 Semidefinite programming 95
Ω = {𝑋 ∈ ℝ𝑛×𝑛 ∶ 𝑋 ⪰ 0} (5.46)
‖𝑢‖ ≤ 𝑡 (5.47)
which is equivalent to
𝑢⊤ 𝑢 ≤ 𝑡 2 (5.48)
2 ⊤
𝑡 − 𝑢 𝐼𝑢 ≥ 0 (5.49)
𝑡𝐼 𝑢
( )⪰0 (5.50)
𝑢⊤ 𝑡
As a direct consequence of this, there is a hierarchy among SOC, SDP, QP, and
LP problems as given in Figure 5.4, since linear programming (LP), quadratic
programming (QP), and quadratically constrained quadratic programming
(QCQP) are particular cases of SOC.
Telegram: @ElectricalDocument
96 5 Conic optimization
Figure 5.4 Venn diagram that represents the relation among different connic
problems
min 𝑡
𝑐⊤ 𝑢 ≥ 1 (5.51)
‖𝑢‖ ≤ 𝑡
import numpy as np
import cvxpy as cvx
n = 10
c = np.random.rand(n)
u = cvx.Variable(n)
t = cvx.Variable()
obj = cvx.Minimize(t)
res = [c@u >= 1, cvx.SOC(t,u)]
ModelSOC = cvx.Problem(obj,res)
ModelSOC.solve()
print("SOC:",obj.value)
print("Time:",ModelSOC.solver_stats.solve_time)
I = np.eye(n)
X = cvx.Variable((n+1,n+1),symmetric=True)
obj = cvx.Minimize(t)
res = [c@u >= 1, X >>0]
res += [X[n,n] == t]
for k in range(n):
res += [ X[k,n] == u[k]]
res += [ X[n,k] == u[k]]
for m in range(n):
res += [X[k,m] == t*I[k,m]]
ModelSDP = cvx.Problem(obj,res)
Telegram: @ElectricalDocument
5.3 Semidefinite programming 97
ModelSDP.solve()
print("SDP:",obj.value)
print("Time:",ModelSDP.solver_stats.solve_time)
⎛ 𝑡𝐼 𝑢 ⎞
‖𝑢‖ ≤ 𝑡 ⎜ ⎟⪰0
⊤
𝑢 𝑡
⎝ ⎠
⎛ 1+𝑥 𝑦 ⎞
𝑥2 + 𝑦2 ≤ 1 ⎜ ⎟⪰0
𝑦 1−𝑥
⎝ ⎠
(𝑐⊤ 𝑥)2 ⎛ 𝑑⊤ 𝑥 𝑐⊤ 𝑥 ⎞
⎜ ⎟⪰0
𝑑⊤ 𝑥 𝑐⊤ 𝑥 𝑡
⎝ ⎠
4 It is essential to remember that >> is different from >=. The first symbol indicates the
matrix is positive semidefinite, whereas the second means that all the matrix entries are
positive.
Telegram: @ElectricalDocument
98 5 Conic optimization
min tr(𝐶𝑋)
tr(𝐴𝑖 𝑋) = 𝑏𝑖 ∀𝑖 (5.52)
𝑋⪰0
where affine constraints are represented using a trace function. Let us define a
Lagrangian funtion as follows:
∑
ℒ(𝑋, 𝑧, 𝑌) = tr(𝐶𝑋) + 𝑧𝑖 (𝑏𝑖 − tr(𝐴𝑖 𝑋)) − tr(𝑌𝑋) (5.53)
𝑖
The following conditions are required to guarantee the existence of this infi-
mum5 :
∑
tr(𝐶𝑋) − 𝑧𝑖 tr(𝐴𝑖 𝑋) − tr(𝑌𝑋) = 0 (5.55)
𝑖
∑
tr(𝐶𝑋 − 𝑧𝑖 𝐴𝑖 𝑋 − 𝑌𝑋) = 0 (5.56)
𝑖
∑
∴ 𝑧𝑖 𝐴𝑖 + 𝑌 = 𝐶 (5.57)
𝑖
max 𝑏⊤ 𝑧
∑
𝑌+ 𝑧𝑖 𝐴𝑖 = 𝐶 (5.58)
𝑌⪰0
Just as in any optimization problem, the dual problem is such that dual ≤
primal and the Slater conditions.
5 Here, we use the fact that the trace is distributive with respect to the sum.
Telegram: @ElectricalDocument
5.4 Semidefinite approximations 99
𝑥 ⊤ 𝐻𝑥 = 1 (5.59)
⎛ 𝑥1 𝑥1 𝑥1 𝑥2 … 𝑥1 𝑥𝑛 ⎞
⎜ 𝑥 𝑥 𝑥2 𝑥2 … 𝑥2 𝑥𝑛 ⎟
𝑋 = 𝑥𝑥 ⊤ = ⎜ 2 1 ⎟ (5.60)
⋮ ⋮ ⋮
⎜ ⎟
𝑥 𝑥 𝑥𝑛 𝑥2 … 𝑥𝑛 𝑥𝑛
⎝ 𝑛 1 ⎠
We can express the quadratic form as function of this matrix as given below6 :
𝑥 ⊤ 𝐻𝑥 = tr(𝐻𝑋) (5.61)
tr(𝐻𝑋) = 1
𝑋⪰0 (5.62)
rank(𝑋) = 1
This set is convex except for the rank constraint. Therefore, we can generate a
convex approximation by relaxing this constraint. Notice the semidefinite con-
dition is imposed in 𝑋 and not in 𝐻. Thus, the approximation is very general
for quadratic and hyperbolic problems.
min 𝑥 ⊤ 𝑄𝑥
𝑥⊤ 𝑥 = 1 (5.63)
1 0.3
𝑄=( ) (5.64)
0.3 −2
This problem is evidently non-convex; however, given its small size, it can be
solved easily using Lagrange multipliers. To do so, we define the following
Telegram: @ElectricalDocument
100 5 Conic optimization
Lagrangian function:
𝑄𝑥 − 𝜆𝑥 = 0 (5.66)
⊤
𝑥 𝑥=1 (5.67)
Therefore, we can conclude that 𝜆 are the eigenvalues of 𝑄 and 𝑥 are the uni-
tary eigenvectors of 𝑄. The optimal solution is just the minimum eigenvalue.
Figure 5.5 shows the level curves of the objective function and the equality con-
straint in the space 𝑥0 , 𝑥1 . The problem has one minimum and one maximum,
achieved at different points; that is to say, the solution is not unique.
This problem was easy to solve because it was defined in ℝ2 ; the situation
becomes more and more complex as 𝑛 increases since we require to evaluate
all possible eigenvalues and their corresponding eigenvectors.
Let us solve the problem using a convex approximation. We define a new
matrix 𝑋 = 𝑥𝑥 ⊤ and the following optimization model which is completely
equivalent to Equation (5.63):
min tr(𝑄𝑋)
tr(𝑋) = 1
𝑋⪰0 (5.68)
rank(𝑋) = 1
Telegram: @ElectricalDocument
5.4 Semidefinite approximations 101
import numpy as np
import cvxpy as cvx
Q = np.array([[1,0.3],[0.3,-2]])
X = cvx.Variable((2,2),symmetric=True)
fo = cvx.Minimize(cvx.trace(Q@X))
re = [X >> 0, cvx.trace(X)==1]
SDaprox = cvx.Problem(fo,re)
SDaprox.solve()
print(’Aprox’,fo.value)
print(’Optimal’,np.linalg.eigvals(Q))
min 𝑥 ⊤ 𝑄𝑥
𝑥𝑖 ∈ {−1, 1} (5.69)
𝑥𝑖2 = 1 (5.70)
min tr(𝑄𝑋)
diag(𝑋) = 1 (5.71)
𝑋⪰0
This approximation may be efficient in some problems, for example, in the max-
cut problem [26, 27].
Telegram: @ElectricalDocument
102 5 Conic optimization
min 𝑓(𝑥)
𝑝(𝑥) = 0 (5.72)
𝑞(𝑥) ≤ 0
Telegram: @ElectricalDocument
5.5 Polynomial optimization 103
𝑝(𝑥, 𝑦) = 𝑞00 𝑥 2 +(𝑞01 +𝑞10 )𝑥𝑦+(𝑞02 +𝑞20 )𝑥 3 +𝑞11 𝑦 2 +(𝑞12 +𝑞21 )𝑦𝑥 2 +𝑞22 𝑥4
(5.78)
𝑞00 = 5
𝑞01 + 𝑞10 = −2
𝑞02 + 𝑞20 = 0
𝑞11 = 1 (5.79)
𝑞12 + 𝑞21 = 2
𝑞22 = 2
𝑄⪰0
Telegram: @ElectricalDocument
104 5 Conic optimization
Q >> 0.01]
SOS = cvx.Problem(obj,res)
SOS.solve()
print(np.round(Q.value,3))
⎛ 5 −1 0 ⎞
𝑄 = ⎜ −1 1 1 ⎟ (5.80)
⎜ ⎟
0 1 2
⎝ ⎠
min 𝑡
𝑥4 − 30𝑥 2 + 8𝑥 − 15 − 𝑡 ∈ 𝑆𝑂𝑆 (5.82)
−100
( )
−200
−5 −4 −3 −2 −1 0 1 2 3 4 5
Telegram: @ElectricalDocument
5.6 Further readings 105
max 𝑡
𝑄 = 𝑄⊤ ⪰ 0
𝑞33 = 1
2𝑞23 = 0 (5.84)
𝑞22 + 2𝑞13 = −30
2𝑞12 = 8
𝑞11 = −15 − 𝑡
The optimal solution to this problem is obtained using CvxPy. The optimal
value corresponds to −271.2461. That is the expected valued, according to
Figure 5.6. Therefore, we have found the global optimum of the problem. The
critical step in this problem was to transform a question from the multivariate
polynomials’ space to the positive semidefinite matrices’ space and solve the
resulting model.
Telegram: @ElectricalDocument
106 5 Conic optimization
5.7 Exercises
1. Make a function in Python that generates random square-semidefinite
matrices of size 𝑛 × 𝑛.
2. Generate random instances of the following quadratically constrained
quadratic program:
min 𝑥⊤ 𝐻𝑥 + 𝑟⊤ 𝑥
𝑥 ⊤ 𝑀𝑥 + 𝑏⊤ 𝑥 + 𝑐 ≤ 0 (5.85)
Telegram: @ElectricalDocument
5.7 Exercises 107
Figure 5.7 Example of a Monte Carlo integration. We add only the points inside the
area that requires to be calculated
exp(𝑥) ≤ 𝑧
1 1
≤𝑥≤ (5.86)
2 2
min 𝑥 + 𝑦 (5.87)
𝑥 1
( )⪰0 (5.88)
1 𝑦
𝑥+𝑦 ≤3 (5.89)
Plot the feasible set, formulate and solve the dual problem, and analyze the
results.
9. Semidefinite programming models can be solved by interior point methods.
In this case, a constraint of the form 𝑋 ⪰ 0 can be penalized by a barrier
function given by 𝜙(𝑋) = −𝜇 ln(det(𝑋)). Use this fact to solve the following
feasibility problem:
min 0
𝑋⪰0 (5.90)
tr(𝑋) = 1
Telegram: @ElectricalDocument
108 5 Conic optimization
Telegram: @ElectricalDocument
109
Robust optimization
Learning outcomes
where ℳ represents the probability space in which 𝛽 lives. There are many
ways to represent ℳ. For example, it may be represented as a set of discrete
scenarios with a given probability, or as a continuous distribution function. In
any case, the challenge is not only the representation of the uncertainty but the
tractability of the resulting optimization model.
A critical step in the problem above is defining the uncertainty set 𝒰 to obtain
a tractable and realistic problem. In the following sections, we present how
to define this set and how it is related to the objective function and the prob-
lem’s constraints. We use the following simple linear programming problem to
present the main concepts:
min 𝑐⊤ 𝑥
𝑎⊤ 𝑥 ≤ 𝑏 (6.4)
Telegram: @ElectricalDocument
6.2 Polyhedral uncertainty 111
(sup 𝑎⊤ 𝑥) ≤ 𝑏 (6.6)
𝑎∈𝒰
This is a linear programming problem, where the decision variables are 𝑎, and
the uncertainty set 𝒰 is a polytope given by (6.5). Therefore, we can define a
primal problem 𝒫(𝑎) written as follows:
max 𝑎⊤ 𝑥
𝒫(𝑎) = { } (6.8)
𝐷⊤ 𝑎 ≤ 𝑑
⎧ min 𝑦 ⊤ 𝑑 ⎫
𝒟(𝑦) = 𝑦 ⊤ 𝐷 = 𝑥 (6.9)
⎨ ⎬
𝑦≥0
⎩ ⎭
The following linear programming problem is obtained, after replacing into
(6.4):
min 𝑐⊤ 𝑥
𝑦⊤ 𝑑 ≤ 𝑏
𝑦⊤ 𝐷 = 𝑥 (6.10)
𝑦≥0
The previous analysis considered only data uncertainty in the constraints.
However, the objective function may also be subject to uncertainty. In that case,
1 The reader is invited to review Section 3.5 for studying the basic duality theory.
Telegram: @ElectricalDocument
112 6 Robust optimization
min 𝑧
𝑐⊤ 𝑥 ≤ 𝑧 (6.11)
⊤
𝑎 𝑥≤𝑏
Thus, the uncertainty set must now include the values of 𝑐. The following
example helps to understand this model.
min 𝑧
( sup 𝑐0 𝑥0 + 𝑐1 𝑥1 ) ≤ 𝑧
(𝑐0 ,𝑐1 )∈𝒰
𝑥0 + 𝑥1 ≥ 1 (6.14)
𝑥0 , 𝑥1 ≥ 0
max 𝑐0 𝑥0 + 𝑐1 𝑥1
⎛ 1 0 ⎞ ⎛ 3.5 ⎞
⎜ −1 0 ⎟ 𝑐0 ⎜ −2.5 ⎟
⎜ 0 ( )≤⎜ (6.15)
1 ⎟ 𝑐1 5.5 ⎟
⎜ ⎟ ⎜ ⎟
0 −1 −4.5
⎝ ⎠ ⎝ ⎠
Telegram: @ElectricalDocument
6.3 Linear problems with norm uncertainty 113
min 𝑧
3.5𝑦0 − 2.5𝑦1 + 5.5𝑦2 − 4.5𝑦3 ≤ 𝑧
𝑦0 − 𝑦1 = 𝑥0
𝑦2 − 𝑦3 = 𝑥1 (6.16)
𝑥0 + 𝑥1 ≥ 1
𝑥0 , 𝑥 1 ≥ 0
𝑦0 , 𝑦 1 , 𝑦 2 , 𝑦 3 ≥ 0
The solution to this problem is 𝑧 = 3.5. This solution is, indeed, worst than the
solution of (6.12). However, it is the best solution in the worst-case scenario,
i.e., it is a robust solution.
min 𝑐⊤ 𝑥
𝑎⊤ 𝑥 ≤ 𝑏 (6.17)
𝑎 ∈ ℬ = {𝑎 ∈ ℝ𝑛 ∶ 𝑎 = 𝛼 + 𝛿𝜉, with, ‖𝜉‖ ≤ 1}
(sup 𝑎⊤ 𝑥) ≤ 𝑏 (6.18)
𝑎∈ℬ
However, this is not a linear programming problem, since the set of feasible
solutions, ℬ, is non-linear. Therefore, the following optimization problem is
raised:
max 𝛼 ⊤ 𝑥 + 𝛿𝜉 ⊤ 𝑥
‖𝜉‖ ≤ 1 (6.19)
Telegram: @ElectricalDocument
114 6 Robust optimization
norm-1 norm-∞
norm-2 norm-2
norm-∞ norm-1
where the decision variables are 𝜉. We can formulate the dual model associ-
ated with this problem and proceed in the same way as in the previous cases.
Nevertheless, a more systematic way to solve the problem is by defining a new
function called dual norm, as follows:
{ }
‖𝑦‖𝒟 = sup 𝑦 ⊤ 𝑥, ‖𝑥‖ ≤ 1 (6.20)
This norm holds all properties presented in Section 2.2. In addition, it is a
bijective operation, which means that the dual norm of ‖⋅‖𝒟 is again ‖⋅‖. Table
6.1 shows the dual norms of the three most common cases.
With this useful definition, we can easily formulate a tractable model for
(6.17), namely:
min 𝑐⊤ 𝑥
𝛼⊤ 𝑥 + 𝛿 ‖𝑥‖𝒟 ≤ 𝑏 (6.21)
notice this is a convex optimization problem since a norm is a convex function.
The problem might be reduced to a linear programming problem for the cases
of 1-norm and ∞ − norm. It is a second-order cone optimization problem for
the case of the 2-norm.
Example 6.2. Let us consider the following linear programming problem:
min 𝑧 = −8𝑥0 − 7𝑥1 − 9𝑥2
𝑥0 + 𝑥1 + 𝑥2 ≤ 10 (6.22)
𝑥≥0
This problem has an optimum in 𝑥 = (0, 0, 10)⊤ with 𝑧 = −90. Now, let us
consider the case in which the coefficients associated to the first constraint are
𝑎 = (𝑎0 , 𝑎1 , 𝑎2 )⊤ with
(𝑎0 − 1)2 + (𝑎1 − 1)2 + (𝑎2 − 1)2 ≤ 0.1 (6.23)
This constraint is equivalent to say that 𝑎 = (1, 1, 1)⊤ + 𝜉 with ‖𝜉‖ ≤ 0.3162.
Therefore, the equivalent robust optimization problem is given by the following
model:
Telegram: @ElectricalDocument
6.4 Defining the uncertainty set 115
With this simple approach, we can define the uncertainty set for a single param-
eter 𝑎. The main idea is to replace the constraint in (6.4) by a chance constraint
as follows:
Prob(𝑎𝑥 ≤ 𝑏) ≥ 𝜂 (6.27)
where 𝜂 is the probability given by (6.26). This equation implies that the
probability of meeting the constraint is above a given value 𝜂.
Example 6.3. Figure 6.1 shows the probability density function for a parame-
ter 𝑎 with mean 𝛼 = 20 and standard deviation 𝜎 = 1. The set 𝒰 constitutes a
confidence interval for the robust optimization problem. Two uncertainty sets
are defined in Figure 6.1, namely: 𝒰𝐴 = [19, 21] and 𝒰𝐵 = [18, 22]. The set 𝒰𝐴
includes values between ±𝜎 with a probability Prob(𝑎 ∈ 𝒰𝐴 ) = 68%, while the
set 𝒰𝐵 includes values between ±2𝜎 and its probability is Prob(𝑎 ∈ 𝒰𝐵 ) = 95%.
These probabilities were calculated using (6.26).
This same idea may be applied for 𝑎 in higher dimensions, for example,
𝑎 ∈ ℝ𝑛 . In that case, the univariate normal distribution is replaced for a mul-
tivariate normal distribution with the following probability density function:
Telegram: @ElectricalDocument
116 6 Robust optimization
0.1
4
0
0 2 4 6 8 2 1
0
10
1 1
𝜓(𝑎) = √ exp (− (𝑎 − 𝛼)⊤ 𝑆 −1 (𝑎 − 𝛼)) (6.28)
(2𝜋)𝑛 det(𝑆) 2
Example 6.4. Figure 6.2 depicts a probability density function for ℝ2 . The
confidence intervals are now replaced by the following confidence regions,
{ }
𝒰𝛾 = 𝑎 ∈ ℝ2 ∶ (𝑎 − 𝛼)⊤ 𝑆 −1 (𝑎 − 𝛼) ≤ 𝛾 (6.29)
Telegram: @ElectricalDocument
6.4 Defining the uncertainty set 117
import numpy as np
from scipy.stats import multivariate_normal
alpha = np.array([5,3])
S = np.array([[3.24,0],[0,0.25]])
p = multivariate_normal(alpha,S)
n_points = 10000
Sinv = np.linalg.inv(S)
gamma = 5
eta_in = 0
for k in range(n_points):
a = p.rvs()
w = np.array(a-alpha)
z = w.T@Sinv@w
if z <= gamma: eta_in += 1
print(’Prob = ’,eta_in/n_points)
Telegram: @ElectricalDocument
118 6 Robust optimization
( )
𝛼⊤ 𝑥 + sup 𝛿 ⊤ 𝑥 ≤ 𝑏 (6.30)
𝛿∈𝒰𝛾
with
{ }
𝒰𝛾 = 𝛿 ∈ ℝ𝑛 ∶ 𝛿⊤ 𝑆 −1 𝛿 ≤ 𝛾1∕2 (6.31)
This set can also be defined using a second-order cone, as presented below:
{ ‖ ‖ }
𝒰𝛾 = 𝛿 ∈ ℝ𝑛 ∶ 𝛾−1∕2 ‖‖‖𝑆 −1∕2 𝛿 ‖‖‖ ≤ 1 (6.32)
The supreme in the left-hand side of (6.33) can be represented as the dual
norm of norm-2. Consequently, the robust constraint is defined by the following
second-order cone:
‖ ‖
𝛼⊤ 𝑥 + 𝛾1∕2 ‖‖‖𝑆 1∕2 𝑥‖‖‖ ≤ 𝑏 (6.34)
import numpy as np
import cvxpy as cvx
c = np.array([-10,-15])
alpha = np.array([5,3])
S = np.array([[3.24,0],[0,0.25]])
M = np.linalg.cholesky(S)
r = np.sqrt(1/5)
x = cvx.Variable(2, nonneg=True)
Telegram: @ElectricalDocument
6.4 Defining the uncertainty set 119
obj = cvx.Minimize(c.T@x)
res = [cvx.SOC(r*10-r*alpha.T@x,M@x)]
Model = cvx.Problem(obj,res)
Model.solve(verbose=True)
print(np.round(x.value,3))
print(np.round(obj.value))
The solution of this problem is 𝑞 = −36 and 𝑥 = (0, 2.428)⊤ . This solution is
clearly lower than the solution of the base problem. However, this solution is
robust enough to guarantee that the solution is feasible in 92% of the scenarios.
Another simple but common case of robust optimization, is when the uncer-
tainty is associated to 𝑏 in (6.4). In that case, the constraint may be transformed
into a robust problem as presented below:
8𝑥 + 15𝑦 ≤ 𝑏 (6.37)
import numpy as np
import matplotlib.pyplot as plt
b = 10 + np.random.randn(10000)
plt.hist(b,20)
plt.grid()
plt.show()
The quantile with a given probability is obtained using the quantile function,
as presented below:
2 The quantile function is defined as 𝜙𝑏−1 (𝑝) = inf {𝑏 ∈ ℝ ∶ 𝐹(𝑏) ≥ 𝑝}; 𝐹 is the cumulative
distribution function.
Telegram: @ElectricalDocument
120 6 Robust optimization
Example 6.8. The numerical method presented in the previous example can
be extended to obtain robust solution in problems where 𝑏 has a distribution
different from the normal distribution. That is the case of the wind velocity
which is often approximated by the Weibull distribution. However, the distri-
bution of the generated power is different, since the output power of a wind
turbine depends on its control. Usually, a wind turbine is controlled to obtain
maximum efficiency for wind velocities between 0 and 𝑣nom ; consequently
the turbine is controlled to obtain nominal power; finally, for wind velocities
higher than 𝑣max , the turbine is blocked. This control can be represented by the
following equation:
3
⎧ 𝑝nom (𝑣∕𝑣nom ) 0 ≤ 𝑣 ≤ 𝑣nom ⎫
𝑝(𝑣) = 𝑝nom 𝑣nom < 𝑣 ≤ 𝑣max (6.39)
⎨ ⎬
0 𝑣 > 𝑣max
⎩ ⎭
Let us consider a wind turbine with 𝑣nom = 12 and 𝑣max = 25. This turbine
is located in an offshore emplacement where the wind varies according to a
Weibull distribution with scale factor 𝜆 = 13 and shape 𝑎 = 2. A histogram of
this variable can be obtained as follows:
import numpy as np
import matplotlib.pyplot as plt
v = 13*np.random.weibull(2, 10000)
plt.hist(v,20)
plt.grid()
plt.show()
Telegram: @ElectricalDocument
6.6 Exercises 121
for k in range(len(v)):
pt[k] = wind_power(v[k])
plt.hist(pt)
plt.grid()
q = []
for k in range(100):
q += [np.quantile(pt,1-k/100)]
plt.plot(q)
plt.grid()
This plot allows obtaining different quantiles according to the expected proba-
bility.
6.6 Exercises
1. Demonstrate the relation between the norm and dual norm for the cases
shown in Table 6.1. Use the definition of dual norm, given by (6.20), and the
theory presented in Section 2.2.
2. Consider a norm ‖𝑥‖ and its corresponding dual norm ‖𝑥‖𝒟 . Show that
these norms holds the following inequality:
3. Example 6.2 used norm-2 to define the uncertainty set. Formulate and solve
the same problem but now using norm-1 and norm-∞.
Telegram: @ElectricalDocument
122 6 Robust optimization
Telegram: @ElectricalDocument
6.6 Exercises 123
max 𝛿 ⊤ 𝑣
𝑣𝑖 = |𝑥𝑖 |𝑤𝑖
∑
𝑤𝑖 ≤ Γ (6.45)
0 ≤ 𝑤𝑖 ≤ 1
Formulate the dual problem associated with (6.45) and the robust counter-
part of the original problem.
Telegram: @ElectricalDocument
Telegram: @ElectricalDocument
125
Part II
Telegram: @ElectricalDocument
Telegram: @ElectricalDocument
127
Learning outcomes
where 𝒯 is the set of thermal units, 𝑓𝑘 is the cost function for each unit 𝑘 ∈ 𝒯,
𝑝𝑘 is the generated power, and 𝑑 is the total demand. In this model, a number
of simplifications were made on the manner in which power systems would
be operated. For instance, power losses, grid constrains, and capacity of the
generation units were neglected (these aspects will be considered later on in
this chapter). Model Equation (7.1) can be solved by the method of Lagrange
multipliers with the following Lagrangian:
∑ ∑
ℒ(𝑝, 𝜆) = 𝑓𝑘 (𝑝𝑘 ) + 𝜆(𝑑 − 𝑝𝑘 ) (7.2)
𝑘∈𝒯 𝑘
𝜕𝑓𝑘
−𝜆 =0 (7.3)
𝜕𝑝𝑘
The value of 𝜕𝑓𝑘 ∕𝜕𝑝𝑘 is known as incremental cost. Therefore, the optimal
dispatch is obtained when the incremental costs of all thermal units are the
same. The second condition is obtained by deriving ℒ with respect to 𝜆 and
gives the power balance (i.e., the sum of the generation must be equal to the
demand).
Cost functions are usually represented as quadratic function as given in
Equation (7.4),
𝑎𝑘 2
𝑓𝑘 (𝑝𝑘 ) = 𝑝 + 𝑏𝑘 𝑝 𝑘 + 𝑐𝑘 (7.4)
2 𝑘
where 𝑎𝑘 , 𝑏𝑘 , 𝑐𝑘 are constants fit from data of the input to output relation of
each thermal unit. A quadratic representation of the thermal units simplifies
the problem enormously. The optimal conditions are the following set of linear
equations that can be easily solved in practice:
𝑎𝑘 𝑝𝑘 + 𝑏𝑘 = 𝜆 (7.5)
∑
𝑝𝑘 = 𝑑 (7.6)
𝑘∈𝒯
Telegram: @ElectricalDocument
7.1 Economic dispatch 129
Figure 7.1 Three thermal units with their respective cost functions for the economic
dispatch problem.
Actual power units have limits of minimum and maximum generation (𝑝min ,
𝑝max ) that must be included into the model as follows:
∑
min 𝑓𝑘 (𝑝𝑘 )
𝑘∈𝒯
∑
𝑝𝑘 = 𝑑 (7.7)
𝑘∈𝒯
𝑝𝑘min ≤ 𝑝𝑘 ≤ 𝑝𝑘max , ∀𝑘 ∈ 𝒯
The effect of these inequality constraints is shown in Figure 7.2. We may obtain
the most economical dispatch by solving a set of linear equations if the solution
is within the operating limits (that is the case for 𝜆𝐴 ). However, one unit may
achieve full load before the others, as is the case of Unit 2 for the incremental
cost 𝜆𝐵 . In that case, Unit 2 is set to the maximum (𝑝2 = 𝑝max ) and the rest
of the demand is supplied by the other two units, at equal incremental cost. In
general, the problem is solved as a quadratic optimization problem as presented
in the following examples.
Telegram: @ElectricalDocument
130 7 Economic dispatch of thermal units
Figure 7.2 Incremental cost for three thermal units considering capability
limits.
Example 7.1. Let us consider a system with two thermal units that supply a
demand of 𝑑 = 200 MW, where the costs functions of each unit is given below:
0.31 2
𝑓0 (𝑝0 ) = 𝑝 + 38𝑝0 (7.8)
2 0
0.22 2
𝑓1 (𝑝1 ) = 𝑝 + 46𝑝1 (7.9)
2 1
Our objective is to supply demand at the minimum cost. Therefore, we require
to minimize the following Lagrangian equation:
𝑓0 (𝑝0 ) + 𝑓1 (𝑝1 ) + 𝜆(𝑑 − 𝑝0 − 𝑝1 ) (7.10)
which results in the following set of linear equations:
0.31𝑝0 + 38 − 𝜆 = 0 (7.11)
0.22𝑝1 + 46 − 𝜆 = 0 (7.12)
𝑝0 + 𝑝1 = 200 (7.13)
The solution of this linear system was 𝑝0 = 98.11, 𝑝1 = 101.88 and 𝜆 = 68.42.
The code in Python for solving this simple problem, is presented below:
A = [[0.31,0,-1],[0,0.22,-1],[1,1,0]]
b = [-38,-46,200]
x = np.linalg.solve(A,b)
print(x)
This problem was simple enough to be solved without any optimization solver.
However, as the number of variables increases, the problem becomes more
complicated. In addition, the presence of box constraints for the maximum and
minimum power generation, makes necessary the use of a general quadratic
programming solver.
Telegram: @ElectricalDocument
7.1 Economic dispatch 131
Table 7.1 Cost functions and operative limits for a system with six thermal units [37].
pmin pmax ak bk 𝜶k 𝜷k
Unit
𝟐 𝟐
(MW) (MW) ($∕MWh ) ($∕MWh) (lb∕MWh ) (lb∕MWh)
Example 7.2. Consider a system with six units with parameters given in Table
7.1 and demand 𝑑 = 1200 MW.
For the sake of simplicity, the values of 𝑐𝑘 were set to zero1 . The economic dis-
patch consists on a quadratic programming problem, given by Equation (7.7),
that can be coded in Python as follows:
import numpy as np
import cvxpy as cvx
pmin = [10,10,35,35,125,130]
pmax = [125,150,210,225,315,325]
a = np.diag([0.30494,0.21174,0.07092,0.05606,0.03598,0.04222])
b = [38.5390,46.1591,38.3055,40.3965,38.2704,36.3278]
d = 1200
p = cvx.Variable(6)
obj = cvx.Minimize(1/2*cvx.quad_form(p,a)+b*p)
res = [sum(p) >= d , p>=pmin, p<=pmax]
Model = cvx.Problem(obj,res)
Model.solve()
print(p.value)
print(’Incremental Cost:’,res[0].dual_value)
The economic dispatch for this case is 𝑝 = (66, 59, 210, 225, 315, 325)⊤ and the
incremental cost is 𝜆 = 58.66 (the reader is invited to implement the code to
prove the results). Notice that the objective function is convex since 𝑎𝑘 ≥ 0. In
addition, the function is strictly convex, therefore, this is the global and unique
optimum of the problem.
Example 7.3. Linear models are common for economic dispatch problem
in modern electricity markets. In that case, the optimization model is highly
simplified, as presented below:
Telegram: @ElectricalDocument
132 7 Economic dispatch of thermal units
∑
min 𝑐𝑘 𝑝 𝑘
𝑘
∑
𝑐𝑘 = 𝑑 (7.14)
𝑘
0 ≤ 𝑝 ≤ 𝑝𝑘max
The following heuristic algorithm, known as merit order method, can solve
this linear problem: First, all units are organized according to the price 𝑐𝑘 , from
the unit with minimum cost to the unit with maximum cost (i.e., ascending
order of price). Next, each unit is dispatched with its maximum power until
the total demand is supplied. The spot price is the dual variable associated to
the power balance constraint.
Example 7.4. A linear model might be obtained from the quadratic cost
as given in Figure 7.3. A linear approximation enormously simplifies the
optimization model.
In that case, each thermal unit is represented by a linear cost function 𝜁𝑘 𝑝𝑘 ,
where the value of 𝜁𝑘 can be calculated as follows:
𝑝max
2
𝑎𝑘 2
min ∫ (𝜁𝑘 𝑝𝑘 − 𝑝𝑘 − 𝑏𝑘 𝑝𝑘 ) 𝑑𝑝𝑘 (7.15)
2
0
3𝑎𝑘 max
𝜁𝑘 = 𝑝 + 𝑏𝑘 (7.16)
8
The economic dispatch is transformed into a linear programming model with
this approximation. Example 7.2 was solved with this model obtaining the fol-
lowing result: 𝑝 = (115, 10, 210, 225, 315, 325)⊤ . Notice the linear model agreed
Telegram: @ElectricalDocument
7.2 Environmental dispatch 133
with the quadratic model in 𝑝3 to 𝑝5 but it was not accurate for 𝑝0 and 𝑝1 .
However, total costs were not that different in one and the other case.
Example 7.5. It might be the case that 𝑐𝑘 in Equation (7.14), is unknown, but
determined by a temporal series, i.e, 𝑐𝑘 = 𝑐̄𝑘 ± 𝛿𝑘 , where 𝛿𝑘 is normally dis-
tributed with mean 𝜇 = 0 and standard deviation 𝛿𝑘 . In that case, we can
obtain a robust optimization model for the economic dispatch problem. The
robust optimization problem is the one presented below:
min 𝑧
∑ ‖‖∑ ‖‖
‖ ‖
𝑐̄𝑘 𝑝𝑘 + 𝛾1∕2 ‖‖‖ 𝜎𝑘 𝑝𝑘 ‖‖‖ ≤ 𝑧
‖‖ ‖‖
𝑘 ‖𝑘 ‖
∑
𝑐𝑘 = 𝑑 (7.17)
𝑘
0 ≤ 𝑝 ≤ 𝑝𝑘max
where 𝛾 defines the size of the confidence region2 . The second-order cone in
the first constraint can be interpreted as a penalization factor for a deviation of
the cost 𝑐𝑘 . A high penalization factor results in a robust although perhaps not
very efficient solution. A trade-off between cost and robustness can be defined
by this parameter.
Example 7.6. Uncertainty in the load or renewable power generation (e.g.,
solar and wind) can be introduced in the model by using robust optimization. In
that case, we just change the power balance for the following robust constraint:
∑
𝑝𝑘 ≤ 𝜙𝑑−1 (𝜂) (7.18)
𝑘
where 𝜙𝑑−1 is the quantile function of the load 𝑑, and 𝜂 is the desired probability.
2 See Chapter 6.
Telegram: @ElectricalDocument
134 7 Economic dispatch of thermal units
Telegram: @ElectricalDocument
7.2 Environmental dispatch 135
Figure 7.4 Example of a Pareto frontier for two contradictory objective functions
that require to be minimized.
problem is considered solved when the Pareto frontier is found. The final deci-
sion about the dispatch is made by the transmission system operator using this
frontier; for example, the transmission system operator may decide the maxi-
mum deviation of the economic dispatch that it is willing to accept to reduce
emissions.
The Pareto frontier can be found by transforming the multiobjective problem
into a single-objective problem as follows:
where 𝜉 is a real number between 0 and 1. This model is convex since both 𝑓𝐴
and 𝑓𝐵 are convex. The Pareto frontier is obtained by solving the problem for
different values of 𝜉 as presented in the example below:
import numpy as np
import cvxpy as cvx
import matplotlib.pyplot as plt
pmin = [10,10,35,35,125,130]
pmax = [125,150,210,225,315,325]
a = np.diag([0.30494,0.21174,0.07092,0.05606,0.03598,0.04222])
b = [38.5390,46.1591,38.3055,40.3965,38.2704,36.3278]
alpha = np.diag([0.00838,0.00838,0.01366,0.01366,0.00922,0.00922])
beta = [0.32767,0.32767,-0.54551,-0.54551,-0.51116,-0.51116]
d = 1200
def Pareto(xi):
Telegram: @ElectricalDocument
136 7 Economic dispatch of thermal units
p = cvx.Variable(6)
f_ecn = 1/2*cvx.quad_form(p,a)+b.T@p
f_env = 1/2*cvx.quad_form(p,alpha)+beta.T@p
fo = cvx.Minimize(xi*f_ecn+(1-xi)*f_env)
res = [sum(p) >= d , p>=pmin, p<=pmax]
Model = cvx.Problem(fo,res)
Model.solve()
return [f_ecn.value,f_env.value]
points = 10
F_ecn = np.zeros(points)
F_env = np.zeros(points)
for k in range(points):
xi = 1/(k+1)
F_ecn[k],F_env[k] = Pareto(xi)
plt.plot(F_ecn,F_env,marker=’o’)
plt.grid()
plt.xlabel(’Economic’)
plt.ylabel(’Enviromental’)
The reader is invited to execute the script and compare the results with previous
examples.
Telegram: @ElectricalDocument
7.3 Effect of the grid 137
∑ ∑
𝑝𝑖 − 𝑑𝑘 = ±𝑠𝑗 (7.24)
𝑖∈Λ𝑘 𝑗∈Ω𝑘
where Λ𝑘 and Ω𝑘 are the set of generators and lines connected to node 𝑘. The
sum in the right-hand side of the equation must take into account the orienta-
tion of the flux, thus 𝑠𝑗 is positive if 𝑗 departs from 𝑘 and negative if it arrives
to 𝑘. This concept is better understood by the following example:
Example 7.9. Consider the grid shown in Figure 7.5. Solve the economic dis-
patch considering the cost functions given in Table 7.1 and the transportation
model of the grid. All lines have a capacity of 300 MW. The complete model is
as follows:
∑
min 𝑓𝑖 (𝑝𝑖 )
𝑖
Power balance equations include power demand, generation and flows in the
directions shown in Figure 7.5. Two lines can connect the same nodes as is the
case of 01𝑎 and 01𝑏; also, two generators can be connected to the same node as
is the case of 𝑝0 , 𝑝1 and 𝑝2 , 𝑝3 . Loads are now a vector 𝑑 = (0, 800, 0, 0, 400, 0)⊤ .
The script for solving this problem starts as in Example 7.2 and continues
with the following code:
ng = 6 # number of generators
nl = 9 # number of lines
nn = 6 # number of nodes
smax = nl*[300]
d = [0,800,0,0,400,0] # demand
Lambda = (0,0,2,2,3,5) # generators location
Omega = ((0, 1),(0,1),(0,3),(0,4),(1,2),(1,5),(2,5),(3,4),(4,5))
# grid
s = cvx.Variable(nl) # power flows
EqB = nn*[0] # equation of balance of energy
Telegram: @ElectricalDocument
138 7 Economic dispatch of thermal units
Figure 7.5 Power grid with six nodes and six generators. All lines have a capacity of
200 MW.
for j in range(nl):
k = Omega[j][0]
m = Omega[j][1]
EqB[k] += s[j] # flow in departing from k
EqB[m] += -s[j] # flow arriving to k
for k in range(ng):
n1 = Lambda[k]
EqB[n1] += -p[k]
res = [p>=pmin, p<=pmax, s<=smax, -s<=smax]
for k in range(nn):
res += [EqB[k] + d[k] ==0]
obj = 1/2*cvx.quad_form(p,a)+b*p
Model = cvx.Problem(cvx.Minimize(obj),res)
Model.solve()
print(’Generation:’,np.round(p.value))
print(’Flows:’,np.round(s.value))
The active power flow in each line, including the double circuit between nodes
0 and 1, is represented by the array 𝑠; loads are represented as a vector of size six,
and EqB represents Equation (7.24) i.e., the balance of energy for each node.
The round solution for this model matches to Example 7.2.
Load flows are 𝑠 = (137, 137, −200, 50, −241, −284, 194, 115, −235)⊤ . Notice
some power flows such as 𝑠03 and 𝑠12 are negative which indicates the power
flows in the opposite direction.
Telegram: @ElectricalDocument
7.3 Effect of the grid 139
The transportation model allows to include grid constraints into the eco-
nomic/environmental dispatch problem. However, it is an oversimplification
of the problem (it could be more useful in radial grids). We must include power
flow equations into the model. A simple yet accurate approximation of the
power flow equations is the linear power flow, also known as dc power flow3 .
In this case, the power flow in each branch 𝑗 = 𝑘𝑚 is given by the following
expression:
𝜃𝑘 − 𝜃𝑚
𝑠𝑗 = 𝑠base (7.26)
𝑥𝑗
snom = 100
x = nl*[0.02]
th = cvx.Variable(nn) # nodal angles
res += [th[0] == 0] # angle reference
for j in range(nl):
k = Omega[j][0]
m = Omega[j][1]
res += [x[j]*s[j] == snom*(th[k]-th[m])]
ModelLPF = cvx.Problem(cvx.Minimize(obj),res)
ModelLPF.solve()
The new economic dispatch was 𝑝 = (94, 100, 178, 188, 315, 325)⊤ origi-
nated by a redistribution of the power flows which are now given by the
vector 𝑠 = (133, 133, −129, 57, −300, −234, 66, 186, −157)⊤ . Notice that line 12
achieves its maximum capability. This effect was not identified with the trans-
portation model, hence the importance of including power flow equations. The
new dispatch is more expensive, but it is feasible with the conditions of the grid.
3 The term dc power flow comes from an analogy between the linearized model and a linear
dc grid [38]. We discourage this name since it can be confused with the power flow in grids
that are actually dc.
Telegram: @ElectricalDocument
140 7 Economic dispatch of thermal units
−1
We can also define the nodal impedance matrix 𝑍bus = 𝑌bus ; this inverse exists
as long as the graph is connected, including a connection with grown, there-
fore, capacitance of the lines must also be included. Nodal voltages are given
by Equation (7.28)
∗
𝑝𝑘 + 𝑗𝑞𝑘 = 𝑣𝑘 𝑒𝑗𝜃𝑘 𝐼bus(𝑘) (7.29)
where 𝑣𝑘 and 𝜃𝑘 are the magnitude and the angle of the voltage. Therefore,
the current can be represented as function of the nodal voltages as given in
Equation (7.30)
where (⋅)H represents the transpose and complex conjugate. This equation can
be represented as function of the real and imaginary parts of the current,
namely:
⊤ ⊤
𝑝loss = real(𝐼bus )𝑅bus real(𝐼bus ) + imag(𝐼bus )𝑅bus imag(𝐼bus ) (7.32)
𝑝loss = 𝑝⊤ 𝐵𝑝 + ℎ⊤ 𝑝 + 𝑤 (7.33)
Telegram: @ElectricalDocument
7.4 Loss equation 141
cos(𝜃𝑘𝑚 )
𝑏𝑘𝑚 = 𝑟𝑘𝑚 (7.34)
𝑣𝑘 𝑣𝑚
Notice that 𝑟𝑘𝑚 is the input 𝑘𝑚 of 𝑅bus and not the resistance of the line 𝑘𝑚;
in fact, it may be the case that there is no transmission line between 𝑘 and 𝑚
and yet, there is an 𝑟𝑘𝑚 in the 𝑅bus matrix. Equation (7.33) constitutes a convex
quadratic form, therefore, it can be relaxed to the following convex inequality
𝑝loss ≥ 𝑝⊤ 𝐵𝑝 + ℎ⊤ 𝑝 + 𝑤 (7.37)
∑ ∑
ℒ(𝑝, 𝜆) = 𝑓𝑘 (𝑝𝑘 ) + 𝜆 (𝑑 + 𝑝loss − 𝑝𝑘 ) (7.38)
𝑘∈𝒯 𝑘
𝜕𝑓𝑘 𝜕𝑝loss
+𝜆( − 1) = 0 (7.39)
𝜕𝑝𝑘 𝜕𝑝𝑘
4 This simplification was also common in times where the computational resources were
limited as presented in [39].
Telegram: @ElectricalDocument
142 7 Economic dispatch of thermal units
where 𝜉𝑘 is a penalty factor that considers the effect of power loss, this factor is
given by Equation (7.41)
1
𝜉𝑘 = (7.41)
1 − 𝜕𝑝loss ∕𝜕𝑝𝑘
Example 7.11. Let us solve the economic dispatch for the system presented in
Example 7.2 with the following loss matrix
⎛ 50 10 0 0 20 0 ⎞
⎜ 10 50 0 0 0 10 ⎟
⎜ 0 0 60 0 0 10 ⎟
𝐵=⎜ × 10−6 (7.42)
0 0 0 350 20 0 ⎟
⎜ ⎟
⎜ 20 0 0 20 370 40 ⎟
⎝ 0 10 10 0 40 480 ⎠
both ℎ and 𝑤 are zero, therefore, it is easy to transform Equation (7.37) into the
following second-order constraint
‖‖ 1∕2 ‖‖
‖‖𝐵 𝑝‖‖ ≤ 𝑧 (7.43)
The new dispatch is 𝑝 = (117, 133, 210, 225, 315, 324)⊤ , total power loss is 𝑧2 =
124. Penalization factors were 𝜉 = (1.03, 1.02, 1.03, 1.2, 1.37, 1.52)⊤ ; the first
two generators had a lower penalization factor compared to the last generator,
and hence it is efficient to dispatch the last generator with less power5 .
Telegram: @ElectricalDocument
7.6 Exercises 143
7.6 Exercises
1. Plot the incremental cost function for each of the six thermal units presented
in Example 7.2; plot also the optimal operation cost vs demand for the system
presented in Example 7.2 with 345 ≤ 𝑑 ≤ 1350.
2. Formulate in Python the optimization model for Example 7.4; compare
results.
3. Solve the problem presented in Example 7.2 but this time, the load varies
according to to a load curve 𝑑 = (0.5, 0.3, 0.4, 0.6, 0.8, 1.0, 0.9, 0.8)⊤ . Plot the
optimal incremental cost for each load.
4. Solve the multi objective economic dispatch problem presented in Example
7.8 but this time, consider the emission of NOx with 𝜂 = 0.0123 and 𝛾 = 0.25
for all the units. Show the Pareto frontier as well as a plot of incremental costs
vs incremental emissions.
5. Solve the problem presented in Example 7.11 without considering a limit
in 𝑝max . Compare results considering and without considering the loss
equation.
6. Write Equation (7.37) as a second-order constrain considering both ℎ and 𝑤.
7. Power loss in a transmission line can be approximated to the following
equation
Telegram: @ElectricalDocument
144 7 Economic dispatch of thermal units
loss 2
𝑝𝑘𝑚 ≈ 𝑔𝑘𝑚 𝜃𝑘𝑚 (7.44)
where 𝑔𝑘𝑚 is the admittance of the line. Use this approximation to include
loss into the economic dispatch with linearized power flow. Use the param-
eters of Example 7.10 with 𝑟 = 0.01 for all transmission lines.
8. Compare results of the transportation and the linear power flow models.
Experiment with different values of 𝑠max and 𝑥𝑗 .
9. Repeat the previous exercise, eliminating lines 3–4, 4–5, and 2–5.
10. Show the matrix 𝐵 given in Equation (7.34) is positive semidefinite (hint:
take into account that the Hadamard product of two definite matrices is also
a definite matrix).
Telegram: @ElectricalDocument
145
Unit commitment
Learning outcomes
temperature
nom
min
output power
nom
min
Figure 8.1 Simplified model for the starting-up of a thermal power plant.
time in which the unit is connected (committed) or disconnected from the grid
(de-committed) is part of the decision; hence the problem dynamic. Additional
constraints are also included in the model, related to the ramps of start-up and
start-down in each thermal unit. In the following sections, we present the basic
model with the most common constraints. As in all the previous chapters, we
offer only toy-models in order to understand the problem.
Telegram: @ElectricalDocument
8.2 Basic unit commitment model 147
defined such that 𝜁𝑘𝑡 = 1 if the unit 𝑘 is operating at the time 𝑡. The starting-
up action is defined by another binary variable 𝜇𝑘𝑡 such that 𝜇𝑘𝑡 = 1 if the
unit 𝑘 was disconnected in time 𝑡 − 1 and connected in the time 𝑡. Similarly, a
binary variable 𝛿𝑘𝑡 is defined such that 𝛿𝑘𝑡 = 1 if the unit was connected at time
𝑡 − 1 but disconnected at time 𝑡. Additional constraints are required in order to
identify starting-up and shutting-down as presented below:
Notice that these constraints uniquely meet the conditions presented in Table
8.1 for binary variables 𝜁, 𝜇, 𝛿. Thus, 𝜇 = 1 only in the case the unit starts to
operate; similarly, 𝛿 = 1 only in the case the unit is disconnected.
0 0 0 0
0 1 1 0
1 0 0 1
1 1 0 0
With these binary variables, it is possible to define the cost functions for a
time horizon, as presented below:
∑∑ 2
𝑓operation = 𝑎𝑘𝑡 𝑝𝑘𝑡 + 𝑏𝑘 𝑝𝑘𝑡 + 𝑐𝑘 𝜁𝑘𝑡 (8.5)
𝑘∈𝒯 𝑡∈𝖳
∑∑ up
𝑓start-up = 𝑐𝑘 𝜇𝑘𝑡 (8.6)
𝑘∈𝒯 𝑡∈𝖳
∑∑
𝑓shut-down = 𝑐𝑘down 𝛿𝑘𝑡 (8.7)
𝑘∈𝒯 𝑡∈𝖳
These functions may be more complex in practice. For example, the start-up
cost depends on how long the unit was de-committed since the cost is lower as
the initial temperature is higher. A detail model of the start-up cost may include
exponential cost functions as presented in [45]. However, it is common practice
to linearize these functions. Notice that 𝜁𝑘 affects the fixed costs in 𝑓operation
under the assumption that the unit incurs this cost only when connected.
Telegram: @ElectricalDocument
148 8 Unit commitment
The variable 𝜁𝑘 affects also the operation limits of the thermal units as
follows:
thus, 𝑝𝑘𝑡 = 0 when 𝜁𝑘𝑡 = 0. The model is completed with the power balance at
each time 𝑡 as presented below:
∑∑ up
min 2
𝑎𝑘𝑡 𝑝𝑘𝑡 + 𝑏𝑘 𝑝𝑘𝑡 + 𝑐𝑘 𝜁𝑘𝑡 + 𝑐𝑘 𝜇𝑘𝑡 + 𝑐𝑘down 𝛿𝑘𝑡
𝑘∈𝒯 𝑡∈𝖳
∑
𝑝𝑘𝑡 = 𝑑𝑡 , ∀𝑡 ∈ 𝖳
𝑘∈𝒯
This is the basic model of the unit commitment problem. However, it can be
complemented with additional constraints related to the grid. Practical applica-
tions combine the hydrothermal schedule with the unit commitment and even
with the ac optimal power flow. Therefore, Equation (8.9) may be considered as
a toy-model used to understand the problem. Let us see the model in practice:
Example 8.1. Let us solve the basic unit commitment problem for a system
with three thermal units. Parameters of the system are presented directly in
the following Python script:
These values were adapted from [46] for 24h operation with 𝑐down = 0. The
optimization model is easily translated from Equation (8.9) to a Python script,
with T = dim(𝖳) and n = 𝒯, as presented below:
Telegram: @ElectricalDocument
8.2 Basic unit commitment model 149
T = len(d)
n = len(a)
zeta = cvx.Variable((n,T), boolean=True)
mu = cvx.Variable((n,T), boolean=True)
delta = cvx.Variable((n,T), boolean=True)
p = cvx.Variable((n,T))
for t in range(T):
res += [cvx.sum(p[:,t])==d[t]]
for t in range(1,T):
for k in range(n):
res += [mu[k,t]-delta[k,t] == zeta[k,t]-zeta[k,t-1]]
res += [mu[k,t]+delta[k,t] <= 1]
for k in range(n):
res += [mu[k,0]-delta[k,0] == zeta[k,0]-z_ini[k]]
res += [mu[k,0]+delta[k,0] <= 1]
obj = cvx.Minimize(fop+fsup)
UnitC = cvx.Problem(obj,res)
UnitC.solve()
print(UnitC.status, obj.value)
The optimal value was 100807. Binary variables can be plotted as follows:
plt.subplot(4,1,1)
plt.plot(p.value.T)
plt.subplot(4,1,2)
plt.pcolor(zeta.value)
plt.subplot(4,1,3)
plt.pcolor(mu.value)
plt.subplot(4,1,4)
plt.pcolor(delta.value)
plt.show()
Telegram: @ElectricalDocument
150 8 Unit commitment
Figure 8.2 Unit commitment for a system with three thermal units.
Figure 8.2 shows the results for the binary variables of the problem. Notice
that 𝜇 and 𝛿 properly identify committed and de-committed time of each
thermal units.
Telegram: @ElectricalDocument
8.4 Effect of the grid 151
up
𝑝𝑘𝑡 − 𝑝𝑘𝑡−1 ≤ 𝜌𝑘 (8.11)
𝑝𝑘𝑡−1 − 𝑝𝑘𝑡 ≤ 𝜌𝑘down (8.12)
Notice the spinning reserve may be different for each time. For example, it could
be higher for the periods of peak load where load changes are greater.
Thermal units may have physical operation limitations that create prohibited
operating zones of power. These restricted zones must be included in the model
as additional binary variables and/or constraints.
Telegram: @ElectricalDocument
152 8 Unit commitment
Let us code this grid in Python but this time, we use the module NetworkX
that allows to operate graphs; the command DiGraph generate an oriented
graph with the connections depicted in Figure 8.3. The graph can be plotted
as presented below:
import networkx as nx
grid = nx.DiGraph([(0,1),(0,3),(1,2),(1,3),(1,4),(2,4),(3,4)])
smax = np.array([100,100,100,100,100,100,100]) # smax lines
smax = smax;
nl = 7 # number of lines
nn = 5 # number of nodes
plt.figure()
nx.draw(grid,with_labels=True)
plt.show()
Finally, we define a new variable 𝑝flow that represents the power flow in each
line and each time. We assume thermal units are connected to nodes 0 to 2 and
load is distributed between nodes 3 and 4 with 60% in node 3 and 40% in node
4. These considerations are transformed in constrains as presented below:
= cvx.Variable((nl,T)) # power flows
p_node = cvx.Variable((nn,T)) # nodal powers
for t in range(T):
res +=[ p_flow[:,t] >= -smax]
res +=[ p_flow[:,t] <= smax]
res +=[ p_node[:,t] == A@p_flow[:,t]]
res +=[ p_node[0,t] == p[0,t]]
res +=[ p_node[1,t] == p[1,t]]
res +=[ p_node[2,t] == p[2,t]]
res +=[ p_node[3,t] == -d[t]*0.6]
res +=[ p_node[4,t] == -d[t]*0.4]
obj = cvx.Minimize(fop)
UnitG = cvx.Problem(obj,res)
UnitG.solve()
print(UnitG.status, obj.value)
The optimal point is now 106795. As expected, the unit commitment was
affected by grid constraints. However, in this case, the starting-up and shutting-
down conditions are the same as in Example 8.1. This is not the general case.
Telegram: @ElectricalDocument
8.6 Exercises 153
However, this system is tiny compared to current power systems, and the grid
has enough capability to transport all generated power. The reader is invited to
experiment with this model, modifying 𝑠max and adding practical constraints in
the model.
8.6 Exercises
1. Make a comparative table between the unit commitment problem and the
economic dispatch.
2. Solve the problem presented in Example Example 8.1 as an economic dis-
patch problem, that is to say, without including start-up and shut-down
costs. Compare the results with the unit commitment.
3. Solve the unit commitment problem in the system presented in Example 8.1
considering a spinning reserve of 𝜎 = 20 𝑀𝑊. Compare results.
4. Include now ramping limits as 𝜌up = 𝜌down = (55, 50, 20)⊤ .
5. Include a minimum up a limit of 4h for all thermal units.
6. Include power loss into the unit commitment model. Use a quadratic
approximation as presented in Example 7.11. Compare results.
7. Solve the unit commitment problem considering the transportation model
(Example 8.2) without using the module NetworkX.
8. Solve the problem presented in Example 8.2 using a linear power flow
instead of the transportation model. Use 𝑥𝑘𝑚 = 0.01pu. Compare results.
Telegram: @ElectricalDocument
154 8 Unit commitment
9. Solve the problem presented in Example 8.2, but this time the load is shared
50% between nodes 3 and 4.
10. Formulate the unit commitment problem considering the ac power flow
constraints. Identify the main characteristics of this model (we will learn
how to solve this type of problems in Chapter 10)
Telegram: @ElectricalDocument
155
Hydrothermal scheduling
Learning outcomes
the volume of the reservoirs and water discharges and spillage. These variables
may be related to other uses of the reservoir, for example, irrigation; hence,
additional constraints must be included in the model. These constraints can
also be related to the safety limits of the volume and/or discharges of the
reservoir.
The level of detail of the model of the hydroelectric system may vary from
one system to another. There are many types of hydroelectric and reservoirs,
and each one has a different type of model. Thus, the mathematical relation
between volume/water discharge and power may be linear or non-linear. In
addition, hydraulic chains can introduce delays in the inflows that affect the
entire system’s dynamic. To do this, we must add non-linear constraints related
to losses and cost of thermal units, and obtaining a model highly non-linear that
requires to be solved in real-time.
On the other hand, the modern power system may include pumped hydro-
electric storage power plants. This type of storage is becoming more popular
with the high penetration of renewable energies. Pump energy storage is just
hydroelectric units with two reservoirs and a reversible capability. Water can be
pumped from the low reservoir to an upper reservoir to store energy. The effect
of other renewable energies, such as wind and solar, must be included in the
model as well.
Telegram: @ElectricalDocument
9.2 Basic hydrothermal coordination 157
plants, while Francis and Kaplan are reaction turbines used for medium and
low heads, respectively. In regards to the water flow, Pelton turbines are used for
relatively low water flow rates while Francis and Kaplan are used for high water
flow [51]. The head and efficiency of the unit depending on the volume of the
reservoir and the water discharge; however, they can be considered constant for
hydro plants with large reservoir capability and in cases where the powerhouse
is placed at a long distance below the dam. In those cases, generated power can
be considered proportional to the water discharge, as given in Equation (9.2):
𝑝𝑖 = 𝜇𝑖 𝑞𝑖 , ∀𝑖 ∈ ℋ (9.2)
𝑝𝑖𝑡 = 𝜇𝑖 𝑞𝑖𝑡 , ∀𝑖 ∈ ℋ
𝑣𝑖𝑡+1 = 𝑣𝑖𝑡 + 𝑎𝑖𝑡 − 𝑞𝑖𝑡 − 𝑠𝑖𝑡 , ∀𝑖 ∈ ℋ, 𝑡 ∈ 𝖳
∑ ∑
𝑝𝑖𝑡 + 𝑝𝑘𝑡 = 𝑑𝑡 , ∀𝑡 ∈ 𝖳
𝑖∈ℋ 𝑘∈𝒯
Telegram: @ElectricalDocument
158 9 Hydrothermal scheduling
Telegram: @ElectricalDocument
9.3 Non-linear models 159
Despite being a system with only two units, the model presents 121 decision
variables, a very high number compared to a dispatch in an all-thermal system.
Nevertheless, the model is linear or, at most quadratic. Generated power in each
unit is given in Figure 9.2 together with the total demand. The power generated
by the hydroelectric unit is very flat, following a curve that guarantees the reser-
voir’s initial and final volume and minimizes the use of the thermal unit. The
power in the thermal unit tries to follow the demand at a minimum cost.
Telegram: @ElectricalDocument
160 9 Hydrothermal scheduling
Telegram: @ElectricalDocument
9.3 Non-linear models 161
100
ℎ
15
50
80 10
100
120
140 5
The minimum permissible water discharge is 𝑞 = 0.5 for both units. Generation
costs of the thermal plants are adjusted to the following quadratic forms:
Telegram: @ElectricalDocument
162 9 Hydrothermal scheduling
In this case, the code was a little different from the previous example. First, gen-
eration power was saved in a single vector where the two first terms correspond
to hydraulic units and the last two to thermal units. Spillages were set to zero,
and quadratic functions were included as inequality constraints. Notice this is
an approximation that requires to be evaluated after solving the optimization
problem. As always, the reader is invited to execute and experiment with the
script.
where Ω𝑖 represents the set of nodes that are connected to reservoir 𝑖 in the
hydraulic chain3 . Notice that Equation (9.11) is an affine constraint, hence the
problem remains convex. On the other hand, flows that come from an upper
reservoir to a lower reservoir do not arrive immediately. Therefore, a time delay
3 For the hydraulic chain given in Figure 9.4, we have that Ω2 = {0, 1} and Ω3 = {2}, whereas
Ω0 and Ω1 are just empty.
Telegram: @ElectricalDocument
9.4 Hydraulic chains 163
0 0
0
0
1 1
1
1
2
2
2
2
3 3
Example 9.3. A power generation system consists on a large thermal unit and
the hydraulic chain depicted in Figure 9.4. Operation cost of the thermal unit is
Telegram: @ElectricalDocument
164 9 Hydrothermal scheduling
linear and given by 𝑓(𝑝) = 19.2𝑝. Parameters of the system including demand
and inflows are coded in Python as follows:
numh = 4
vmin = [80,60,100,70]
vmax = [150,120,240,160]
vini = [100,80,170,120]
vend = [120,80,170,100]
qmin = numh*[0]
qmax = [15,15,30,30]
smin = numh*[0]
smax = numh*[10]
pHmax = numh*[500]
pHmin = numh*[0]
pTmax = 2500
pTmin = 0
a = [[ 9.0, 7.5, 2.5, 2.8],
[ 9.2, 8.0, 3.0, 2.4],
[ 9.5, 8.8, 4.0, 1.6],
[ 9.6, 9.0, 4.5, 1.0],
[ 9.8, 9.3, 4.3, 1.0],
[ 9.9, 9.5, 4.0, 1.0],
[10.0, 10.0, 3.0, 1.0],
[10.3, 10.2, 2.0, 1.3],
[10.5, 10.3, 1.5, 1.5],
[11.0, 10.3, 1.0, 1.6],
[11.2, 10.5, 1.0, 1.7],
[11.5, 10.4, 1.8, 1.5],
[11.4, 10.3, 2.3, 1.5],
[11.3, 10.0, 3.0, 1.3],
[11.2, 9.8, 3.0, 1.2],
[10.0, 9.5, 2.8, 1.2],
[ 9.3, 9.3, 2.5, 1.2],
[ 8.6, 9.0, 2.0, 1.0],
[ 7.5, 8.8, 1.8, 1.0],
[ 7.0, 8.7, 1.6, 0.8],
[ 7.2, 8.6, 1.6, 0.8],
[ 7.3, 8.3, 1.8, 0.8],
[ 7.4, 8.0, 2.0, 0.8],
[ 7.5, 8.0, 2.0, 0.8]]
d = [685,695,680,645,645,705,825,1000, 1120,1160,1115,1155,
1115,1100,1065,1035,1065,1070,1120,1140, 1120,1060,925,795]
miu = [6.5,5.5,9.4,4.7]
Telegram: @ElectricalDocument
9.5 Pumped hydroelectric storage 165
The model does not grow significantly in the number of variables. It is required
only to include additional constraints related to the balance of flows in each
reservoir in the hydraulic chain. Otherwise, the model is the same as the pre-
vious cases. Spillages are important in hydraulic chains since they affect the
power production of hydraulic units placed downstream. In some cases, the
optimization model could introduce spillages in one reservoir in order to supply
another reservoir and increase power generation.
Telegram: @ElectricalDocument
166 9 Hydrothermal scheduling
power to the electric grid. In charging mode, water is pumped from the lower
to the upper reservoir taking electric power from the grid.
Finding a suitable place for building a pumped hydroelectric storage sys-
tem is the main limitation of this technology. However, construction of a lower
reservoir placed deep underground and directly below the upper reservoir can
reduce this limitation [58]. Efficiency and energy density is another main limi-
tation; the total efficiency of the existing pumped hydroelectric storage system
is around 70−85% [59]. However, the use of variable speed systems can increase
these values [60].
Compared to other storage technologies, pumped hydroelectric have the
largest capacity in both energy and power, which varies from 1 to 300 MW.
The turbine/pump system is usually placed just below the upper reservoir, con-
nected with a vertical tunnel or penstock. Many existing pumped hydroelectric
consist of separate pump and turbine systems, but current configurations are
based on reversible turbines. A separate pump and turbine system allows for a
shorter transition time between pumping and generation modes, but its cost is
high.
The model of a pumped hydroelectric requires considering the dynamics of
the reservoir, just as in the case of hydraulic chains.
up up
𝑣𝑡+1 = 𝑣𝑡 − 𝑞𝑡 (9.12)
dw
𝑣𝑡+1 = 𝑣𝑡dw + 𝑞𝑡 (9.13)
The model must include inflows and spillage in case they exist. The model
must consider the net efficiency 𝜂 for a charge/discharge cycle as presented
in Equation (9.14).
gen pmp
𝑝𝑡 − 𝜂𝑝𝑡 == 𝜇𝑞𝑡 (9.14)
Telegram: @ElectricalDocument
9.5 Pumped hydroelectric storage 167
where 𝑝gen is the power generated by the pumped hydroelectric and 𝑝𝑝𝑚𝑝 is the
power required from the system to pump water to the upper reservoir. Pump-
ing requires more energy than is obtained by generating and hence 𝜂 ≤ 1.
Equation (9.14) is valid only if 𝑝gen is not positive simultaneously. That is to
say the system is generating or pumping but not the two at the same time. This
condition can be added to the model as the following set of constraints:
gen
0 ≤ 𝑝𝑡 ≤ 𝑝𝑡max 𝑥𝑡
pmp
0 ≤ 𝑝𝑡 ≤ 𝑝𝑡max (1 − 𝑥𝑡 ) (9.15)
where 𝛼 is the incremental cost of the thermal unit, and 𝑝𝑡thm is generated power
at the time 𝑡. Moreover, 𝑝𝑡 is the total power trade with the main grid, that is to
say:
gen pmp
𝑝𝑡 = 𝑝𝑡thm + 𝑝𝑡sol + 𝑝𝑡 − 𝑝𝑡 (9.17)
where 𝑝gen is the power injected by the hydroelectric in generation mode, 𝑝pmp
is the power taken from the grid in pumping mode, and 𝑝sol is the power gen-
erated by the solar farm; notice that 𝑝𝑡 may be negative, meaning the system is
taking energy from the main grid to pump water.
The optimization model implemented in Python is presented below:
import cvxpy as cvx
pS = [0,0,0,0,0,0,0,26,50,71,87,97,100,97,87,71,50,26,0,0,0,0,0,0]
c = [0.4, 0.4, 0.4, 0.4, 0.4, 0.5, 0.6, 0.6, 0.6, 0.5, 0.5, 0.4,
0.4, 0.4, 0.5, 0.5, 0.6, 0.9, 1.1, 1.1, 1.0, 0.8, 0.7, 0.5]
Telegram: @ElectricalDocument
168 9 Hydrothermal scheduling
vup = cvx.Variable(25,nonneg=True)
vdw = cvx.Variable(25,nonneg=True)
pgen = cvx.Variable(24,nonneg=True)
ppmp = cvx.Variable(24, nonneg=True)
pthm = cvx.Variable(24, nonneg=True)
q = cvx.Variable(24)
p = cvx.Variable(24)
x = cvx.Variable(24, boolean=True)
f = 0
res = [vup[0] == 0, vdw[0] == 120] # initial conditions
for t in range(24):
f = f + c[t]*p[t]-0.95*pthm[t]
res += [vup[t] <= 120, vdw[t] <= 120]
res += [pgen[t] - 0.8*ppmp[t] == 1*q[t]]
res += [pgen[t] - ppmp[t] + pS[t] + pthm[t] == p[t]]
res += [pgen[t] <= 30*x[t], ppmp[t] <= 30*(1-x[t])]
res += [vup[t+1] == vup[t] - q[t] ]
res += [vdw[t+1] == vdw[t] + q[t] ]
res += [pthm[t] <= 10]
PHS = cvx.Problem(cvx.Maximize(f),res)
PHS.solve()
print(’eff:’,print(np.sum(pgen.value-psto.value)))
Results of this problem are shown in Figure 9.6. The lower reservoir starts
full and the upper reservoir empty. Prices are low in the first four hours, and
hence, the hydroelectric unit starts pumping water; from 4 am to 9 am prices
increase, making it viable to generate this energy stored; At medium day, solar
generation is maximum, but prices are minimum. Therefore, it is convenient to
store this energy pumping water to the upper reservoir; this energy is released
to the grid from 16h to 20h where the prices are maximum. The thermal unit
is turned on in this last period. The storage system ends with the same starting
conditions (lower reservoir full and upper reservoir empty). Total efficiency of
the storage process can be calculated by adding 𝑝gen − 𝑝pmp , in this case, the
result is 40MW.
Telegram: @ElectricalDocument
9.7 Exercises 169
All models presented in this chapter simplify real operation problems, which
can consider coupling with other models such as the unit commitment [65].
There is a vast literature in the field, especially in the power system soci-
ety of IEEE; however, the problem has been studied by other communities,
for example, the operation research community [66]. The problem may be
extended to the operation planning that includes periods of one or several
years; in that case, the problem is also stochastic. A tutorial on stochastic
programming to solve this problem can also be found in [67].
9.7 Exercises
1. Solve the problem given in Example 9.1 considering the grid depicted in
Figure 9.7. Use the transportation model with 𝑝max = 150MW in all
transmission lines.
2. Solve the hydrothermal scheduling problem given in Example 9.1 but
now, consider a non-linear model of the hydroelectric power given by
Equation (9.18),
where 𝑣 is the volume of the reservoir and 𝑞 is the water discharge. Plot the
surface and transform the equation into a second-order inequality constrain
ℎ(𝑣, 𝑞) ≥ 𝑝𝐻 . Solve the corresponding hydrothermal dispatch and compare
results with the linear model.
3. Solve the problem presented in Example 9.2 but without considering losses.
Analyze and compare results.
Telegram: @ElectricalDocument
170 9 Hydrothermal scheduling
Telegram: @ElectricalDocument
171
10
Learning outcomes
∗
𝑠𝑘 − 𝑑𝑘 ∑
( ) = 𝑦𝑘𝑚 𝑣𝑚 , ∀𝑘 ∈ 𝒩 (10.2)
𝑣𝑘 𝑚∈𝒩
where (⋅)∗ represents the convex conjugate, 𝑠𝑘 is the generated nodal power,
and 𝑑𝑘 is the corresponding load. For the sake of a compact representation of
the model, we will assume that subscripts 𝑚 and 𝑘 belong to 𝒩 in all cases. The
model is presented in complex variable, for example, Equation (10.2) is repre-
sented in the complex domain; this is only a representation since the equation
requires to be separated into real and imaginary parts. However, a complex
representation is more direct when implemented in Python1 .
Although the problem may consider different objectives and may combine
problems such as the economic/environmental dispatch, the typical applica-
tion consists in minimizing power losses given by (10.3):
∑∑ ∗
𝑝𝐿 = real ( 𝑦𝑘𝑚 𝑣𝑘 𝑣𝑚 ) (10.3)
𝑘 𝑚
This equation can be represented in a real domain by splitting 𝑦𝑘𝑚 = 𝑔𝑘𝑚 +𝑗𝑏𝑘𝑚
and 𝑣 = 𝑣 real + 𝑗𝑣 imag , resulting in the following equivalent expression:
∑∑ imag imag
𝑝𝐿 = 𝑔𝑘𝑚 (𝑣𝑘real 𝑣𝑚
real
+ 𝑣𝑘 𝑣𝑚 ) (10.4)
𝑘 𝑚
∑∑ ∗
min real ( 𝑦𝑘𝑚 𝑣𝑘 𝑣𝑚 )
𝑘 𝑚
𝑣0 = 1 + 𝑗0
1 − 𝛿 ≤ ‖𝑣𝑘 ‖ ≤ 1 + 𝛿, ∀𝑘 ∈ 𝒩
𝑝𝑘max ≥ 𝑠𝑘real ≥ 𝑝𝑘min , ∀𝑘 ∈ 𝒩 (10.5)
𝑠𝑘max ≥ ‖𝑠𝑘 ‖ , ∀𝑘 ∈ 𝒩
max
𝑖𝑘𝑚 ≥ ‖𝑦𝑘𝑚 (𝑣𝑘 − 𝑣𝑚 )‖ , ∀(𝑘𝑚) ∈ ℰ
∗
𝑠𝑘 − 𝑑𝑘 ∑
( ) = 𝑦𝑘𝑚 𝑣𝑚 ∀𝑘 ∈ 𝒩
𝑣𝑘 𝑚
1 See Section 4.6 in Chapter 4 for more details about optimization on the complex field.
2 This can be easily demonstrated taking into account that 𝐺 can be calculated as 𝐺 = 𝐴𝐺𝑝 𝐴⊤ ,
where 𝐴 is the incidence matrix and 𝐺𝑝 is a diagonal matrix with the resisting effect of each
branch.
Telegram: @ElectricalDocument
10.1 OPF in power distribution grids 173
As we have seen, the objective function is convex; the first constraint is affine
and represents the voltage in the slack node; the right-hand side of the second
constraint is a second-order cone that represents the maximum deviation of
the nodal voltage, whereas the left-hand side is a non-convex constraint that
represents the minimum deviation of the nodal voltage. The value of the devi-
ation 𝛿 is usually between 0.05pu to 0.10pu, according to the grid code in each
country. The third and fourth constraints are the maximum capacity of each
renewable source; the fifth constraint represents the thermal limit of each line,
and the final constraint is the set of power flow equations. The latter is the pri-
mary source of complexity of this model; since it is not non-convex, therein lies
the necessity of convex approximations to the OPF.
𝑌00 𝑌0𝑁
𝑌bus = ( ) (10.6)
𝑌𝑁0 𝑌𝑁𝑁
With a slight abuse of notation, we can represent (10.2) in matrix form as given
below:
∗
𝑆𝑁 − 𝐷 𝑁
( ) = 𝑣0 𝑌𝑁0 + 𝑌𝑁𝑁 𝑉𝑁 (10.7)
𝑉𝑁
3 See Appendix A for more details about the construction of the admittance matrix.
4 𝑆∕𝑉 indicates a division term to term.
Telegram: @ElectricalDocument
174 10 Optimal power flow
𝑉𝑁 = 𝑇(𝑉𝑁 ) (10.8)
Telegram: @ElectricalDocument
10.1 OPF in power distribution grids 175
Example 10.1. All the information related to the power distribution grid
depicted in Figure 10.1 can be stored in a single variable using the module
networkx as presented below:
import numpy as np
import networkx as nx
G = nx.DiGraph()
G.add_node(0,name=’slack’,smax=10,d=0)
G.add_node(1,name=’step’,smax=0,d=0)
G.add_node(2,name=’house’,smax=0,d=1.2+0.3j)
G.add_node(3,name=’solar’,smax=1,d=0)
G.add_node(4,name=’building’,smax=0,d=2.5+0.9j)
G.add_node(5,name=’wind’,smax=1.5,d=0)
G.add_edge(0,1,y=1/(0.0075+0.010j),thlim=2)
G.add_edge(1,2,y=1/(0.0080+0.011j),thlim=2)
G.add_edge(2,3,y=1/(0.0090+0.018j),thlim=2)
G.add_edge(1,4,y=1/(0.0040+0.004j),thlim=2)
G.add_edge(4,5,y=1/(0.0050+0.006j),thlim=2)
nx.draw(G,with_labels=True,pos=nx.spectral_layout(G))
All the examples below depart from this definition of the graph, stored in a
variable 𝐺. More details of this module are presented in Appendix A.
Example 10.2. We require to build the 𝑌bus as the block matrices given
in (10.6). The nodal admittance matrix is calculated as given in (10.10):
𝑌bus = 𝐴𝑌𝑝 𝐴⊤ (10.10)
where 𝐴 is the incidence matrix of the oriented graph and 𝑌𝑝 is a diag-
onal matrix of the branch admittance. The incidence matrix can be easily
obtained using the module networkx named as nx in Example 10.1, see the code
below:
A = nx.incidence_matrix(G,oriented=True)
Yp = np.diag([G.edges[k][’y’] for k in G.edges])
Ybus = A@[email protected]
print(Ybus)
print(np.linalg.eigvals(Ybus.real))
In the last line, we checked if the real part of this matrix is positive semidefinite
by calculating its eigenvalues.
Block matrices given in (10.6) are calculated from the 𝑌bus as follows:
n = G.number_of_nodes()
YN0 = Ybus[1:n,0]
YNN = Ybus[1:n,1:n]
ZNN = np.linalg.inv(YNN)
d = np.array([G.nodes[k][’d’] for k in G.nodes])
print(YN0)
print(YNN)
Telegram: @ElectricalDocument
176 10 Optimal power flow
Example 10.3. The power flow equations seen as fixed point (10.8) allow a
simple algorithm for calculating the operation point of the system. Let us define
a function for the load flow calculation using this fixed point map with ten
iterations:
def LoadFlow(sN,dN):
v0 = 1+0j
vN = np.ones(n-1)*v0
for t in range(10):
vN = ZNN@(np.conj((sN-dN)/vN)-v0*YN0)
vT = np.hstack([v0,vN]);
sT = vT*np.conj(Ybus@vT)
err = np.linalg.norm(sT[1:n]-(sN-dN))
print(’Load Flow, after 10 iterations the error is’,err)
return vT
The algorithm depart from 𝑉𝑁 = 1𝑁 and evaluates the fixed point map (10.9).
After that, the new voltages are stored in a variable 𝑉𝑇 , including the slack node.
Total loss is displayed at the end of the process. The algorithm can be improved
using a while-loop instead of a for-loop (in this example, we preferred a compact
code over an efficient algorithm).
We can evaluate the function using results from Example 10.2, considering
loads exclusively (i.e., the solar panel and the wind turbine have generation
equal to zero):
VT = LoadFlow(np.zeros(n-1),d[1:n])
ST = VT*np.conj(Ybus@VT)
pL = sum(ST)
print(’Loss’,pL)
for (k,m) in G.edges:
Sf = Ybus[k,m]*(VT[k]-VT[m])
print(’flow’,(k,m),np.abs(Sf))
import pandas as pd
results = pd.DataFrame()
results[’name’] = [G.nodes[k][’name’] for k in G.nodes]
results[’vpu’] = np.abs(VT)
results[’ang’] = np.angle(VT)*180/np.pi
results[’pnode’] = np.round(ST.real,4)
results[’qnode’] = np.round(ST.imag,4)
results.head(n)
Telegram: @ElectricalDocument
10.2 Complex linearization 177
Example 10.4. Node 1 in the system depicted in Figure 10.1 does not have
generation or load. Therefore, it can be eliminated using a Kron reduction. Let
us split the set of nodes 𝒩 = {𝑠, 𝑟} where 𝑠 is the set of nodes with nodal current
equal to zero, and 𝑟 are the remaining nodes. Then, we have the following:
where 𝑌𝑠𝑠 , 𝑌𝑠𝑟 , 𝑌𝑟𝑠 , 𝑌𝑟𝑟 are block matrices from 𝑌bus . Therefore, we can define
a reduced admittance matrix 𝑌kron as follows:
−1
𝑌kron = 𝑌𝑟𝑟 − 𝑌𝑟𝑠 𝑌𝑠𝑠 𝑌𝑠𝑟 (10.13)
This equation can be coded in Python as presented below for a single node
𝑠 = [1]:
s = [1]
r = list(set(range(n)).difference(s))
nn = len(r)
Ykron = np.zeros((5,5))*0j
for k in range(nn):
for m in range(nn):
Ykron[k,m] = Ybus[r[k],r[m]]-1/Ybus[s,s]*Ybus[r[k],s]*
Ybus[s,r[m]]
Telegram: @ElectricalDocument
178 10 Optimal power flow
where 𝑤𝑘𝑚 is a new complex variable5 . Notice that Equation (10.14) is affine
and the non-convexity appears in Equation (10.15). This equations can be lin-
earized in the complex plain around a given point 𝑢𝑘 , 𝑢𝑚 , using Wirtinger’s
calculus (see Appendix B for more details):
𝑤𝑘𝑚 − 𝑢𝑘∗ 𝑢𝑚 = 𝑢𝑘∗ (𝑣𝑚 − 𝑢𝑚 ) + 𝑢𝑚 (𝑣𝑘∗ − 𝑢𝑘∗ ) (10.16)
usually 𝑢𝑘 = 𝑢𝑚 = 1pu resulting in the following affine constraint:
𝑤𝑘𝑚 = 𝑣𝑘∗ + 𝑣𝑚 − 1 (10.17)
This simple equation constitutes a convex linearization of the power flow
equations.
On the other hand, voltage limitation introduces another set of non-convex
constraints, namely:
1 − 𝛿 ≤ ‖𝑣𝑘 ‖ ≤ 1 + 𝛿 (10.18)
The right hand is a ball or radius 1+𝛿 which is, of course, convex. However, the
left-hand side is a non-convex constraint since it is the exterior of a open ball
of radius 1 − 𝛿. The set defined by (10.18) (both left- and right-hand sides) is
named an annulus and is a non-convex set. In practice, this set can be replaced
by the following set:
1 − 𝛿 ≤ 𝑣𝑘real ≤ 1 + 𝛿 (10.19)
imag
1 − 𝛿 ≤ 𝑣𝑘 ≤1+𝛿 (10.20)
or equivalently as:
‖𝑣𝑘 − 1‖1 ≤ 𝛿 (10.21)
where ‖⋅‖1 represents the 1-norm. Although this approximation may seem
arbitrary, the following example shows in logic behind it.
Example 10.5. Constraint (10.21) is suitable approximation for values of 𝛿 =
0.1 and below. Figure 10.2 shows a subsection of the annulus 0.9 ≤ ‖𝑣𝑘 ‖ ≤ 1.1
for values around 1 + 0𝑗. The box constraint (10.21) is represented as a shadow
square which is a close approximation of the set for angles between 𝜃 = ±5𝑜 and
𝜃 = ±7𝑜 . Voltage angles are usually small in power distribution networks [69],
so this is a fair approximation. The model may be complemented by constraints
on the angle, which are convex. An exact value for the maximum angle would
require stability criteria beyond the objectives of this book. A more conservative
constraint is obtained by replacing the 1-norm with a 2-norm in (10.21).
5 This new variable increases the dimension of the set of feasible solutions; sometimes the
nature of the problem is only revealed when we change our perspective to a higher dimension.
Telegram: @ElectricalDocument
10.2 Complex linearization 179
𝑣0 = 1 + 𝑗0
𝛿 ≥ ‖𝑣𝑘 − 1‖1 , ∀𝑘 ∈ 𝒩
𝑝𝑘max ≥ real(𝑠𝑘 ) ≥ 𝑝𝑘min , ∀𝑘 ∈ 𝒩 (10.22)
𝑠𝑘max ≥ ‖𝑠𝑘 ‖ , ∀𝑘 ∈ 𝒩
max
𝑖𝑘𝑚 ≥ ‖𝑦𝑘𝑚 (𝑣𝑘 − 𝑣𝑚 )‖ , ∀(𝑘𝑚) ∈ ℰ
∑
𝑠𝑘∗ − 𝑑𝑘∗ = 𝑦𝑘𝑚 𝑤𝑘𝑚 , ∀𝑘 ∈ 𝒩
𝑚
notice that 𝑤𝑘𝑚 increases the number of variables of the model; however, the
new equations are affine and hence, it is not a problem in practice. It is also
possible to replace (10.17) into (10.14) to obtain a model with the same num-
ber of variables as the original problem. Here, we are prioritizing a simple
representation over the efficiency of the algorithm.
Notice the model is still non-linear since the objective function is quadratic.
In addition, there are second-order constraints related to the nodal voltage
and the capacity of each renewable power resource. However, these non-linear
equations generate a convex model that can be efficiently solved using CvxPy,
as shown in the following example.
Example 10.6. Let us solve the OPF problem for the system given in
Figure 10.1 using a convex linearization of the power flow equations. We
Telegram: @ElectricalDocument
180 10 Optimal power flow
assume we have stored the graph as given in Example 10.1 and calculated the
𝑌bus as shown in Example 10.2. Both solar panel and wind turbine are available
to generate its nominal power. The code is presented below:
Most of the lines in this code are self explanatory; however, there are some
aspects that require careful explanation. First, notice that 𝑊 = [𝑤𝑘𝑚 ] is a
matrix of the same size of 𝑌bus , therefore, we can define a new matrix given
by (10.23):
𝑀 = 𝑌bus 𝑊 (10.23)
Telegram: @ElectricalDocument
10.2 Complex linearization 181
VT = LoadFlow(s.value[1:n],d[1:n])
ST = VT*np.conj(Ybus@VT)
pL = sum(ST)
print(’Loss’,pL)
After executing this code, power loss is 𝑝𝐿 = 0.0406 (a great reduction in com-
parison to Example 10.3). Notice that although the solar panel has a capacity
of 𝑠𝑘max = 1, not all generation is an active power. The algorithm chooses to
reduce its active power in order to generate some reactive power and minimize
power loss. In case the primary resource (i.e., wind/solar) is limited, then we
require to include constraints of the form real(𝑠𝑘 ) ≤ 𝑝𝑘max . This constraint is, of
course, affine and does not represent a complication of the model. The reader is
invited to compare nodal voltages in the system, with and without distributed
generation.
def LinearOPF(u):
v = cvx.Variable(n,complex=True)
s = cvx.Variable(n,complex=True)
W = cvx.Variable((n,n),complex=True)
obj = cvx.Minimize(cvx.quad_form(cvx.real(v),Ybus.real)+
cvx.quad_form(cvx.imag(v),Ybus.real))
M = Ybus@W
res = [v[0] == 1.0]
Telegram: @ElectricalDocument
182 10 Optimal power flow
for k in range(n):
res += [cvx.conj(s[k]-d[k]) == M[k,k]]
res += [cvx.abs(s[k]) <= smax[k]]
for m in range(n):
res += [W[m,k] == cvx.conj(v[k])*u[m]+
np.conj(u[k])*v[m]
-np.conj(u[k])*u[m]]
OPF = cvx.Problem(obj,res)
OPF.solve()
print(’pL’,obj.value,OPF.status)
return s.value
The main difference of this model with respect to the model in Example 10.6 is
the point in which 𝑤𝑘𝑚 is linearized; in this case, we linearize around 𝑈. Next,
we evaluate this function as well as the power flow already defined in Example
10.3, namely:
VT = np.ones(n)*(1.0+0.0j)
for t in range(3):
ST = LinearOPF(VT)
VT = LoadFlow(ST[1:n],d[1:n])
print(’Loss’,sum(VT*np.conj(Ybus@VT)))
Power loss is 𝑝𝐿 = 0.04258 for both the load flow and the linear OPF.
where 𝛼, 𝛽 are real numbers that represent the variation of the active and reac-
tive power, with respect to the voltage. Typical values of 𝛼, 𝛽 are 𝛼 = 𝛽 = 0 for
industrial loads, 𝛼 = 𝛽 = 1 for commercial loads and 𝛼 = 𝛽 = 2 for residential
loads. Nevertheless, fractional values are allowed.
Equation (10.25) leads to a non-convex constraint, however, it can be eas-
ily linearized using Wirtinger’s calculus. We present only the linearization
𝛼 𝛼
of ‖𝑣𝑘 ‖ since the linearization of ‖𝑣𝑘 ‖ follows the same procedure. First,
consider the following complex function:
𝛼
‖𝑣‖ = (𝑣𝑣 ∗ )𝛼∕2 (10.26)
Telegram: @ElectricalDocument
10.2 Complex linearization 183
import numpy as np
import matplotlib.pyplot as plt
n = 10000
vreal = [0.9+0.2*np.random.rand() for k in range(n)]
vimag = [0.1-0.2*np.random.rand() for k in range(n)]
v = np.array(vreal) + 1j*np.array(vimag)
alpha = 2
f = np.abs(v)**alpha
g = 1-alpha + alpha/2*(v+v.conj())
error = np.abs(f - g)
Telegram: @ElectricalDocument
184 10 Optimal power flow
error.sort()
probability = np.linspace(0,1,n)
plt.plot(error*100,probability)
plt.grid()
plt.show()
Figure 10.3 shows the results for 𝛼 = 2. This plot represents the cumulative
distribution function of 𝜖. In this case, 80% of the randomly generated points
produced an error less than 1%.
This demonstrates the high accuracy of the method. The student is invited to
generate this plot for different 𝑛 and different values of 𝛼 > 0.
∗
𝑤𝑘𝑚 𝑤𝑘𝑚 = (𝑣𝑘∗ 𝑣𝑚 )(𝑣𝑘 𝑣𝑚
∗
) (10.37)
2 2 2
‖𝑤𝑘𝑚 ‖ = ‖𝑣𝑘 ‖ ‖𝑣𝑚 ‖ (10.38)
0.6
0.4
0.2
0
0 0.2 0.4 0.6 0.8 1 1.2 1.4 1.6 1.8 2
error in %
Telegram: @ElectricalDocument
10.3 Second-order cone approximation 185
2
Let us define a new vector 𝐻 ∈ ℝ𝑛 with entries ℎ𝑘 = ‖𝑣𝑘 ‖ , then (10.38) is
transformed into (10.39)
2
‖𝑤𝑘𝑚 ‖ = ℎ𝑘 ℎ𝑚 (10.39)
ℎ0 = 1
(1 + 𝛿)2 ≥ ℎ𝑘 ≥ (1 − 𝛿)2 , ∀𝑘 ∈ 𝒩
𝑝𝑘max ≥ real(𝑠𝑘 ) ≥ 𝑝𝑘min , ∀𝑘 ∈ 𝒩
𝑠𝑘max ≥ ‖𝑠𝑘 ‖ , ∀𝑘 ∈ 𝒩 (10.43)
max
𝑖𝑘𝑚 ≥ ‖𝑦𝑘𝑚 (ℎ𝑘 − 𝑤𝑘𝑚 )‖ , ∀(𝑘𝑚) ∈ ℰ
∑
𝑠𝑘∗ − 𝑑𝑘∗ = 𝑦𝑘𝑚 𝑤𝑘𝑚 , ∀𝑘 ∈ 𝒩
𝑚
‖‖ ‖‖
‖‖ 2𝑤𝑘𝑚 ‖
‖‖( )‖‖‖ ≤ ℎ𝑘 + ℎ𝑚 , ∀(𝑘𝑚) ∈ 𝒩 × 𝒩
‖‖ ℎ𝑘 − ℎ𝑚 ‖‖
‖ ‖
In this model, we calculated power loss as the sum of nodal powers. This
equation is entirely equivalent.
Example 10.9. Let us implement the SOC model given by (10.43) for the
distribution system shown in Figure 10.1. The code in Python is given below:
Telegram: @ElectricalDocument
186 10 Optimal power flow
The angle can be calculated evaluating the angle of each edge of the graph as
given below:
Telegram: @ElectricalDocument
10.3 Second-order cone approximation 187
Figure 10.4 Comparison between the constraint 𝑤𝑘𝑚 = 𝑣𝑘 + 𝑣𝑚 − 1 (solid line) and
the constraint 𝑤𝑘𝑚
2 2
≤ 𝑣𝑘2 𝑣𝑚 (dashed line) for (𝑣𝑘 , 𝑣𝑚 , 𝑤𝑘𝑚 ) ∈ ℝ3 .
Telegram: @ElectricalDocument
188 10 Optimal power flow
𝐸 𝑍
( ) (10.46)
𝑍⊤ 𝐹
𝐸𝑘𝑚 = 𝑒𝑘 𝑒𝑚 (10.47)
𝑍𝑘𝑚 = 𝑒𝑘 𝑓𝑚 (10.48)
𝐹𝑘𝑚 = 𝑓𝑘 𝑓𝑚 (10.49)
where 𝐺bus = real(𝑌bus ). With these simple change of variables, we obtain the
following semidefinite problem:
Telegram: @ElectricalDocument
10.4 Semidefinite approximation 189
𝐸 𝑍
( )⪰0
𝑍⊤ 𝐹
⎛ 𝑠max 0 real(𝑠𝑘 ) ⎞
𝑘
⎜ 0 𝑠𝑘max imag(𝑠𝑘 ) ⎟⪰0
⎜ ⎟
real(𝑠𝑘 ) imag(𝑠𝑘 ) 𝑠𝑘max
⎝ ⎠
For simplicity, we have omitted some constraints related to the thermal limit
and voltage regulation. In addition, the last constraint which is equivalent to
‖𝑠𝑘 ‖ ≤ 𝑠𝑘max is transformed into a semidefinite constraint in order to obtain a
pure SDP problem.
Telegram: @ElectricalDocument
190 10 Optimal power flow
10.6 Exercises
1. Make a comparative analysis among linearization, sequential linearization,
SOC and SDP approximations. Identify the advantages and disadvantages
of each approach.
2. Analyze convergence properties of the power flow algorithm presented in
Section 10.1.1, by plotting a curve of error vs iterations for different values
of load.
3. Compare numerical results for linearization, sequential linearization, SOC
and SDP approximations in the system depicted in Figure 10.1 for different
values of loads and power factor.
Telegram: @ElectricalDocument
10.6 Exercises 191
4. Calculate the OPF for the system depicted in Figure 10.1 if a new line is
included between Node 3 and Node 5, with 𝑧15 = 0.0060 + 0.01.
5. Solve the OPF using the linearization and SOC approximation, for the
power distribution system given in Table 10.1. Assume there is dis-
tributed generation at nodes 11, 20, 21, and 26 with nominal capacity
𝑠max = 0.08pu.
6. T1, T2, and T3 in Table 10.1 represent the load curve for the 34-bus test
system. T1 represents the load factor for operation between 0h:8h, T2
for 8h:16h, and T3 for 16h:24h. Solve the OPF problem for each of this
operation points.
7. Conventional distributed generation are based on synchronous machines
instead of power electric converters. This type of machine presents
a capability curve as shown in Figure 10.5. Include this capabil-
ity curve into the OPF model (notice this curve generates a convex
constraint).
8. Include voltage constraints in the SDP approximation given in (10.52).
Recover the nodal voltages from the semidefinite approximation presented
in Example 10.12.
9. The optimal power flow problem can be extended to the operation of
DC distribution systems. Consider the DC distribution system given in
Telegram: @ElectricalDocument
192 10 Optimal power flow
Telegram: @ElectricalDocument
10.6 Exercises 193
Table 10.2; solve the corresponding OPF problem using linearization and
SOC approximation.
Telegram: @ElectricalDocument
Telegram: @ElectricalDocument
195
11
Learning outcomes
Figure 11.1 Three-feeder test system for power system reconfiguration [84].
𝐼𝒩 = 𝐴𝐼ℰ (11.1)
⊤
𝑉ℰ = 𝐴 𝑉𝒩 (11.2)
Telegram: @ElectricalDocument
11.2 Primary feeder reconfiguration 197
where 𝐼𝒩 and 𝑉𝒩 are the vectors of nodal current and voltage, and 𝐼ℰ , 𝑉ℰ are
the vectors of branch current and voltage, respectively. The Ohm’s law in each
edge and the power balance in each node are also included into the model as
follows:
Telegram: @ElectricalDocument
198 11 Active distribution networks
has |ℰ|−1 node and second, the graph must be connected. The first observation
can be imposed in the model as the following affine constraint:
∑
𝜇𝑘𝑚 = 𝑛 − 1 (11.12)
𝑘𝑚∈ℰ
where 𝑛 is the number of nodes. In this way, we ensure there are only 𝑛 − 1
switches connected in the grid. The second condition can be imposed by
noticing that the Laplacian matrix associated to the graph must be diagonally
dominant. The Laplacian matrix 𝑊 is defined as follows:
𝑊 = 𝐴 diag(𝜇)𝐴⊤ (11.13)
where diag(𝜇) is a diagonal matrix of size |ℰ| × |ℰ|. We could impose a con-
straint such that 𝑊 is positive semidefinite in which case, we would obtain a
semidefinite programming problem. However, it is straightforward to impose a
simple linear constraint related to the diagonal-dominant characteristic of the
Laplacian matrix, namely:
∑
𝑤𝑘𝑘 ≥ 𝑤𝑘𝑚 , ∀𝑘 (11.14)
𝑚
Vnode_real = cvx.Variable(num_nodes)
Vnode_imag = cvx.Variable(num_nodes)
Inode_real = cvx.Variable(num_nodes)
Inode_imag = cvx.Variable(num_nodes)
Vedge_real = cvx.Variable(num_edges)
Vedge_imag = cvx.Variable(num_edges)
Iedge_real = cvx.Variable(num_edges)
Iedge_imag = cvx.Variable(num_edges)
Jedge_real = cvx.Variable(num_edges)
Jedge_imag = cvx.Variable(num_edges)
W = cvx.Variable((num_nodes,num_nodes))
mu = cvx.Variable(num_edges, integer=True)
Telegram: @ElectricalDocument
11.2 Primary feeder reconfiguration 199
for k in range(num_edges):
re += [-mu[k]*deltaI_real[k] <= Iedge_real[k]]
re += [-mu[k]*deltaI_imag[k] <= Iedge_imag[k]]
re += [Iedge_real[k] <= mu[k]*deltaI_real[k]]
re += [Iedge_imag[k] <= mu[k]*deltaI_imag[k]]
re += [Iedge_real[k] <= Jedge_real[k]+(1-mu[k])
*deltaI_real[k]]
re += [Iedge_imag[k] <= Jedge_imag[k]+(1-mu[k])
*deltaI_imag[k]]
re += [Iedge_real[k] >= Jedge_real[k]-(1-mu[k])
*deltaI_real[k]]
re += [Iedge_imag[k] >= Jedge_imag[k]-(1-mu[k])
*deltaI_imag[k]]
fo = cvx.Minimize(Inode_real[0])
Reconfiguration = cvx.Problem(fo,re)
Telegram: @ElectricalDocument
200 11 Active distribution networks
Telegram: @ElectricalDocument
11.3 Optimal placement of capacitors 201
min 𝑓objective
∑∑
𝑝𝐿 ≥ real ( 𝑦𝑘𝑚 𝑣𝑘 𝑣𝑚 )
𝑘 𝑚
𝑣0 = 1 + 0𝑗
𝛿 ≥ ‖𝑣𝑘 − 1‖ , ∀𝑘 ∈ 𝒩
max
𝑖𝑘𝑚 ≥ ‖𝑦𝑘𝑚 (𝑣𝑘 − 𝑣𝑚 )‖ , ∀𝑘𝑚 ∈ ℰ (11.15)
∑
𝑠𝑘∗ − 𝑑𝑘∗ − 𝑗𝜉𝑘 𝑞nom = 𝑦𝑘𝑚 𝑣𝑘∗ 𝑣𝑚 , ∀𝑘 ∈ 𝒩
𝑚
‖𝑠𝑘 ‖ ≤ 𝑠𝑘max , ∀𝑘 ∈ 𝒩
∑
𝜉𝑘 ≤ 𝜉 available
𝑘
𝜉𝑘 ∈ {0, 1} , ∀𝑘 ∈ 𝒩
Where 𝑞nom is the nominal value of the shunt capacitors to be placed in the
feeder and 𝜉𝑘 is a binary variable that indicates the placement of one capacitor
in node 𝑘; the amount of capacitors to be placed in the feeder is limited by
𝜉 available ; the rest of the variables and constraints have the same interpretation
as the OPF problem studied in Chapter 10.
Model Equation (11.15) has two sources of complexity: first, power flow
equations are non-affine; and second, the problem is mixed-integer. The first
issue can be addressed by using convex approximations, whereas the second
issue is solved directly by CvxPy. Both linearization or conic approximations
(i.e., SOC and SDP) can be used in this problem. A linearization is convenient
since the model results in mixed-integer quadratic programming (MIQP), and
these type of models are solvable in practice; the quadratic term comes from
the power loss equation, which is convex. SOC and SDP approximations result
in mixed-integer second-order and mixed-integer semidefinite programming
problems, which are computationally more demanding.
We may be interested in minimizing operation costs in a planning period
(e.g., one year). In that case, the objective function includes costs associated
with the power and energy losses, as well as the cost of installation of shunt
capacitors. The objective function is therefore given by Equation (11.16):
where 𝑒𝐿 is the energy loss, and 𝑓loss , 𝑓installation are functions of annual costs
and installation, respectively. These functions are usually linear. The number
of binary variables is the same in this case, but the feeder requires to be repre-
sented in a load curve in order to calculate both power and energy losses. Some
Telegram: @ElectricalDocument
202 11 Active distribution networks
0 1 2 3 4 5 6 7
countries have different penalization costs for power and energy loss, and then
the model requires to be adapted to each grid code.
Example 11.2. Let us consider the 8-nodes primary feeder shown in Figure
11.2; loads are depicted in the figure and impedance is 𝑧𝑘𝑚 = 0.01 + 0.005𝑗 for
all line segments. We already calculated the matrix 𝑌bus and have a vector 𝑑 of
size 𝑛 that stores the loads; up to 0.01pu reactive power compensation will be
allowed. The optimization model is presented below:
n = 8
v = cvx.Variable(n,complex=True) # voltages
W = cvx.Variable((n,n),complex=True) # linearization
s0 = cvx.Variable(complex=True) # power at slack
xi = cvx.Variable(n, boolean=True) # shunt capacitors
pL = cvx.Variable() # power loss
s = n*[0]
s[0] = s0
M = Ybus@W
res = [pL >= cvx.quad_form(cvx.real(v),Ybus.real)+
cvx.quad_form(cvx.imag(v),Ybus.real)]
res += [v[0]==1.0]
for k in range(n):
res += [cvx.conj(s[k]+0.01j*xi[k]-d[k]) == M[k,k]]
res += [cvx.abs(v[k]-1) <= 0.1]
res += [xi[k]>= 0]
res += [xi[k]<= 1]
for m in range(n):
res += [W[m,k] == cvx.conj(v[k])+v[m]-1]
res += [cvx.sum(xi) <= 1]
obj = cvx.Minimize(pL)
OPCAP = cvx.Problem(obj,res)
OPCAP.solve()
print(’pL’,pL.value)
print(’shunt capacitors’, np.round(xi.value))
Telegram: @ElectricalDocument
11.4 Optimal placement of distributed generation 203
Therefore, the optimization model returns not only the placement of the
component but also the reactive power that must inject into the grid.
Telegram: @ElectricalDocument
204 11 Active distribution networks
min 𝑝𝐿
∑∑
𝑝𝐿 ≥ real ( 𝑦𝑘𝑚 𝑣𝑘 𝑣𝑚 )
𝑘 𝑚
𝑣0 = 1 + 0𝑗
𝛿 ≥ ‖𝑣𝑘 − 1‖ , ∀𝑘 ∈ 𝒩
max
𝑖𝑘𝑚 ≥ ‖𝑦𝑘𝑚 (𝑣𝑘 − 𝑣𝑚 )‖ , ∀𝑘𝑚 ∈ ℰ (11.18)
∑
𝑠𝑘∗ − 𝑑𝑘∗ = 𝑦𝑘𝑚 𝑣𝑘∗ 𝑣𝑚 , ∀𝑘 ∈ 𝒩
𝑚
‖𝑠𝑘 ‖ ≤ 𝜉𝑘 𝑠nom , ∀𝑘 ∈ 𝒩
∑
𝜉𝑘 ≤ 𝜉 max
𝑚
𝜉𝑘 ∈ {0, 1} , ∀𝑘 ∈ 𝒩
n = G.number_of_nodes()
d = np.array([G.nodes[k][’d’] for k in G.nodes])
nt = 2
v = cvx.Variable(n,complex=True)
W = cvx.Variable((n,n),complex=True)
s = cvx.Variable(n,complex=True)
xi = cvx.Variable(n,nonneg=True)
pL = cvx.Variable()
M = Ybus@W
res = [pL >= cvx.quad_form(cvx.real(v),Ybus.real)+
cvx.quad_form(cvx.imag(v),Ybus.real)]
res += [v[0]==1.0]
for k in range(n):
res += [cvx.conj(s[k]-d[k]) == M[k,k]]
res += [cvx.abs(v[k]-1) <= 0.05]
Telegram: @ElectricalDocument
11.5 Hosting capacity of solar energy 205
for m in range(n):
res += [W[m,k] == cvx.conj(v[k])+v[m]-1]
for k in range(1,n): # except the slack
res += [cvx.abs(s[k]) <= 0.02*xi[k]]
res += [xi[k]>=0, xi[k]<=1]
res += [cvx.sum(xi) <= nt]
obj = cvx.Minimize(pL)
HOSTCAP = cvx.Problem(obj,res)
HOSTCAP.solve()
print(HOSTCAP.status,obj.value)
print(np.round(xi.value,3))
Telegram: @ElectricalDocument
206 11 Active distribution networks
In this model, ℎ𝑘 represents the maximum active power that can host each
Node 𝑘; the objective function measures the maximum amount of power that
can host the system, subject to the power flow equations and limits of volt-
age and current flow; 𝜌 represents the minimum power factor in each power
electronic converter.
There are different metrics to measure the hosting capacity, for instance we
may be interested in maximizing the total distributed generation, in that case
the objective function is given by Equation (11.20),
∑
𝑓objective = ℎ𝑘 (11.20)
𝑘
However, it may be the case that most of the distribution generation con-
centrates in a single node. To solve this problem, a metric based on the
hypervolume of the new distribution generation is proposed, namely:
∏
max ℎ𝑘 (11.21)
𝑘
∏
where represents the product among the active power generated in the grid.
In order to understand the logic behind Equation Equation (11.21) consider a
system with two distributed generators ℎ1 , ℎ2 with two possible configurations
shown in Figure 11.3. Both configurations host the same amount of distributed
generation, i.e., host(𝐴) = 60MW + 40MW = 100MW and host(𝐵) = 90MW +
10MW = 100MW; however, 𝐵 concentrates most of the power in one node
whereas 𝐴 distribute the power more equitably; this can be measured by the
area(𝐴) = 2400, that is greater than area(𝐵) = 2000. In a system with three
generators, we can calculate the volume vol = ℎ1 ℎ2 ℎ3 instead of the area, and
in the general case we can calculate the hypervolume given by Equation (11.21).
Telegram: @ElectricalDocument
11.5 Hosting capacity of solar energy 207
Example 11.5. Let us define the hosting capacity of the 8-nodes radial distri-
bution network presented in Figure 11.2; we already defined a graph G with all
the parameters of the grid. The code in Python for Model Equation (11.23) is
presented below:
n = G.number_of_nodes()
d = np.array([G.nodes[k][’d’] for k in G.nodes])
v = cvx.Variable(n,complex=True)
W = cvx.Variable((n,n),complex=True)
s = cvx.Variable(n, complex=True)
h = cvx.Variable(n)
M = Ybus@W
res = [v[0]==1.0]
for k in range(n):
res += [cvx.conj(s[k]-d[k]) == M[k,k]]
res += [cvx.abs(v[k]-1) <= 0.05]
for m in range(n):
res += [W[m,k] == cvx.conj(v[k])+v[m]-1]
htotal = 0
for k in range(1,n): # except the slack
htotal = htotal + h[k]
res += [cvx.abs(s[k]) <= 1.2*h[k]]
res += [cvx.real(s[k]) >= h[k]]
obj = cvx.Maximize(htotal)
HOSTCAP = cvx.Problem(obj,res)
HOSTCAP.solve()
print(HOSTCAP.status,obj.value)
print(’hosting:’,np.round(h.value,3))
After executed this code, a total power of 4.63pu is placed along the
feeder with ℎ = (0, 4.54, 0.03, 0.02, 0.01, 0.01, 0.01, 0.01)⊤ ; notice that most
of the new generation is concentrated in a single node. However, in
Telegram: @ElectricalDocument
208 11 Active distribution networks
2 See [88] for more details about modulation and control of power electronic converters, for
the integration of renewable energies.
Telegram: @ElectricalDocument
11.6 Harmonics and reactive power compensation 209
Figure 11.4 Schematic representation of the voltages and currents involved in the
model for reactive power compensation and harmonic filtering.
where 𝑇 = 1∕(2𝜋𝑓) and Φ = {𝐴, 𝐵, 𝐶}; notice that, minimizing line currents
entails optimization in the power losses of the system. The constraint indicates
that the instantaneous power delivered by the active filter is always zero in one
period. This implies that, in average, the active filter does not deliver power to
the grid.
This model is designed for real-time control, meaning that all variables are
time-dependent. The optimization model is solved using Lagrange multipliers;
therefore, the lagrangian function is calculated, namely:
𝑡+𝑇 𝑡+𝑇
1 ∑ 𝜆 ∑
ℒ(𝑢, 𝜆) = ∫ ( (𝑖𝑘 − 𝑢𝑘 )2 ) 𝑑𝑡′ + ∫ ( 𝑣𝑘 𝑢𝑘 ) 𝑑𝑡′ (11.25)
𝑇 𝑘∈Φ
𝑇 𝑘∈Φ
𝑡 𝑡
𝑡+𝑇
1
∫ (−2(𝑖𝑘 − 𝑢𝑘 ) + 𝜆𝑣𝑘 ) 𝑑𝑡 ′ = 0 (11.26)
𝑇
𝑡
For the integral to be zero, it is required that its integrand is also zero. Therefore,
we have the following expresion:
Telegram: @ElectricalDocument
210 11 Active distribution networks
Now, we integrate this expression and use the fact that the active filter does
not deliver power in a period. Therefore, the following expression is obtained:
𝑡+𝑇
1 ∑( )
∫ ( −2𝑖𝑘 𝑣𝑘 + 𝑣𝑘 𝑢𝑘 + 𝜆𝑣𝑘2 ) 𝑑𝑡 ′ = 0 (11.30)
𝑇 𝑘∈Φ
𝑡
2
−2𝑝 + 𝜆𝑣 = 0 (11.31)
2
and 𝑣 is the three-phase square voltage, given by the following expression:
𝑡+𝑇
2 1 ∑ 2
𝑣 = ∫ ( 𝑣𝑘 ) 𝑑𝑡 ′ (11.33)
𝑇 𝑘∈Φ
𝑡
2 2 2
= 𝑣𝐴(rms) + 𝑣𝐵(rms) + 𝑣𝐶(rms) (11.34)
Telegram: @ElectricalDocument
11.6 Harmonics and reactive power compensation 211
import NumPy as np
import matplotlib.pyplot as plt
t = np.linspace(0,2/60,100)
w = 2*np.pi*60
def three_phase(w,m,ph):
xA = m*np.cos(w*t+ph)
xB = m*np.cos(w*t+ph-2*np.pi/3)
xC = m*np.cos(w*t+ph+2*np.pi/3)
return xA, xB, xC
iA = iA+hA
iB = iB+hB
iC = iC+hC
This compensation not only reduces the harmonic contents of the line currents
but also achieves a unity power factor. The reader is invited to plot currents
𝑖𝑘 − 𝑢𝑘 and analyze the results.
Telegram: @ElectricalDocument
212 11 Active distribution networks
11.8 Exercises
1. Solve the problem presented in Example 11.2 using a SOC formulation for
the power flow equations. Compare the results.
2. Solve the problem of optimal placement of D-STATCOMs in the system
presented in Example 11.2. Use the same parameters of costs and 𝑞nom .
Telegram: @ElectricalDocument
11.8 Exercises 213
3. Find the optimal capacitor placement for the 34-bus test system presented in
Table 10.1 (Chapter 10); T1 represents the load factor for operation between
0h:8h, T2 for 8h:16h, and T3 for 16h:24h. Try different objective functions,
for example power loss, energy loss, and/or costs.
4. Solve the problem presented in Example 11.4 considering binary variables
𝜉𝑘 and 𝑠nom = 0.3pu.
5. Solve the problem presented in Example 11.4 using an SDP approximation
for the power flow equations. Compare the results.
6. Solve the primary feeder reconfiguration for the test system presented in
Table 11.2.
7. Solve the problem presented in Example 11.5 using a SOC approximation
for the power flow equations.
8. Consider the problem presented in Example 11.5 but now, a loop is created
connecting nodes 2 and 5. Compare the results.
9. Determine the hosting capacity for the power distribution network pre-
sented in Table 10.1 (Chapter 10).
10. The concept of hosting capacity can be extended to dc distribution grids.
Formulate and solve the problem in the 21-nodes dc-distribution system
presented in Table 10.2.
Telegram: @ElectricalDocument
214 11 Active distribution networks
12
Learning outcomes
𝑧 = ℎ(𝑥) + 𝑒 (12.1)
1 In our naive example, we have one state 𝑥 = 𝑖, two equation ℎ1 = 𝑅𝑖, ℎ2 = 𝑖, and two
measurements 𝑧1 = 𝑣, 𝑧2 = 𝑖.
Telegram: @ElectricalDocument
12.2 State estimation 217
simplicity, we focus on the unrestricted case, the reader who wishes to delve
into the subject can refer to [103].
In the classic formulation of the problem, the state variables 𝑥 are the nodal
voltage (magnitude and angle), whereas the measurements 𝑧 include volt-
age magnitudes, active and reactive power flows, active and reactive power
injections, and current magnitudes, among others. Modern state estimation
models include phasor measurement units which allow obtaining the angles
as real-time and synchronized measurements.
In general, Model (12.2) is non-convex since ℎ is made up of non-linear rela-
tions between states and measurements. In those cases, the problem is solved
using Newton-based methods without guarantee of finding the global opti-
mum. The general case includes inequality constraints, and hence it is solved
using interior-point methods, again, without a theoretical guarantee of conver-
gence or optimality. However, we are interested in linear measurement models
that make the problem convex and solvable in CvxPy. On the positive side, this
approach is close to reality to the extent that modern systems rely on PMUs,
which generate linear relationships between states and measurements. More-
over, we seek for toy-models that allow us to understand the problem and
solve it using the paradigm of disciplined convex optimization. On the negative
side, a state estimation algorithm is mainly designed for real-time operation,
and hence Python may not be the best option in practice since algorithms
implemented in Python tend to be slower than their counterpart in compiled
languages C or C++.
The most simple instance of the problem is the dc state estimation. In this
case, the grid is represented by the linear equations or DC power flow; hence,
the state of the system is given by the angle of nodal voltages 𝜃. Our objec-
tive is to find a vector 𝑥th that estimates 𝜃 using available measurements of
power at each substation. Three type of measurements are available as shown
in Figure 12.1, namely: nodal powers 𝑧p , power flows departing from the
node𝑧pf1 , and power flows arriving to the node 𝑧pf2 . Nodal powers and power
flows in the transmission lines are linearly related to the nodal powers as
follows:
𝑧p = 𝐵𝑥th + 𝑒p (12.3)
Telegram: @ElectricalDocument
218 12 State estimation and grid identification
Telegram: @ElectricalDocument
12.2 State estimation 219
Figure 12.2 Three-bus system. ▾ represents points with power metering systems.
have a linear relation with the nodal angles as given in (12.3) to (12.5) with the
following numerical values for matrices 𝐵 and 𝐻:
⎛ 1∕0.012 −1∕0.012 0 ⎞
𝐻 = ⎜ 1∕0.010 0 −1∕0.010 ⎟ (12.13)
⎜ ⎟
0 1∕0.011 −1∕0.011
⎝ ⎠
Let us suppose nodal powers are 𝑝 = (0.8, 0.7, −1.5)⊤ , therefore, nodal angles
𝜃 = th and power flows pf can be calculated as follows:
import networkx as nx
G = nx.DiGraph()
G.add_edges_from([(0,1),(0,2),(1,2)])
A = nx.incidence_matrix(G,oriented=True)
Y = 1/np.array([0.012,0.010,0.011])
B = [email protected](Y)@A.T
p = np.array([0.8,0.7,-1.5])
th = np.linalg.solve(B,p)
th = th - th[0] # the angle in the slack is 0
H = -np.diag(Y)@A.T
pf1 = H@th # power flow at the beginning of the line
pf2 = -pf1 # power flow at the end of the line
This is the real state of the grid, however, we can only obtain measurements
with normal distributed noise with zero mean and variance 𝜎𝑝 and 𝜎𝑓 for the
nodal powers and the power flows, respectively. This effect can be considered
as follows:
Telegram: @ElectricalDocument
220 12 State estimation and grid identification
sigma_p = 0.01
sigma_f = 0.01
zp = p + np.random.randn(3)*sigma_p
zf1 = pf1 + np.random.randn(3)*sigma_f
zf2 = pf2 + np.random.randn(3)*sigma_f
With these measurements we have all the elements to formulate Model (12.11)
as given below:
import cvxpy as cvx
Wp = (1/sigma_p**2)*np.identity(3)
Wf = (1/sigma_f**2)*np.identity(3)
x_th = cvx.Variable(3)
obj = cvx.Minimize(1/2*cvx.quad_form(zp-B@x_th,Wp)+
1/2*cvx.quad_form(zf1-H@x_th,Wf)+
1/2*cvx.quad_form(zf2+H@x_th,Wf))
res = [x_th[0] == 0]
WLS = cvx.Problem(obj,res)
WLS.solve(verbose=True)
We can know how accurate our model is by calculating the distance between 𝜃
(the real state) and 𝑥th (the estimation).
print(np.linalg.norm(x_th.value-th)*100)
The reader is invited to experiment with the model by executing the code
several times with different values of 𝜎p and 𝜎pf .
Example 12.2. Consider the power distribution grid depicted in Figure 10.1,
Chapter 10. The 𝑌bus is calculated as Example 10.2 and the real state of the sys-
tem is obtained by the load flow algorithm given in Example 10.3, then, nodal
values can be calculated as given below:
d = np.array([G.nodes[k][’d’] for k in G.nodes])
s = np.array([G.nodes[k][’smax’] for k in G.nodes])
Vn = LoadFlow(s[1:n],d[1:n])
In = Ybus@Vn
Sn = Vn*In.conj()
Let us suppose this is the real state of the system, however, we have only inac-
curate measurements of voltages and currents; this can be represented in the
model as measurements 𝑧𝑣 , 𝑧𝑖 with random noise, namely:
zv = Vn + np.random.randn(n)*0.001*np.exp(0.1j*np.random.
randn(n))
zi = In + np.random.randn(n)*0.0001*np.exp(0.1j*np.random.
randn(n))
Telegram: @ElectricalDocument
12.3 Topology identification 221
Both voltages and currents are inaccurate so we cannot rely on one to calcu-
late the other. However, we can generate the following measurement model in
complex variable:
𝑧𝑣 1 𝑒
( ) = ( 𝑛 ) 𝑥𝑣 + ( 𝑣 ) (12.14)
𝑧𝑖 𝑌bus 𝑒𝑖
where the state variables are represented by the vector 𝑥𝑣 that estimates the
nodal voltages and the measurements are 𝑧 = (𝑧𝑣 , 𝑧𝑖 )⊤ = (𝑉𝑛 + 𝑒𝑣 , 𝐼𝑛 + 𝑒𝑖 )⊤ .
The matrix 1𝑛 is the identity of size 𝑛 and the errors are given by (𝑒𝑣 , 𝑒𝑖 )⊤ . We
assume both voltages and currents has the same accuracy and hence the weight
matrix can be given as the identity. Therefore, Model (12.2) can be directly
implemented in Python as follows:
import cvxpy as cvx
xv = cvx.Variable(n, complex=True)
id = np.identity(n)
obj = cvx.Minimize(1/2*cvx.quad_form(zv-xv,id)+
1/2*cvx.quad_form(zi-Ybus*xv,id))
WLS = cvx.Problem(obj)
WLS.solve(verbose=True)
At first glance, it would seem illogical to calculate 𝑥𝑣 given that we have a set of
voltage measurements 𝑧𝑣 , however, note that 𝑥𝑣 has a smaller deviation from
the true state of the system 𝑉𝑛 (which we do not know in practice), thanks
to the information provided by the other measurements. Let us calculate this
deviation in percentage:
print(np.linalg.norm(zv-Vn)*100)
print(np.linalg.norm(xv.value-Vn)*100)
After executing this code, the deviation of 𝑧𝑣 with respect to 𝑉𝑛 is around 0.4%,
whereas the deviation of the estimation is around 0.03% (results can change
from one execution to another due to the random error introduced in the code).
Telegram: @ElectricalDocument
222 12 State estimation and grid identification
𝜇𝑘𝑚 ∈ {0, 1}
𝑉𝒩 = 𝐴 ⊤ 𝑉ℰ (12.15)
𝐼𝒩 = 𝐴𝐼ℰ
𝐼ℰ = 𝜇𝑌ℰ 𝑉ℰ
𝑖𝑘 = (𝑠𝑘 ∕𝑣𝑘 )∗
Telegram: @ElectricalDocument
12.3 Topology identification 223
where 𝜆𝑘𝑚 is an auxiliary complex variable related to the current for each
branch 𝑘𝑚 and 𝛿𝑘𝑚 is the current capacity of each branch.
Example 12.3. The mixed-integer model for topology identification in power
distribution is implemented in Python as follows:
Vnode_real = cvx.Variable(num_nodes)
Vnode_imag = cvx.Variable(num_nodes)
Inode_real = cvx.Variable(num_nodes)
Inode_imag = cvx.Variable(num_nodes)
Vedge_real = cvx.Variable(num_edges)
Vedge_imag = cvx.Variable(num_edges)
Iedge_real = cvx.Variable(num_edges)
Iedge_imag = cvx.Variable(num_edges)
Jedge_real = cvx.Variable(num_edges)
Jedge_imag = cvx.Variable(num_edges)
mu = cvx.Variable(num_edges, integer=True)
re = [mu >= 0, mu <= 1,
Vnode_real[0] == 1, Vnode_imag[0] == 0,
Vedge_real == A.T@Vnode_real, Vedge_imag ==
A.T@Vnode_imag,
Inode_real == A@Iedge_real, Inode_imag ==
A@Iedge_imag,
Jedge_real == Yedge_real@Vedge_real-Yedge_imag@
Vedge_imag,
Jedge_imag == Yedge_real@Vedge_imag+Yedge_imag@
Vedge_real]
for k in range(1,num_nodes):
re += [Inode_real[k]==S_real[k]*(2-Vnode_real[k])+
Telegram: @ElectricalDocument
224 12 State estimation and grid identification
S_imag[k]*(Vnode_imag[k])]
re += [Inode_imag[k]==S_real[k]*(Vnode_imag[k])-
S_imag[k]*(2-Vnode_real[k])]
for k in range(num_edges):
re += [-mu[k]*deltaI_real[k] <= Iedge_real[k]]
re += [-mu[k]*deltaI_imag[k] <= Iedge_imag[k]]
re += [Iedge_real[k] <= mu[k]*deltaI_real[k]]
re += [Iedge_imag[k] <= mu[k]*deltaI_imag[k]]
re += [Iedge_real[k] <= Jedge_real[k]+(1-mu[k])
*deltaI_real[k]]
re += [Iedge_imag[k] <= Jedge_imag[k]+(1-mu[k])
*deltaI_imag[k]]
re += [Iedge_real[k] >= Jedge_real[k]-(1-mu[k])
*deltaI_real[k]]
re += [Iedge_imag[k] >= Jedge_imag[k]-(1-mu[k])
*deltaI_imag[k]]
fo = cvx.sum([email protected](Iedge_real-IE.real))
fo += cvx.sum([email protected](Iedge_imag-IE.imag))
Identification = cvx.Problem(cvx.Minimize(fo),re)
Identification.solve(verbose=True)
where the input are the measurements IE, the incidence matrix A, and
the pseudo-measurements of power S_real and S_imag. The model
was separated into real and imaginary parts in order to simplify its
implementation.
As the norm of a vector, a matrix norm is a convex function that may be used as
the objective function is convex optimization problems implemented in CvxPy.
Consider a power grid in which all nodes are equipped with PMUs that
allow measuring both voltages and currents. Let us assume we do not know
the exact values of the parameters of the transmission lines and the topology of
Telegram: @ElectricalDocument
12.4 Ybus estimation 225
3 4
PMU PMU
PMU PMU
central computer
1 2
Figure 12.3 Four-node grid with PMUs in all nodes for 𝑌bus identification.
the grid, and therefore, an 𝑌bus estimation algorithm is required. A central com-
puter receives and stores the information for different scenarios as depicted in
Figure 12.3.
The basic estimation algorithm is defined as the following unconstrained
optimization problem:
2
min ‖𝑌𝑉 − 𝐼‖ (12.19)
𝑌
where ‖⋅‖ is any matrix norm, 𝑉 and 𝐼 are matrices of size 𝑛𝑛 × 𝑛𝑠 with 𝑛𝑛 the
number of nodes and 𝑛𝑠 the number of scenarios. Notice this optimization prob-
lem is defined in the set of the complex matrices and not in the set of vectors as
in the optimization problems presented in previous chapters.
The model may be complemented with additional constraints related to the
main features of the 𝑌bus . For instance, we know it is symmetric, meaning that
𝑌 = 𝑌⊤ (12.20)
Telegram: @ElectricalDocument
226 12 State estimation and grid identification
Example 12.4. Let us estimate the 𝑌bus for the system shown in Figure 12.3.
Our example is divided into three parts: first, we generate the exact model of
the grid, in order to obtain the correct value of the 𝑌bus ; then, a random set of
measurement scenarios are generated with this matrix; and finally, the 𝑌bus is
estimated by the proposed optimization model.
We use the module NetworkX for generating the 𝑌bus as presented below;
parameters of the transmission lines are included in the code:
import numpy as np
import networkx as nx
Grid = nx.DiGraph()
Grid.add_edges_from(((1,2),(2,3),(3,4),(4,1)))
Yp = 1/np.array([0.002+0.02j,0.001+0.03j,0.001+0.02j,
0.001+0.04j])
A = nx.incidence_matrix(Grid,oriented=True)
Ybus = [email protected](Yp)@A.T
Now, we generate a set of random scenarios for the voltages around 1pu
and next, these voltages are used to calculate nodal currents for each scenario.
Finally, a random noise is added in order to emulate possible inaccuracies of
the measure devices. The code in Python is presented below:
nn = 4 # number of nodes
ns = 20 # number of scenarios
v = 0.9*np.ones((nn,ns))+0.2*np.random.random((nn,ns))
a = np.random.random((nn,ns))-0.5
Vbus = v*np.exp(a*1j)
Ibus = Ybus@Vbus + np.random.normal(0,0.1,(nn,ns))
Ibus = Ibus + 1j*np.random.normal(0,0.1,(nn,ns))
The result of this model is different each time the script is executed due to the
random scenarios. However, the order of magnitude of the error is the same
according to the number of scenarios. The script was executed with a different
number of scenarios, and the results are shown in Figure 12.4; it shows that
a high number of scenarios does not necessarily increase the accuracy of the
estimation.
Telegram: @ElectricalDocument
12.4 Ybus estimation 227
Example 12.5. Consider now the previous example with semidefinite con-
traints as follows:
Y = cvx.Variable((nn,nn), complex=True)
fo = cvx.Minimize(cvx.norm(Y@Vbus-Ibus))
re = [Y==Y.T, cvx.real(Y) >> 0, -cvx.imag(Y)>>0]
Est2 = cvx.Problem(fo,re)
Est2.solve()
print(np.linalg.norm(Y.value-Ybus))
The reader is invited to execute the script for different number of scenarios 𝑛𝑠 .
In general, the positive semidefinite constraints does not improve the accuracy
of the solution for a large set of scenarios (e.g 𝑛𝑠 = 20), and instead, the time
calculation is highly increased. However, for a small data set (for instance 𝑛𝑠 =
3), the semidefinite constraints highly improve the results.
Example 12.6. We can show that the following conditions hold in the grid of
Example 12.4:
∑
𝑔𝑘𝑘 ≥ −𝑔𝑘𝑚
𝑚≠𝑘
∑
−𝑏𝑘𝑘 ≥ 𝑏𝑘𝑚 (12.21)
𝑚≠𝑘
This conditions are general, easy to implement, and less time-consuming that
semidefinite constraints, for problems with few measurement scenarios. A
script with this constraints is presented below:
Y = cvx.Variable((nn,nn), complex=True)
fo = cvx.Minimize(cvx.norm(Y@Vbus-Ibus))
re = [Y==Y.T]
re += [cvx.real(Y[0,0]) >= -cvx.real(Y[0,1]+Y[0,2]+Y[0,3])]
re += [cvx.real(Y[1,1]) >= -cvx.real(Y[1,0]+Y[1,2]+Y[1,3])]
re += [cvx.real(Y[2,2]) >= -cvx.real(Y[2,0]+Y[2,1]+Y[2,3])]
re += [cvx.real(Y[3,3]) >= -cvx.real(Y[3,0]+Y[3,1]+Y[3,2])]
re += [-cvx.imag(Y[0,0]) >= cvx.imag(Y[0,1]+Y[0,2]+Y[0,3])]
Telegram: @ElectricalDocument
228 12 State estimation and grid identification
The student is invited to compare results with the previous examples for 𝑛𝑠 = 3.
where 𝑝0 , 𝑞0 , and 𝑣 represent the nominal active/reactive power and the nodal
voltage in per unit. Each coefficient in the quadratic form has a physical mean-
ing according to the type of load, thus 𝑐𝑝 and 𝑐𝑞 represent constant-power loads
whereas coefficients of the linear part (𝑏𝑝 and 𝑏𝑞 ) represent constant-current
loads and, coefficient associated to the quadratic terms (𝑎𝑝 and 𝑎𝑞 ) represent
constant-impedance loads. This model is known as ZIP model since each term
represent the percentage of constant impedance loads (Z), constant current
loads, (I) and constant power loads (P). Therefore, all coefficients in the model
are positive and the following constraints hold:
𝑎𝑝 + 𝑏𝑝 + 𝑐𝑝 = 1 (12.24)
𝑎𝑞 + 𝑏𝑞 + 𝑐𝑞 = 1 (12.25)
3 The model for the reactive power has the same structure.
Telegram: @ElectricalDocument
12.5 Load model estimation 229
𝑛−1
1 ∑( )2
min 𝑎 𝑣 2 + 𝑏𝑝 𝑣𝑘 + 𝑐𝑝 − 𝑟𝑝 𝑝 𝑘
2 𝑘=0 𝑝 𝑘
𝑎 𝑝 + 𝑏𝑝 + 𝑐𝑝 = 1 (12.26)
𝑎𝑝 , 𝑏 𝑝 , 𝑐 𝑝 , 𝑟 𝑝 ≥ 0
where 𝑝𝑘 and 𝑣𝑘 are measures of power and nodal voltage with dim(𝑝) =
dim(𝑣) = 𝑛 and 𝑟𝑝 = 1∕𝑝0 . The objective is to minimize the sum of the squares
of the error between the data and the model, subject to (12.24). Notice that
Model (12.26) is convex and can be easily solved using CvxPy. This model can
be executed for a database grouped by hours, in order to obtain values of each
hour of the day, but can be also executed to evaluate the average behavior of
the load.
Example 12.7. Let us see how Model (12.26) works in practice; first, we gen-
erate a set of 𝑛 = 800 synthetic measurements of voltage and active/reactive
power. Voltages are randomly generated through a normal distribution such
that most of the data is between 0.95 and 1.05. To do this, we define a mean of
1 and a standard deviation of 0.05∕3 (thus, the 98% of the data falls into this
interval). Active and reactive power are calculated by a predefined ZIP model
with additional noise, also generated by a normal distribution as follows:
import numpy as np
n = 800
v = np.random.normal(1,0.05/3,n)
p = 1.2*(0.3*v**2+0.2*v+0.5) + np.random.normal(0,0.004,n)
q = 0.2*(0.6*v**2+0.2*v+0.2) + np.random.normal(0,0.001,n)
Figure 12.5 shows the results for one execution of this code.
A script for the estimation of the ZIP model for the active power is straight-
forward for this case:
ap = cvx.Variable(nonneg=True)
bp = cvx.Variable(nonneg=True)
cp = cvx.Variable(nonneg=True)
rp = cvx.Variable(nonneg=True)
fo = cvx.Minimize(1/2*cvx.sum((ap*v**2+bp*v+cp-rp*p)**2))
re = [ap+bp+cp == 1]
Model = cvx.Problem(fo,re)
Model.solve()
The student is invited to execute the script and evaluate the accuracy of the
estimation, taking into account this synthetic data set is perhaps more distorted
than actual measurements. More general models are possible, including the
Telegram: @ElectricalDocument
230 12 State estimation and grid identification
Figure 12.5 Synthetic data of voltage and power for load estimation.
effect of the frequency. The structure of these models is also the least square
model and can be solved quickly, as presented here.
Example 12.8. The least square model for the load estimation can be solved
directly by relaxing inequality constraints. In that case, the Lagragian is given
by (12.27):
𝑛−1
1 ∑( )2
ℒ= 𝑎 𝑣2 + 𝑏𝑝 𝑣𝑘 + 𝑐𝑝 − 𝑟𝑝 𝑝𝑘 + 𝜆𝑝 (𝑎𝑝 + 𝑏𝑝 + 𝑐𝑝 − 1) (12.27)
2 𝑘=0 𝑝 𝑘
Telegram: @ElectricalDocument
12.6 Further readings 231
with
𝑛−1 𝑛−1
∑ ∑
𝜎𝑣4 = 𝑣𝑘4 𝜎𝑣3 = 𝑣𝑘3
𝑘=0 𝑘=0
𝑛−1 𝑛−1
∑ ∑
𝜎𝑣2 = 𝑣𝑘2 𝜎𝑣1 = 𝑣𝑘
𝑘=0 𝑘=0
(12.29)
𝑛−1 𝑛−1
∑ ∑
𝜎𝑝𝑣2 = 𝑝𝑘 𝑣𝑘2 𝜎𝑝𝑣1 = 𝑝𝑘 𝑣𝑘
𝑘=0 𝑘=0
𝑛−1 𝑛−1
∑ ∑
𝜎𝑝1 = 𝑝𝑘 𝜎𝑝2 = 𝑝𝑘2
𝑘=0 𝑘=0
By solving this five linear system, we may obtain the values of 𝑎𝑝 , 𝑏𝑝 , 𝑐𝑝 , and
𝑟𝑝 ; however, in some pathological cases, the values may be negatively violating
the inequality constraint.
Telegram: @ElectricalDocument
232 12 State estimation and grid identification
12.7 Exercises
1. Solve the dc state estimation problem presented in Example 12.1 including
PMUs measurements of the angles of the system, that is, including a new
set of measurements 𝑧𝜃 = (𝜃0 , 𝜃1 , 𝜃2 )⊤ + (𝑒𝜃1 , 𝑒𝜃2 , 𝑒𝜃2 )⊤ with 𝜎𝜃 = 1 × 10−6 .
Compare the results with the classic problem without PMUs.
2. Solve the ac state estimation problem presented in Example 12.2, includ-
ing nodal and branch power flows measurements. Formulate a second-order
approximation to make the problem convex.
3. Repeat the previous problem using a semidefinite approximation.
4. Solve the non-convex formulation of the state estimation problem, consider-
ing nodal and branch power flows measurements, using Newton’s method.
Compare results with the previous problems.
5. Solve the topology identification problem on the IEEE 33-bus test system
presented in Table 11.2, Chapter 11.
6. Prove that the matrix norm defined as (12.18) has the following property:
7. The gradient method may be also used in matrix functions. Consider the
following optimization problem:
1 2
min 𝑓(𝑋) = ‖𝐴𝑋 − 𝐵‖𝐹 (12.31)
2
where 𝐴, 𝐵, 𝑋 are square matrices and ‖⋅‖𝐹 is the Frobenius norm, defined
as (12.32).
√
‖𝑋‖ = tr(𝑋𝑋 ⊤ ) (12.32)
Telegram: @ElectricalDocument
12.7 Exercises 233
Telegram: @ElectricalDocument
Telegram: @ElectricalDocument
235
13
Demand-side management
Learning outcomes
(kW)
load shift
time(h)
load (kW)
time(h)
Figure 13.1 Example of a shifting load. In both cases the shape and the total energy
are the same, but the peak as moved.
⎛ 0 1 0 0 … 0 0 ⎞
⎜ 0 0 1 0 … 0 0 ⎟
⎜ 0 0 0 1 … 0 0 ⎟
𝑀=⎜ 0 0 0 0 … 0 0 ⎟ (13.1)
⎜ ⎟
⋮ ⋮ ⋮ ⋮ ⋮ ⋮
⎜ ⎟
⎜ 0 0 0 0 … 0 1 ⎟
⎝ 1 0 0 0 … 0 0 ⎠
This matrix shifts the load in one position, that is it returns the same load curve
but delayed in one hour; thus, the shifted load is a vector given by the expression
𝑝 = 𝑀𝑠, which returns 𝑝2 = 𝑠1 , 𝑝3 = 𝑠2 , 𝑝4 = 𝑠3 and so on, until 𝑝24 = 𝑠23 and
finally, 𝑝1 = 𝑠24 . If we desire to shift the load in two positions, then we must
use twice the same permutation, namely 𝑝 = 𝑀𝑀𝑠 = 𝑀 2 𝑠. In general, a shift
permutation of 𝑘 positions is given by Equation (13.2):
𝑝 = 𝑀𝑘 𝑠 (13.2)
Telegram: @ElectricalDocument
13.1 Shifting loads 237
min 𝑐⊤ 𝑝total
∑
𝑝total = 𝑝𝑖
𝑖∈𝒟
∑
𝑝𝑖 = ( 𝑥𝑖𝑘 𝑀 𝑘 ) 𝑠𝑖 , ∀𝑖 ∈ 𝒟 (13.3)
𝑘
∑
𝑥𝑖𝑘 = 1, ∀𝑖 ∈ 𝒟
𝑘
𝑥𝑖𝑘 ∈ {0, 1}
where 𝑐 is the vector of energy cost for 24 h operation; 𝑥𝑖𝑘 is a binary vari-
able which is 1 if the load 𝑖 is shifted to 𝑘 positions; and 𝑀 is the one-shift
permutation given by Equation (13.1). The objective function seeks to mini-
mize total costs, subject to the energy balance. Additional constraint may be
included, such as maximum peak load 𝑝total ≤ 𝑝max and hours of banned oper-
ation (e.g, we might avoid operation between 0:00 and 7:00 AM). Notice that
Equation (13.3) is a mixed-integer programming problem, since 𝑀 𝑘 is constant.
Example 13.1. Let us make a small experiment to see the properties of the
cyclic permutation matrices. In the script below, we create the matrix 𝑀 and
a permutation 𝑀 𝑘 with 𝑘 as input. The result is the expected permutation
according to 𝑘.
import numpy as np
M = np.zeros((24,24))
M[23,0] = 1
for k in range(23):
M[k,k+1] = 1
t = int(input(’Enter the time shifting:’))
p = np.linspace(1,24,24)
R = np.linalg.matrix_power(M,t)
m = p @ R
for k in range(24):
print(p[k],’->’,m[k])
The student is invited to use different integer values of 𝑘, even values greater
than 24.
Example 13.2. An industry has three specific loads that correspond to a dif-
ferent industrial process. These loads can be shifted in order to minimize total
costs. The capability of the transformer is 𝑝max = 20 and no process can be per-
formed between 0:00 and 6:00 AM. Table 13.1 shows the data for the current
operation.
Telegram: @ElectricalDocument
238 13 Demand-side management
0 460 0 0 0
1 450 0 0 0
2 450 0 0 0
3 450 0 0 0
4 470 0 0 0
5 470 0 0 0
6 500 0 0 0
7 530 0 0 2
8 580 5 0 3
9 600 10 3 4
10 620 10 4 10
11 600 8 10 12
12 600 5 12 7
13 600 3 9 5
14 580 0 8 4
15 570 0 5 0
16 560 0 0 0
17 565 0 0 0
18 550 0 0 0
19 610 0 0 0
20 650 0 0 0
21 650 0 0 0
22 610 0 0 0
23 500 0 0 0
The following code shows the implementation of Model Equation (13.3) for
these three loads. First, we load the data, which was stored in a CSV file named
Table.csv.
import numpy as np
import matplotlib.pyplot as plt
from pandas import read_csv
import cvxpy as cvx
Telegram: @ElectricalDocument
13.1 Shifting loads 239
data = read_csv(’Table.csv’)
c = data[’Price’].to_numpy(dtype= float)
s1 = data[’Load 1’].to_numpy(dtype= float)
s2 = data[’Load 2’].to_numpy(dtype= float)
s3 = data[’Load 3’].to_numpy(dtype= float)
M = np.zeros((24,24))
M[23,0] = 1
for k in range(23):
M[k,k+1] = 1
x1 = cvx.Variable(24,boolean=True)
x2 = cvx.Variable(24,boolean=True)
x3 = cvx.Variable(24,boolean=True)
pt = cvx.Variable(24)
p1 = cvx.Variable(24)
p2 = cvx.Variable(24)
p3 = cvx.Variable(24)
u = np.ones(24)
pmax = 20
Eq1 = 0
Eq2 = 0
Eq3 = 0
for k in range(24):
Eq1 = Eq1 + x1[k]*np.linalg.matrix_power(M,k)@s1
Eq2 = Eq2 + x2[k]*np.linalg.matrix_power(M,k)@s2
Eq3 = Eq3 + x3[k]*np.linalg.matrix_power(M,k)@s3
res = [pt == p1+p2+p3,
pt <= pmax,
p1 == Eq1,
p2 == Eq2,
p3 == Eq3,
cvx.sum(x1) == 1,
cvx.sum(x2) == 1,
cvx.sum(x3) == 1,
pt[0:6] == 0]
fo = cvx.Minimize(c.T@pt)
SL = cvx.Problem(fo,res)
SL.solve()
Most of the code is self-explanatory. Notice there are only 24 binary variables
for each load in this Model. The rest of the variables are continuous.
Results are shown in Figure 13.2. Initial loads are shown at the top, while
shifted loads are shown at the bottom. Notice the peak of the load was 30 kW
in the first case, while the new peak is only 20 in the shifted loads. The shifting
Telegram: @ElectricalDocument
240 13 Demand-side management
Figure 13.2 Results for the shifting load problem. Original loads (top), shifted loads
(bottom).
load optimization reduces by 5% the total cost. A great reduction taking into
account we only required to move the loads in time.
2 See [113] for more details about the general assignment problem.
Telegram: @ElectricalDocument
13.2 Phase balancing 241
⎛ 𝑑0 ⎞
⎛ 𝑝𝐴 ⎞ ⎛ 𝑥𝐴0 𝑥𝐴1 … 𝑥𝐴𝑛−1 ⎞
⎜ 𝑑1 ⎟
⎜ 𝑝𝐵 ⎟ = ⎜ 𝑥𝐵0 𝑥𝐵1 … 𝑥𝐵𝑛−1 ⎟ ⎜ (13.4)
⋮ ⎟
⎜ ⎟ ⎜ ⎟
𝑝𝐶 𝑥𝐶0 𝑥𝐶1 … 𝑥𝐶𝑛−1 ⎜ ⎟
⎝ ⎠ ⎝ ⎠ 𝑑𝑛−1
⎝ ⎠
1
𝜓= (‖𝑝𝐴 − 𝑝mean ‖ + ‖𝑝𝐵 − 𝑝mean ‖ + ‖𝑝𝐶 − 𝑝mean ‖) (13.6)
3
where 𝑝𝐴 , 𝑝𝐵 , 𝑝𝐶 are the total power in each phase and, 𝑝mean is the average
power per phase given by Equation (13.7),
𝑝𝐴 + 𝑝𝐵 + 𝑝𝐶
𝑝mean = (13.7)
3
Telegram: @ElectricalDocument
242 13 Demand-side management
𝑥𝑖𝑗 ∈ {0, 1}
Example 13.3. Let us balance a system with nine single-phase loads given by
a vector 𝑑 = (5, 8, 7, 3, 5, 5, 3, 4, 4)⊤ kW. The model consists in Equations (13.4)
to (13.7) with 𝑥 a Boolean matrix:
The optimal value is 𝜓 = 0.444 with a total power of 15 kW in two of the phases
and 14 kW in the remaining phase. This solution is, of course, not unique since
there are different manners to obtain the same unbalance index. The student
is invited to test different solvers for the Model and create instances with more
loads.
The previous Model is valid for single-phase loads. In the case of three-phase
loads, the assignment model must take into account that each phase of the load
Telegram: @ElectricalDocument
13.2 Phase balancing 243
⎛ 1 0 0 ⎞
𝑀0 ⎜ 0 1 0 ⎟ ABC +1
⎜ ⎟
⎝ 0 0 1 ⎠
⎛ 0 1 0 ⎞
𝑀1 ⎜ 0 0 1 ⎟ BCA +1
⎜ ⎟
⎝ 1 0 0 ⎠
⎛ 0 0 1 ⎞
𝑀2 ⎜ 1 0 0 ⎟ CAB +1
⎜ ⎟
⎝ 0 1 0 ⎠
⎛ 1 0 0 ⎞
𝑀3 ⎜ 0 0 1 ⎟ ACB −1
⎜ ⎟
⎝ 0 1 0 ⎠
⎛ 0 1 0 ⎞
𝑀4 ⎜ 1 0 0 ⎟ BAC −1
⎜ ⎟
⎝ 0 0 1 ⎠
⎛ 0 0 1 ⎞
𝑀5 ⎜ 0 1 0 ⎟ CBA −1
⎜ ⎟
⎝ 1 0 0 ⎠
3 det(𝑀𝑖 ) = 1 if the permutation maintains the sequence. A change in the sequence of the
load may have practical effects. For example, a reverse in the sequence of a motor causes an
opposite rotation.
4 Other representations are possible. However, this representation reduces the number of
binary variables. See Exercise 6 at the end of this chapter.
Telegram: @ElectricalDocument
244 13 Demand-side management
we assume only real power, but the model can be extended to consider active
and reactive power. A new vector of loads 𝑝𝑘 is defined with the required
permutation as given below:
𝑝𝑘 = (𝑥0𝑘 𝑀0 + 𝑥1𝑘 𝑀1 + 𝑥2𝑘 𝑀2 + 𝑥3𝑘 𝑀3 + 𝑥4𝑘 𝑀4 + 𝑥5𝑘 𝑀5 ) 𝑑𝑘 (13.9)
where 𝑥𝑖𝑘 is a binary variable which is 1 as the permutation 𝑖 is activated in
the load 𝑗. This decision must be univocal, so the following constrain must be
added:
𝑥0𝑘 + 𝑥1𝑘 + 𝑥2𝑘 + 𝑥3𝑘 + 𝑥4𝑘 + 𝑥5𝑘 = 1 (13.10)
Finally, the power per phase is represented by a vector 𝑠 ∈ ℝ3 and the average
power is represented by 𝑠mean . The mathematical model is given below:
1 ∑
min 𝜓 = ( |𝑠 − 𝑠𝑘 |)
3 𝑘∈Ω mean
5
∑
𝑝𝑘 = 𝑥𝑖𝑘 𝑀𝑖 𝑑𝑘 , ∀𝑘 ∈ 𝒟
𝑖=0
5
∑
𝑥𝑖𝑘 = 1, ∀𝑘 ∈ 𝒟
𝑖=0
1 ∑
𝑠mean = 𝑠 (13.11)
3 𝑘∈Ω 𝑘
𝑠𝑘 = 𝟙⊤ 𝑝
𝑥𝑖𝑘 ∈ {0, 1}
where Ω = {𝐴, 𝐵, 𝐶} represents the phases of the system. Notice this is a integer
linear programming model that can be easily coded in CvxPy. This is only a toy-
model, since the phase balance problem may be integrated with the power flow
equations to minimize power loss in power distribution systems. Interested
reader is referred to [114].
Example 13.4. Let us make an instance of Model Equation (13.11) for a system
with four loads 𝑑0 = (10, 12, 11)⊤ , 𝑑1 = (12, 15, 11)⊤ , 𝑑2 = (11, 12, 15)⊤ , 𝑑3 =
(13, 10, 12)⊤ . First, we define a list that contains the permutation matrices given
in Table 13.2:
import numpy as np
import cvxpy as cvx
M = []
M += [np.array([[1,0,0],[0,1,0],[0,0,1]])]
M += [np.array([[0,1,0],[0,0,1],[1,0,0]])]
M += [np.array([[0,0,1],[1,0,0],[0,1,0]])]
Telegram: @ElectricalDocument
13.2 Phase balancing 245
M += [np.array([[1,0,0],[0,0,1],[0,1,0]])]
M += [np.array([[0,1,0],[1,0,0],[0,0,1]])]
M += [np.array([[0,0,1],[0,1,0],[1,0,0]])]
num_loads = len(d.T)
x = cvx.Variable((6,num_loads),boolean=True)
p = cvx.Variable((3,num_loads))
s_mean = cvx.Variable()
s = cvx.Variable(3)
res = []
for k in range(num_loads):
res += [p[:,k] == (x[0,k]*M[0] +
x[1,k]*M[1] +
x[2,k]*M[2] +
x[3,k]*M[3] +
x[4,k]*M[4] +
x[5,k]*M[5])@d[:,k]]
res += [cvx.sum(x[:,k]) == 1]
res += [s_mean==sum(s)/3]
res += [s == sum(p.T)]
obj = cvx.Minimize(1/3*(cvx.abs(s_mean-s[0])+
cvx.abs(s_mean-s[1])+
cvx.abs(s_mean-s[2])))
PhaseBalancing = cvx.Problem(obj,res)
PhaseBalancing.solve()
This result could have been obtained by hand since the problem is quite simple.
However, the model is general for any number of loads. The student is invited
to generate more instances of the model with a high number of loads.
Telegram: @ElectricalDocument
246 13 Demand-side management
100
Net load
50
0
0 2 4 6 8 10 12 14 16 18 20 22
time (h)
Figure 13.4 Load curve in a typical day: (- -) normal load without solar generation,
(—) load curve including the effect of solar generation (duck curve).
5 This term was coined by the California Independent System Operator but now used in the
power system literature.
Telegram: @ElectricalDocument
13.3 Energy storage management 247
Let us define 𝑠𝑡 as the power generated by the solar system and 𝑔𝑡 as the power
injected by the main grid; 𝑝𝑡 is the power required by the storage system (in this
case a battery) and 𝑑𝑡 is the power required by the load. Therefore, the balance
of power in the common bus-bar is given by Equation (13.12):
𝑠𝑡 + 𝑔𝑡 = 𝑝𝑡 + 𝑑𝑡 (13.12)
where the sub-index 𝑡 indicates the time in hours for a operation in 24 h. Power
is measured in kW, time in h and energy in kWh; thus, the energy in the next
hour is given by Equation (13.13):
𝑒𝑡+1 = 𝑒𝑡 + 𝑝𝑡 (13.13)
By convention we assume 𝑝𝑡 > 0 for charging mode and 𝑝𝑡 < 0 for discharg-
ing mode. For the sake of simplicity we assume an ideal process with 100%
efficiency. Both the price of the energy 𝑐𝑡 , the power generated by the solar sys-
tem 𝑠𝑡 and, the load 𝑑𝑡 are known a priory via an accurate forecasting, so the
optimization model is a deterministic linear programming problem:
∑
min 𝑐𝑡 𝑔𝑡
𝑡
𝑔𝑡 + 𝑠𝑡 = 𝑝𝑡 + 𝑑𝑡
𝑒𝑡+1 = 𝑒𝑡 + 𝑝𝑡
0 ≤ 𝑒𝑡 ≤ 𝑒max (13.14)
|𝑝𝑡 | ≤ 𝑝max
𝑒0 = 0
Telegram: @ElectricalDocument
248 13 Demand-side management
As mentioned before, the objective is to minimize total costs, and the main
result is the schedule for charge and discharge of the battery. The following
example shows the use of the Model in practice.
Example 13.5. Table 13.3 shows a forecasting for solar generation, load and
price for a microgrid as the one shown in Figure 13.5. This table is stored in a
cvs file named Table.csv. We are going to use data frames in Pandas as a
tool for analysis and data manipulation.
Model Equation (13.14) is implemented in Python with 𝑒max = 100 kWh and
max
𝑝 = 30 kW. The battery start discharged at 𝑡 = 0. The corresponding code is
presented below:
import numpy as np
import matplotlib.pyplot as plt
import cvxpy as cvx
from pandas import read_csv
data = read_csv(’Table.csv’)
p_stor = cvx.Variable(24) # p>0 charging
p_grid = cvx.Variable(24) # p<0 discharging
e_stor = cvx.Variable(25)
pmax = 30
emax = 100
f = 0
res = [p_stor>=-pmax,
p_stor<= pmax,
e_stor>=0,
e_stor<=emax,
e_stor[0]==0]
for t in range(24):
f += data[’Price’][t]*p_grid[t]
res += [e_stor[t+1] == e_stor[t] + p_stor[t]]
res += [p_grid[t]+data[’Solar’][t]==p_stor[t]+data[’Load’][t]]
BM = cvx.Problem(cvx.Minimize(f),res)
BM.solve()
plt.subplot(3,1,1)
data[’Solar’].plot()
data[’Load’].plot()
plt.plot(p_stor.value)
plt.plot(p_grid.value)
plt.legend([’Solar’,’Load’,’Battery’,’Grid’])
plt.grid()
plt.ylabel(’Power (kW)’)
plt.subplot(3,1,2)
plt.plot(e_stor.value)
plt.grid()
plt.ylabel(’Energy (kWh)’)
Telegram: @ElectricalDocument
13.5 Exercises 249
plt.subplot(3,1,3)
data[’Price’].plot()
plt.ylabel(’Spot price ($/kW)’)
plt.grid()
plt.show()
As common along with the book, the reader is invited to do experiments with
this code. For example, compare results for larger values of 𝑝max and 𝑒max .
Compare the results with and without energy storage.
13.5 Exercises
1. Modify the Model presented in Example 13.5 for peak shaving. Compare
results with the case of cost minimization.
2. Evaluate Example 13.5 with different values of 𝑝max and 𝑒max for both cost
minimization and peak shaving. What is more important in each case, to
have a large energy storage capacity or a large power capacity?.
Telegram: @ElectricalDocument
250 13 Demand-side management
0 0 68.5 140
1 0 69.5 140
2 0 68 140
3 0 64.5 140
4 0 64.5 140
5 0 70.5 175
6 0 82.5 210
7 26 100 210
8 50 112 210
9 71 112 175
10 87 112.5 170
11 97 115.5 170
12 100 111.5 173
13 97 111 175
14 87 100 180
15 71 98 190
16 50 99 210
17 26 110 315
18 0 130 385
19 0 130 385
20 0 130 350
21 0 120 280
22 0 92.5 245
23 0 79.5 175
3. Modify the code presented in Example 13.1 to show the cyclic permutation
if the problem is divide into 15-minute intervals.
4. Modify Example 13.2 for minimization of the peak load.
5. Generate random instances with different sizes of the phase balancing prob-
lem presented in Example 13.3. Evaluate the quality of the solution and time
calculation according to the size of the problem. Use different solvers.
Telegram: @ElectricalDocument
13.5 Exercises 251
Formulate the phase balancing problem in these terms and compare the
solutions. How many binary variables are required in this formulation
compared to Model Equation (13.11)?
7. Solve the phase balancing problem for three-phase loads avoiding permuta-
tions that reverse the sequence.
8. Solve the phase balancing problem relaxing the binary variables. Use a
randomly generated instance of the problem with more than ten loads.
9. Formulate the phase balancing problem considering active and reactive
power. Propose a suitable objective function in this case.
10. Demand-side management is a vast area of research; there are many other
problems such as thermal loads and V2G that are closely related. Search on
the internet for these problems and formulate their corresponding models.
Telegram: @ElectricalDocument
Telegram: @ElectricalDocument
253
1 Notice that some books define the node–branch incidence matrix which is the transpose of
our definition.
The incidence matrix is used to define relations between nodal and branch
variables in a power grid. For instance, nodal currents can be calculated from
branch currents as presented below:
𝐼𝑁 = 𝐴𝐼𝐵 (A.2)
𝑉𝐵 = 𝐴 ⊤ 𝑉𝑁 (A.3)
Branch currents are in turns related to the branch voltages as given in (A.4)
which constitute a matrix representation of the Ohm’s law:
𝐼𝐵 = 𝑌𝐵 𝑉𝐵 (A.4)
𝐼𝑁 = 𝐴𝑌𝐵 𝐴⊤ 𝑉𝑁 (A.5)
From (A.5) we can obtain a direct definition of the nodal admittance matrix
𝑌bus :
This is, of course, one of many ways to obtain the 𝑌bus matrix. Another approach
consists in defining its entries directly as follows:
∑
𝑌bus (𝑖, 𝑖) = 𝑦𝑖𝑗 (A.7)
𝑖𝑗∈Ω𝑖
where 𝑦𝑖𝑗 is the admittance of each branch (𝑖𝑗) ∈ 𝐵 and Ω𝑖 represents the set of
branches that connects the node 𝑖. The following example shows how to build
the 𝑌bus in practice.
Telegram: @ElectricalDocument
A The nodal admittance matrix 255
Intuitively, we have defined 𝑁 and 𝐵 in the last two lines. Thus, we can
obtain a representation of the graph using the code given below, which is
self-explanatory:
Remember that it is the connections and not the shape of the graph that matter
in this figure. Therefore, the draw may look different from Figure A.1, but the
graph 𝐺 is the same.
Example A.2. The incidence matrix can be easily calculated in Python using
the modulde NetworkX. Let us continue with the graph depicted in Figure A.1,
where the incidence matrix is calculated as given below:
A = nx.incidence_matrix(G,oriented = True)
Let us suppose the admittance of each branch is 𝑦𝑖𝑗 = −10𝑗, then, the 𝑌bus is
obtained as follows:
import numpy as np
yB = -10j*np.identity(6)
Ybus = A@[email protected]
Telegram: @ElectricalDocument
Telegram: @ElectricalDocument
257
Complex linearization
1 Notice that an inequality constraint, such as 𝑓(𝑧) ≤ 0 may be meaningless in the complex
domain, since it is a non-ordered set. See Chapter 2 for a discussion about ordered sets.
𝑢(𝑥, 𝑦) = 0
𝑣(𝑥, 𝑦) = 0 (B.5)
This is the same definition as in the real numbers; however, there are infinitely
many directions in which this limit may be taken in the complex plane. This
implies an important consideration related to the continuity of the function. In
a real function, we require that the limits from the left and the right are equal.
Here, we require the same limit from all directions, as depicted in Figure B.1.
This fact restricts the analysis to a special set of functions, known as a holomor-
phic functions. Sufficient conditions for differentiating a complex function, are
given by the Cauchy–Riemann equations, as presented below:
𝜕𝑢 𝜕𝑣
=
𝜕𝑥 𝜕𝑦
𝜕𝑢 𝜕𝑣
=− (B.7)
𝜕𝑦 𝜕𝑥
Telegram: @ElectricalDocument
B Complex linearization 259
Telegram: @ElectricalDocument
260 B Complex linearization
𝑢(𝑥, 𝑦) = 𝑥 2 + 𝑦 2 + 8𝑥 + 5𝑥
𝑣(𝑥, 𝑦) = 8𝑦 − 5𝑦 (B.19)
𝜕𝑢
= 2𝑥 + 13
𝜕𝑥
𝜕𝑢
= 2𝑦
𝜕𝑦
𝜕𝑣
=0 (B.20)
𝜕𝑥
𝜕𝑣
=3
𝜕𝑦
2𝑥 + 13 0
𝐽=( ) (B.21)
2𝑦 3
𝑢 0 13 0 ∆𝑥
( )=( )+( )( ) (B.22)
𝑣 0 0 3 ∆𝑦
𝑢 = 13∆𝑥
𝑣 = 3∆𝑦 (B.23)
Telegram: @ElectricalDocument
B Complex linearization 261
Example B.4. Power flow equations in a power distribution grid are given by
Equation (B.27):
∑
𝑠𝑘∗ = 𝑦𝑘𝑚 𝑣𝑘∗ 𝑣𝑚 (B.27)
𝑚
1 1
𝑖𝑘 = 𝑠𝑘∗ ( − ∆𝑣 ∗ ) (B.32)
(1 + 0𝑗)∗ ((1 + 0𝑗)∗ )2 𝑘
= 𝑠𝑘∗ (1 − (𝑣𝑘∗ − 1)) (B.33)
= 𝑠𝑘∗ (2 − 𝑣𝑘∗ ) (B.34)
This linearization is convenient for problems in which 𝑠𝑘 is constant, for
example, the primary feeder reconfiguration.
Telegram: @ElectricalDocument
Telegram: @ElectricalDocument
263
print("Hello word")
Notice that the last case is a square, e.g., 𝑤 = 102 = 100. All comments in the
code were done using a hash mark (#).
Example C.3. An array in Python may be stored in different ways; here, we
used manly lists and tuples. A tuple is defined by parenthesis and is immutable,
whereas a list is defined by square brackets and can change in size. See the
difference in the code presented below:
X = (10,15,12) # this is a tuple
Y = [10,15,12] # this is a list
Example C.4. We use tuples when the size of the array is fixed, for example:
A = (10,15,12)
in this case, 𝐴 is a vector with three entries. We can access each entry as
A[0], A[1], and A[2]. In this case, A[0]=10, A[1]=15, and A[2]=12.
Besides, we can count from the last to the first entry in the following way:
A[-1]=12,A[-2]=15, and A[-3]=10.
Example C.5. We use lists if we require to modify the entries of the array or
its size, for example:
A = [10,15,12]
Telegram: @ElectricalDocument
C.1 Basic Python 265
We access the entries of 𝐴 in the same way as a tuple. Moreover, we can increase
the size of 𝐴, as follows:
A += [30]
Here, we have added an entry at the end of the list. Therefore, the new list has
entries A[0]=10,A[1]=15,A[2]=12, and A[3]=30.
B = 8*[5]
x = 10
y = 20
if x <= y:
print("x is lower or equal than y")
print("This line is inside the body of if")
print("This line is still inside the body of if")
print("This is outside the body of if")
Indentation in Python allows a neat code since we do not require any command
to begin and end the block code inside the conditional. However, we must be
cautious to avoid unnecessary spaces at the beginning of a line code. A simple
space may change the results of the algorithm drastically.
for k in range(5):
y = k**2
print(’k is ’,k,’ and k^2 is ’,y)
print(’This is the end’)
The first print is indented, meaning that this command is executed inside the
body of the for structure. The second print is outside the body of the for
structure.
Telegram: @ElectricalDocument
266 C Some Python examples
Example C.9. A function is defined by the command def. The following script
shows the definition of the function 𝑓(𝑥) = 1∕𝑥 5 :
def f(x):
y = 1/(x**5)
return y
After defining the function, we can evaluate it in any real variable, namely:
a = 5.3
b = f(a)
print(b)
a = 5.3 + 2.0j
b = f(a)
print(b)
C.2 NumPy
One of the most useful modules in Python is NumPy, which allows operation
with multidimensional arrays and matrices similarly to Matlab. The following
examples show the use of this module.
Example C.10. The script below, shows a simple definition of a NumPy array:
import numpy as np
x = np.array([10,15,12])
The first line imports the library and defines an alias (np). The second line
defines the array itself; this array behaves as expected in linear algebra. For
instance, we can multiply for a scalar as presented below:
y = 5 *x
Telegram: @ElectricalDocument
C.2 NumPy 267
Example C.11. A matrix may be easily defined using NumPy. Consider the
following 3 × 3 matrix:
⎛ 4 8 7 ⎞
𝐴=⎜ 3 0 1 ⎟ (C.1)
⎜ ⎟
4 2 1
⎝ ⎠
This array is defined as follows:
A = np.array([[4,8,7],[3,0,1],[4,2,1]])
Now, we can make different operations related to linear algebra. These oper-
ations are available in the linalg submodule. Some common functions are
presented below:
B = np.linalg.inv(A) # inverse
d = np.linalg.det(A) # determinant
L,V = np.linalg.eig(A) # eigenvalues and eigenvectors
A = np.array([[4,8,7],[3,0,1],[4,2,1]])
b = np.array([12,15,9])
x = np.linalg.solve(A,b)
x = np.array([1,8,3])
H = np.array([[4,8,7],[3,0,1],[4,2,1]])
f = x.T @ H @ x
Telegram: @ElectricalDocument
268 C Some Python examples
c = np.tan(x)
d = np.exp(x)
C.3 MatplotLib
Example C.15. MatplotLib is a library that allows to obtain plots in a way
as simple as Matlab. The code below, shows the plot of the function 𝑓(𝑥) =
sin(𝑥)∕𝑥 for −10 ≤ 𝑥 ≤ 10:
import numpy as np
import matplotlib.pyplot as plt
xr = np.linspace(-10,10,100) # vector with 100 points
from -10 to 10
yr = np.sin(xr)/xr
plt.plot(xr,yr)
the command linspace create a vector with 100 points, between −10 and 10;
next, the function 𝑓 is invoked and the function is plotted. After that, we can
add some labels to the axis, as follows:
plt.grid()
plt.xlabel(’abscissa’)
plt.ylabel(’ordinate’)
plt.show()
C.4 Pandas
Most of the examples presented in this book are toy-models. However, they can
be extended to solve large models. In that case, we require a simple and effi-
cient way to read, store, and manipulate data. The module Pandas allows these
operations.
Example C.16. The essential component of Pandas is a DataFrame which
allows to store and manipulate data. The following code shows the creation
of a DataFrame that store the information given in Table C.1:
import pandas as pd
mytable = pd.DataFrame()
mytable["Source"] = ["Solar","Wind","Hydro","Geothermal"]
mytable["Installed"] = [12.1, 61.1, 78.4, 3.4]
Telegram: @ElectricalDocument
C.4 Pandas 269
This Table may be also stored in a CSV file. In that case, we can open the file
by a simple line of code as presented below:
mytable = pd.read_csv("MYFILE.csv")
where the table is stored in a file named MYFILE.csv inside the same folder of
the script. The following line returns the source in the second row (i.e., wind):
print(mytable["Source"][1])
We can also plot the information given in the DataFrame using MatplotLib,
as follows:
import matplotlib.pyplot as plt
mytable.plot()
plt.grid()
plt.show()
There are many functionalities available in Pandas. This is just a hint about the
possibilities of the module. As always, the reader is invited to explore further
functions.
Telegram: @ElectricalDocument
Telegram: @ElectricalDocument
271
Bibliography
Telegram: @ElectricalDocument
Bibliography 273
Telegram: @ElectricalDocument
274 Bibliography
Telegram: @ElectricalDocument
Bibliography 275
[58] Pickard WF. The History, Present State, and Future Prospects of
Underground Pumped Hydro for Massive Energy Storage. Proceedings of
the IEEE. 2012;100(2):473–483.
[59] Luo X, Wang J, Dooner M, Clarke J. Overview of current development in
electrical energy storage technologies and the application potential in power
system operation. Applied Energy. 2015;137:511 – 536. Available from:
http://www.sciencedirect.com/science/article/pii/S0306261914010290.
[60] Suul JA. Variable Speed Pumped Storage Hydropower Plants for
Integration of Wind Power in Isolated Power Systems. Renewable Energy,
T J Hammons, InTech; 2009.
[61] Redondo NJ, Conejo AJ. Short-term hydro-thermal coordination by
Lagrangian relaxation: solution of the dual problem. IEEE Transactions on
Power Systems. 1999;14(1):89–95.
[62] Wong KP, Wong YW. Short-term hydrothermal scheduling part. I.
Simulated annealing approach. IEE Proceedings - Generation,
Transmission and Distribution. 1994;141(5):497–501.
[63] Gil E, Bustos J, Rudnick H. Short-term hydrothermal generation scheduling
model using a genetic algorithm. IEEE Transactions on Power Systems.
2003;18(4):1256–1264.
[64] van Ackooij W, Finardi EC, Ramalho GM. An Exact Solution Method for
the Hydrothermal Unit Commitment Under Wind Power Uncertainty With
Joint Probability Constraints. IEEE Transactions on Power Systems.
2018;33(6):6487–6500.
[65] Bruninx K, Dvorkin Y, Delarue E, Pandžić H, D’haeseleer W, Kirschen DS.
Coupling Pumped Hydro Energy Storage With Unit Commitment. IEEE
Transactions on Sustainable Energy. 2016;7(2):786–796.
[66] Terry L, Pereira M, Araripe-Neto T, Silva L, Sales P. Coordinating the Energy
Generation of the Brazilian National Hydrothermal Electrical Generating
System. INFORMS Journal on Applied Analytics. 1986;p. 361–379.
[67] Finardi E, Decker B, de Matos V. An Introductory Tutorial on Stochastic
Programming Using a Long-term Hydrothermal Scheduling Problem.
Journal of Control Automation and Electric Systems. 2013;24:361–379.
[68] Garces A. Uniqueness of the power flow solutions in low voltage direct
current grids. Electric Power Systems Research. 2017;151:149 – 153.
Available from: http://www.sciencedirect.com/science/article/pii/
S0378779617302298.
[69] Ochoa LF, Wilson DH. Angle constraint active management of distribution
networks with wind power. In: 2010 IEEE PES Innovative Smart Grid
Technologies Conference Europe (ISGT Europe); 2010. p. 1–5.
Telegram: @ElectricalDocument
276 Bibliography
[70] Garces A, Ramirez D, Mora J. A Wirtinger Linearization for the Power Flow
in Microgrids. Presented in 2019 IEEE Power and Energy Society General
Meeting, Atlanta. 2019 Aug;.
[71] Dommel HW, Tinney WF. Optimal Power Flow Solutions. IEEE
Transactions on Power Apparatus and Systems.
1968;PAS-87(10):1866–1876.
[72] Peschon J, Bree DW, Hajdu LP. Optimal power-flow solutions for power
system planning. Proceedings of the IEEE. 1972;60(1):64–70.
[73] Gómez Expósito A, Romero Ramos E. Reliable load flow technique for
radial distribution networks. IEEE Transactions on Power Systems.
1999;14(3):1063–1069.
[74] Torres GL, Quintana VH. An interior-point method for nonlinear optimal
power flow using voltage rectangular coordinates. IEEE Transactions on
Power Systems. 1998;13(4):1211–1218.
[75] Garces A. A Linear Three-Phase Load Flow for Power Distribution Systems.
IEEE Transactions on Power Systems. 2016 Jan;31(1):827–828.
[76] Low SH. Convex Relaxation of Optimal Power Flow—Part I: Formulations
and Equivalence. IEEE Transactions on Control of Network Systems. 2014
March;1(1):15–27.
[77] Low SH. Convex Relaxation of Optimal Power Flow—Part II: Exactness.
IEEE Transactions on Control of Network Systems. 2014;1(2):177–189.
[78] Molzahn DK, Hiskens IA. A Survey of Relaxations and Approximations of
the Power Flow Equations. now; 2019. Available from:
https://ieeexplore.ieee.org/document/8635446.
[79] Li J, Liu F, Wang Z, Low SH, Mei S. Optimal Power Flow in Stand-Alone
DC Microgrids. IEEE Transactions on Power Systems. 2018;33(5):
5496–5506.
[80] Lavaei J, Low SH. Zero Duality Gap in Optimal Power Flow Problem. IEEE
Transactions on Power Systems. 2012;27(1):92–107.
[81] Molzahn DK, Hiskens IA. Convex Relaxations of Optimal Power Flow
Problems: An Illustrative Example. IEEE Transactions on Circuits and
Systems I: Regular Papers. 2016;63(5):650–660.
[82] Madani R, Sojoudi S, Lavaei J. Convex Relaxation for Optimal Power Flow
Problem: Mesh Networks. IEEE Transactions on Power Systems.
2015;30(1):199–211.
[83] Chis M, Salama MMA, Jayaram S. Capacitor placement in distribution
systems using heuristic search strategies. IEE Proceedings - Generation,
Transmission and Distribution. 1997;144(3):225–230.
[84] Civanlar S, Grainger JJ, Yin H, Lee SSH. Distribution feeder reconfiguration
for loss reduction. IEEE Transactions on Power Delivery. 1988;3(3):
1217–1223.
Telegram: @ElectricalDocument
Bibliography 277
Telegram: @ElectricalDocument
278 Bibliography
Telegram: @ElectricalDocument
Bibliography 279
Telegram: @ElectricalDocument
Telegram: @ElectricalDocument
281
Index
m s
Manhattan norm, 23 SCADA, 9, 215
matrix norm, 224 SDP, 188
MI-SOC, 201 sectionalizing switches, 196
minimum square, 230 semidefinite, 69, 95
MIQP, 201 semidefinite matrix, 67, 69
model predictive control, 14 skew-symmetric, 68
SOC, 184
n
strictly convex, 45
negative semidefinite matrix, 69
networkx, 175 strong duality, 54
norm, 22 strongly convex, 51
sup, 19
o
OPF, 171 t
trace, 92
p
pelton turbine, 157 u
PMU, 9 uniform norm, 23
PMUs, 215 unit commitment, 148
polytope, 42
positive semidefinite matrix, 69 v
power flow, 173 V2G, 8
pumped hydroelectric storage, 165 vehicle-to-grid, 8
virtual power plant, 9
q VPP, 9
quadratic form, 67
quantile function, 120, 133 w
weak duality, 54
r Wirtinger, 177
receding horizon, 14
Reconfiguration, primary feeder, z
196 ZIP model, 228
Telegram: @ElectricalDocument
WILEY END USER LICENSE
AGREEMENT
Go to www.wiley.com/go/eula to access Wiley’s eb-
ook EULA.
Telegram: @ElectricalDocument