Skip to content

Commit

Permalink
Amend PR 1701 for 3ph
Browse files Browse the repository at this point in the history
Taking into account:
- the number of parallel lines when converting from line to impedance
- a factor 3 for all three sequences
- the assumtion, that c and c0 is 0 for lines
  • Loading branch information
elodin committed Oct 13, 2022
1 parent 7906eea commit 5d5620f
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 25 deletions.
35 changes: 21 additions & 14 deletions pandapower/build_branch.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def _initialize_branch_lookup(net):
start = 0
end = 0
net._pd2ppc_lookups["branch"] = {}
for element in ["line", "trafo", "trafo3w", "impedance", "xward"]:
for element in ["line", "impedance", "trafo", "trafo3w", "xward"]:
if len(net[element]) > 0:
if element == "trafo3w":
end = start + len(net[element]) * 3
Expand Down Expand Up @@ -579,20 +579,27 @@ def _calc_impedance_parameter(net, ppc):
branch[f:t, BR_STATUS] = net["impedance"]["in_service"].values


def _calc_impedance_parameters_from_dataframe(net):
def _calc_impedance_parameters_from_dataframe(net, zero_sequence=False):
impedance = net.impedance
sn_impedance = impedance["sn_mva"].values
sn_net = net.sn_mva
rij = impedance["rft_pu"].values
xij = impedance["xft_pu"].values
rji = impedance["rtf_pu"].values
xji = impedance["xtf_pu"].values

r = rij / sn_impedance * sn_net
x = xij / sn_impedance * sn_net
r_asym = (rji - rij) / sn_impedance * sn_net
x_asym = (xji - xij) / sn_impedance * sn_net
return r, x, r_asym, x_asym
suffix = "0" if zero_sequence else ""

rij = impedance[f"rft{suffix}_pu"].values
xij = impedance[f"xft{suffix}_pu"].values
rji = impedance[f"rtf{suffix}_pu"].values
xji = impedance[f"xtf{suffix}_pu"].values

mode = net["_options"]["mode"]
sn_factor = 3. if mode == 'pf_3ph' else 1.
sn_impedance = impedance["sn_mva"].values if mode == 'sc' else 1.
sn_net = net.sn_mva if mode == 'sc' else 1.

r_f = (rij * sn_factor) / (sn_impedance * sn_net)
x_f = (xij * sn_factor) / (sn_impedance * sn_net)
r_t = (rji * sn_factor) / (sn_impedance * sn_net)
x_t = (xji * sn_factor) / (sn_impedance * sn_net)
r_asym = r_t - r_f
x_asym = x_t - x_f
return r_f, x_f, r_asym, x_asym


def _calc_xward_parameter(net, ppc):
Expand Down
28 changes: 24 additions & 4 deletions pandapower/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -3552,7 +3552,8 @@ def create_shunt_as_capacitor(net, bus, q_mvar, loss_factor, **kwargs):


