Transformer with non-trivial phase shift and tap ratio

Note

You can download this example as a Jupyter notebook or start it in interactive mode.

Transformer with non-trivial phase shift and tap ratio#

This example is a copy of pandapower’s minimal example.

[1]:
import numpy as np
import pandas as pd

import pypsa
[2]:
network = pypsa.Network()

network.add("Bus", "MV bus", v_nom=20, v_mag_pu_set=1.02)
network.add("Bus", "LV1 bus", v_nom=0.4)
network.add("Bus", "LV2 bus", v_nom=0.4)

network.add(
    "Transformer",
    "MV-LV trafo",
    type="0.4 MVA 20/0.4 kV",
    bus0="MV bus",
    bus1="LV1 bus",
)
network.add(
    "Line", "LV cable", type="NAYY 4x50 SE", bus0="LV1 bus", bus1="LV2 bus", length=0.1
)
network.add(
    "Generator", "External Grid", bus="MV bus", control="Slack", marginal_cost=10
)
network.add("Load", "LV load", bus="LV2 bus", p_set=0.1, q_set=0.05)
[2]:
Index(['LV load'], dtype='object')
[3]:
def run_pf():
    network.lpf()
    network.pf(use_seed=True)
    return pd.DataFrame(
        {
            "Voltage Angles": network.buses_t.v_ang.loc["now"] * 180.0 / np.pi,
            "Volate Magnitude": network.buses_t.v_mag_pu.loc["now"],
        }
    )
[4]:
run_pf()
INFO:pypsa.pf:Performing linear load-flow on AC sub-network <pypsa.networks.SubNetwork object at 0x7502b4628c20> for snapshot(s) Index(['now'], dtype='object', name='snapshot')
INFO:pypsa.pf:Performing non-linear load-flow on AC sub-network <pypsa.networks.SubNetwork object at 0x75026cd38550> for snapshots Index(['now'], dtype='object', name='snapshot')
[4]:
Voltage Angles Volate Magnitude
Bus
MV bus 0.000000 1.020000
LV1 bus -150.760126 1.008843
LV2 bus -149.884141 0.964431
[5]:
network.transformers.tap_position = 2
run_pf()
INFO:pypsa.pf:Performing linear load-flow on AC sub-network <pypsa.networks.SubNetwork object at 0x75026d113ed0> for snapshot(s) Index(['now'], dtype='object', name='snapshot')
INFO:pypsa.pf:Performing non-linear load-flow on AC sub-network <pypsa.networks.SubNetwork object at 0x75026ceb6c40> for snapshots Index(['now'], dtype='object', name='snapshot')
[5]:
Voltage Angles Volate Magnitude
Bus
MV bus 0.000000 1.020000
LV1 bus -150.843911 0.959655
LV2 bus -149.870837 0.912713
[6]:
network.transformers.tap_position = -2
run_pf()
INFO:pypsa.pf:Performing linear load-flow on AC sub-network <pypsa.networks.SubNetwork object at 0x75026ceb6c40> for snapshot(s) Index(['now'], dtype='object', name='snapshot')
INFO:pypsa.pf:Performing non-linear load-flow on AC sub-network <pypsa.networks.SubNetwork object at 0x75026cdbe7b0> for snapshots Index(['now'], dtype='object', name='snapshot')
[6]:
Voltage Angles Volate Magnitude
Bus
MV bus 0.000000 1.020000
LV1 bus -150.681666 1.063133
LV2 bus -149.896634 1.021202

Now play with tap changer on LV side

