This tutorial introduces the pandapower controle module with the example of tap changer control. For this, we first load the MV oberrhein network that contains two 110/20 kV transformers:
# Importing necessary packages
import pandapower as pp
from pandapower.networks import mv_oberrhein
net = mv_oberrhein()
net.trafo
name | std_type | hv_bus | lv_bus | sn_mva | vn_hv_kv | vn_lv_kv | vk_percent | vkr_percent | pfe_kw | ... | tap_neutral | tap_min | tap_max | tap_step_percent | tap_step_degree | tap_pos | tap_phase_shifter | parallel | df | in_service | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
114 | HV/MV Transformer 0 | 25 MVA 110/20 kV | 58 | 39 | 25.0 | 110.0 | 20.0 | 11.2 | 0.282 | 29.0 | ... | 0 | -9 | 9 | 1.5 | NaN | -2 | False | 1 | 1.0 | True |
142 | HV/MV Transformer 1 | 25 MVA 110/20 kV | 318 | 319 | 25.0 | 110.0 | 20.0 | 11.2 | 0.282 | 29.0 | ... | 0 | -9 | 9 | 1.5 | NaN | -3 | False | 1 | 1.0 | True |
2 rows × 23 columns
If we run a power flow, we can see the voltage at the low voltage side of the transformers:
pp.runpp(net)
net.res_trafo.vm_lv_pu
114 1.014598 142 1.028804 Name: vm_lv_pu, dtype: float64
Both transformers include a tap changer with a range of -9 to +9, which are set to positions -2 and -3 respectively:
net.trafo["tap_pos"]
114 -2 142 -3 Name: tap_pos, dtype: int32
The tap position is constant within a power flow calculation. A controller can now be used to control the tap changer position depending on the bus voltage.
The DiscreteTapControl from the pandapower control package receives a deadband of permissable voltage and uses the tap changer to keep the voltage within this voltage band. We define such a controller for the first transformer in the oberrhein network with a deadband of 0.99 to 1.01pu:
import pandapower.control as control
trafo_controller = control.DiscreteTapControl(net=net, tid=114, vm_lower_pu=0.99, vm_uppe_pur=1.01)
The initiated controller automatically registers in the net. It can be found in the controller table:
net.controller
controller | in_service | order | level | recycle | |
---|---|---|---|---|---|
0 | DiscreteTapControl of trafo 114 | True | 0.0 | 0 | False |
We now run a controlled power flow by setting run_control=True within the runpp arguments and check the transformer voltage:
# running a control-loop
pp.runpp(net, run_control=True)
net.res_trafo.vm_lv_pu
114 0.998267 142 1.028804 Name: vm_lv_pu, dtype: float64
The voltage at transformer 114 is now within the given range. If we checke the transformer table, we can see that the tap position of the first transformer as been changed from -2 to -1:
net.trafo["tap_pos"]
114 -1 142 -3 Name: tap_pos, dtype: int32
It is also possible to control transformer with a ContiniousTapControl strategy. Instead of a range, this type of controller is able to achieve an exact output voltage. For this it assumes tap positions as floating numbers. We define such a controller for the second transformer in the network:
trafo_controller = control.ContinuousTapControl(net=net, tid=142, vm_set_pu=0.98, tol=1e-6)
If we now run the result, the low voltage side of the second transformer is controlled to exactly 0.98 pu:
pp.runpp(net, run_control=True)
net.res_trafo.vm_lv_pu
114 0.998267 142 0.980000 Name: vm_lv_pu, dtype: float64
The tap position is set to -0.07:
net.trafo["tap_pos"]
114 -1.000000 142 -0.067373 Name: tap_pos, dtype: float64
While this obviously would not possible in real transformers, it can be useful to assume continous taps in large scale studies to avoid big steps in the results.