State Estimation

The module provides a state estimation for pandapower networks.

Theoretical Background

State Estimation is a process to estimate the electrical state of a network by eliminating inaccuracies and errors from measurement data. Various measurements are placed around the network and transferred to the operational control center via SCADA. Unfortunately measurements are not perfect: There are tolerances for each measurement device, which lead to an inherent inaccuracy in the measurement value. Analog transmission of data can change the measurement values through noise. Faulty devices can return completely wrong measurement values. To account for the measurement errors, the state estimation processes all available measurements and uses a regression method to identify the likely real state of the electrical network. The output of the state estimator is therefore a set of voltage absolutes and voltage angles for all buses in the grid. The input is the network in pandapower format and a number of measurements.

Amount of Measurements

There is a minimum amount of required measurements necessary for the regression to be mathematically possible. Assuming the network contains \(n\) buses, the network is then described by \(2n\) variables, namely \(n\) voltage absolute values and \(n\) voltage angles. A slack bus serves as the reference, its voltage angle is set to zero or the value provided in the corresponding net.ext_grid.va_degree entry (see init parameter) and is not altered in the estimation process. The voltage angles of the other network buses are relative to the voltage angles of the connected slack bus. The state estimation therefore has to find \(2n-k\) variables, where \(k\) is the number of defined slack buses. The minimum amount of measurements \(m_{min}\) needed for the method to work is therefore:

\(m_{min} = 2n-k\)

To perform well however, the number of redundant measurements should be higher. A value of \(m \approx 4n\) is often considered reasonable for practical purposes.

Standard Deviation

Since each measurement device may have a different tolerance and a different path length it has to travel to the control center, the accuracy of each measurement can be different. Therefore each measurement is assigned an accuracy value in the form of a standard deviation. Typical measurement errors are 1 % for voltage measurements and 1-3 % for power measurements.

For a more in-depth explanation of the internals of the state estimation method, please see the following sources:

See also

  • Power System State Estimation: Theory and Implementation by Ali Abur, Antonio Gómez Expósito, CRC Press, 2004.
  • State Estimation in Electric Power Systems - A Generalized Approach by A. Monticelli, Springer, 1999.

Defining Measurements

Measurements are defined via the pandapower “create_measurement” function. There are different physical properties, which can be measured at different elements. The following lists and table clarify the possible combinations. Bus power injection measurements are given in the producer system. Generated power is positive, consumed power is negative.

Types of Measurements

  • “v” for voltage measurements (in per-unit)
  • “p” for active power measurements (in kW)
  • “q” for reactive power measurements (in kVar)
  • “i” for electrical current measurements at a line (in A)

Element Types

  • “bus” for bus measurements
  • “line” for line measurements
  • “transformer” for transformer measurements

Available Measurements per Element

Element Type Available Measurement Types
bus v, p, q
line i, p, q
transformer i, p, q

The “create_measurement” function is defined as follows:

pandapower.create.create_measurement(net, type, element_type, value, std_dev, bus, element=None, check_existing=True, index=None, name=None)

Creates a measurement, which is used by the estimation module. Possible types of measurements are: v, p, q, i

INPUT:

type (string) - Type of measurement. “v”, “p”, “q”, “i” are possible.

element_type (string) - Clarifies which element is measured. “bus”, “line”, “transformer” are possible.

value (float) - Measurement value. Units are “kW” for P, “kVar” for Q, “p.u.” for V, “A” for I. Generation is a positive bus power injection, consumption negative.

std_dev (float) - Standard deviation in the same unit as the measurement.

bus (int) - Index of bus. Determines the position of the measurement for line/transformer measurements (bus == from_bus: measurement at from_bus; same for to_bus)

element (int, None) - Index of measured element, if element_type is “line” or “transformer”.

OPTIONAL:

check_existing (bool) - Check for and replace existing measurements for this bus and type. Set it to false for performance improvements which can cause unsafe behaviour.

name (str, None) - name of measurement.

OUTPUT:
(int) Index of measurement
EXAMPLE:
500 kW load measurement with 10 kW standard deviation on bus 0: create_measurement(net, “p”, “bus”, -500., 10., 0)

Running the State Estimation

The state estimation can be used with the wrapper function “estimate”, which prevents the need to deal with the state_estimation class object and functions. It can be imported from “estimation.state_estimation”.

pandapower.estimation.estimate(net, init='flat', tolerance=1e-06, maximum_iterations=10, calculate_voltage_angles=True)

Wrapper function for WLS state estimation.

INPUT:

net - The net within this line should be created.

init - (string) Initial voltage for the estimation. ‘flat’ sets 1.0 p.u. / 0° for all buses, ‘results’ uses the values from res_bus_est if available and ‘slack’ considers the slack bus voltage (and optionally, angle) as the initial values. Default is ‘flat’.

OPTIONAL:

tolerance - (float) - When the maximum state change between iterations is less than tolerance, the process stops. Default is 1e-6.

maximum_iterations - (integer) - Maximum number of iterations. Default is 10.

calculate_voltage_angles - (boolean) - Take into account absolute voltage angles and phase shifts in transformers, if init is ‘slack’. Default is True.

OUTPUT:
successful (boolean) - Was the state estimation successful?

Handling of bad data

Note

The bad data removal is not very robust at this time. Please treat the results with caution!

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. Both methods are combined in the perform_rn_max_test function that is part of the state estimation class. To access it, the following wrapper function remove_bad_data has been created.

