From bf3aaa660efbae52ecb684ccbab79756d19beceb Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Mon, 11 Sep 2023 15:17:40 -0700 Subject: [PATCH 1/5] modify inverter struct model --- src/models/dynamic_inverter.jl | 9 +++++++++ src/models/dynamic_inverter_components.jl | 1 + 2 files changed, 10 insertions(+) diff --git a/src/models/dynamic_inverter.jl b/src/models/dynamic_inverter.jl index 8cb824c812..d9f9e6802a 100644 --- a/src/models/dynamic_inverter.jl +++ b/src/models/dynamic_inverter.jl @@ -17,6 +17,7 @@ abstract type InverterComponent <: DynamicComponent end dc_source::DC freq_estimator::P filter::F + limiter::Union{nothing, InverterLimiter} base_power::Float64 n_states::Int states::Vector{Symbol} @@ -36,6 +37,7 @@ a DC Source, a Frequency Estimator and a Filter. It requires a Static Injection - `dc_source <: DCSource`: DC Source model. - `freq_estimator <: FrequencyEstimator`: Frequency Estimator (typically a PLL) model. - `filter <: Filter`: Filter model. +- `limiter <: Union{nothing, InverterLimiter}`: Inverter Inner Control Limiter model - `base_power::Float64`: Base power - `n_states::Int`: Number of states (will depend on the components). - `states::Vector{Symbol}`: Vector of states (will depend on the components). @@ -58,6 +60,7 @@ mutable struct DynamicInverter{ dc_source::DC freq_estimator::P filter::F + limiter::Union{Nothing, InverterLimiter} base_power::Float64 n_states::Int states::Vector{Symbol} @@ -74,6 +77,7 @@ function DynamicInverter( dc_source::DC, freq_estimator::P, filter::F, + limiter::Union{Nothing, L} = nothing, base_power::Float64 = 100.0, ext::Dict{String, Any} = Dict{String, Any}(), ) where { @@ -83,6 +87,7 @@ function DynamicInverter( DC <: DCSource, P <: FrequencyEstimator, F <: Filter, + L <: InverterLimiter, } n_states = _calc_n_states( converter, @@ -110,6 +115,7 @@ function DynamicInverter( dc_source, freq_estimator, filter, + limiter, base_power, n_states, states, @@ -127,6 +133,7 @@ function DynamicInverter(; dc_source::DC, freq_estimator::P, filter::F, + limiter::Union{Nothing, L} = nothing, base_power::Float64 = 100.0, n_states = _calc_n_states( converter, @@ -153,6 +160,7 @@ function DynamicInverter(; DC <: DCSource, P <: FrequencyEstimator, F <: Filter, + L <: InverterLimiter, } return DynamicInverter( name, @@ -163,6 +171,7 @@ function DynamicInverter(; dc_source, freq_estimator, filter, + limiter, base_power, n_states, states, diff --git a/src/models/dynamic_inverter_components.jl b/src/models/dynamic_inverter_components.jl index 21f7992dc2..5318fce89e 100644 --- a/src/models/dynamic_inverter_components.jl +++ b/src/models/dynamic_inverter_components.jl @@ -4,6 +4,7 @@ abstract type DCSource <: DynamicInverterComponent end abstract type Filter <: DynamicInverterComponent end abstract type FrequencyEstimator <: DynamicInverterComponent end abstract type InnerControl <: DynamicInverterComponent end +abstract type InverterLimiter <: DynamicInverterComponent end abstract type ActivePowerControl <: DeviceParameter end abstract type ReactivePowerControl <: DeviceParameter end From 338c7e36c4871e361941ad9dcbfa18c4499fce27 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Mon, 11 Sep 2023 15:18:14 -0700 Subject: [PATCH 2/5] Add Inverter Limiter Structs Co-authored-by: HaleyRoss --- src/PowerSystems.jl | 5 ++ src/descriptors/power_system_structs.json | 89 +++++++++++++++++++ .../generated/InstantaneousCurrentLimiter.jl | 55 ++++++++++++ .../generated/MagnitudeCurrentLimiter.jl | 46 ++++++++++ .../generated/PriorityCurrentLimiter.jl | 55 ++++++++++++ src/models/generated/includes.jl | 9 ++ 6 files changed, 259 insertions(+) create mode 100644 src/models/generated/InstantaneousCurrentLimiter.jl create mode 100644 src/models/generated/MagnitudeCurrentLimiter.jl create mode 100644 src/models/generated/PriorityCurrentLimiter.jl diff --git a/src/PowerSystems.jl b/src/PowerSystems.jl index 21d716a9fe..dd0922e00a 100644 --- a/src/PowerSystems.jl +++ b/src/PowerSystems.jl @@ -195,6 +195,11 @@ export VoltageModeControl export CurrentModeControl export RECurrentControlB +# InverterLimiters Export +export MagnitudeCurrentLimiter +export InstantaneousCurrentLimiter +export PriorityCurrentLimiter + export Source export PeriodicVariableSource diff --git a/src/descriptors/power_system_structs.json b/src/descriptors/power_system_structs.json index 5e648979ab..c4dd2d43f7 100644 --- a/src/descriptors/power_system_structs.json +++ b/src/descriptors/power_system_structs.json @@ -15039,6 +15039,95 @@ ], "supertype": "InnerControl" }, + { + "struct_name": "MagnitudeCurrentLimiter", + "docstring": "Parameters of Magnitude (Circular) Current Controller Limiter", + "fields": [ + { + "name": "I_max", + "comment": "Maximum limit on current controller input current (device base)", + "null_value": 0, + "data_type": "Float64", + "valid_range": { + "min": 0, + "max": null + } + }, + { + "name": "ext", + "data_type": "Dict{String, Any}", + "null_value": "Dict{String, Any}()", + "default": "Dict{String, Any}()" + } + ], + "supertype": "InverterLimiter" + }, + { + "struct_name": "InstantaneousCurrentLimiter", + "docstring": "Parameters of Instantaneous (Square) Current Controller Limiter", + "fields": [ + { + "name": "Id_max", + "comment": "Maximum limit on d-axis current controller input current (device base)", + "null_value": 0, + "data_type": "Float64", + "valid_range": { + "min": 0, + "max": null + } + }, + { + "name": "Iq_max", + "comment": "Maximum limit on d-axis current controller input current (device base)", + "null_value": 0, + "data_type": "Float64", + "valid_range": { + "min": 0, + "max": null + } + }, + { + "name": "ext", + "data_type": "Dict{String, Any}", + "null_value": "Dict{String, Any}()", + "default": "Dict{String, Any}()" + } + ], + "supertype": "InverterLimiter" + }, + { + "struct_name": "PriorityCurrentLimiter", + "docstring": "Parameters of Priority-Based Current Controller Limiter", + "fields": [ + { + "name": "I_max", + "comment": "Maximum limit on current controller input current (device base)", + "null_value": 0, + "data_type": "Float64", + "valid_range": { + "min": 0, + "max": null + } + }, + { + "name": "ϕ_I", + "comment": "Pre-defined angle (measured against the d-axis) for Iref once limit is hit", + "null_value": 0, + "data_type": "Float64", + "valid_range": { + "min": -1.571, + "max": 1.571 + } + }, + { + "name": "ext", + "data_type": "Dict{String, Any}", + "null_value": "Dict{String, Any}()", + "default": "Dict{String, Any}()" + } + ], + "supertype": "InverterLimiter" + }, { "struct_name": "AggregateDistributedGenerationA", "docstring": "Parameters of the DERA1 model in PSS/E", diff --git a/src/models/generated/InstantaneousCurrentLimiter.jl b/src/models/generated/InstantaneousCurrentLimiter.jl new file mode 100644 index 0000000000..49fb315395 --- /dev/null +++ b/src/models/generated/InstantaneousCurrentLimiter.jl @@ -0,0 +1,55 @@ +#= +This file is auto-generated. Do not edit. +=# + +#! format: off + +""" + mutable struct InstantaneousCurrentLimiter <: InverterLimiter + Id_max::Float64 + Iq_max::Float64 + ext::Dict{String, Any} + end + +Parameters of Instantaneous (Square) Current Controller Limiter + +# Arguments +- `Id_max::Float64`: Maximum limit on d-axis current controller input current (device base), validation range: `(0, nothing)` +- `Iq_max::Float64`: Maximum limit on d-axis current controller input current (device base), validation range: `(0, nothing)` +- `ext::Dict{String, Any}` +""" +mutable struct InstantaneousCurrentLimiter <: InverterLimiter + "Maximum limit on d-axis current controller input current (device base)" + Id_max::Float64 + "Maximum limit on d-axis current controller input current (device base)" + Iq_max::Float64 + ext::Dict{String, Any} +end + + +function InstantaneousCurrentLimiter(; Id_max, Iq_max, ext=Dict{String, Any}(), ) + InstantaneousCurrentLimiter(Id_max, Iq_max, ext, ) +end + +# Constructor for demo purposes; non-functional. +function InstantaneousCurrentLimiter(::Nothing) + InstantaneousCurrentLimiter(; + Id_max=0, + Iq_max=0, + ext=Dict{String, Any}(), + ) +end + +"""Get [`InstantaneousCurrentLimiter`](@ref) `Id_max`.""" +get_Id_max(value::InstantaneousCurrentLimiter) = value.Id_max +"""Get [`InstantaneousCurrentLimiter`](@ref) `Iq_max`.""" +get_Iq_max(value::InstantaneousCurrentLimiter) = value.Iq_max +"""Get [`InstantaneousCurrentLimiter`](@ref) `ext`.""" +get_ext(value::InstantaneousCurrentLimiter) = value.ext + +"""Set [`InstantaneousCurrentLimiter`](@ref) `Id_max`.""" +set_Id_max!(value::InstantaneousCurrentLimiter, val) = value.Id_max = val +"""Set [`InstantaneousCurrentLimiter`](@ref) `Iq_max`.""" +set_Iq_max!(value::InstantaneousCurrentLimiter, val) = value.Iq_max = val +"""Set [`InstantaneousCurrentLimiter`](@ref) `ext`.""" +set_ext!(value::InstantaneousCurrentLimiter, val) = value.ext = val diff --git a/src/models/generated/MagnitudeCurrentLimiter.jl b/src/models/generated/MagnitudeCurrentLimiter.jl new file mode 100644 index 0000000000..a8c08a8e19 --- /dev/null +++ b/src/models/generated/MagnitudeCurrentLimiter.jl @@ -0,0 +1,46 @@ +#= +This file is auto-generated. Do not edit. +=# + +#! format: off + +""" + mutable struct MagnitudeCurrentLimiter <: InverterLimiter + I_max::Float64 + ext::Dict{String, Any} + end + +Parameters of Magnitude (Circular) Current Controller Limiter + +# Arguments +- `I_max::Float64`: Maximum limit on current controller input current (device base), validation range: `(0, nothing)` +- `ext::Dict{String, Any}` +""" +mutable struct MagnitudeCurrentLimiter <: InverterLimiter + "Maximum limit on current controller input current (device base)" + I_max::Float64 + ext::Dict{String, Any} +end + + +function MagnitudeCurrentLimiter(; I_max, ext=Dict{String, Any}(), ) + MagnitudeCurrentLimiter(I_max, ext, ) +end + +# Constructor for demo purposes; non-functional. +function MagnitudeCurrentLimiter(::Nothing) + MagnitudeCurrentLimiter(; + I_max=0, + ext=Dict{String, Any}(), + ) +end + +"""Get [`MagnitudeCurrentLimiter`](@ref) `I_max`.""" +get_I_max(value::MagnitudeCurrentLimiter) = value.I_max +"""Get [`MagnitudeCurrentLimiter`](@ref) `ext`.""" +get_ext(value::MagnitudeCurrentLimiter) = value.ext + +"""Set [`MagnitudeCurrentLimiter`](@ref) `I_max`.""" +set_I_max!(value::MagnitudeCurrentLimiter, val) = value.I_max = val +"""Set [`MagnitudeCurrentLimiter`](@ref) `ext`.""" +set_ext!(value::MagnitudeCurrentLimiter, val) = value.ext = val diff --git a/src/models/generated/PriorityCurrentLimiter.jl b/src/models/generated/PriorityCurrentLimiter.jl new file mode 100644 index 0000000000..59dfa1335e --- /dev/null +++ b/src/models/generated/PriorityCurrentLimiter.jl @@ -0,0 +1,55 @@ +#= +This file is auto-generated. Do not edit. +=# + +#! format: off + +""" + mutable struct PriorityCurrentLimiter <: InverterLimiter + I_max::Float64 + ϕ_I::Float64 + ext::Dict{String, Any} + end + +Parameters of Priority-Based Current Controller Limiter + +# Arguments +- `I_max::Float64`: Maximum limit on current controller input current (device base), validation range: `(0, nothing)` +- `ϕ_I::Float64`: Pre-defined angle (measured against the d-axis) for Iref once limit is hit, validation range: `(-1.571, 1.571)` +- `ext::Dict{String, Any}` +""" +mutable struct PriorityCurrentLimiter <: InverterLimiter + "Maximum limit on current controller input current (device base)" + I_max::Float64 + "Pre-defined angle (measured against the d-axis) for Iref once limit is hit" + ϕ_I::Float64 + ext::Dict{String, Any} +end + + +function PriorityCurrentLimiter(; I_max, ϕ_I, ext=Dict{String, Any}(), ) + PriorityCurrentLimiter(I_max, ϕ_I, ext, ) +end + +# Constructor for demo purposes; non-functional. +function PriorityCurrentLimiter(::Nothing) + PriorityCurrentLimiter(; + I_max=0, + ϕ_I=0, + ext=Dict{String, Any}(), + ) +end + +"""Get [`PriorityCurrentLimiter`](@ref) `I_max`.""" +get_I_max(value::PriorityCurrentLimiter) = value.I_max +"""Get [`PriorityCurrentLimiter`](@ref) `ϕ_I`.""" +get_ϕ_I(value::PriorityCurrentLimiter) = value.ϕ_I +"""Get [`PriorityCurrentLimiter`](@ref) `ext`.""" +get_ext(value::PriorityCurrentLimiter) = value.ext + +"""Set [`PriorityCurrentLimiter`](@ref) `I_max`.""" +set_I_max!(value::PriorityCurrentLimiter, val) = value.I_max = val +"""Set [`PriorityCurrentLimiter`](@ref) `ϕ_I`.""" +set_ϕ_I!(value::PriorityCurrentLimiter, val) = value.ϕ_I = val +"""Set [`PriorityCurrentLimiter`](@ref) `ext`.""" +set_ext!(value::PriorityCurrentLimiter, val) = value.ext = val diff --git a/src/models/generated/includes.jl b/src/models/generated/includes.jl index d4ac501c1c..26d2c5aa69 100644 --- a/src/models/generated/includes.jl +++ b/src/models/generated/includes.jl @@ -116,6 +116,9 @@ include("ReactiveVirtualOscillator.jl") include("VoltageModeControl.jl") include("CurrentModeControl.jl") include("RECurrentControlB.jl") +include("MagnitudeCurrentLimiter.jl") +include("InstantaneousCurrentLimiter.jl") +include("PriorityCurrentLimiter.jl") include("AggregateDistributedGenerationA.jl") include("Source.jl") include("PeriodicVariableSource.jl") @@ -172,9 +175,11 @@ export get_H_lim export get_H_lp export get_I_lr export get_I_max +export get_Id_max export get_Iflim export get_Io_lim export get_Iq_lim +export get_Iq_max export get_Iqinj_lim export get_Iqr_lim export get_Iqr_lims @@ -652,6 +657,7 @@ export get_ω_ref export get_ωad export get_ωf export get_ωz +export get_ϕ_I export set_A! export set_A1! export set_A2! @@ -703,9 +709,11 @@ export set_H_lim! export set_H_lp! export set_I_lr! export set_I_max! +export set_Id_max! export set_Iflim! export set_Io_lim! export set_Iq_lim! +export set_Iq_max! export set_Iqinj_lim! export set_Iqr_lim! export set_Iqr_lims! @@ -1183,3 +1191,4 @@ export set_ω_ref! export set_ωad! export set_ωf! export set_ωz! +export set_ϕ_I! From d390dcc0d83f14a4d1e57100ee0cfd22578e3735 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Mon, 11 Sep 2023 15:19:59 -0700 Subject: [PATCH 3/5] add test --- test/Project.toml | 1 - test/test_dynamic_inverter.jl | 65 +++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/test/Project.toml b/test/Project.toml index f6b0046b70..3f20f6e04a 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -23,4 +23,3 @@ YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6" [compat] InfrastructureSystems = "1" julia = "^1.2" -PowerSystemCaseBuilder = "^1.1.0" diff --git a/test/test_dynamic_inverter.jl b/test/test_dynamic_inverter.jl index 5dd1af7ba9..126a042fea 100644 --- a/test/test_dynamic_inverter.jl +++ b/test/test_dynamic_inverter.jl @@ -66,6 +66,71 @@ end test_accessors(test_inverter) end +@testset "Dynamic Inverter Limiters" begin + converter = AverageConverter(690.0, 2750000.0) #S_rated goes in Watts + dc_source = FixedDCSource(600.0) #Not in the original data, guessed. + filt = LCLFilter(0.08, 0.003, 0.074, 0.2, 0.01) + pll = KauraPLL(500.0, 0.084, 4.69) + virtual_H = VirtualInertia(2.0, 400.0, 20.0, 2 * pi * 50.0) + Q_control = ReactivePowerDroop(0.2, 1000.0) + outer_control = OuterControl(virtual_H, Q_control) + vsc = VoltageModeControl(0.59, 736.0, 0.0, 0.0, 0.2, 1.27, 14.3, 0.0, 50.0, 0.2) + inverter = DynamicInverter(; + name = "TestInverter", + ω_ref = 1.0, + converter = converter, + outer_control = outer_control, + inner_control = vsc, + dc_source = dc_source, + freq_estimator = pll, + filter = filt, + ) + @test test_inverter isa PowerSystems.Component + test_accessors(inverter) + inv_magnitude = DynamicInverter(; + name = "TestInverter", + ω_ref = 1.0, + converter = converter, + outer_control = outer_control, + inner_control = vsc, + dc_source = dc_source, + freq_estimator = pll, + filter = filt, + limiter = MagnitudeCurrentLimiter(; I_max = 1.0), + ) + @test inv_magnitude isa PowerSystems.Components + test_accessors(inv_magnitude) + inv_inst = DynamicInverter(; + name = "TestInverter", + ω_ref = 1.0, + converter = converter, + outer_control = outer_control, + inner_control = vsc, + dc_source = dc_source, + freq_estimator = pll, + filter = filt, + limiter = InstantaneousCurrentLimiter(; + Id_max = 1.0 / sqrt(2), + Iq_max = 1.0 / sqrt(2), + ), + ) + @test inv_inst isa PowerSystems.Components + test_accessors(inv_inst) + inv_priority = DynamicInverter(; + name = "TestInverter", + ω_ref = 1.0, + converter = converter, + outer_control = outer_control, + inner_control = vsc, + dc_source = dc_source, + freq_estimator = pll, + filter = filt, + limiter = PriorityCurrentLimiter(; I_max = 1.0, ϕ_I = 0.1), + ) + @test inv_priority isa PowerSystems.Components + test_accessors(inv_priority) +end + @testset "Generic Renewable Models" begin converter_regca1 = RenewableEnergyConverterTypeA(; T_g = 0.02, From 6e814dce6a4854331c422ae3038aac7b38a1c874 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Mon, 11 Sep 2023 17:12:02 -0700 Subject: [PATCH 4/5] fix unbound params --- src/models/dynamic_inverter.jl | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/models/dynamic_inverter.jl b/src/models/dynamic_inverter.jl index d9f9e6802a..3181b5c751 100644 --- a/src/models/dynamic_inverter.jl +++ b/src/models/dynamic_inverter.jl @@ -51,6 +51,7 @@ mutable struct DynamicInverter{ DC <: DCSource, P <: FrequencyEstimator, F <: Filter, + L <: Union{Nothing, InverterLimiter}, } <: DynamicInjection name::String ω_ref::Float64 @@ -60,7 +61,7 @@ mutable struct DynamicInverter{ dc_source::DC freq_estimator::P filter::F - limiter::Union{Nothing, InverterLimiter} + limiter::L base_power::Float64 n_states::Int states::Vector{Symbol} @@ -77,7 +78,7 @@ function DynamicInverter( dc_source::DC, freq_estimator::P, filter::F, - limiter::Union{Nothing, L} = nothing, + limiter::L = nothing, base_power::Float64 = 100.0, ext::Dict{String, Any} = Dict{String, Any}(), ) where { @@ -87,7 +88,7 @@ function DynamicInverter( DC <: DCSource, P <: FrequencyEstimator, F <: Filter, - L <: InverterLimiter, + L <: Union{Nothing, InverterLimiter}, } n_states = _calc_n_states( converter, @@ -133,7 +134,7 @@ function DynamicInverter(; dc_source::DC, freq_estimator::P, filter::F, - limiter::Union{Nothing, L} = nothing, + limiter::L = nothing, base_power::Float64 = 100.0, n_states = _calc_n_states( converter, @@ -160,7 +161,7 @@ function DynamicInverter(; DC <: DCSource, P <: FrequencyEstimator, F <: Filter, - L <: InverterLimiter, + L <: Union{Nothing, InverterLimiter}, } return DynamicInverter( name, From be02aac049e74ac91fdfdf3c61c347c3a14eaa24 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Mon, 11 Sep 2023 17:31:01 -0700 Subject: [PATCH 5/5] update tests --- src/models/dynamic_inverter.jl | 2 +- test/test_dynamic_inverter.jl | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/models/dynamic_inverter.jl b/src/models/dynamic_inverter.jl index 3181b5c751..5dea636429 100644 --- a/src/models/dynamic_inverter.jl +++ b/src/models/dynamic_inverter.jl @@ -107,7 +107,7 @@ function DynamicInverter( filter, ) - return DynamicInverter{C, O, IC, DC, P, F}( + return DynamicInverter{C, O, IC, DC, P, F, L}( name, ω_ref, converter, diff --git a/test/test_dynamic_inverter.jl b/test/test_dynamic_inverter.jl index 126a042fea..8577435748 100644 --- a/test/test_dynamic_inverter.jl +++ b/test/test_dynamic_inverter.jl @@ -75,17 +75,17 @@ end Q_control = ReactivePowerDroop(0.2, 1000.0) outer_control = OuterControl(virtual_H, Q_control) vsc = VoltageModeControl(0.59, 736.0, 0.0, 0.0, 0.2, 1.27, 14.3, 0.0, 50.0, 0.2) - inverter = DynamicInverter(; - name = "TestInverter", - ω_ref = 1.0, - converter = converter, - outer_control = outer_control, - inner_control = vsc, - dc_source = dc_source, - freq_estimator = pll, - filter = filt, + inverter = DynamicInverter( + "TestInverter", + 1.0, + converter, + outer_control, + vsc, + dc_source, + pll, + filt, ) - @test test_inverter isa PowerSystems.Component + @test inverter isa PowerSystems.Component test_accessors(inverter) inv_magnitude = DynamicInverter(; name = "TestInverter", @@ -98,7 +98,7 @@ end filter = filt, limiter = MagnitudeCurrentLimiter(; I_max = 1.0), ) - @test inv_magnitude isa PowerSystems.Components + @test inv_magnitude isa PowerSystems.Component test_accessors(inv_magnitude) inv_inst = DynamicInverter(; name = "TestInverter", @@ -114,7 +114,7 @@ end Iq_max = 1.0 / sqrt(2), ), ) - @test inv_inst isa PowerSystems.Components + @test inv_inst isa PowerSystems.Component test_accessors(inv_inst) inv_priority = DynamicInverter(; name = "TestInverter", @@ -127,7 +127,7 @@ end filter = filt, limiter = PriorityCurrentLimiter(; I_max = 1.0, ϕ_I = 0.1), ) - @test inv_priority isa PowerSystems.Components + @test inv_priority isa PowerSystems.Component test_accessors(inv_priority) end