Skip to content

Commit

Permalink
bugfix when VSC is connected to ext_grid; bugfix for B2B VSC configur…
Browse files Browse the repository at this point in the history
…ation; bugfix for VSC as slack and dc-side has p_mw set-point (p_mw must be ignored in this case)
  • Loading branch information
rbolgaryn committed Feb 14, 2024
1 parent 393301a commit 2c96a7d
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 22 deletions.
2 changes: 1 addition & 1 deletion pandapower/pd2ppc.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ def _pd2ppc(net, sequence=None):

_check_line_dc_at_b2b_buses(ppci)
_check_vsc_different_ac_control_modes_at_same_bus(ppci)
_check_slack_at_vsc_bus(ppci)
# _check_slack_at_vsc_bus(ppci)

if mode == "pf":
# check if any generators connected to the same bus have different voltage setpoints
Expand Down
8 changes: 4 additions & 4 deletions pandapower/pf/create_jacobian_facts.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ def create_J_modification_ssc(J, V, Ybus_ssc, f, t, pvpq, pq, pvpq_lookup, pq_lo
# todo
# data = np.r_[data, -S_Fik.imag[f_in_pvpq], S_Fik.imag[f_in_pvpq & t_in_pvpq], S_Fki.imag[f_in_pvpq & t_in_pvpq], -S_Fki.imag[t_in_pvpq]]
# data = np.r_[data, -S_Fik.imag[f_in_pvpq], S_Fik.imag[f_in_pvpq & t_in_pvpq], one[f_in_pvpq & t_in_pvpq], zero[t_in_pvpq]]
data = np.r_[data, -Q_Fik[f_in_pvpq], Q_Fik[f_in_pvpq & t_in_pvpq], np.where(control_delta, one[f_in_pvpq & t_in_pvpq], Q_Fki[f_in_pvpq & t_in_pvpq]), np.where(control_delta, zero[t_in_pvpq], -Q_Fki[t_in_pvpq])]
data = np.r_[data, -Q_Fik[f_in_pvpq], Q_Fik[f_in_pvpq & t_in_pvpq], np.where(control_delta[f_in_pvpq & t_in_pvpq], one[f_in_pvpq & t_in_pvpq], Q_Fki[f_in_pvpq & t_in_pvpq]), np.where(control_delta[t_in_pvpq], zero[t_in_pvpq], -Q_Fki[t_in_pvpq])]


# # J_C_P_u = np.zeros(shape=(len(pvpq), len(pq)), dtype=np.float64)
Expand All @@ -307,7 +307,7 @@ def create_J_modification_ssc(J, V, Ybus_ssc, f, t, pvpq, pq, pvpq_lookup, pq_lo
rows = np.r_[rows, pvpq_lookup[f[f_in_pvpq]], pvpq_lookup[f[f_in_pvpq & t_in_pq]], pvpq_lookup[t[f_in_pvpq & t_in_pq]], pvpq_lookup[t[t_in_pvpq & t_in_pq]]]
cols = np.r_[cols, len(pvpq)+pq_lookup[f[f_in_pq]], len(pvpq)+pq_lookup[t[f_in_pvpq & t_in_pq]], len(pvpq)+pq_lookup[f[f_in_pvpq & t_in_pq]], len(pvpq)+pq_lookup[t[t_in_pvpq & t_in_pq]]]
# data = np.r_[data, ((2 * S_Fii.real + S_Fik.real) / Vmf)[f_in_pvpq], (S_Fik.real/Vmt)[f_in_pvpq & t_in_pq], (S_Fki.real/Vmf)[f_in_pvpq & t_in_pq], ((2 * S_Fkk.real + S_Fki.real) / Vmt)[t_in_pvpq & t_in_pq]]
data = np.r_[data, ((2 * P_Fii + P_Fik) / Vmf)[f_in_pvpq], (P_Fik/Vmt)[f_in_pvpq & t_in_pq], np.where(control_delta, zero[f_in_pvpq & t_in_pq], (P_Fki/Vmf)[f_in_pvpq & t_in_pq]), np.where(control_delta, zero[t_in_pq], ((2 * P_Fkk + P_Fki) / Vmt)[t_in_pvpq & t_in_pq])]
data = np.r_[data, ((2 * P_Fii + P_Fik) / Vmf)[f_in_pvpq], (P_Fik/Vmt)[f_in_pvpq & t_in_pq], np.where(control_delta[f_in_pvpq & t_in_pq], zero[f_in_pvpq & t_in_pq], (P_Fki/Vmf)[f_in_pvpq & t_in_pq]), np.where(control_delta[t_in_pvpq & t_in_pq], zero[t_in_pvpq & t_in_pq], ((2 * P_Fkk + P_Fki) / Vmt)[t_in_pvpq & t_in_pq])]


# # J_C_Q_d = np.zeros(shape=(len(pq), len(pvpq)), dtype=np.float64)
Expand All @@ -329,7 +329,7 @@ def create_J_modification_ssc(J, V, Ybus_ssc, f, t, pvpq, pq, pvpq_lookup, pq_lo

rows = np.r_[rows, len(pvpq) + pq_lookup[f[f_in_pq]], len(pvpq) + pq_lookup[f[f_in_pq & t_in_pvpq]], len(pvpq) + pq_lookup[t[f_in_pvpq & t_in_pq]], len(pvpq) + pq_lookup[t[t_in_pq]]]
cols = np.r_[cols, pvpq_lookup[f[f_in_pvpq]], pvpq_lookup[t[f_in_pq & t_in_pvpq]], pvpq_lookup[f[f_in_pvpq & t_in_pq]], pvpq_lookup[t[t_in_pvpq]]]
data = np.r_[data, P_Fik[f_in_pq], -P_Fik[f_in_pq & t_in_pvpq], np.where(control_v, zero[f_in_pvpq & t_in_pq], P_Fik[f_in_pvpq & t_in_pq]), np.where(control_v, zero[t_in_pq], -P_Fik[t_in_pq])]
data = np.r_[data, P_Fik[f_in_pq], -P_Fik[f_in_pq & t_in_pvpq], np.where(control_v[f_in_pvpq & t_in_pq], zero[f_in_pvpq & t_in_pq], P_Fik[f_in_pvpq & t_in_pq]), np.where(control_v[t_in_pq], zero[t_in_pq], -P_Fik[t_in_pq])]



Expand All @@ -354,7 +354,7 @@ def create_J_modification_ssc(J, V, Ybus_ssc, f, t, pvpq, pq, pvpq_lookup, pq_lo

rows = np.r_[rows, len(pvpq)+pq_lookup[f[f_in_pq]], len(pvpq)+pq_lookup[f[f_in_pq & t_in_pq]], len(pvpq)+pq_lookup[t[f_in_pq & t_in_pq]], len(pvpq)+pq_lookup[t[t_in_pq]]]
cols = np.r_[cols, len(pvpq)+pq_lookup[f[f_in_pq]], len(pvpq)+pq_lookup[t[f_in_pq & t_in_pq]], len(pvpq)+pq_lookup[f[f_in_pq & t_in_pq]], len(pvpq)+pq_lookup[t[t_in_pq]]]
data = np.r_[data, ((2 * Q_Fii + Q_Fik) / Vmf)[f_in_pq], (Q_Fik / Vmt)[f_in_pq & t_in_pq], np.where(control_v, one[f_in_pq & t_in_pq], ((2 * Q_Fii + Q_Fik) / Vmf)[f_in_pq & t_in_pq]), np.where(control_v, zero[t_in_pq], (Q_Fik / Vmt)[t_in_pq])]
data = np.r_[data, ((2 * Q_Fii + Q_Fik) / Vmf)[f_in_pq], (Q_Fik / Vmt)[f_in_pq & t_in_pq], np.where(control_v[f_in_pq & t_in_pq], one[f_in_pq & t_in_pq], ((2 * Q_Fii + Q_Fik) / Vmf)[f_in_pq & t_in_pq]), np.where(control_v[t_in_pq], zero[t_in_pq], (Q_Fik / Vmt)[t_in_pq])]

# for vsc ac slack buses:
# rows = np.r_[rows, ac_slack]
Expand Down
14 changes: 8 additions & 6 deletions pandapower/pypower/newtonpf.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,12 @@ def newtonpf(Ybus, Sbus, V0, ref, pv, pq, ppci, options, makeYbus=None):
num_bus_dc = len(relevant_bus_dc)
any_branch_dc = num_branch_dc > 0
P_dc = np.zeros_like(bus_dc[relevant_bus_dc, DC_BUS_I], dtype=np.float64)
p_set_point_index = vsc_controllable & (vsc_mode_dc == 1)
p_set_point_index = vsc_controllable & (vsc_mode_dc == VSC_MODE_DC_P) & (vsc_mode_ac != VSC_MODE_AC_SL)
# P_dc[vsc[p_set_point_index, VSC_BUS_DC].astype(np.int64)] = -vsc_value_dc[vsc_mode_dc == 1] # todo sum by group
vsc_group_buses_p, P_dc_sum, vsc_group_buses_p_number = _sum_by_group(vsc_dc_bus[p_set_point_index], -vsc_value_dc[vsc_mode_dc == 1], np.ones(sum(p_set_point_index)))
vsc_group_buses_p, P_dc_sum, vsc_group_buses_p_number = _sum_by_group(vsc_dc_bus[p_set_point_index], -vsc_value_dc[p_set_point_index], np.ones(sum(p_set_point_index)))
P_dc[vsc_group_buses_p] = P_dc_sum
if len(P_dc_sum) == 0:
P_dc_sum = 0.
#vsc_group_buses_ref, _, vsc_group_buses_ref_number = _sum_by_group(vsc_dc_bus[p_set_point_index], -vsc_value_dc[vsc_mode_dc == 1], np.ones(sum(p_set_point_index)))

# J for HVDC is expanded by the number of DC "P" buses (added below)
Expand Down Expand Up @@ -300,7 +302,7 @@ def newtonpf(Ybus, Sbus, V0, ref, pv, pq, ppci, options, makeYbus=None):
ssc_tb[ssc_controllable], Ybus_ssc, ssc_controllable, ssc_set_vm_pu, F,
pq_lookup, vsc_controllable, vsc_fb, vsc_tb, Ybus_vsc, vsc_mode_ac, vsc_mode_dc,
vsc_value_ac, vsc_value_dc, vsc_dc_bus, V_dc, Ybus_hvdc, num_branch_dc, P_dc,
dc_p, dc_ref, dc_b2b, dc_p_lookup, dc_ref_lookup, dc_b2b_lookup)
dc_p, dc_ref, dc_b2b, dc_p_lookup, dc_ref_lookup, dc_b2b_lookup, P_dc_sum)
F = r_[F, mis_facts]

T_base = 100 # T in p.u. for better convergence
Expand Down Expand Up @@ -471,7 +473,7 @@ def newtonpf(Ybus, Sbus, V0, ref, pv, pq, ppci, options, makeYbus=None):
vsc_fb[vsc_controllable], vsc_tb[vsc_controllable], Ybus_vsc, vsc_mode_ac,
vsc_mode_dc, vsc_value_ac, vsc_value_dc, vsc_dc_bus, V_dc, Ybus_hvdc,
num_branch_dc, P_dc, dc_p, dc_ref, dc_b2b, dc_p_lookup, dc_ref_lookup,
dc_b2b_lookup)
dc_b2b_lookup, P_dc_sum)
F = r_[F, mis_facts]

