Repository: e2nIEE/pandapower

Issue:
State estimation error with bus-bus switches and measurements on each bus
Hi,
i am currently working on a high voltage network with lots of measurements. The bus of the pandapower network represents a busbar in the substation in the real world and the buses were connected with each other through bus-bus switches. The measurement of bus (p, q) represents the power flow on a busbar. However the state estimation module (and similarly in power flow calculation) will merge the buses connected through bb-switch to a single bus and which was not in the _add_measurement function the measurement correctly merged. 

I have tried to connect the bus with measurement (and also load or sgens) with lines instead of bb-switches as small impedance. This might be a possibility to solve the issue. However it will be better to leave this subsititution to minimum. 

The code for test with a simple four bus network:

```python
import numpy as np
from copy import deepcopy

import pandapower as pp
import pandapower.networks as pn
from pandapower.estimation import estimate as se

def r2(base, v):
    return np.random.normal(base, v)

# 1. Create network
net = pp.create_empty_network()
pp.create_bus(net, name="bus1", vn_kv=10.)
pp.create_bus(net, name="bus2", vn_kv=10.)
pp.create_bus(net, name="bus3", vn_kv=10.)
pp.create_bus(net, name="bus4", vn_kv=110.)
pp.create_ext_grid(net, bus=3, vm_pu=1.01)
pp.create_line_from_parameters(net, 0, 1, 10, r_ohm_per_km=.59, x_ohm_per_km=.35, c_nf_per_km=10.1,
                               max_i_ka=1)
pp.create_line_from_parameters(net, 0, 2, 10, r_ohm_per_km=.59, x_ohm_per_km=.35, c_nf_per_km=10.1,
                               max_i_ka=1)
pp.create_line_from_parameters(net, 1, 2, 10, r_ohm_per_km=.59, x_ohm_per_km=.35, c_nf_per_km=10.1,
                               max_i_ka=1)
pp.create_transformer(net, 3, 0, std_type="40 MVA 110/10 kV")

pp.create_load(net, 0, .350, .100)
pp.create_load(net, 1, .450, .200)
pp.create_load(net, 2, .250, .100)

# Created bb switch and the line will be short circuited (ignored)
pp.create_switch(net, 1, element=2, et='b')

net_meas_on_bb_bus = deepcopy(net)

net_switch_as_impedance = deepcopy(net)
net_switch_as_impedance.switch.at[0 ,"closed"] = False
net_switch_as_impedance.line.at[2, 'length_km'] /= 1000
net_switch_as_impedance_with_meas = deepcopy(net_switch_as_impedance)

pp.runpp(net)
pp.runpp(net_meas_on_bb_bus)
pp.runpp(net_switch_as_impedance)
pp.runpp(net_switch_as_impedance_with_meas)

def create_test_measurement(net, measurement_on_bb_switch_bus=False):
    pp.create_measurement(net, "v", "bus", r2(net.res_bus.vm_pu.iloc[0], .004), .004, element=0)
    pp.create_measurement(net, "v", "bus", r2(net.res_bus.vm_pu.iloc[1], .004), .004, element=1)
    pp.create_measurement(net, "v", "bus", r2(net.res_bus.vm_pu.iloc[3], .004), .004, element=3)
    
    pp.create_measurement(net, "p", "bus", -r2(net.res_bus.p_mw.iloc[3], .002), .004, element=3)
    pp.create_measurement(net, "q", "bus", -r2(net.res_bus.q_mvar.iloc[3], .002), .004, element=3)
    
## If measurement on the bus with bb-switch activated, it will incluence the results of the merged bus
    if measurement_on_bb_switch_bus:
        pp.create_measurement(net, "p", "bus", -r2(net.res_bus.p_mw.iloc[2], .002), .004, element=2)
        pp.create_measurement(net, "q", "bus", -r2(net.res_bus.q_mvar.iloc[2], .002), .004, element=2)
    
    pp.create_measurement(net, "p", "line", r2(net.res_line.p_from_mw.iloc[0], .001), .002, 0, side='from')
    pp.create_measurement(net, "q", "line", r2(net.res_line.q_from_mvar.iloc[0], .001), .002, 0, side='from')
    pp.create_measurement(net, "p", "line", r2(net.res_line.p_from_mw.iloc[1], .001), .002, 1, side='from')
    pp.create_measurement(net, "q", "line", r2(net.res_line.q_from_mvar.iloc[1], .001), .002, 1, side='from')
    
    pp.create_measurement(net, "p", "trafo", r2(net.res_trafo.p_hv_mw.iloc[0], .002), .01,
                          side="hv", element=0)  # transformer meas.
    pp.create_measurement(net, "q", "trafo", r2(net.res_trafo.q_hv_mvar.iloc[0], .002), .01,
                          side=3, element=0)  # at hv side

create_test_measurement(net)
create_test_measurement(net_switch_as_impedance)
create_test_measurement(net_meas_on_bb_bus, True)
create_test_measurement(net_switch_as_impedance_with_meas, True)

# 2. Do state estimation
success_net = se(net, tolerance=1e-5, maximum_iterations=20)
success_net_meas_on_bb_bus = se(net_meas_on_bb_bus, tolerance=1e-5, maximum_iterations=20)
success_net_with_impedance = se(net_switch_as_impedance, tolerance=1e-5, maximum_iterations=20)
success_impedance_with_meas = se(net_switch_as_impedance_with_meas, tolerance=1e-5, maximum_iterations=20)


res_bus_with_switch = net.res_bus_est
res_bus_meas_on_bb_bus = net_meas_on_bb_bus.res_bus_est
res_bus_small_impedance = net_switch_as_impedance.res_bus_est
res_bus_small_impedance_with_meas = net_switch_as_impedance_with_meas.res_bus_est
```
The network has the following variations:

