Skip to content
1 change: 1 addition & 0 deletions src/definitions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ const BRANCH_BUS_VOLTAGE_DIFFERENCE_TOL = 0.01

const PSSE_PARSER_TAP_RATIO_UBOUND = 1.5
const PSSE_PARSER_TAP_RATIO_LBOUND = 0.5
const PARSER_TAP_RATIO_CORRECTION_TOL = 1e-5

const WINDING_NAMES = Dict(
WindingCategory.PRIMARY_WINDING => "primary",
Expand Down
86 changes: 81 additions & 5 deletions src/parsers/pm_io/psse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,37 @@ function _psse2pm_shunt!(pm_data::Dict, pti_data::Dict, import_all::Bool)
end
end

function apply_tap_correction!(
Comment thread
m-bossart marked this conversation as resolved.
windv_value::Float64,
transformer::Dict{String, Any},
cod_key::String,
rmi_key::String,
rma_key::String,
ntp_key::String,
cw_value::Int64,
winding_name::String,
)
if abs(transformer[cod_key]) ∈ [1, 2] && cw_value ∈ [1, 3]
tap_positions = collect(
range(
transformer[rmi_key],
transformer[rma_key];
length = Int(transformer[ntp_key]),
),
)
closest_tap_ix = argmin(abs.(tap_positions .- windv_value))
if !isapprox(
windv_value,
tap_positions[closest_tap_ix];
atol = PARSER_TAP_RATIO_CORRECTION_TOL,
)
@warn "Transformer $winding_name winding tap setting is not on a step; $windv_value set to $(tap_positions[closest_tap_ix])"
return tap_positions[closest_tap_ix]
end
end
return windv_value
end

"""
_psse2pm_transformer!(pm_data, pti_data)

Expand Down Expand Up @@ -769,10 +800,20 @@ function _psse2pm_transformer!(pm_data::Dict, pti_data::Dict, import_all::Bool)
sub_data["nomv2"] = transformer["NOMV2"]
end

sub_data["tap"] = pop!(transformer, "WINDV1") / pop!(transformer, "WINDV2")
windv1 = pop!(transformer, "WINDV1")
windv1 = apply_tap_correction!(
windv1,
transformer,
"COD1",
"RMI1",
"RMA1",
"NTP1",
transformer["CW"],
"primary",
)
sub_data["tap"] = windv1 / pop!(transformer, "WINDV2")
sub_data["shift"] = pop!(transformer, "ANG1")

# Unit Transformations
if transformer["CW"] != 1 # NOT "for off-nominal turns ratio in pu of winding bus base voltage"
sub_data["tap"] *=
_get_bus_value(transformer["J"], "base_kv", pm_data) /
Expand Down Expand Up @@ -1082,10 +1123,45 @@ function _psse2pm_transformer!(pm_data::Dict, pti_data::Dict, import_all::Bool)
sub_data["secondary_correction_table"] = transformer["TAB2"]
sub_data["tertiary_correction_table"] = transformer["TAB3"]

windv1 = transformer["WINDV1"]
windv2 = transformer["WINDV2"]
windv3 = transformer["WINDV3"]

windv1 = apply_tap_correction!(
windv1,
transformer,
"COD1",
"RMI1",
"RMA1",
"NTP1",
transformer["CW"],
"primary",
)
windv2 = apply_tap_correction!(
windv2,
transformer,
"COD2",
"RMI2",
"RMA2",
"NTP2",
transformer["CW"],
"secondary",
)
windv3 = apply_tap_correction!(
windv3,
transformer,
"COD3",
"RMI3",
"RMA3",
"NTP3",
transformer["CW"],
"tertiary",
)

if transformer["CW"] == 1
sub_data["primary_turns_ratio"] = transformer["WINDV1"]
sub_data["secondary_turns_ratio"] = transformer["WINDV2"]
sub_data["tertiary_turns_ratio"] = transformer["WINDV3"]
sub_data["primary_turns_ratio"] = windv1
sub_data["secondary_turns_ratio"] = windv2
sub_data["tertiary_turns_ratio"] = windv3
else
sub_data["primary_turns_ratio"] =
transformer["WINDV1"] / sub_data["base_voltage_primary"]
Expand Down
21 changes: 21 additions & 0 deletions test/test_parse_psse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,27 @@ end
@test IS.compare_values(original_sys, deserialized_sys)
end

@testset "PSSE transformer tap position correction testing" begin
sys = build_system(
PSSEParsingTestSystems,
"psse_14_tap_correction_test_system";
force_build = true,
)
#test 2W correction matches PSSE
trf = get_component(TapTransformer, sys, "BUS 104-BUS 107-i_1")
tap = get_tap(trf)
@test isapprox(tap, 0.979937; atol = 1e-6)

#test 3W correction matches PSSE
trf_3w = get_component(Transformer3W, sys, "BUS 109-BUS 104-BUS 107-i_1")
tap1 = get_primary_turns_ratio(trf_3w)
tap2 = get_secondary_turns_ratio(trf_3w)
tap3 = get_tertiary_turns_ratio(trf_3w)
@test isapprox(tap1, 0.98750; atol = 1e-6)
@test isapprox(tap2, 0.97500; atol = 1e-6)
@test isapprox(tap3, 0.96250; atol = 1e-6)
end

@testset "PSSE isolated bus handling (unavailable vs topologically isolated)" begin
sys =
build_system(PSSEParsingTestSystems, "isolated_bus_test_system"; force_build = true)
Expand Down
Loading