def create_impedance(net, from_bus, to_bus, rft_pu, xft_pu, sn_mva, rtf_pu=None, xtf_pu=None,
name=None, in_service=True, index=None, **kwargs):
name=None, in_service=True, index=None,
rft0_pu=None, xft0_pu=None, rtf0_pu=None, xtf0_pu=None, **kwargs):
"""
Creates an per unit impedance element
Expand All @@ -3577,21 +3578,37 @@ def create_impedance(net, from_bus, to_bus, rft_pu, xft_pu, sn_mva, rtf_pu=None,

_check_branch_element(net, "Impedance", index, from_bus, to_bus)

if rft_pu is None or xft_pu is None or (rft0_pu is None and rtf0_pu is not None) or \
(xft0_pu is None and xtf0_pu is not None):
raise UserWarning("*ft_pu parameters are missing for impedance element")

if rtf_pu is None:
rtf_pu = rft_pu
if xtf_pu is None:
xtf_pu = xft_pu
if rft0_pu is not None and rtf0_pu is None:
rtf0_pu = rft0_pu
if xft0_pu is not None and xtf0_pu is None:
xtf0_pu = xft0_pu

columns = ["from_bus", "to_bus", "rft_pu", "xft_pu", "rtf_pu", "xtf_pu", "name", "sn_mva",
"in_service"]
values = [from_bus, to_bus, rft_pu, xft_pu, rtf_pu, xtf_pu, name, sn_mva, in_service]
_set_entries(net, "impedance", index, **dict(zip(columns, values)), **kwargs)
entries = dict(zip(columns, values))
_set_entries(net, "impedance", index, **entries, **kwargs)

if rft0_pu is not None:
_create_column_and_set_value(net, index, rft0_pu, "rft0_pu", "impedance")
_create_column_and_set_value(net, index, xft0_pu, "xft0_pu", "impedance")
_create_column_and_set_value(net, index, rtf0_pu, "rtf0_pu", "impedance")
_create_column_and_set_value(net, index, xtf0_pu, "xtf0_pu", "impedance")

return index


def create_series_reactor_as_impedance(net, from_bus, to_bus, r_ohm, x_ohm, sn_mva,
name=None, in_service=True, index=None, **kwargs):
name=None, in_service=True, index=None,
r0_ohm=None, x0_ohm=None, **kwargs):
"""
Creates a series reactor as per-unit impedance
:param net: (pandapowerNet) - The pandapower network in which the element is created
Expand Down Expand Up @@ -3619,9 +3636,12 @@ def create_series_reactor_as_impedance(net, from_bus, to_bus, r_ohm, x_ohm, sn_m
base_z_ohm = vn_kv ** 2 / sn_mva
rft_pu = r_ohm / base_z_ohm
xft_pu = x_ohm / base_z_ohm
rft0_pu = r0_ohm / base_z_ohm if r0_ohm is not None else None
xft0_pu = x0_ohm / base_z_ohm if x0_ohm is not None else None

index = create_impedance(net, from_bus=from_bus, to_bus=to_bus, rft_pu=rft_pu, xft_pu=xft_pu,
sn_mva=sn_mva, name=name, in_service=in_service, index=index, **kwargs)
sn_mva=sn_mva, name=name, in_service=in_service, index=index,
rft0_pu=rft0_pu, xft0_pu=xft0_pu, **kwargs)
return index


Expand Down
2 changes: 1 addition & 1 deletion pandapower/pd2ppc.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def _pd2ppc(net, sequence=None):
_add_ext_grid_sc_impedance(net, ppc)
# Generator impedance are seperately added in sc module
_add_motor_impedances_ppc(net, ppc)

# TODO Roman: Implementation wind generation units IEC 60909-2016
else:
_calc_pq_elements_and_add_on_ppc(net, ppc, sequence=sequence)
Expand Down
30 changes: 27 additions & 3 deletions pandapower/pd2ppc_zero.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@
from pandapower.build_bus import _build_bus_ppc
from pandapower.build_gen import _build_gen_ppc
# from pandapower.pd2ppc import _ppc2ppci, _init_ppc
from pandapower.pypower.idx_brch import BR_B, BR_R, BR_X, F_BUS, T_BUS, branch_cols, BR_STATUS, SHIFT, TAP
from pandapower.pypower.idx_brch import BR_B, BR_R, BR_X, F_BUS, T_BUS, branch_cols, BR_STATUS, SHIFT, TAP, BR_R_ASYM, \
BR_X_ASYM
from pandapower.pypower.idx_bus import BASE_KV, BS, GS, BUS_TYPE
from pandapower.pypower.idx_brch_sc import branch_cols_sc
from pandapower.pypower.idx_bus_sc import C_MAX, C_MIN
from pandapower.build_branch import _calc_tap_from_dataframe, _transformer_correction_factor, _calc_nominal_ratio_from_dataframe,\
get_trafo_values, _trafo_df_from_trafo3w, _calc_branch_values_from_trafo_df, _calc_switch_parameter
from pandapower.build_branch import _calc_tap_from_dataframe, _transformer_correction_factor, \
_calc_nominal_ratio_from_dataframe, \
get_trafo_values, _trafo_df_from_trafo3w, _calc_branch_values_from_trafo_df, _calc_switch_parameter, \
_calc_impedance_parameters_from_dataframe
from pandapower.build_branch import _switch_branches, _branches_with_oos_buses, _initialize_branch_lookup, _end_temperature_correction_factor
from pandapower.pd2ppc import _ppc2ppci, _init_ppc