[7]:
new_trafo_lv_tap = network.transformer_types.loc[["0.4 MVA 20/0.4 kV"]]
new_trafo_lv_tap.index = ["New trafo"]
new_trafo_lv_tap.tap_side = 1
new_trafo_lv_tap.T
[7]:
New trafo
f_nom 50.0
s_nom 0.4
v_nom_0 20.0
v_nom_1 0.4
vsc 6.0
vscr 1.425
pfe 1.35
i0 0.3375
phase_shift 150.0
tap_side 1
tap_neutral 0
tap_min -2
tap_max 2
tap_step 2.5
references pandapower;Oswald - Transformatoren - Vorlesun...
[8]:
network.transformer_types = pd.concat([network.transformer_types, new_trafo_lv_tap])
network.transformers.type = "New trafo"
network.transformers.tap_position = 2
run_pf()
INFO:pypsa.pf:Performing linear load-flow on AC sub-network <pypsa.networks.SubNetwork object at 0x75026cf09d00> for snapshot(s) Index(['now'], dtype='object', name='snapshot')
INFO:pypsa.pf:Performing non-linear load-flow on AC sub-network <pypsa.networks.SubNetwork object at 0x75026cf09d00> for snapshots Index(['now'], dtype='object', name='snapshot')
[8]:
Voltage Angles Volate Magnitude
Bus
MV bus 0.000000 1.020000
LV1 bus -150.755820 1.059317
LV2 bus -149.964875 1.017221
[9]:
network.transformers.T
[9]:
Transformer MV-LV trafo
bus0 MV bus
bus1 LV1 bus
type New trafo
model t
x 0.058283
r 0.01425
g 0.003375
b -0.0
s_nom 0.4
s_nom_mod 0.0
s_nom_extendable False
s_nom_min 0.0
s_nom_max inf
s_max_pu 1.0
capital_cost 0.0
num_parallel 1.0
tap_ratio 1.05
tap_side 1
tap_position 2
phase_shift 150.0
active True
build_year 0
lifetime inf
v_ang_min -inf
v_ang_max inf
sub_network 0
x_pu 0.145712
r_pu 0.035618
g_pu 0.00135
b_pu -0.0
x_pu_eff 0.152994
r_pu_eff 0.037406
s_nom_opt 0.0
[10]:
network.transformers.tap_position = -2
run_pf()
INFO:pypsa.pf:Performing linear load-flow on AC sub-network <pypsa.networks.SubNetwork object at 0x75026cc36450> for snapshot(s) Index(['now'], dtype='object', name='snapshot')
INFO:pypsa.pf:Performing non-linear load-flow on AC sub-network <pypsa.networks.SubNetwork object at 0x75026cebf750> for snapshots Index(['now'], dtype='object', name='snapshot')
[10]:
Voltage Angles Volate Magnitude
Bus
MV bus 0.000000 1.020000
LV1 bus -150.765232 0.958366
LV2 bus -149.789394 0.911353

Now make sure that the phase shift is also there in the LOPF

[11]:
network.generators.p_nom = 1.0
network.lines.s_nom = 1.0
network.optimize()
pd.DataFrame(
    {
        "Voltage Angles": network.buses_t.v_ang.loc["now"] * 180.0 / np.pi,
        "Volate Magnitude": network.buses_t.v_mag_pu.loc["now"],
    }
)
WARNING:pypsa.consistency:The following sub_networks have carriers which are not defined:
Index(['0'], dtype='object', name='SubNetwork')
WARNING:pypsa.consistency:The following lines have carriers which are not defined:
Index(['LV cable'], dtype='object', name='Line')
WARNING:pypsa.consistency:The following buses have carriers which are not defined:
Index(['MV bus', 'LV1 bus', 'LV2 bus'], dtype='object', name='Bus')
INFO:linopy.model: Solve problem using Highs solver
INFO:linopy.io: Writing time: 0.03s
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 3 primals, 9 duals
Objective: 1.00e+00
Solver model: available
Solver message: optimal

INFO:pypsa.optimization.optimize:The shadow-prices of the constraints Generator-fix-p-lower, Generator-fix-p-upper, Line-fix-s-lower, Line-fix-s-upper, Transformer-fix-s-lower, Transformer-fix-s-upper were not assigned to the network.
Running HiGHS 1.10.0 (git hash: fd86653): Copyright (c) 2025 HiGHS under MIT licence terms
LP   linopy-problem-zfaq2apq has 9 rows; 3 cols; 11 nonzeros
Coefficient ranges:
  Matrix [1e+00, 1e+00]
  Cost   [1e+01, 1e+01]
  Bound  [0e+00, 0e+00]
  RHS    [1e-01, 1e+00]
Presolving model
0 rows, 0 cols, 0 nonzeros  0s
0 rows, 0 cols, 0 nonzeros  0s
Presolve : Reductions: rows 0(-9); columns 0(-3); elements 0(-11) - Reduced to empty
Solving the original LP from the solution after postsolve
Model name          : linopy-problem-zfaq2apq
Model status        : Optimal
Objective value     :  1.0000000000e+00
Relative P-D gap    :  0.0000000000e+00
HiGHS run time      :          0.00
Writing the solution to /tmp/linopy-solve-5wuwper2.sol
[11]:
Voltage Angles Volate Magnitude
Bus
MV bus 0.627810 1.020000
LV1 bus -0.165294 0.958366
LV2 bus -0.462516 0.911353