if tdpf:
Expand Down Expand Up @@ -590,7 +592,7 @@ def _evaluate_Fx_facts(V,pq ,svc_buses=None, svc_set_vm_pu=None, tcsc_controllab
vsc_controllable=None, vsc_fb=None, vsc_tb=None, Ybus_vsc=None,
vsc_mode_ac=None, vsc_mode_dc=None, vsc_value_ac=None, vsc_value_dc=None, vsc_dc_bus=None,
V_dc=None, Ybus_hvdc=None, num_branch_dc=None, P_dc=None, dc_p=None, dc_ref=None, dc_b2b=None,
dc_p_lookup=None, dc_ref_lookup=None, dc_b2b_lookup=None):
dc_p_lookup=None, dc_ref_lookup=None, dc_b2b_lookup=None, P_dc_sum=None):
mis_facts = np.array([], dtype=np.float64)

if svc_buses is not None and len(svc_buses) > 0:
Expand Down Expand Up @@ -647,7 +649,7 @@ def _evaluate_Fx_facts(V,pq ,svc_buses=None, svc_set_vm_pu=None, tcsc_controllab
# this connects the AC slack result and the DC bus P set-point:
vsc_slack_p = -Sbus_vsc[vsc_tb[ac_mode_sl]].real
vsc_slack_p_dc_bus, vsc_slack_p_dc, _ = _sum_by_group(vsc_dc_bus[ac_mode_sl], vsc_slack_p, vsc_slack_p)
P_dc[vsc_slack_p_dc_bus] = vsc_slack_p_dc
P_dc[vsc_slack_p_dc_bus] = P_dc_sum + vsc_slack_p_dc

# find the connection between the DC buses and VSC buses
# find the slack DC buses
Expand Down
59 changes: 48 additions & 11 deletions pandapower/test/loadflow/test_facts.py
Original file line number Diff line number Diff line change
Expand Up @@ -1933,10 +1933,55 @@ def test_b2b_vsc_4():


def test_b2b_vsc_5():
net = pp.create_empty_network()
# AC part
pp.create_buses(net, 5, 110)
pp.create_line_from_parameters(net, 1, 3, 30, 0.0487, 0.13823, 160, 0.664)
pp.create_line_from_parameters(net, 2, 4, 30, 0.0487, 0.13823, 160, 0.664)
pp.create_ext_grid(net, 3)
pp.create_ext_grid(net, 4)
pp.create_load(net, 0, 40, 10)
pp.create_load(net, 2, 80, 20)


# DC part
pp.create_bus_dc(net, 150, 'A')

pp.create_vsc(net, 0, 0, 0.1, 5, control_mode_ac="slack", control_value_ac=1.,
control_mode_dc="p_mw", control_value_dc=0.)
pp.create_vsc(net, 1, 0, 0.1, 5, control_mode_ac="q_mvar", control_value_ac=10.,
control_mode_dc="vm_pu", control_value_dc=1.02)
pp.create_vsc(net, 2, 0, 0.1, 5, control_mode_ac="q_mvar", control_value_ac=4.,
control_mode_dc="p_mw", control_value_dc=5.)
runpp_with_consistency_checks(net)


def test_b2b_vsc_6():
net = pp.create_empty_network()
# AC part
pp.create_buses(net, 3, 110)
pp.create_line_from_parameters(net, 1, 2, 30, 0.0487, 0.13823, 160, 0.664)
pp.create_ext_grid(net, 2)
pp.create_load(net, 0, 20, 5)

# DC part
pp.create_bus_dc(net, 150, 'A')
pp.create_vsc(net, 0, 0, 0.1, 5, control_mode_ac="slack", control_value_ac=1.,
control_mode_dc="p_mw", control_value_dc=0.)
pp.create_vsc(net, 1, 0, 0.1, 5, control_mode_ac="q_mvar", control_value_ac=0.,
control_mode_dc="vm_pu", control_value_dc=1.)

# with pytest.raises(NotImplementedError):
# pp.runpp(net)
runpp_with_consistency_checks(net)


def test_b2b_vsc_7():
net = pp.create_empty_network()
# AC part
pp.create_buses(net, 2, 110)
pp.create_ext_grid(net, 0)
pp.create_ext_grid(net, 1) # todo: why is it not working when ext_grid is connected to the VSC AC bus?
pp.create_load(net, 0, 20, 5)

# DC part
pp.create_bus_dc(net, 150, 'A')
Expand All @@ -1945,8 +1990,7 @@ def test_b2b_vsc_5():
pp.create_vsc(net, 1, 0, 0.1, 5, control_mode_ac="q_mvar", control_value_ac=0.,
control_mode_dc="vm_pu", control_value_dc=1.)

with pytest.raises(NotImplementedError):
pp.runpp(net)
runpp_with_consistency_checks(net)


def test_b2b_line_dc_raise():
Expand Down Expand Up @@ -2240,20 +2284,13 @@ def test_vsc_slack2():
pp.create_line_dc(net, 0, 1, 100, std_type="2400-CU")

pp.create_vsc(net, 1, 0, 0.1, 5, control_mode_ac="vm_pu", control_value_ac=1, control_mode_dc="vm_pu", control_value_dc=1.02)
pp.create_vsc(net, 2, 1, 0.1, 5, control_mode_ac="slack", control_value_ac=1, control_mode_dc="p_mw", control_value_dc=1)
pp.create_vsc(net, 2, 1, 0.1, 5, control_mode_ac="slack", control_value_ac=1, control_mode_dc="p_mw", control_value_dc=10)

runpp_with_consistency_checks(net)

# pp.plotting.simple_plot(net, plot_loads=True)





# TODO VSC as slack - cannot work because slack is a Vm-Va bus,
# and the VSC is a Vm bus? One way to implement this is to declare
# the aux AC bus as slack, then use the result as the P set-point for
# the DC bus. This would enable connecting an island AC grid with an HVDC line.
# TODO test for when the VSC, SSC, TCSC, connect to same buses

if __name__ == "__main__":
Expand Down

0 comments on commit 2c96a7d

Please sign in to comment.