Expand Down Expand Up @@ -84,6 +87,7 @@ def _build_branch_ppc_zero(net, ppc, k_st=None):
ppc["branch"][:, :13] = np.array([0, 0, 0, 0, 0, 250, 250, 250, 1, 0, 1, -360, 360])

_add_line_sc_impedance_zero(net, ppc)
_add_impedance_sc_impedance_zero(net, ppc)
_add_trafo_sc_impedance_zero(net, ppc, k_st=k_st)
if "switch" in lookup:
_calc_switch_parameter(net, ppc)
Expand Down Expand Up @@ -456,6 +460,26 @@ def _add_line_sc_impedance_zero(net, ppc):
ppc["branch"][f:t, BR_STATUS] = line["in_service"].astype(int)


def _add_impedance_sc_impedance_zero(net, ppc):
branch_lookup = net["_pd2ppc_lookups"]["branch"]
if "impedance" not in branch_lookup:
return
bus_lookup = net["_pd2ppc_lookups"]["bus"]
branch = ppc["branch"]

f, t = branch_lookup["impedance"]

# impedance zero sequence impedance
rij, xij, r_asym, x_asym = _calc_impedance_parameters_from_dataframe(net, zero_sequence=True)
branch[f:t, BR_R] = rij
branch[f:t, BR_X] = xij
branch[f:t, BR_R_ASYM] = r_asym
branch[f:t, BR_X_ASYM] = x_asym
branch[f:t, F_BUS] = bus_lookup[net.impedance["from_bus"].values]
branch[f:t, T_BUS] = bus_lookup[net.impedance["to_bus"].values]
branch[f:t, BR_STATUS] = net["impedance"]["in_service"].values.astype(np.int64)


def _add_trafo3w_sc_impedance_zero(net, ppc):
# TODO Roman: check this/expand this
branch_lookup = net["_pd2ppc_lookups"]["branch"]
Expand Down
12 changes: 12 additions & 0 deletions pandapower/test/loadflow/test_runpp_3ph.py
Original file line number Diff line number Diff line change
Expand Up @@ -518,5 +518,17 @@ def test_balanced_power_flow_with_unbalanced_loads_and_sgens():
assert net.res_bus.vm_pu.equals(vm_pu)


def test_3ph_with_impedance():
nw_dir = os.path.abspath(os.path.join(pp.pp_dir, "test/loadflow"))
net = pp.from_json(nw_dir + '/runpp_3ph Validation.json')
net.line.c_nf_per_km = 0.
net.line.c0_nf_per_km = 0.
net_imp = net.deepcopy()
pp.replace_line_by_impedance(net_imp, net.line.index, 100)
pp.runpp_3ph(net)
pp.runpp_3ph(net_imp)
assert pp.dataframes_equal(net.res_bus_3ph, net_imp.res_bus_3ph)


if __name__ == "__main__":
pytest.main(["test_runpp_3ph.py"])
18 changes: 18 additions & 0 deletions pandapower/test/shortcircuit/test_1ph.py
Original file line number Diff line number Diff line change
Expand Up @@ -524,5 +524,23 @@ def test_trafo():
assert np.allclose(net.res_bus_sc.ikss_ka, results[vc], rtol=0, atol=1e-6), f"{vc}: inconsistent results"