- original
- bb: using bb-switch between bus 1, 2
- imp: using small impedance instead of bb-switch between bus 1,2
- bb+meas: using bb-switch and has p, q measurement on one of the buses with bb-switch
- imp+meas: using small impedance and has p, q measurement on one of the buses

P_mw injections on buses:

| bus id | Original| bb |  imp |  bb+meas | imp+meas |
|--|--|--|--|--|--|
| 0 | 0.35 | 0.35 | 0.35 | 0.43| 0.35 |
| 1 | 0.45 | 0.7 | 0.05 | 0.62 | 0.45 |
| 2 | 0.25 | 0.7 | 0.65 | 0.62 | 0.25 |
| 3 | -1.09 | -1.09 | -1.08 | -1.09 | -1.08 |

From the result, it seems like that small impedance with measurements delivers the best result. And if the network has bb-switch, the state estimation module seems fail to identify the buses, since it's automatically merged to one bus in ppc.


State estimation error with bus-bus switches and measurements on each bus
Hi,
i am currently working on a high voltage network with lots of measurements. The bus of the pandapower network represents a busbar in the substation in the real world and the buses were connected with each other through bus-bus switches. The measurement of bus (p, q) represents the power flow on a busbar. However the state estimation module (and similarly in power flow calculation) will merge the buses connected through bb-switch to a single bus and which was not in the _add_measurement function the measurement correctly merged. 

I have tried to connect the bus with measurement (and also load or sgens) with lines instead of bb-switches as small impedance. This might be a possibility to solve the issue. However it will be better to leave this subsititution to minimum. 

The code for test with a simple four bus network:

