Skip to content

Commit

Permalink
AC voltage droop implementation
Browse files Browse the repository at this point in the history
Implementation and testing of two different options to control AC voltage for VSCs, i.e., reactive power droop and constant AC voltage control
  • Loading branch information
ozgurcansakinci committed Apr 3, 2024
1 parent 6d367ef commit bcb4442
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 8 deletions.
7 changes: 7 additions & 0 deletions src/core/constraint_template.jl
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,13 @@ function constraint_dc_droop_control(pm::_PM.AbstractPowerModel, i::Int; nw::Int
constraint_dc_droop_control(pm, nw, i, conv["busdc_i"], conv["Vdcset"], conv["Pdcset"], conv["droop"])
end

function constraint_ac_voltage_droop_control(pm::_PM.AbstractPowerModel, i::Int; nw::Int=_PM.nw_id_default)
conv = _PM.ref(pm, nw, :convdc, i)
bus = _PM.ref(pm, nw, :bus, conv["busac_i"])
v_ref = conv["Vtar"]
constraint_ac_voltage_droop_control(pm, nw, i, bus["index"], v_ref, conv["Q_g"], conv["kq_droop"])
end

############## TNEP Constraints #####################
function constraint_voltage_dc_ne(pm::_PM.AbstractPowerModel; nw::Int=_PM.nw_id_default)
constraint_voltage_dc_ne(pm, nw)
Expand Down
6 changes: 6 additions & 0 deletions src/formconv/acp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,12 @@ function constraint_dc_droop_control(pm::_PM.AbstractACPModel, n::Int, i::Int, b
JuMP.@constraint(pm.model, pconv_dc == pref_dc - sign(pref_dc) * 1 / k_droop * (vdc - vref_dc))
end

function constraint_ac_voltage_droop_control(pm::_PM.AbstractACPModel, n::Int, i::Int, busac_i, v_ref, qref, kq_droop)
q_inj = _PM.var(pm, n, :qconv_tf_fr, i)
vac = _PM.var(pm, n, :vm, busac_i)
# Arranging the signs of reactive powers below
JuMP.@constraint(pm.model, q_inj == -qref - kq_droop * (v_ref - vac))
end

#################### TNEP Constraints #########################
"""
Expand Down
17 changes: 9 additions & 8 deletions src/prob/acdcpf.jl
Original file line number Diff line number Diff line change
Expand Up @@ -74,23 +74,24 @@ function build_acdcpf(pm::_PM.AbstractPowerModel)
constraint_conv_filter(pm, c)
if conv["type_dc"] == 2
constraint_dc_voltage_magnitude_setpoint(pm, c)
constraint_reactive_conv_setpoint(pm, c)
elseif conv["type_dc"] == 3
if typeof(pm) <: _PM.AbstractACPModel || typeof(pm) <: _PM.AbstractACRModel
constraint_dc_droop_control(pm, c)
constraint_reactive_conv_setpoint(pm, c)
else
Memento.warn(_PM._LOGGER, join(["Droop only defined for ACP and ACR formulations, converter ", c, " will be treated as type 2"]))
constraint_dc_voltage_magnitude_setpoint(pm, c)
constraint_reactive_conv_setpoint(pm, c)
end
else
if conv["type_ac"] == 2
constraint_active_conv_setpoint(pm, c)
else
constraint_active_conv_setpoint(pm, c)
constraint_reactive_conv_setpoint(pm, c)
constraint_active_conv_setpoint(pm, c)
end
if conv["type_ac"] == 2
if haskey(conv, "acq_droop") && conv["acq_droop"] == 1 # AC voltage droop control
constraint_ac_voltage_droop_control(pm, c)
else # Constant AC voltage control
_PM.constraint_voltage_magnitude_setpoint(pm, conv["busac_i"])
end
else
constraint_reactive_conv_setpoint(pm, c)
end
constraint_converter_losses(pm, c)
constraint_converter_current(pm, c)
Expand Down
60 changes: 60 additions & 0 deletions test/data/case4_acdroop.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
function mpc = case4acdroop()
% 4bus case to test the AC voltage control functionalities of HVDC converters

%% MATPOWER Case Format : Version 1
%%----- Power Flow Data -----%%
%% system MVA base
mpc.baseMVA = 1000;

%% bus data
% bus_i type Pd Qd Gs Bs area Vm Va baseKV zone Vmax Vmin
mpc.bus = [
1 3 0 0 0 0 1 1 0 380 1 1.1 0.9;
2 3 0 0 0 0 1 1 0 380 1 1.1 0.9;
3 2 0 0 0 0 1 1 0 380 1 1.1 0.9;
4 2 0 0 0 0 1 1 0 380 1 1.1 0.9;
];

%% generator data
% bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin pc1 pc2 qlcmin qlcmax qc2min qc2max ramp_agc ramp_10 ramp_30 ramp_q apf
mpc.gen = [
1 -600 0 400 -400 1 100 1 1000 -1000 0 0 0 0 0 0 0 0 0 0 0;
2 600 0 400 -400 1 100 1 1000 -1000 0 0 0 0 0 0 0 0 0 0 0;
];

%% branch data
% fbus tbus r x b rateA rateB rateC ratio angle status angmin angmax
mpc.branch = [
1 3 0.111803414E-01 0.758119137E-01 0.945984133E-02 250 250 250 0 0 1 -90 90;
2 4 0.401327479E-01 0.272541773 0.340797668E-01 250 250 250 0 0 1 -90 90;
];


%% dc grid topology
%colunm_names% dcpoles
mpc.dcpol=1;
% numbers of poles (1=monopolar grid, 2=bipolar grid)
%% bus data
%column_names% busdc_i grid Pdc Vdc basekVdc Vdcmax Vdcmin Cdc
mpc.busdc = [
1 1 -600 1 380 1.1 0.9 0;
2 1 600 1 380 1.1 0.9 0;
3 1 -600 1 380 1.1 0.9 0;
4 1 600 1 380 1.1 0.9 0;
];

%% converters
%column_names% busdc_i busac_i type_dc type_ac P_g Q_g islcc Vtar rtf xtf transformer tm bf filter rc xc reactor basekVac Vmmax Vmmin Imax status LossA LossB LossCrec LossCinv droop Pdcset Vdcset dVdcset Pacmax Pacmin Qacmax Qacmin acq_droop kq_droop Vtar
mpc.convdc = [
1 3 2 2 -600 100 0 1 0 0 0 1 0 0 0.0074 0.1849 1 380 1.1 0.9 11 1 0 0 0 0 0.0050 -58.6274 1.0079 0 250 -250 100 -100 1 20 1;
2 4 1 2 600 100 0 1 0 0 0 1 0 0 0.0074 0.1849 1 380 1.1 0.9 11 1 0 0 0 0 0.0070 21.9013 1.0000 0 250 -250 100 -100 0 0 1;
3 3 2 2 -600 -100 0 1 0 0 0 1 0 0 0.0074 0.1849 1 380 1.1 0.9 11 1 0 0 0 0 0.0050 -58.6274 1.0079 0 250 -250 100 -100 1 10 1;
4 4 1 1 600 100 0 1 0 0 0 1 0 0 0.0074 0.1849 1 380 1.1 0.9 11 1 0 0 0 0 0.0070 21.9013 1.0000 0 250 -250 100 -100 0 0 1;
];

%% branches
%column_names% fbusdc tbusdc r l c rateA rateB rateC status
mpc.branchdc = [
1 2 0.644767896E-02 0 0 250 250 250 1;
3 4 0.644767896E-02 0 0 250 250 250 1;
];
33 changes: 33 additions & 0 deletions test/pf.jl
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,37 @@ end
@test isapprox(result["solution"]["convdc"]["2"]["pgrid"], -0.753; atol = 2e-3)
@test isapprox(result["solution"]["convdc"]["3"]["pdc"], -1.39167; atol = 2e-3)
end
end

@testset "4-bus ac voltage droop case" begin
result = run_acdcpf("./test/data/case4_acdroop.m", ACPPowerModel, ipopt_solver; setting = s)

@test result["termination_status"] == LOCALLY_SOLVED
@test isapprox(result["objective"], 0; atol = 1e-2)

@test isapprox(result["solution"]["gen"]["1"]["pg"], 1.23; atol = 2e-3)
@test isapprox(result["solution"]["gen"]["2"]["pg"], -1.142; atol = 2e-3)
@test isapprox(result["solution"]["gen"]["1"]["qg"], -0.057; atol = 2e-3)
@test isapprox(result["solution"]["gen"]["2"]["qg"], 0.352; atol = 2e-3)

@test isapprox(result["solution"]["bus"]["1"]["vm"], 1.0; atol = 2e-3)
@test isapprox(result["solution"]["bus"]["1"]["va"], 0.00000; atol = 2e-3)
@test isapprox(result["solution"]["bus"]["2"]["vm"], 1.0; atol = 2e-3)
@test isapprox(result["solution"]["bus"]["2"]["va"], 0.00000; atol = 2e-3)
@test isapprox(result["solution"]["bus"]["3"]["vm"], 0.995; atol = 2e-3)
@test isapprox(result["solution"]["bus"]["3"]["va"], -0.095; atol = 2e-3)
@test isapprox(result["solution"]["bus"]["4"]["vm"], 1.0; atol = 2e-3)
@test isapprox(result["solution"]["bus"]["4"]["va"], 0.332; atol = 2e-3)

@test isapprox(result["solution"]["convdc"]["1"]["pgrid"], 0.6067; atol = 2e-3)
@test isapprox(result["solution"]["convdc"]["1"]["qgrid"], -0.2081; atol = 2e-3)
@test isapprox(result["solution"]["convdc"]["3"]["pgrid"], 0.6067; atol = 2e-3)
@test isapprox(result["solution"]["convdc"]["3"]["qgrid"], 0.0459; atol = 2e-3)
@test isapprox(result["solution"]["convdc"]["2"]["pgrid"], -0.6; atol = 2e-3)
@test isapprox(result["solution"]["convdc"]["2"]["qgrid"], 0.0932; atol = 2e-3)
@test isapprox(result["solution"]["convdc"]["4"]["pgrid"], -0.6; atol = 2e-3)
@test isapprox(result["solution"]["convdc"]["4"]["qgrid"], -0.1; atol = 2e-3)

# @test isapprox(result["solution"]["busdc"]["1"]["vm"], 1.008; atol = 2e-3)

end
12 changes: 12 additions & 0 deletions test/scripts/ACdrooptest.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using PowerModels, JuMP, Ipopt

casename = "case4_acdroop"

file = "./test/data/$casename.m"
data = PowerModels.parse_file(file)
PowerModelsACDC.process_additional_data!(data)

ipopt = JuMP.optimizer_with_attributes(Ipopt.Optimizer, "tol" => 1e-6, "print_level" => 0)
s = Dict("output" => Dict("branch_flows" => true), "conv_losses_mp" => false)
result = run_acdcpf(data, ACPPowerModel, ipopt; setting = s)
println(result["termination_status"])

0 comments on commit bcb4442

Please sign in to comment.