def test_sc_1ph_impedance():
net = pp.create_empty_network()
pp.create_buses(net, 2, 110)
pp.create_ext_grid(net, 0, s_sc_max_mva=1000, s_sc_min_mva=800,
rx_max=0.1, x0x_max=1, r0x0_max=0.1,
rx_min=0.1, x0x_min=1, r0x0_min=0.1)
pp.create_impedance(net, 0, 1, rft_pu=0.2, xft_pu=0.4, sn_mva=50, rtf_pu=0.25, xtf_pu=0.5,
rft0_pu=0.1, xft0_pu=0.2, rtf0_pu=0.05, xtf0_pu=0.1)

sc.calc_sc(net, fault="1ph")

assert np.allclose(net.res_bus_sc.ikss_ka, [5.248639, 0.625166], rtol=0, atol=1e-6)
assert np.allclose(net.res_bus_sc.rk0_ohm, [1.324394, 12.762198], rtol=0, atol=1e-6)
assert np.allclose(net.res_bus_sc.xk0_ohm, [13.243945, 30.821973], rtol=0, atol=1e-6)
assert np.allclose(net.res_bus_sc.rk_ohm, [1.3243945, 62.1554916], rtol=0, atol=1e-5)
assert np.allclose(net.res_bus_sc.xk_ohm, [13.2439445, 137.5549268], rtol=0, atol=1e-5)


if __name__ == "__main__":
pytest.main([__file__])
24 changes: 21 additions & 3 deletions pandapower/toolbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -2176,7 +2176,16 @@ def replace_impedance_by_line(net, index=None, only_valid_replace=True, max_i_ka
if max_i == 'imp.sn_mva':
max_i = imp.sn_mva / vn / np.sqrt(3)
new_index.append(create_line_from_parameters(
net, imp.from_bus, imp.to_bus, 1, imp.rft_pu * Zni, imp.xft_pu * Zni, 0, max_i,
net, imp.from_bus, imp.to_bus,
length_km=1,
r_ohm_per_km=imp.rft_pu * Zni,
x_ohm_per_km=imp.xft_pu * Zni,
c_nf_per_km=0,
max_i_ka=max_i,
r0_ohm_per_km=imp.rft0_pu * Zni if "rft0_pu" in net.impedance.columns else None,
x0_ohm_per_km=imp.xft0_pu * Zni if "xft0_pu" in net.impedance.columns else None,
c0_nf_per_km=0,
parallel=1,
name=imp.name, in_service=imp.in_service))
net.impedance.drop(index, inplace=True)
return new_index
Expand Down Expand Up @@ -2206,6 +2215,9 @@ def replace_line_by_impedance(net, index=None, sn_mva=None, only_valid_replace=T
sn_mva = sn_mva if hasattr(sn_mva, "__iter__") else [sn_mva] * len(index)
if len(sn_mva) != len(index):
raise ValueError("index and sn_mva must have the same length.")

parallel = net.line["parallel"].values

i = 0
new_index = []
for idx, line_ in net.line.loc[index].iterrows():
Expand All @@ -2217,9 +2229,15 @@ def replace_line_by_impedance(net, index=None, sn_mva=None, only_valid_replace=T
"converted to impedances, which do not model such parameters.")
vn = net.bus.vn_kv.at[line_.from_bus]
Zni = vn ** 2 / sn_mva[i]
par = parallel[idx]
new_index.append(create_impedance(
net, line_.from_bus, line_.to_bus, line_.r_ohm_per_km * line_.length_km / Zni,
line_.x_ohm_per_km * line_.length_km / Zni, sn_mva[i], name=line_.name,
net, line_.from_bus, line_.to_bus,
rft_pu=line_.r_ohm_per_km * line_.length_km / (Zni * par),
xft_pu=line_.x_ohm_per_km * line_.length_km / (Zni * par),
sn_mva=sn_mva[i],
rft0_pu=line_.r0_ohm_per_km * line_.length_km / (Zni * par) if "r0_ohm_per_km" in net.line.columns else None,
xft0_pu=line_.x0_ohm_per_km * line_.length_km / (Zni * par) if "x0_ohm_per_km" in net.line.columns else None,
name=line_.name,
in_service=line_.in_service))
i += 1
drop_lines(net, index)
Expand Down

0 comments on commit 5d5620f

Please sign in to comment.