```python
import numpy as np
from copy import deepcopy

import pandapower as pp
import pandapower.networks as pn
from pandapower.estimation import estimate as se

def r2(base, v):
    return np.random.normal(base, v)

# 1. Create network
net = pp.create_empty_network()
pp.create_bus(net, name="bus1", vn_kv=10.)
pp.create_bus(net, name="bus2", vn_kv=10.)
pp.create_bus(net, name="bus3", vn_kv=10.)
pp.create_bus(net, name="bus4", vn_kv=110.)
pp.create_ext_grid(net, bus=3, vm_pu=1.01)
pp.create_line_from_parameters(net, 0, 1, 10, r_ohm_per_km=.59, x_ohm_per_km=.35, c_nf_per_km=10.1,
                               max_i_ka=1)
pp.create_line_from_parameters(net, 0, 2, 10, r_ohm_per_km=.59, x_ohm_per_km=.35, c_nf_per_km=10.1,
                               max_i_ka=1)
pp.create_line_from_parameters(net, 1, 2, 10, r_ohm_per_km=.59, x_ohm_per_km=.35, c_nf_per_km=10.1,
                               max_i_ka=1)
pp.create_transformer(net, 3, 0, std_type="40 MVA 110/10 kV")

pp.create_load(net, 0, .350, .100)
pp.create_load(net, 1, .450, .200)
pp.create_load(net, 2, .250, .100)

# Created bb switch and the line will be short circuited (ignored)
pp.create_switch(net, 1, element=2, et='b')

net_meas_on_bb_bus = deepcopy(net)

net_switch_as_impedance = deepcopy(net)
net_switch_as_impedance.switch.at[0 ,"closed"] = False
net_switch_as_impedance.line.at[2, 'length_km'] /= 1000
net_switch_as_impedance_with_meas = deepcopy(net_switch_as_impedance)

pp.runpp(net)
pp.runpp(net_meas_on_bb_bus)
pp.runpp(net_switch_as_impedance)
pp.runpp(net_switch_as_impedance_with_meas)

def create_test_measurement(net, measurement_on_bb_switch_bus=False):
    pp.create_measurement(net, "v", "bus", r2(net.res_bus.vm_pu.iloc[0], .004), .004, element=0)
    pp.create_measurement(net, "v", "bus", r2(net.res_bus.vm_pu.iloc[1], .004), .004, element=1)
    pp.create_measurement(net, "v", "bus", r2(net.res_bus.vm_pu.iloc[3], .004), .004, element=3)
    
    pp.create_measurement(net, "p", "bus", -r2(net.res_bus.p_mw.iloc[3], .002), .004, element=3)
    pp.create_measurement(net, "q", "bus", -r2(net.res_bus.q_mvar.iloc[3], .002), .004, element=3)
    
## If measurement on the bus with bb-switch activated, it will incluence the results of the merged bus
    if measurement_on_bb_switch_bus:
        pp.create_measurement(net, "p", "bus", -r2(net.res_bus.p_mw.iloc[2], .002), .004, element=2)
        pp.create_measurement(net, "q", "bus", -r2(net.res_bus.q_mvar.iloc[2], .002), .004, element=2)
    
    pp.create_measurement(net, "p", "line", r2(net.res_line.p_from_mw.iloc[0], .001), .002, 0, side='from')
    pp.create_measurement(net, "q", "line", r2(net.res_line.q_from_mvar.iloc[0], .001), .002, 0, side='from')
    pp.create_measurement(net, "p", "line", r2(net.res_line.p_from_mw.iloc[1], .001), .002, 1, side='from')
    pp.create_measurement(net, "q", "line", r2(net.res_line.q_from_mvar.iloc[1], .001), .002, 1, side='from')
    
    pp.create_measurement(net, "p", "trafo", r2(net.res_trafo.p_hv_mw.iloc[0], .002), .01,
                          side="hv", element=0)  # transformer meas.
    pp.create_measurement(net, "q", "trafo", r2(net.res_trafo.q_hv_mvar.iloc[0], .002), .01,
                          side=3, element=0)  # at hv side

create_test_measurement(net)
create_test_measurement(net_switch_as_impedance)
create_test_measurement(net_meas_on_bb_bus, True)
create_test_measurement(net_switch_as_impedance_with_meas, True)

# 2. Do state estimation
success_net = se(net, tolerance=1e-5, maximum_iterations=20)
success_net_meas_on_bb_bus = se(net_meas_on_bb_bus, tolerance=1e-5, maximum_iterations=20)
success_net_with_impedance = se(net_switch_as_impedance, tolerance=1e-5, maximum_iterations=20)
success_impedance_with_meas = se(net_switch_as_impedance_with_meas, tolerance=1e-5, maximum_iterations=20)


res_bus_with_switch = net.res_bus_est
res_bus_meas_on_bb_bus = net_meas_on_bb_bus.res_bus_est
res_bus_small_impedance = net_switch_as_impedance.res_bus_est
res_bus_small_impedance_with_meas = net_switch_as_impedance_with_meas.res_bus_est
```
The network has the following variations:

- original
- bb: using bb-switch between bus 1, 2
- imp: using small impedance instead of bb-switch between bus 1,2
- bb+meas: using bb-switch and has p, q measurement on one of the buses with bb-switch
- imp+meas: using small impedance and has p, q measurement on one of the buses

P_mw injections on buses:

| bus id | Original| bb |  imp |  bb+meas | imp+meas |
|--|--|--|--|--|--|
| 0 | 0.35 | 0.35 | 0.35 | 0.43| 0.35 |
| 1 | 0.45 | 0.7 | 0.05 | 0.62 | 0.45 |
| 2 | 0.25 | 0.7 | 0.65 | 0.62 | 0.25 |
| 3 | -1.09 | -1.09 | -1.08 | -1.09 | -1.08 |

