{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Introduction to the pandapower control module" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
namestd_typehv_buslv_bussn_mvavn_hv_kvvn_lv_kvvk_percentvkr_percentpfe_kw...tap_neutraltap_mintap_maxtap_step_percenttap_step_degreetap_postap_phase_shifterparalleldfin_service
114HV/MV Transformer 025 MVA 110/20 kV583925.0110.020.011.20.28229.0...0-991.5NaN-2False11.0True
142HV/MV Transformer 125 MVA 110/20 kV31831925.0110.020.011.20.28229.0...0-991.5NaN-3False11.0True
\n", "

2 rows × 23 columns

\n", "
" ], "text/plain": [ " name std_type hv_bus lv_bus sn_mva vn_hv_kv \\\n", "114 HV/MV Transformer 0 25 MVA 110/20 kV 58 39 25.0 110.0 \n", "142 HV/MV Transformer 1 25 MVA 110/20 kV 318 319 25.0 110.0 \n", "\n", " vn_lv_kv vk_percent vkr_percent pfe_kw ... tap_neutral tap_min \\\n", "114 20.0 11.2 0.282 29.0 ... 0 -9 \n", "142 20.0 11.2 0.282 29.0 ... 0 -9 \n", "\n", " tap_max tap_step_percent tap_step_degree tap_pos tap_phase_shifter \\\n", "114 9 1.5 NaN -2 False \n", "142 9 1.5 NaN -3 False \n", "\n", " parallel df in_service \n", "114 1 1.0 True \n", "142 1 1.0 True \n", "\n", "[2 rows x 23 columns]" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Importing necessary packages\n", "import pandapower as pp\n", "from pandapower.networks import mv_oberrhein\n", "\n", "net = mv_oberrhein()\n", "net.trafo" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we run a power flow, we can see the voltage at the low voltage side of the transformers:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "114 1.014598\n", "142 1.028804\n", "Name: vm_lv_pu, dtype: float64" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pp.runpp(net)\n", "net.res_trafo.vm_lv_pu" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Both transformers include a tap changer with a range of -9 to +9, which are set to positions -2 and -3 respectively:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "114 -2\n", "142 -3\n", "Name: tap_pos, dtype: int32" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "net.trafo[\"tap_pos\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Discrete Tap Control" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "import pandapower.control as control\n", "trafo_controller = control.DiscreteTapControl(net=net, tid=114, vm_lower_pu=0.99, vm_upper_pu=1.01)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The initiated controller automatically registers in the net. It can be found in the controller table:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
objectin_serviceorderlevelinitial_runrecycle
0DiscreteTapControl of trafo 114True0.00True{'trafo': True, 'gen': False, 'bus_pq': False}
\n", "
" ], "text/plain": [ " object in_service order level initial_run \\\n", "0 DiscreteTapControl of trafo 114 True 0.0 0 True \n", "\n", " recycle \n", "0 {'trafo': True, 'gen': False, 'bus_pq': False} " ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "net.controller" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We now run a controlled power flow by setting **run_control=True** within the runpp arguments and check the transformer voltage:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "114 0.998267\n", "142 1.028804\n", "Name: vm_lv_pu, dtype: float64" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# running a control-loop\n", "pp.runpp(net, run_control=True)\n", "net.res_trafo.vm_lv_pu" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "114 -1\n", "142 -3\n", "Name: tap_pos, dtype: int32" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "net.trafo[\"tap_pos\"]" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "114 25 MVA 110/20 kV\n", "142 25 MVA 110/20 kV\n", "Name: std_type, dtype: object" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "net.trafo.std_type" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Discrete Tap Control: Alternative mode" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "net.controller.drop([trafo_controller.index], inplace = True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The tap step percent is an alternative way to Discrete Tap Control. It sets a single voltage instead of a deadband of permissable voltage and calculates the voltage limit for the upper and lower side by adding and subtracting the vm_delta_pu respectively. We define such a controller for the first transformer as an alternative to Discrete Tap Control in the oberrhein network with a voltage of 1.05 pu:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.0075 1.0425 1.0575\n" ] } ], "source": [ "vm_delta_pu = net.trafo.at[142, \"tap_step_percent\"] / 100. * .5\n", "vm_lower_pu = 1.05 - vm_delta_pu\n", "vm_upper_pu = 1.05 + vm_delta_pu\n", "print(vm_delta_pu,vm_lower_pu,vm_upper_pu)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We got the limit of upper side voltage by adding the vm_delta_pu to the set voltage and the lower side voltage limit by substracting the vm_delta_pu from the vm_set_pu." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "trafo_controller2 = control.DiscreteTapControl.from_tap_step_percent(net=net, tid=114, vm_set_pu=1.05, side=\"lv\", tol=1e-3, in_service=True, order=0,\n", " drop_same_existing_ctrl=False, matching_params=None)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here we added the tap step percent to the first transformer" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "pp.runpp(net, run_control=True)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
objectin_serviceorderlevelinitial_runrecycle
0DiscreteTapControl of trafo 114True0.00True{'trafo': True, 'gen': False, 'bus_pq': False}
\n", "
" ], "text/plain": [ " object in_service order level initial_run \\\n", "0 DiscreteTapControl of trafo 114 True 0.0 0 True \n", "\n", " recycle \n", "0 {'trafo': True, 'gen': False, 'bus_pq': False} " ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "net.controller" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "114 1.048740\n", "142 1.028804\n", "Name: vm_lv_pu, dtype: float64" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "net.res_trafo.vm_lv_pu" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The voltage at transformer 114 is now changed to 1.048740 which is between the upper and lower limits" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
p_hv_mwq_hv_mvarp_lv_mwq_lv_mvarpl_mwql_mvari_hv_kai_lv_kavm_hv_puva_hv_degreevm_lv_puva_lv_degreeloading_percent
11417.2450993.741077-17.181802-2.5110610.0632981.2300160.0926190.4779691.00.01.048740-3.94403270.584884
14220.8630174.653035-20.784893-2.7894310.0781231.8636050.1121930.5884381.00.01.028804-4.94395385.502393
\n", "
" ], "text/plain": [ " p_hv_mw q_hv_mvar p_lv_mw q_lv_mvar pl_mw ql_mvar i_hv_ka \\\n", "114 17.245099 3.741077 -17.181802 -2.511061 0.063298 1.230016 0.092619 \n", "142 20.863017 4.653035 -20.784893 -2.789431 0.078123 1.863605 0.112193 \n", "\n", " i_lv_ka vm_hv_pu va_hv_degree vm_lv_pu va_lv_degree loading_percent \n", "114 0.477969 1.0 0.0 1.048740 -3.944032 70.584884 \n", "142 0.588438 1.0 0.0 1.028804 -4.943953 85.502393 " ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "net.res_trafo" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "114 -4\n", "142 -3\n", "Name: tap_pos, dtype: int32" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "net.trafo[\"tap_pos\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The tap position of the second transformer has been changed from -1 to -4:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Continous Tap Control\n", "\n", "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:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "trafo_controller = control.ContinuousTapControl(net=net, tid=142, vm_set_pu=0.98, tol=1e-6)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we now run the result, the low voltage side of the second transformer is controlled to exactly 0.98 pu:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "114 1.04874\n", "142 0.98000\n", "Name: vm_lv_pu, dtype: float64" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pp.runpp(net, run_control=True)\n", "net.res_trafo.vm_lv_pu" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The tap position is set to -0.07:" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "114 -4.000000\n", "142 -0.067373\n", "Name: tap_pos, dtype: float64" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "net.trafo[\"tap_pos\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.13" } }, "nbformat": 4, "nbformat_minor": 2 }