DSBR_DV Computes partial derivatives of branch power flows w.r.t. voltage. The derivatives can be take with respect to polar or cartesian coordinates of voltage, depending on the 5th argument. [DSF_DVA, DSF_DVM, DST_DVA, DST_DVM, SF, ST] = DSBR_DV(BRANCH, YF, YT, V) [DSF_DVA, DSF_DVM, DST_DVA, DST_DVM, SF, ST] = DSBR_DV(BRANCH, YF, YT, V, 0) 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). [DSF_DVR, DSF_DVI, DST_DVR, DST_DVI, SF, ST] = DSBR_DV(BRANCH, YF, YT, V, 1) Returns four matrices containing partial derivatives of the complex branch power flows at "from" and "to" ends of each branch w.r.t real and imaginary parts of voltage, 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 Polar coordinates: 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))) Cartesian coordinates: Partials of V, Vf & If w.r.t. real part of complex voltage dV/dVr = diag(ones(n,1)) dVf/dVr = Cf dIf/dVr = Yf where Cf is the connection matrix for line & from buses Partials of V, Vf & If w.r.t. imaginary part of complex voltage dV/dVi = j * diag(ones(n,1)) dVf/dVi = j * Cf dIf/dVi = j * Yf Partials of Sf w.r.t. real part of complex voltage dSf/dVr = conj(diag(If)) * Cf + diag(Vf) * conj(Yf) Partials of Sf w.r.t. imaginary part of complex voltage dSf/dVi = j * (conj(diag(If)) * Cf - diag(Vf) * conj(Yf)) Derivations for "to" bus are similar. Examples: [Ybus, Yf, Yt] = makeYbus(baseMVA, bus, branch); [dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St] = ... dSbr_dV(branch, Yf, Yt, V); [dSf_dVr, dSf_dVi, dSt_dVr, dSt_dVi, Sf, St] = ... dSbr_dV(branch, Yf, Yt, V, 1); 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. [Online]. Available: https://matpower.org/docs/TN2-OPF-Derivatives.pdf doi: 10.5281/zenodo.3237866 [TN4] B. Sereeter and R. D. Zimmerman, "AC Power Flows and their Derivatives using Complex Matrix Notation and Cartesian Coordinate Voltages," MATPOWER Technical Note 4, April 2018. [Online]. Available: https://matpower.org/docs/TN4-OPF-Derivatives-Cartesian.pdf doi: 10.5281/zenodo.3237909
0001 function [dSf_dV1, dSf_dV2, dSt_dV1, dSt_dV2, Sf, St] = dSbr_dV(branch, Yf, Yt, V, vcart) 0002 %DSBR_DV Computes partial derivatives of branch power flows w.r.t. voltage. 0003 % 0004 % The derivatives can be take with respect to polar or cartesian coordinates 0005 % of voltage, depending on the 5th argument. 0006 % 0007 % [DSF_DVA, DSF_DVM, DST_DVA, DST_DVM, SF, ST] = DSBR_DV(BRANCH, YF, YT, V) 0008 % [DSF_DVA, DSF_DVM, DST_DVA, DST_DVM, SF, ST] = DSBR_DV(BRANCH, YF, YT, V, 0) 0009 % 0010 % Returns four matrices containing partial derivatives of the complex 0011 % branch power flows at "from" and "to" ends of each branch w.r.t voltage 0012 % magnitude and voltage angle, respectively (for all buses). 0013 % 0014 % [DSF_DVR, DSF_DVI, DST_DVR, DST_DVI, SF, ST] = DSBR_DV(BRANCH, YF, YT, V, 1) 0015 % 0016 % Returns four matrices containing partial derivatives of the complex 0017 % branch power flows at "from" and "to" ends of each branch w.r.t real and 0018 % imaginary parts of voltage, respectively (for all buses). 0019 % 0020 % If YF is a sparse matrix, the partial derivative matrices will be as well. 0021 % Optionally returns vectors containing the power flows themselves. The 0022 % following explains the expressions used to form the matrices: 0023 % 0024 % If = Yf * V; 0025 % Sf = diag(Vf) * conj(If) = diag(conj(If)) * Vf 0026 % 0027 % Polar coordinates: 0028 % Partials of V, Vf & If w.r.t. voltage angles 0029 % dV/dVa = j * diag(V) 0030 % dVf/dVa = sparse(1:nl, f, j * V(f)) = j * sparse(1:nl, f, V(f)) 0031 % dIf/dVa = Yf * dV/dVa = Yf * j * diag(V) 0032 % 0033 % Partials of V, Vf & If w.r.t. voltage magnitudes 0034 % dV/dVm = diag(V./abs(V)) 0035 % dVf/dVm = sparse(1:nl, f, V(f)./abs(V(f)) 0036 % dIf/dVm = Yf * dV/dVm = Yf * diag(V./abs(V)) 0037 % 0038 % Partials of Sf w.r.t. voltage angles 0039 % dSf/dVa = diag(Vf) * conj(dIf/dVa) 0040 % + diag(conj(If)) * dVf/dVa 0041 % = diag(Vf) * conj(Yf * j * diag(V)) 0042 % + conj(diag(If)) * j * sparse(1:nl, f, V(f)) 0043 % = -j * diag(Vf) * conj(Yf * diag(V)) 0044 % + j * conj(diag(If)) * sparse(1:nl, f, V(f)) 0045 % = j * (conj(diag(If)) * sparse(1:nl, f, V(f)) 0046 % - diag(Vf) * conj(Yf * diag(V))) 0047 % 0048 % Partials of Sf w.r.t. voltage magnitudes 0049 % dSf/dVm = diag(Vf) * conj(dIf/dVm) 0050 % + diag(conj(If)) * dVf/dVm 0051 % = diag(Vf) * conj(Yf * diag(V./abs(V))) 0052 % + conj(diag(If)) * sparse(1:nl, f, V(f)./abs(V(f))) 0053 % 0054 % Cartesian coordinates: 0055 % Partials of V, Vf & If w.r.t. real part of complex voltage 0056 % dV/dVr = diag(ones(n,1)) 0057 % dVf/dVr = Cf 0058 % dIf/dVr = Yf 0059 % where Cf is the connection matrix for line & from buses 0060 % 0061 % Partials of V, Vf & If w.r.t. imaginary part of complex voltage 0062 % dV/dVi = j * diag(ones(n,1)) 0063 % dVf/dVi = j * Cf 0064 % dIf/dVi = j * Yf 0065 % 0066 % Partials of Sf w.r.t. real part of complex voltage 0067 % dSf/dVr = conj(diag(If)) * Cf + diag(Vf) * conj(Yf) 0068 % 0069 % Partials of Sf w.r.t. imaginary part of complex voltage 0070 % dSf/dVi = j * (conj(diag(If)) * Cf - diag(Vf) * conj(Yf)) 0071 % 0072 % Derivations for "to" bus are similar. 0073 % 0074 % Examples: 0075 % [Ybus, Yf, Yt] = makeYbus(baseMVA, bus, branch); 0076 % [dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm, Sf, St] = ... 0077 % dSbr_dV(branch, Yf, Yt, V); 0078 % [dSf_dVr, dSf_dVi, dSt_dVr, dSt_dVi, Sf, St] = ... 0079 % dSbr_dV(branch, Yf, Yt, V, 1); 0080 % 0081 % For more details on the derivations behind the derivative code used 0082 % in MATPOWER information, see: 0083 % 0084 % [TN2] R. D. Zimmerman, "AC Power Flows, Generalized OPF Costs and 0085 % their Derivatives using Complex Matrix Notation", MATPOWER 0086 % Technical Note 2, February 2010. [Online]. Available: 0087 % https://matpower.org/docs/TN2-OPF-Derivatives.pdf 0088 % doi: 10.5281/zenodo.3237866 0089 % [TN4] B. Sereeter and R. D. Zimmerman, "AC Power Flows and their 0090 % Derivatives using Complex Matrix Notation and Cartesian 0091 % Coordinate Voltages," MATPOWER Technical Note 4, April 2018. 0092 % [Online]. Available: https://matpower.org/docs/TN4-OPF-Derivatives-Cartesian.pdf 0093 % doi: 10.5281/zenodo.3237909 0094 0095 % MATPOWER 0096 % Copyright (c) 1996-2019, Power Systems Engineering Research Center (PSERC) 0097 % by Ray Zimmerman, PSERC Cornell 0098 % and Baljinnyam Sereeter, Delft University of Technology 0099 % 0100 % This file is part of MATPOWER. 0101 % Covered by the 3-clause BSD License (see LICENSE file for details). 0102 % See https://matpower.org for more info. 0103 0104 %% define named indices into bus, gen, branch matrices 0105 [F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ... 0106 TAP, SHIFT, BR_STATUS, PF, QF, PT, QT, MU_SF, MU_ST, ... 0107 ANGMIN, ANGMAX, MU_ANGMIN, MU_ANGMAX] = idx_brch; 0108 0109 %% default input args 0110 if nargin < 5 0111 vcart = 0; %% default to polar coordinates 0112 end 0113 0114 %% define 0115 f = branch(:, F_BUS); %% list of "from" buses 0116 t = branch(:, T_BUS); %% list of "to" buses 0117 nl = length(f); 0118 nb = length(V); 0119 0120 %% compute intermediate values 0121 Yfc = conj(Yf); 0122 Ytc = conj(Yt); 0123 Vc = conj(V); 0124 Ifc = Yfc * Vc; %% conjugate of "from" current 0125 Itc = Ytc * Vc; %% conjugate of "to" current 0126 0127 if issparse(Yf) %% sparse version (if Yf is sparse) 0128 diagVf = sparse(1:nl, 1:nl, V(f), nl, nl); 0129 diagVt = sparse(1:nl, 1:nl, V(t), nl, nl); 0130 diagIfc = sparse(1:nl, 1:nl, Ifc, nl, nl); 0131 diagItc = sparse(1:nl, 1:nl, Itc, nl, nl); 0132 if ~vcart 0133 Vnorm = V ./ abs(V); 0134 diagVc = sparse(1:nb, 1:nb, Vc, nb, nb); 0135 diagVnorm = sparse(1:nb, 1:nb, Vnorm, nb, nb); 0136 CVf = sparse(1:nl, f, V(f), nl, nb); 0137 CVnf = sparse(1:nl, f, Vnorm(f), nl, nb); 0138 CVt = sparse(1:nl, t, V(t), nl, nb); 0139 CVnt = sparse(1:nl, t, Vnorm(t), nl, nb); 0140 end 0141 else %% dense version 0142 diagVf = diag(V(f)); 0143 diagVt = diag(V(t)); 0144 diagIfc = diag(Ifc); 0145 diagItc = diag(Itc); 0146 if ~vcart 0147 Vnorm = V ./ abs(V); 0148 diagVc = diag(Vc); 0149 diagVnorm = diag(Vnorm); 0150 % CVf = zeros(nl, nb); CVf(sub2ind([nl,nb], (1:nl)', f)) = V(f); 0151 % CVnf = zeros(nl, nb); CVnf(sub2ind([nl,nb], (1:nl)', f)) = Vnorm(f); 0152 % CVt = zeros(nl, nb); CVt(sub2ind([nl,nb], (1:nl)', t)) = V(t); 0153 % CVnt = zeros(nl, nb); CVnt(sub2ind([nl,nb], (1:nl)', t)) = Vnorm(t); 0154 CVf = full(sparse(1:nl, f, V(f), nl, nb)); 0155 CVnf = full(sparse(1:nl, f, Vnorm(f), nl, nb)); 0156 CVt = full(sparse(1:nl, t, V(t), nl, nb)); 0157 CVnt = full(sparse(1:nl, t, Vnorm(t), nl, nb)); 0158 end 0159 end 0160 if vcart 0161 Cf = sparse(1:nl, f, ones(nl, 1), nl, nb); %% connection matrix for line & from buses 0162 Ct = sparse(1:nl, t, ones(nl, 1), nl, nb); %% connection matrix for line & to buses 0163 Af = diagIfc * Cf; 0164 Bf = diagVf * Yfc; 0165 At = diagItc * Ct; 0166 Bt = diagVt * Ytc; 0167 0168 dSf_dV1 = Af + Bf; %% dSf_dVr 0169 dSf_dV2 = 1j * (Af - Bf); %% dSf_dVi 0170 dSt_dV1 = At + Bt; %% dSt_dVr 0171 dSt_dV2 = 1j * (At - Bt); %% dSt_dVi 0172 else 0173 dSf_dV1 = 1j * (diagIfc * CVf - diagVf * Yfc * diagVc); %% dSf_dVa 0174 dSf_dV2 = diagVf * conj(Yf * diagVnorm) + diagIfc * CVnf; %% dSf_dVm 0175 dSt_dV1 = 1j * (diagItc * CVt - diagVt * Ytc * diagVc); %% dSt_dVa 0176 dSt_dV2 = diagVt * conj(Yt * diagVnorm) + diagItc * CVnt; %% dSt_dVm 0177 end 0178 0179 if nargout > 4 0180 Sf = V(f) .* Ifc; 0181 St = V(t) .* Itc; 0182 end