From the result, it seems like that small impedance with measurements delivers the best result. And if the network has bb-switch, the state estimation module seems fail to identify the buses, since it's automatically merged to one bus in ppc.




Discussion:
I am thinking of a possible fix to the issue with minimum change of the original process. Since the reason for the problem is that on the ppci level, multiple measurements (and also load, sgens) are fused together onto one single bus. My idea is to identify such cluster (ppci bus) with many-to-one bus mapping and using auxiliary buses on such a cluster with mupltiple devices to achieve the minimum code adjustment. 

1.  if a cluster has more than one buses with devices, add auxiliary buses for all the buses except the first one (to avoid generating a bus with zero p,q) to substitute the original bus in the ppci cluster
2. set all the bb switch onto the original bus to out of service and add auxiliary bb switches onto the newly added buses with the same configuration
3. add lines with small impedance between the auxilliary buses and the buses, which were substituted by the auxilliary buses
4. run the normal state estimation
5. remove all auxiliary buses, bb switches and lines, restore the in_service state of the original bb-switch
6. remove state estimation results for the auxiliary elements

The results will thus mapping correctly onto the original configuration. 


I am thinking of a possible fix to the issue with minimum change of the original process. Since the reason for the problem is that on the ppci level, multiple measurements (and also load, sgens) are fused together onto one single bus. My idea is to identify such cluster (ppci bus) with many-to-one bus mapping and using auxiliary buses on such a cluster with mupltiple devices to achieve the minimum code adjustment. 

1.  if a cluster has more than one buses with devices, add auxiliary buses for all the buses except the first one (to avoid generating a bus with zero p,q) to substitute the original bus in the ppci cluster
2. set all the bb switch onto the original bus to out of service and add auxiliary bb switches onto the newly added buses with the same configuration
3. add lines with small impedance between the auxilliary buses and the buses, which were substituted by the auxilliary buses
4. run the normal state estimation
5. remove all auxiliary buses, bb switches and lines, restore the in_service state of the original bb-switch
6. remove state estimation results for the auxiliary elements

The results will thus mapping correctly onto the original configuration. 



Resolving patch:
diff --git a/pandapower/estimation/state_estimation.py b/pandapower/estimation/state_estimation.py
--- a/pandapower/estimation/state_estimation.py
+++ b/pandapower/estimation/state_estimation.py
@@ -9,7 +9,7 @@
 from scipy.stats import chi2
 
 from pandapower.estimation.wls_ppc_conversions import _add_measurements_to_ppc, \
-    _build_measurement_vectors, _init_ppc
+    _build_measurement_vectors, _init_ppc, _add_aux_elements_for_bb_switch, _drop_aux_elements_for_bb_switch
 from pandapower.estimation.results import _copy_power_flow_results, _rename_results
 from pandapower.idx_brch import F_BUS, T_BUS, BR_STATUS, PF, PT, QF, QT
 from pandapower.auxiliary import _add_pf_options, get_values, _clean_up
@@ -27,7 +27,7 @@
 
 
 def estimate(net, init='flat', tolerance=1e-6, maximum_iterations=10,
-             calculate_voltage_angles=True):
+             calculate_voltage_angles=True, fuse_all_bb_switches=True):
     """
     Wrapper function for WLS state estimation.
 
@@ -46,6 +46,11 @@ def estimate(net, init='flat', tolerance=1e-6, maximum_iterations=10,
 
         **calculate_voltage_angles** - (boolean) - Take into account absolute voltage angles and phase
         shifts in transformers, if init is 'slack'. Default is True.
+        
+        **fuse_all_bb_switches** - (bool) - if true when considering bus-bus-switches the buses
+        will fused (Default behaviour) otherwise auxiliary lines will be added between those buses 
+        where an element is connected to them in order to clear the p,q results on each buses 
+        instead of fusing them all together
 
     OUTPUT:
         **successful** (boolean) - Was the state estimation successful?
@@ -63,7 +68,7 @@ def estimate(net, init='flat', tolerance=1e-6, maximum_iterations=10,
             delta_start = res_bus.va_degree.values
     elif init != 'flat':
         raise UserWarning("Unsupported init value. Using flat initialization.")
-    return wls.estimate(v_start, delta_start, calculate_voltage_angles)
+    return wls.estimate(v_start, delta_start, calculate_voltage_angles, fuse_all_bb_switches)
 
 
 def remove_bad_data(net, init='flat', tolerance=1e-6, maximum_iterations=10,
@@ -186,7 +191,7 @@ def __init__(self, tolerance=1e-6, maximum_iterations=10, net=None, logger=None)
         self.delta = None
         self.bad_data_present = None
 
-    def estimate(self, v_start=None, delta_start=None, calculate_voltage_angles=True):
+    def estimate(self, v_start=None, delta_start=None, calculate_voltage_angles=True, fuse_all_bb_switches=True):
         """
         The function estimate is the main function of the module. It takes up to three input
         arguments: v_start, delta_start and calculate_voltage_angles. The first two are the initial
