1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 """Computes partial derivatives of power flows w.r.t. voltage.
18 """
19
20 from numpy import conj, arange, diag, zeros, asmatrix, asarray, asscalar
21 from scipy.sparse import issparse, csr_matrix as sparse
22
23 from idx_brch import F_BUS, T_BUS
24
26 """Computes partial derivatives of power flows w.r.t. voltage.
27
28 returns four matrices containing partial derivatives of the complex
29 branch power flows at "from" and "to" ends of each branch w.r.t voltage
30 magnitude and voltage angle respectively (for all buses). If C{Yf} is a
31 sparse matrix, the partial derivative matrices will be as well. Optionally
32 returns vectors containing the power flows themselves. The following
33 explains the expressions used to form the matrices::
34
35 If = Yf * V;
36 Sf = diag(Vf) * conj(If) = diag(conj(If)) * Vf
37
38 Partials of V, Vf & If w.r.t. voltage angles::
39 dV/dVa = j * diag(V)
40 dVf/dVa = sparse(range(nl), f, j*V(f)) = j * sparse(range(nl), f, V(f))
41 dIf/dVa = Yf * dV/dVa = Yf * j * diag(V)
42
43 Partials of V, Vf & If w.r.t. voltage magnitudes::
44 dV/dVm = diag(V / abs(V))
45 dVf/dVm = sparse(range(nl), f, V(f) / abs(V(f))
46 dIf/dVm = Yf * dV/dVm = Yf * diag(V / abs(V))
47
48 Partials of Sf w.r.t. voltage angles::
49 dSf/dVa = diag(Vf) * conj(dIf/dVa)
50 + diag(conj(If)) * dVf/dVa
51 = diag(Vf) * conj(Yf * j * diag(V))
52 + conj(diag(If)) * j * sparse(range(nl), f, V(f))
53 = -j * diag(Vf) * conj(Yf * diag(V))
54 + j * conj(diag(If)) * sparse(range(nl), f, V(f))
55 = j * (conj(diag(If)) * sparse(range(nl), f, V(f))
56 - diag(Vf) * conj(Yf * diag(V)))
57
58 Partials of Sf w.r.t. voltage magnitudes::
59 dSf/dVm = diag(Vf) * conj(dIf/dVm)
60 + diag(conj(If)) * dVf/dVm
61 = diag(Vf) * conj(Yf * diag(V / abs(V)))
62 + conj(diag(If)) * sparse(range(nl), f, V(f)/abs(V(f)))
63
64 Derivations for "to" bus are similar.
65
66 For more details on the derivations behind the derivative code used
67 in PYPOWER information, see:
68
69 [TN2] R. D. Zimmerman, "AC Power Flows, Generalized OPF Costs and
70 their Derivatives using Complex Matrix Notation", MATPOWER
71 Technical Note 2, February 2010.
72 U{http://www.pserc.cornell.edu/matpower/TN2-OPF-Derivatives.pdf}
73
74 @author: Ray Zimmerman (PSERC Cornell)
75 @author: Richard Lincoln
76 """
77
78 f = branch[:, F_BUS].astype(int)
79 t = branch[:, T_BUS].astype(int)
80 nl = len(f)
81 nb = len(V)
82 il = arange(nl)
83 ib = arange(nb)
84
85 Vnorm = V / abs(V)
86
87 if issparse(Yf):
88
89 If = Yf * V
90 It = Yt * V
91
92 diagVf = sparse((V[f], (il, il)))
93 diagIf = sparse((If, (il, il)))
94 diagVt = sparse((V[t], (il, il)))
95 diagIt = sparse((It, (il, il)))
96 diagV = sparse((V, (ib, ib)))
97 diagVnorm = sparse((Vnorm, (ib, ib)))
98
99 shape = (nl, nb)
100
101 dSf_dVa = 1j * (conj(diagIf) *
102 sparse((V[f], (il, f)), shape) - diagVf * conj(Yf * diagV))
103
104 dSt_dVa = 1j * (conj(diagIt) *
105 sparse((V[t], (il, t)), shape) - diagVt * conj(Yt * diagV))
106
107
108 dSf_dVm = diagVf * conj(Yf * diagVnorm) + conj(diagIf) * \
109 sparse((Vnorm[f], (il, f)), shape)
110
111 dSt_dVm = diagVt * conj(Yt * diagVnorm) + conj(diagIt) * \
112 sparse((Vnorm[t], (il, t)), shape)
113 else:
114
115 If = asarray( Yf * asmatrix(V).T ).flatten()
116 It = asarray( Yt * asmatrix(V).T ).flatten()
117
118 diagVf = asmatrix( diag(V[f]) )
119 diagIf = asmatrix( diag(If) )
120 diagVt = asmatrix( diag(V[t]) )
121 diagIt = asmatrix( diag(It) )
122 diagV = asmatrix( diag(V) )
123 diagVnorm = asmatrix( diag(Vnorm) )
124 temp1 = asmatrix( zeros((nl, nb), complex) )
125 temp2 = asmatrix( zeros((nl, nb), complex) )
126 temp3 = asmatrix( zeros((nl, nb), complex) )
127 temp4 = asmatrix( zeros((nl, nb), complex) )
128 for i in range(nl):
129 fi, ti = f[i], t[i]
130 temp1[i, fi] = asscalar(V[fi])
131 temp2[i, fi] = asscalar(Vnorm[fi])
132 temp3[i, ti] = asscalar(V[ti])
133 temp4[i, ti] = asscalar(Vnorm[ti])
134
135 dSf_dVa = 1j * (conj(diagIf) * temp1 - diagVf * conj(Yf * diagV))
136 dSf_dVm = diagVf * conj(Yf * diagVnorm) + conj(diagIf) * temp2
137 dSt_dVa = 1j * (conj(diagIt) * temp3 - diagVt * conj(Yt * diagV))
138 dSt_dVm = diagVt * conj(Yt * diagVnorm) + conj(diagIt) * temp4
139
140
141 Sf = V[f] * conj(If)
142 St = V[t] * conj(It)
143
144 return dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St
145