# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
# SPDX-License-Identifier: MPL-2.0
import numpy as np
from typing import Tuple
from scipy.sparse.linalg import spsolve
from scipy.sparse.linalg import inv
from scipy.sparse import csc_matrix
from VeraGridEngine.enumerations import FaultType
from VeraGridEngine.basic_structures import CxVec, Vec
[docs]
def short_circuit_3p(bus_idx: int, Ybus: csc_matrix, Vbus: CxVec, Vnom: Vec, Zf: CxVec, baseMVA: float) -> Tuple[
CxVec, float, float]:
"""
Executes a 3-phase balanced short circuit study
:param bus_idx: Index of the bus at which the short circuit is being studied
:param Ybus: Admittance matrix
:param Vbus: Voltages of the buses in the steady state
:param Vnom: Nominal Voltages of the buses (kV)
:param Zf: Fault impedance array
:param baseMVA:
:return: Voltages after the short circuit (p.u.), Short circuit power in MVA
Computed as V = Vpre + V increment, where Vpre is the power flow solution and
V increment is the fault contribution
The short-circuit power is V_i^2 / Z[i,i], it will tend to infinity if the
generator is ideal (r1 and x1 approach 0)
"""
n = len(Vbus)
tmp = np.zeros(n)
tmp[bus_idx] = 1
Zcol = spsolve(Ybus, tmp)
Zii = Zcol[bus_idx]
Ifvec = np.zeros(n, dtype=complex)
Ifvec[bus_idx] = Vbus[bus_idx] / (Zii + Zf[bus_idx])
Av = - spsolve(Ybus, Ifvec)
V = Vbus + Av
idx_buses = range(n)
Ibase = baseMVA / Vnom[idx_buses]
ICC = Ibase * Vbus[idx_buses] / Zii
SCC = baseMVA * Vbus[idx_buses] * Vbus[idx_buses] / Zii
return V, SCC, ICC
[docs]
def short_circuit_unbalance(bus_idx: int,
Y0: csc_matrix,
Y1: csc_matrix,
Y2: csc_matrix,
Vbus: CxVec,
Vnom: Vec,
Zf: CxVec,
fault_type: FaultType,
baseMVA) -> Tuple[CxVec, CxVec, CxVec, CxVec, CxVec]:
"""
Executes the unbalanced short circuits (LG, LL, LLG types)
:param bus_idx: bus where the fault is caused
:param Y0: Admittance matrix for the zero sequence
:param Y1: Admittance matrix for the positive sequence
:param Y2: Admittance matrix for the negative sequence
:param Vbus: pre-fault voltage (positive sequence)
:param Vnom: nominal voltage (kV)
:param Zf: fault impedance
:param fault_type: type of unbalanced fault
:param baseMVA: base MVA (100 MVA)
:return: V0, V1, V2 for all buses
"""
n = len(Vbus)
# solve the fault
Vpr = Vbus[bus_idx]
tmp = np.zeros(n)
tmp[bus_idx] = 1
Zth0 = spsolve(Y0, tmp)[bus_idx]
Zth1 = spsolve(Y1, tmp)[bus_idx]
Zth2 = spsolve(Y2, tmp)[bus_idx]
Zflt = Zf[bus_idx]
if fault_type == FaultType.LG:
I0 = Vpr / (Zth0 + Zth1 + Zth2 + 3 * Zflt)
I1 = I0
I2 = I0
elif fault_type == FaultType.LL: # between phases b and c
I0 = 0
I1 = Vpr / (Zth1 + Zth2 + Zflt)
I2 = - I1
elif fault_type == FaultType.LLG: # between phases b and c
I1 = Vpr / (Zth1 + Zth2 * (Zth0 + 3 * Zflt) / (Zth2 + Zth0 + 3 * Zflt))
I0 = -I1 * Zth2 / (Zth2 + Zth0 + 3 * Zflt)
I2 = -I1 * (Zth0 + 3 * Zflt) / (Zth2 + Zth0 + 3 * Zflt)
else:
raise Exception('Unknown unbalanced fault type')
# obtain the post fault voltages
I0_vec = np.zeros(n, dtype=complex)
I1_vec = np.zeros(n, dtype=complex)
I2_vec = np.zeros(n, dtype=complex)
I0_vec[bus_idx] = I0
I1_vec[bus_idx] = I1
I2_vec[bus_idx] = I2
V0_fin = - spsolve(Y0, I0_vec)
V1_fin = Vbus - spsolve(Y1, I1_vec)
V2_fin = - spsolve(Y2, I2_vec)
SCC = np.zeros_like(Vbus)
ICC = np.zeros_like(Vbus)
Ibase = baseMVA / Vnom[bus_idx]
ICC[bus_idx] = Ibase * V1_fin[bus_idx] / Zth1
SCC[bus_idx] = baseMVA * V1_fin[bus_idx] * V1_fin[bus_idx] / Zth1
return V0_fin, V1_fin, V2_fin, SCC, ICC
# def short_circuit_phases():
#