@@ -214,6 +219,11 @@ def estimate(self, v_start=None, delta_start=None, calculate_voltage_angles=True
         OPTIONAL:
             **calculate_voltage_angles** - (bool) - Take into account absolute voltage angles and
             phase shifts in transformers Default is True.
+            
+            **fuse_all_bb_switches** - (bool) - if true when considering bus-bus-switches the buses
+            will fused (Default behaviour) otherwise auxiliary lines will be added between those buses 
+            where an element is connected to them in order to clear the p,q results on each buses 
+            instead of fusing them all together
 
         OUTPUT:
             **successful** (boolean) - True if the estimation process was successful
@@ -229,6 +239,12 @@ def estimate(self, v_start=None, delta_start=None, calculate_voltage_angles=True
         if self.net is None:
             raise UserWarning("Component was not initialized with a network.")
         t0 = time()
+        
+        # change the configuration of the pp net to avoid auto fusing of buses connected
+        # through bb switch with elements on each bus if this feature enabled
+        if not fuse_all_bb_switches and not self.net.switch.empty:
+            _add_aux_elements_for_bb_switch(self.net)
+        
         # add initial values for V and delta
         # node voltages
         # V<delta
@@ -369,6 +385,9 @@ def estimate(self, v_start=None, delta_start=None, calculate_voltage_angles=True
                                                    mapping_table)
         
         _clean_up(self.net)
+        # clear the aux elements and calculation results created for the substitution of bb switches
+        if not fuse_all_bb_switches and not self.net.switch.empty:
+            _drop_aux_elements_for_bb_switch(self.net)
 
         # store variables required for chi^2 and r_N_max test:
         self.R_inv = r_inv.toarray()
diff --git a/pandapower/estimation/wls_ppc_conversions.py b/pandapower/estimation/wls_ppc_conversions.py
--- a/pandapower/estimation/wls_ppc_conversions.py
+++ b/pandapower/estimation/wls_ppc_conversions.py
@@ -5,6 +5,7 @@
 
 
 import numpy as np
+import pandas as pd
 from pandapower.auxiliary import _select_is_elements_numba, _add_ppc_options, _add_auxiliary_elements
 from pandapower.pd2ppc import _pd2ppc
 from pandapower.estimation.idx_bus import *
@@ -13,6 +14,7 @@
 from pandapower.idx_bus import bus_cols
 from pandapower.pf.run_newton_raphson_pf import _run_dc_pf
 from pandapower.build_branch import get_is_lines
+from pandapower.create import create_buses, create_line_from_parameters
 
 try:
     import pplog as logging
@@ -20,6 +22,92 @@
     import logging
 std_logger = logging.getLogger(__name__)
 
+AUX_BUS_NAME, AUX_LINE_NAME, AUX_SWITCH_NAME =\
+    "aux_bus_se", "aux_line_se", "aux_bbswitch_se"
+
+def _add_aux_elements_for_bb_switch(net):
+    """
+    Add auxiliary elements (bus, bb switch, line) to the pandapower net to avoid
+    automatic fuse of buses connected with bb switch with elements on it
+    :param net: pandapower net
+    :return: None
+    """
+    def get_bus_branch_mapping(net):
+        bus_with_elements = set(net.load.bus).union(set(net.sgen.bus)).union(
+                        set(net.shunt.bus)).union(set(net.gen.bus)).union(
+                        set(net.ext_grid.bus)).union(set(net.ward.bus)).union(
+                        set(net.xward.bus))
+
+        bus_ppci = pd.DataFrame(data=net._pd2ppc_lookups['bus'], columns=["bus_ppci"])
+        bus_ppci['bus_with_elements'] = bus_ppci.index.isin(bus_with_elements)
+        bus_ppci['vn_kv'] = net.bus.loc[bus_ppci.index, 'vn_kv']
+        ppci_bus_with_elements = bus_ppci.groupby('bus_ppci')['bus_with_elements'].sum()
+        bus_ppci.loc[:, 'elements_in_cluster'] = ppci_bus_with_elements[bus_ppci['bus_ppci'].values].values 
+        return bus_ppci
+
+    # find the buses which was fused together in the pp2ppc conversion with elements on them
+    # the first one will be skipped
+    _pd2ppc(net)
+    bus_ppci_mapping = get_bus_branch_mapping(net)
+    bus_to_be_handled = bus_ppci_mapping[((bus_ppci_mapping ['elements_in_cluster']>=2)&\
+                                          bus_ppci_mapping ['bus_with_elements'])]
+    bus_to_be_handled = bus_to_be_handled[bus_to_be_handled['bus_ppci'].duplicated(keep='first')]
+
+    # create auxiliary buses for the buses need to be handled
+    aux_bus_index = create_buses(net, bus_to_be_handled.shape[0], bus_to_be_handled.vn_kv.values, 
+                                 name=AUX_BUS_NAME)
+    bus_aux_mapping = pd.Series(aux_bus_index, index=bus_to_be_handled.index.values)
+
+    # create auxiliary switched and disable original switches connected to the related buses
+    net.switch.loc[:, 'original_closed'] = net.switch.loc[:, 'closed']
+    switch_to_be_replaced_sel = ((net.switch.et == 'b') &
+                                 (net.switch.element.isin(bus_to_be_handled.index) | 
+                                  net.switch.bus.isin(bus_to_be_handled.index)))
+    net.switch.loc[switch_to_be_replaced_sel, 'closed'] = False
+
+    # create aux switches with selecting the existed switches
+    aux_switch = net.switch.loc[switch_to_be_replaced_sel, ['bus', 'closed', 'element', 
+                                                            'et', 'name', 'original_closed']]
+    aux_switch.loc[:,'name'] = AUX_SWITCH_NAME
+    
+    # replace the original bus with the correspondent auxiliary bus
+    bus_to_be_replaced = aux_switch.loc[aux_switch.bus.isin(bus_to_be_handled.index), 'bus']
+    element_to_be_replaced = aux_switch.loc[aux_switch.element.isin(bus_to_be_handled.index), 'element']
+    aux_switch.loc[bus_to_be_replaced.index, 'bus'] =\
+        bus_aux_mapping[bus_to_be_replaced].values
+    aux_switch.loc[element_to_be_replaced.index, 'element'] =\
+        bus_aux_mapping[element_to_be_replaced].values
+    aux_switch['closed'] = aux_switch['original_closed']
+    net.switch = net.switch.append(aux_switch, ignore_index=True)
+
+    # create auxiliary lines as small impedance
+    for bus_ori, bus_aux in bus_aux_mapping.iteritems():
+        create_line_from_parameters(net, bus_ori, bus_aux, length_km=1e-5, name=AUX_LINE_NAME,
+                                    r_ohm_per_km=0.15, x_ohm_per_km=0.2, c_nf_per_km=10, max_i_ka=1)
+
+
+def _drop_aux_elements_for_bb_switch(net):
+    """
+    Remove auxiliary elements (bus, bb switch, line) added by
+    _add_aux_elements_for_bb_switch function
+    :param net: pandapower net
+    :return: None
+    """
+    # Remove auxiliary switches and restore switch status
+    net.switch = net.switch[net.switch.name!=AUX_SWITCH_NAME]
+    if 'original_closed' in net.switch.columns:
+        net.switch.loc[:, 'closed'] = net.switch.loc[:, 'original_closed']
+        net.switch.drop('original_closed', axis=1, inplace=True)
+    
+    # Remove auxiliary buses, lines in net and result
+    for key in net.keys():
+        if key.startswith('res_bus'):
+            net[key] = net[key].loc[net.bus.name != AUX_BUS_NAME, :]
+        if key.startswith('res_line'):
+            net[key] = net[key].loc[net.line.name != AUX_LINE_NAME, :]
+    net.bus = net.bus.loc[net.bus.name != AUX_BUS_NAME, :]
+    net.line = net.line.loc[net.line.name != AUX_LINE_NAME, :]
+
 
 def _init_ppc(net, v_start, delta_start, calculate_voltage_angles):
     # select elements in service and convert pandapower ppc to ppc


Test patch:
diff --git a/pandapower/test/estimation/test_wls_estimation.py b/pandapower/test/estimation/test_wls_estimation.py
--- a/pandapower/test/estimation/test_wls_estimation.py
+++ b/pandapower/test/estimation/test_wls_estimation.py
@@ -628,6 +628,55 @@ def test_network_with_trafo3w_with_disabled_branch():
     assert success
     assert (np.nanmax(np.abs(net.res_bus.vm_pu.values - net.res_bus_est.vm_pu.values)) < 0.006)
     assert (np.nanmax(np.abs(net.res_bus.va_degree.values- net.res_bus_est.va_degree.values)) < 0.006)
+    
+
+def test_net_with_bb_switch():
+    net = pp.create_empty_network()
+    pp.create_bus(net, name="bus1", vn_kv=10.)
+    pp.create_bus(net, name="bus2", vn_kv=10.)
+    pp.create_bus(net, name="bus3", vn_kv=10.)
+    pp.create_bus(net, name="bus4", vn_kv=110.)
+    pp.create_ext_grid(net, bus=3, vm_pu=1.0)
+    pp.create_line_from_parameters(net, 0, 1, 10, r_ohm_per_km=.59, x_ohm_per_km=.35, c_nf_per_km=10.1,
+                                   max_i_ka=1)
+    pp.create_transformer(net, 3, 0, std_type="40 MVA 110/10 kV")
+
+    pp.create_load(net, 0, p_mw=.350, q_mvar=.100)
+    pp.create_load(net, 1, p_mw=.450, q_mvar=.100)
+    pp.create_load(net, 2, p_mw=.250, q_mvar=.100)
+
+    # Created bb switch
+    pp.create_switch(net, 1, element=2, et='b')
+    pp.runpp(net, calculate_voltage_angles=True)
+
+    pp.create_measurement(net, "v", "bus", r2(net.res_bus.vm_pu.iloc[0], .002), .002, element=0)
+    pp.create_measurement(net, "v", "bus", r2(net.res_bus.vm_pu.iloc[1], .002), .002, element=1)
+    pp.create_measurement(net, "v", "bus", r2(net.res_bus.vm_pu.iloc[3], .002), .002, element=3)
+
+    pp.create_measurement(net, "p", "bus", -r2(net.res_bus.p_mw.iloc[3], .002), .002, element=3)
+    pp.create_measurement(net, "q", "bus", -r2(net.res_bus.q_mvar.iloc[3], .002), .002, element=3)
+
+    # If measurement on the bus with bb-switch activated, it will incluence the results of the merged bus
+    pp.create_measurement(net, "p", "bus", -r2(net.res_bus.p_mw.iloc[2], .001), .001, element=2)
+    pp.create_measurement(net, "q", "bus", -r2(net.res_bus.q_mvar.iloc[2], .001), .001, element=2)
+    pp.create_measurement(net, "p", "bus", -r2(net.res_bus.p_mw.iloc[1], .001), .001, element=1)
+    pp.create_measurement(net, "q", "bus", -r2(net.res_bus.q_mvar.iloc[1], .001), .001, element=1)
+
+    pp.create_measurement(net, "p", "line", r2(net.res_line.p_from_mw.iloc[0], .002), .002, 0, side='from')
+    pp.create_measurement(net, "q", "line", r2(net.res_line.q_from_mvar.iloc[0], .002), .002, 0, side='from')
+
+    pp.create_measurement(net, "p", "trafo", r2(net.res_trafo.p_hv_mw.iloc[0], .001), .01,
+                          side="hv", element=0)  
+    pp.create_measurement(net, "q", "trafo", r2(net.res_trafo.q_hv_mvar.iloc[0], .001), .01,
+                          side="hv", element=0)  
+
+    success = estimate(net, tolerance=1e-5, fuse_all_bb_switches=False)
+    assert success
+    assert np.allclose(net.res_bus.va_degree.values,net.res_bus_est.va_degree.values, 1e-2)
+    assert np.allclose(net.res_bus.vm_pu.values,net.res_bus_est.vm_pu.values, 1e-2)
+    # asserting with more tolerance since the added impedance will cause some inaccuracy
+    assert np.allclose(net.res_bus.p_mw.values,net.res_bus_est.p_mw.values, atol=1e-2)
+    assert np.allclose(net.res_bus.q_mvar.values,net.res_bus_est.q_mvar.values, atol=1e-2)
 
 
 def r(v=0.03):