dSbr_dV

dSbr_dV(branch, Yf, Yt, V, vcart)

dSbr_dV() - Computes partial derivatives of branch power flows w.r.t. voltage.

The derivatives can be taken 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, 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