{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# pandapower WLS State Estimation\n", "This is an introduction into the usage of the pandapower state estimation module. It shows how to \n", "create measurements for a pandapower network and how to perform a state estimation with the weighted least squares (WLS) algorithm.\n", "\n", "## Example Network\n", "\n", "We will be using the reference network from the book \"Power System State Estimation\" by Ali Abur and Antonio Gómez Expósito. \n", "It contains 3 buses with connecting lines between buses 1-2, 1-3 and 2-3. 8 measurements of different types enable WLS state estimation.\n", "\n", "We first create this network in pandapower." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "This pandapower network includes the following parameter tables:\n", " - line (3 elements)\n", " - bus (3 elements)\n", " - ext_grid (1 elements)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import pandapower as pp\n", "\n", "net = pp.create_empty_network()\n", "\n", "b1 = pp.create_bus(net, name=\"bus 1\", vn_kv=1., index=1)\n", "b2 = pp.create_bus(net, name=\"bus 2\", vn_kv=1., index=2)\n", "b3 = pp.create_bus(net, name=\"bus 3\", vn_kv=1., index=3)\n", "\n", "pp.create_ext_grid(net, 1) # set the slack bus to bus 1\n", "\n", "l1 = pp.create_line_from_parameters(net, 1, 2, 1, r_ohm_per_km=.01, x_ohm_per_km=.03, c_nf_per_km=0., max_i_ka=1)\n", "l2 = pp.create_line_from_parameters(net, 1, 3, 1, r_ohm_per_km=.02, x_ohm_per_km=.05, c_nf_per_km=0., max_i_ka=1)\n", "l3 = pp.create_line_from_parameters(net, 2, 3, 1, r_ohm_per_km=.03, x_ohm_per_km=.08, c_nf_per_km=0., max_i_ka=1)\n", "\n", "net" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we can add our measurements, which are valid for one point in time.\n", "\n", "We add two voltage magnitude measurements on buses 1 / 2 with voltage magnitude of 1.006 pu / 0.968 pu and a standard deviation of 0.004 pu each:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Adding Measurements\n", "\n", "Measurements are defined via the pandapower *create_measurement* function. \n", "The physical properties which can be measured are set with the *type* argument and can be one of the following: \"p\" for active power, \"q\" for reactive power, \"v\" for voltage and \"i\" for electrical current. \n", "The element is set with the *element_type* argument, it can be either \"bus\", \"line\" or \"transformer\". \n", "Power is measured in kW / kVar, voltage in per unit and current in A. Bus power injections are positive if power is generated at the bus and negative if it is consumed." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false, "scrolled": true }, "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", "
nametypeelement_typevaluestd_devbuselement
0Nonevbus1.0060.0041None
1Nonevbus0.9680.0042None
\n", "
" ], "text/plain": [ " name type element_type value std_dev bus element\n", "0 None v bus 1.006 0.004 1 None\n", "1 None v bus 0.968 0.004 2 None" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pp.create_measurement(net, \"v\", \"bus\", 1.006, .004, b1) # V at bus 1\n", "pp.create_measurement(net, \"v\", \"bus\", 0.968, .004, b2) # V at bus 2\n", "net.measurement" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We add bus injection measurements on bus 2 with P=-501 kW and Q=-286kVar and standard deviations of 10kVA: " ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "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", "
nametypeelement_typevaluestd_devbuselement
0Nonevbus1.0060.0041None
1Nonevbus0.9680.0042None
2Nonepbus-501.00010.0002None
3Noneqbus-286.00010.0002None
\n", "
" ], "text/plain": [ " name type element_type value std_dev bus element\n", "0 None v bus 1.006 0.004 1 None\n", "1 None v bus 0.968 0.004 2 None\n", "2 None p bus -501.000 10.000 2 None\n", "3 None q bus -286.000 10.000 2 None" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pp.create_measurement(net, \"p\", \"bus\", -501, 10, b2) # P at bus 2\n", "pp.create_measurement(net, \"q\", \"bus\", -286, 10, b2) # Q at bus 2\n", "net.measurement" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, we add line measurements for lines 0 and 1, both placed at the side of bus 1. The bus parameter defines the bus at which the line measurement is positioned, the line argument is the index of the line." ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
nametypeelement_typevaluestd_devbuselement
0Nonevbus1.0060.0041None
1Nonevbus0.9680.0042None
2Nonepbus-501.00010.0002None
3Noneqbus-286.00010.0002None
4Nonepline888.0008.00010
5Nonepline1173.0008.00011
6Noneqline568.0008.00010
7Noneqline663.0008.00011
\n", "
" ], "text/plain": [ " name type element_type value std_dev bus element\n", "0 None v bus 1.006 0.004 1 None\n", "1 None v bus 0.968 0.004 2 None\n", "2 None p bus -501.000 10.000 2 None\n", "3 None q bus -286.000 10.000 2 None\n", "4 None p line 888.000 8.000 1 0\n", "5 None p line 1173.000 8.000 1 1\n", "6 None q line 568.000 8.000 1 0\n", "7 None q line 663.000 8.000 1 1" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pp.create_measurement(net, \"p\", \"line\", 888, 8, bus=b1, element=l1) # Pline (bus 1 -> bus 2) at bus 1\n", "pp.create_measurement(net, \"p\", \"line\", 1173, 8, bus=b1, element=l2) # Pline (bus 1 -> bus 3) at bus 1\n", "pp.create_measurement(net, \"q\", \"line\", 568, 8, bus=b1, element=l1) # Qline (bus 1 -> bus 2) at bus 1\n", "pp.create_measurement(net, \"q\", \"line\", 663, 8, bus=b1, element=l2) # Qline (bus 1 -> bus 3) at bus 1\n", "net.measurement" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Performing the State Estimation\n", "\n", "The measurements are now set. We have to initialize the starting voltage magnitude and voltage angles for the state estimator. In continous operation, this can be the result of the last state estimation. In our case, we set flat start conditions: 1.0 p.u. for voltage magnitude, 0.0 degree for voltage angles. This is easily done with the parameter \"init\", which we define as \"flat\"." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And now run the state estimation. Afterwards, the result will be stored in the table res_bus_est." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n" ] } ], "source": [ "from pandapower.estimation import estimate\n", "\n", "success = estimate(net, init='flat')\n", "print(success)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Handling of Bad Data\n", "\n", "The state estimation class allows additionally the removal of bad data, especially single or non-interacting false measurements. For detecting bad data the Chi-squared distribution is used to identify the presence of them. Afterwards follows the largest normalized residual test that identifys the actual measurements which will be removed at the end.\n", "\n", "To test this function we will add a single false measurement to the network (active power flow of line 1 at bus 3):" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false }, "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", " \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", "
nametypeelement_typevaluestd_devbuselement
0Nonevbus1.0060.0041None
1Nonevbus0.9680.0042None
2Nonepbus-501.00010.0002None
3Noneqbus-286.00010.0002None
4Nonepline888.0008.00010
5Nonepline1173.0008.00011
6Noneqline568.0008.00010
7Noneqline663.0008.00011
8Nonepline1000.0008.00030
\n", "
" ], "text/plain": [ " name type element_type value std_dev bus element\n", "0 None v bus 1.006 0.004 1 None\n", "1 None v bus 0.968 0.004 2 None\n", "2 None p bus -501.000 10.000 2 None\n", "3 None q bus -286.000 10.000 2 None\n", "4 None p line 888.000 8.000 1 0\n", "5 None p line 1173.000 8.000 1 1\n", "6 None q line 568.000 8.000 1 0\n", "7 None q line 663.000 8.000 1 1\n", "8 None p line 1000.000 8.000 3 0" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pp.create_measurement(net, \"p\", \"line\", 1000, 8, bus=b3, element=l1) # Pline (bus 1 -> bus 2) at bus 3\n", "net.measurement" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The next step is the call of the largest normalized residual test's wrapper function *remove_bad_data* that handles the removal of the added false measurement, and returns a identication of success of the state estimation. The argument structure of this function is similiar to the *estimate* function (compare above). It only provides further adjustments according to the maximum allowed normalized residual (\"rn_max_threshold\"), and the probability of false required by the chi-squared test (\"chi2_prob_false\")." ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n" ] } ], "source": [ "from pandapower.estimation import remove_bad_data\n", "import numpy as np\n", "\n", "success_rn_max = remove_bad_data(net, init='flat', rn_max_threshold=3.0, chi2_prob_false=0.05)\n", "print(success_rn_max)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The management of results will be the same like for the *estimate* function (see following section)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Working with Results\n", "\n", "We can show the voltage magnitude and angles directly:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false, "scrolled": false }, "outputs": [ { "data": { "text/plain": [ "1 0.999629\n", "2 0.974156\n", "3 0.943890\n", "Name: vm_pu, dtype: float64" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "net.res_bus_est.vm_pu" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "1 0.000000\n", "2 -1.247547\n", "3 -2.745717\n", "Name: va_degree, dtype: float64" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "net.res_bus_est.va_degree" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The results match exactly with the results from the book: Voltages 0.9996, 0.9742, 0.9439; Voltage angles 0.0, -1.2475, -2.7457). Nice! \n", "Let's look at the bus power injections, which are available in res_bus_est as well" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "1 -2064.016454\n", "2 495.974966\n", "3 1514.220983\n", "Name: p_kw, dtype: float64" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "net.res_bus_est.p_kw" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "1 -1226.440397\n", "2 297.749528\n", "3 787.528929\n", "Name: q_kvar, dtype: float64" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "net.res_bus_est.q_kvar" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also compare the resulting line power flows with the measurements." ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0 892.991989\n", "1 1171.024465\n", "2 385.911626\n", "Name: p_from_kw, dtype: float64" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "net.res_line_est.p_from_kw" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0 558.821689\n", "1 667.618708\n", "2 227.755971\n", "Name: q_from_kvar, dtype: float64" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "net.res_line_est.q_from_kvar" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Again, this values do match the estimated values from our reference book.\n", "This concludes the small tutorial how to perform state estimation with a pandapower network." ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python [default]", "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.4.5" } }, "nbformat": 4, "nbformat_minor": 0 }