pandapower.estimation.remove_bad_data(net, init='flat', tolerance=1e-06, maximum_iterations=10, calculate_voltage_angles=True, rn_max_threshold=3.0, chi2_prob_false=0.05)

Wrapper function for bad data removal.

INPUT:

net - The net within this line should be created.

init - (string) Initial voltage for the estimation. ‘flat’ sets 1.0 p.u. / 0° for all buses, ‘results’ uses the values from res_bus_est if available and ‘slack’ considers the slack bus voltage (and optionally, angle) as the initial values. Default is ‘flat’.

OPTIONAL:

tolerance - (float) - When the maximum state change between iterations is less than tolerance, the process stops. Default is 1e-6.

maximum_iterations - (integer) - Maximum number of iterations. Default is 10.

calculate_voltage_angles - (boolean) - Take into account absolute voltage angles and phase shifts in transformers, if init is ‘slack’. Default is True.

rn_max_threshold (float) - Identification threshold to determine if the largest normalized residual reflects a bad measurement (default value of 3.0)

chi2_prob_false (float) - probability of error / false alarms (default value: 0.05)

OUTPUT:
successful (boolean) - Was the state estimation successful?

Nevertheless the Chi-squared test is available as well to allow a identification of topology errors or, as explained, false measurements. It is named as chi2_analysis. The detection’s result of present bad data of the Chi-squared test is stored internally as bad_data_present (boolean, class member variable) and returned by the function call.

pandapower.estimation.chi2_analysis(net, init='flat', tolerance=1e-06, maximum_iterations=10, calculate_voltage_angles=True, chi2_prob_false=0.05)

Wrapper function for the chi-squared test.

INPUT:

net - The net within this line should be created.

init - (string) Initial voltage for the estimation. ‘flat’ sets 1.0 p.u. / 0° for all buses, ‘results’ uses the values from res_bus_est if available and ‘slack’ considers the slack bus voltage (and optionally, angle) as the initial values. Default is ‘flat’.

OPTIONAL:

tolerance - (float) - When the maximum state change between iterations is less than tolerance, the process stops. Default is 1e-6.

maximum_iterations - (integer) - Maximum number of iterations. Default is 10.

calculate_voltage_angles - (boolean) - Take into account absolute voltage angles and phase shifts in transformers, if init is ‘slack’. Default is True.

chi2_prob_false (float) - probability of error / false alarms (default value: 0.05)

OUTPUT:
bad_data_detected (boolean) - Returns true if bad data has been detected

Background information about this topic can be sourced from the following literature:

See also

  • Power System State Estimation: Theory and Implementation by Ali Abur, Antonio Gómez Expósito, CRC Press, 2004.
  • Power Generation, Operation, and Control by Allen J. Wood, Bruce Wollenberg, Wiley Interscience Publication, 1996.

Example

As an example, we will define measurements for a simple pandapower network net with 4 buses. Bus 4 is out-of-service. The external grid is connected at bus 1.

There are multiple measurements available, which have to be defined for the state estimator. There are two voltage measurements at buses 1 and 2. There are two power measurements (active and reactive power) at bus 2. There are also line power measurements at bus 1. The measurements are both for active and reactive power and are located on the line from bus 1 to bus 2 and from bus 1 to bus 3. This yields the following code:

pp.create_measurement(net, "v", "bus", 1.006, .004, bus1)      # V at bus 1
pp.create_measurement(net, "v", "bus", 0.968, .004, bus2)      # V at bus 2

pp.create_measurement(net, "p", "bus", -501, 10, bus2)         # P at bus 2
pp.create_measurement(net, "q", "bus", -286, 10, bus2)         # Q at bus 2

pp.create_measurement(net, "p", "line", 888, 8, bus=bus1, element=line1)    # Pline (bus 1 -> bus 2) at bus 1
pp.create_measurement(net, "p", "line", 1173, 8, bus=bus1, element=line2)   # Pline (bus 1 -> bus 3) at bus 1
pp.create_measurement(net, "q", "line", 568, 8, bus=bus1, element=line1)    # Qline (bus 1 -> bus 2) at bus 1
pp.create_measurement(net, "q", "line", 663, 8, bus=bus1, element=line2)    # Qline (bus 1 -> bus 3) at bus 1

Now that the data is ready, the state_estimation can be initialized and run. We want to use the flat start condition, in which all voltages are set to 1.0 p.u..

success = estimate(net, init="flat")
V, delta = net.res_bus_est.vm_pu, net.res_bus_est.va_degree

The resulting variables now contain the voltage absolute values in V, the voltage angles in delta, an indication of success in success. The bus power injections can be accessed similarly with net.res_bus_est.p_kw and net.res_bus_est.q_kvar. Line data is also available in the same format as defined in res_line.

If we like to check our data for fault measurements, and exclude them in in our state estimation, we use the following code:

success_rn_max = remove_bad_data(net, init="flat")
V_rn_max, delta_rn_max = net.res_bus_est.vm_pu, net.res_bus_est.va_degree

In the case that we only like to know if there is a likelihood of fault measurements (probabilty of fault can be adjusted), the Chi-squared test should be performed separatly. If the test detects the possibility of fault data, the value of the added class member variable bad_data_present would be true as well as the boolean variable success_chi2 that is used here:

success_chi2 = chi2_analysis(net, init="flat")