Skip to content

Commit

Permalink
Merge pull request e2nIEE#2298 from e2nIEE/fix/trafo3w_tap
Browse files Browse the repository at this point in the history
Fix/trafo3w tap
  • Loading branch information
pawellytaev authored Jul 2, 2024
2 parents 2dadf8f + aadea6a commit 6f1113d
Show file tree
Hide file tree
Showing 8 changed files with 3,593 additions and 36 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Change Log

[upcoming release] - 2024-..-..
-------------------------------
- [FIXED] trafo3w with tap changer at star point corrected
- [FIXED] namespace changes from numpy 2.0 release
- [CHANGED] inf to np.full(...) with value inf for array operations in pypower folder
- [CHANGED] node existence check for multiple branch elements from mixed array and set operations to set operations only
Expand Down
24 changes: 17 additions & 7 deletions pandapower/build_branch.py
Original file line number Diff line number Diff line change
Expand Up @@ -984,9 +984,12 @@ def _trafo_df_from_trafo3w(net, sequence=1):
trafo2 = dict()
sides = ["hv", "mv", "lv"]
mode = net._options["mode"]
loss_side = net._options["trafo3w_losses"].lower()
nr_trafos = len(net["trafo3w"])
t3 = net["trafo3w"]
# todo check magnetizing impedance implementation:
#loss_side = net._options["trafo3w_losses"].lower()
loss_side = t3.loss_side.values if "loss_side" in t3.columns else np.full(len(t3),
net._options["trafo3w_losses"].lower())
nr_trafos = len(net["trafo3w"])
if sequence==1:
mode_tmp = "type_c" if mode == "sc" and net._options.get("use_pre_fault_voltage", False) else mode
_calculate_sc_voltages_of_equivalent_transformers(t3, trafo2, mode_tmp, characteristic=net.get(
Expand All @@ -1004,8 +1007,11 @@ def _trafo_df_from_trafo3w(net, sequence=1):
trafo2["hv_bus"] = {"hv": t3.hv_bus.values, "mv": aux_buses, "lv": aux_buses}
trafo2["lv_bus"] = {"hv": aux_buses, "mv": t3.mv_bus.values, "lv": t3.lv_bus.values}
trafo2["in_service"] = {side: t3.in_service.values for side in sides}
trafo2["i0_percent"] = {side: t3.i0_percent.values if loss_side == side else zeros for side in sides}
trafo2["pfe_kw"] = {side: t3.pfe_kw.values if loss_side == side else zeros for side in sides}
# todo check magnetizing impedance implementation:
#trafo2["i0_percent"] = {side: t3.i0_percent.values if loss_side == side else zeros for side in sides}
#trafo2["pfe_kw"] = {side: t3.pfe_kw.values if loss_side == side else zeros for side in sides}
trafo2["i0_percent"] = {side: np.where(loss_side == side, t3.i0_percent.values, zeros) for side in sides}
trafo2["pfe_kw"] = {side: np.where(loss_side == side, t3.pfe_kw.values, zeros) for side in sides}
trafo2["vn_hv_kv"] = {side: t3.vn_hv_kv.values for side in sides}
trafo2["vn_lv_kv"] = {side: t3["vn_%s_kv" % side].values for side in sides}
trafo2["shift_degree"] = {"hv": np.zeros(nr_trafos), "mv": t3.shift_mv_degree.values,
Expand Down Expand Up @@ -1105,8 +1111,12 @@ def _calculate_3w_tap_changers(t3, t2, sides):
tap_arrays["tap_side"][side][tap_mask] = "hv" if side == "hv" else "lv"

# t3 trafos with tap changer at star points
if any_at_star_point:
mask_star_point = tap_mask & at_star_point
if any_at_star_point & np.any(mask_star_point := (tap_mask & at_star_point)):
t = tap_arrays["tap_step_percent"][side][mask_star_point] * np.exp(1j * np.deg2rad(tap_arrays["tap_step_degree"][side][mask_star_point]))
tap_pos = tap_arrays["tap_pos"][side][mask_star_point]
t_corrected = 100 * t / (100 + (t * tap_pos))
tap_arrays["tap_step_percent"][side][mask_star_point] = np.abs(t_corrected)
tap_arrays["tap_side"][side][mask_star_point] = "lv" if side == "hv" else "hv"
tap_arrays["tap_step_degree"][side][mask_star_point] += 180
tap_arrays["tap_step_degree"][side][mask_star_point] = np.rad2deg(np.angle(t_corrected))
tap_arrays["tap_step_degree"][side][mask_star_point] -= 180
t2.update(tap_arrays)
4 changes: 0 additions & 4 deletions pandapower/converter/powerfactory/pp_import_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2417,10 +2417,6 @@ def create_trafo3w(net, item, tap_opt='nntap'):
'in_service': not bool(item.outserv)
}

if params['tap_at_star_point']:
logger.warning('%s: implementation for tap changer at star point is not finalized - it can '
'lead to wrong results for voltage' % item.loc_name)

if item.nt3nm != 1:
logger.warning("trafo3w %s has parallel=%d, this is not implemented. "
"Calculation results will be incorrect." % (item.loc_name, item.nt3nm))
Expand Down
27 changes: 27 additions & 0 deletions pandapower/test/loadflow/test_results.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

# Copyright (c) 2016-2024 by University of Kassel and Fraunhofer Institute for Energy Economics
# and Energy System Technology (IEE), Kassel. All rights reserved.
import os
import pandas as pd
import pytest
import numpy as np
from numpy import in1d, isnan, isclose, allclose

import pandapower as pp
Expand Down Expand Up @@ -635,6 +637,31 @@ def test_trafo3w(result_test_network, v_tol=1e-6, i_tol=1e-6, s_tol=2e-2, l_tol=
assert abs((net.res_trafo3w.i_mv_ka.at[t3] - imv)) < i_tol
assert abs((net.res_trafo3w.i_lv_ka.at[t3] - ilv)) < i_tol

@pytest.mark.parametrize("tap_pos", (-1, 2))
@pytest.mark.parametrize("tap_side", ('hv', 'mv', 'lv'))
@pytest.mark.parametrize("tap_step_degree", (15, 30))
def test_trafo3w_tap(tap_pos, tap_side, tap_step_degree):
results = pd.read_csv(os.path.join(pp.pp_dir, "test", "test_files", "test_results_files", "trafo_3w_tap_results.csv"), sep=";", decimal=",")

if results.query("tap_side == @tap_side & tap_pos == @tap_pos & tap_step_degree == @tap_step_degree").empty:
pytest.skip(f"Skipping combination: tap_side={tap_side}, tap_pos={tap_pos}, tap_step_degree={tap_step_degree}")

net = pp.from_json(os.path.join(pp.pp_dir, "test", "test_files","test_trafo3w_tap.json")) #
net.trafo3w.loc[0, 'tap_at_star_point']= False
net.trafo3w.loc[1, 'tap_at_star_point']= True

net.trafo3w.loc[0, "tap_side"] = tap_side
net.trafo3w.loc[1, "tap_side"] = tap_side
net.trafo3w.loc[0, "tap_pos"] = tap_pos
net.trafo3w.loc[1, "tap_pos"] = tap_pos
net.trafo3w.loc[0, "tap_step_degree"] = tap_step_degree
net.trafo3w.loc[1, "tap_step_degree"] = tap_step_degree
pp.runpp(net)

for index in range(8):
for variable, tol in zip(("vm_pu", "va_degree"), (1e-6, 1e-3)):
assert np.isclose(net.res_bus.at[index, variable], results.query("tap_side==@tap_side & tap_pos==@tap_pos & tap_step_degree==@tap_step_degree &"
"index==@index & element=='bus' & variable==@variable").value, rtol=0, atol=tol), f"failed for bus {index=}, {variable}, value {net.res_bus.at[index, variable]}"

def test_impedance(result_test_network, v_tol=1e-6, i_tol=1e-6, s_tol=5e-3, l_tol=1e-3):
net = result_test_network
Expand Down
129 changes: 129 additions & 0 deletions pandapower/test/test_files/test_results_files/trafo_3w_tap_results.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
tap_side;tap_pos;tap_step_degree;element;name;index;variable;value
hv;2;0;bus;0_Slack;0;vm_pu;1
hv;2;0;bus;0_Slack;0;va_degree;0
hv;2;0;bus;1_HV;1;vm_pu;0,998129
hv;2;0;bus;1_HV;1;va_degree;-0,093039
hv;2;0;bus;2_MV;2;vm_pu;0,898854
hv;2;0;bus;2_MV;2;va_degree;-0,686136
hv;2;0;bus;3_LV;3;vm_pu;0,903326
hv;2;0;bus;3_LV;3;va_degree;-0,394202
hv;2;0;bus;4_Slack;4;vm_pu;1
hv;2;0;bus;4_Slack;4;va_degree;0
hv;2;0;bus;5_HV;5;vm_pu;0,998127
hv;2;0;bus;5_HV;5;va_degree;-0,092972
hv;2;0;bus;6_MV;6;vm_pu;0,898367
hv;2;0;bus;6_MV;6;va_degree;-0,723542
hv;2;0;bus;7_LV;7;vm_pu;0,902842
hv;2;0;bus;7_LV;7;va_degree;-0,431292
hv;-1;0;bus;0_Slack;0;vm_pu;1
hv;-1;0;bus;0_Slack;0;va_degree;0
hv;-1;0;bus;1_HV;1;vm_pu;0,998009
hv;-1;0;bus;1_HV;1;va_degree;-0,092674
hv;-1;0;bus;2_MV;2;vm_pu;1,042353
hv;-1;0;bus;2_MV;2;va_degree;-0,583495
hv;-1;0;bus;3_LV;3;vm_pu;1,046203
hv;-1;0;bus;3_LV;3;va_degree;-0,366142
hv;-1;0;bus;4_Slack;4;vm_pu;1
hv;-1;0;bus;4_Slack;4;va_degree;0
hv;-1;0;bus;5_HV;5;vm_pu;0,99801
hv;-1;0;bus;5_HV;5;va_degree;-0,092708
hv;-1;0;bus;6_MV;6;vm_pu;1,042629
hv;-1;0;bus;6_MV;6;va_degree;-0,565781
hv;-1;0;bus;7_LV;7;vm_pu;1,046477
hv;-1;0;bus;7_LV;7;va_degree;-0,348542
mv;2;0;bus;0_Slack;0;vm_pu;1
mv;2;0;bus;0_Slack;0;va_degree;0
mv;2;0;bus;1_HV;1;vm_pu;0,998058
mv;2;0;bus;1_HV;1;va_degree;-0,092876
mv;2;0;bus;2_MV;2;vm_pu;1,089856
mv;2;0;bus;2_MV;2;va_degree;-0,555702
mv;2;0;bus;3_LV;3;vm_pu;0,993842
mv;2;0;bus;3_LV;3;va_degree;-0,374824
mv;2;0;bus;4_Slack;4;vm_pu;1
mv;2;0;bus;4_Slack;4;va_degree;0
mv;2;0;bus;5_HV;5;vm_pu;0,998055
mv;2;0;bus;5_HV;5;va_degree;-0,092822
mv;2;0;bus;6_MV;6;vm_pu;1,088759
mv;2;0;bus;6_MV;6;va_degree;-0,61575
mv;2;0;bus;7_LV;7;vm_pu;0,993837
mv;2;0;bus;7_LV;7;va_degree;-0,374788
mv;-1;0;bus;0_Slack;0;vm_pu;1
mv;-1;0;bus;0_Slack;0;va_degree;0
mv;-1;0;bus;1_HV;1;vm_pu;0,998054
mv;-1;0;bus;1_HV;1;va_degree;-0,092788
mv;-1;0;bus;2_MV;2;vm_pu;0,9397
mv;-1;0;bus;2_MV;2;va_degree;-0,653191
mv;-1;0;bus;3_LV;3;vm_pu;0,993834
mv;-1;0;bus;3_LV;3;va_degree;-0,374766
mv;-1;0;bus;4_Slack;4;vm_pu;1
mv;-1;0;bus;4_Slack;4;va_degree;0
mv;-1;0;bus;5_HV;5;vm_pu;0,998055
mv;-1;0;bus;5_HV;5;va_degree;-0,092822
mv;-1;0;bus;6_MV;6;vm_pu;0,940291
mv;-1;0;bus;6_MV;6;va_degree;-0,61575
mv;-1;0;bus;7_LV;7;vm_pu;0,993837
mv;-1;0;bus;7_LV;7;va_degree;-0,374788
lv;2;0;bus;0_Slack;0;vm_pu;1
lv;2;0;bus;0_Slack;0;va_degree;0
lv;2;0;bus;1_HV;1;vm_pu;0,998056
lv;2;0;bus;1_HV;1;va_degree;-0,092829
lv;2;0;bus;2_MV;2;vm_pu;0,989781
lv;2;0;bus;2_MV;2;va_degree;-0,615751
lv;2;0;bus;3_LV;3;vm_pu;1,093532
lv;2;0;bus;3_LV;3;va_degree;-0,356789
lv;2;0;bus;4_Slack;4;vm_pu;1
lv;2;0;bus;4_Slack;4;va_degree;0
lv;2;0;bus;5_HV;5;vm_pu;0,998055
lv;2;0;bus;5_HV;5;va_degree;-0,092822
lv;2;0;bus;6_MV;6;vm_pu;0,98978
lv;2;0;bus;6_MV;6;va_degree;-0,61575
lv;2;0;bus;7_LV;7;vm_pu;1,093221
lv;2;0;bus;7_LV;7;va_degree;-0,374788
lv;-1;0;bus;0_Slack;0;vm_pu;1
lv;-1;0;bus;0_Slack;0;va_degree;0
lv;-1;0;bus;1_HV;1;vm_pu;0,998055
lv;-1;0;bus;1_HV;1;va_degree;-0,092817
lv;-1;0;bus;2_MV;2;vm_pu;0,98978
lv;-1;0;bus;2_MV;2;va_degree;-0,61575
lv;-1;0;bus;3_LV;3;vm_pu;0,943978
lv;-1;0;bus;3_LV;3;va_degree;-0,385997
lv;-1;0;bus;4_Slack;4;vm_pu;1
lv;-1;0;bus;4_Slack;4;va_degree;0
lv;-1;0;bus;5_HV;5;vm_pu;0,998055
lv;-1;0;bus;5_HV;5;va_degree;-0,092822
lv;-1;0;bus;6_MV;6;vm_pu;0,98978
lv;-1;0;bus;6_MV;6;va_degree;-0,61575
lv;-1;0;bus;7_LV;7;vm_pu;0,944145
lv;-1;0;bus;7_LV;7;va_degree;-0,374788
hv;2;15;bus;0_Slack;0;vm_pu;1
hv;2;15;bus;0_Slack;0;va_degree;0
hv;2;15;bus;1_HV;1;vm_pu;0,998127
hv;2;15;bus;1_HV;1;va_degree;-0,093034
hv;2;15;bus;2_MV;2;vm_pu;0,901427
hv;2;15;bus;2_MV;2;va_degree;-2,035887
hv;2;15;bus;3_LV;3;vm_pu;0,905886
hv;2;15;bus;3_LV;3;va_degree;-1,74561
hv;2;15;bus;4_Slack;4;vm_pu;1
hv;2;15;bus;4_Slack;4;va_degree;0
hv;2;15;bus;5_HV;5;vm_pu;0,998125
hv;2;15;bus;5_HV;5;va_degree;-0,092969
hv;2;15;bus;6_MV;6;vm_pu;0,900955
hv;2;15;bus;6_MV;6;va_degree;-2,07209
hv;2;15;bus;7_LV;7;vm_pu;0,905417
hv;2;15;bus;7_LV;7;va_degree;-1,781509
hv;-1;30;bus;0_Slack;0;vm_pu;1
hv;-1;30;bus;0_Slack;0;va_degree;0
hv;-1;30;bus;1_HV;1;vm_pu;0,998016
hv;-1;30;bus;1_HV;1;va_degree;-0,092697
hv;-1;30;bus;2_MV;2;vm_pu;1,034638
hv;-1;30;bus;2_MV;2;va_degree;0,908979
hv;-1;30;bus;3_LV;3;vm_pu;1,038516
hv;-1;30;bus;3_LV;3;va_degree;1,129574
hv;-1;30;bus;4_Slack;4;vm_pu;1
hv;-1;30;bus;4_Slack;4;va_degree;0
hv;-1;30;bus;5_HV;5;vm_pu;0,998017
hv;-1;30;bus;5_HV;5;va_degree;-0,092725
hv;-1;30;bus;6_MV;6;vm_pu;1,034873
hv;-1;30;bus;6_MV;6;va_degree;0,924241
hv;-1;30;bus;7_LV;7;vm_pu;1,038751
hv;-1;30;bus;7_LV;7;va_degree;1,144736
Loading

0 comments on commit 6f1113d

Please sign in to comment.