DSBR_DV Computes partial derivatives of power flows w.r.t. voltage. [DSF_DVA, DSF_DVM, DST_DVA, DST_DVM, SF, ST] = DSBR_DV(BRANCH, YF, YT, V) returns four matrices containing partial derivatives of the complex branch power flows at "from" and "to" ends of each branch w.r.t voltage magnitude and voltage angle respectively (for all buses). If YF is a sparse matrix, the partial derivative matrices will be as well. Optionally returns vectors containing the power flows themselves. The following explains the expressions used to form the matrices: If = Yf * V; Sf = diag(Vf) * conj(If) = diag(conj(If)) * Vf Partials of V, Vf & If w.r.t. voltage angles dV/dVa = j * diag(V) dVf/dVa = sparse(1:nl, f, j * V(f)) = j * sparse(1:nl, f, V(f)) dIf/dVa = Yf * dV/dVa = Yf * j * diag(V) Partials of V, Vf & If w.r.t. voltage magnitudes dV/dVm = diag(V./abs(V)) dVf/dVm = sparse(1:nl, f, V(f)./abs(V(f)) dIf/dVm = Yf * dV/dVm = Yf * diag(V./abs(V)) Partials of Sf w.r.t. voltage angles dSf/dVa = diag(Vf) * conj(dIf/dVa) + diag(conj(If)) * dVf/dVa = diag(Vf) * conj(Yf * j * diag(V)) + conj(diag(If)) * j * sparse(1:nl, f, V(f)) = -j * diag(Vf) * conj(Yf * diag(V)) + j * conj(diag(If)) * sparse(1:nl, f, V(f)) = j * (conj(diag(If)) * sparse(1:nl, f, V(f)) - diag(Vf) * conj(Yf * diag(V))) Partials of Sf w.r.t. voltage magnitudes dSf/dVm = diag(Vf) * conj(dIf/dVm) + diag(conj(If)) * dVf/dVm = diag(Vf) * conj(Yf * diag(V./abs(V))) + conj(diag(If)) * sparse(1:nl, f, V(f)./abs(V(f))) Derivations for "to" bus are similar. Example: [Ybus, Yf, Yt] = makeYbus(baseMVA, bus, branch); [dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St] = ... dSbr_dV(branch, Yf, Yt, V); For more details on the derivations behind the derivative code used in MATPOWER information, see: [TN2] R. D. Zimmerman, "AC Power Flows, Generalized OPF Costs and their Derivatives using Complex Matrix Notation", MATPOWER Technical Note 2, February 2010. http://www.pserc.cornell.edu/matpower/TN2-OPF-Derivatives.pdf
0001 function [dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St] = dSbr_dV(branch, Yf, Yt, V) 0002 %DSBR_DV Computes partial derivatives of power flows w.r.t. voltage. 0003 % [DSF_DVA, DSF_DVM, DST_DVA, DST_DVM, SF, ST] = DSBR_DV(BRANCH, YF, YT, V) 0004 % returns four matrices containing partial derivatives of the complex 0005 % branch power flows at "from" and "to" ends of each branch w.r.t voltage 0006 % magnitude and voltage angle respectively (for all buses). If YF is a 0007 % sparse matrix, the partial derivative matrices will be as well. Optionally 0008 % returns vectors containing the power flows themselves. The following 0009 % explains the expressions used to form the matrices: 0010 % 0011 % If = Yf * V; 0012 % Sf = diag(Vf) * conj(If) = diag(conj(If)) * Vf 0013 % 0014 % Partials of V, Vf & If w.r.t. voltage angles 0015 % dV/dVa = j * diag(V) 0016 % dVf/dVa = sparse(1:nl, f, j * V(f)) = j * sparse(1:nl, f, V(f)) 0017 % dIf/dVa = Yf * dV/dVa = Yf * j * diag(V) 0018 % 0019 % Partials of V, Vf & If w.r.t. voltage magnitudes 0020 % dV/dVm = diag(V./abs(V)) 0021 % dVf/dVm = sparse(1:nl, f, V(f)./abs(V(f)) 0022 % dIf/dVm = Yf * dV/dVm = Yf * diag(V./abs(V)) 0023 % 0024 % Partials of Sf w.r.t. voltage angles 0025 % dSf/dVa = diag(Vf) * conj(dIf/dVa) 0026 % + diag(conj(If)) * dVf/dVa 0027 % = diag(Vf) * conj(Yf * j * diag(V)) 0028 % + conj(diag(If)) * j * sparse(1:nl, f, V(f)) 0029 % = -j * diag(Vf) * conj(Yf * diag(V)) 0030 % + j * conj(diag(If)) * sparse(1:nl, f, V(f)) 0031 % = j * (conj(diag(If)) * sparse(1:nl, f, V(f)) 0032 % - diag(Vf) * conj(Yf * diag(V))) 0033 % 0034 % Partials of Sf w.r.t. voltage magnitudes 0035 % dSf/dVm = diag(Vf) * conj(dIf/dVm) 0036 % + diag(conj(If)) * dVf/dVm 0037 % = diag(Vf) * conj(Yf * diag(V./abs(V))) 0038 % + conj(diag(If)) * sparse(1:nl, f, V(f)./abs(V(f))) 0039 % 0040 % Derivations for "to" bus are similar. 0041 % 0042 % Example: 0043 % [Ybus, Yf, Yt] = makeYbus(baseMVA, bus, branch); 0044 % [dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St] = ... 0045 % dSbr_dV(branch, Yf, Yt, V); 0046 % 0047 % For more details on the derivations behind the derivative code used 0048 % in MATPOWER information, see: 0049 % 0050 % [TN2] R. D. Zimmerman, "AC Power Flows, Generalized OPF Costs and 0051 % their Derivatives using Complex Matrix Notation", MATPOWER 0052 % Technical Note 2, February 2010. 0053 % http://www.pserc.cornell.edu/matpower/TN2-OPF-Derivatives.pdf 0054 0055 % MATPOWER 0056 % $Id: dSbr_dV.m,v 1.15 2010/11/16 16:05:46 cvs Exp $ 0057 % by Ray Zimmerman, PSERC Cornell 0058 % Copyright (c) 1996-2010 by Power System Engineering Research Center (PSERC) 0059 % 0060 % This file is part of MATPOWER. 0061 % See http://www.pserc.cornell.edu/matpower/ for more info. 0062 % 0063 % MATPOWER is free software: you can redistribute it and/or modify 0064 % it under the terms of the GNU General Public License as published 0065 % by the Free Software Foundation, either version 3 of the License, 0066 % or (at your option) any later version. 0067 % 0068 % MATPOWER is distributed in the hope that it will be useful, 0069 % but WITHOUT ANY WARRANTY; without even the implied warranty of 0070 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0071 % GNU General Public License for more details. 0072 % 0073 % You should have received a copy of the GNU General Public License 0074 % along with MATPOWER. If not, see <http://www.gnu.org/licenses/>. 0075 % 0076 % Additional permission under GNU GPL version 3 section 7 0077 % 0078 % If you modify MATPOWER, or any covered work, to interface with 0079 % other modules (such as MATLAB code and MEX-files) available in a 0080 % MATLAB(R) or comparable environment containing parts covered 0081 % under other licensing terms, the licensors of MATPOWER grant 0082 % you additional permission to convey the resulting work. 0083 0084 %% define named indices into bus, gen, branch matrices 0085 [F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ... 0086 TAP, SHIFT, BR_STATUS, PF, QF, PT, QT, MU_SF, MU_ST, ... 0087 ANGMIN, ANGMAX, MU_ANGMIN, MU_ANGMAX] = idx_brch; 0088 0089 %% define 0090 f = branch(:, F_BUS); %% list of "from" buses 0091 t = branch(:, T_BUS); %% list of "to" buses 0092 nl = length(f); 0093 nb = length(V); 0094 0095 %% compute currents 0096 If = Yf * V; 0097 It = Yt * V; 0098 0099 Vnorm = V ./ abs(V); 0100 if issparse(Yf) %% sparse version (if Yf is sparse) 0101 diagVf = sparse(1:nl, 1:nl, V(f), nl, nl); 0102 diagIf = sparse(1:nl, 1:nl, If, nl, nl); 0103 diagVt = sparse(1:nl, 1:nl, V(t), nl, nl); 0104 diagIt = sparse(1:nl, 1:nl, It, nl, nl); 0105 diagV = sparse(1:nb, 1:nb, V, nb, nb); 0106 diagVnorm = sparse(1:nb, 1:nb, Vnorm, nb, nb); 0107 0108 dSf_dVa = 1j * (conj(diagIf) * sparse(1:nl, f, V(f), nl, nb) - diagVf * conj(Yf * diagV)); 0109 dSf_dVm = diagVf * conj(Yf * diagVnorm) + conj(diagIf) * sparse(1:nl, f, Vnorm(f), nl, nb); 0110 dSt_dVa = 1j * (conj(diagIt) * sparse(1:nl, t, V(t), nl, nb) - diagVt * conj(Yt * diagV)); 0111 dSt_dVm = diagVt * conj(Yt * diagVnorm) + conj(diagIt) * sparse(1:nl, t, Vnorm(t), nl, nb); 0112 else %% dense version 0113 diagVf = diag(V(f)); 0114 diagIf = diag(If); 0115 diagVt = diag(V(t)); 0116 diagIt = diag(It); 0117 diagV = diag(V); 0118 diagVnorm = diag(Vnorm); 0119 temp1 = zeros(nl, nb); temp1(sub2ind([nl,nb], (1:nl)', f)) = V(f); 0120 temp2 = zeros(nl, nb); temp2(sub2ind([nl,nb], (1:nl)', f)) = Vnorm(f); 0121 temp3 = zeros(nl, nb); temp3(sub2ind([nl,nb], (1:nl)', t)) = V(t); 0122 temp4 = zeros(nl, nb); temp4(sub2ind([nl,nb], (1:nl)', t)) = Vnorm(t); 0123 0124 dSf_dVa = 1j * (conj(diagIf) * temp1 - diagVf * conj(Yf * diagV)); 0125 dSf_dVm = diagVf * conj(Yf * diagVnorm) + conj(diagIf) * temp2; 0126 dSt_dVa = 1j * (conj(diagIt) * temp3 - diagVt * conj(Yt * diagV)); 0127 dSt_dVm = diagVt * conj(Yt * diagVnorm) + conj(diagIt) * temp4; 0128 end 0129 0130 if nargout > 4 0131 Sf = V(f) .* conj(If); 0132 St = V(t) .* conj(It); 0133 end