From 528371abec826cb00e9cdd12291b6669811e7c11 Mon Sep 17 00:00:00 2001 From: Philibert Parquier Date: Thu, 20 Jun 2024 14:03:51 +0200 Subject: [PATCH] #3248 Add IEC63406 model Signed-off-by: Philibert Parquier --- .../IEC/IEC63406/AuxiliaryBlocks/Min3.mo | 38 ++ .../IEC63406/AuxiliaryBlocks/QuadriSwitch.mo | 38 ++ .../IEC63406/AuxiliaryBlocks/StrongDelay.mo | 29 ++ .../IEC63406/AuxiliaryBlocks/SwitchComplex.mo | 44 ++ .../IEC63406/AuxiliaryBlocks/TripleSwitch.mo | 36 ++ .../IEC/IEC63406/AuxiliaryBlocks/package.mo | 18 + .../IEC63406/AuxiliaryBlocks/package.order | 5 + .../IEC/IEC63406/ControlAndProtection.mo | 296 ++++++++++++ .../AuxiliaryControls/IpLimitation.mo | 50 ++ .../AuxiliaryControls/IqLimitation.mo | 49 ++ .../BaseControls/AuxiliaryControls/package.mo | 17 + .../AuxiliaryControls/package.order | 2 + .../BaseControls/CurrentLimitation.mo | 217 +++++++++ .../IEC/IEC63406/Controls/BaseControls/FFR.mo | 131 +++++ .../Controls/BaseControls/PControl.mo | 167 +++++++ .../Controls/BaseControls/QControl.mo | 321 +++++++++++++ .../Controls/BaseControls/QLimitation.mo | 159 +++++++ .../IEC63406/Controls/BaseControls/package.mo | 17 + .../Controls/BaseControls/package.order | 6 + .../Controls/IEC/IEC63406/Controls/Control.mo | 274 +++++++++++ .../Controls/IEC/IEC63406/Controls/package.mo | 17 + .../IEC/IEC63406/Controls/package.order | 2 + .../IEC/IEC63406/FaultModules/package.order | 0 .../IEC/IEC63406/InjectorCurrentSource.mo | 110 +++++ .../IEC/IEC63406/InjectorVoltageSource.mo | 108 +++++ .../IEC63406/Measurement/GridMeasurement.mo | 62 +++ .../Controls/IEC/IEC63406/Measurement/PLL.mo | 188 ++++++++ .../IEC/IEC63406/Measurement/package.mo | 17 + .../IEC/IEC63406/Measurement/package.order | 2 + .../IEC/IEC63406/PlantCommunication.mo | 149 ++++++ .../PrimaryEnergy/Auxiliary/SOCcontrol.mo | 50 ++ .../PrimaryEnergy/Auxiliary/StorageSys.mo | 99 ++++ .../PrimaryEnergy/Auxiliary/package.mo | 17 + .../PrimaryEnergy/Auxiliary/package.order | 2 + .../PrimaryEnergy/EnergyConversion.mo | 92 ++++ .../IEC/IEC63406/PrimaryEnergy/package.mo | 17 + .../IEC/IEC63406/PrimaryEnergy/package.order | 2 + .../AuxiliaryProtections/FRTCurrentBounds.mo | 57 +++ .../FRTCurrentCalculation.mo | 99 ++++ .../AuxiliaryProtections/package.mo | 17 + .../AuxiliaryProtections/package.order | 2 + .../AuxiliaryProtections/FRTCurrentBounds.mo | 57 +++ .../FRTCurrentCalculation.mo | 99 ++++ .../AuxiliaryProtections/package.mo | 17 + .../AuxiliaryProtections/package.order | 2 + .../Protections/BaseProtections/FRTControl.mo | 259 ++++++++++ .../Protections/BaseProtections/Protection.mo | 450 ++++++++++++++++++ .../Protections/BaseProtections/package.mo | 17 + .../Protections/BaseProtections/package.order | 3 + .../IEC/IEC63406/Protections/FRTControl.mo | 256 ++++++++++ .../IEC/IEC63406/Protections/Protection.mo | 446 +++++++++++++++++ .../IEC/IEC63406/Protections/package.mo | 17 + .../IEC/IEC63406/Protections/package.order | 4 + .../Controls/IEC/IEC63406/package.mo | 17 + .../Controls/IEC/IEC63406/package.order | 9 + .../Sources/ConverterCurrentSourceIEC63406.mo | 369 ++++++++++++++ .../Sources/ConverterVoltageSourceIEC63406.mo | 368 ++++++++++++++ .../BaseConverters/CurrentSourceIEC63406.mo | 87 ++++ .../IEC/BaseConverters/UgridToUconverter.mo | 45 ++ .../BaseConverters/VoltageSourceIEC63406.mo | 118 +++++ .../Sources/IEC/BaseConverters/package.order | 3 + .../Dynawo/Electrical/Sources/package.order | 2 + .../Converters/IEC/CurrentSourceIEC63406.mo | 99 ++++ .../Converters/IEC/VoltageSourceIEC63406.mo | 99 ++++ .../Dynawo/Examples/Converters/IEC/package.mo | 17 + .../Examples/Converters/IEC/package.order | 2 + .../Dynawo/Examples/Converters/package.mo | 17 + .../Dynawo/Examples/Converters/package.order | 1 + .../Modelica/Dynawo/Examples/package.order | 1 + 69 files changed, 5904 insertions(+) create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/Min3.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/QuadriSwitch.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/StrongDelay.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/SwitchComplex.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/TripleSwitch.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/package.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/package.order create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/ControlAndProtection.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/AuxiliaryControls/IpLimitation.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/AuxiliaryControls/IqLimitation.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/AuxiliaryControls/package.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/AuxiliaryControls/package.order create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/CurrentLimitation.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/FFR.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/PControl.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/QControl.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/QLimitation.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/package.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/package.order create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/Control.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/package.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/package.order create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/FaultModules/package.order create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/InjectorCurrentSource.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/InjectorVoltageSource.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Measurement/GridMeasurement.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Measurement/PLL.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Measurement/package.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Measurement/package.order create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PlantCommunication.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/Auxiliary/SOCcontrol.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/Auxiliary/StorageSys.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/Auxiliary/package.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/Auxiliary/package.order create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/EnergyConversion.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/package.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/package.order create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/AuxiliaryProtections/FRTCurrentBounds.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/AuxiliaryProtections/FRTCurrentCalculation.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/AuxiliaryProtections/package.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/AuxiliaryProtections/package.order create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/AuxiliaryProtections/FRTCurrentBounds.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/AuxiliaryProtections/FRTCurrentCalculation.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/AuxiliaryProtections/package.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/AuxiliaryProtections/package.order create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/FRTControl.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/Protection.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/package.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/package.order create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/FRTControl.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/Protection.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/package.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/package.order create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/package.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/package.order create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/ConverterCurrentSourceIEC63406.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/ConverterVoltageSourceIEC63406.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/IEC/BaseConverters/CurrentSourceIEC63406.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/IEC/BaseConverters/UgridToUconverter.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/IEC/BaseConverters/VoltageSourceIEC63406.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/IEC/CurrentSourceIEC63406.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/IEC/VoltageSourceIEC63406.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/IEC/package.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/IEC/package.order create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/package.mo create mode 100644 dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/package.order diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/Min3.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/Min3.mo new file mode 100644 index 00000000000..61d61b83f21 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/Min3.mo @@ -0,0 +1,38 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.AuxiliaryBlocks; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +block Min3 "Pass through the smallest signal" + Modelica.Blocks.Interfaces.RealInput u1 annotation( + Placement(visible = true, transformation(origin = {-120, 46}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, -60}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput u3 annotation( + Placement(visible = true, transformation(origin = {-118, -54}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 60}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput u2 annotation( + Placement(visible = true, transformation(origin = {-120, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput y annotation( + Placement(visible = true, transformation(origin = {110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + +equation + y = min(u1, min(u2, u3)); + + annotation( + Icon(coordinateSystem(preserveAspectRatio = true, extent = {{-100, -100}, {100, 100}}), graphics = {Text(lineColor = {160, 160, 164}, extent = {{-90, 36}, {90, -36}}, textString = "min()"), Rectangle(extent = {{-100, 100}, {100, -100}})}), + Documentation(info = " +

+This block computes the output y as minimum of +the two Real inputs u1 and u2: +

+
    y = min ( u1 , u2 );
+
+")); +end Min3; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/QuadriSwitch.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/QuadriSwitch.mo new file mode 100644 index 00000000000..d0f6a815a34 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/QuadriSwitch.mo @@ -0,0 +1,38 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.AuxiliaryBlocks; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model QuadriSwitch + + //Input variables + Modelica.Blocks.Interfaces.RealInput e0 annotation( + Placement(visible = true, transformation(origin = {-120, 60}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 80}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput e1 annotation( + Placement(visible = true, transformation(origin = {-120, 20}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 26}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput e2 annotation( + Placement(visible = true, transformation(origin = {-120, -22}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, -28}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput e3 annotation( + Placement(visible = true, transformation(origin = {-120, -58}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, -80}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.IntegerInput flag annotation( + Placement(visible = true, transformation(origin = {0, -120}, extent = {{-20, -20}, {20, 20}}, rotation = 90), iconTransformation(origin = {0, -120}, extent = {{-20, -20}, {20, 20}}, rotation = 90))); + + //Output variables + Modelica.Blocks.Interfaces.RealOutput y annotation( + Placement(visible = true, transformation(origin = {110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + equation + y = if flag == 0 then e0 else if flag == 1 then e1 else if flag == 2 then e2 else e3; + + annotation( + Icon(graphics = {Rectangle(extent = {{-100, 100}, {100, -100}}), Text(extent = {{-100, 100}, {100, -100}}, textString = "4 Entries\nSwitch")})); +end QuadriSwitch; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/StrongDelay.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/StrongDelay.mo new file mode 100644 index 00000000000..08f8b82cdd3 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/StrongDelay.mo @@ -0,0 +1,29 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.AuxiliaryBlocks; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model StrongDelay + + parameter Types.Time T(start=1) "Time Constant"; + + Modelica.Blocks.Interfaces.RealInput u annotation( + Placement(visible = true, transformation(origin = {-120, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput y annotation( + Placement(visible = true, transformation(origin = {110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + +equation + der(y) = u - delay(u,T); + + annotation( + Icon(graphics = {Rectangle(extent = {{-100, 100}, {100, -100}}), Text(extent = {{-100, 100}, {100, -100}}, textString = "1 - e(-T.s) \n ___________\n\ns")})); +end StrongDelay; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/SwitchComplex.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/SwitchComplex.mo new file mode 100644 index 00000000000..8959a613c64 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/SwitchComplex.mo @@ -0,0 +1,44 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.AuxiliaryBlocks; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +block SwitchComplex "Switch between two Complex signals" + extends Modelica.Blocks.Icons.PartialBooleanBlock; + + //Input variables + Modelica.ComplexBlocks.Interfaces.ComplexInput u1 annotation( + Placement(visible = true, transformation(origin = {-120, 58}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 80}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.ComplexBlocks.Interfaces.ComplexInput u3 annotation( + Placement(visible = true, transformation(origin = {-122, -60}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, -80}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.BooleanInput u2 annotation( + Placement(visible = true, transformation(extent = {{-140, -20}, {-100, 20}}, rotation = 0), iconTransformation(extent = {{-140, -20}, {-100, 20}}, rotation = 0))); + + //Output variables + Modelica.ComplexBlocks.Interfaces.ComplexOutput y annotation( + Placement(visible = true, transformation(origin = {110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + +equation + y = if u2 then u1 else u3; + + annotation( + defaultComponentName = "switch1", + Documentation(info = " +

The Logical.Switch switches, depending on the +logical connector u2 (the middle connector) +between the two possible input signals +u1 (upper connector) and u3 (lower connector).

+

If u2 is true, the output signal y is set equal to +u1, else it is set equal to u3.

+"), + Icon(graphics = {Line(points = {{-38, 80}, {6, 2}}, color = {0, 0, 127}, thickness = 1), Line(points = {{-100, 0}, {-40, 0}}, color = {255, 0, 255}), Line(points = {{12, 0}, {100, 0}}, color = {0, 0, 127}), Line(points = {{-40, 12}, {-40, -12}}, color = {255, 0, 255}), Line(points = {{-100, 80}, {-38, 80}}, color = {0, 0, 127}), Ellipse(lineColor = {0, 0, 255}, pattern = LinePattern.None, fillPattern = FillPattern.Solid, extent = {{2, -8}, {18, 8}}), Line(points = {{-100, -80}, {-40, -80}, {-40, -80}}, color = {0, 0, 127})})); +end SwitchComplex; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/TripleSwitch.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/TripleSwitch.mo new file mode 100644 index 00000000000..45a643cb8fa --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/TripleSwitch.mo @@ -0,0 +1,36 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.AuxiliaryBlocks; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model TripleSwitch + + //Input variables + Modelica.Blocks.Interfaces.RealInput e0 annotation( + Placement(visible = true, transformation(origin = {-120, 20}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 60}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput e1 annotation( + Placement(visible = true, transformation(origin = {-120, -20}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput e2 annotation( + Placement(visible = true, transformation(origin = {-120, -60}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, -60}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.IntegerInput flag annotation( + Placement(visible = true, transformation(origin = {-120, 68}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {0, 120}, extent = {{-20, -20}, {20, 20}}, rotation = -90))); + + //Output variables + Modelica.Blocks.Interfaces.RealOutput y annotation( + Placement(visible = true, transformation(origin = {110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + +equation + y = if flag == 0 then e0 else if flag == 1 then e1 else e2; + + annotation( + Icon(graphics = {Rectangle(extent = {{-100, 100}, {100, -100}}), Text(extent = {{-100, 100}, {100, -100}}, textString = "3 entries\nswitch")})); +end TripleSwitch; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/package.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/package.mo new file mode 100644 index 00000000000..fa7c703f9b8 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/package.mo @@ -0,0 +1,18 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406; + + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +package AuxiliaryBlocks + extends Icons.Package; +end AuxiliaryBlocks; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/package.order b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/package.order new file mode 100644 index 00000000000..07cae29add5 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/AuxiliaryBlocks/package.order @@ -0,0 +1,5 @@ +StrongDelay +QuadriSwitch +TripleSwitch +SwitchComplex +Min3 diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/ControlAndProtection.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/ControlAndProtection.mo new file mode 100644 index 00000000000..f7285350b17 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/ControlAndProtection.mo @@ -0,0 +1,296 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model ControlAndProtection + + //General parameters + parameter Types.PerUnit IMaxPu "Maximum current" annotation( + Dialog(tab = "General")); + parameter Types.PerUnit IPMaxPu "Maximum active current" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit IQMaxPu "Maximum reactive current" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit IPMinPu "Minimum active current" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit IQMinPu "Minimum reactive current" annotation( + Dialog(tab = "FRT")); + + //Nominal parameter + parameter Types.ApparentPowerModule SNom "Nominal converter apparent power in MVA"; + + //PControl Parameters + parameter Real KIp "Integral gain in the active power PI controller" annotation( + Dialog(tab = "PControl")); + parameter Real KPp "Proportional gain in the active power PI controller" annotation( + Dialog(tab = "PControl")); + parameter Types.Time TpRef "Time constant in the active power filter" annotation( + Dialog(tab = "PControl")); + parameter Boolean PFlag "1 for closed-loop active power control, 0 for open-loop active power control" annotation( + Dialog(tab = "PControl")); + parameter Boolean PriorityFlag "0 for active current priority, 1 for reactive current priority"; + parameter Types.Time Trocof "Time constant for frequency differential operation" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit fThresholdPu "Threshold at which the frequency is considered" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit f0Pu "Frequency setpoint for FFR control" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit PffrMaxPu "Maximum output power utilized for FFR control" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit PffrMinPu "Maximum absorbing power utilized for FFR control" annotation( + Dialog(tab = "FFR")); + parameter Boolean FFRflag "1 to enable the fast frequency response, 0 to disable the fast frequency response" annotation( + Dialog(tab = "FFR")); + parameter Real InertialTable[:, :] = [Pi11, Pi12; Pi21, Pi22] "Pair of points for frequence dependant powers piecewise linear curve [u1,y1; u2,y2;...]" annotation( + Dialog(tab = "FFR")); + parameter Real FFRTable[:, :] = [Pf11, Pf12; Pf21, Pf22] "Pair of points for frequence dependant powers piecewise linear curve [u1,y1; u2,y2;...]" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit Pi11 annotation( + Dialog(tab = "FFR tables")); + parameter Types.PerUnit Pi12 annotation( + Dialog(tab = "FFR tables")); + parameter Types.PerUnit Pi21 annotation( + Dialog(tab = "FFR tables")); + parameter Types.PerUnit Pi22 annotation( + Dialog(tab = "FFR tables")); + parameter Types.PerUnit Pf11 annotation( + Dialog(tab = "FFR tables")); + parameter Types.PerUnit Pf12 annotation( + Dialog(tab = "FFR tables")); + parameter Types.PerUnit Pf21 annotation( + Dialog(tab = "FFR tables")); + parameter Types.PerUnit Pf22 annotation( + Dialog(tab = "FFR tables")); + + //QControl Parameters + parameter Types.PerUnit QMaxUd "Maximum reactive power defined by users" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit QMinUd "Minimum reactive power defined by users" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit UMaxPu "Maximum voltage defined by users" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit UMinPu "Minimum voltage defined by users" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KPqu "Proportional gain in the reactive power PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KIqu "Integral gain in the reactive power PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KPuq "Proportional gain in the outer voltage PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KIuq "Integral gain in the outer voltage PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KPui "Proportional gain in the inner voltage PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KIui "Integral gain in the inner voltage PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KPqi "Proportional gain in the inner reactive power PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KIqi "Integral gain in the inner reactive power PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KDroop "Q/U droop gain" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit DUdb1Pu "Voltage change dead band lower limit (typically negative) in pu (base UNom)" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit DUdb2Pu "Voltage change dead band upper limit (typically positive) in pu (base UNom)" annotation( + Dialog(tab = "QControl")); + parameter Real TanPhi "Power factor used in the power factor control" annotation( + Dialog(tab = "QControl")); + parameter Integer PFFlag annotation( + Dialog(tab = "QControl")); + parameter Integer LFlag annotation( + Dialog(tab = "QControl")); + parameter Boolean QLimFlag "0 to use the defined lookup tables, 1 to use the constant values" annotation( + Dialog(tab = "QControl")); + parameter Boolean UFlag annotation( + Dialog(tab = "QControl")); + parameter Types.Time Tiq "Time constant in reactive power order lag" annotation( + Dialog(tab = "QControl")); + + //LVRT and HVRT parameters + parameter Types.PerUnit uLVRTPu "LVRT threshold value" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit uHVRTPu "HVRT threshold value" annotation( + Dialog(tab = "FRT")); + parameter Boolean LVRTinPFlag = PFlag "Active current flag during LVRT, 0/1" annotation( + Dialog(tab = "FRT")); + parameter Boolean LVRTinQFlag "Reactive current flag during LVRT, 0/1" annotation( + Dialog(tab = "FRT")); + parameter Boolean HVRTinPFlag = PFlag "Active current flag during HVRT, 0/1" annotation( + Dialog(tab = "FRT")); + parameter Boolean HVRTinQFlag "Reactive current flag during HVRT, 0/1" annotation( + Dialog(tab = "FRT")); + parameter Real K1IpLV "Active current factor 1 during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2IpLV "Active current factor 2 during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K1IqLV "Reactive current factor 1 during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2IqLV "Reactive current factor 2 during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KpLVRT "Active power factor during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KqLVRT "Reactive power factor during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iPSetLVPu "Active current setting during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iQSetLVPu "Reactive current setting during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit pSetLVPu "Active power setting during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit qSetLVPu "Reactive power setting during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K1IpHV "Active current factor 1 during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2IpHV "Active current factor 2 during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K1IqHV "Reactive current factor 1 during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2IqHV "Reactive current factor 2 during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KpHVRT "Active power factor during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KqHVRT "Reactive power factor during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iPSetHVPu "Active current setting during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iQSetHVPu "Reactive current setting during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit pSetHVPu "Active power setting during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit qSetHVPu "Reactive power setting during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Boolean pqFRTFlag "Active/reactive control priority, 0/1" annotation( + Dialog(tab = "FRT")); + + //Input variables + Modelica.Blocks.Interfaces.RealInput qRefPu(start = -Q0Pu) "Voltage reference provided by the plant controller" annotation( + Placement(visible = true, transformation(origin = {-200, -60}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-200, -80}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput uRefPu(start = U0Pu) "Voltage reference provided by the plant controller" annotation( + Placement(visible = true, transformation(origin = {-200, 20}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-200, -120}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput pAvailInPu(start = PAvailIn0Pu) "Maximum input electrical power available to the active power control module" annotation( + Placement(visible = true, transformation(origin = {-60, 200}, extent = {{-20, -20}, {20, 20}}, rotation = -90), iconTransformation(origin = {0, 200}, extent = {{-20, -20}, {20, 20}}, rotation = -90))); + Modelica.Blocks.Interfaces.RealInput pAvailOutPu(start = PAvailOut0Pu) "Maximum output electrical power available to the active power control module" annotation( + Placement(visible = true, transformation(origin = {-20, 200}, extent = {{-20, -20}, {20, 20}}, rotation = -90), iconTransformation(origin = {90, 200}, extent = {{-20, -20}, {20, 20}}, rotation = -90))); + Modelica.Blocks.Interfaces.RealInput pMeasPu(start = -P0Pu) "Measured (and filtered) active power component (generator convention)" annotation( + Placement(visible = true, transformation(origin = {-200, 60}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-200, 80}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput qMeasPu(start = -Q0Pu) "Measured (and filtered) reactive power component" annotation( + Placement(visible = true, transformation(origin = {-202, -100}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-200, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput uMeasPu(start = U0Pu) "Measured (and filtered) voltage component" annotation( + Placement(visible = true, transformation(origin = {-200, -20}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-200, 40}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput fMeasPu(start = fInitPu) "Measured frequency outputted by the phase-locked loop" annotation( + Placement(visible = true, transformation(origin = {-200, 140}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-200, 120}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput thetaPLL(start = UPhase0) "Phase angle outputted by phase-locked loop" annotation( + Placement(visible = true, transformation(origin = {-200, -140}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-90, 200}, extent = {{20, -20}, {-20, 20}}, rotation = 90))); + Modelica.Blocks.Interfaces.RealInput pRefPu(start = -P0Pu) annotation( + Placement(visible = true, transformation(origin = {-200, 100}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(extent = {{-220, -60}, {-180, -20}}, rotation = 0))); + + //Output variables + Modelica.Blocks.Interfaces.RealOutput ipRefPu(start = -P0Pu * SystemBase.SnRef / (SNom * U0Pu)) "Active current reference" annotation( + Placement(visible = true, transformation(origin = {220, 40}, extent = {{-40, -40}, {40, 40}}, rotation = 0), iconTransformation(origin = {200, 40}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iqRefPu(start = Q0Pu * SystemBase.SnRef / (SNom * U0Pu)) "Reactive current reference" annotation( + Placement(visible = true, transformation(origin = {220, -40}, extent = {{-40, -40}, {40, 40}}, rotation = 0), iconTransformation(origin = {200, -40}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.BooleanOutput tripFlag(start = false) annotation( + Placement(visible = true, transformation(origin = {200, -100}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {190, -120}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput ippPu(start = -P0Pu * SystemBase.SnRef / (SNom * U0Pu)) annotation( + Placement(visible = true, transformation(origin = {200, 140}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {190, 140}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iqqPu(start = Q0Pu * SystemBase.SnRef / (SNom * U0Pu)) annotation( + Placement(visible = true, transformation(origin = {200, 100}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {190, 100}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.Protections.FRTControl fRTControl(HVRTinPFlag = HVRTinPFlag, HVRTinQFlag = HVRTinQFlag, IMaxPu = IMaxPu, IPMax0Pu = IPMax0Pu, IPMaxPu = IPMaxPu, IPMin0Pu = IPMin0Pu, IPMinPu = IPMinPu, IQMax0Pu = IQMax0Pu, IQMaxPu = IQMaxPu, IQMin0Pu = IQMin0Pu, IQMinPu = IQMinPu, K1IpHV = K1IpHV, K1IpLV = K1IpLV, K1IqHV = K1IqHV, K1IqLV = K1IqLV, K2IpHV = K2IpHV, K2IpLV = K2IpLV, K2IqHV = K2IqHV, K2IqLV = K2IqLV, KpHVRT = KpHVRT, KpLVRT = KpLVRT, KqHVRT = KqHVRT, KqLVRT = KqLVRT, LVRTinPFlag = LVRTinPFlag, LVRTinQFlag = LVRTinQFlag, P0Pu = P0Pu, Q0Pu = Q0Pu, SNom = SNom, U0Pu = U0Pu, iPSetHVPu = iPSetHVPu, iPSetLVPu = iPSetLVPu, iQSetHVPu = iQSetHVPu, iQSetLVPu = iQSetLVPu, pSetHVPu = pSetHVPu, pSetLVPu = pSetLVPu, pqFRTFlag = pqFRTFlag, qSetHVPu = qSetHVPu, qSetLVPu = qSetLVPu, uHVRTPu = uHVRTPu, uLVRTPu = uLVRTPu) annotation( + Placement(visible = true, transformation(origin = {120, 100}, extent = {{-40, -40}, {40, 40}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.Protections.Protection protection(U0Pu = U0Pu, fInitPu = fInitPu, UPhase0 = UPhase0) annotation( + Placement(visible = true, transformation(origin = {93.5294, -114.4}, extent = {{-32.4706, -55.2}, {32.4706, 55.2}}, rotation = 0))); + + //Initial parameters + parameter Types.PerUnit fInitPu "Initial frequency" annotation( + Dialog(tab = "Operating point")); + parameter Types.VoltageModulePu U0Pu "Initial voltage amplitude at grid terminal in pu (base UNom)" annotation( + Dialog(group = "Operating point")); + parameter Types.ActivePowerPu P0Pu "Initial active power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.ReactivePowerPu Q0Pu "Initial reactive power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit PAvailOut0Pu "Initial maximum output electrical power available to the active power control module" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit PAvailIn0Pu "Initial minimum output electrical power available to the active power control module" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit PFFR0Pu "Initial output power utilized for FFR control" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit QMax0Pu "Initial maximum reactive power" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit QMin0Pu "Initial minimum reactive power" annotation( + Dialog(tab = "Operating point")); + parameter Types.Angle UPhase0 "Initial Phase angle outputted by phase-locked loop" annotation( + Dialog(group = "Operating point")); + parameter Types.PerUnit IPMin0Pu annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IPMax0Pu annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IQMin0Pu "Initial minimum reactive current" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IQMax0Pu "Initial maximum reactive current" annotation( + Dialog(tab = "Operating point")); + Dynawo.Electrical.Controls.IEC.IEC63406.Controls.Control control(DUdb1Pu = DUdb1Pu, DUdb2Pu = DUdb2Pu, FFRflag = FFRflag, IMaxPu = IMaxPu, IPMax0Pu = IPMax0Pu, IPMin0Pu = IPMin0Pu, IQMax0Pu = IQMax0Pu, IQMin0Pu = IQMin0Pu, KDroop = KDroop, KIp = KIp, KIqi = KIqi, KIqu = KIqu, KIui = KIui, KIuq = KIuq, KPp = KPp, KPqi = KPqi, KPqu = KPqu, KPui = KPui, KPuq = KPuq, LFlag = LFlag, P0Pu = P0Pu, PAvailIn0Pu = PAvailIn0Pu, PAvailOut0Pu = PAvailOut0Pu, PFFR0Pu = PFFR0Pu, PFFlag = PFFlag, PFlag = PFlag, PffrMaxPu = PffrMaxPu, PffrMinPu = PffrMinPu, PriorityFlag = PriorityFlag, Q0Pu = Q0Pu, QLimFlag = QLimFlag, QMax0Pu = QMax0Pu, QMaxUd = QMaxUd, QMin0Pu = QMin0Pu, QMinUd = QMinUd, SNom = SNom, TanPhi = TanPhi, Tiq = Tiq, TpRef = TpRef, Trocof = Trocof, U0Pu = U0Pu, UFlag = UFlag, UMaxPu = UMaxPu, UMinPu = UMinPu, f0Pu = f0Pu, fInitPu = fInitPu, fThresholdPu = fThresholdPu, uHVRTPu = uHVRTPu, uLVRTPu = uLVRTPu) annotation( + Placement(visible = true, transformation(origin = {-40, 20}, extent = {{-40, -40}, {40, 40}}, rotation = 0))); + +equation + //TripFlag equations + ipRefPu = if tripFlag then 0 else ippPu; + iqRefPu = if tripFlag then 0 else iqqPu; + + connect(thetaPLL, protection.thetaPLL) annotation( + Line(points = {{-200, -140}, {55, -140}}, color = {0, 0, 127})); + connect(fMeasPu, protection.fMeasPu) annotation( + Line(points = {{-200, 140}, {-100, 140}, {-100, -115}, {55, -115}}, color = {0, 0, 127})); + connect(protection.tripFlag, tripFlag) annotation( + Line(points = {{132, -114}, {159, -114}, {159, -100}, {200, -100}}, color = {255, 0, 255})); + connect(uMeasPu, fRTControl.uMeasPu) annotation( + Line(points = {{-200, -20}, {-160, -20}, {-160, -80}, {40, -80}, {40, 100}, {76, 100}}, color = {0, 0, 127})); + connect(pMeasPu, fRTControl.pMeasPu) annotation( + Line(points = {{-200, 60}, {-140, 60}, {-140, 86}, {76, 86}}, color = {0, 0, 127})); + connect(qMeasPu, fRTControl.qMeasPu) annotation( + Line(points = {{-202, -100}, {-120, -100}, {-120, -50}, {60, -50}, {60, 70}, {76, 70}}, color = {0, 0, 127})); + connect(uMeasPu, protection.uMeasPu) annotation( + Line(points = {{-200, -20}, {-160, -20}, {-160, -80}, {40, -80}, {40, -88}, {54, -88}}, color = {0, 0, 127})); + connect(fRTControl.ippPu, ippPu) annotation( + Line(points = {{166, 126}, {170, 126}, {170, 140}, {200, 140}}, color = {0, 0, 127})); + connect(fRTControl.iqqPu, iqqPu) annotation( + Line(points = {{166, 116}, {170, 116}, {170, 100}, {200, 100}}, color = {0, 0, 127})); + connect(control.iQcmdPu, fRTControl.iQcmdPu) annotation( + Line(points = {{6, 28}, {30, 28}, {30, 115}, {75, 115}}, color = {0, 0, 127})); + connect(control.iPcmdPu, fRTControl.iPcmdPu) annotation( + Line(points = {{6, 44}, {20, 44}, {20, 130}, {75, 130}}, color = {0, 0, 127})); + connect(pAvailInPu, control.pAvailInPu) annotation( + Line(points = {{-60, 200}, {-60, 80}, {-52, 80}, {-52, 64}}, color = {0, 0, 127})); + connect(qMeasPu, control.qMeasPu) annotation( + Line(points = {{-202, -100}, {-120, -100}, {-120, -16}, {-84, -16}}, color = {0, 0, 127})); + connect(qRefPu, control.qRefPu) annotation( + Line(points = {{-200, -60}, {-140, -60}, {-140, -4}, {-84, -4}}, color = {0, 0, 127})); + connect(uMeasPu, control.uMeasPu) annotation( + Line(points = {{-200, -20}, {-160, -20}, {-160, 8}, {-84, 8}}, color = {0, 0, 127})); + connect(uRefPu, control.uRefPu) annotation( + Line(points = {{-200, 20}, {-84, 20}}, color = {0, 0, 127})); + connect(pMeasPu, control.pMeasPu) annotation( + Line(points = {{-200, 60}, {-140, 60}, {-140, 32}, {-84, 32}}, color = {0, 0, 127})); + connect(pRefPu, control.pRefPu) annotation( + Line(points = {{-200, 100}, {-120, 100}, {-120, 44}, {-84, 44}}, color = {0, 0, 127})); + connect(fMeasPu, control.fMeasPu) annotation( + Line(points = {{-200, 140}, {-100, 140}, {-100, 56}, {-84, 56}}, color = {0, 0, 127})); + connect(pAvailOutPu, control.pAvailOutPu) annotation( + Line(points = {{-20, 200}, {-20, 80}, {-28, 80}, {-28, 64}}, color = {0, 0, 127})); + + annotation( + Icon(graphics = {Rectangle(extent = {{-180, 180}, {180, -180}}), Text(extent = {{-180, 180}, {180, -180}}, textString = "Control +& +Protection")}, coordinateSystem(extent = {{-180, -180}, {180, 180}})), + Diagram(coordinateSystem(extent = {{-180, -180}, {180, 180}}))); +end ControlAndProtection; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/AuxiliaryControls/IpLimitation.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/AuxiliaryControls/IpLimitation.mo new file mode 100644 index 00000000000..fa419314009 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/AuxiliaryControls/IpLimitation.mo @@ -0,0 +1,50 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.Controls.BaseControls.AuxiliaryControls; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model IpLimitation + + //Nominal parameter + parameter Types.ApparentPowerModule SNom "Nominal converter apparent power in MVA"; + + //General parameters + parameter Types.PerUnit IMaxPu "Maximum current" annotation( + Dialog(tab = "General")); + + //Input variables + Modelica.Blocks.Interfaces.RealInput iQcmdPu(start=-Q0Pu*SystemBase.SnRef/(SNom*U0Pu)) "Reactive current command" annotation( + Placement(visible = true, transformation(origin = {-120, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + + //Output variables + Modelica.Blocks.Interfaces.RealOutput iPMaxPu(start = IPMax0Pu) annotation( + Placement(visible = true, transformation(origin = {120, 50}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {110, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iPMinPu(start = IPMin0Pu) annotation( + Placement(visible = true, transformation(origin = {120, -50}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {110, -50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + //Initial parameters + parameter Types.ReactivePowerPu Q0Pu "Initial reactive power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.VoltageModulePu U0Pu "Initial voltage amplitude at grid terminal in pu (base UNom)" annotation( + Dialog(group="Operating point")); + parameter Types.PerUnit IPMin0Pu annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IPMax0Pu annotation( + Dialog(tab = "Operating point")); + +equation + iPMaxPu = sqrt(max(0.001, IMaxPu ^ 2 - iQcmdPu ^ 2)); + iPMinPu = -iPMaxPu; + +annotation( + Icon(graphics = {Rectangle(extent = {{-100, 100}, {100, -100}}), Text(origin = {-2, 2}, extent = {{-96, 96}, {96, -96}}, textString = "Limit\nIp")})); +end IpLimitation; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/AuxiliaryControls/IqLimitation.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/AuxiliaryControls/IqLimitation.mo new file mode 100644 index 00000000000..0d48b6a9bbf --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/AuxiliaryControls/IqLimitation.mo @@ -0,0 +1,49 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.Controls.BaseControls.AuxiliaryControls; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model IqLimitation + + //Nominal parameter + parameter Types.ApparentPowerModule SNom "Nominal converter apparent power in MVA"; + + //General parameters + parameter Types.PerUnit IMaxPu "Maximum current" annotation( + Dialog(tab = "General")); + + //Input variables + Modelica.Blocks.Interfaces.RealInput iPcmdPu(start=-P0Pu*SystemBase.SnRef/(SNom*U0Pu)) "Reactive current command" annotation( + Placement(visible = true, transformation(origin = {-120, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + + //Output variables + Modelica.Blocks.Interfaces.RealOutput iQMaxPu(start = IQMax0Pu) annotation( + Placement(visible = true, transformation(origin = {120, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + //Initial parameters + parameter Types.ReactivePowerPu P0Pu "Initial reactive power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.VoltageModulePu U0Pu "Initial voltage amplitude at grid terminal in pu (base UNom)" annotation( + Dialog(group="Operating point")); + parameter Types.PerUnit IQMax0Pu "Initial maximum reactive current" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IQMin0Pu "Initial minimum reactive current" annotation( + Dialog(tab = "Operating point")); + + +equation + iQMaxPu = sqrt(max(0.001,IMaxPu ^ 2 - iPcmdPu ^ 2)); + +annotation( + Icon(graphics = {Rectangle(extent = {{-100, 100}, {100, -100}}), Text(origin = {-2, 2}, extent = {{-96, 96}, {96, -96}}, textString = "Limit +Iq")})); +end IqLimitation; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/AuxiliaryControls/package.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/AuxiliaryControls/package.mo new file mode 100644 index 00000000000..ca021bee222 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/AuxiliaryControls/package.mo @@ -0,0 +1,17 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.Controls.BaseControls; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +package AuxiliaryControls + extends Icons.Package; +end AuxiliaryControls; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/AuxiliaryControls/package.order b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/AuxiliaryControls/package.order new file mode 100644 index 00000000000..d784c0e0679 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/AuxiliaryControls/package.order @@ -0,0 +1,2 @@ +IqLimitation +IpLimitation diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/CurrentLimitation.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/CurrentLimitation.mo new file mode 100644 index 00000000000..da36e741241 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/CurrentLimitation.mo @@ -0,0 +1,217 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.Controls.BaseControls; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model CurrentLimitation + extends Dynawo.Electrical.Controls.IEC.IEC61400.Parameters.QLimitParameters; + + //Nominal parameter + parameter Types.ApparentPowerModule SNom "Nominal converter apparent power in MVA"; + + //Parameters + parameter Types.PerUnit IMaxPu "Maximum current" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit QMaxUd "Maximum reactive power defined by users" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit QMinUd "Minimum reactive power defined by users" annotation( + Dialog(tab = "QControl")); + parameter Boolean QLimFlag "0 to use the defined lookup tables, 1 to use the constant values" annotation( + Dialog(tab = "QControl")); + parameter Boolean PriorityFlag "0 for active current priority, 1 for reactive current priority" annotation( + Dialog(tab = "QControl")); + + //Input variables + Modelica.Blocks.Interfaces.RealInput iPcmdPu(start = -P0Pu * SystemBase.SnRef / (SNom * U0Pu)) "Active current command" annotation( + Placement(visible = true, transformation(origin = {-140, 100}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-140, 100}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput uMeasPu(start = U0Pu) annotation( + Placement(visible = true, transformation(origin = {-140, 20}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-134, 0}, extent = {{-14, -14}, {14, 14}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput qMaxPu(start = QMax0Pu) annotation( + Placement(visible = true, transformation(origin = {-140, 40}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-134, 40}, extent = {{-14, -14}, {14, 14}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput qMinPu(start = QMin0Pu) annotation( + Placement(visible = true, transformation(origin = {-140, -20}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-134, -40}, extent = {{-14, -14}, {14, 14}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput iQcmdPu(start = Q0Pu * SystemBase.SnRef / (SNom * U0Pu)) annotation( + Placement(visible = true, transformation(origin = {-140, -80}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-140, -100}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + + //Output variables + Modelica.Blocks.Interfaces.RealOutput iQMaxPu(start = IQMax0Pu) "Maximum reactive current" annotation( + Placement(visible = true, transformation(origin = {130, 80}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {130, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iQMinPu(start = IQMin0Pu) "Minimum reactive current" annotation( + Placement(visible = true, transformation(origin = {130, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {130, -80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iPMaxPu(start = IPMax0Pu) annotation( + Placement(visible = true, transformation(origin = {130, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {130, 80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + //Initial parameters + parameter Types.VoltageModulePu U0Pu "Initial voltage amplitude at grid terminal in pu (base UNom)" annotation( + Dialog(group = "Operating point")); + parameter Types.ActivePowerPu P0Pu "Initial active power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.ReactivePowerPu Q0Pu "Initial reactive power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IQMax0Pu "Initial maximum reactive current" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IQMin0Pu "Initial minimum reactive current" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IPMin0Pu annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IPMax0Pu annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit QMax0Pu "Initial maximum reactive power" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit QMin0Pu "Initial minimum reactive power" annotation( + Dialog(tab = "Operating point")); + + Dynawo.Electrical.Controls.IEC.IEC63406.Controls.BaseControls.AuxiliaryControls.IqLimitation iqLimitation(IMaxPu = IMaxPu, IQMax0Pu = IQMax0Pu, IQMin0Pu = IQMin0Pu, P0Pu = P0Pu, SNom = SNom, U0Pu = U0Pu) annotation( + Placement(visible = true, transformation(origin = {-60, 100}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.AuxiliaryBlocks.Min3 min3 annotation( + Placement(visible = true, transformation(origin = {-10, 90}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.BooleanInput FFlag annotation( + Placement(visible = true, transformation(origin = {10, 140}, extent = {{-20, -20}, {20, 20}}, rotation = -90), iconTransformation(origin = {0, 140}, extent = {{-20, -20}, {20, 20}}, rotation = -90))); + Modelica.Blocks.Sources.RealExpression realExpression2(y = IMaxPu) annotation( + Placement(visible = true, transformation(origin = {-60, -100}, extent = {{-10, -12}, {10, 12}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iPMinPu(start = IPMin0Pu) annotation( + Placement(visible = true, transformation(origin = {130, -80}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {130, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Switch switch12 annotation( + Placement(visible = true, transformation(origin = {90, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Math.Gain gain(k = -1) annotation( + Placement(visible = true, transformation(origin = {58, -100}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Switch switch13 annotation( + Placement(visible = true, transformation(origin = {90, -80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.Controls.BaseControls.AuxiliaryControls.IpLimitation ipLimitation(IMaxPu = IMaxPu, IPMax0Pu = IPMax0Pu, IPMin0Pu = IPMin0Pu, Q0Pu = Q0Pu, SNom = SNom, U0Pu = U0Pu) annotation( + Placement(visible = true, transformation(origin = {-60, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression(y = IMaxPu) annotation( + Placement(visible = true, transformation(origin = {-60, 116}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Switch switch11 annotation( + Placement(visible = true, transformation(origin = {90, 80}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Math.Division division1 annotation( + Placement(visible = true, transformation(origin = {-60, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.Limiter limiter(limitsAtInit = true, uMax = Modelica.Constants.inf, uMin = 0.01) annotation( + Placement(visible = true, transformation(origin = {-100, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Math.Min min annotation( + Placement(visible = true, transformation(origin = {-10, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression4(y = IMaxPu) annotation( + Placement(visible = true, transformation(origin = {-60, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Switch freeze annotation( + Placement(visible = true, transformation(origin = {40, 100}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.BooleanExpression booleanExpression7(y = PriorityFlag) annotation( + Placement(visible = true, transformation(origin = {65, 130}, extent = {{-11, -10}, {11, 10}}, rotation = -90))); + Modelica.Blocks.Sources.RealExpression realExpression5 annotation( + Placement(visible = true, transformation(origin = {-10, 108}, extent = {{-10, -8}, {10, 8}}, rotation = 0))); + Modelica.Blocks.Logical.Switch freeze1 annotation( + Placement(visible = true, transformation(origin = {40, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression6 annotation( + Placement(visible = true, transformation(origin = {-10, 68}, extent = {{-10, -8}, {10, 8}}, rotation = 0))); + Modelica.Blocks.Math.Division division2 annotation( + Placement(visible = true, transformation(origin = {-60, 0}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Logical.Switch freeze4 annotation( + Placement(visible = true, transformation(origin = {40, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression9 annotation( + Placement(visible = true, transformation(origin = {-10, 8}, extent = {{-10, -8}, {10, 8}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression10(y = -IMaxPu) annotation( + Placement(visible = true, transformation(origin = {-60, -27}, extent = {{-10, -11}, {10, 11}}, rotation = 0))); + Modelica.Blocks.Math.Max max annotation( + Placement(visible = true, transformation(origin = {-10, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Switch switch16 annotation( + Placement(visible = true, transformation(origin = {90, 20}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Math.Gain gain3(k = -1) annotation( + Placement(visible = true, transformation(origin = {60, 40}, extent = {{-6, -6}, {6, 6}}, rotation = -90))); + +equation + connect(switch11.y, iQMaxPu) annotation( + Line(points = {{101, 80}, {130, 80}}, color = {0, 0, 127})); + connect(switch16.y, iQMinPu) annotation( + Line(points = {{101, 20}, {130, 20}}, color = {0, 0, 127})); + connect(iPcmdPu, iqLimitation.iPcmdPu) annotation( + Line(points = {{-140, 100}, {-72, 100}}, color = {0, 0, 127})); + connect(iqLimitation.iQMaxPu, min3.u2) annotation( + Line(points = {{-49, 100}, {-41, 100}, {-41, 90}, {-23, 90}}, color = {0, 0, 127})); + connect(realExpression.y, min3.u3) annotation( + Line(points = {{-49, 116}, {-31, 116}, {-31, 96}, {-23, 96}}, color = {0, 0, 127})); + connect(qMaxPu, division1.u1) annotation( + Line(points = {{-140, 40}, {-80, 40}, {-80, 46}, {-72, 46}}, color = {0, 0, 127})); + connect(uMeasPu, limiter.u) annotation( + Line(points = {{-140, 20}, {-112, 20}}, color = {0, 0, 127})); + connect(limiter.y, division1.u2) annotation( + Line(points = {{-89, 20}, {-80, 20}, {-80, 34}, {-72, 34}}, color = {0, 0, 127})); + connect(qMinPu, division2.u1) annotation( + Line(points = {{-140, -20}, {-80, -20}, {-80, -6}, {-72, -6}}, color = {0, 0, 127})); + connect(limiter.y, division2.u2) annotation( + Line(points = {{-89, 20}, {-81, 20}, {-81, 6}, {-73, 6}}, color = {0, 0, 127})); + connect(division1.y, min.u2) annotation( + Line(points = {{-49, 40}, {-41, 40}, {-41, 34}, {-23, 34}}, color = {0, 0, 127})); + connect(realExpression4.y, min.u1) annotation( + Line(points = {{-49, 60}, {-41, 60}, {-41, 46}, {-23, 46}}, color = {0, 0, 127})); + connect(division2.y, max.u1) annotation( + Line(points = {{-49, 0}, {-41, 0}, {-41, -14}, {-23, -14}}, color = {0, 0, 127})); + connect(realExpression10.y, max.u2) annotation( + Line(points = {{-49, -27}, {-23, -27}}, color = {0, 0, 127})); + connect(max.y, freeze4.u3) annotation( + Line(points = {{1, -20}, {19, -20}, {19, -8}, {27, -8}}, color = {0, 0, 127})); + connect(realExpression9.y, freeze4.u1) annotation( + Line(points = {{1, 8}, {28, 8}}, color = {0, 0, 127})); + connect(realExpression5.y, freeze.u1) annotation( + Line(points = {{1, 108}, {27, 108}}, color = {0, 0, 127})); + connect(min3.y, freeze.u3) annotation( + Line(points = {{1, 90}, {19, 90}, {19, 92}, {27, 92}}, color = {0, 0, 127})); + connect(realExpression6.y, freeze1.u1) annotation( + Line(points = {{1, 68}, {27, 68}}, color = {0, 0, 127})); + connect(min.y, freeze1.u3) annotation( + Line(points = {{1, 40}, {21, 40}, {21, 52}, {29, 52}}, color = {0, 0, 127})); + connect(freeze1.y, switch11.u1) annotation( + Line(points = {{51, 60}, {69, 60}, {69, 72}, {77, 72}}, color = {0, 0, 127})); + connect(freeze.y, switch11.u3) annotation( + Line(points = {{51, 100}, {69, 100}, {69, 88}, {77, 88}}, color = {0, 0, 127})); + connect(freeze4.y, switch16.u1) annotation( + Line(points = {{51, 0}, {59, 0}, {59, 12}, {77, 12}}, color = {0, 0, 127})); + connect(freeze.y, gain3.u) annotation( + Line(points = {{51, 100}, {60, 100}, {60, 47}}, color = {0, 0, 127})); + connect(FFlag, freeze.u2) annotation( + Line(points = {{10, 140}, {10, 100}, {28, 100}}, color = {255, 0, 255})); + connect(FFlag, freeze1.u2) annotation( + Line(points = {{10, 140}, {10, 60}, {28, 60}}, color = {255, 0, 255})); + connect(FFlag, freeze4.u2) annotation( + Line(points = {{10, 140}, {10, 0}, {28, 0}}, color = {255, 0, 255})); + connect(booleanExpression7.y, switch11.u2) annotation( + Line(points = {{65, 118}, {65, 79.7}, {78, 79.7}}, color = {255, 0, 255})); + connect(booleanExpression7.y, switch16.u2) annotation( + Line(points = {{65, 118}, {65, 19.7}, {78, 19.7}}, color = {255, 0, 255})); + connect(division1.y, min3.u1) annotation( + Line(points = {{-49, 40}, {-31, 40}, {-31, 84}, {-23, 84}}, color = {0, 0, 127})); + connect(switch13.y, iPMinPu) annotation( + Line(points = {{101, -80}, {130, -80}}, color = {0, 0, 127})); + connect(switch12.y, iPMaxPu) annotation( + Line(points = {{101, -40}, {130, -40}}, color = {0, 0, 127})); + connect(gain3.y, switch16.u3) annotation( + Line(points = {{60, 33}, {60, 27.4}, {78, 27.4}}, color = {0, 0, 127})); + connect(iQcmdPu, ipLimitation.iQcmdPu) annotation( + Line(points = {{-140, -80}, {-100, -80}, {-100, -60}, {-72, -60}}, color = {0, 0, 127})); + connect(realExpression2.y, gain.u) annotation( + Line(points = {{-48, -100}, {46, -100}}, color = {0, 0, 127})); + connect(ipLimitation.iPMaxPu, switch12.u1) annotation( + Line(points = {{-48, -54}, {20, -54}, {20, -32}, {78, -32}}, color = {0, 0, 127})); + connect(ipLimitation.iPMinPu, switch13.u1) annotation( + Line(points = {{-48, -64}, {20, -64}, {20, -72}, {78, -72}}, color = {0, 0, 127})); + connect(gain.y, switch13.u3) annotation( + Line(points = {{69, -100}, {70, -100}, {70, -88}, {78, -88}}, color = {0, 0, 127})); + connect(booleanExpression7.y, switch12.u2) annotation( + Line(points = {{65, 118}, {65, -40}, {78, -40}}, color = {255, 0, 255})); + connect(booleanExpression7.y, switch13.u2) annotation( + Line(points = {{65, 118}, {65, -80}, {78, -80}}, color = {255, 0, 255})); + connect(realExpression2.y, switch12.u3) annotation( + Line(points = {{-48, -100}, {40, -100}, {40, -48}, {78, -48}}, color = {0, 0, 127})); +protected + + annotation( + Icon(graphics = {Rectangle(extent = {{-120, 120}, {120, -120}}), Text(extent = {{-120, 120}, {120, -120}}, textString = "Current +Limitation")}, coordinateSystem(extent = {{-120, -120}, {120, 120}})), + Diagram(coordinateSystem(extent = {{-120, -120}, {120, 120}}))); +end CurrentLimitation; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/FFR.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/FFR.mo new file mode 100644 index 00000000000..304a1758672 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/FFR.mo @@ -0,0 +1,131 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.Controls.BaseControls; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model FFR + + //Parameters + parameter Types.Time Trocof "Time constant for frequency differential operation" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit fThresholdPu "Threshold at which the frequency is considered" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit f0Pu "Frequency setpoint for FFR control" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit PffrMaxPu "Maximum output power utilized for FFR control" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit PffrMinPu "Maximum absorbing power utilized for FFR control" annotation( + Dialog(tab = "FFR")); + parameter Boolean FFRflag "1 to enable the fast frequency response, 0 to disable the fast frequency response" annotation( + Dialog(tab = "FFR")); + parameter Real InertialTable[:, :] = [Pi11, Pi12; Pi21, Pi22] "Pair of points for frequence dependant powers piecewise linear curve [u1,y1; u2,y2;...]" annotation( + Dialog(tab = "FFR")); + parameter Real FFRTable[:, :] = [Pf11, Pf12; Pf21, Pf22] "Pair of points for frequence dependant powers piecewise linear curve [u1,y1; u2,y2;...]" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit Pi11=-1 annotation( + Dialog(tab = "FFR table")); + parameter Types.PerUnit Pi12=-1 annotation( + Dialog(tab = "FFR table")); + parameter Types.PerUnit Pi21=1 annotation( + Dialog(tab = "FFR table")); + parameter Types.PerUnit Pi22=1 annotation( + Dialog(tab = "FFR table")); + parameter Types.PerUnit Pf11=-1 annotation( + Dialog(tab = "FFR table")); + parameter Types.PerUnit Pf12=-1 annotation( + Dialog(tab = "FFR table")); + parameter Types.PerUnit Pf21=1 annotation( + Dialog(tab = "FFR table")); + parameter Types.PerUnit Pf22=1 annotation( + Dialog(tab = "FFR table")); + + //Input variables + Modelica.Blocks.Interfaces.RealInput fMeasPu(start = fInitPu) annotation( + Placement(visible = true, transformation(origin = {-140, 40}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + + //Output variables + Modelica.Blocks.Interfaces.RealOutput pFFRPu(start = PFFR0Pu) annotation( + Placement(visible = true, transformation(origin = {130, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + Modelica.Blocks.Nonlinear.DeadZone deadZone(deadZoneAtInit = true, uMax = fThresholdPu, uMin = -fThresholdPu) annotation( + Placement(visible = true, transformation(origin = {-66, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.Limiter limiter(limitsAtInit = true, uMax = PffrMaxPu, uMin = PffrMinPu) annotation( + Placement(visible = true, transformation(origin = {-6, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Math.Add add(k1 = -1) annotation( + Placement(visible = true, transformation(origin = {30, 34}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Switch switch1 annotation( + Placement(visible = true, transformation(origin = {102, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression annotation( + Placement(visible = true, transformation(origin = {62, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.BooleanExpression booleanEntry(y = FFRflag) annotation( + Placement(visible = true, transformation(origin = {62, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.Limiter limiter1(limitsAtInit = true, uMax = PffrMaxPu, uMin = PffrMinPu) annotation( + Placement(visible = true, transformation(origin = {62, 34}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Math.Add add1(k1 = -1) annotation( + Placement(visible = true, transformation(origin = {-98, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression1(y = f0Pu) annotation( + Placement(visible = true, transformation(origin = {-130, -26}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.DeadZone deadZone1(deadZoneAtInit = true, uMax = fThresholdPu, uMin = -fThresholdPu) annotation( + Placement(visible = true, transformation(origin = {-70, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.Limiter limiter2(limitsAtInit = true, uMax = PffrMaxPu, uMin = PffrMinPu) annotation( + Placement(visible = true, transformation(origin = {-14, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Tables.CombiTable1Ds combiTable1Ds(table = InertialTable) annotation( + Placement(visible = true, transformation(origin = {-36, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Tables.CombiTable1Ds combiTable1Ds1(table = FFRTable) annotation( + Placement(visible = true, transformation(origin = {-42, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Continuous.Derivative derivative(T = Trocof, k = Trocof, y_start = 0) annotation( + Placement(visible = true, transformation(origin = {-96, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + //Initial parameters + parameter Types.PerUnit PFFR0Pu "Initial output power utilized for FFR control" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit fInitPu "Initial frequency" annotation( + Dialog(tab = "Operating point")); + +equation + connect(booleanEntry.y, switch1.u2) annotation( + Line(points = {{73, 0}, {90, 0}}, color = {255, 0, 255})); + connect(limiter.y, add.u1) annotation( + Line(points = {{5, 40}, {18, 40}}, color = {0, 0, 127})); + connect(add.y, limiter1.u) annotation( + Line(points = {{41, 34}, {50, 34}}, color = {0, 0, 127})); + connect(switch1.y, pFFRPu) annotation( + Line(points = {{113, 0}, {130, 0}}, color = {0, 0, 127})); + connect(fMeasPu, add1.u1) annotation( + Line(points = {{-140, 40}, {-114, 40}, {-114, -14}, {-110, -14}}, color = {0, 0, 127})); + connect(realExpression1.y, add1.u2) annotation( + Line(points = {{-119, -26}, {-110, -26}}, color = {0, 0, 127})); + connect(add1.y, deadZone1.u) annotation( + Line(points = {{-87, -20}, {-82, -20}}, color = {0, 0, 127})); + connect(deadZone.y, combiTable1Ds.u) annotation( + Line(points = {{-55, 40}, {-48, 40}}, color = {0, 0, 127})); + connect(combiTable1Ds.y[1], limiter.u) annotation( + Line(points = {{-25, 40}, {-18, 40}}, color = {0, 0, 127})); + connect(deadZone1.y, combiTable1Ds1.u) annotation( + Line(points = {{-59, -20}, {-54, -20}}, color = {0, 0, 127})); + connect(combiTable1Ds1.y[1], limiter2.u) annotation( + Line(points = {{-31, -20}, {-26, -20}}, color = {0, 0, 127})); + connect(fMeasPu, derivative.u) annotation( + Line(points = {{-140, 40}, {-108, 40}}, color = {0, 0, 127})); + connect(derivative.y, deadZone.u) annotation( + Line(points = {{-85, 40}, {-78, 40}}, color = {0, 0, 127})); + connect(realExpression.y, switch1.u3) annotation( + Line(points = {{74, -20}, {80, -20}, {80, -8}, {90, -8}}, color = {0, 0, 127})); + connect(limiter1.y, switch1.u1) annotation( + Line(points = {{74, 34}, {80, 34}, {80, 8}, {90, 8}}, color = {0, 0, 127})); + connect(limiter2.y, add.u2) annotation( + Line(points = {{-2, -20}, {12, -20}, {12, 28}, {18, 28}}, color = {0, 0, 127})); + + annotation( + Icon(graphics = {Text(extent = {{-92, 52}, {92, -52}}, textString = "FFR"), Rectangle(extent = {{-100, 100}, {100, -100}})}, coordinateSystem(extent = {{-120, -100}, {120, 100}})), + Diagram(coordinateSystem(extent = {{-120, -100}, {120, 100}}))); +end FFR; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/PControl.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/PControl.mo new file mode 100644 index 00000000000..01068cafe78 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/PControl.mo @@ -0,0 +1,167 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.Controls.BaseControls; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model PControl + + //Nominal parameter + parameter Types.ApparentPowerModule SNom "Nominal converter apparent power in MVA"; + + //Parameters + parameter Real KIp "Integral gain in the active power PI controller" annotation( + Dialog(tab = "PControl")); + parameter Real KPp "Proportional gain in the active power PI controller" annotation( + Dialog(tab = "PControl")); + parameter Types.Time TpRef "Time constant in the active power filter" annotation( + Dialog(tab = "PControl")); + parameter Boolean PFlag "1 for closed-loop active power control, 0 for open-loop active power control" annotation( + Dialog(tab = "PControl")); + + //Input variables + Modelica.Blocks.Interfaces.RealInput pFFRPu(start=PFFR0Pu) "Measured frequency outputted by the phase-locked loop" annotation( + Placement(visible = true, transformation(origin = {-90, 120}, extent = {{-20, -20}, {20, 20}}, rotation = -90), iconTransformation(origin = {-160, 110}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Modelica.Blocks.Interfaces.RealInput pMeasPu(start=-P0Pu) "Measured (and filtered) active power component (generator convention)" annotation( + Placement(visible = true, transformation(origin = {-40, -40}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-190, -50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput uMeasPu(start=U0Pu) "Measured (and filtered) voltage component" annotation( + Placement(visible = true, transformation(origin = {10, 120}, extent = {{-20, -20}, {20, 20}}, rotation = -90), iconTransformation(origin = {0, 110}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Modelica.Blocks.Interfaces.RealInput pAvailOutPu(start=PAvailOut0Pu) "Maximum output electrical power available to the active power control module" annotation( + Placement(visible = true, transformation(origin = {-40, 110}, extent = {{-10, -10}, {10, 10}}, rotation = -90), iconTransformation(origin = {-60, 110}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Modelica.Blocks.Interfaces.RealInput pAvailInPu(start=PAvailIn0Pu) "Minimum output electrical power available to the active power control module" annotation( + Placement(visible = true, transformation(origin = {-56, 110}, extent = {{-10, -10}, {10, 10}}, rotation = -90), iconTransformation(origin = {-90, 110}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Modelica.Blocks.Interfaces.RealInput pRefPu(start=-P0Pu) "Active power reference provided by the plant controller" annotation( + Placement(visible = true, transformation(origin = {-200, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-190, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.BooleanInput FFlag(start=false) annotation( + Placement(visible = true, transformation(origin = {-80, -120}, extent = {{-20, -20}, {20, 20}}, rotation = 90), iconTransformation(origin = {-120, -110}, extent = {{-10, -10}, {10, 10}}, rotation = 90))); + Modelica.Blocks.Interfaces.RealInput iPMinPu(start = IPMin0Pu) annotation( + Placement(visible = true, transformation(origin = {126, 110}, extent = {{-10, -10}, {10, 10}}, rotation = -90), iconTransformation(origin = {140, -110}, extent = {{10, -10}, {-10, 10}}, rotation = -90))); + Modelica.Blocks.Interfaces.RealInput iPMaxPu(start = IPMax0Pu) annotation( + Placement(visible = true, transformation(origin = {140, 110}, extent = {{-10, -10}, {10, 10}}, rotation = -90), iconTransformation(origin = {170, -110}, extent = {{10, -10}, {-10, 10}}, rotation = -90))); + + //Output variables + Modelica.Blocks.Interfaces.RealOutput iPcmdPu(start = -P0Pu * SystemBase.SnRef / (SNom * U0Pu)) "Active current command" annotation( + Placement(visible = true, transformation(origin = {200, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {190, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + //Inner variables + Real pRefFreezePu; + Real iPcmdFreezePu; + + Modelica.Blocks.Continuous.FirstOrder firstOrder(T = TpRef, y_start = -P0Pu) annotation( + Placement(visible = true, transformation(origin = {-150, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Math.Add add annotation( + Placement(visible = true, transformation(origin = {-70, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.VariableLimiter variableLimiter annotation( + Placement(visible = true, transformation(origin = {-20, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Math.Division division annotation( + Placement(visible = true, transformation(origin = {30, 0}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.Limiter limiter(limitsAtInit = true, uMax = Modelica.Constants.inf, uMin = 0.01) annotation( + Placement(visible = true, transformation(origin = {10, 70}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Modelica.Blocks.Math.Add add1(k2 = -1) annotation( + Placement(visible = true, transformation(origin = {16, -32}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Switch switch1 annotation( + Placement(visible = true, transformation(origin = {110, 0}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Sources.BooleanExpression booleanExpression(y = PFlag) annotation( + Placement(visible = true, transformation(origin = {80, 70}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Modelica.Blocks.Nonlinear.VariableLimiter variableLimiter1 annotation( + Placement(visible = true, transformation(origin = {162, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Switch switch11 annotation( + Placement(visible = true, transformation(origin = {82, -40}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression(y = iPcmdFreezePu) annotation( + Placement(visible = true, transformation(origin = {41, -80}, extent = {{-19, -10}, {19, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Switch switch annotation( + Placement(visible = true, transformation(origin = {-110, 0}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression1(y = pRefFreezePu) annotation( + Placement(visible = true, transformation(origin = {-127, -59}, extent = {{-18, -18}, {18, 18}}, rotation = 90))); + Dynawo.NonElectrical.Blocks.Continuous.PIFreeze pIFreeze(Gain = KPp, Y0 = -P0Pu * SystemBase.SnRef / (SNom * U0Pu), tIntegral = 1 / KIp) annotation( + Placement(visible = true, transformation(origin = {50, -32}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + //Initial parameters + parameter Types.PerUnit fInitPu "Initial frequency" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IPMin0Pu annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IPMax0Pu annotation( + Dialog(tab = "Operating point")); + parameter Types.VoltageModulePu U0Pu "Initial voltage amplitude at grid terminal in pu (base UNom)" annotation( + Dialog(group="Operating point")); + parameter Types.PerUnit PAvailOut0Pu "Initial maximum output electrical power available to the active power control module" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit PAvailIn0Pu "Initial minimum output electrical power available to the active power control module" annotation( + Dialog(tab = "Operating point")); + parameter Types.ActivePowerPu P0Pu "Initial active power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit PFFR0Pu "Initial output power utilized for FFR control" annotation( + Dialog(tab = "Operating point")); + +equation + when FFlag == true then + pRefFreezePu = pre(pRefPu); + iPcmdFreezePu = pre(iPcmdPu); + end when; + + connect(pRefPu, firstOrder.u) annotation( + Line(points = {{-200, 0}, {-162, 0}}, color = {0, 0, 127})); + connect(add.y, variableLimiter.u) annotation( + Line(points = {{-59, 0}, {-32, 0}}, color = {0, 0, 127})); + connect(division.y, switch1.u3) annotation( + Line(points = {{41, 0}, {60.5, 0}, {60.5, 8}, {98, 8}}, color = {0, 0, 127})); + connect(switch1.y, variableLimiter1.u) annotation( + Line(points = {{121, 0}, {150, 0}}, color = {0, 0, 127})); + connect(variableLimiter1.y, iPcmdPu) annotation( + Line(points = {{173, 0}, {200, 0}}, color = {0, 0, 127})); + connect(realExpression1.y, switch.u1) annotation( + Line(points = {{-127, -39.2}, {-127.2, -39.2}, {-127.2, -8.2}, {-122, -8.2}}, color = {0, 0, 127})); + connect(firstOrder.y, switch.u3) annotation( + Line(points = {{-139, 0}, {-134.5, 0}, {-134.5, 8}, {-122, 8}}, color = {0, 0, 127})); + connect(add1.y, pIFreeze.u) annotation( + Line(points = {{27, -32}, {38, -32}}, color = {0, 0, 127})); + connect(pIFreeze.y, switch11.u3) annotation( + Line(points = {{61, -32}, {70, -32}}, color = {0, 0, 127})); + connect(switch.y, add.u2) annotation( + Line(points = {{-98, 0}, {-90, 0}, {-90, -6}, {-82, -6}}, color = {0, 0, 127})); + connect(pFFRPu, add.u1) annotation( + Line(points = {{-90, 120}, {-90, 6}, {-82, 6}}, color = {0, 0, 127})); + connect(variableLimiter.y, add1.u1) annotation( + Line(points = {{-8, 0}, {0, 0}, {0, -26}, {4, -26}}, color = {0, 0, 127})); + connect(variableLimiter.y, division.u1) annotation( + Line(points = {{-8, 0}, {0, 0}, {0, -6}, {18, -6}}, color = {0, 0, 127})); + connect(pMeasPu, add1.u2) annotation( + Line(points = {{-40, -40}, {0, -40}, {0, -38}, {4, -38}}, color = {0, 0, 127})); + connect(pAvailOutPu, variableLimiter.limit1) annotation( + Line(points = {{-40, 110}, {-40, 8}, {-32, 8}}, color = {0, 0, 127})); + connect(pAvailInPu, variableLimiter.limit2) annotation( + Line(points = {{-56, 110}, {-56, -8}, {-32, -8}}, color = {0, 0, 127})); + connect(uMeasPu, limiter.u) annotation( + Line(points = {{10, 120}, {10, 82}}, color = {0, 0, 127})); + connect(limiter.y, division.u2) annotation( + Line(points = {{10, 60}, {10, 6}, {18, 6}}, color = {0, 0, 127})); + connect(realExpression.y, switch11.u1) annotation( + Line(points = {{62, -80}, {66, -80}, {66, -48}, {70, -48}}, color = {0, 0, 127})); + connect(booleanExpression.y, switch1.u2) annotation( + Line(points = {{80, 60}, {80, 0}, {98, 0}}, color = {255, 0, 255})); + connect(switch11.y, switch1.u1) annotation( + Line(points = {{94, -40}, {98, -40}, {98, -8}}, color = {0, 0, 127})); + connect(iPMaxPu, variableLimiter1.limit1) annotation( + Line(points = {{140, 110}, {140, 8}, {150, 8}}, color = {0, 0, 127})); + connect(iPMinPu, variableLimiter1.limit2) annotation( + Line(points = {{126, 110}, {126, -8}, {150, -8}}, color = {0, 0, 127})); + connect(FFlag, pIFreeze.freeze) annotation( + Line(points = {{-80, -120}, {-80, -60}, {50, -60}, {50, -44}}, color = {255, 0, 255})); + connect(FFlag, switch11.u2) annotation( + Line(points = {{-80, -120}, {-80, -60}, {62, -60}, {62, -40}, {70, -40}}, color = {255, 0, 255})); + connect(FFlag, switch.u2) annotation( + Line(points = {{-80, -120}, {-80, -20}, {-130, -20}, {-130, 0}, {-122, 0}}, color = {255, 0, 255})); + + annotation( + Icon(graphics = {Rectangle(extent = {{-180, 100}, {180, -100}}), Text(extent = {{-180, 100}, {180, -100}}, textString = "PControl")}, coordinateSystem(extent = {{-180, -100}, {180, 100}})), + Diagram(coordinateSystem(extent = {{-180, -100}, {180, 100}}))); +end PControl; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/QControl.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/QControl.mo new file mode 100644 index 00000000000..242479b9501 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/QControl.mo @@ -0,0 +1,321 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.Controls.BaseControls; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model QControl + + //Nominal parameter + parameter Types.ApparentPowerModule SNom "Nominal converter apparent power in MVA"; + + //Parameters + parameter Types.PerUnit UMaxPu "Maximum voltage defined by users" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit UMinPu "Minimum voltage defined by users" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KPqu "Proportional gain in the reactive power PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KIqu "Integral gain in the reactive power PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KPuq "Proportional gain in the outer voltage PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KIuq "Integral gain in the outer voltage PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KPui "Proportional gain in the inner voltage PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KIui "Integral gain in the inner voltage PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KPqi "Proportional gain in the inner reactive power PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KIqi "Integral gain in the inner reactive power PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KDroop "Q/U droop gain" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit DUdb1Pu "Voltage change dead band lower limit (typically negative) in pu (base UNom)" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit DUdb2Pu "Voltage change dead band upper limit (typically positive) in pu (base UNom)" annotation( + Dialog(tab = "QControl")); + parameter Real TanPhi "Power factor used in the power factor control" annotation( + Dialog(tab = "QControl")); + parameter Integer PFFlag annotation( + Dialog(tab = "QControl")); + parameter Integer LFlag annotation( + Dialog(tab = "QControl")); + parameter Boolean UFlag annotation( + Dialog(tab = "QControl")); + parameter Types.Time Tiq "Time constant in reactive power order lag" annotation( + Dialog(tab = "QControl")); + + //Input variables + Modelica.Blocks.Interfaces.RealInput uRefPu(start=U0Pu) "Voltage reference provided by the plant controller" annotation( + Placement(visible = true, transformation(origin = {-330, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-331, 81}, extent = {{-11, -11}, {11, 11}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput qRefPu(start=-Q0Pu) "Voltage reference provided by the plant controller" annotation( + Placement(visible = true, transformation(origin = {-330, 1.42109e-14}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-332, 0}, extent = {{-12, -12}, {12, 12}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput uMeasPu(start=U0Pu) "Measured (and filtered) voltage component" annotation( + Placement(visible = true, transformation(origin = {-330, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-331, 41}, extent = {{-11, -11}, {11, 11}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput qMeasPu(start=-Q0Pu) "Measured (and filtered) reactive power component" annotation( + Placement(visible = true, transformation(origin = {-330, 80}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-332, -40}, extent = {{-12, -12}, {12, 12}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput pMeasPu(start=-P0Pu) "Measured (and filtered) active power component" annotation( + Placement(visible = true, transformation(origin = {-330, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-332, -80}, extent = {{-12, -12}, {12, 12}}, rotation = 0))); + Modelica.Blocks.Interfaces.BooleanInput FFlag(start=false) annotation( + Placement(visible = true, transformation(origin = {-170, 110}, extent = {{-10, -10}, {10, 10}}, rotation = -90), iconTransformation(origin = {0, 120}, extent = {{-20, -20}, {20, 20}}, rotation = -90))); + Modelica.Blocks.Interfaces.RealInput iQMinPu(start=IQMin0Pu) annotation( + Placement(visible = true, transformation(origin = {100, -120}, extent = {{-20, -20}, {20, 20}}, rotation = 90), iconTransformation(origin = {239, 115}, extent = {{15, -15}, {-15, 15}}, rotation = 90))); + Modelica.Blocks.Interfaces.RealInput iQMaxPu(start=IQMax0Pu) annotation( + Placement(visible = true, transformation(origin = {160, -120}, extent = {{-20, -20}, {20, 20}}, rotation = 90), iconTransformation(origin = {281, 115}, extent = {{15, -15}, {-15, 15}}, rotation = 90))); + Modelica.Blocks.Interfaces.RealInput qMinPu(start=QMin0Pu) annotation( + Placement(visible = true, transformation(origin = {-120, -120}, extent = {{-20, -20}, {20, 20}}, rotation = 90), iconTransformation(origin = {-141, 115}, extent = {{15, -15}, {-15, 15}}, rotation = 90))); + Modelica.Blocks.Interfaces.RealInput qMaxPu(start=QMax0Pu) annotation( + Placement(visible = true, transformation(origin = {-60, -120}, extent = {{-20, -20}, {20, 20}}, rotation = 90), iconTransformation(origin = {-101, 115}, extent = {{15, -15}, {-15, 15}}, rotation = 90))); + + //Output variables + Modelica.Blocks.Interfaces.RealOutput iQcmdPu(start=Q0Pu*SystemBase.SnRef/(SNom*U0Pu)) "Reactive current command" annotation( + Placement(visible = true, transformation(origin = {330, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {340, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + + Modelica.Blocks.Math.Add add(k2 = -1) annotation( + Placement(visible = true, transformation(origin = {110, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Switch switch1 annotation( + Placement(visible = true, transformation(origin = {76, 40}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Math.Add add1(k2 = -1) annotation( + Placement(visible = true, transformation(origin = {-290, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.DeadZone deadZone(deadZoneAtInit = true, uMax = DUdb2Pu, uMin = DUdb1Pu) annotation( + Placement(visible = true, transformation(origin = {-260, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Math.Gain gain(k = KDroop) annotation( + Placement(visible = true, transformation(origin = {-230, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.VariableLimiter variableLimiter annotation( + Placement(visible = true, transformation(origin = {-200, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Math.Add add2(k1 = -1) annotation( + Placement(visible = true, transformation(origin = {-40, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Math.Add add3 annotation( + Placement(visible = true, transformation(origin = {-160, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.VariableLimiter variableLimiter1 annotation( + Placement(visible = true, transformation(origin = {-70, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.NonElectrical.Blocks.Continuous.PIFreeze pIFreeze(Gain = KPqu, Y0 = U0Pu, tIntegral = 1 / KIqu) annotation( + Placement(visible = true, transformation(origin = {0, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.BooleanExpression booleanExpression(y = FFlag) annotation( + Placement(visible = true, transformation(origin = {0, 10}, extent = {{-10, -8}, {10, 8}}, rotation = 90))); + Modelica.Blocks.Nonlinear.VariableLimiter variableLimiter2 annotation( + Placement(visible = true, transformation(origin = {42, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.DeadZone deadZone1(deadZoneAtInit = true, uMax = DUdb2Pu, uMin = DUdb1Pu) annotation( + Placement(visible = true, transformation(origin = {138, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.NonElectrical.Blocks.Continuous.PIFreeze pIFreeze1(Gain = KPui, Y0 = -Q0Pu * SystemBase.SnRef / (SNom * U0Pu), tIntegral = 1 / KIui) annotation( + Placement(visible = true, transformation(origin = {170, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.VariableLimiter variableLimiter3 annotation( + Placement(visible = true, transformation(origin = {200, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.IntegerExpression integerExpression(y = LFlag) annotation( + Placement(visible = true, transformation(origin = {260, 33}, extent = {{-13, -14}, {13, 14}}, rotation = -90))); + Modelica.Blocks.Nonlinear.VariableLimiter variableLimiter4 annotation( + Placement(visible = true, transformation(origin = {90, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.BooleanExpression booleanExpression2(y = FFlag) annotation( + Placement(visible = true, transformation(origin = {130, -42}, extent = {{-9, -9}, {9, 9}}, rotation = -90))); + Modelica.Blocks.Sources.IntegerExpression integerExpression1(y = PFFlag) annotation( + Placement(visible = true, transformation(origin = {-110, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 90))); + Modelica.Blocks.Math.Add add4(k2 = -1) annotation( + Placement(visible = true, transformation(origin = {-290, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.DeadZone deadZone2(deadZoneAtInit = true, uMax = DUdb2Pu, uMin = DUdb1Pu) annotation( + Placement(visible = true, transformation(origin = {-250, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.BooleanExpression booleanExpression4(y = FFlag) annotation( + Placement(visible = true, transformation(origin = {-210, -111}, extent = {{-10, -9}, {10, 9}}, rotation = 90))); + Dynawo.NonElectrical.Blocks.Continuous.PIFreeze pIFreeze5(Gain = KPuq, Y0 = -Q0Pu * SystemBase.SnRef / SNom, tIntegral = 1 / KIuq) annotation( + Placement(visible = true, transformation(origin = {-210, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.NonElectrical.Blocks.Continuous.PIFreeze pIFreeze2(Gain = KPqi, Y0 = -Q0Pu * SystemBase.SnRef / (SNom * U0Pu), tIntegral = 1 / KIqi) annotation( + Placement(visible = true, transformation(origin = {30, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Math.Division division annotation( + Placement(visible = true, transformation(origin = {30, -80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Math.Gain gain2(k = -1) annotation( + Placement(visible = true, transformation(origin = {300, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression12(y = qMinPu) annotation( + Placement(visible = true, transformation(origin = {-82, -30}, extent = {{-10, -8}, {10, 8}}, rotation = 90))); + Modelica.Blocks.Sources.RealExpression realExpression13(y = qMaxPu) annotation( + Placement(visible = true, transformation(origin = {-230, 64}, extent = {{-10, -8}, {10, 8}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression14(y = qMinPu) annotation( + Placement(visible = true, transformation(origin = {-230, 16}, extent = {{-10, -8}, {10, 8}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression15(y = UMaxPu) annotation( + Placement(visible = true, transformation(origin = {10, 65}, extent = {{-10, -9}, {10, 9}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression16(y = UMinPu) annotation( + Placement(visible = true, transformation(origin = {24, 10}, extent = {{-10, -8}, {10, 8}}, rotation = 90))); + Modelica.Blocks.Sources.RealExpression realExpression17(y = iQMaxPu) annotation( + Placement(visible = true, transformation(origin = {170, 64}, extent = {{-10, -8}, {10, 8}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression18(y = iQMinPu) annotation( + Placement(visible = true, transformation(origin = {187, 9}, extent = {{10, -8}, {-10, 8}}, rotation = -90))); + Modelica.Blocks.Sources.RealExpression realExpression20(y = iQMinPu) annotation( + Placement(visible = true, transformation(origin = {58, -32}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.BooleanExpression booleanExpression11(y = UFlag) annotation( + Placement(visible = true, transformation(origin = {61, 89}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Dynawo.Electrical.Controls.IEC.IEC63406.AuxiliaryBlocks.TripleSwitch tripleSwitch annotation( + Placement(visible = true, transformation(origin = {260, -20}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.AuxiliaryBlocks.QuadriSwitch quadriSwitch annotation( + Placement(visible = true, transformation(origin = {-110, 20}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression19(y = iQMaxPu) annotation( + Placement(visible = true, transformation(origin = {58, -12}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression21(y = iQMinPu) annotation( + Placement(visible = true, transformation(origin = {90, -92}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression22(y = iQMaxPu) annotation( + Placement(visible = true, transformation(origin = {90, -69}, extent = {{-10, -9}, {10, 9}}, rotation = 0))); + Dynawo.NonElectrical.Blocks.Continuous.AbsLimRateLimFirstOrderFreeze absLimRateLimFirstOrderFreeze(DyMax = 1000, UseLimits = true, Y0 = -Q0Pu * SystemBase.SnRef / (SNom * U0Pu), tI = Tiq) annotation( + Placement(visible = true, transformation(origin = {130, -80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +Modelica.Blocks.Nonlinear.Limiter limiter1(limitsAtInit = true, uMax = Modelica.Constants.inf, uMin = 0.01) annotation( + Placement(visible = true, transformation(origin = {-60, -80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Math.Gain gain1(k = TanPhi) annotation( + Placement(visible = true, transformation(origin = {-250, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression(y = uRefPu) annotation( + Placement(visible = true, transformation(origin = {-330, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression1(y = uMeasPu) annotation( + Placement(visible = true, transformation(origin = {-330, -80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression2(y = uMeasPu) annotation( + Placement(visible = true, transformation(origin = {90, 90}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Modelica.Blocks.Sources.RealExpression realExpression3(y = uRefPu) annotation( + Placement(visible = true, transformation(origin = {40, 90}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Modelica.Blocks.Sources.BooleanExpression booleanExpression1(y = FFlag) annotation( + Placement(visible = true, transformation(origin = {170, 9}, extent = {{-10, -9}, {10, 9}}, rotation = 90))); + + //Initial parameters + parameter Types.VoltageModulePu U0Pu "Initial voltage amplitude at grid terminal in pu (base UNom)" annotation( + Dialog(group="Operating point")); + parameter Types.ActivePowerPu P0Pu "Initial active power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.ReactivePowerPu Q0Pu "Initial reactive power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IQMax0Pu "Initial maximum reactive current" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IQMin0Pu "Initial minimum reactive current" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit QMax0Pu "Initial maximum reactive power" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit QMin0Pu "Initial minimum reactive power" annotation( + Dialog(tab = "Operating point")); + +equation + connect(deadZone.u, add1.y) annotation( + Line(points = {{-272, 40}, {-279, 40}}, color = {0, 0, 127})); + connect(deadZone.y, gain.u) annotation( + Line(points = {{-249, 40}, {-242, 40}}, color = {0, 0, 127})); + connect(gain.y, variableLimiter.u) annotation( + Line(points = {{-219, 40}, {-212, 40}}, color = {0, 0, 127})); + connect(add2.y, pIFreeze.u) annotation( + Line(points = {{-29, 40}, {-12, 40}}, color = {0, 0, 127})); + connect(pIFreeze.y, variableLimiter2.u) annotation( + Line(points = {{11, 40}, {30, 40}}, color = {0, 0, 127})); + connect(add.y, deadZone1.u) annotation( + Line(points = {{121, 40}, {126, 40}}, color = {0, 0, 127})); + connect(deadZone1.y, pIFreeze1.u) annotation( + Line(points = {{149, 40}, {158, 40}}, color = {0, 0, 127})); + connect(pIFreeze1.y, variableLimiter3.u) annotation( + Line(points = {{181, 40}, {188, 40}}, color = {0, 0, 127})); + connect(add4.y, deadZone2.u) annotation( + Line(points = {{-279, -60}, {-262, -60}}, color = {0, 0, 127})); + connect(pIFreeze2.y, variableLimiter4.u) annotation( + Line(points = {{41, -20}, {78, -20}}, color = {0, 0, 127})); + connect(deadZone2.y, pIFreeze5.u) annotation( + Line(points = {{-239, -60}, {-222, -60}}, color = {0, 0, 127})); + connect(booleanExpression4.y, pIFreeze5.freeze) annotation( + Line(points = {{-210, -100}, {-210, -72}}, color = {255, 0, 255})); + connect(realExpression15.y, variableLimiter2.limit1) annotation( + Line(points = {{21, 65}, {30, 65}, {30, 48}}, color = {0, 0, 127})); + connect(realExpression17.y, variableLimiter3.limit1) annotation( + Line(points = {{181, 64}, {188, 64}, {188, 48}}, color = {0, 0, 127})); + connect(realExpression18.y, variableLimiter3.limit2) annotation( + Line(points = {{187, 20}, {187, 32}, {188, 32}}, color = {0, 0, 127})); + connect(variableLimiter4.y, tripleSwitch.e1) annotation( + Line(points = {{101, -20}, {236, -20}}, color = {0, 0, 127})); + connect(quadriSwitch.y, variableLimiter1.u) annotation( + Line(points = {{-88, 20}, {-82, 20}}, color = {0, 0, 127})); + connect(integerExpression1.y, quadriSwitch.flag) annotation( + Line(points = {{-110, -19}, {-110, -4}}, color = {255, 127, 0})); + connect(division.y, absLimRateLimFirstOrderFreeze.u) annotation( + Line(points = {{41, -80}, {118, -80}}, color = {0, 0, 127})); + connect(booleanExpression2.y, absLimRateLimFirstOrderFreeze.freeze) annotation( + Line(points = {{130, -51.9}, {130, -67.9}}, color = {255, 0, 255})); + connect(uRefPu, add1.u1) annotation( + Line(points = {{-330, 60}, {-310, 60}, {-310, 46}, {-302, 46}}, color = {0, 0, 127})); + connect(uMeasPu, add1.u2) annotation( + Line(points = {{-330, 20}, {-310, 20}, {-310, 34}, {-302, 34}}, color = {0, 0, 127})); + connect(realExpression13.y, variableLimiter.limit1) annotation( + Line(points = {{-219, 64}, {-212, 64}, {-212, 48}}, color = {0, 0, 127})); + connect(realExpression14.y, variableLimiter.limit2) annotation( + Line(points = {{-219, 16}, {-212, 16}, {-212, 32}}, color = {0, 0, 127})); + connect(variableLimiter.y, add3.u1) annotation( + Line(points = {{-189, 40}, {-181, 40}, {-181, 46}, {-172, 46}}, color = {0, 0, 127})); + connect(pMeasPu, gain1.u) annotation( + Line(points = {{-330, -20}, {-262, -20}}, color = {0, 0, 127})); + connect(qRefPu, add3.u2) annotation( + Line(points = {{-330, 1.42109e-14}, {-180, 1.42109e-14}, {-180, 34}, {-172, 34}}, color = {0, 0, 127})); + connect(realExpression.y, add4.u1) annotation( + Line(points = {{-319, -40}, {-311, -40}, {-311, -54}, {-303, -54}}, color = {0, 0, 127})); + connect(realExpression1.y, add4.u2) annotation( + Line(points = {{-319, -80}, {-311, -80}, {-311, -66}, {-303, -66}}, color = {0, 0, 127})); + connect(add3.y, quadriSwitch.e0) annotation( + Line(points = {{-149, 40}, {-141, 40}, {-141, 36}, {-134, 36}}, color = {0, 0, 127})); + connect(qRefPu, quadriSwitch.e1) annotation( + Line(points = {{-330, 1.42109e-14}, {-180, 1.42109e-14}, {-180, 20}, {-140, 20}, {-140, 25}, {-134, 25}}, color = {0, 0, 127})); + connect(gain1.y, quadriSwitch.e2) annotation( + Line(points = {{-239, -20}, {-141, -20}, {-141, 14}, {-134, 14}}, color = {0, 0, 127})); + connect(pIFreeze5.y, quadriSwitch.e3) annotation( + Line(points = {{-199, -60}, {-134, -60}, {-134, 4}}, color = {0, 0, 127})); + connect(qMeasPu, add2.u1) annotation( + Line(points = {{-330, 80}, {-52, 80}, {-52, 46}}, color = {0, 0, 127})); + connect(booleanExpression.y, pIFreeze.freeze) annotation( + Line(points = {{0, 21}, {0, 28}}, color = {255, 0, 255})); + connect(realExpression16.y, variableLimiter2.limit2) annotation( + Line(points = {{24, 21}, {24, 32}, {30, 32}}, color = {0, 0, 127})); + connect(variableLimiter2.y, switch1.u1) annotation( + Line(points = {{53, 40}, {55, 40}, {55, 32}, {64, 32}}, color = {0, 0, 127})); + connect(switch1.y, add.u1) annotation( + Line(points = {{87, 40}, {93, 40}, {93, 46}, {98, 46}}, color = {0, 0, 127})); + connect(realExpression2.y, add.u2) annotation( + Line(points = {{90, 79}, {90, 34}, {98, 34}}, color = {0, 0, 127})); + connect(booleanExpression11.y, switch1.u2) annotation( + Line(points = {{61, 78}, {59, 78}, {59, 40}, {64, 40}}, color = {255, 0, 255})); + connect(realExpression3.y, switch1.u3) annotation( + Line(points = {{40, 79}, {40, 59}, {56, 59}, {56, 48}, {64, 48}}, color = {0, 0, 127})); + connect(booleanExpression1.y, pIFreeze1.freeze) annotation( + Line(points = {{170, 20}, {170, 28}}, color = {255, 0, 255})); + connect(realExpression1.y, limiter1.u) annotation( + Line(points = {{-319, -80}, {-72, -80}}, color = {0, 0, 127})); + connect(variableLimiter1.y, add2.u2) annotation( + Line(points = {{-59, 20}, {-52, 20}, {-52, 34}}, color = {0, 0, 127})); + connect(variableLimiter1.y, division.u1) annotation( + Line(points = {{-59, 20}, {-40, 20}, {-40, -74}, {18, -74}}, color = {0, 0, 127})); + connect(realExpression22.y, absLimRateLimFirstOrderFreeze.yMax) annotation( + Line(points = {{101, -69}, {113, -69}, {113, -75}, {117, -75}}, color = {0, 0, 127})); + connect(realExpression21.y, absLimRateLimFirstOrderFreeze.yMin) annotation( + Line(points = {{101, -92}, {113, -92}, {113, -86}, {117, -86}}, color = {0, 0, 127})); + connect(add2.y, pIFreeze2.u) annotation( + Line(points = {{-29, 40}, {-21, 40}, {-21, -20}, {18, -20}}, color = {0, 0, 127})); + connect(realExpression20.y, variableLimiter4.limit2) annotation( + Line(points = {{69, -32}, {73.5, -32}, {73.5, -28}, {78, -28}}, color = {0, 0, 127})); + connect(realExpression19.y, variableLimiter4.limit1) annotation( + Line(points = {{69, -12}, {78, -12}}, color = {0, 0, 127})); + connect(absLimRateLimFirstOrderFreeze.y, tripleSwitch.e2) annotation( + Line(points = {{141, -80}, {219, -80}, {219, -32}, {236, -32}}, color = {0, 0, 127})); + connect(variableLimiter3.y, tripleSwitch.e0) annotation( + Line(points = {{211, 40}, {219, 40}, {219, -8}, {236, -8}}, color = {0, 0, 127})); + connect(tripleSwitch.y, gain2.u) annotation( + Line(points = {{282, -20}, {288, -20}}, color = {0, 0, 127})); + connect(gain2.y, iQcmdPu) annotation( + Line(points = {{311, -20}, {329, -20}}, color = {0, 0, 127})); + connect(integerExpression.y, tripleSwitch.flag) annotation( + Line(points = {{260, 19}, {260, 4}}, color = {255, 127, 0})); + connect(limiter1.y, division.u2) annotation( + Line(points = {{-48, -80}, {0, -80}, {0, -86}, {18, -86}}, color = {0, 0, 127})); + connect(booleanExpression2.y, pIFreeze2.freeze) annotation( + Line(points = {{130, -52}, {130, -60}, {30, -60}, {30, -32}}, color = {255, 0, 255})); + connect(realExpression13.y, variableLimiter1.limit1) annotation( + Line(points = {{-218, 64}, {-82, 64}, {-82, 28}}, color = {0, 0, 127})); + connect(realExpression12.y, variableLimiter1.limit2) annotation( + Line(points = {{-82, -19}, {-82, 12}}, color = {0, 0, 127})); +protected + + annotation( + Icon(graphics = {Rectangle(extent = {{-320, 100}, {320, -100}}), Text(extent = {{-320, 98}, {320, -98}}, textString = "QControl")}, coordinateSystem(extent = {{-320, -100}, {320, 100}})), + Diagram(coordinateSystem(extent = {{-320, -100}, {320, 100}}))); +end QControl; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/QLimitation.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/QLimitation.mo new file mode 100644 index 00000000000..88eb14d9064 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/QLimitation.mo @@ -0,0 +1,159 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.Controls.BaseControls; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model QLimitation + extends Dynawo.Electrical.Controls.IEC.IEC61400.Parameters.QLimitParameters; + + //Nominal parameter + parameter Types.ApparentPowerModule SNom "Nominal converter apparent power in MVA"; + + //Parameters + parameter Types.PerUnit QMaxUd "Maximum reactive power defined by users" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit QMinUd "Minimum reactive power defined by users" annotation( + Dialog(tab = "QControl")); + parameter Boolean QLimFlag "0 to use the defined lookup tables, 1 to use the constant values" annotation( + Dialog(tab = "QControl")); + + //Input variables + Modelica.Blocks.Interfaces.RealInput uMeasPu(start = U0Pu) annotation( + Placement(visible = true, transformation(origin = {-120, 80}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 40}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput pMeasPu(start = -P0Pu) annotation( + Placement(visible = true, transformation(origin = {-120, 40}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, -40}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.BooleanInput FFlag(start = false) annotation( + Placement(visible = true, transformation(origin = {-20, 110}, extent = {{-10, -10}, {10, 10}}, rotation = -90), iconTransformation(origin = {0, 120}, extent = {{-20, -20}, {20, 20}}, rotation = -90))); + + //Output variables + Modelica.Blocks.Interfaces.RealOutput qMaxPu(start = QMax0Pu) "Maximum reactive power" annotation( + Placement(visible = true, transformation(origin = {110, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput qMinPu(start = QMin0Pu) "Minimum reactive power" annotation( + Placement(visible = true, transformation(origin = {110, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + Modelica.Blocks.Tables.CombiTable1Ds combiTable1Ds(table = TableQMaxUwtcFilt) annotation( + Placement(visible = true, transformation(origin = {-40, 80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Switch freeze2 annotation( + Placement(visible = true, transformation(origin = {0, 80}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression1 annotation( + Placement(visible = true, transformation(origin = {-40, 60}, extent = {{-10, -8}, {10, 8}}, rotation = 0))); + Modelica.Blocks.Tables.CombiTable1Ds combiTable1Ds1(table = TableQMaxPwtcFilt) annotation( + Placement(visible = true, transformation(origin = {-40, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Switch freeze3 annotation( + Placement(visible = true, transformation(origin = {0, 40}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression2(y = QMaxUd) annotation( + Placement(visible = true, transformation(origin = {-40, 20}, extent = {{-10, -8}, {10, 8}}, rotation = 0))); + Modelica.Blocks.Logical.Switch switch14 annotation( + Placement(visible = true, transformation(origin = {80, 60}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Dynawo.Electrical.CBGU.Auxiliaries.Min3 min31 annotation( + Placement(visible = true, transformation(origin = {40, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.BooleanExpression booleanExpression5(y = QLimFlag) annotation( + Placement(visible = true, transformation(origin = {60, 100}, extent = {{-20, -14}, {20, 14}}, rotation = -90))); + Modelica.Blocks.Tables.CombiTable1Ds combiTable1Ds2(table = TableQMinUwtcFilt) annotation( + Placement(visible = true, transformation(origin = {-40, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Tables.CombiTable1Ds combiTable1Ds3(table = TableQMinPwtcFilt) annotation( + Placement(visible = true, transformation(origin = {-40, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Switch switch12 annotation( + Placement(visible = true, transformation(origin = {0, -60}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Logical.Switch switch13 annotation( + Placement(visible = true, transformation(origin = {0, -20}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression7(y = QMinUd) annotation( + Placement(visible = true, transformation(origin = {-40, -80}, extent = {{-10, -8}, {10, 8}}, rotation = 0))); + Dynawo.Electrical.CBGU.Auxiliaries.Min3 min32 annotation( + Placement(visible = true, transformation(origin = {40, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression8 annotation( + Placement(visible = true, transformation(origin = {-40, -40}, extent = {{-10, -8}, {10, 8}}, rotation = 0))); + Modelica.Blocks.Logical.Switch switch15 annotation( + Placement(visible = true, transformation(origin = {80, -40}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + +//Initial parameters + parameter Types.VoltageModulePu U0Pu "Initial voltage amplitude at grid terminal in pu (base UNom)" annotation( + Dialog(group = "Operating point")); + parameter Types.ActivePowerPu P0Pu "Initial active power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.ReactivePowerPu Q0Pu "Initial reactive power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IQMax0Pu "Initial maximum reactive current" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IQMin0Pu "Initial minimum reactive current" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit QMax0Pu "Initial maximum reactive power" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit QMin0Pu "Initial minimum reactive power" annotation( + Dialog(tab = "Operating point")); + +equation + connect(booleanExpression5.y, switch14.u2) annotation( + Line(points = {{60, 78}, {60, 60}, {68, 60}}, color = {255, 0, 255})); + connect(switch13.y, min32.u3) annotation( + Line(points = {{11, -20}, {20.4, -20}, {20.4, -34}, {28, -34}}, color = {0, 0, 127})); + connect(booleanExpression5.y, switch15.u2) annotation( + Line(points = {{60, 78}, {60, -40}, {68, -40}}, color = {255, 0, 255})); + connect(realExpression2.y, switch14.u1) annotation( + Line(points = {{-29, 20}, {68, 20}, {68, 52}}, color = {0, 0, 127})); + connect(switch14.y, qMaxPu) annotation( + Line(points = {{91, 60}, {110, 60}}, color = {0, 0, 127})); + connect(switch15.y, qMinPu) annotation( + Line(points = {{91, -40}, {110, -40}}, color = {0, 0, 127})); + connect(realExpression7.y, switch15.u1) annotation( + Line(points = {{-29, -80}, {68, -80}, {68, -48}}, color = {0, 0, 127})); + connect(realExpression1.y, freeze2.u1) annotation( + Line(points = {{-29, 60}, {-25, 60}, {-25, 72}, {-13, 72}}, color = {0, 0, 127})); + connect(realExpression1.y, freeze3.u1) annotation( + Line(points = {{-29, 60}, {-25, 60}, {-25, 32}, {-13, 32}}, color = {0, 0, 127})); + connect(FFlag, freeze2.u2) annotation( + Line(points = {{-20, 110}, {-20, 80}, {-12, 80}}, color = {255, 0, 255})); + connect(FFlag, freeze3.u2) annotation( + Line(points = {{-20, 110}, {-20, 40}, {-12, 40}}, color = {255, 0, 255})); + connect(FFlag, switch13.u2) annotation( + Line(points = {{-20, 110}, {-20, -20}, {-12, -20}}, color = {255, 0, 255})); + connect(realExpression8.y, switch13.u1) annotation( + Line(points = {{-30, -40}, {-24, -40}, {-24, -28}, {-12, -28}}, color = {0, 0, 127})); + connect(realExpression8.y, switch12.u1) annotation( + Line(points = {{-30, -40}, {-24, -40}, {-24, -68}, {-12, -68}}, color = {0, 0, 127})); + connect(FFlag, switch12.u2) annotation( + Line(points = {{-20, 110}, {-20, -60}, {-12, -60}}, color = {255, 0, 255})); + connect(switch12.y, min32.u2) annotation( + Line(points = {{12, -60}, {20, -60}, {20, -40}, {28, -40}}, color = {0, 0, 127})); + connect(realExpression7.y, min32.u1) annotation( + Line(points = {{-30, -80}, {28, -80}, {28, -46}}, color = {0, 0, 127})); + connect(min32.y, switch15.u3) annotation( + Line(points = {{50, -40}, {56, -40}, {56, -32}, {68, -32}}, color = {0, 0, 127})); + connect(min31.y, switch14.u3) annotation( + Line(points = {{50.8, 60}, {55.8, 60}, {55.8, 68}, {67.8, 68}}, color = {0, 0, 127})); + connect(realExpression2.y, min31.u1) annotation( + Line(points = {{-28, 20}, {28, 20}, {28, 54}}, color = {0, 0, 127})); + connect(freeze3.y, min31.u2) annotation( + Line(points = {{12, 40}, {20, 40}, {20, 60}, {28, 60}}, color = {0, 0, 127})); + connect(freeze2.y, min31.u3) annotation( + Line(points = {{12, 80}, {20, 80}, {20, 66}, {28, 66}}, color = {0, 0, 127})); + connect(combiTable1Ds.y[1], freeze2.u3) annotation( + Line(points = {{-28, 80}, {-22, 80}, {-22, 88}, {-12, 88}}, color = {0, 0, 127})); + connect(combiTable1Ds1.y[1], freeze3.u3) annotation( + Line(points = {{-28, 40}, {-22, 40}, {-22, 48}, {-12, 48}}, color = {0, 0, 127})); + connect(pMeasPu, combiTable1Ds1.u) annotation( + Line(points = {{-120, 40}, {-52, 40}}, color = {0, 0, 127})); + connect(uMeasPu, combiTable1Ds.u) annotation( + Line(points = {{-120, 80}, {-52, 80}}, color = {0, 0, 127})); + connect(uMeasPu, combiTable1Ds2.u) annotation( + Line(points = {{-120, 80}, {-60, 80}, {-60, -20}, {-52, -20}}, color = {0, 0, 127})); + connect(pMeasPu, combiTable1Ds3.u) annotation( + Line(points = {{-120, 40}, {-80, 40}, {-80, -60}, {-52, -60}}, color = {0, 0, 127})); + connect(combiTable1Ds2.y[1], switch13.u3) annotation( + Line(points = {{-28, -20}, {-22, -20}, {-22, -12}, {-12, -12}}, color = {0, 0, 127})); + connect(combiTable1Ds3.y[1], switch12.u3) annotation( + Line(points = {{-28, -60}, {-22, -60}, {-22, -52}, {-12, -52}}, color = {0, 0, 127})); +protected + + annotation( + Icon(graphics = {Rectangle(extent = {{-100, 100}, {100, -100}}), Text(extent = {{-100, 100}, {100, -100}}, textString = "Q\nLimitation")})); +end QLimitation; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/package.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/package.mo new file mode 100644 index 00000000000..83b6730a3b9 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/package.mo @@ -0,0 +1,17 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.Controls; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +package BaseControls + extends Icons.Package; +end BaseControls; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/package.order b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/package.order new file mode 100644 index 00000000000..a6d8c63e59d --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/BaseControls/package.order @@ -0,0 +1,6 @@ +AuxiliaryControls +FFR +PControl +QControl +QLimitation +CurrentLimitation diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/Control.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/Control.mo new file mode 100644 index 00000000000..2616097895e --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/Control.mo @@ -0,0 +1,274 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.Controls; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model Control + + //Nominal parameter + parameter Types.ApparentPowerModule SNom "Nominal converter apparent power in MVA"; + + //FFR parameters + parameter Types.Time Trocof "Time constant for frequency differential operation" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit fThresholdPu "Threshold at which the frequency is considered" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit f0Pu "Frequency setpoint for FFR control" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit PffrMaxPu "Maximum output power utilized for FFR control" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit PffrMinPu "Maximum absorbing power utilized for FFR control" annotation( + Dialog(tab = "FFR")); + parameter Boolean FFRflag "1 to enable the fast frequency response, 0 to disable the fast frequency response" annotation( + Dialog(tab = "FFR")); + parameter Real InertialTable[:, :] = [Pi11, Pi12; Pi21, Pi22] "Pair of points for frequence dependant powers piecewise linear curve [u1,y1; u2,y2;...]" annotation( + Dialog(tab = "FFR")); + parameter Real FFRTable[:, :] = [Pf11, Pf12; Pf21, Pf22] "Pair of points for frequence dependant powers piecewise linear curve [u1,y1; u2,y2;...]" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit Pi11=-1 annotation( + Dialog(tab = "FFR table")); + parameter Types.PerUnit Pi12=-1 annotation( + Dialog(tab = "FFR table")); + parameter Types.PerUnit Pi21=1 annotation( + Dialog(tab = "FFR table")); + parameter Types.PerUnit Pi22=1 annotation( + Dialog(tab = "FFR table")); + parameter Types.PerUnit Pf11=-1 annotation( + Dialog(tab = "FFR table")); + parameter Types.PerUnit Pf12=-1 annotation( + Dialog(tab = "FFR table")); + parameter Types.PerUnit Pf21=1 annotation( + Dialog(tab = "FFR table")); + parameter Types.PerUnit Pf22=1 annotation( + Dialog(tab = "FFR table")); + + //FRT parameters + parameter Types.PerUnit uLVRTPu "LVRT threshold value" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit uHVRTPu "HVRT threshold value" annotation( + Dialog(tab = "FRT")); + + //PControl parameters + parameter Real KIp "Integral gain in the active power PI controller" annotation( + Dialog(tab = "PControl")); + parameter Real KPp "Proportional gain in the active power PI controller" annotation( + Dialog(tab = "PControl")); + parameter Types.Time TpRef "Time constant in the active power filter" annotation( + Dialog(tab = "PControl")); + parameter Boolean PFlag "1 for closed-loop active power control, 0 for open-loop active power control" annotation( + Dialog(tab = "PControl")); + + //QControl parameters + parameter Types.PerUnit UMaxPu "Maximum voltage defined by users" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit UMinPu "Minimum voltage defined by users" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KPqu "Proportional gain in the reactive power PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KIqu "Integral gain in the reactive power PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KPuq "Proportional gain in the outer voltage PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KIuq "Integral gain in the outer voltage PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KPui "Proportional gain in the inner voltage PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KIui "Integral gain in the inner voltage PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KPqi "Proportional gain in the inner reactive power PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KIqi "Integral gain in the inner reactive power PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KDroop "Q/U droop gain" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit DUdb1Pu "Voltage change dead band lower limit (typically negative) in pu (base UNom)" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit DUdb2Pu "Voltage change dead band upper limit (typically positive) in pu (base UNom)" annotation( + Dialog(tab = "QControl")); + parameter Real TanPhi "Power factor used in the power factor control" annotation( + Dialog(tab = "QControl")); + parameter Integer PFFlag annotation( + Dialog(tab = "QControl")); + parameter Integer LFlag annotation( + Dialog(tab = "QControl")); + parameter Boolean UFlag annotation( + Dialog(tab = "QControl")); + parameter Types.Time Tiq "Time constant in reactive power order lag" annotation( + Dialog(tab = "QControl")); + + //Current and Q limitation parameters + parameter Types.PerUnit IMaxPu "Maximum current" annotation( + Dialog(tab = "Current and Q limitation")); + parameter Boolean QLimFlag "0 to use the defined lookup tables, 1 to use the constant values" annotation( + Dialog(tab = "Current and Q limitation")); + parameter Boolean PriorityFlag "0 for active current priority, 1 for reactive current priority" annotation( + Dialog(tab = "Current and Q limitation")); + parameter Types.PerUnit QMaxUd "Maximum reactive power defined by users" annotation( + Dialog(tab = "Current and Q limitation")); + parameter Types.PerUnit QMinUd "Minimum reactive power defined by users" annotation( + Dialog(tab = "Current and Q limitation")); + + //Input variables + Modelica.Blocks.Interfaces.RealInput pRefPu(start = -P0Pu * SystemBase.SnRef / SNom) annotation( + Placement(visible = true, transformation(origin = {-120, 60}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-110, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput pMeasPu(start = -P0Pu * SystemBase.SnRef / SNom) annotation( + Placement(visible = true, transformation(origin = {-120, 30}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-110, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput uMeasPu(start = U0Pu) annotation( + Placement(visible = true, transformation(origin = {-120, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-110, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput uRefPu(start = U0Pu) annotation( + Placement(visible = true, transformation(origin = {-120, -30}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput qMeasPu(start = -Q0Pu * SystemBase.SnRef / SNom) annotation( + Placement(visible = true, transformation(origin = {-120, -90}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-110, -90}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput qRefPu(start = -Q0Pu * SystemBase.SnRef / SNom) annotation( + Placement(visible = true, transformation(origin = {-120, -60}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-110, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput fMeasPu(start = fInitPu) annotation( + Placement(visible = true, transformation(origin = {-120, 90}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-110, 90}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput pAvailInPu(start = PAvailIn0Pu) annotation( + Placement(visible = true, transformation(origin = {-9, 111}, extent = {{-11, -11}, {11, 11}}, rotation = -90), iconTransformation(origin = {-30, 110}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Modelica.Blocks.Interfaces.RealInput pAvailOutPu(start = PAvailOut0Pu) annotation( + Placement(visible = true, transformation(origin = {7, 111}, extent = {{-11, -11}, {11, 11}}, rotation = -90), iconTransformation(origin = {30, 110}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + + //Output variables + Modelica.Blocks.Interfaces.RealOutput iQcmdPu(start = Q0Pu * SystemBase.SnRef / (SNom * U0Pu)) annotation( + Placement(visible = true, transformation(origin = {110, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {115, 21}, extent = {{-15, -15}, {15, 15}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iPcmdPu(start = -P0Pu * SystemBase.SnRef / (SNom * U0Pu)) annotation( + Placement(visible = true, transformation(origin = {110, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {115, 61}, extent = {{-15, -15}, {15, 15}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iPMaxPu(start = IPMax0Pu ) annotation( + Placement(visible = true, transformation(origin = {110, 14}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iPMinPu(start = IPMin0Pu ) annotation( + Placement(visible = true, transformation(origin = {110, 2}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iQMaxPu(start = IQMax0Pu ) annotation( + Placement(visible = true, transformation(origin = {110, -12}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iQMinPu(start = IQMin0Pu ) annotation( + Placement(visible = true, transformation(origin = {110, -26}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + //Variables + Boolean FFlag; + + Dynawo.Electrical.Controls.IEC.IEC63406.Controls.BaseControls.PControl pControl(IPMax0Pu = IPMax0Pu, IPMin0Pu = IPMin0Pu, KIp = KIp, KPp = KPp, P0Pu = P0Pu, PAvailIn0Pu = PAvailIn0Pu, PAvailOut0Pu = PAvailOut0Pu, PFFR0Pu = PFFR0Pu, PFlag = PFlag, SNom = SNom, TpRef = TpRef, U0Pu = U0Pu, fInitPu = fInitPu) annotation( + Placement(visible = true, transformation(origin = {20.2, 59.2223}, extent = {{-40.2, -22.3333}, {40.2, 22.3333}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.Controls.BaseControls.QControl qControl(DUdb1Pu = DUdb1Pu, DUdb2Pu = DUdb2Pu, IQMax0Pu = IQMax0Pu, IQMin0Pu = IQMin0Pu, KDroop = KDroop, KIqi = KIqi, KIqu = KIqu, KIui = KIui, KIuq = KIuq, KPqi = KPqi, KPqu = KPqu, KPui = KPui, KPuq = KPuq, LFlag = LFlag, P0Pu = P0Pu, PFFlag = PFFlag, Q0Pu = Q0Pu, QMax0Pu = QMax0Pu, QMin0Pu = QMin0Pu, SNom = SNom, TanPhi = TanPhi, Tiq = Tiq, U0Pu = U0Pu, UFlag = UFlag, UMaxPu = UMaxPu, UMinPu = UMinPu) annotation( + Placement(visible = true, transformation(origin = {0.8, -60}, extent = {{-59.6, -18.625}, {59.6, 18.625}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.Controls.BaseControls.CurrentLimitation currentLimitation(IMaxPu = IMaxPu, IPMax0Pu = IPMax0Pu, IPMin0Pu = IPMin0Pu, IQMax0Pu = IQMax0Pu, IQMin0Pu = IQMin0Pu, P0Pu = P0Pu, PriorityFlag = PriorityFlag, Q0Pu = Q0Pu, QLimFlag = QLimFlag, QMax0Pu = QMax0Pu, QMaxUd = QMaxUd, QMin0Pu = QMin0Pu, QMinUd = QMinUd, SNom = SNom, U0Pu = U0Pu) annotation( + Placement(visible = true, transformation(origin = {20, 3.55271e-15}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.Controls.BaseControls.QLimitation qLimitation(IQMax0Pu = IQMax0Pu, IQMin0Pu = IQMin0Pu, P0Pu = P0Pu, Q0Pu = Q0Pu, QLimFlag = QLimFlag, QMax0Pu = QMax0Pu, QMaxUd = QMaxUd, QMin0Pu = QMin0Pu, QMinUd = QMinUd, SNom = SNom, U0Pu = U0Pu) annotation( + Placement(visible = true, transformation(origin = {-60, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.Controls.BaseControls.FFR ffr(FFRflag = FFRflag, PFFR0Pu = PFFR0Pu, PffrMaxPu = PffrMaxPu, PffrMinPu = PffrMinPu, Trocof = Trocof, f0Pu = f0Pu, fInitPu = fInitPu, fThresholdPu = fThresholdPu) annotation( + Placement(visible = true, transformation(origin = {-70, 90}, extent = {{-12, -10}, {12, 10}}, rotation = 0))); + Modelica.Blocks.Sources.BooleanExpression booleanExpression(y = FFlag) annotation( + Placement(visible = true, transformation(origin = {110, 30}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); + + //Initial parameters + parameter Types.VoltageModulePu U0Pu "Initial voltage amplitude at grid terminal in pu (base UNom)" annotation( + Dialog(group="Operating point")); + parameter Types.ActivePowerPu P0Pu "Initial active power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.ReactivePowerPu Q0Pu "Initial reactive power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IQMax0Pu "Initial maximum reactive current" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IQMin0Pu "Initial minimum reactive current" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit QMax0Pu "Initial maximum reactive power" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit QMin0Pu "Initial minimum reactive power" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit fInitPu "Initial frequency" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IPMin0Pu annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IPMax0Pu annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit PAvailOut0Pu "Initial maximum output electrical power available to the active power control module" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit PAvailIn0Pu "Initial minimum output electrical power available to the active power control module" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit PFFR0Pu "Initial output power utilized for FFR control" annotation( + Dialog(tab = "Operating point")); + +equation + FFlag = if uMeasPu < uLVRTPu or uMeasPu > uHVRTPu then true else false; + + connect(fMeasPu, ffr.fMeasPu) annotation( + Line(points = {{-120, 90}, {-82, 90}}, color = {0, 0, 127})); + connect(pRefPu, pControl.pRefPu) annotation( + Line(points = {{-120, 60}, {-40, 60}, {-40, 70}, {-22, 70}}, color = {0, 0, 127})); + connect(pMeasPu, pControl.pMeasPu) annotation( + Line(points = {{-120, 30}, {-90, 30}, {-90, 48}, {-22, 48}}, color = {0, 0, 127})); + connect(pMeasPu, qLimitation.pMeasPu) annotation( + Line(points = {{-120, 30}, {-90, 30}, {-90, -8}, {-84, -8}}, color = {0, 0, 127})); + connect(uRefPu, qControl.uRefPu) annotation( + Line(points = {{-120, -30}, {-80, -30}, {-80, -45}, {-61, -45}}, color = {0, 0, 127})); + connect(uMeasPu, qControl.uMeasPu) annotation( + Line(points = {{-120, 0}, {-96, 0}, {-96, -52}, {-61, -52}}, color = {0, 0, 127})); + connect(uMeasPu, qLimitation.uMeasPu) annotation( + Line(points = {{-120, 0}, {-96, 0}, {-96, 8}, {-84, 8}}, color = {0, 0, 127})); + connect(qRefPu, qControl.qRefPu) annotation( + Line(points = {{-120, -60}, {-61, -60}}, color = {0, 0, 127})); + connect(qMeasPu, qControl.qMeasPu) annotation( + Line(points = {{-120, -90}, {-80, -90}, {-80, -67}, {-61, -67}}, color = {0, 0, 127})); + connect(pMeasPu, qControl.pMeasPu) annotation( + Line(points = {{-120, 30}, {-90, 30}, {-90, -75}, {-61, -75}}, color = {0, 0, 127})); + connect(qLimitation.qMaxPu, currentLimitation.qMaxPu) annotation( + Line(points = {{-38, 8}, {-2, 8}, {-2, 6}}, color = {0, 0, 127})); + connect(qLimitation.qMinPu, currentLimitation.qMinPu) annotation( + Line(points = {{-38, -8}, {-2, -8}, {-2, -6}}, color = {0, 0, 127})); + connect(uMeasPu, currentLimitation.uMeasPu) annotation( + Line(points = {{-120, 0}, {-2, 0}}, color = {0, 0, 127})); + connect(ffr.pFFRPu, pControl.pFFRPu) annotation( + Line(points = {{-58, 90}, {-16, 90}, {-16, 84}}, color = {0, 0, 127})); + connect(currentLimitation.iPMaxPu, pControl.iPMaxPu) annotation( + Line(points = {{42, 14}, {58, 14}, {58, 35}}, color = {0, 0, 127})); + connect(currentLimitation.iPMinPu, pControl.iPMinPu) annotation( + Line(points = {{42, 6}, {51, 6}, {51, 35}}, color = {0, 0, 127})); + connect(qLimitation.qMaxPu, qControl.qMaxPu) annotation( + Line(points = {{-38, 8}, {-18, 8}, {-18, -39}}, color = {0, 0, 127})); + connect(qLimitation.qMinPu, qControl.qMinPu) annotation( + Line(points = {{-38, -8}, {-25, -8}, {-25, -39}}, color = {0, 0, 127})); + connect(currentLimitation.iQMaxPu, qControl.iQMaxPu) annotation( + Line(points = {{42, -6}, {53, -6}, {53, -39}}, color = {0, 0, 127})); + connect(currentLimitation.iQMinPu, qControl.iQMinPu) annotation( + Line(points = {{42, -14}, {45, -14}, {45, -39}}, color = {0, 0, 127})); + connect(pControl.iPcmdPu, currentLimitation.iPcmdPu) annotation( + Line(points = {{62, 60}, {80, 60}, {80, 28}, {-20, 28}, {-20, 16}, {-4, 16}}, color = {0, 0, 127})); + connect(qControl.iQcmdPu, currentLimitation.iQcmdPu) annotation( + Line(points = {{64, -60}, {80, -60}, {80, -28}, {-12, -28}, {-12, -16}, {-4, -16}}, color = {0, 0, 127})); + connect(pControl.iPcmdPu, iPcmdPu) annotation( + Line(points = {{62, 60}, {110, 60}}, color = {0, 0, 127})); + connect(qControl.iQcmdPu, iQcmdPu) annotation( + Line(points = {{64, -60}, {110, -60}}, color = {0, 0, 127})); + connect(pAvailInPu, pControl.pAvailInPu) annotation( + Line(points = {{-8, 112}, {-8, 84}, {0, 84}}, color = {0, 0, 127})); + connect(pAvailOutPu, pControl.pAvailOutPu) annotation( + Line(points = {{8, 112}, {6, 112}, {6, 84}}, color = {0, 0, 127})); + connect(uMeasPu, pControl.uMeasPu) annotation( + Line(points = {{-120, 0}, {-96, 0}, {-96, 120}, {20, 120}, {20, 84}}, color = {0, 0, 127})); + connect(booleanExpression.y, pControl.FFlag) annotation( + Line(points = {{100, 30}, {-6, 30}, {-6, 34}}, color = {255, 0, 255})); + connect(booleanExpression.y, qLimitation.FFlag) annotation( + Line(points = {{100, 30}, {-60, 30}, {-60, 24}}, color = {255, 0, 255})); + connect(booleanExpression.y, currentLimitation.FFlag) annotation( + Line(points = {{100, 30}, {20, 30}, {20, 24}}, color = {255, 0, 255})); + connect(booleanExpression.y, qControl.FFlag) annotation( + Line(points = {{100, 30}, {84, 30}, {84, -32}, {1, -32}, {1, -38}}, color = {255, 0, 255})); + connect(currentLimitation.iPMaxPu, iPMaxPu) annotation( + Line(points = {{42, 14}, {110, 14}}, color = {0, 0, 127})); + connect(currentLimitation.iPMinPu, iPMinPu) annotation( + Line(points = {{42, 6}, {80, 6}, {80, 2}, {110, 2}}, color = {0, 0, 127})); + connect(currentLimitation.iQMaxPu, iQMaxPu) annotation( + Line(points = {{42, -6}, {80, -6}, {80, -12}, {110, -12}}, color = {0, 0, 127})); + connect(currentLimitation.iQMinPu, iQMinPu) annotation( + Line(points = {{42, -14}, {80, -14}, {80, -26}, {110, -26}}, color = {0, 0, 127})); + +annotation( + Icon(graphics = {Rectangle(extent = {{100, 100}, {-100, -100}}), Text(extent = {{-100, 100}, {100, -100}}, textString = "Control")})); +end Control; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/package.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/package.mo new file mode 100644 index 00000000000..b2b347a618d --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/package.mo @@ -0,0 +1,17 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +package Controls + extends Icons.Package; +end Controls; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/package.order b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/package.order new file mode 100644 index 00000000000..96836145436 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Controls/package.order @@ -0,0 +1,2 @@ +BaseControls +Control diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/FaultModules/package.order b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/FaultModules/package.order new file mode 100644 index 00000000000..e69de29bb2d diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/InjectorCurrentSource.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/InjectorCurrentSource.mo new file mode 100644 index 00000000000..a6d23267bbd --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/InjectorCurrentSource.mo @@ -0,0 +1,110 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model InjectorCurrentSource + extends Dynawo.Electrical.Controls.Basics.SwitchOff.SwitchOffInjector; + + //Nominal parameter + parameter Types.ApparentPowerModule SNom "Nominal converter apparent power in MVA"; + + //Circuit parameters + parameter Types.PerUnit BesPu "Shunt susceptance in pu (base UNom, SNom)" annotation( + Dialog(tab = "Electrical")); + parameter Types.PerUnit GesPu "Shunt conductance in pu (base UNom, SNom)" annotation( + Dialog(tab = "Electrical")); + parameter Types.PerUnit ResPu "Serial resistance in pu (base UNom, SNom)" annotation( + Dialog(tab = "Electrical")); + parameter Types.PerUnit XesPu "Serial reactance in pu (base UNom, SNom)" annotation( + Dialog(tab = "Electrical")); + parameter Types.Time Tg "Time constant to represent the control delay effect of the inner current control loop (larger than twice of the time step of 1/20 cycle [3]. Alternatively set it to zero to bypass this delay." annotation( + Dialog(tab = "CurrentSource")); + + //Input variables + Modelica.Blocks.Interfaces.RealInput ipRefPu(start = -P0Pu * SystemBase.SnRef / (SNom * U0Pu)) "Active current reference" annotation( + Placement(visible = true, transformation(origin = {-120, 20}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 50}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput iqRefPu(start = Q0Pu * SystemBase.SnRef / (SNom * U0Pu)) "Reactive current reference" annotation( + Placement(visible = true, transformation(origin = {-120, -20}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, -50}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput thetaPLL(start = UPhase0) "Phase angle outputted by phase-locked loop" annotation( + Placement(visible = true, transformation(origin = {-120, 60}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {0, 120}, extent = {{-20, -20}, {20, 20}}, rotation = -90))); + + //Output variables + Modelica.ComplexBlocks.Interfaces.ComplexOutput uPu(re(start = u0Pu.re), im(start = u0Pu.im)) annotation( + Placement(visible = true, transformation(origin = {108, -88}, extent = {{-8, -8}, {8, 8}}, rotation = 0), iconTransformation(origin = {110, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.ComplexBlocks.Interfaces.ComplexOutput iPu(re(start = -i0Pu.re * SystemBase.SnRef / SNom), im(start = -i0Pu.im * SystemBase.SnRef / SNom)) "generator convention" annotation( + Placement(visible = true, transformation(origin = {108, -66}, extent = {{-8, -8}, {8, 8}}, rotation = 0), iconTransformation(origin = {110, 80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + //Interfaces + Dynawo.Connectors.ACPower terminal(V(re(start = u0Pu.re), im(start = u0Pu.im)), i(re(start = i0Pu.re), im(start = i0Pu.im))) "Grid terminal, complex voltage and current in pu (base UNom, SnRef) (receptor convention)" annotation( + Placement(visible = true, transformation(origin = {121, -3.55271e-15}, extent = {{-21, -21}, {21, 21}}, rotation = 0), iconTransformation(origin = {110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + Modelica.ComplexBlocks.ComplexMath.RealToComplex realToComplex annotation( + Placement(visible = true, transformation(origin = {72, -66}, extent = {{-8, 8}, {8, -8}}, rotation = 0))); + Modelica.ComplexBlocks.ComplexMath.RealToComplex realToComplex1 annotation( + Placement(visible = true, transformation(origin = {72, -88}, extent = {{-8, 8}, {8, -8}}, rotation = 0))); + Dynawo.Electrical.Sources.IEC.BaseConverters.CurrentSourceIEC63406 currentSourceIEC63406(IGsIm0Pu = IsIm0Pu, IGsRe0Pu = IsRe0Pu, P0Pu = P0Pu, Q0Pu = Q0Pu, SNom = SNom, Tg = Tg, U0Pu = U0Pu, UGsIm0Pu = UsIm0Pu, UGsRe0Pu = UsRe0Pu, UPhase0 = UPhase0) annotation( + Placement(visible = true, transformation(origin = {-40, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Dynawo.Electrical.Sources.IEC.BaseConverters.ElecSystem elecSystem(BesPu = BesPu, GesPu = GesPu, IGsIm0Pu = IsIm0Pu, IGsRe0Pu = IsRe0Pu, ResPu = ResPu, SNom = SNom, UGsIm0Pu = UsIm0Pu, UGsRe0Pu = UsRe0Pu, XesPu = XesPu, i0Pu = i0Pu, u0Pu = u0Pu) annotation( + Placement(visible = true, transformation(origin = {40, 1.77636e-15}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + + //Initial parameters + parameter Types.ComplexCurrentPu i0Pu "Initial complex current at grid terminal in pu (base UNom, SnRef) (receptor convention)" annotation( + Dialog(group = "Operating point")); + parameter Types.ActivePowerPu P0Pu "Initial active power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.ReactivePowerPu Q0Pu "Initial reactive power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.VoltageModulePu U0Pu "Initial voltage amplitude at grid terminal in pu (base UNom)" annotation( + Dialog(group = "Operating point")); + parameter Types.ComplexVoltagePu u0Pu "Initial complex voltage at grid terminal in pu (base UNom)" annotation( + Dialog(group = "Operating point")); + parameter Types.PerUnit UsIm0Pu "Initial imaginary component of the voltage at converter terminal in pu (base UNom)" annotation( + Dialog(group = "Operating point")); + parameter Types.PerUnit UsRe0Pu "Initial real component of the voltage at converter terminal in pu (base UNom)" annotation( + Dialog(group = "Operating point")); + parameter Types.PerUnit IsIm0Pu "Initial imaginary component of the current at converter terminal in pu (base UNom, SNom) (generator convention)" annotation( + Dialog(group = "Operating point")); + parameter Types.PerUnit IsRe0Pu "Initial real component of the current at converter terminal in pu (base UNom, SNom) (generator convention)" annotation( + Dialog(group = "Operating point")); + parameter Types.Angle UPhase0 "Initial Phase angle outputted by phase-locked loop" annotation( + Dialog(group = "Operating point")); + +equation + currentSourceIEC63406.running = running.value; + + connect(realToComplex1.y, uPu) annotation( + Line(points = {{80.8, -88}, {107.8, -88}}, color = {85, 170, 255})); + connect(realToComplex.y, iPu) annotation( + Line(points = {{80.8, -66}, {107.8, -66}}, color = {85, 170, 255})); + connect(thetaPLL, currentSourceIEC63406.thetaPLL) annotation( + Line(points = {{-120, 60}, {-40, 60}, {-40, 22}}, color = {0, 0, 127})); + connect(ipRefPu, currentSourceIEC63406.ipRefPu) annotation( + Line(points = {{-120, 20}, {-80, 20}, {-80, 8}, {-62, 8}}, color = {0, 0, 127})); + connect(iqRefPu, currentSourceIEC63406.iqRefPu) annotation( + Line(points = {{-120, -20}, {-80, -20}, {-80, -8}, {-62, -8}}, color = {0, 0, 127})); + connect(currentSourceIEC63406.terminal, elecSystem.terminal1) annotation( + Line(points = {{-18, 0}, {18, 0}}, color = {0, 0, 255})); + connect(elecSystem.terminal2, terminal) annotation( + Line(points = {{62, 0}, {122, 0}}, color = {0, 0, 255})); + connect(elecSystem.uWtRePu, realToComplex1.re) annotation( + Line(points = {{22, -22}, {22, -92}, {62, -92}}, color = {0, 0, 127})); + connect(elecSystem.uWtImPu, realToComplex1.im) annotation( + Line(points = {{26, -22}, {26, -84}, {62, -84}}, color = {0, 0, 127})); + connect(elecSystem.iWtRePu, realToComplex.re) annotation( + Line(points = {{32, -22}, {32, -70}, {62, -70}}, color = {0, 0, 127})); + connect(elecSystem.iWtImPu, realToComplex.im) annotation( + Line(points = {{36, -22}, {36, -62}, {62, -62}}, color = {0, 0, 127})); + + annotation( + Icon(graphics = {Rectangle(extent = {{-100, 100}, {100, -100}}), Text(extent = {{-100, 100}, {100, -100}}, textString = "Injector")})); +end InjectorCurrentSource; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/InjectorVoltageSource.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/InjectorVoltageSource.mo new file mode 100644 index 00000000000..cf4ff95b6cf --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/InjectorVoltageSource.mo @@ -0,0 +1,108 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model InjectorVoltageSource + extends Dynawo.Electrical.Controls.Basics.SwitchOff.SwitchOffInjector; + + //Nominal parameter + parameter Types.ApparentPowerModule SNom "Nominal converter apparent power in MVA"; + + //Circuit parameters + parameter Types.PerUnit BesPu "Shunt susceptance in pu (base UNom, SNom)" annotation( + Dialog(tab = "Electrical")); + parameter Types.PerUnit GesPu "Shunt conductance in pu (base UNom, SNom)" annotation( + Dialog(tab = "Electrical")); + parameter Types.PerUnit ResPu "Serial resistance in pu (base UNom, SNom)" annotation( + Dialog(tab = "Electrical")); + parameter Types.PerUnit XesPu "Serial reactance in pu (base UNom, SNom)" annotation( + Dialog(tab = "Electrical")); + parameter Types.Time Tg "Time constant to represent the control delay effect of the inner current control loop (larger than twice of the time step of 1/20 cycle [3]. Alternatively set it to zero to bypass this delay." annotation( + Dialog(tab = "CurrentSource")); + + //Input variables + Modelica.Blocks.Interfaces.RealInput ipRefPu(start = -P0Pu * SystemBase.SnRef / (SNom * U0Pu)) "Active current reference" annotation( + Placement(visible = true, transformation(origin = {-120, 20}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 50}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput iqRefPu(start = Q0Pu * SystemBase.SnRef / (SNom * U0Pu)) "Reactive current reference" annotation( + Placement(visible = true, transformation(origin = {-120, -20}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, -50}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput thetaPLL(start = UPhase0) "Phase angle outputted by phase-locked loop" annotation( + Placement(visible = true, transformation(origin = {-120, 60}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {0, 120}, extent = {{-20, -20}, {20, 20}}, rotation = -90))); + + //Output variables + Modelica.ComplexBlocks.Interfaces.ComplexOutput uPu(re(start = u0Pu.re), im(start = u0Pu.im)) annotation( + Placement(visible = true, transformation(origin = {108, -88}, extent = {{-8, -8}, {8, 8}}, rotation = 0), iconTransformation(origin = {110, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.ComplexBlocks.Interfaces.ComplexOutput iPu(re(start = -i0Pu.re * SystemBase.SnRef / SNom), im(start = -i0Pu.im * SystemBase.SnRef / SNom)) "generator convention" annotation( + Placement(visible = true, transformation(origin = {108, -66}, extent = {{-8, -8}, {8, 8}}, rotation = 0), iconTransformation(origin = {110, 80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + //Interfaces + Dynawo.Connectors.ACPower terminal(V(re(start = u0Pu.re), im(start = u0Pu.im)), i(re(start = i0Pu.re), im(start = i0Pu.im))) "Grid terminal, complex voltage and current in pu (base UNom, SnRef) (receptor convention)" annotation( + Placement(visible = true, transformation(origin = {121, -3.55271e-15}, extent = {{-21, -21}, {21, 21}}, rotation = 0), iconTransformation(origin = {110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + Modelica.ComplexBlocks.ComplexMath.RealToComplex realToComplex annotation( + Placement(visible = true, transformation(origin = {72, -66}, extent = {{-8, 8}, {8, -8}}, rotation = 0))); + Modelica.ComplexBlocks.ComplexMath.RealToComplex realToComplex1 annotation( + Placement(visible = true, transformation(origin = {72, -88}, extent = {{-8, 8}, {8, -8}}, rotation = 0))); + Dynawo.Electrical.Sources.IEC.BaseConverters.ElecSystem elecSystem(BesPu = BesPu, GesPu = GesPu, IGsIm0Pu = IsIm0Pu, IGsRe0Pu = IsRe0Pu, ResPu = ResPu, SNom = SNom, UGsIm0Pu = UsIm0Pu, UGsRe0Pu = UsRe0Pu, XesPu = XesPu, i0Pu = i0Pu, u0Pu = u0Pu) annotation( + Placement(visible = true, transformation(origin = {40, 1.77636e-15}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + + //Initial parameters + parameter Types.ComplexCurrentPu i0Pu "Initial complex current at grid terminal in pu (base UNom, SnRef) (receptor convention)" annotation( + Dialog(group = "Operating point")); + parameter Types.ActivePowerPu P0Pu "Initial active power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.ReactivePowerPu Q0Pu "Initial reactive power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.VoltageModulePu U0Pu "Initial voltage amplitude at grid terminal in pu (base UNom)" annotation( + Dialog(group = "Operating point")); + parameter Types.ComplexVoltagePu u0Pu "Initial complex voltage at grid terminal in pu (base UNom)" annotation( + Dialog(group = "Operating point")); + parameter Types.PerUnit UsIm0Pu "Initial imaginary component of the voltage at converter terminal in pu (base UNom)" annotation( + Dialog(group = "Operating point")); + parameter Types.PerUnit UsRe0Pu "Initial real component of the voltage at converter terminal in pu (base UNom)" annotation( + Dialog(group = "Operating point")); + parameter Types.PerUnit IsIm0Pu "Initial imaginary component of the current at converter terminal in pu (base UNom, SNom) (generator convention)" annotation( + Dialog(group = "Operating point")); + parameter Types.PerUnit IsRe0Pu "Initial real component of the current at converter terminal in pu (base UNom, SNom) (generator convention)" annotation( + Dialog(group = "Operating point")); + parameter Types.Angle UPhase0 "Initial Phase angle outputted by phase-locked loop" annotation( + Dialog(group = "Operating point")); + Dynawo.Electrical.Sources.IEC.BaseConverters.VoltageSourceIEC63406 voltageSourceIEC63406(IGsIm0Pu = IsIm0Pu, IGsRe0Pu = IsRe0Pu, P0Pu = P0Pu, Q0Pu = Q0Pu, ResPu = ResPu, SNom = SNom, Tg = Tg, U0Pu = U0Pu, UGsIm0Pu = UsIm0Pu, UGsRe0Pu = UsRe0Pu, UPhase0 = UPhase0, XesPu = XesPu) annotation( + Placement(visible = true, transformation(origin = {-40, 0}, extent = {{-40, -20}, {40, 20}}, rotation = 0))); + +equation + voltageSourceIEC63406.running = running.value; + connect(realToComplex1.y, uPu) annotation( + Line(points = {{80.8, -88}, {107.8, -88}}, color = {85, 170, 255})); + connect(realToComplex.y, iPu) annotation( + Line(points = {{80.8, -66}, {107.8, -66}}, color = {85, 170, 255})); + connect(elecSystem.terminal2, terminal) annotation( + Line(points = {{62, 0}, {122, 0}}, color = {0, 0, 255})); + connect(elecSystem.uWtRePu, realToComplex1.re) annotation( + Line(points = {{22, -22}, {22, -92}, {62, -92}}, color = {0, 0, 127})); + connect(elecSystem.uWtImPu, realToComplex1.im) annotation( + Line(points = {{26, -22}, {26, -84}, {62, -84}}, color = {0, 0, 127})); + connect(elecSystem.iWtRePu, realToComplex.re) annotation( + Line(points = {{32, -22}, {32, -70}, {62, -70}}, color = {0, 0, 127})); + connect(elecSystem.iWtImPu, realToComplex.im) annotation( + Line(points = {{36, -22}, {36, -62}, {62, -62}}, color = {0, 0, 127})); + connect(voltageSourceIEC63406.terminal, elecSystem.terminal1) annotation( + Line(points = {{-18, 0}, {18, 0}}, color = {0, 0, 255})); + connect(iqRefPu, voltageSourceIEC63406.iqRefPu) annotation( + Line(points = {{-120, -20}, {-80, -20}, {-80, -8}, {-62, -8}}, color = {0, 0, 127})); + connect(ipRefPu, voltageSourceIEC63406.ipRefPu) annotation( + Line(points = {{-120, 20}, {-80, 20}, {-80, 8}, {-62, 8}}, color = {0, 0, 127})); + connect(thetaPLL, voltageSourceIEC63406.thetaPLL) annotation( + Line(points = {{-120, 60}, {-40, 60}, {-40, 22}}, color = {0, 0, 127})); + annotation( + Icon(graphics = {Rectangle(extent = {{-100, 100}, {100, -100}}), Text(extent = {{-100, 100}, {100, -100}}, textString = "Injector")})); +end InjectorVoltageSource; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Measurement/GridMeasurement.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Measurement/GridMeasurement.mo new file mode 100644 index 00000000000..9b2dd509a4e --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Measurement/GridMeasurement.mo @@ -0,0 +1,62 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.Measurement; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model GridMeasurement + extends Dynawo.Electrical.Controls.IEC.BaseClasses.BaseMeasurements; + + //PLL parameters + parameter Integer PLLFlag "0 for the case when the phase angle can be read from the calculation result of the simulation program, 1 for the case of adding a filter based on case 1, 2 for the case where the dynamics of the PLL need to be considered" annotation( + Dialog(tab = "PLL")); + parameter Types.Time TpllFilt "Time constant in PLL angle filter. Put 0 if no filter for the PLL (PLLFlag=2 in the norm)" annotation( + Dialog(tab = "PLL")); + parameter Types.Time TfFilt "Time constant in PLL angle filter. Put 0 if no filter for the PLL (PLLFlag=2 in the norm)" annotation( + Dialog(tab = "PLL")); + parameter Types.Time DeltaT "Integral time step" annotation( + Dialog(tab = "PLL")); + parameter Types.Frequency fref "Rated frequency (50/60 Hz)" annotation( + Dialog(tab = "PLL")); + parameter Real KPpll "Proportional gain in PI controller" annotation( + Dialog(tab = "PLL")); + parameter Real KIpll "Integral gain in PI controller" annotation( + Dialog(tab = "PLL")); + parameter Types.PerUnit UpllPu "Voltage below which the frequency of the voltage is filtered and the angle of the voltage is possibly frozen" annotation( + Dialog(tab = "PLL")); + parameter Types.AngularVelocity Wref = 2 * Modelica.Constants.pi * fref "Rated angular velocity" annotation( + Dialog(tab = "PLL")); + parameter Types.PerUnit WMaxPu "Maximum PLL frequency deviation" annotation( + Dialog(tab = "PLL")); + parameter Types.PerUnit WMinPu "Minimum PLL frequency deviation" annotation( + Dialog(tab = "PLL")); + parameter Types.AngularVelocityPu DfMaxPu "Maximum angle rotation ramp rate in rad/s" annotation( + Dialog(tab = "PLL")); + + //Output variables + Modelica.Blocks.Interfaces.RealOutput thetaPLL(start=UPhase0) "Phase angle outputted by phase-locked loop" annotation( + Placement(visible = true, transformation(origin = {150, -80}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput fFiltPu(start=fInitPu) "Measured frequency outputted by the phase-locked loop" annotation( + Placement(visible = true, transformation(origin = {150, -120}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + //Initial parameters + parameter Types.PerUnit fInitPu "Initial frequency" annotation( + Dialog(tab = "Operating point")); + PLL pll(DeltaT = DeltaT, DfMaxPu = DfMaxPu, KIpll = KIpll, KPpll = KPpll, PLLFlag = PLLFlag, TfFilt = TfFilt, TpllFilt = TpllFilt, UPhase0 = UPhase0, UpllPu = UpllPu, WMaxPu = WMaxPu, WMinPu = WMinPu, fInitPu = fInitPu, fref = fref, tS = tS, u0Pu = u0Pu) annotation( + Placement(visible = true, transformation(origin = {3.55271e-15, -100}, extent = {{-40, -40}, {40, 40}}, rotation = 0))); +equation + connect(uPu, pll.uPu) annotation( + Line(points = {{-160, 0}, {-100, 0}, {-100, -100}, {-48, -100}}, color = {85, 170, 255})); + connect(pll.thetaPLL, thetaPLL) annotation( + Line(points = {{44, -80}, {150, -80}}, color = {0, 0, 127})); + connect(pll.fMeasPu, fFiltPu) annotation( + Line(points = {{44, -120}, {150, -120}}, color = {0, 0, 127})); +end GridMeasurement; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Measurement/PLL.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Measurement/PLL.mo new file mode 100644 index 00000000000..4c7b4b15ef3 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Measurement/PLL.mo @@ -0,0 +1,188 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.Measurement; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model PLL + + //Nominal parameters + parameter Types.Time tS "Integration time step in s"; + + //Parameters + parameter Integer PLLFlag "0 for the case when the phase angle can be read from the calculation result of the simulation program, 1 for the case of adding a filter based on case 1, 2 for the case where the dynamics of the PLL need to be considered" annotation( + Dialog(tab = "PLL")); + parameter Types.Time TpllFilt "Time constant in PLL angle filter. Put 0 if no filter for the PLL (PLLFlag=2 in the norm)" annotation( + Dialog(tab = "PLL")); + parameter Types.Time TfFilt "Time constant in PLL angle filter. Put 0 if no filter for the PLL (PLLFlag=2 in the norm)" annotation( + Dialog(tab = "PLL")); + parameter Types.Frequency fref "Rated frequency (50/60 Hz)" annotation( + Dialog(tab = "PLL")); + parameter Real KPpll "Proportional gain in PI controller" annotation( + Dialog(tab = "PLL")); + parameter Real KIpll "Integral gain in PI controller" annotation( + Dialog(tab = "PLL")); + parameter Types.PerUnit UpllPu "Voltage below which the frequency of the voltage is filtered and the angle of the voltage is possibly frozen" annotation( + Dialog(tab = "PLL")); + parameter Types.AngularVelocity Wref = 2 * Modelica.Constants.pi * fref "Rated angular velocity" annotation( + Dialog(tab = "PLL")); + parameter Types.PerUnit WMaxPu "Maximum PLL frequency deviation" annotation( + Dialog(tab = "PLL")); + parameter Types.PerUnit WMinPu "Minimum PLL frequency deviation" annotation( + Dialog(tab = "PLL")); + parameter Types.Time DeltaT "Time step of the simulation" annotation( + Dialog(tab = "PLL")); + parameter Types.AngularVelocityPu DfMaxPu "Maximum angle rotation ramp rate in rad/s" annotation( + Dialog(tab = "PLL")); + + //Input variables + Modelica.ComplexBlocks.Interfaces.ComplexInput uPu(re(start = u0Pu.re), im(start = u0Pu.im)) annotation( + Placement(visible = true, transformation(origin = {-112, 0}, extent = {{-12, -12}, {12, 12}}, rotation = 0), iconTransformation(origin = {-120, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + + //Output variables + Modelica.Blocks.Interfaces.RealOutput thetaPLL(start=UPhase0) "Phase angle outputted by phase-locked loop" annotation( + Placement(visible = true, transformation(origin = {110, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput fMeasPu(start=fInitPu) "Measured frequency outputted by the phase-locked loop" annotation( + Placement(visible = true, transformation(origin = {110, -80}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + Modelica.Blocks.Continuous.FirstOrder firstOrder(T = TpllFilt, y_start = UPhase0) annotation( + Placement(visible = true, transformation(origin = {10, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.IntegerExpression integerExpression(y = PLLFlag) annotation( + Placement(visible = true, transformation(origin = {80, 80}, extent = {{-14, -10}, {14, 10}}, rotation = -90))); + Modelica.ComplexBlocks.Sources.ComplexExpression complexExpr(y = Complex(0, 0)) annotation( + Placement(visible = true, transformation(origin = {-92, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 90))); + Modelica.Blocks.Logical.Switch switch11 annotation( + Placement(visible = true, transformation(origin = {22, 0}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.AuxiliaryBlocks.SwitchComplex switch12 annotation( + Placement(visible = true, transformation(origin = {-70, 0}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Math.Add add annotation( + Placement(visible = true, transformation(origin = {0, -80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression1(y = Wref) annotation( + Placement(visible = true, transformation(origin = {-20, -102}, extent = {{-10, -10}, {10, 10}}, rotation = 90))); + Modelica.Blocks.Logical.Switch switch1 annotation( + Placement(visible = true, transformation(origin = {-38, -80}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Continuous.FirstOrder firstOrder1(T = TfFilt) annotation( + Placement(visible = true, transformation(origin = {-68, -88}, extent = {{-6, -6}, {6, 6}}, rotation = 0))); + Dynawo.NonElectrical.Blocks.Complex.ComplexToPolar complexToPolar1 annotation( + Placement(visible = true, transformation(origin = {-50, 80}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.AuxiliaryBlocks.TripleSwitch tripleSwitch annotation( + Placement(visible = true, transformation(origin = {80, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.AuxiliaryBlocks.TripleSwitch tripleSwitch1 annotation( + Placement(visible = true, transformation(origin = {80, -80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression3(y = 1) annotation( + Placement(visible = true, transformation(origin = {90, -40}, extent = {{10, -6}, {-10, 6}}, rotation = 0))); + Modelica.Blocks.Math.Add add3 annotation( + Placement(visible = true, transformation(origin = {60, -58}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Modelica.Blocks.Math.Gain gain2(k = 1 / Wref) annotation( + Placement(visible = true, transformation(origin = {42, -40}, extent = {{8, -8}, {-8, 8}}, rotation = 180))); + Modelica.Blocks.Continuous.Derivative derivative annotation( + Placement(visible = true, transformation(origin = {80, -20}, extent = {{-8, -8}, {8, 8}}, rotation = 180))); + Modelica.Blocks.Logical.LessThreshold lessThreshold(threshold = UpllPu) annotation( + Placement(visible = true, transformation(origin = {-50, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 180))); + Dynawo.Electrical.Controls.WECC.Utilities.TransformRItoDQ transformRItoDQ annotation( + Placement(visible = true, transformation(origin = {-40, 0}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Continuous.Integrator integrator(y_start = UPhase0) annotation( + Placement(visible = true, transformation(origin = {48, 6}, extent = {{-6, -6}, {6, 6}}, rotation = 0))); + Modelica.Blocks.Math.Gain gain1(k = 1 / Wref) annotation( + Placement(visible = true, transformation(origin = {28, -80}, extent = {{-8, -8}, {8, 8}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression realExpression annotation( + Placement(visible = true, transformation(origin = {12, -28}, extent = {{-8, -8}, {8, 8}}, rotation = 90))); + Dynawo.NonElectrical.Blocks.Continuous.LimitedPI limitedPI(Ki = KIpll * Wref, Kp = KPpll * Wref, YMax = WMaxPu * Wref, YMin = WMinPu * Wref) annotation( + Placement(visible = true, transformation(origin = {-10, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.NonElectrical.Blocks.NonLinear.RampLimiter rampLimiter(DuMax = DfMaxPu, Y0 = 0, tS = tS) annotation( + Placement(visible = true, transformation(origin = {-36, -40}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); + Dynawo.NonElectrical.Blocks.NonLinear.RampLimiter rampLimiter1(DuMax = DfMaxPu, Y0 = 0, tS = tS) annotation( + Placement(visible = true, transformation(origin = {54, -20}, extent = {{8, -8}, {-8, 8}}, rotation = 0))); + + //Initial parameters + parameter Types.PerUnit fInitPu "Initial frequency" annotation( + Dialog(tab = "Operating point")); + parameter Types.Angle UPhase0 "Initial Phase angle outputted by phase-locked loop" annotation( + Dialog(group="Operating point")); + parameter Types.ComplexVoltagePu u0Pu "Initial complex voltage at grid terminal in pu (base UNom)" annotation( + Dialog(group="Operating point")); +equation + connect(uPu, switch12.u3) annotation( + Line(points = {{-112, 0}, {-92, 0}, {-92, 6}, {-82, 6}}, color = {85, 170, 255})); + connect(complexExpr.y, switch12.u1) annotation( + Line(points = {{-92, -19}, {-92, -6}, {-82, -6}}, color = {85, 170, 255})); + connect(tripleSwitch.y, thetaPLL) annotation( + Line(points = {{91, 40}, {110, 40}}, color = {0, 0, 127})); + connect(complexToPolar1.len, lessThreshold.u) annotation( + Line(points = {{-38, 74}, {-20, 74}, {-20, 40}, {-38, 40}}, color = {0, 0, 127})); + connect(lessThreshold.y, switch12.u2) annotation( + Line(points = {{-60, 40}, {-86, 40}, {-86, 0}, {-82, 0}}, color = {255, 0, 255})); + connect(uPu, complexToPolar1.u) annotation( + Line(points = {{-112, 0}, {-92, 0}, {-92, 80}, {-62, 80}}, color = {85, 170, 255})); + connect(complexToPolar1.phi, tripleSwitch.e0) annotation( + Line(points = {{-38, 86}, {40, 86}, {40, 46}, {68, 46}}, color = {0, 0, 127})); + connect(complexToPolar1.phi, firstOrder.u) annotation( + Line(points = {{-38, 86}, {-10, 86}, {-10, 40}, {-2, 40}}, color = {0, 0, 127})); + connect(firstOrder.y, tripleSwitch.e1) annotation( + Line(points = {{22, 40}, {68, 40}}, color = {0, 0, 127})); + connect(integerExpression.y, tripleSwitch.flag) annotation( + Line(points = {{80, 65}, {80, 52.6}}, color = {255, 127, 0})); + connect(switch12.y, transformRItoDQ.uPu) annotation( + Line(points = {{-58, 0}, {-54, 0}, {-54, -6}, {-51, -6}}, color = {85, 170, 255})); + connect(switch11.y, integrator.u) annotation( + Line(points = {{33, 0}, {37, 0}, {37, 6}, {41, 6}}, color = {0, 0, 127})); + connect(integrator.y, tripleSwitch.e2) annotation( + Line(points = {{55, 6}, {64, 6}, {64, 34}, {68, 34}}, color = {0, 0, 127})); + connect(lessThreshold.y, switch11.u2) annotation( + Line(points = {{-60, 40}, {-86, 40}, {-86, 20}, {6, 20}, {6, 0}, {10, 0}}, color = {255, 0, 255})); + connect(firstOrder1.y, switch1.u1) annotation( + Line(points = {{-62, -88}, {-50, -88}}, color = {0, 0, 127})); + connect(switch1.y, add.u1) annotation( + Line(points = {{-26, -80}, {-20, -80}, {-20, -74}, {-12, -74}}, color = {0, 0, 127})); + connect(realExpression1.y, add.u2) annotation( + Line(points = {{-20, -91}, {-20, -86}, {-12, -86}}, color = {0, 0, 127})); + connect(add.y, gain1.u) annotation( + Line(points = {{12, -80}, {18, -80}}, color = {0, 0, 127})); + connect(realExpression.y, switch11.u1) annotation( + Line(points = {{12, -19}, {12, -16}, {6, -16}, {6, -8}, {10, -8}}, color = {0, 0, 127})); + connect(tripleSwitch.y, derivative.u) annotation( + Line(points = {{92, 40}, {94, 40}, {94, -20}, {90, -20}}, color = {0, 0, 127})); + connect(gain2.y, add3.u2) annotation( + Line(points = {{51, -40}, {54, -40}, {54, -46}}, color = {0, 0, 127})); + connect(realExpression3.y, add3.u1) annotation( + Line(points = {{79, -40}, {66, -40}, {66, -46}}, color = {0, 0, 127})); + connect(add3.y, tripleSwitch1.e0) annotation( + Line(points = {{60, -69}, {60, -74}, {68, -74}}, color = {0, 0, 127})); + connect(add3.y, tripleSwitch1.e1) annotation( + Line(points = {{60, -68}, {60, -80}, {68, -80}}, color = {0, 0, 127})); + connect(gain1.y, tripleSwitch1.e2) annotation( + Line(points = {{36, -80}, {52, -80}, {52, -86}, {68, -86}}, color = {0, 0, 127})); + connect(tripleSwitch1.y, fMeasPu) annotation( + Line(points = {{92, -80}, {110, -80}}, color = {0, 0, 127})); + connect(integrator.y, transformRItoDQ.phi) annotation( + Line(points = {{55, 6}, {64, 6}, {64, 16}, {-54, 16}, {-54, 6}, {-50, 6}}, color = {0, 0, 127})); + connect(lessThreshold.y, switch1.u2) annotation( + Line(points = {{-60, 40}, {-86, 40}, {-86, -80}, {-50, -80}}, color = {255, 0, 255})); + connect(transformRItoDQ.uqPu, limitedPI.u) annotation( + Line(points = {{-28, 6}, {-26, 6}, {-26, 0}, {-22, 0}}, color = {0, 0, 127})); + connect(limitedPI.y, switch11.u3) annotation( + Line(points = {{1, 0}, {4, 0}, {4, 8}, {10, 8}}, color = {0, 0, 127})); + connect(limitedPI.y, rampLimiter.u) annotation( + Line(points = {{1, 0}, {4, 0}, {4, -40}, {-24, -40}}, color = {0, 0, 127})); + connect(rampLimiter.y, firstOrder1.u) annotation( + Line(points = {{-46, -40}, {-80, -40}, {-80, -88}, {-76, -88}}, color = {0, 0, 127})); + connect(rampLimiter.y, switch1.u3) annotation( + Line(points = {{-46, -40}, {-80, -40}, {-80, -72}, {-50, -72}}, color = {0, 0, 127})); + connect(derivative.y, rampLimiter1.u) annotation( + Line(points = {{72, -20}, {64, -20}}, color = {0, 0, 127})); + connect(rampLimiter1.y, gain2.u) annotation( + Line(points = {{46, -20}, {28, -20}, {28, -40}, {32, -40}}, color = {0, 0, 127})); + connect(integerExpression.y, tripleSwitch1.flag) annotation( + Line(points = {{80, 64}, {80, 60}, {140, 60}, {140, -60}, {80, -60}, {80, -68}}, color = {255, 127, 0})); + annotation( + Icon(graphics = {Text(extent = {{-100, 100}, {100, -100}}, textString = "PLL"), Rectangle(extent = {{-100, 100}, {100, -100}})}), + experiment(StartTime = 0, StopTime = 1, Tolerance = 1e-6, Interval = 0.002)); +end PLL; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Measurement/package.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Measurement/package.mo new file mode 100644 index 00000000000..7d03da61b8e --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Measurement/package.mo @@ -0,0 +1,17 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +package Measurement + extends Icons.Package; +end Measurement; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Measurement/package.order b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Measurement/package.order new file mode 100644 index 00000000000..f364e079f24 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Measurement/package.order @@ -0,0 +1,2 @@ +PLL +GridMeasurement diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PlantCommunication.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PlantCommunication.mo new file mode 100644 index 00000000000..7324130f674 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PlantCommunication.mo @@ -0,0 +1,149 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model PlantCommunication + + //Parameters + parameter Types.Time Tcom "Time constant for communication delay between the plant-level controller and the generating unit-level controller" annotation( + Dialog(tab = "PlantCommunication")); + parameter Types.Time Tlead "Time constant for communication lead between the plant-level controller and the generating unit-level controller" annotation( + Dialog(tab = "PlantCommunication")); + parameter Types.Time Tlag "Time constant for communication lag between the plant-level controller and the generating unit-level controller" annotation( + Dialog(tab = "PlantCommunication")); + parameter Integer ComFlag "0 if the communication delay is relatively long and affects the control, 1 if accurate modeling of the communication delay is provided, 2 for linear communication and 3 for 1st order lag communication" annotation( + Dialog(tab = "PlantCommunication")); + + //Input variables + Modelica.Blocks.Interfaces.RealInput pCmdPu(start = -P0Pu) "Active power command" annotation( + Placement(visible = true, transformation(origin = {-120, 60}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-110, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput qCmdPu(start = -Q0Pu) "Reactive power command" annotation( + Placement(visible = true, transformation(origin = {-120, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput uCmdPu(start = U0Pu) "Voltage command" annotation( + Placement(visible = true, transformation(origin = {-120, -60}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-110, -50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + //Output variables + Modelica.Blocks.Interfaces.RealOutput pRefPu(start = -P0Pu) "Active power reference provided by the plant controller" annotation( + Placement(visible = true, transformation(origin = {110, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput qRefPu(start = -Q0Pu) "Reactive power reference provided by the plant controller" annotation( + Placement(visible = true, transformation(origin = {110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput uRefPu(start = U0Pu) "Voltage reference provided by the plant controller" annotation( + Placement(visible = true, transformation(origin = {110, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + Dynawo.Electrical.Controls.IEC.IEC63406.AuxiliaryBlocks.StrongDelay strongDelay(T = Tcom) annotation( + Placement(visible = true, transformation(origin = {-13, 80}, extent = {{-7, -7}, {7, 7}}, rotation = 0))); + Modelica.Blocks.Nonlinear.FixedDelay fixedDelay(delayTime = Tcom) annotation( + Placement(visible = true, transformation(origin = {14, 66}, extent = {{-7, -7}, {7, 7}}, rotation = 0))); + Modelica.Blocks.Continuous.TransferFunction transferFunction(a = {Tlag, 1}, b = {Tlead, 1}, y_start = -P0Pu) annotation( + Placement(visible = true, transformation(origin = {-13, 54}, extent = {{-7, -7}, {7, 7}}, rotation = 0))); + Modelica.Blocks.Continuous.FirstOrder firstOrder(T = Tcom, y_start = -P0Pu) annotation( + Placement(visible = true, transformation(origin = {13, 40}, extent = {{-7, -7}, {7, 7}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.AuxiliaryBlocks.QuadriSwitch quadriSwitch annotation( + Placement(visible = true, transformation(origin = {70, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.AuxiliaryBlocks.QuadriSwitch quadriSwitch1 annotation( + Placement(visible = true, transformation(origin = {70, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.AuxiliaryBlocks.QuadriSwitch quadriSwitch2 annotation( + Placement(visible = true, transformation(origin = {70, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.IntegerExpression IntegerExpression(y = ComFlag) annotation( + Placement(visible = true, transformation(origin = {70, -90}, extent = {{-10, -10}, {10, 10}}, rotation = 90))); + Dynawo.Electrical.Controls.IEC.IEC63406.AuxiliaryBlocks.StrongDelay strongDelay1(T = Tcom) annotation( + Placement(visible = true, transformation(origin = {-13, 20}, extent = {{-7, -7}, {7, 7}}, rotation = 0))); + Modelica.Blocks.Nonlinear.FixedDelay fixedDelay1(delayTime = Tcom) annotation( + Placement(visible = true, transformation(origin = {14, 6}, extent = {{-7, -7}, {7, 7}}, rotation = 0))); + Modelica.Blocks.Continuous.TransferFunction transferFunction1(a = {Tlag, 1}, b = {Tlead, 1}, y_start = -P0Pu) annotation( + Placement(visible = true, transformation(origin = {-13, -6}, extent = {{-7, -7}, {7, 7}}, rotation = 0))); + Modelica.Blocks.Continuous.FirstOrder firstOrder1(T = Tcom, y_start = -Q0Pu) annotation( + Placement(visible = true, transformation(origin = {13, -20}, extent = {{-7, -7}, {7, 7}}, rotation = 0))); + Modelica.Blocks.Continuous.TransferFunction transferFunction2(a = {Tlag, 1}, b = {Tlead, 1}, y_start = -P0Pu) annotation( + Placement(visible = true, transformation(origin = {-13, -66}, extent = {{-7, -7}, {7, 7}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.AuxiliaryBlocks.StrongDelay strongDelay2(T = Tcom) annotation( + Placement(visible = true, transformation(origin = {-13, -40}, extent = {{-7, -7}, {7, 7}}, rotation = 0))); + Modelica.Blocks.Continuous.FirstOrder firstOrder2(T = Tcom, y_start = U0Pu) annotation( + Placement(visible = true, transformation(origin = {13, -80}, extent = {{-7, -7}, {7, 7}}, rotation = 0))); + Modelica.Blocks.Nonlinear.FixedDelay fixedDelay2(delayTime = Tcom) annotation( + Placement(visible = true, transformation(origin = {14, -54}, extent = {{-7, -7}, {7, 7}}, rotation = 0))); + + //Initial parameters + parameter Types.VoltageModulePu U0Pu "Initial voltage amplitude at grid terminal in pu (base UNom)" annotation( + Dialog(group = "Operating point")); + parameter Types.ActivePowerPu P0Pu "Initial active power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.ReactivePowerPu Q0Pu "Initial reactive power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + +equation + connect(quadriSwitch.y, pRefPu) annotation( + Line(points = {{81, 60}, {110, 60}}, color = {0, 0, 127})); + connect(quadriSwitch1.y, qRefPu) annotation( + Line(points = {{81, 0}, {110, 0}}, color = {0, 0, 127})); + connect(quadriSwitch2.y, uRefPu) annotation( + Line(points = {{81, -60}, {110, -60}}, color = {0, 0, 127})); + connect(pCmdPu, strongDelay.u) annotation( + Line(points = {{-120, 60}, {-40, 60}, {-40, 80}, {-21, 80}}, color = {0, 0, 127})); + connect(pCmdPu, fixedDelay.u) annotation( + Line(points = {{-120, 60}, {-40, 60}, {-40, 66}, {6, 66}}, color = {0, 0, 127})); + connect(pCmdPu, transferFunction.u) annotation( + Line(points = {{-120, 60}, {-40, 60}, {-40, 54}, {-21, 54}}, color = {0, 0, 127})); + connect(pCmdPu, firstOrder.u) annotation( + Line(points = {{-120, 60}, {-40, 60}, {-40, 40}, {5, 40}}, color = {0, 0, 127})); + connect(strongDelay.y, quadriSwitch.e0) annotation( + Line(points = {{-5, 80}, {40, 80}, {40, 68}, {58, 68}}, color = {0, 0, 127})); + connect(fixedDelay.y, quadriSwitch.e1) annotation( + Line(points = {{22, 66}, {40, 66}, {40, 63}, {58, 63}}, color = {0, 0, 127})); + connect(transferFunction.y, quadriSwitch.e2) annotation( + Line(points = {{-5, 54}, {40, 54}, {40, 57}, {58, 57}}, color = {0, 0, 127})); + connect(firstOrder.y, quadriSwitch.e3) annotation( + Line(points = {{21, 40}, {40, 40}, {40, 52}, {58, 52}}, color = {0, 0, 127})); + connect(IntegerExpression.y, quadriSwitch2.flag) annotation( + Line(points = {{70, -79}, {70, -72}}, color = {255, 127, 0})); + connect(IntegerExpression.y, quadriSwitch1.flag) annotation( + Line(points = {{70, -79}, {70, -12}}, color = {255, 127, 0})); + connect(IntegerExpression.y, quadriSwitch.flag) annotation( + Line(points = {{70, -79}, {70, 48}}, color = {255, 127, 0})); + connect(qCmdPu, strongDelay1.u) annotation( + Line(points = {{-120, 0}, {-40, 0}, {-40, 20}, {-21, 20}}, color = {0, 0, 127})); + connect(qCmdPu, fixedDelay1.u) annotation( + Line(points = {{-120, 0}, {-40, 0}, {-40, 6}, {6, 6}}, color = {0, 0, 127})); + connect(qCmdPu, transferFunction1.u) annotation( + Line(points = {{-120, 0}, {-40, 0}, {-40, -6}, {-21, -6}}, color = {0, 0, 127})); + connect(qCmdPu, firstOrder1.u) annotation( + Line(points = {{-120, 0}, {-40, 0}, {-40, -20}, {5, -20}}, color = {0, 0, 127})); + connect(strongDelay1.y, quadriSwitch1.e0) annotation( + Line(points = {{-5, 20}, {40, 20}, {40, 8}, {58, 8}}, color = {0, 0, 127})); + connect(fixedDelay1.y, quadriSwitch1.e1) annotation( + Line(points = {{22, 6}, {40, 6}, {40, 3}, {58, 3}}, color = {0, 0, 127})); + connect(transferFunction1.y, quadriSwitch1.e2) annotation( + Line(points = {{-5, -6}, {40, -6}, {40, -3}, {58, -3}}, color = {0, 0, 127})); + connect(firstOrder1.y, quadriSwitch1.e3) annotation( + Line(points = {{21, -20}, {40, -20}, {40, -8}, {58, -8}}, color = {0, 0, 127})); + connect(uCmdPu, strongDelay2.u) annotation( + Line(points = {{-120, -60}, {-40, -60}, {-40, -40}, {-21, -40}}, color = {0, 0, 127})); + connect(uCmdPu, fixedDelay2.u) annotation( + Line(points = {{-120, -60}, {-40, -60}, {-40, -54}, {6, -54}}, color = {0, 0, 127})); + connect(uCmdPu, transferFunction2.u) annotation( + Line(points = {{-120, -60}, {-40, -60}, {-40, -66}, {-21, -66}}, color = {0, 0, 127})); + connect(uCmdPu, firstOrder2.u) annotation( + Line(points = {{-120, -60}, {-40, -60}, {-40, -80}, {5, -80}}, color = {0, 0, 127})); + connect(strongDelay2.y, quadriSwitch2.e0) annotation( + Line(points = {{-5, -40}, {40, -40}, {40, -52}, {58, -52}}, color = {0, 0, 127})); + connect(fixedDelay2.y, quadriSwitch2.e1) annotation( + Line(points = {{22, -54}, {40, -54}, {40, -57}, {58, -57}}, color = {0, 0, 127})); + connect(transferFunction2.y, quadriSwitch2.e2) annotation( + Line(points = {{-5, -66}, {40, -66}, {40, -63}, {58, -63}}, color = {0, 0, 127})); + connect(firstOrder2.y, quadriSwitch2.e3) annotation( + Line(points = {{21, -80}, {40, -80}, {40, -68}, {58, -68}}, color = {0, 0, 127})); + + annotation( + Icon(graphics = {Rectangle(extent = {{-100, 100}, {100, -100}}), Text(extent = {{-100, 100}, {100, -100}}, textString = "Plant +Com")})); +end PlantCommunication; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/Auxiliary/SOCcontrol.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/Auxiliary/SOCcontrol.mo new file mode 100644 index 00000000000..2514f1564a4 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/Auxiliary/SOCcontrol.mo @@ -0,0 +1,50 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.PrimaryEnergy.Auxiliary; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model SOCcontrol "Module to limit output power depending on SOC (IEC N°61400-27-1)" + + // Parameters + parameter Types.Percent SOCMax "Maximum SOC amount for charging" annotation( + Dialog(tab = "SOCcontrol")); + parameter Types.Percent SOCMin "Minimum SOC amount for discharging" annotation( + Dialog(tab = "SOCcontrol")); + parameter Types.PerUnit PMaxPu "EMaximum capacity of the CBGU" annotation( + Dialog(tab = "SOCcontrol")); + + //Input variables + Modelica.Blocks.Interfaces.RealInput soc annotation( + Placement(visible = true, transformation(origin = {-120, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + + //Output variables + Modelica.Blocks.Interfaces.RealOutput pAvailInPu annotation( + Placement(visible = true, transformation(origin = {110, 22}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 22}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput pAvailOutPu annotation( + Placement(visible = true, transformation(origin = {110, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + +equation +// Equation de la boucle if + if soc >= SOCMax - 0.0001 * SOCMax then + pAvailInPu = 0; + pAvailOutPu = PMaxPu; + elseif soc <= SOCMin + 0.0001 * SOCMin then + pAvailInPu = -PMaxPu; + pAvailOutPu = 0; + else + pAvailInPu = -PMaxPu; + pAvailOutPu = PMaxPu; + end if; + + annotation( + Icon(graphics = {Text(origin = {4, 2}, extent = {{-88, 62}, {88, -62}}, textString = "SOC\nControl"), Rectangle(fillColor = {255, 255, 255}, extent = {{-100, 100}, {100, -100}})})); +end SOCcontrol; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/Auxiliary/StorageSys.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/Auxiliary/StorageSys.mo new file mode 100644 index 00000000000..1fb1bb38ab3 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/Auxiliary/StorageSys.mo @@ -0,0 +1,99 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.PrimaryEnergy.Auxiliary; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model StorageSys "Primary energy source-driven electric conversion module of energy generation systems (IEC TS 63406 ED1)" + + //Nominal parameter + parameter Types.ApparentPowerModule SNom "Nominal converter apparent power in MVA"; + + //Input variables + Modelica.Blocks.Interfaces.RealInput pMeasPu(start = -P0Pu) annotation( + Placement(visible = true, transformation(origin = {-120, 8.88178e-16}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(extent = {{-140, -20}, {-100, 20}}, rotation = 0))); + + //Output variable + Modelica.Blocks.Interfaces.RealOutput pAvailInPu(start = PMaxPu) annotation( + Placement(visible = true, transformation(origin = {110, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput pAvailOutPu(start = -PMaxPu) annotation( + Placement(visible = true, transformation(origin = {110, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + //Parameters + parameter Types.Time Tess "Equivalent time constant for the battery, supercapacitor or flywheel energy storage systems" annotation( + Dialog(tab = "StorageSys")); + parameter Types.Percent SOCMax "Maximum SOC amount for charging" annotation( + Dialog(tab = "StorageSys")); + parameter Types.Percent SOCMin "Minimum SOC amount for discharging" annotation( + Dialog(tab = "StorageSys")); + parameter Boolean SOCFlag "0 for battery energy storage systems, 1 for supercapacitor energy storage systems and flywheel energy storage systems" annotation( + Dialog(tab = "StorageSys")); + parameter Types.PerUnit PMaxPu "Maximum power capacity of the CBGU" annotation( + Dialog(tab = "StorageSys")); + + Modelica.Blocks.Math.Division division annotation( + Placement(visible = true, transformation(origin = {-76, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Switch SOCFlagSwitch annotation( + Placement(visible = true, transformation(origin = {-42, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Continuous.Integrator integrator(k = 1 / Tess) annotation( + Placement(visible = true, transformation(origin = {-10, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Math.Add add(k1 = -1, k2 = +1) annotation( + Placement(visible = true, transformation(origin = {20, 9.99201e-16}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.Limiter SOClimiter(limitsAtInit = true, uMax = SOCMax, uMin = SOCMin) annotation( + Placement(visible = true, transformation(origin = {50, 4.44089e-16}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant const(k = SOCInit) annotation( + Placement(visible = true, transformation(origin = {-10, -50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.PrimaryEnergy.Auxiliary.SOCcontrol sOCcontrol(PMaxPu = PMaxPu, SOCMax = SOCMax, SOCMin = SOCMin) annotation( + Placement(visible = true, transformation(origin = {80, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Math.Gain gain(k = 100) annotation( + Placement(visible = true, transformation(origin = {-84, 0}, extent = {{-8, -8}, {8, 8}}, rotation = 0))); + Modelica.Blocks.Sources.BooleanExpression boolean(y = SOCFlag) annotation( + Placement(visible = true, transformation(origin = {-60, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 90))); + + //Initial parameters + parameter Types.ActivePowerPu P0Pu "Initial active power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.Percent SOCInit "Initial SOC amount" annotation( + Dialog(tab = "StorageSys")); + +equation + connect(gain.y, SOCFlagSwitch.u3) annotation( + Line(points = {{-75, 0}, {-66.5, 0}, {-66.5, -8}, {-54, -8}}, color = {0, 0, 127})); + connect(pMeasPu, gain.u) annotation( + Line(points = {{-120, 0}, {-94, 0}}, color = {0, 0, 127})); + connect(integrator.y, add.u1) annotation( + Line(points = {{1, 0}, {3.5, 0}, {3.5, 6}, {8, 6}}, color = {0, 0, 127})); + connect(const.y, add.u2) annotation( + Line(points = {{1, -50}, {8, -50}, {8, -6}}, color = {0, 0, 127})); + connect(add.y, SOClimiter.u) annotation( + Line(points = {{31, 0}, {38, 0}}, color = {0, 0, 127})); + connect(SOClimiter.y, sOCcontrol.soc) annotation( + Line(points = {{61, 0}, {68, 0}}, color = {0, 0, 127})); + connect(gain.y, division.u1) annotation( + Line(points = {{-75, 0}, {-66, 0}, {-66, 20}, {-100, 20}, {-100, 56}, {-88, 56}}, color = {0, 0, 127})); + connect(SOClimiter.y, division.u2) annotation( + Line(points = {{61, 0}, {64, 0}, {64, 32}, {-92, 32}, {-92, 44}, {-88, 44}}, color = {0, 0, 127})); + connect(division.y, SOCFlagSwitch.u1) annotation( + Line(points = {{-65, 50}, {-61, 50}, {-61, 8}, {-54, 8}}, color = {0, 0, 127})); + connect(boolean.y, SOCFlagSwitch.u2) annotation( + Line(points = {{-60, -19}, {-60, 0}, {-54, 0}}, color = {255, 0, 255})); + connect(SOCFlagSwitch.y, integrator.u) annotation( + Line(points = {{-31, 0}, {-22, 0}}, color = {0, 0, 127})); + connect(sOCcontrol.pAvailOutPu, pAvailOutPu) annotation( + Line(points = {{92, -2}, {96, -2}, {96, -40}, {110, -40}}, color = {0, 0, 127})); + connect(sOCcontrol.pAvailInPu, pAvailInPu) annotation( + Line(points = {{92, 2}, {96, 2}, {96, 40}, {110, 40}}, color = {0, 0, 127})); +protected + + annotation( + preferredView = "diagram", + Icon(graphics = {Rectangle(fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-100, 100}, {100, -100}}), Text(origin = {8, -19}, extent = {{-107, 118}, {92, -81}}, textString = "Storage\nModule")})); +end StorageSys; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/Auxiliary/package.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/Auxiliary/package.mo new file mode 100644 index 00000000000..5381c38e551 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/Auxiliary/package.mo @@ -0,0 +1,17 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.PrimaryEnergy; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +package Auxiliary + extends Icons.Package; +end Auxiliary; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/Auxiliary/package.order b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/Auxiliary/package.order new file mode 100644 index 00000000000..929ddf434af --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/Auxiliary/package.order @@ -0,0 +1,2 @@ +SOCcontrol +StorageSys diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/EnergyConversion.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/EnergyConversion.mo new file mode 100644 index 00000000000..703ef7a38ba --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/EnergyConversion.mo @@ -0,0 +1,92 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.PrimaryEnergy; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model EnergyConversion + + //Nominal parameter + parameter Types.ApparentPowerModule SNom "Nominal converter apparent power in MVA"; + + //Parameters + parameter Boolean StorageFlag "1 if it is a storage unit, 0 if not" annotation( + Dialog(tab = "General")); + parameter Boolean SOCFlag "0 for battery energy storage systems, 1 for supercapacitor energy storage systems and flywheel energy storage systems" annotation( + Dialog(tab = "Storage")); + parameter Types.PerUnit PMaxPu "Maximum capacity of the CBGU" annotation( + Dialog(tab = "General")); + parameter Real SOCInit (unit="%") "Initial SOC amount" annotation( + Dialog(tab = "Storage")); + parameter Real SOCMax (unit="%") "Maximum SOC amount for charging" annotation( + Dialog(tab = "Storage")); + parameter Real SOCMin (unit="%") "Minimum SOC amount for charging" annotation( + Dialog(tab = "Storage")); + parameter Types.Time Tess "Equivalent time constant for the battery, supercapacitor, +or flywheel energy storage systems" annotation( + Dialog(tab = "Storage")); + parameter Types.Time Tconv "Equivalent time for primary energy conversion" annotation( + Dialog(tab = "Storage")); + + //Input variables + Modelica.Blocks.Interfaces.RealInput pPrimPu(start = -P0Pu) "Power from the primary energy, which should be specified by model users and can be time-varying to represent the variations of primary energy" annotation( + Placement(visible = true, transformation(origin = {-120, 40}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 34}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput pMeasPu(start = -P0Pu) annotation( + Placement(visible = true, transformation(origin = {-122, -40}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, -34}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + + //Output variables + Modelica.Blocks.Interfaces.RealOutput pAvailInPu(start = P0Pu) annotation( + Placement(visible = true, transformation(origin = {110, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 34}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput pAvailOutPu(start = -P0Pu) annotation( + Placement(visible = true, transformation(origin = {110, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -34}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + Dynawo.Electrical.Controls.IEC.IEC63406.PrimaryEnergy.Auxiliary.StorageSys storageSys(PMaxPu = PMaxPu, SNom = SNom, SOCFlag = SOCFlag, SOCInit = SOCInit, SOCMax = SOCMax, SOCMin = SOCMin, Tess = Tess) annotation( + Placement(visible = true, transformation(origin = {-20, -40}, extent = {{-20, 20}, {20, -20}}, rotation = 0))); + Modelica.Blocks.Logical.Switch switch1 annotation( + Placement(visible = true, transformation(origin = {70, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Switch switch11 annotation( + Placement(visible = true, transformation(origin = {70, 40}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Sources.RealExpression real annotation( + Placement(visible = true, transformation(origin = {-10, -80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.BooleanConstant booleanConstant(k = StorageFlag) annotation( + Placement(visible = true, transformation(origin = {40, 90}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Dynawo.NonElectrical.Blocks.NonLinear.LimitedFirstOrder limitedFirstOrder(Y0 = -P0Pu, YMax = PMaxPu, YMin = 0, tFilter = Tconv) annotation( + Placement(visible = true, transformation(origin = {-20, 40}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + + //Initial parameters + parameter Types.ActivePowerPu P0Pu "Initial active power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + +equation + connect(switch11.y, pAvailOutPu) annotation( + Line(points = {{81, 40}, {110, 40}}, color = {0, 0, 127})); + connect(switch1.y, pAvailInPu) annotation( + Line(points = {{81, -40}, {110, -40}}, color = {0, 0, 127})); + connect(pPrimPu, limitedFirstOrder.u) annotation( + Line(points = {{-120, 40}, {-44, 40}}, color = {0, 0, 127})); + connect(booleanConstant.y, switch11.u2) annotation( + Line(points = {{40, 79}, {40, 40}, {58, 40}}, color = {255, 0, 255})); + connect(booleanConstant.y, switch1.u2) annotation( + Line(points = {{40, 79}, {40, -40}, {58, -40}}, color = {255, 0, 255})); + connect(pMeasPu, storageSys.pMeasPu) annotation( + Line(points = {{-122, -40}, {-82, -40}, {-82, -28}, {-44, -28}}, color = {0, 0, 127})); + connect(storageSys.pAvailInPu, switch1.u1) annotation( + Line(points = {{2, -48}, {30, -48}, {30, -32}, {58, -32}}, color = {0, 0, 127})); + connect(real.y, switch1.u3) annotation( + Line(points = {{2, -80}, {50, -80}, {50, -48}, {58, -48}}, color = {0, 0, 127})); + connect(limitedFirstOrder.y, switch11.u3) annotation( + Line(points = {{2, 40}, {20, 40}, {20, 48}, {58, 48}}, color = {0, 0, 127})); + connect(storageSys.pAvailOutPu, switch11.u1) annotation( + Line(points = {{2, -36}, {20, -36}, {20, 32}, {58, 32}}, color = {0, 0, 127})); + + annotation( + Icon(graphics = {Rectangle(extent = {{-100, 100}, {100, -100}}), Text(extent = {{-100, 100}, {100, -100}}, textString = "Energy\nConversion")})); +end EnergyConversion; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/package.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/package.mo new file mode 100644 index 00000000000..46724540517 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/package.mo @@ -0,0 +1,17 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +package PrimaryEnergy + extends Icons.Package; +end PrimaryEnergy; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/package.order b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/package.order new file mode 100644 index 00000000000..1acee40984d --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/PrimaryEnergy/package.order @@ -0,0 +1,2 @@ +Auxiliary +EnergyConversion diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/AuxiliaryProtections/FRTCurrentBounds.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/AuxiliaryProtections/FRTCurrentBounds.mo new file mode 100644 index 00000000000..465fa5dd38c --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/AuxiliaryProtections/FRTCurrentBounds.mo @@ -0,0 +1,57 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.Protections.AuxiliaryProtections; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model FRTCurrentBounds + + //Parameters + parameter Types.PerUnit IMaxPu "Maximum current" annotation( + Dialog(tab = "FRT")); + parameter Boolean pqFRTFlag "Active/reactive control priority, 0/1" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit IPMaxPu "Maximum active current" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit IQMaxPu "Maximum reactive current" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit IPMinPu "Minimum active current" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit IQMinPu "Minimum reactive current" annotation( + Dialog(tab = "FRT")); + + //Input variables + Modelica.Blocks.Interfaces.RealInput ipLVRTPrimPu annotation( + Placement(visible = true, transformation(origin = {-120, 40}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 40}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput iqLVRTPrimPu annotation( + Placement(visible = true, transformation(origin = {-120, -40}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, -40}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + + //Output variables + Modelica.Blocks.Interfaces.RealOutput ipMinPu annotation( + Placement(visible = true, transformation(origin = {110, 32}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput ipMaxPu annotation( + Placement(visible = true, transformation(origin = {110, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iqMaxPu annotation( + Placement(visible = true, transformation(origin = {110, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iqMinPu annotation( + Placement(visible = true, transformation(origin = {110, -46}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + +equation + ipMaxPu = if pqFRTFlag then min(sqrt(max(IMaxPu ^ 2 - iqLVRTPrimPu ^ 2, 0)), IPMaxPu) else min(IMaxPu, IPMaxPu); + ipMinPu = 0; + iqMaxPu = if pqFRTFlag then min(IMaxPu, IQMaxPu) else min(sqrt(max(IMaxPu ^ 2 - ipLVRTPrimPu ^ 2, 0)), IQMaxPu); + iqMinPu = if pqFRTFlag then max(-IMaxPu, IQMinPu) else max(-sqrt(max(IMaxPu ^ 2 - ipLVRTPrimPu ^ 2, 0)), IQMinPu); + + annotation( + Diagram(graphics = {Rectangle(extent = {{-100, 100}, {100, -100}})}), + Icon(graphics = {Text(extent = {{-100, 100}, {100, -100}}, textString = "Ip&Iq +limiter"), Rectangle(extent = {{-100, 100}, {100, -100}})})); +end FRTCurrentBounds; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/AuxiliaryProtections/FRTCurrentCalculation.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/AuxiliaryProtections/FRTCurrentCalculation.mo new file mode 100644 index 00000000000..5c93c1b0805 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/AuxiliaryProtections/FRTCurrentCalculation.mo @@ -0,0 +1,99 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.Protections.AuxiliaryProtections; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model FRTCurrentCalculation + + //Nominal parameter + parameter Types.ApparentPowerModule SNom "Nominal converter apparent power in MVA"; + + //Parameters + parameter Types.PerUnit uLVRTPu "LVRT threshold value" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit uHVRTPu "HVRT threshold value" annotation( + Dialog(tab = "FRT")); + parameter Real K1Ip "Active current factor 1 during LVRT or HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2Ip "Active current factor 2 during LVRT or HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K1Iq "Reactive current factor 1 during LVRT or HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2Iq "Reactive current factor 2 during LVRT or HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KpRT "Active power factor during LVRT or HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KqRT "Reactive power factor during LVRT or HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iPSetPu "Active current setting during LVRT or HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iQSetPu "Reactive current setting during LVRT or HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit pSetPu "Active power setting during LVRT or HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit qSetPu "Reactive power setting during LVRT or HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit uRTPu "LVRT or HVRT threshold value" annotation( + Dialog(tab = "FRT")); + Types.PerUnit pPreFaultPu(start = 0); + Types.PerUnit qPreFaultPu(start = 0); + + //Input variables + Modelica.Blocks.Interfaces.RealInput iPcmdPu(start = -P0Pu * SystemBase.SnRef / (SNom * U0Pu)) "Active current command" annotation( + Placement(visible = true, transformation(origin = {-120, 80}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 40}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput iQcmdPu(start = Q0Pu * SystemBase.SnRef / (SNom * U0Pu)) "Reactive current command" annotation( + Placement(visible = true, transformation(origin = {-120, 40}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput uMeasPu(start = U0Pu) "Filtered voltage amplitude at grid terminal in pu (base UNom)" annotation( + Placement(visible = true, transformation(origin = {-120, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 80}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput pMeasPu(start = U0Pu) "Filtered active power at grid terminal in pu (base SNom) (generator convention)" annotation( + Placement(visible = true, transformation(origin = {-120, -40}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, -40}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput qMeasPu(start = U0Pu) "Filtered reactive power at grid terminal in pu (base SNom) (generator convention)" annotation( + Placement(visible = true, transformation(origin = {-120, -80}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, -80}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + + //Output variables + Modelica.Blocks.Interfaces.RealOutput ipRTPu0 annotation( + Placement(visible = true, transformation(origin = {110, 70}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput ipRTPu1 annotation( + Placement(visible = true, transformation(origin = {110, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iqRTPu0 annotation( + Placement(visible = true, transformation(origin = {110, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iqRTPu1 annotation( + Placement(visible = true, transformation(origin = {110, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + //Initial parameters + parameter Types.VoltageModulePu U0Pu "Initial voltage amplitude at grid terminal in pu (base UNom)" annotation( + Dialog(group = "Operating point")); + parameter Types.ActivePowerPu P0Pu "Initial active power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.ReactivePowerPu Q0Pu "Initial reactive power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + +equation + //PreFault powers for the fault control loop + when uMeasPu < uLVRTPu then + pPreFaultPu = pre(pMeasPu); + qPreFaultPu = pre(qMeasPu); + elsewhen uMeasPu > uHVRTPu then + pPreFaultPu = pre(pMeasPu); + qPreFaultPu = pre(qMeasPu); + end when; + + ipRTPu0 = K1Ip * uMeasPu + K2Ip * iPcmdPu + iPSetPu; + ipRTPu1 = (KpRT * pPreFaultPu + pSetPu) / uMeasPu; + iqRTPu0 = K1Iq * (uRTPu - uMeasPu) + K2Iq * iQcmdPu + iQSetPu; + iqRTPu1 = (KqRT * qPreFaultPu + qSetPu) / uMeasPu; + + annotation( + Icon(graphics = {Rectangle(extent = {{-100, 100}, {100, -100}}), Text(extent = {{-100, 100}, {100, -100}}, textString = "FRT +Current +Calculat°")})); +end FRTCurrentCalculation; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/AuxiliaryProtections/package.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/AuxiliaryProtections/package.mo new file mode 100644 index 00000000000..6df2daf5188 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/AuxiliaryProtections/package.mo @@ -0,0 +1,17 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.Protections; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +package AuxiliaryProtections + extends Icons.Package; +end AuxiliaryProtections; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/AuxiliaryProtections/package.order b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/AuxiliaryProtections/package.order new file mode 100644 index 00000000000..d5cc84e858e --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/AuxiliaryProtections/package.order @@ -0,0 +1,2 @@ +FRTCurrentBounds +FRTCurrentCalculation diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/AuxiliaryProtections/FRTCurrentBounds.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/AuxiliaryProtections/FRTCurrentBounds.mo new file mode 100644 index 00000000000..27e324d25c6 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/AuxiliaryProtections/FRTCurrentBounds.mo @@ -0,0 +1,57 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.Protections.BaseProtections.AuxiliaryProtections; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model FRTCurrentBounds + + //Parameters + parameter Types.PerUnit IMaxPu "Maximum current" annotation( + Dialog(tab = "FRT")); + parameter Boolean pqFRTFlag "Active/reactive control priority, 0/1" annotation( + Dialog(tab = "FRT")); + + //Input variables + Modelica.Blocks.Interfaces.RealInput ipLVRTPrimPu annotation( + Placement(visible = true, transformation(origin = {-120, 40}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 40}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput iqLVRTPrimPu annotation( + Placement(visible = true, transformation(origin = {-120, -40}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, -40}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput iQMaxPu annotation( + Placement(visible = true, transformation(origin = {40, -120}, extent = {{-20, -20}, {20, 20}}, rotation = 90), iconTransformation(origin = {40, -120}, extent = {{-20, -20}, {20, 20}}, rotation = 90))); + Modelica.Blocks.Interfaces.RealInput iQMinPu annotation( + Placement(visible = true, transformation(origin = {-40, -120}, extent = {{-20, -20}, {20, 20}}, rotation = 90), iconTransformation(origin = {-40, -120}, extent = {{-20, -20}, {20, 20}}, rotation = 90))); + Modelica.Blocks.Interfaces.RealInput iPMinPu annotation( + Placement(visible = true, transformation(origin = {-40, 120}, extent = {{-20, -20}, {20, 20}}, rotation = -90), iconTransformation(origin = {-40, 120}, extent = {{-20, -20}, {20, 20}}, rotation = -90))); + Modelica.Blocks.Interfaces.RealInput iPMaxPu annotation( + Placement(visible = true, transformation(origin = {40, 120}, extent = {{-20, -20}, {20, 20}}, rotation = -90), iconTransformation(origin = {40, 120}, extent = {{-20, -20}, {20, 20}}, rotation = -90))); + + //Output variables + Modelica.Blocks.Interfaces.RealOutput ipMinPu annotation( + Placement(visible = true, transformation(origin = {110, 32}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput ipMaxPu annotation( + Placement(visible = true, transformation(origin = {110, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iqMaxPu annotation( + Placement(visible = true, transformation(origin = {110, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iqMinPu annotation( + Placement(visible = true, transformation(origin = {110, -46}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + +equation + ipMaxPu = if pqFRTFlag then min(sqrt(max(IMaxPu ^ 2 - iqLVRTPrimPu ^ 2, 0)), iPMaxPu) else min(IMaxPu, iPMaxPu); + ipMinPu = 0; + iqMaxPu = if pqFRTFlag then min(IMaxPu, iQMaxPu) else min(sqrt(max(IMaxPu ^ 2 - ipLVRTPrimPu ^ 2, 0)), iQMaxPu); + iqMinPu = if pqFRTFlag then max(-IMaxPu, iQMinPu) else max(-sqrt(max(IMaxPu ^ 2 - ipLVRTPrimPu ^ 2, 0)), iQMinPu); + + annotation( + Diagram(graphics = {Rectangle(extent = {{-100, 100}, {100, -100}}), Text(extent = {{-100, 100}, {100, -100}}, textString = "Ip & Iq \nBounds")}), + Icon(graphics = {Text(extent = {{-100, 100}, {100, -100}}, textString = "Ip&Iq +limiter"), Rectangle(extent = {{-100, 100}, {100, -100}})})); +end FRTCurrentBounds; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/AuxiliaryProtections/FRTCurrentCalculation.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/AuxiliaryProtections/FRTCurrentCalculation.mo new file mode 100644 index 00000000000..8a2232109f2 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/AuxiliaryProtections/FRTCurrentCalculation.mo @@ -0,0 +1,99 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.Protections.BaseProtections.AuxiliaryProtections; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model FRTCurrentCalculation + + //Nominal parameter + parameter Types.ApparentPowerModule SNom "Nominal converter apparent power in MVA"; + + //Parameters + parameter Types.PerUnit uLVRTPu "LVRT threshold value" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit uHVRTPu "HVRT threshold value" annotation( + Dialog(tab = "FRT")); + parameter Real K1Ip "Active current factor 1 during LVRT or HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2Ip "Active current factor 2 during LVRT or HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K1Iq "Reactive current factor 1 during LVRT or HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2Iq "Reactive current factor 2 during LVRT or HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KpRT "Active power factor during LVRT or HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KqRT "Reactive power factor during LVRT or HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iPSetPu "Active current setting during LVRT or HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iQSetPu "Reactive current setting during LVRT or HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit pSetPu "Active power setting during LVRT or HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit qSetPu "Reactive power setting during LVRT or HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit uRTPu "LVRT or HVRT threshold value" annotation( + Dialog(tab = "FRT")); + Types.PerUnit pPreFaultPu(start = 0); + Types.PerUnit qPreFaultPu(start = 0); + + //Input variables + Modelica.Blocks.Interfaces.RealInput iPcmdPu(start = -P0Pu * SystemBase.SnRef / (SNom * U0Pu)) "Active current command" annotation( + Placement(visible = true, transformation(origin = {-120, 80}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 40}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput iQcmdPu(start = Q0Pu * SystemBase.SnRef / (SNom * U0Pu)) "Reactive current command" annotation( + Placement(visible = true, transformation(origin = {-120, 40}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput uMeasPu(start = U0Pu) "Filtered voltage amplitude at grid terminal in pu (base UNom)" annotation( + Placement(visible = true, transformation(origin = {-120, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 80}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput pMeasPu(start = U0Pu) "Filtered active power at grid terminal in pu (base SNom) (generator convention)" annotation( + Placement(visible = true, transformation(origin = {-120, -40}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, -40}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput qMeasPu(start = U0Pu) "Filtered reactive power at grid terminal in pu (base SNom) (generator convention)" annotation( + Placement(visible = true, transformation(origin = {-120, -80}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, -80}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + + //Output variables + Modelica.Blocks.Interfaces.RealOutput ipRTPu0 annotation( + Placement(visible = true, transformation(origin = {110, 70}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput ipRTPu1 annotation( + Placement(visible = true, transformation(origin = {110, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iqRTPu0 annotation( + Placement(visible = true, transformation(origin = {110, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iqRTPu1 annotation( + Placement(visible = true, transformation(origin = {110, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + //Initial parameters + parameter Types.VoltageModulePu U0Pu "Initial voltage amplitude at grid terminal in pu (base UNom)" annotation( + Dialog(group = "Operating point")); + parameter Types.ActivePowerPu P0Pu "Initial active power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.ReactivePowerPu Q0Pu "Initial reactive power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + +equation + //PreFault powers for the fault control loop + when uMeasPu < uLVRTPu then + pPreFaultPu = pre(pMeasPu); + qPreFaultPu = pre(qMeasPu); + elsewhen uMeasPu > uHVRTPu then + pPreFaultPu = pre(pMeasPu); + qPreFaultPu = pre(qMeasPu); + end when; + + ipRTPu0 = K1Ip * uMeasPu + K2Ip * iPcmdPu + iPSetPu; + ipRTPu1 = (KpRT * pPreFaultPu + pSetPu) / uMeasPu; + iqRTPu0 = K1Iq * (uRTPu - uMeasPu) + K2Iq * iQcmdPu + iQSetPu; + iqRTPu1 = (KqRT * qPreFaultPu + qSetPu) / uMeasPu; + + annotation( + Icon(graphics = {Rectangle(extent = {{-100, 100}, {100, -100}}), Text(extent = {{-100, 100}, {100, -100}}, textString = "FRT +Current +Calculat°")})); +end FRTCurrentCalculation; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/AuxiliaryProtections/package.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/AuxiliaryProtections/package.mo new file mode 100644 index 00000000000..db77fddab84 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/AuxiliaryProtections/package.mo @@ -0,0 +1,17 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.Protections.BaseProtections; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +package AuxiliaryProtections + extends Icons.Package; +end AuxiliaryProtections; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/AuxiliaryProtections/package.order b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/AuxiliaryProtections/package.order new file mode 100644 index 00000000000..d5cc84e858e --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/AuxiliaryProtections/package.order @@ -0,0 +1,2 @@ +FRTCurrentBounds +FRTCurrentCalculation diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/FRTControl.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/FRTControl.mo new file mode 100644 index 00000000000..014123982d0 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/FRTControl.mo @@ -0,0 +1,259 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.Protections.BaseProtections; + +model FRTControl + + //Nominal parameter + parameter Types.ApparentPowerModule SNom "Nominal converter apparent power in MVA"; + + //LVRT and HVRT parameters + parameter Types.PerUnit uLVRTPu "LVRT threshold value" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit uHVRTPu "HVRT threshold value" annotation( + Dialog(tab = "FRT")); + parameter Boolean LVRTinPFlag "Active current flag during LVRT, 0/1" annotation( + Dialog(tab = "FRT")); + parameter Boolean LVRTinQFlag "Reactive current flag during LVRT, 0/1" annotation( + Dialog(tab = "FRT")); + parameter Boolean HVRTinPFlag "Active current flag during HVRT, 0/1" annotation( + Dialog(tab = "FRT")); + parameter Boolean HVRTinQFlag "Reactive current flag during HVRT, 0/1" annotation( + Dialog(tab = "FRT")); + + parameter Real K1IpLV "Active current factor 1 during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2IpLV "Active current factor 2 during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K1IqLV "Reactive current factor 1 during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2IqLV "Reactive current factor 2 during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KpLVRT "Active power factor during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KqLVRT "Reactive power factor during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iPSetLVPu "Active current setting during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iQSetLVPu "Reactive current setting during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit pSetLVPu "Active power setting during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit qSetLVPu "Reactive power setting during LVRT" annotation( + Dialog(tab = "FRT")); + + parameter Real K1IpHV "Active current factor 1 during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2IpHV "Active current factor 2 during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K1IqHV "Reactive current factor 1 during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2IqHV "Reactive current factor 2 during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KpHVRT "Active power factor during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KqHVRT "Reactive power factor during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iPSetHVPu "Active current setting during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iQSetHVPu "Reactive current setting during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit pSetHVPu "Active power setting during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit qSetHVPu "Reactive power setting during HVRT" annotation( + Dialog(tab = "FRT")); + + parameter Types.PerUnit IMaxPu "Maximum current" annotation( + Dialog(tab = "FRT")); + parameter Boolean pqFRTFlag "Active/reactive control priority, 0/1" annotation( + Dialog(tab = "FRT")); + + //Input variables + Modelica.Blocks.Interfaces.RealInput iPcmdPu(start=-P0Pu*SystemBase.SnRef/(SNom*U0Pu)) "Active current command" annotation( + Placement(visible = true, transformation(origin = {-180, 60}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-180, 120}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput iQcmdPu(start=Q0Pu*SystemBase.SnRef/(SNom*U0Pu)) "Reactive current command" annotation( + Placement(visible = true, transformation(origin = {-180, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-180, 60}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput uMeasPu(start=U0Pu) "Measured (and filtered) voltage component" annotation( + Placement(visible = true, transformation(origin = {-180, 120}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-180, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput pMeasPu(start = -P0Pu * SystemBase.SnRef / (SNom * U0Pu)) annotation( + Placement(visible = true, transformation(origin = {-180, -60}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-180, -60}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput qMeasPu(start = -Q0Pu * SystemBase.SnRef / (SNom * U0Pu)) annotation( + Placement(visible = true, transformation(origin = {-180, -120}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-180, -120}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput iPMinPu(start = IPMin0Pu) annotation( + Placement(visible = true, transformation(origin = {52, 170}, extent = {{-10, -10}, {10, 10}}, rotation = -90), iconTransformation(origin = {-100, 180}, extent = {{-20, -20}, {20, 20}}, rotation = -90))); + Modelica.Blocks.Interfaces.RealInput iPMaxPu(start = IPMax0Pu) annotation( + Placement(visible = true, transformation(origin = {68, 170}, extent = {{-10, -10}, {10, 10}}, rotation = -90), iconTransformation(origin = {-40, 180}, extent = {{-20, -20}, {20, 20}}, rotation = -90))); + Modelica.Blocks.Interfaces.RealInput iQMinPu(start = IQMin0Pu) annotation( + Placement(visible = true, transformation(origin = {52, -170}, extent = {{-10, -10}, {10, 10}}, rotation = 90), iconTransformation(origin = {-100, -180}, extent = {{20, 20}, {-20, -20}}, rotation = -90))); + Modelica.Blocks.Interfaces.RealInput iQMaxPu(start = IQMax0Pu) annotation( + Placement(visible = true, transformation(origin = {68, -170}, extent = {{10, -10}, {-10, 10}}, rotation = -90), iconTransformation(origin = {-40, -180}, extent = {{20, -20}, {-20, 20}}, rotation = -90))); + + //Output variables + Modelica.Blocks.Interfaces.RealOutput ippPu(start=-P0Pu*SystemBase.SnRef/(SNom*U0Pu)) "Intermediary active current command in protection block" annotation( + Placement(visible = true, transformation(origin = {180, 100}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {180, 100}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iqqPu(start=Q0Pu*SystemBase.SnRef/(SNom*U0Pu)) "Intermediary reactive current command in protection block" annotation( + Placement(visible = true, transformation(origin = {180, 60}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {180, 60}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput ipLVRTPu annotation( + Placement(visible = true, transformation(origin = {170, 140}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {170, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iqLVRTPu annotation( + Placement(visible = true, transformation(origin = {170, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {170, -90}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput ipHVRTPu annotation( + Placement(visible = true, transformation(origin = {170, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {170, -10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iqHVRTPu annotation( + Placement(visible = true, transformation(origin = {170, -140}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {170, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + //Initial parameters + parameter Types.PerUnit IPMin0Pu annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IPMax0Pu annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IQMin0Pu annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IQMax0Pu annotation( + Dialog(tab = "Operating point")); + + parameter Types.VoltageModulePu U0Pu "Initial voltage amplitude at grid terminal in pu (base UNom)" annotation( + Dialog(group="Operating point")); + parameter Types.ActivePowerPu P0Pu "Initial active power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.ReactivePowerPu Q0Pu "Initial reactive power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + + Modelica.Blocks.Logical.Switch switch1 annotation( + Placement(visible = true, transformation(origin = {-20, 140}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Logical.Switch switch11 annotation( + Placement(visible = true, transformation(origin = {-20, 20}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Sources.BooleanExpression booleanExpression(y = LVRTinPFlag) annotation( + Placement(visible = true, transformation(origin = {-80, 140}, extent = {{-20, -10}, {20, 10}}, rotation = 0))); + Modelica.Blocks.Sources.BooleanExpression booleanExpression1(y = LVRTinQFlag) annotation( + Placement(visible = true, transformation(origin = {-80, 20}, extent = {{-20, -10}, {20, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.VariableLimiter variableLimiter annotation( + Placement(visible = true, transformation(origin = {140, 140}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.VariableLimiter variableLimiter1 annotation( + Placement(visible = true, transformation(origin = {140, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.VariableLimiter variableLimiter2 annotation( + Placement(visible = true, transformation(origin = {140, -140}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Switch switch12 annotation( + Placement(visible = true, transformation(origin = {-20, -140}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.VariableLimiter variableLimiter3 annotation( + Placement(visible = true, transformation(origin = {140, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Switch switch13 annotation( + Placement(visible = true, transformation(origin = {-20, -20}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Sources.BooleanExpression booleanExpression2(y = HVRTinQFlag) annotation( + Placement(visible = true, transformation(origin = {-80, -140}, extent = {{-20, -10}, {20, 10}}, rotation = 0))); + Modelica.Blocks.Sources.BooleanExpression booleanExpression3(y = HVRTinPFlag) annotation( + Placement(visible = true, transformation(origin = {-80, -20}, extent = {{-20, -10}, {20, 10}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.Protections.BaseProtections.AuxiliaryProtections.FRTCurrentBounds LVRTCurrentBounds annotation( + Placement(visible = true, transformation(origin = {60, 80}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.Protections.BaseProtections.AuxiliaryProtections.FRTCurrentBounds HVRTCurrentBounds1 annotation( + Placement(visible = true, transformation(origin = {60, -80}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.Protections.BaseProtections.AuxiliaryProtections.FRTCurrentCalculation LVRTCurrentCalculation annotation( + Placement(visible = true, transformation(origin = {-80, 80}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.Protections.BaseProtections.AuxiliaryProtections.FRTCurrentCalculation HVRTCurrentCalculation annotation( + Placement(visible = true, transformation(origin = {-80, -80}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + +equation + ippPu = if uMeasPu > uHVRTPu then ipHVRTPu else if uMeasPu < uLVRTPu then ipLVRTPu else iPcmdPu; + iqqPu = if uMeasPu > uHVRTPu then iqHVRTPu else if uMeasPu < uLVRTPu then iqLVRTPu else iQcmdPu; + connect(booleanExpression1.y, switch11.u2) annotation( + Line(points = {{-58, 20}, {-32, 20}}, color = {255, 0, 255})); + connect(booleanExpression.y, switch1.u2) annotation( + Line(points = {{-58, 140}, {-31.8, 140}}, color = {255, 0, 255})); + connect(switch11.y, variableLimiter1.u) annotation( + Line(points = {{-9, 20}, {128, 20}}, color = {0, 0, 127})); + connect(variableLimiter1.y, iqLVRTPu) annotation( + Line(points = {{151, 20}, {170, 20}}, color = {0, 0, 127})); + connect(switch1.y, variableLimiter.u) annotation( + Line(points = {{-9, 140}, {128, 140}}, color = {0, 0, 127})); + connect(variableLimiter.y, ipLVRTPu) annotation( + Line(points = {{151, 140}, {170, 140}}, color = {0, 0, 127})); + connect(switch12.y, variableLimiter2.u) annotation( + Line(points = {{-9, -140}, {128, -140}}, color = {0, 0, 127})); + connect(switch13.y, variableLimiter3.u) annotation( + Line(points = {{-9, -20}, {128, -20}}, color = {0, 0, 127})); + connect(variableLimiter3.y, ipHVRTPu) annotation( + Line(points = {{151, -20}, {170, -20}}, color = {0, 0, 127})); + connect(variableLimiter2.y, iqHVRTPu) annotation( + Line(points = {{151, -140}, {170, -140}}, color = {0, 0, 127})); + connect(booleanExpression2.y, switch12.u2) annotation( + Line(points = {{-58, -140}, {-32, -140}}, color = {255, 0, 255})); + connect(booleanExpression3.y, switch13.u2) annotation( + Line(points = {{-58, -20}, {-32, -20}}, color = {255, 0, 255})); + connect(uMeasPu, LVRTCurrentCalculation.uMeasPu) annotation( + Line(points = {{-180, 120}, {-112, 120}, {-112, 96}, {-104, 96}}, color = {0, 0, 127})); + connect(uMeasPu, HVRTCurrentCalculation.uMeasPu) annotation( + Line(points = {{-180, 120}, {-112, 120}, {-112, -64}, {-104, -64}}, color = {0, 0, 127})); + connect(iPcmdPu, LVRTCurrentCalculation.iPcmdPu) annotation( + Line(points = {{-180, 60}, {-120, 60}, {-120, 88}, {-104, 88}}, color = {0, 0, 127})); + connect(iPcmdPu, HVRTCurrentCalculation.iPcmdPu) annotation( + Line(points = {{-180, 60}, {-120, 60}, {-120, -72}, {-104, -72}}, color = {0, 0, 127})); + connect(iQcmdPu, LVRTCurrentCalculation.iQcmdPu) annotation( + Line(points = {{-180, 0}, {-130, 0}, {-130, 80}, {-104, 80}}, color = {0, 0, 127})); + connect(iQcmdPu, HVRTCurrentCalculation.iQcmdPu) annotation( + Line(points = {{-180, 0}, {-130, 0}, {-130, -80}, {-104, -80}}, color = {0, 0, 127})); + connect(pMeasPu, HVRTCurrentCalculation.pMeasPu) annotation( + Line(points = {{-180, -60}, {-140, -60}, {-140, -88}, {-104, -88}}, color = {0, 0, 127})); + connect(pMeasPu, LVRTCurrentCalculation.pMeasPu) annotation( + Line(points = {{-180, -60}, {-140, -60}, {-140, 72}, {-104, 72}}, color = {0, 0, 127})); + connect(qMeasPu, LVRTCurrentCalculation.qMeasPu) annotation( + Line(points = {{-180, -120}, {-150, -120}, {-150, 64}, {-104, 64}}, color = {0, 0, 127})); + connect(qMeasPu, HVRTCurrentCalculation.qMeasPu) annotation( + Line(points = {{-180, -120}, {-150, -120}, {-150, -96}, {-104, -96}}, color = {0, 0, 127})); + connect(LVRTCurrentCalculation.ipRTPu0, switch1.u3) annotation( + Line(points = {{-58, 94}, {-48, 94}, {-48, 148}, {-32, 148}}, color = {0, 0, 127})); + connect(LVRTCurrentCalculation.ipRTPu1, switch1.u1) annotation( + Line(points = {{-58, 86}, {-40, 86}, {-40, 132}, {-32, 132}}, color = {0, 0, 127})); + connect(LVRTCurrentCalculation.iqRTPu0, switch11.u3) annotation( + Line(points = {{-58, 74}, {-40, 74}, {-40, 28}, {-32, 28}}, color = {0, 0, 127})); + connect(LVRTCurrentCalculation.iqRTPu1, switch11.u1) annotation( + Line(points = {{-58, 66}, {-48, 66}, {-48, 12}, {-32, 12}}, color = {0, 0, 127})); + connect(HVRTCurrentCalculation.ipRTPu0, switch13.u3) annotation( + Line(points = {{-58, -66}, {-50, -66}, {-50, -12}, {-32, -12}}, color = {0, 0, 127})); + connect(HVRTCurrentCalculation.ipRTPu1, switch13.u1) annotation( + Line(points = {{-58, -74}, {-40, -74}, {-40, -28}, {-32, -28}}, color = {0, 0, 127})); + connect(HVRTCurrentCalculation.iqRTPu0, switch12.u3) annotation( + Line(points = {{-58, -86}, {-40, -86}, {-40, -132}, {-32, -132}}, color = {0, 0, 127})); + connect(HVRTCurrentCalculation.iqRTPu1, switch12.u1) annotation( + Line(points = {{-58, -94}, {-50, -94}, {-50, -148}, {-32, -148}}, color = {0, 0, 127})); + connect(switch13.y, HVRTCurrentBounds1.ipLVRTPrimPu) annotation( + Line(points = {{-9, -20}, {0, -20}, {0, -72}, {36, -72}}, color = {0, 0, 127})); + connect(switch12.y, HVRTCurrentBounds1.iqLVRTPrimPu) annotation( + Line(points = {{-9, -140}, {0, -140}, {0, -88}, {36, -88}}, color = {0, 0, 127})); + connect(switch11.y, LVRTCurrentBounds.iqLVRTPrimPu) annotation( + Line(points = {{-9, 20}, {0, 20}, {0, 72}, {36, 72}}, color = {0, 0, 127})); + connect(switch1.y, LVRTCurrentBounds.ipLVRTPrimPu) annotation( + Line(points = {{-9, 140}, {0, 140}, {0, 88}, {36, 88}}, color = {0, 0, 127})); + connect(LVRTCurrentBounds.ipMaxPu, variableLimiter.limit1) annotation( + Line(points = {{82, 94}, {110, 94}, {110, 148}, {128, 148}}, color = {0, 0, 127})); + connect(LVRTCurrentBounds.ipMinPu, variableLimiter.limit2) annotation( + Line(points = {{82, 86}, {120, 86}, {120, 132}, {128, 132}}, color = {0, 0, 127})); + connect(LVRTCurrentBounds.iqMaxPu, variableLimiter1.limit1) annotation( + Line(points = {{82, 74}, {120, 74}, {120, 28}, {128, 28}}, color = {0, 0, 127})); + connect(LVRTCurrentBounds.iqMinPu, variableLimiter1.limit2) annotation( + Line(points = {{82, 66}, {110, 66}, {110, 12}, {128, 12}}, color = {0, 0, 127})); + connect(HVRTCurrentBounds1.ipMaxPu, variableLimiter3.limit1) annotation( + Line(points = {{82, -66}, {110, -66}, {110, -12}, {128, -12}}, color = {0, 0, 127})); + connect(HVRTCurrentBounds1.ipMinPu, variableLimiter3.limit2) annotation( + Line(points = {{82, -74}, {120, -74}, {120, -28}, {128, -28}}, color = {0, 0, 127})); + connect(HVRTCurrentBounds1.iqMaxPu, variableLimiter2.limit1) annotation( + Line(points = {{82, -86}, {120, -86}, {120, -132}, {128, -132}}, color = {0, 0, 127})); + connect(HVRTCurrentBounds1.iqMinPu, variableLimiter2.limit2) annotation( + Line(points = {{82, -94}, {110, -94}, {110, -148}, {128, -148}}, color = {0, 0, 127})); + connect(iPMinPu, LVRTCurrentBounds.iPMinPu) annotation( + Line(points = {{52, 170}, {52, 104}}, color = {0, 0, 127})); + connect(iPMaxPu, LVRTCurrentBounds.iPMaxPu) annotation( + Line(points = {{68, 170}, {68, 104}}, color = {0, 0, 127})); + connect(iQMinPu, HVRTCurrentBounds1.iQMinPu) annotation( + Line(points = {{52, -170}, {52, -104}}, color = {0, 0, 127})); + connect(iQMaxPu, HVRTCurrentBounds1.iQMaxPu) annotation( + Line(points = {{68, -170}, {68, -104}}, color = {0, 0, 127})); + connect(iPMinPu, HVRTCurrentBounds1.iPMinPu) annotation( + Line(points = {{52, 170}, {52, 130}, {10, 130}, {10, -40}, {52, -40}, {52, -56}}, color = {0, 0, 127})); + connect(iPMaxPu, HVRTCurrentBounds1.iPMaxPu) annotation( + Line(points = {{68, 170}, {68, 120}, {20, 120}, {20, -30}, {68, -30}, {68, -56}}, color = {0, 0, 127})); + connect(iQMaxPu, LVRTCurrentBounds.iQMaxPu) annotation( + Line(points = {{68, -170}, {68, -130}, {100, -130}, {100, 40}, {68, 40}, {68, 56}}, color = {0, 0, 127})); + connect(iQMinPu, LVRTCurrentBounds.iQMinPu) annotation( + Line(points = {{52, -170}, {52, -120}, {90, -120}, {90, 30}, {52, 30}, {52, 56}}, color = {0, 0, 127})); + annotation( + Icon(graphics = {Rectangle(extent = {{-160, 160}, {160, -160}}), Text(extent = {{-160, 160}, {160, -160}}, textString = "FRT\nControl")}, coordinateSystem(extent = {{-160, -160}, {160, 160}})), + Diagram(coordinateSystem(extent = {{-160, -160}, {160, 160}}))); +end FRTControl; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/Protection.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/Protection.mo new file mode 100644 index 00000000000..1b3ffaffb43 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/Protection.mo @@ -0,0 +1,450 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.Protections.BaseProtections; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model Protection + + // Voltage protection table parameters + parameter Real TLVP3 = 0.3 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real TLVP2 = 0.5 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real TLVP1 = 1 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real THVP1 = 1 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real THVP2 = 0.5 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real THVP3 = 0.3 annotation( + Dialog(tab = "GridProtectionTables")); + + parameter Real ULVP3 = 0.80 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real ULVP2 = 0.85 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real ULVP1 = 0.90 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real UHVP1 = 1.1 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real UHVP2 = 1.15 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real UHVP3 = 1.2 annotation( + Dialog(tab = "GridProtectionTables")); + + parameter Real TabletUProtection[:,:] = [0, TLVP3; ULVP3-0.001, TLVP3; ULVP3, TLVP2; ULVP2-0.001, TLVP2; ULVP2, TLVP1; ULVP1-0.001, TLVP1; ULVP1, Modelica.Constants.inf; UHVP1, Modelica.Constants.inf; UHVP1+0.001, THVP1; UHVP2, THVP1; UHVP2+0.001, THVP2; UHVP3, THVP2; UHVP3+0.001, THVP3; 1000, THVP3] "Disconnection time versus over voltage lookup table" annotation( + Dialog(tab = "GridProtectionTables")); + + // Frequency protection table parameters + parameter Real TLfP3 = 0.25 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real TLfP2 = 0.5 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real TLfP1 = 1 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real THfP1 = 1 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real THfP2 = 0.5 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real THfP3 = 0.25 annotation( + Dialog(tab = "GridProtectionTables")); + + parameter Real fLfP3 = 0.98 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real fLfP2 = 0.99 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real fLfP1 = 0.996 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real fHfP1 = 1.004 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real fHfP2 = 1.01 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real fHfP3 = 1.02 annotation( + Dialog(tab = "GridProtectionTables")); + + parameter Real TabletfProtection[:,:] = [0, TLfP3; fLfP3-0.001, TLfP3; fLfP3, TLfP2; fLfP2-0.001, TLfP2; fLfP2, TLfP1; fLfP1-0.001, TLfP1; fLfP1, Modelica.Constants.inf; fHfP1, Modelica.Constants.inf; fHfP1+0.001, THfP1; fHfP2, THfP1; fHfP2+0.001, THfP2; fHfP3, THfP2; fHfP3+0.001, THfP3; 1000, THfP3] "Disconnection time versus over voltage lookup table" annotation( + Dialog(tab = "GridProtectionTables")); + + // Derivatives parameters + + parameter Real DerfMaxPu = 0.02 annotation( + Dialog(tab = "Protection")); + parameter Real TDerfMax = 0.5 annotation( + Dialog(tab = "Protection")); + parameter Real DerThetaMax = 1 annotation( + Dialog(tab = "Protection")); + parameter Real TDerThetaMax = 0.5 annotation( + Dialog(tab = "Protection")); + + //Input variables + Modelica.Blocks.Interfaces.RealInput uMeasPu(start=U0Pu) "Measured (and filtered) voltage component" annotation( + Placement(visible = true, transformation(origin = {-220, 200}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-239, 161}, extent = {{-39, -39}, {39, 39}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput fMeasPu(start=fInitPu) "Measured frequency outputted by the phase-locked loop" annotation( + Placement(visible = true, transformation(origin = {-220, -100}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-239, -1}, extent = {{-39, -39}, {39, 39}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput thetaPLL(start=thetaPLL0) "Phase angle outputted by phase-locked loop" annotation( + Placement(visible = true, transformation(origin = {-220, -320}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-239, -159}, extent = {{-39, -39}, {39, 39}}, rotation = 0))); + + //Output variables + Modelica.Blocks.Interfaces.BooleanOutput tripFlag(start = false) annotation( + Placement(visible = true, transformation(origin = {220, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {240, 0}, extent = {{-40, -40}, {40, 40}}, rotation = 0))); + + //Initial parameters + parameter Types.VoltageModulePu U0Pu "Initial voltage amplitude at grid terminal in pu (base UNom)" annotation( + Dialog(group="Operating point")); + parameter Types.Angle thetaPLL0 "Initial Phase angle outputted by phase-locked loop" annotation( + Dialog(group="Operating point")); + parameter Types.PerUnit fInitPu "Initial frequency" annotation( + Dialog(tab = "Operating point")); + + Modelica.Blocks.Logical.Timer timer annotation( + Placement(visible = true, transformation(origin = {-10, 240}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Greater greater annotation( + Placement(visible = true, transformation(origin = {110, 240}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual annotation( + Placement(visible = true, transformation(origin = {-70, 240}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant const(k = UHVP1) annotation( + Placement(visible = true, transformation(origin = {-130, 240}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant const2(k = UHVP2) annotation( + Placement(visible = true, transformation(origin = {-130, 280}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual2 annotation( + Placement(visible = true, transformation(origin = {-70, 280}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer2 annotation( + Placement(visible = true, transformation(origin = {-10, 280}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant const3(k = UHVP3) annotation( + Placement(visible = true, transformation(origin = {-130, 320}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual3 annotation( + Placement(visible = true, transformation(origin = {-70, 320}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer3 annotation( + Placement(visible = true, transformation(origin = {-10, 320}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Greater greater1 annotation( + Placement(visible = true, transformation(origin = {110, 280}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Greater greater2 annotation( + Placement(visible = true, transformation(origin = {110, 320}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.Limiter limiter(limitsAtInit = true, uMax = THVP2) annotation( + Placement(visible = true, transformation(origin = {50, 260}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.Limiter limiter1(limitsAtInit = true, uMax = THVP1) annotation( + Placement(visible = true, transformation(origin = {50, 220}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.MathBoolean.Or or1(nu = 14) annotation( + Placement(visible = true, transformation(origin = {170, 1.77636e-15}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant const1(k = ULVP1) annotation( + Placement(visible = true, transformation(origin = {-130, 160}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual1 annotation( + Placement(visible = true, transformation(origin = {-70, 168}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual4 annotation( + Placement(visible = true, transformation(origin = {-70, 128}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant const4(k = ULVP2) annotation( + Placement(visible = true, transformation(origin = {-130, 120}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant const5(k = ULVP3) annotation( + Placement(visible = true, transformation(origin = {-130, 80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual5 annotation( + Placement(visible = true, transformation(origin = {-70, 88}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer1 annotation( + Placement(visible = true, transformation(origin = {-10, 160}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer4 annotation( + Placement(visible = true, transformation(origin = {-10, 120}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer5 annotation( + Placement(visible = true, transformation(origin = {-10, 80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.Limiter limiter2(limitsAtInit = true, uMax = TLVP1) annotation( + Placement(visible = true, transformation(origin = {50, 180}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.Limiter limiter3(limitsAtInit = true, uMax = TLVP2) annotation( + Placement(visible = true, transformation(origin = {50, 140}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual6 annotation( + Placement(visible = true, transformation(origin = {110, 88}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual7 annotation( + Placement(visible = true, transformation(origin = {112, 128}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual8 annotation( + Placement(visible = true, transformation(origin = {110, 168}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Tables.CombiTable1Ds combiTable1Ds(table = TabletUProtection) annotation( + Placement(visible = true, transformation(origin = {-40, 200}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual9 annotation( + Placement(visible = true, transformation(origin = {110, -172}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer6 annotation( + Placement(visible = true, transformation(origin = {-10, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual10 annotation( + Placement(visible = true, transformation(origin = {-70, -212}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual11 annotation( + Placement(visible = true, transformation(origin = {110, -212}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual12 annotation( + Placement(visible = true, transformation(origin = {-70, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Tables.CombiTable1Ds combiTable1Ds1(table = TabletfProtection) annotation( + Placement(visible = true, transformation(origin = {-40, -100}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual13 annotation( + Placement(visible = true, transformation(origin = {-70, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant constant1(k = fLfP2) annotation( + Placement(visible = true, transformation(origin = {-130, -180}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Greater greater3 annotation( + Placement(visible = true, transformation(origin = {110, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant constant2(k = fLfP1) annotation( + Placement(visible = true, transformation(origin = {-130, -140}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer7 annotation( + Placement(visible = true, transformation(origin = {-10, -180}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant constant3(k = fHfP1) annotation( + Placement(visible = true, transformation(origin = {-130, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual14 annotation( + Placement(visible = true, transformation(origin = {-70, -172}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant constant4(k = fHfP3) annotation( + Placement(visible = true, transformation(origin = {-130, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual15 annotation( + Placement(visible = true, transformation(origin = {110, -132}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer8 annotation( + Placement(visible = true, transformation(origin = {-10, -220}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.Limiter limiter4(limitsAtInit = true, uMax = THfP1) annotation( + Placement(visible = true, transformation(origin = {50, -80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer9 annotation( + Placement(visible = true, transformation(origin = {-10, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant constant5(k = fLfP3) annotation( + Placement(visible = true, transformation(origin = {-130, -220}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer10 annotation( + Placement(visible = true, transformation(origin = {-10, -140}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant constant6(k = fHfP2) annotation( + Placement(visible = true, transformation(origin = {-130, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Greater greater4 annotation( + Placement(visible = true, transformation(origin = {110, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Greater greater5 annotation( + Placement(visible = true, transformation(origin = {110, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.Limiter limiter5(limitsAtInit = true, uMax = TLfP1) annotation( + Placement(visible = true, transformation(origin = {50, -120}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual16 annotation( + Placement(visible = true, transformation(origin = {-70, -132}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.Limiter limiter6(limitsAtInit = true, uMax = TLfP2) annotation( + Placement(visible = true, transformation(origin = {50, -160}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.Limiter limiter7(limitsAtInit = true, uMax = THfP2) annotation( + Placement(visible = true, transformation(origin = {50, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual17 annotation( + Placement(visible = true, transformation(origin = {-70, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer11 annotation( + Placement(visible = true, transformation(origin = {-10, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer12 annotation( + Placement(visible = true, transformation(origin = {-10, -280}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual18 annotation( + Placement(visible = true, transformation(origin = {-70, -272}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant constant7(k = DerfMaxPu) annotation( + Placement(visible = true, transformation(origin = {-130, -260}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual19 annotation( + Placement(visible = true, transformation(origin = {110, -272}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant const6(k = TDerfMax) annotation( + Placement(visible = true, transformation(origin = {50, -260}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant constant8(k = DerThetaMax) annotation( + Placement(visible = true, transformation(origin = {-130, -300}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual20 annotation( + Placement(visible = true, transformation(origin = {110, -312}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual21 annotation( + Placement(visible = true, transformation(origin = {-70, -312}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant constant9(k = TDerThetaMax) annotation( + Placement(visible = true, transformation(origin = {50, -300}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer13 annotation( + Placement(visible = true, transformation(origin = {-10, -320}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Continuous.Derivative derivative1 annotation( + Placement(visible = true, transformation(origin = {-160, -320}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Continuous.Derivative derivative annotation( + Placement(visible = true, transformation(origin = {-160, -280}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + +equation + when or1.y == true then + tripFlag = true; + end when; + connect(lessEqual.y, timer.u) annotation( + Line(points = {{-59, 240}, {-22, 240}}, color = {255, 0, 255})); + connect(const.y, lessEqual.u1) annotation( + Line(points = {{-119, 240}, {-82, 240}}, color = {0, 0, 127})); + connect(const3.y, lessEqual3.u1) annotation( + Line(points = {{-119, 320}, {-82, 320}}, color = {0, 0, 127})); + connect(const2.y, lessEqual2.u1) annotation( + Line(points = {{-119, 280}, {-82, 280}}, color = {0, 0, 127})); + connect(lessEqual3.y, timer3.u) annotation( + Line(points = {{-59, 320}, {-22, 320}}, color = {255, 0, 255})); + connect(lessEqual2.y, timer2.u) annotation( + Line(points = {{-59, 280}, {-22, 280}}, color = {255, 0, 255})); + connect(timer3.y, greater2.u1) annotation( + Line(points = {{1, 320}, {98, 320}}, color = {0, 0, 127})); + connect(timer2.y, greater1.u1) annotation( + Line(points = {{1, 280}, {98, 280}}, color = {0, 0, 127})); + connect(timer.y, greater.u1) annotation( + Line(points = {{1, 240}, {98, 240}}, color = {0, 0, 127})); + connect(limiter.y, greater1.u2) annotation( + Line(points = {{61, 260}, {79.5, 260}, {79.5, 272}, {98, 272}}, color = {0, 0, 127})); + connect(limiter1.y, greater.u2) annotation( + Line(points = {{61, 220}, {79.5, 220}, {79.5, 232}, {98, 232}}, color = {0, 0, 127})); + connect(const5.y, lessEqual5.u2) annotation( + Line(points = {{-119, 80}, {-82, 80}}, color = {0, 0, 127})); + connect(limiter2.y, lessEqual8.u1) annotation( + Line(points = {{61, 180}, {79.5, 180}, {79.5, 168}, {98, 168}}, color = {0, 0, 127})); + connect(limiter3.y, lessEqual7.u1) annotation( + Line(points = {{61, 140}, {79.5, 140}, {79.5, 128}, {100, 128}}, color = {0, 0, 127})); + connect(constant1.y, lessEqual14.u2) annotation( + Line(points = {{-119, -180}, {-82, -180}}, color = {0, 0, 127})); + connect(limiter7.y, greater3.u2) annotation( + Line(points = {{61, -40}, {77.5, -40}, {77.5, -28}, {98, -28}}, color = {0, 0, 127})); + connect(constant5.y, lessEqual10.u2) annotation( + Line(points = {{-119, -220}, {-82, -220}}, color = {0, 0, 127})); + connect(timer6.y, greater5.u1) annotation( + Line(points = {{1, 20}, {98, 20}}, color = {0, 0, 127})); + connect(constant6.y, lessEqual17.u1) annotation( + Line(points = {{-119, -20}, {-82, -20}}, color = {0, 0, 127})); + connect(timer7.y, lessEqual9.u2) annotation( + Line(points = {{1, -180}, {98, -180}}, color = {0, 0, 127})); + connect(lessEqual10.y, timer8.u) annotation( + Line(points = {{-59, -212}, {-40.5, -212}, {-40.5, -220}, {-22, -220}}, color = {255, 0, 255})); + connect(lessEqual12.y, timer11.u) annotation( + Line(points = {{-59, -60}, {-22, -60}}, color = {255, 0, 255})); + connect(lessEqual14.y, timer7.u) annotation( + Line(points = {{-59, -172}, {-40.5, -172}, {-40.5, -180}, {-22, -180}}, color = {255, 0, 255})); + connect(timer8.y, lessEqual11.u2) annotation( + Line(points = {{1, -220}, {98, -220}}, color = {0, 0, 127})); + connect(timer11.y, greater4.u1) annotation( + Line(points = {{1, -60}, {98, -60}}, color = {0, 0, 127})); + connect(timer9.y, greater3.u1) annotation( + Line(points = {{1, -20}, {98, -20}}, color = {0, 0, 127})); + connect(lessEqual17.y, timer9.u) annotation( + Line(points = {{-59, -20}, {-22, -20}}, color = {255, 0, 255})); + connect(constant3.y, lessEqual12.u1) annotation( + Line(points = {{-119, -60}, {-82, -60}}, color = {0, 0, 127})); + connect(limiter6.y, lessEqual9.u1) annotation( + Line(points = {{61, -160}, {77.5, -160}, {77.5, -172}, {98, -172}}, color = {0, 0, 127})); + connect(constant2.y, lessEqual16.u2) annotation( + Line(points = {{-119, -140}, {-82, -140}}, color = {0, 0, 127})); + connect(limiter4.y, greater4.u2) annotation( + Line(points = {{61, -80}, {79.5, -80}, {79.5, -68}, {98, -68}}, color = {0, 0, 127})); + connect(limiter5.y, lessEqual15.u1) annotation( + Line(points = {{61, -120}, {76.5, -120}, {76.5, -132}, {98, -132}}, color = {0, 0, 127})); + connect(lessEqual16.y, timer10.u) annotation( + Line(points = {{-59, -132}, {-40.5, -132}, {-40.5, -140}, {-22, -140}}, color = {255, 0, 255})); + connect(lessEqual13.y, timer6.u) annotation( + Line(points = {{-59, 20}, {-22, 20}}, color = {255, 0, 255})); + connect(constant4.y, lessEqual13.u1) annotation( + Line(points = {{-119, 20}, {-82, 20}}, color = {0, 0, 127})); + connect(timer10.y, lessEqual15.u2) annotation( + Line(points = {{1, -140}, {98, -140}}, color = {0, 0, 127})); + connect(combiTable1Ds.y[1], greater2.u2) annotation( + Line(points = {{-29, 200}, {20, 200}, {20, 312}, {98, 312}}, color = {0, 0, 127})); + connect(combiTable1Ds.y[1], limiter.u) annotation( + Line(points = {{-29, 200}, {20, 200}, {20, 260}, {38, 260}}, color = {0, 0, 127})); + connect(combiTable1Ds.y[1], limiter1.u) annotation( + Line(points = {{-29, 200}, {20, 200}, {20, 220}, {38, 220}}, color = {0, 0, 127})); + connect(combiTable1Ds.y[1], limiter2.u) annotation( + Line(points = {{-29, 200}, {20, 200}, {20, 180}, {38, 180}}, color = {0, 0, 127})); + connect(combiTable1Ds.y[1], limiter3.u) annotation( + Line(points = {{-29, 200}, {20, 200}, {20, 140}, {38, 140}}, color = {0, 0, 127})); + connect(combiTable1Ds.y[1], lessEqual6.u1) annotation( + Line(points = {{-29, 200}, {20, 200}, {20, 88}, {98, 88}}, color = {0, 0, 127})); + connect(timer1.y, lessEqual8.u2) annotation( + Line(points = {{1, 160}, {98, 160}}, color = {0, 0, 127})); + connect(timer4.y, lessEqual7.u2) annotation( + Line(points = {{1, 120}, {100, 120}}, color = {0, 0, 127})); + connect(timer5.y, lessEqual6.u2) annotation( + Line(points = {{1, 80}, {98, 80}}, color = {0, 0, 127})); + connect(uMeasPu, combiTable1Ds.u) annotation( + Line(points = {{-220, 200}, {-52, 200}}, color = {0, 0, 127})); + connect(fMeasPu, combiTable1Ds1.u) annotation( + Line(points = {{-220, -100}, {-52, -100}}, color = {0, 0, 127})); + connect(const1.y, lessEqual1.u2) annotation( + Line(points = {{-119, 160}, {-83, 160}}, color = {0, 0, 127})); + connect(lessEqual4.y, timer4.u) annotation( + Line(points = {{-59, 128}, {-41, 128}, {-41, 120}, {-23, 120}}, color = {255, 0, 255})); + connect(lessEqual1.y, timer1.u) annotation( + Line(points = {{-59, 168}, {-40, 168}, {-40, 160}, {-22, 160}}, color = {255, 0, 255})); + connect(lessEqual5.y, timer5.u) annotation( + Line(points = {{-59, 88}, {-41, 88}, {-41, 80}, {-23, 80}}, color = {255, 0, 255})); + connect(const4.y, lessEqual4.u2) annotation( + Line(points = {{-119, 120}, {-83, 120}}, color = {0, 0, 127})); + connect(combiTable1Ds1.y[1], limiter7.u) annotation( + Line(points = {{-29, -100}, {19, -100}, {19, -40}, {37, -40}}, color = {0, 0, 127})); + connect(combiTable1Ds1.y[1], limiter4.u) annotation( + Line(points = {{-29, -100}, {19, -100}, {19, -80}, {37, -80}}, color = {0, 0, 127})); + connect(combiTable1Ds1.y[1], limiter5.u) annotation( + Line(points = {{-29, -100}, {19, -100}, {19, -120}, {37, -120}}, color = {0, 0, 127})); + connect(combiTable1Ds1.y[1], limiter6.u) annotation( + Line(points = {{-29, -100}, {19, -100}, {19, -160}, {37, -160}}, color = {0, 0, 127})); + connect(combiTable1Ds1.y[1], greater5.u2) annotation( + Line(points = {{-29, -100}, {19, -100}, {19, 12}, {97, 12}}, color = {0, 0, 127})); + connect(combiTable1Ds1.y[1], lessEqual11.u1) annotation( + Line(points = {{-29, -100}, {19, -100}, {19, -212}, {97, -212}}, color = {0, 0, 127})); + connect(thetaPLL, derivative1.u) annotation( + Line(points = {{-220, -320}, {-172, -320}}, color = {0, 0, 127})); + connect(derivative1.y, lessEqual21.u2) annotation( + Line(points = {{-149, -320}, {-82, -320}}, color = {0, 0, 127})); + connect(lessEqual21.y, timer13.u) annotation( + Line(points = {{-59, -312}, {-41, -312}, {-41, -320}, {-23, -320}}, color = {255, 0, 255})); + connect(timer13.y, lessEqual20.u2) annotation( + Line(points = {{1, -320}, {97, -320}}, color = {0, 0, 127})); + connect(derivative.y, lessEqual18.u2) annotation( + Line(points = {{-149, -280}, {-82, -280}}, color = {0, 0, 127})); + connect(timer12.y, lessEqual19.u2) annotation( + Line(points = {{1, -280}, {97, -280}}, color = {0, 0, 127})); + connect(const6.y, lessEqual19.u1) annotation( + Line(points = {{61, -260}, {79, -260}, {79, -272}, {97, -272}}, color = {0, 0, 127})); + connect(constant9.y, lessEqual20.u1) annotation( + Line(points = {{61, -300}, {79, -300}, {79, -312}, {97, -312}}, color = {0, 0, 127})); + connect(constant8.y, lessEqual21.u1) annotation( + Line(points = {{-119, -300}, {-101, -300}, {-101, -312}, {-83, -312}}, color = {0, 0, 127})); + connect(constant7.y, lessEqual18.u1) annotation( + Line(points = {{-119, -260}, {-101, -260}, {-101, -272}, {-83, -272}}, color = {0, 0, 127})); + connect(fMeasPu, derivative.u) annotation( + Line(points = {{-220, -100}, {-180, -100}, {-180, -280}, {-172, -280}}, color = {0, 0, 127})); + connect(lessEqual18.y, timer12.u) annotation( + Line(points = {{-59, -272}, {-41, -272}, {-41, -280}, {-23, -280}}, color = {255, 0, 255})); + connect(greater2.y, or1.u[1]) annotation( + Line(points = {{122, 320}, {140, 320}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(greater5.y, or1.u[2]) annotation( + Line(points = {{122, 20}, {140, 20}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(greater3.y, or1.u[3]) annotation( + Line(points = {{122, -20}, {140, -20}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(greater4.y, or1.u[4]) annotation( + Line(points = {{122, -60}, {140, -60}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(lessEqual15.y, or1.u[5]) annotation( + Line(points = {{122, -132}, {140, -132}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(lessEqual9.y, or1.u[6]) annotation( + Line(points = {{122, -172}, {140, -172}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(lessEqual11.y, or1.u[7]) annotation( + Line(points = {{122, -212}, {140, -212}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(lessEqual19.y, or1.u[8]) annotation( + Line(points = {{122, -272}, {140, -272}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(lessEqual20.y, or1.u[9]) annotation( + Line(points = {{122, -312}, {140, -312}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(greater1.y, or1.u[10]) annotation( + Line(points = {{122, 280}, {140, 280}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(greater.y, or1.u[11]) annotation( + Line(points = {{122, 240}, {140, 240}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(lessEqual8.y, or1.u[12]) annotation( + Line(points = {{122, 168}, {140, 168}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(lessEqual7.y, or1.u[13]) annotation( + Line(points = {{124, 128}, {140, 128}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(lessEqual6.y, or1.u[14]) annotation( + Line(points = {{122, 88}, {140, 88}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(fMeasPu, lessEqual13.u2) annotation( + Line(points = {{-220, -100}, {-100, -100}, {-100, 12}, {-82, 12}}, color = {0, 0, 127})); + connect(fMeasPu, lessEqual17.u2) annotation( + Line(points = {{-220, -100}, {-100, -100}, {-100, -28}, {-82, -28}}, color = {0, 0, 127})); + connect(fMeasPu, lessEqual12.u2) annotation( + Line(points = {{-220, -100}, {-100, -100}, {-100, -68}, {-82, -68}}, color = {0, 0, 127})); + connect(fMeasPu, lessEqual16.u1) annotation( + Line(points = {{-220, -100}, {-100, -100}, {-100, -132}, {-82, -132}}, color = {0, 0, 127})); + connect(fMeasPu, lessEqual14.u1) annotation( + Line(points = {{-220, -100}, {-100, -100}, {-100, -172}, {-82, -172}}, color = {0, 0, 127})); + connect(fMeasPu, lessEqual10.u1) annotation( + Line(points = {{-220, -100}, {-100, -100}, {-100, -212}, {-82, -212}}, color = {0, 0, 127})); + connect(uMeasPu, lessEqual3.u2) annotation( + Line(points = {{-220, 200}, {-100, 200}, {-100, 312}, {-82, 312}}, color = {0, 0, 127})); + connect(uMeasPu, lessEqual2.u2) annotation( + Line(points = {{-220, 200}, {-100, 200}, {-100, 272}, {-82, 272}}, color = {0, 0, 127})); + connect(uMeasPu, lessEqual.u2) annotation( + Line(points = {{-220, 200}, {-100, 200}, {-100, 232}, {-82, 232}}, color = {0, 0, 127})); + connect(uMeasPu, lessEqual1.u1) annotation( + Line(points = {{-220, 200}, {-100, 200}, {-100, 168}, {-82, 168}}, color = {0, 0, 127})); + connect(uMeasPu, lessEqual4.u1) annotation( + Line(points = {{-220, 200}, {-100, 200}, {-100, 128}, {-82, 128}}, color = {0, 0, 127})); + connect(uMeasPu, lessEqual5.u1) annotation( + Line(points = {{-220, 200}, {-100, 200}, {-100, 88}, {-82, 88}}, color = {0, 0, 127})); + annotation( + Diagram(coordinateSystem(extent = {{-200, -340}, {200, 340}})), + Icon(graphics = {Rectangle(extent = {{-200, 340}, {200, -340}}), Text(origin = {-1, 0}, extent = {{-197, 340}, {197, -340}}, textString = "Protection")}, coordinateSystem(extent = {{-200, -340}, {200, 340}}))); +end Protection; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/package.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/package.mo new file mode 100644 index 00000000000..9a3b8acebbe --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/package.mo @@ -0,0 +1,17 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.Protections; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +package BaseProtections + extends Icons.Package; +end BaseProtections; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/package.order b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/package.order new file mode 100644 index 00000000000..ac2a95883e4 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/BaseProtections/package.order @@ -0,0 +1,3 @@ +AuxiliaryProtections +Protection +FRTControl diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/FRTControl.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/FRTControl.mo new file mode 100644 index 00000000000..be38052b5ab --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/FRTControl.mo @@ -0,0 +1,256 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.Protections; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model FRTControl + + //Nominal parameter + parameter Types.ApparentPowerModule SNom "Nominal converter apparent power in MVA"; + + //General parameters + parameter Types.PerUnit IPMaxPu "Maximum active current" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit IQMaxPu "Maximum reactive current" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit IPMinPu "Minimum active current" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit IQMinPu "Minimum reactive current" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit IMaxPu "Maximum current" annotation( + Dialog(tab = "FRT")); + parameter Boolean pqFRTFlag "Active/reactive control priority, 0/1" annotation( + Dialog(tab = "FRT")); + + //LVRT and HVRT parameters + parameter Types.PerUnit uLVRTPu "LVRT threshold value" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit uHVRTPu "HVRT threshold value" annotation( + Dialog(tab = "FRT")); + parameter Boolean LVRTinPFlag "Active current flag during LVRT, 0/1" annotation( + Dialog(tab = "FRT")); + parameter Boolean LVRTinQFlag "Reactive current flag during LVRT, 0/1" annotation( + Dialog(tab = "FRT")); + parameter Boolean HVRTinPFlag "Active current flag during HVRT, 0/1" annotation( + Dialog(tab = "FRT")); + parameter Boolean HVRTinQFlag "Reactive current flag during HVRT, 0/1" annotation( + Dialog(tab = "FRT")); + + parameter Real K1IpLV "Active current factor 1 during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2IpLV "Active current factor 2 during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K1IqLV "Reactive current factor 1 during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2IqLV "Reactive current factor 2 during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KpLVRT "Active power factor during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KqLVRT "Reactive power factor during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iPSetLVPu "Active current setting during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iQSetLVPu "Reactive current setting during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit pSetLVPu "Active power setting during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit qSetLVPu "Reactive power setting during LVRT" annotation( + Dialog(tab = "FRT")); + + parameter Real K1IpHV "Active current factor 1 during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2IpHV "Active current factor 2 during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K1IqHV "Reactive current factor 1 during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2IqHV "Reactive current factor 2 during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KpHVRT "Active power factor during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KqHVRT "Reactive power factor during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iPSetHVPu "Active current setting during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iQSetHVPu "Reactive current setting during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit pSetHVPu "Active power setting during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit qSetHVPu "Reactive power setting during HVRT" annotation( + Dialog(tab = "FRT")); + + + //Input variables + Modelica.Blocks.Interfaces.RealInput iPcmdPu(start = -P0Pu*SystemBase.SnRef/(SNom*U0Pu)) "Active current command" annotation( + Placement(visible = true, transformation(origin = {-180, 60}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-180, 120}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput iQcmdPu(start = Q0Pu*SystemBase.SnRef/(SNom*U0Pu)) "Reactive current command" annotation( + Placement(visible = true, transformation(origin = {-180, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-180, 60}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput uMeasPu(start = U0Pu) "Measured (and filtered) voltage component" annotation( + Placement(visible = true, transformation(origin = {-180, 120}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-180, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput pMeasPu(start = -P0Pu * SystemBase.SnRef / (SNom * U0Pu)) annotation( + Placement(visible = true, transformation(origin = {-180, -60}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-180, -60}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput qMeasPu(start = -Q0Pu * SystemBase.SnRef / (SNom * U0Pu)) annotation( + Placement(visible = true, transformation(origin = {-180, -120}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-180, -120}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + + //Output variables + Modelica.Blocks.Interfaces.RealOutput ippPu(start = -P0Pu*SystemBase.SnRef/(SNom*U0Pu)) "Intermediary active current command in protection block" annotation( + Placement(visible = true, transformation(origin = {180, 100}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {180, 100}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iqqPu(start = Q0Pu*SystemBase.SnRef/(SNom*U0Pu)) "Intermediary reactive current command in protection block" annotation( + Placement(visible = true, transformation(origin = {180, 60}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {180, 60}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput ipLVRTPu annotation( + Placement(visible = true, transformation(origin = {170, 140}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {170, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iqLVRTPu annotation( + Placement(visible = true, transformation(origin = {170, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {170, -90}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput ipHVRTPu annotation( + Placement(visible = true, transformation(origin = {170, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {170, -10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput iqHVRTPu annotation( + Placement(visible = true, transformation(origin = {170, -140}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {170, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + //Initial parameters + parameter Types.PerUnit IPMin0Pu annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IPMax0Pu annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IQMin0Pu annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IQMax0Pu annotation( + Dialog(tab = "Operating point")); + parameter Types.VoltageModulePu U0Pu "Initial voltage amplitude at grid terminal in pu (base UNom)" annotation( + Dialog(group="Operating point")); + parameter Types.ActivePowerPu P0Pu "Initial active power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.ReactivePowerPu Q0Pu "Initial reactive power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + + Modelica.Blocks.Logical.Switch switch1 annotation( + Placement(visible = true, transformation(origin = {-20, 140}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Logical.Switch switch11 annotation( + Placement(visible = true, transformation(origin = {-20, 20}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Sources.BooleanExpression booleanExpression(y = LVRTinPFlag) annotation( + Placement(visible = true, transformation(origin = {-80, 140}, extent = {{-20, -10}, {20, 10}}, rotation = 0))); + Modelica.Blocks.Sources.BooleanExpression booleanExpression1(y = LVRTinQFlag) annotation( + Placement(visible = true, transformation(origin = {-80, 20}, extent = {{-20, -10}, {20, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.VariableLimiter variableLimiter annotation( + Placement(visible = true, transformation(origin = {140, 140}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.VariableLimiter variableLimiter1 annotation( + Placement(visible = true, transformation(origin = {140, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.VariableLimiter variableLimiter2 annotation( + Placement(visible = true, transformation(origin = {140, -140}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Switch switch12 annotation( + Placement(visible = true, transformation(origin = {-20, -140}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.VariableLimiter variableLimiter3 annotation( + Placement(visible = true, transformation(origin = {140, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Switch switch13 annotation( + Placement(visible = true, transformation(origin = {-20, -20}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Modelica.Blocks.Sources.BooleanExpression booleanExpression2(y = HVRTinQFlag) annotation( + Placement(visible = true, transformation(origin = {-80, -140}, extent = {{-20, -10}, {20, 10}}, rotation = 0))); + Modelica.Blocks.Sources.BooleanExpression booleanExpression3(y = HVRTinPFlag) annotation( + Placement(visible = true, transformation(origin = {-80, -20}, extent = {{-20, -10}, {20, 10}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.Protections.AuxiliaryProtections.FRTCurrentBounds LVRTCurrentBounds(IMaxPu = IMaxPu, IPMaxPu = IPMaxPu, IPMinPu = IPMinPu, IQMaxPu = IQMaxPu, IQMinPu = IQMinPu, pqFRTFlag = pqFRTFlag) annotation( + Placement(visible = true, transformation(origin = {60, 80}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.Protections.AuxiliaryProtections.FRTCurrentBounds HVRTCurrentBounds1(IMaxPu = IMaxPu, IPMaxPu = IPMaxPu, IPMinPu = IPMinPu, IQMaxPu = IQMaxPu, IQMinPu = IQMinPu, pqFRTFlag = pqFRTFlag) annotation( + Placement(visible = true, transformation(origin = {60, -80}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.Protections.AuxiliaryProtections.FRTCurrentCalculation LVRTCurrentCalculation(K1Ip = K1IpLV, K1Iq = K1IqLV, K2Ip = K2IpLV, K2Iq = K2IqLV, KpRT = KpLVRT, KqRT = KqLVRT, P0Pu = P0Pu, Q0Pu = Q0Pu, SNom = SNom, U0Pu = U0Pu, iPSetPu = iPSetLVPu, iQSetPu = iQSetLVPu, pSetPu = pSetLVPu, qSetPu = qSetLVPu, uHVRTPu = uHVRTPu, uLVRTPu = uLVRTPu, uRTPu = uLVRTPu) annotation( + Placement(visible = true, transformation(origin = {-80, 80}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.Protections.AuxiliaryProtections.FRTCurrentCalculation HVRTCurrentCalculation(K1Ip = K1IpHV, K1Iq = K1IqHV, K2Ip = K2IpHV, K2Iq = K2IqHV, KpRT = KpHVRT, KqRT = KqHVRT, P0Pu = P0Pu, Q0Pu = Q0Pu, SNom = SNom, U0Pu = U0Pu, iPSetPu = iPSetHVPu, iQSetPu = iQSetHVPu, pSetPu = pSetHVPu, qSetPu = qSetHVPu, uHVRTPu = uHVRTPu, uLVRTPu = uLVRTPu, uRTPu = uHVRTPu) annotation( + Placement(visible = true, transformation(origin = {-80, -80}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); +equation + ippPu = if uMeasPu > uHVRTPu then ipHVRTPu else if uMeasPu < uLVRTPu then ipLVRTPu else iPcmdPu; + iqqPu = if uMeasPu > uHVRTPu then iqHVRTPu else if uMeasPu < uLVRTPu then iqLVRTPu else iQcmdPu; + connect(booleanExpression1.y, switch11.u2) annotation( + Line(points = {{-58, 20}, {-32, 20}}, color = {255, 0, 255})); + connect(booleanExpression.y, switch1.u2) annotation( + Line(points = {{-58, 140}, {-31.8, 140}}, color = {255, 0, 255})); + connect(switch11.y, variableLimiter1.u) annotation( + Line(points = {{-9, 20}, {128, 20}}, color = {0, 0, 127})); + connect(variableLimiter1.y, iqLVRTPu) annotation( + Line(points = {{151, 20}, {170, 20}}, color = {0, 0, 127})); + connect(switch1.y, variableLimiter.u) annotation( + Line(points = {{-9, 140}, {128, 140}}, color = {0, 0, 127})); + connect(variableLimiter.y, ipLVRTPu) annotation( + Line(points = {{151, 140}, {170, 140}}, color = {0, 0, 127})); + connect(switch12.y, variableLimiter2.u) annotation( + Line(points = {{-9, -140}, {128, -140}}, color = {0, 0, 127})); + connect(switch13.y, variableLimiter3.u) annotation( + Line(points = {{-9, -20}, {128, -20}}, color = {0, 0, 127})); + connect(variableLimiter3.y, ipHVRTPu) annotation( + Line(points = {{151, -20}, {170, -20}}, color = {0, 0, 127})); + connect(variableLimiter2.y, iqHVRTPu) annotation( + Line(points = {{151, -140}, {170, -140}}, color = {0, 0, 127})); + connect(booleanExpression2.y, switch12.u2) annotation( + Line(points = {{-58, -140}, {-32, -140}}, color = {255, 0, 255})); + connect(booleanExpression3.y, switch13.u2) annotation( + Line(points = {{-58, -20}, {-32, -20}}, color = {255, 0, 255})); + connect(uMeasPu, LVRTCurrentCalculation.uMeasPu) annotation( + Line(points = {{-180, 120}, {-112, 120}, {-112, 96}, {-104, 96}}, color = {0, 0, 127})); + connect(uMeasPu, HVRTCurrentCalculation.uMeasPu) annotation( + Line(points = {{-180, 120}, {-112, 120}, {-112, -64}, {-104, -64}}, color = {0, 0, 127})); + connect(iPcmdPu, LVRTCurrentCalculation.iPcmdPu) annotation( + Line(points = {{-180, 60}, {-120, 60}, {-120, 88}, {-104, 88}}, color = {0, 0, 127})); + connect(iPcmdPu, HVRTCurrentCalculation.iPcmdPu) annotation( + Line(points = {{-180, 60}, {-120, 60}, {-120, -72}, {-104, -72}}, color = {0, 0, 127})); + connect(iQcmdPu, LVRTCurrentCalculation.iQcmdPu) annotation( + Line(points = {{-180, 0}, {-130, 0}, {-130, 80}, {-104, 80}}, color = {0, 0, 127})); + connect(iQcmdPu, HVRTCurrentCalculation.iQcmdPu) annotation( + Line(points = {{-180, 0}, {-130, 0}, {-130, -80}, {-104, -80}}, color = {0, 0, 127})); + connect(pMeasPu, HVRTCurrentCalculation.pMeasPu) annotation( + Line(points = {{-180, -60}, {-140, -60}, {-140, -88}, {-104, -88}}, color = {0, 0, 127})); + connect(pMeasPu, LVRTCurrentCalculation.pMeasPu) annotation( + Line(points = {{-180, -60}, {-140, -60}, {-140, 72}, {-104, 72}}, color = {0, 0, 127})); + connect(qMeasPu, LVRTCurrentCalculation.qMeasPu) annotation( + Line(points = {{-180, -120}, {-150, -120}, {-150, 64}, {-104, 64}}, color = {0, 0, 127})); + connect(qMeasPu, HVRTCurrentCalculation.qMeasPu) annotation( + Line(points = {{-180, -120}, {-150, -120}, {-150, -96}, {-104, -96}}, color = {0, 0, 127})); + connect(LVRTCurrentCalculation.ipRTPu0, switch1.u3) annotation( + Line(points = {{-58, 94}, {-48, 94}, {-48, 148}, {-32, 148}}, color = {0, 0, 127})); + connect(LVRTCurrentCalculation.ipRTPu1, switch1.u1) annotation( + Line(points = {{-58, 86}, {-40, 86}, {-40, 132}, {-32, 132}}, color = {0, 0, 127})); + connect(LVRTCurrentCalculation.iqRTPu0, switch11.u3) annotation( + Line(points = {{-58, 74}, {-40, 74}, {-40, 28}, {-32, 28}}, color = {0, 0, 127})); + connect(LVRTCurrentCalculation.iqRTPu1, switch11.u1) annotation( + Line(points = {{-58, 66}, {-48, 66}, {-48, 12}, {-32, 12}}, color = {0, 0, 127})); + connect(HVRTCurrentCalculation.ipRTPu0, switch13.u3) annotation( + Line(points = {{-58, -66}, {-50, -66}, {-50, -12}, {-32, -12}}, color = {0, 0, 127})); + connect(HVRTCurrentCalculation.ipRTPu1, switch13.u1) annotation( + Line(points = {{-58, -74}, {-40, -74}, {-40, -28}, {-32, -28}}, color = {0, 0, 127})); + connect(HVRTCurrentCalculation.iqRTPu0, switch12.u3) annotation( + Line(points = {{-58, -86}, {-40, -86}, {-40, -132}, {-32, -132}}, color = {0, 0, 127})); + connect(HVRTCurrentCalculation.iqRTPu1, switch12.u1) annotation( + Line(points = {{-58, -94}, {-50, -94}, {-50, -148}, {-32, -148}}, color = {0, 0, 127})); + connect(switch13.y, HVRTCurrentBounds1.ipLVRTPrimPu) annotation( + Line(points = {{-9, -20}, {0, -20}, {0, -72}, {36, -72}}, color = {0, 0, 127})); + connect(switch12.y, HVRTCurrentBounds1.iqLVRTPrimPu) annotation( + Line(points = {{-9, -140}, {0, -140}, {0, -88}, {36, -88}}, color = {0, 0, 127})); + connect(switch11.y, LVRTCurrentBounds.iqLVRTPrimPu) annotation( + Line(points = {{-9, 20}, {0, 20}, {0, 72}, {36, 72}}, color = {0, 0, 127})); + connect(switch1.y, LVRTCurrentBounds.ipLVRTPrimPu) annotation( + Line(points = {{-9, 140}, {0, 140}, {0, 88}, {36, 88}}, color = {0, 0, 127})); + connect(LVRTCurrentBounds.ipMaxPu, variableLimiter.limit1) annotation( + Line(points = {{82, 94}, {110, 94}, {110, 148}, {128, 148}}, color = {0, 0, 127})); + connect(LVRTCurrentBounds.ipMinPu, variableLimiter.limit2) annotation( + Line(points = {{82, 86}, {120, 86}, {120, 132}, {128, 132}}, color = {0, 0, 127})); + connect(LVRTCurrentBounds.iqMaxPu, variableLimiter1.limit1) annotation( + Line(points = {{82, 74}, {120, 74}, {120, 28}, {128, 28}}, color = {0, 0, 127})); + connect(LVRTCurrentBounds.iqMinPu, variableLimiter1.limit2) annotation( + Line(points = {{82, 66}, {110, 66}, {110, 12}, {128, 12}}, color = {0, 0, 127})); + connect(HVRTCurrentBounds1.ipMaxPu, variableLimiter3.limit1) annotation( + Line(points = {{82, -66}, {110, -66}, {110, -12}, {128, -12}}, color = {0, 0, 127})); + connect(HVRTCurrentBounds1.ipMinPu, variableLimiter3.limit2) annotation( + Line(points = {{82, -74}, {120, -74}, {120, -28}, {128, -28}}, color = {0, 0, 127})); + connect(HVRTCurrentBounds1.iqMaxPu, variableLimiter2.limit1) annotation( + Line(points = {{82, -86}, {120, -86}, {120, -132}, {128, -132}}, color = {0, 0, 127})); + connect(HVRTCurrentBounds1.iqMinPu, variableLimiter2.limit2) annotation( + Line(points = {{82, -94}, {110, -94}, {110, -148}, {128, -148}}, color = {0, 0, 127})); + annotation( + Icon(graphics = {Rectangle(extent = {{-160, 160}, {160, -160}}), Text(extent = {{-160, 160}, {160, -160}}, textString = "FRT +Control")}, coordinateSystem(extent = {{-160, -160}, {160, 160}})), + Diagram(coordinateSystem(extent = {{-160, -160}, {160, 160}}))); +end FRTControl; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/Protection.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/Protection.mo new file mode 100644 index 00000000000..ef3af860505 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/Protection.mo @@ -0,0 +1,446 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406.Protections; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model Protection + + // Voltage protection table parameters + parameter Real TLVP3 = 0.3 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real TLVP2 = 0.5 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real TLVP1 = 1 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real THVP1 = 1 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real THVP2 = 0.5 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real THVP3 = 0.3 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real ULVP3 = 0.80 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real ULVP2 = 0.85 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real ULVP1 = 0.90 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real UHVP1 = 1.1 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real UHVP2 = 1.15 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real UHVP3 = 1.2 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real TabletUProtection[:, :] = [0, TLVP3; ULVP3 - 0.001, TLVP3; ULVP3, TLVP2; ULVP2 - 0.001, TLVP2; ULVP2, TLVP1; ULVP1 - 0.001, TLVP1; ULVP1, Modelica.Constants.inf; UHVP1, Modelica.Constants.inf; UHVP1 + 0.001, THVP1; UHVP2, THVP1; UHVP2 + 0.001, THVP2; UHVP3, THVP2; UHVP3 + 0.001, THVP3; 1000, THVP3] "Disconnection time versus over voltage lookup table" annotation( + Dialog(tab = "GridProtectionTables")); + + // Frequency protection table parameters + parameter Real TLfP3 = 0.25 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real TLfP2 = 0.5 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real TLfP1 = 1 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real THfP1 = 1 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real THfP2 = 0.5 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real THfP3 = 0.25 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real fLfP3 = 0.98 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real fLfP2 = 0.99 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real fLfP1 = 0.996 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real fHfP1 = 1.004 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real fHfP2 = 1.01 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real fHfP3 = 1.02 annotation( + Dialog(tab = "GridProtectionTables")); + parameter Real TabletfProtection[:, :] = [0, TLfP3; fLfP3 - 0.001, TLfP3; fLfP3, TLfP2; fLfP2 - 0.001, TLfP2; fLfP2, TLfP1; fLfP1 - 0.001, TLfP1; fLfP1, Modelica.Constants.inf; fHfP1, Modelica.Constants.inf; fHfP1 + 0.001, THfP1; fHfP2, THfP1; fHfP2 + 0.001, THfP2; fHfP3, THfP2; fHfP3 + 0.001, THfP3; 1000, THfP3] "Disconnection time versus over voltage lookup table" annotation( + Dialog(tab = "GridProtectionTables")); + + // Derivatives parameters + parameter Real DerfMaxPu = 0.02 annotation( + Dialog(tab = "Protection")); + parameter Real TDerfMax = 0.5 annotation( + Dialog(tab = "Protection")); + parameter Real DerThetaMax = 1 annotation( + Dialog(tab = "Protection")); + parameter Real TDerThetaMax = 0.5 annotation( + Dialog(tab = "Protection")); + + //Input variables + Modelica.Blocks.Interfaces.RealInput uMeasPu(start = U0Pu) "Measured (and filtered) voltage component" annotation( + Placement(visible = true, transformation(origin = {-220, 200}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-239, 161}, extent = {{-39, -39}, {39, 39}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput fMeasPu(start = fInitPu) "Measured frequency outputted by the phase-locked loop" annotation( + Placement(visible = true, transformation(origin = {-220, -100}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-239, -1}, extent = {{-39, -39}, {39, 39}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput thetaPLL(start = UPhase0) "Phase angle outputted by phase-locked loop" annotation( + Placement(visible = true, transformation(origin = {-220, -320}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-239, -159}, extent = {{-39, -39}, {39, 39}}, rotation = 0))); + + //Output variables + Modelica.Blocks.Interfaces.BooleanOutput tripFlag(start = false) annotation( + Placement(visible = true, transformation(origin = {220, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {240, 0}, extent = {{-40, -40}, {40, 40}}, rotation = 0))); + + //Initial parameters + parameter Types.VoltageModulePu U0Pu "Initial voltage amplitude at grid terminal in pu (base UNom)" annotation( + Dialog(group = "Operating point")); + parameter Types.Angle UPhase0 "Initial Phase angle outputted by phase-locked loop" annotation( + Dialog(group = "Operating point")); + parameter Types.PerUnit fInitPu "Initial frequency" annotation( + Dialog(tab = "Operating point")); + Modelica.Blocks.Logical.Timer timer annotation( + Placement(visible = true, transformation(origin = {-10, 240}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Greater greater annotation( + Placement(visible = true, transformation(origin = {110, 240}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual annotation( + Placement(visible = true, transformation(origin = {-70, 240}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant const(k = UHVP1) annotation( + Placement(visible = true, transformation(origin = {-130, 240}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant const2(k = UHVP2) annotation( + Placement(visible = true, transformation(origin = {-130, 280}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual2 annotation( + Placement(visible = true, transformation(origin = {-70, 280}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer2 annotation( + Placement(visible = true, transformation(origin = {-10, 280}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant const3(k = UHVP3) annotation( + Placement(visible = true, transformation(origin = {-130, 320}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual3 annotation( + Placement(visible = true, transformation(origin = {-70, 320}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer3 annotation( + Placement(visible = true, transformation(origin = {-10, 320}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Greater greater1 annotation( + Placement(visible = true, transformation(origin = {110, 280}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Greater greater2 annotation( + Placement(visible = true, transformation(origin = {110, 320}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.Limiter limiter(limitsAtInit = true, uMax = THVP2) annotation( + Placement(visible = true, transformation(origin = {50, 260}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.Limiter limiter1(limitsAtInit = true, uMax = THVP1) annotation( + Placement(visible = true, transformation(origin = {50, 220}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.MathBoolean.Or or1(nu = 14) annotation( + Placement(visible = true, transformation(origin = {170, 1.77636e-15}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant const1(k = ULVP1) annotation( + Placement(visible = true, transformation(origin = {-130, 160}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual1 annotation( + Placement(visible = true, transformation(origin = {-70, 168}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual4 annotation( + Placement(visible = true, transformation(origin = {-70, 128}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant const4(k = ULVP2) annotation( + Placement(visible = true, transformation(origin = {-130, 120}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant const5(k = ULVP3) annotation( + Placement(visible = true, transformation(origin = {-130, 80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual5 annotation( + Placement(visible = true, transformation(origin = {-70, 88}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer1 annotation( + Placement(visible = true, transformation(origin = {-10, 160}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer4 annotation( + Placement(visible = true, transformation(origin = {-10, 120}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer5 annotation( + Placement(visible = true, transformation(origin = {-10, 80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.Limiter limiter2(limitsAtInit = true, uMax = TLVP1) annotation( + Placement(visible = true, transformation(origin = {50, 180}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.Limiter limiter3(limitsAtInit = true, uMax = TLVP2) annotation( + Placement(visible = true, transformation(origin = {50, 140}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual6 annotation( + Placement(visible = true, transformation(origin = {110, 88}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual7 annotation( + Placement(visible = true, transformation(origin = {112, 128}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual8 annotation( + Placement(visible = true, transformation(origin = {110, 168}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Tables.CombiTable1Ds combiTable1Ds(table = TabletUProtection) annotation( + Placement(visible = true, transformation(origin = {-40, 200}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual9 annotation( + Placement(visible = true, transformation(origin = {110, -172}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer6 annotation( + Placement(visible = true, transformation(origin = {-10, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual10 annotation( + Placement(visible = true, transformation(origin = {-70, -212}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual11 annotation( + Placement(visible = true, transformation(origin = {110, -212}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual12 annotation( + Placement(visible = true, transformation(origin = {-70, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Tables.CombiTable1Ds combiTable1Ds1(table = TabletfProtection) annotation( + Placement(visible = true, transformation(origin = {-40, -100}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual13 annotation( + Placement(visible = true, transformation(origin = {-70, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant constant1(k = fLfP2) annotation( + Placement(visible = true, transformation(origin = {-130, -180}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Greater greater3 annotation( + Placement(visible = true, transformation(origin = {110, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant constant2(k = fLfP1) annotation( + Placement(visible = true, transformation(origin = {-130, -140}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer7 annotation( + Placement(visible = true, transformation(origin = {-10, -180}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant constant3(k = fHfP1) annotation( + Placement(visible = true, transformation(origin = {-130, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual14 annotation( + Placement(visible = true, transformation(origin = {-70, -172}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant constant4(k = fHfP3) annotation( + Placement(visible = true, transformation(origin = {-130, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual15 annotation( + Placement(visible = true, transformation(origin = {110, -132}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer8 annotation( + Placement(visible = true, transformation(origin = {-10, -220}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.Limiter limiter4(limitsAtInit = true, uMax = THfP1) annotation( + Placement(visible = true, transformation(origin = {50, -80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer9 annotation( + Placement(visible = true, transformation(origin = {-10, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant constant5(k = fLfP3) annotation( + Placement(visible = true, transformation(origin = {-130, -220}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer10 annotation( + Placement(visible = true, transformation(origin = {-10, -140}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant constant6(k = fHfP2) annotation( + Placement(visible = true, transformation(origin = {-130, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Greater greater4 annotation( + Placement(visible = true, transformation(origin = {110, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Greater greater5 annotation( + Placement(visible = true, transformation(origin = {110, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.Limiter limiter5(limitsAtInit = true, uMax = TLfP1) annotation( + Placement(visible = true, transformation(origin = {50, -120}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual16 annotation( + Placement(visible = true, transformation(origin = {-70, -132}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.Limiter limiter6(limitsAtInit = true, uMax = TLfP2) annotation( + Placement(visible = true, transformation(origin = {50, -160}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.Limiter limiter7(limitsAtInit = true, uMax = THfP2) annotation( + Placement(visible = true, transformation(origin = {50, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual17 annotation( + Placement(visible = true, transformation(origin = {-70, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer11 annotation( + Placement(visible = true, transformation(origin = {-10, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer12 annotation( + Placement(visible = true, transformation(origin = {-10, -280}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual18 annotation( + Placement(visible = true, transformation(origin = {-70, -272}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant constant7(k = DerfMaxPu) annotation( + Placement(visible = true, transformation(origin = {-130, -260}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual19 annotation( + Placement(visible = true, transformation(origin = {110, -272}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant const6(k = TDerfMax) annotation( + Placement(visible = true, transformation(origin = {50, -260}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant constant8(k = DerThetaMax) annotation( + Placement(visible = true, transformation(origin = {-130, -300}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual20 annotation( + Placement(visible = true, transformation(origin = {110, -312}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.LessEqual lessEqual21 annotation( + Placement(visible = true, transformation(origin = {-70, -312}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Constant constant9(k = TDerThetaMax) annotation( + Placement(visible = true, transformation(origin = {50, -300}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Logical.Timer timer13 annotation( + Placement(visible = true, transformation(origin = {-10, -320}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Continuous.Derivative derivative1 annotation( + Placement(visible = true, transformation(origin = {-160, -320}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Continuous.Derivative derivative annotation( + Placement(visible = true, transformation(origin = {-160, -280}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + +equation + when or1.y == true then + tripFlag = true; + end when; + + connect(lessEqual.y, timer.u) annotation( + Line(points = {{-59, 240}, {-22, 240}}, color = {255, 0, 255})); + connect(const.y, lessEqual.u1) annotation( + Line(points = {{-119, 240}, {-82, 240}}, color = {0, 0, 127})); + connect(const3.y, lessEqual3.u1) annotation( + Line(points = {{-119, 320}, {-82, 320}}, color = {0, 0, 127})); + connect(const2.y, lessEqual2.u1) annotation( + Line(points = {{-119, 280}, {-82, 280}}, color = {0, 0, 127})); + connect(lessEqual3.y, timer3.u) annotation( + Line(points = {{-59, 320}, {-22, 320}}, color = {255, 0, 255})); + connect(lessEqual2.y, timer2.u) annotation( + Line(points = {{-59, 280}, {-22, 280}}, color = {255, 0, 255})); + connect(timer3.y, greater2.u1) annotation( + Line(points = {{1, 320}, {98, 320}}, color = {0, 0, 127})); + connect(timer2.y, greater1.u1) annotation( + Line(points = {{1, 280}, {98, 280}}, color = {0, 0, 127})); + connect(timer.y, greater.u1) annotation( + Line(points = {{1, 240}, {98, 240}}, color = {0, 0, 127})); + connect(limiter.y, greater1.u2) annotation( + Line(points = {{61, 260}, {79.5, 260}, {79.5, 272}, {98, 272}}, color = {0, 0, 127})); + connect(limiter1.y, greater.u2) annotation( + Line(points = {{61, 220}, {79.5, 220}, {79.5, 232}, {98, 232}}, color = {0, 0, 127})); + connect(const5.y, lessEqual5.u2) annotation( + Line(points = {{-119, 80}, {-82, 80}}, color = {0, 0, 127})); + connect(limiter2.y, lessEqual8.u1) annotation( + Line(points = {{61, 180}, {79.5, 180}, {79.5, 168}, {98, 168}}, color = {0, 0, 127})); + connect(limiter3.y, lessEqual7.u1) annotation( + Line(points = {{61, 140}, {79.5, 140}, {79.5, 128}, {100, 128}}, color = {0, 0, 127})); + connect(constant1.y, lessEqual14.u2) annotation( + Line(points = {{-119, -180}, {-82, -180}}, color = {0, 0, 127})); + connect(limiter7.y, greater3.u2) annotation( + Line(points = {{61, -40}, {77.5, -40}, {77.5, -28}, {98, -28}}, color = {0, 0, 127})); + connect(constant5.y, lessEqual10.u2) annotation( + Line(points = {{-119, -220}, {-82, -220}}, color = {0, 0, 127})); + connect(timer6.y, greater5.u1) annotation( + Line(points = {{1, 20}, {98, 20}}, color = {0, 0, 127})); + connect(constant6.y, lessEqual17.u1) annotation( + Line(points = {{-119, -20}, {-82, -20}}, color = {0, 0, 127})); + connect(timer7.y, lessEqual9.u2) annotation( + Line(points = {{1, -180}, {98, -180}}, color = {0, 0, 127})); + connect(lessEqual10.y, timer8.u) annotation( + Line(points = {{-59, -212}, {-40.5, -212}, {-40.5, -220}, {-22, -220}}, color = {255, 0, 255})); + connect(lessEqual12.y, timer11.u) annotation( + Line(points = {{-59, -60}, {-22, -60}}, color = {255, 0, 255})); + connect(lessEqual14.y, timer7.u) annotation( + Line(points = {{-59, -172}, {-40.5, -172}, {-40.5, -180}, {-22, -180}}, color = {255, 0, 255})); + connect(timer8.y, lessEqual11.u2) annotation( + Line(points = {{1, -220}, {98, -220}}, color = {0, 0, 127})); + connect(timer11.y, greater4.u1) annotation( + Line(points = {{1, -60}, {98, -60}}, color = {0, 0, 127})); + connect(timer9.y, greater3.u1) annotation( + Line(points = {{1, -20}, {98, -20}}, color = {0, 0, 127})); + connect(lessEqual17.y, timer9.u) annotation( + Line(points = {{-59, -20}, {-22, -20}}, color = {255, 0, 255})); + connect(constant3.y, lessEqual12.u1) annotation( + Line(points = {{-119, -60}, {-82, -60}}, color = {0, 0, 127})); + connect(limiter6.y, lessEqual9.u1) annotation( + Line(points = {{61, -160}, {77.5, -160}, {77.5, -172}, {98, -172}}, color = {0, 0, 127})); + connect(constant2.y, lessEqual16.u2) annotation( + Line(points = {{-119, -140}, {-82, -140}}, color = {0, 0, 127})); + connect(limiter4.y, greater4.u2) annotation( + Line(points = {{61, -80}, {79.5, -80}, {79.5, -68}, {98, -68}}, color = {0, 0, 127})); + connect(limiter5.y, lessEqual15.u1) annotation( + Line(points = {{61, -120}, {76.5, -120}, {76.5, -132}, {98, -132}}, color = {0, 0, 127})); + connect(lessEqual16.y, timer10.u) annotation( + Line(points = {{-59, -132}, {-40.5, -132}, {-40.5, -140}, {-22, -140}}, color = {255, 0, 255})); + connect(lessEqual13.y, timer6.u) annotation( + Line(points = {{-59, 20}, {-22, 20}}, color = {255, 0, 255})); + connect(constant4.y, lessEqual13.u1) annotation( + Line(points = {{-119, 20}, {-82, 20}}, color = {0, 0, 127})); + connect(timer10.y, lessEqual15.u2) annotation( + Line(points = {{1, -140}, {98, -140}}, color = {0, 0, 127})); + connect(combiTable1Ds.y[1], greater2.u2) annotation( + Line(points = {{-29, 200}, {20, 200}, {20, 312}, {98, 312}}, color = {0, 0, 127})); + connect(combiTable1Ds.y[1], limiter.u) annotation( + Line(points = {{-29, 200}, {20, 200}, {20, 260}, {38, 260}}, color = {0, 0, 127})); + connect(combiTable1Ds.y[1], limiter1.u) annotation( + Line(points = {{-29, 200}, {20, 200}, {20, 220}, {38, 220}}, color = {0, 0, 127})); + connect(combiTable1Ds.y[1], limiter2.u) annotation( + Line(points = {{-29, 200}, {20, 200}, {20, 180}, {38, 180}}, color = {0, 0, 127})); + connect(combiTable1Ds.y[1], limiter3.u) annotation( + Line(points = {{-29, 200}, {20, 200}, {20, 140}, {38, 140}}, color = {0, 0, 127})); + connect(combiTable1Ds.y[1], lessEqual6.u1) annotation( + Line(points = {{-29, 200}, {20, 200}, {20, 88}, {98, 88}}, color = {0, 0, 127})); + connect(timer1.y, lessEqual8.u2) annotation( + Line(points = {{1, 160}, {98, 160}}, color = {0, 0, 127})); + connect(timer4.y, lessEqual7.u2) annotation( + Line(points = {{1, 120}, {100, 120}}, color = {0, 0, 127})); + connect(timer5.y, lessEqual6.u2) annotation( + Line(points = {{1, 80}, {98, 80}}, color = {0, 0, 127})); + connect(uMeasPu, combiTable1Ds.u) annotation( + Line(points = {{-220, 200}, {-52, 200}}, color = {0, 0, 127})); + connect(fMeasPu, combiTable1Ds1.u) annotation( + Line(points = {{-220, -100}, {-52, -100}}, color = {0, 0, 127})); + connect(const1.y, lessEqual1.u2) annotation( + Line(points = {{-119, 160}, {-83, 160}}, color = {0, 0, 127})); + connect(lessEqual4.y, timer4.u) annotation( + Line(points = {{-59, 128}, {-41, 128}, {-41, 120}, {-23, 120}}, color = {255, 0, 255})); + connect(lessEqual1.y, timer1.u) annotation( + Line(points = {{-59, 168}, {-40, 168}, {-40, 160}, {-22, 160}}, color = {255, 0, 255})); + connect(lessEqual5.y, timer5.u) annotation( + Line(points = {{-59, 88}, {-41, 88}, {-41, 80}, {-23, 80}}, color = {255, 0, 255})); + connect(const4.y, lessEqual4.u2) annotation( + Line(points = {{-119, 120}, {-83, 120}}, color = {0, 0, 127})); + connect(combiTable1Ds1.y[1], limiter7.u) annotation( + Line(points = {{-29, -100}, {19, -100}, {19, -40}, {37, -40}}, color = {0, 0, 127})); + connect(combiTable1Ds1.y[1], limiter4.u) annotation( + Line(points = {{-29, -100}, {19, -100}, {19, -80}, {37, -80}}, color = {0, 0, 127})); + connect(combiTable1Ds1.y[1], limiter5.u) annotation( + Line(points = {{-29, -100}, {19, -100}, {19, -120}, {37, -120}}, color = {0, 0, 127})); + connect(combiTable1Ds1.y[1], limiter6.u) annotation( + Line(points = {{-29, -100}, {19, -100}, {19, -160}, {37, -160}}, color = {0, 0, 127})); + connect(combiTable1Ds1.y[1], greater5.u2) annotation( + Line(points = {{-29, -100}, {19, -100}, {19, 12}, {97, 12}}, color = {0, 0, 127})); + connect(combiTable1Ds1.y[1], lessEqual11.u1) annotation( + Line(points = {{-29, -100}, {19, -100}, {19, -212}, {97, -212}}, color = {0, 0, 127})); + connect(thetaPLL, derivative1.u) annotation( + Line(points = {{-220, -320}, {-172, -320}}, color = {0, 0, 127})); + connect(derivative1.y, lessEqual21.u2) annotation( + Line(points = {{-149, -320}, {-82, -320}}, color = {0, 0, 127})); + connect(lessEqual21.y, timer13.u) annotation( + Line(points = {{-59, -312}, {-41, -312}, {-41, -320}, {-23, -320}}, color = {255, 0, 255})); + connect(timer13.y, lessEqual20.u2) annotation( + Line(points = {{1, -320}, {97, -320}}, color = {0, 0, 127})); + connect(derivative.y, lessEqual18.u2) annotation( + Line(points = {{-149, -280}, {-82, -280}}, color = {0, 0, 127})); + connect(timer12.y, lessEqual19.u2) annotation( + Line(points = {{1, -280}, {97, -280}}, color = {0, 0, 127})); + connect(const6.y, lessEqual19.u1) annotation( + Line(points = {{61, -260}, {79, -260}, {79, -272}, {97, -272}}, color = {0, 0, 127})); + connect(constant9.y, lessEqual20.u1) annotation( + Line(points = {{61, -300}, {79, -300}, {79, -312}, {97, -312}}, color = {0, 0, 127})); + connect(constant8.y, lessEqual21.u1) annotation( + Line(points = {{-119, -300}, {-101, -300}, {-101, -312}, {-83, -312}}, color = {0, 0, 127})); + connect(constant7.y, lessEqual18.u1) annotation( + Line(points = {{-119, -260}, {-101, -260}, {-101, -272}, {-83, -272}}, color = {0, 0, 127})); + connect(fMeasPu, derivative.u) annotation( + Line(points = {{-220, -100}, {-180, -100}, {-180, -280}, {-172, -280}}, color = {0, 0, 127})); + connect(lessEqual18.y, timer12.u) annotation( + Line(points = {{-59, -272}, {-41, -272}, {-41, -280}, {-23, -280}}, color = {255, 0, 255})); + connect(greater2.y, or1.u[1]) annotation( + Line(points = {{122, 320}, {140, 320}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(greater5.y, or1.u[2]) annotation( + Line(points = {{122, 20}, {140, 20}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(greater3.y, or1.u[3]) annotation( + Line(points = {{122, -20}, {140, -20}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(greater4.y, or1.u[4]) annotation( + Line(points = {{122, -60}, {140, -60}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(lessEqual15.y, or1.u[5]) annotation( + Line(points = {{122, -132}, {140, -132}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(lessEqual9.y, or1.u[6]) annotation( + Line(points = {{122, -172}, {140, -172}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(lessEqual11.y, or1.u[7]) annotation( + Line(points = {{122, -212}, {140, -212}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(lessEqual19.y, or1.u[8]) annotation( + Line(points = {{122, -272}, {140, -272}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(lessEqual20.y, or1.u[9]) annotation( + Line(points = {{122, -312}, {140, -312}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(greater1.y, or1.u[10]) annotation( + Line(points = {{122, 280}, {140, 280}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(greater.y, or1.u[11]) annotation( + Line(points = {{122, 240}, {140, 240}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(lessEqual8.y, or1.u[12]) annotation( + Line(points = {{122, 168}, {140, 168}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(lessEqual7.y, or1.u[13]) annotation( + Line(points = {{124, 128}, {140, 128}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(lessEqual6.y, or1.u[14]) annotation( + Line(points = {{122, 88}, {140, 88}, {140, 0}, {160, 0}}, color = {255, 0, 255})); + connect(fMeasPu, lessEqual13.u2) annotation( + Line(points = {{-220, -100}, {-100, -100}, {-100, 12}, {-82, 12}}, color = {0, 0, 127})); + connect(fMeasPu, lessEqual17.u2) annotation( + Line(points = {{-220, -100}, {-100, -100}, {-100, -28}, {-82, -28}}, color = {0, 0, 127})); + connect(fMeasPu, lessEqual12.u2) annotation( + Line(points = {{-220, -100}, {-100, -100}, {-100, -68}, {-82, -68}}, color = {0, 0, 127})); + connect(fMeasPu, lessEqual16.u1) annotation( + Line(points = {{-220, -100}, {-100, -100}, {-100, -132}, {-82, -132}}, color = {0, 0, 127})); + connect(fMeasPu, lessEqual14.u1) annotation( + Line(points = {{-220, -100}, {-100, -100}, {-100, -172}, {-82, -172}}, color = {0, 0, 127})); + connect(fMeasPu, lessEqual10.u1) annotation( + Line(points = {{-220, -100}, {-100, -100}, {-100, -212}, {-82, -212}}, color = {0, 0, 127})); + connect(uMeasPu, lessEqual3.u2) annotation( + Line(points = {{-220, 200}, {-100, 200}, {-100, 312}, {-82, 312}}, color = {0, 0, 127})); + connect(uMeasPu, lessEqual2.u2) annotation( + Line(points = {{-220, 200}, {-100, 200}, {-100, 272}, {-82, 272}}, color = {0, 0, 127})); + connect(uMeasPu, lessEqual.u2) annotation( + Line(points = {{-220, 200}, {-100, 200}, {-100, 232}, {-82, 232}}, color = {0, 0, 127})); + connect(uMeasPu, lessEqual1.u1) annotation( + Line(points = {{-220, 200}, {-100, 200}, {-100, 168}, {-82, 168}}, color = {0, 0, 127})); + connect(uMeasPu, lessEqual4.u1) annotation( + Line(points = {{-220, 200}, {-100, 200}, {-100, 128}, {-82, 128}}, color = {0, 0, 127})); + connect(uMeasPu, lessEqual5.u1) annotation( + Line(points = {{-220, 200}, {-100, 200}, {-100, 88}, {-82, 88}}, color = {0, 0, 127})); + + annotation( + Diagram(coordinateSystem(extent = {{-200, -340}, {200, 340}})), + Icon(graphics = {Rectangle(extent = {{-200, 340}, {200, -340}}), Text(origin = {-1, 0}, extent = {{-197, 340}, {197, -340}}, textString = "Protection")}, coordinateSystem(extent = {{-200, -340}, {200, 340}}))); +end Protection; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/package.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/package.mo new file mode 100644 index 00000000000..d5c01101d4e --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/package.mo @@ -0,0 +1,17 @@ +within Dynawo.Electrical.Controls.IEC.IEC63406; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +package Protections + extends Icons.Package; +end Protections; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/package.order b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/package.order new file mode 100644 index 00000000000..612797339c2 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/Protections/package.order @@ -0,0 +1,4 @@ +BaseProtections +AuxiliaryProtections +FRTControl +Protection diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/package.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/package.mo new file mode 100644 index 00000000000..fd17ec591b1 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/package.mo @@ -0,0 +1,17 @@ +within Dynawo.Electrical.Controls.IEC; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +package IEC63406 + extends Icons.Package; +end IEC63406; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/package.order b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/package.order new file mode 100644 index 00000000000..0bece36f440 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Controls/IEC/IEC63406/package.order @@ -0,0 +1,9 @@ +AuxiliaryBlocks +PlantCommunication +PrimaryEnergy +Measurement +Controls +Protections +ControlAndProtection +InjectorCurrentSource +InjectorVoltageSource diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/ConverterCurrentSourceIEC63406.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/ConverterCurrentSourceIEC63406.mo new file mode 100644 index 00000000000..4333b593a5d --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/ConverterCurrentSourceIEC63406.mo @@ -0,0 +1,369 @@ +within Dynawo.Electrical.Sources; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model ConverterCurrentSourceIEC63406 + + //Nominal parameter + parameter Types.ApparentPowerModule SNom "Nominal converter apparent power in MVA"; + parameter Types.Time tS "Integration time step in s"; + + //General parameters + parameter Types.PerUnit IMaxPu "Maximum current" annotation( + Dialog(tab = "General")); + parameter Types.PerUnit IPMaxPu "Maximum active current" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit IQMaxPu "Maximum reactive current" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit IPMinPu "Minimum active current" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit IQMinPu "Minimum reactive current" annotation( + Dialog(tab = "FRT")); + + //Communication Interface Parameters + parameter Types.Time Tcom "Time constant for communication delay between the plant-level controller and the generating unit-level controller" annotation( + Dialog(tab = "PlantCommunication")); + parameter Types.Time Tlead "Time constant for communication lead between the plant-level controller and the generating unit-level controller" annotation( + Dialog(tab = "PlantCommunication")); + parameter Types.Time Tlag "Time constant for communication lag between the plant-level controller and the generating unit-level controller" annotation( + Dialog(tab = "PlantCommunication")); + parameter Integer ComFlag "0 if the communication delay is relatively long and affects the control, 1 if accurate modeling of the communication delay is provided, 2 for linear communication and 3 for 1st order lag communication" annotation( + Dialog(tab = "PlantCommunication")); + + //Storage parameters + parameter Boolean StorageFlag "1 if it is a storage unit, 0 if not" annotation( + Dialog(tab = "General")); + parameter Boolean SOCFlag "0 for battery energy storage systems, 1 for supercapacitor energy storage systems and flywheel energy storage systems" annotation( + Dialog(tab = "Storage")); + parameter Real SOCInit(unit = "%") "Initial SOC amount" annotation( + Dialog(tab = "Storage")); + parameter Real SOCMax(unit = "%") "Maximum SOC amount for charging" annotation( + Dialog(tab = "Storage")); + parameter Real SOCMin(unit = "%") "Minimum SOC amount for charging" annotation( + Dialog(tab = "Storage")); + parameter Types.Time Tess "Equivalent time constant for the battery, supercapacitor, + or flywheel energy storage systems" annotation( + Dialog(tab = "Storage")); + parameter Types.Time Tconv "Equivalent time for primary energy conversion" annotation( + Dialog(tab = "Storage")); + parameter Types.PerUnit PMaxPu "Maximum capacity of the CBGU" annotation( + Dialog(tab = "General")); + + //PControl Parameters + parameter Real KIp "Integral gain in the active power PI controller" annotation( + Dialog(tab = "PControl")); + parameter Real KPp "Proportional gain in the active power PI controller" annotation( + Dialog(tab = "PControl")); + parameter Types.Time TpRef "Time constant in the active power filter" annotation( + Dialog(tab = "PControl")); + parameter Boolean PFlag "1 for closed-loop active power control, 0 for open-loop active power control" annotation( + Dialog(tab = "PControl")); + parameter Boolean PriorityFlag "0 for active current priority, 1 for reactive current priority"; + parameter Types.Time Trocof "Time constant for frequency differential operation" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit fThresholdPu "Threshold at which the frequency is considered" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit f0Pu "Frequency setpoint for FFR control" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit PffrMaxPu "Maximum output power utilized for FFR control" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit PffrMinPu "Maximum absorbing power utilized for FFR control" annotation( + Dialog(tab = "FFR")); + parameter Boolean FFRflag "1 to enable the fast frequency response, 0 to disable the fast frequency response" annotation( + Dialog(tab = "FFR")); + parameter Real InertialTable[:, :] = [Pi11, Pi12; Pi21, Pi22] "Pair of points for frequence dependant powers piecewise linear curve [u1,y1; u2,y2;...]" annotation( + Dialog(tab = "FFR")); + parameter Real FFRTable[:, :] = [Pf11, Pf12; Pf21, Pf22] "Pair of points for frequence dependant powers piecewise linear curve [u1,y1; u2,y2;...]" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit Pi11 = -1 annotation( + Dialog(tab = "FFR tables")); + parameter Types.PerUnit Pi12 = -1 annotation( + Dialog(tab = "FFR tables")); + parameter Types.PerUnit Pi21 = 1 annotation( + Dialog(tab = "FFR tables")); + parameter Types.PerUnit Pi22 = 1 annotation( + Dialog(tab = "FFR tables")); + parameter Types.PerUnit Pf11 = -1 annotation( + Dialog(tab = "FFR tables")); + parameter Types.PerUnit Pf12 = -1 annotation( + Dialog(tab = "FFR tables")); + parameter Types.PerUnit Pf21 = 1 annotation( + Dialog(tab = "FFR tables")); + parameter Types.PerUnit Pf22 = 1 annotation( + Dialog(tab = "FFR tables")); + + //QControl Parameters + parameter Types.PerUnit QMaxUd "Maximum reactive power defined by users" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit QMinUd "Minimum reactive power defined by users" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit UMaxPu "Maximum voltage defined by users" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit UMinPu "Minimum voltage defined by users" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KPqu "Proportional gain in the reactive power PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KIqu "Integral gain in the reactive power PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KPuq "Proportional gain in the outer voltage PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KIuq "Integral gain in the outer voltage PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KPui "Proportional gain in the inner voltage PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KIui "Integral gain in the inner voltage PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KPqi "Proportional gain in the inner reactive power PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KIqi "Integral gain in the inner reactive power PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KDroop "Q/U droop gain" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit DUdb1Pu "Voltage change dead band lower limit (typically negative) in pu (base UNom)" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit DUdb2Pu "Voltage change dead band upper limit (typically positive) in pu (base UNom)" annotation( + Dialog(tab = "QControl")); + parameter Real TanPhi = Q0Pu / P0Pu "Power factor used in the power factor control" annotation( + Dialog(tab = "QControl")); + parameter Integer PFFlag annotation( + Dialog(tab = "QControl")); + parameter Integer LFlag annotation( + Dialog(tab = "QControl")); + parameter Boolean QLimFlag "0 to use the defined lookup tables, 1 to use the constant values" annotation( + Dialog(tab = "QControl")); + parameter Boolean UFlag annotation( + Dialog(tab = "QControl")); + parameter Types.Time Tiq "Time constant in reactive power order lag" annotation( + Dialog(tab = "QControl")); + + //LVRT and HVRT parameters + parameter Types.PerUnit uLVRTPu "LVRT threshold value" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit uHVRTPu "HVRT threshold value" annotation( + Dialog(tab = "FRT")); + parameter Boolean LVRTinPFlag = PFlag "Active current flag during LVRT, 0/1" annotation( + Dialog(tab = "FRT")); + parameter Boolean LVRTinQFlag "Reactive current flag during LVRT, 0/1" annotation( + Dialog(tab = "FRT")); + parameter Boolean HVRTinPFlag = PFlag "Active current flag during HVRT, 0/1" annotation( + Dialog(tab = "FRT")); + parameter Boolean HVRTinQFlag "Reactive current flag during HVRT, 0/1" annotation( + Dialog(tab = "FRT")); + parameter Real K1IpLV "Active current factor 1 during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2IpLV "Active current factor 2 during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K1IqLV "Reactive current factor 1 during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2IqLV "Reactive current factor 2 during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KpLVRT "Active power factor during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KqLVRT "Reactive power factor during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iPSetLVPu "Active current setting during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iQSetLVPu "Reactive current setting during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit pSetLVPu "Active power setting during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit qSetLVPu "Reactive power setting during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K1IpHV "Active current factor 1 during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2IpHV "Active current factor 2 during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K1IqHV "Reactive current factor 1 during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2IqHV "Reactive current factor 2 during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KpHVRT "Active power factor during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KqHVRT "Reactive power factor during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iPSetHVPu "Active current setting during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iQSetHVPu "Reactive current setting during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit pSetHVPu "Active power setting during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit qSetHVPu "Reactive power setting during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Boolean pqFRTFlag "Active/reactive control priority, 0/1" annotation( + Dialog(tab = "FRT")); + + //Circuit parameters + parameter Types.PerUnit BesPu "Shunt susceptance in pu (base UNom, SNom)" annotation( + Dialog(tab = "Electrical")); + parameter Types.PerUnit GesPu "Shunt conductance in pu (base UNom, SNom)" annotation( + Dialog(tab = "Electrical")); + parameter Types.PerUnit ResPu "Serial resistance in pu (base UNom, SNom)" annotation( + Dialog(tab = "Electrical")); + parameter Types.PerUnit XesPu "Serial reactance in pu (base UNom, SNom)" annotation( + Dialog(tab = "Electrical")); + parameter Types.Time Tg "Time constant to represent the control delay effect of the inner current control loop (larger than twice of the time step of 1/20 cycle [3]. Alternatively set it to zero to bypass this delay." annotation( + Dialog(tab = "CurrentSource")); + + //Grid measurement Parameters + parameter Types.Time TpFilt "Time constant in active power measurement filter" annotation( + Dialog(tab = "GridMeasurement")); + parameter Types.Time TqFilt "Time constant in reactive power measurement filter" annotation( + Dialog(tab = "GridMeasurement")); + parameter Types.Time TiFilt "Time constant in current measurement filter" annotation( + Dialog(tab = "GridMeasurement")); + parameter Types.Time TuFilt "Time constant in voltage measurement filter" annotation( + Dialog(tab = "GridMeasurement")); + + //PLL parameters + parameter Integer PLLFlag "0 for the case when the phase angle can be read from the calculation result of the simulation program, 1 for the case of adding a filter based on case 1, 2 for the case where the dynamics of the PLL need to be considered" annotation( + Dialog(tab = "PLL")); + parameter Types.Time TpllFilt "Time constant in PLL angle filter. Put 0 if no filter for the PLL (PLLFlag=2 in the norm)" annotation( + Dialog(tab = "PLL")); + parameter Types.Time TfFilt "Time constant in PLL angle filter. Put 0 if no filter for the PLL (PLLFlag=2 in the norm)" annotation( + Dialog(tab = "PLL")); + parameter Types.Time DeltaT "Integral time step" annotation( + Dialog(tab = "PLL")); + parameter Types.Frequency fref "Rated frequency (50/60 Hz)" annotation( + Dialog(tab = "PLL")); + parameter Real KPpll "Proportional gain in PI controller" annotation( + Dialog(tab = "PLL")); + parameter Real KIpll "Integral gain in PI controller" annotation( + Dialog(tab = "PLL")); + parameter Types.PerUnit UpllPu "Voltage below which the frequency of the voltage is filtered and the angle of the voltage is possibly frozen" annotation( + Dialog(tab = "PLL")); + parameter Types.AngularVelocity Wref = 2 * Modelica.Constants.pi * fref "Rated angular velocity" annotation( + Dialog(tab = "PLL")); + parameter Types.PerUnit WMaxPu "Maximum PLL frequency deviation" annotation( + Dialog(tab = "PLL")); + parameter Types.PerUnit WMinPu "Minimum PLL frequency deviation" annotation( + Dialog(tab = "PLL")); + parameter Types.AngularVelocityPu DfMaxPu = Wref "Maximum angle rotation ramp rate in rad/s" annotation( + Dialog(tab = "PLL")); + + //Input variables + Modelica.Blocks.Interfaces.RealInput pCmdPu(start = -P0Pu) annotation( + Placement(visible = true, transformation(origin = {-250, -120}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-260, 60}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput qCmdPu(start = -Q0Pu) annotation( + Placement(visible = true, transformation(origin = {-250, -140}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-260, -60}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput uCmdPu(start = U0Pu) annotation( + Placement(visible = true, transformation(origin = {-250, -160}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-260, -180}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput pPrimPu(start = -P0Pu) annotation( + Placement(visible = true, transformation(origin = {-260, 160}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-260, 180}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + + //Interfaces + Dynawo.Connectors.ACPower terminal(V(re(start = u0Pu.re), im(start = u0Pu.im)), i(re(start = i0Pu.re), im(start = i0Pu.im))) annotation( + Placement(visible = true, transformation(origin = {260, -80}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {250, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + Dynawo.Electrical.Controls.IEC.IEC63406.Measurement.GridMeasurement gridMeasurement(DeltaT = DeltaT, DfMaxPu = DfMaxPu, KIpll = KIpll, KPpll = KPpll, P0Pu = P0Pu, PLLFlag = PLLFlag, Q0Pu = Q0Pu, SNom = SNom, TfFilt = TfFilt, TpllFilt = TpllFilt, U0Pu = U0Pu, UPhase0 = UPhase0, UpllPu = UpllPu, WMaxPu = WMaxPu, WMinPu = WMinPu, fInitPu = fInitPu, fref = fref, i0Pu = i0Pu, tIFilt = TiFilt, tPFilt = TpFilt, tQFilt = TqFilt, tS = tS, tUFilt = TuFilt, thetaPLL(start = UPhase0), u0Pu = u0Pu) annotation( + Placement(visible = true, transformation(origin = {150, 70}, extent = {{50, -50}, {-50, 50}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.ControlAndProtection controlAndProtection(DUdb1Pu = DUdb1Pu, DUdb2Pu = DUdb2Pu, FFRflag = FFRflag, HVRTinQFlag = HVRTinQFlag, IMaxPu = IMaxPu, IPMax0Pu = IPMax0Pu, IPMaxPu = IPMaxPu, IPMin0Pu = IPMin0Pu, IPMinPu = IPMinPu, IQMax0Pu = IQMax0Pu, IQMaxPu = IQMaxPu, IQMin0Pu = IQMin0Pu, IQMinPu = IQMinPu, K1IpHV = K1IpHV, K1IpLV = K1IpLV, K1IqHV = K1IqHV, K1IqLV = K1IqLV, K2IpHV = K2IpHV, K2IpLV = K2IpLV, K2IqHV = K2IqHV, K2IqLV = K2IqLV, KDroop = KDroop, KIp = KIp, KIqi = KIqi, KIqu = KIqu, KIui = KIui, KIuq = KIuq, KPp = KPp, KPqi = KPqi, KPqu = KPqu, KPui = KPui, KPuq = KPuq, KpHVRT = KpHVRT, KpLVRT = KpLVRT, KqHVRT = KqHVRT, KqLVRT = KqLVRT, LFlag = LFlag, LVRTinQFlag = LVRTinQFlag, P0Pu = P0Pu, PAvailIn0Pu = PAvailIn0Pu, PAvailOut0Pu = PAvailOut0Pu, PFFR0Pu = PFFR0Pu, PFFlag = PFFlag, PFlag = PFlag, Pf11 = Pf11, Pf12 = Pf12, Pf21 = Pf21, Pf22 = Pf22, PffrMaxPu = PffrMaxPu, PffrMinPu = PffrMinPu, Pi11 = Pi11, Pi12 = Pi12, Pi21 = Pi21, Pi22 = Pi22, PriorityFlag = PriorityFlag, Q0Pu = Q0Pu, QLimFlag = QLimFlag, QMax0Pu = QMax0Pu, QMaxUd = QMaxUd, QMin0Pu = QMin0Pu, QMinUd = QMinUd, SNom = SNom, TanPhi = TanPhi, Tiq = Tiq, TpRef = TpRef, Trocof = Trocof, U0Pu = U0Pu, UFlag = UFlag, UMaxPu = UMaxPu, UMinPu = UMinPu, UPhase0 = UPhase0, f0Pu = f0Pu, fInitPu = fInitPu, fThresholdPu = fThresholdPu, iPSetHVPu = iPSetHVPu, iPSetLVPu = iPSetLVPu, iQSetHVPu = iQSetHVPu, iQSetLVPu = iQSetLVPu, pSetHVPu = pSetHVPu, pSetLVPu = pSetLVPu, pqFRTFlag = pqFRTFlag, qSetHVPu = qSetHVPu, qSetLVPu = qSetLVPu, uHVRTPu = uHVRTPu, uLVRTPu = uLVRTPu) annotation( + Placement(visible = true, transformation(origin = {-3.55271e-15, -80}, extent = {{-40, -40}, {40, 40}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.PrimaryEnergy.EnergyConversion energyConversion(P0Pu = P0Pu, PMaxPu = PMaxPu, SNom = SNom, SOCFlag = SOCFlag, SOCInit = SOCInit, SOCMax = SOCMax, SOCMin = SOCMin, StorageFlag = StorageFlag, Tconv = Tconv, Tess = Tess) annotation( + Placement(visible = true, transformation(origin = {-70, 150}, extent = {{-30, -30}, {30, 30}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.PlantCommunication plantCommunication(ComFlag = ComFlag, P0Pu = P0Pu, Q0Pu = Q0Pu, Tcom = Tcom, Tlag = Tlag, Tlead = Tlead, U0Pu = U0Pu) annotation( + Placement(visible = true, transformation(origin = {-180, -140}, extent = {{-40, -40}, {40, 40}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.InjectorCurrentSource injectorCurrentSource(BesPu = BesPu, GesPu = GesPu, IsIm0Pu = IsIm0Pu, IsRe0Pu = IsRe0Pu, P0Pu = P0Pu, Q0Pu = Q0Pu, ResPu = ResPu, SNom = SNom, Tg = Tg, U0Pu = U0Pu, UPhase0 = UPhase0, UsIm0Pu = UsIm0Pu, UsRe0Pu = UsRe0Pu, XesPu = XesPu, i0Pu = i0Pu, u0Pu = u0Pu) annotation( + Placement(visible = true, transformation(origin = {160, -80}, extent = {{-40, -40}, {40, 40}}, rotation = 0))); + + //Initial parameters + parameter Types.ComplexVoltagePu u0Pu "Initial complex voltage at grid terminal in pu (base UNom)" annotation( + Dialog(group = "Operating point")); + parameter Types.ComplexCurrentPu i0Pu "Initial complex current at grid terminal in pu (base UNom, SnRef) (receptor convention)" annotation( + Dialog(group = "Operating point")); + parameter Types.ActivePowerPu P0Pu "Initial active power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.ReactivePowerPu Q0Pu "Initial reactive power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.VoltageModulePu U0Pu "Initial voltage amplitude at grid terminal in pu (base UNom)" annotation( + Dialog(group = "Operating point")); + parameter Types.PerUnit UsIm0Pu "Initial imaginary component of the voltage at converter terminal in pu (base UNom)" annotation( + Dialog(group = "Operating point")); + parameter Types.PerUnit UsRe0Pu "Initial real component of the voltage at converter terminal in pu (base UNom)" annotation( + Dialog(group = "Operating point")); + parameter Types.PerUnit IsIm0Pu "Initial imaginary component of the current at converter terminal in pu (base UNom, SNom) (generator convention)" annotation( + Dialog(group = "Operating point")); + parameter Types.PerUnit IsRe0Pu "Initial real component of the current at converter terminal in pu (base UNom, SNom) (generator convention)" annotation( + Dialog(group = "Operating point")); + parameter Types.PerUnit fInitPu "Initial frequency" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit PAvailOut0Pu "Initial maximum output electrical power available to the active power control module" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit PAvailIn0Pu "Initial minimum output electrical power available to the active power control module" annotation( + Dialog(tab = "Operating point")); + parameter Types.Angle UPhase0 "Initial Phase angle outputted by phase-locked loop" annotation( + Dialog(group = "Operating point")); + parameter Types.PerUnit IPMin0Pu annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IPMax0Pu annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IQMax0Pu "Initial maximum reactive current" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IQMin0Pu "Initial minimum reactive current" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit QMax0Pu "Initial maximum reactive power" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit QMin0Pu "Initial minimum reactive power" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit PFFR0Pu "Initial output power utilized for FFR control" annotation( + Dialog(tab = "Operating point")); + +equation + connect(pCmdPu, plantCommunication.pCmdPu) annotation( + Line(points = {{-250, -120}, {-224, -120}}, color = {0, 0, 127})); + connect(qCmdPu, plantCommunication.qCmdPu) annotation( + Line(points = {{-250, -140}, {-224, -140}}, color = {0, 0, 127})); + connect(uCmdPu, plantCommunication.uCmdPu) annotation( + Line(points = {{-250, -160}, {-224, -160}}, color = {0, 0, 127})); + connect(pPrimPu, energyConversion.pPrimPu) annotation( + Line(points = {{-260, 160}, {-106, 160}}, color = {0, 0, 127})); + connect(gridMeasurement.PFiltPu, controlAndProtection.pMeasPu) annotation( + Line(points = {{95, 110}, {-80, 110}, {-80, -62}, {-44, -62}}, color = {0, 0, 127})); + connect(gridMeasurement.QFiltPu, controlAndProtection.qMeasPu) annotation( + Line(points = {{95, 100}, {-120, 100}, {-120, -80}, {-44, -80}}, color = {0, 0, 127})); + connect(gridMeasurement.UFiltPu, controlAndProtection.uMeasPu) annotation( + Line(points = {{95, 60}, {-100, 60}, {-100, -71}, {-44, -71}}, color = {0, 0, 127})); + connect(gridMeasurement.fFiltPu, controlAndProtection.fMeasPu) annotation( + Line(points = {{95, 40}, {-60, 40}, {-60, -53}, {-44, -53}}, color = {0, 0, 127})); + connect(gridMeasurement.thetaPLL, controlAndProtection.thetaPLL) annotation( + Line(points = {{95, 30}, {-20, 30}, {-20, -36}}, color = {0, 0, 127})); + connect(plantCommunication.pRefPu, controlAndProtection.pRefPu) annotation( + Line(points = {{-136, -120}, {-100, -120}, {-100, -89}, {-44, -89}}, color = {0, 0, 127})); + connect(plantCommunication.qRefPu, controlAndProtection.qRefPu) annotation( + Line(points = {{-136, -140}, {-80, -140}, {-80, -98}, {-44, -98}}, color = {0, 0, 127})); + connect(gridMeasurement.PFiltPu, energyConversion.pMeasPu) annotation( + Line(points = {{95, 110}, {-120, 110}, {-120, 140}, {-106, 140}}, color = {0, 0, 127})); + connect(energyConversion.pAvailOutPu, controlAndProtection.pAvailOutPu) annotation( + Line(points = {{-36, 140}, {20, 140}, {20, -36}}, color = {0, 0, 127})); + connect(energyConversion.pAvailInPu, controlAndProtection.pAvailInPu) annotation( + Line(points = {{-36, 160}, {0, 160}, {0, -36}}, color = {0, 0, 127})); + connect(injectorCurrentSource.terminal, terminal) annotation( + Line(points = {{204, -80}, {260, -80}}, color = {0, 0, 255})); + connect(gridMeasurement.thetaPLL, injectorCurrentSource.thetaPLL) annotation( + Line(points = {{96, 30}, {80, 30}, {80, 0}, {160, 0}, {160, -32}}, color = {0, 0, 127})); + connect(controlAndProtection.ipRefPu, injectorCurrentSource.ipRefPu) annotation( + Line(points = {{44, -72}, {80, -72}, {80, -60}, {112, -60}}, color = {0, 0, 127})); + connect(controlAndProtection.iqRefPu, injectorCurrentSource.iqRefPu) annotation( + Line(points = {{44, -88}, {80, -88}, {80, -100}, {112, -100}}, color = {0, 0, 127})); + connect(injectorCurrentSource.iPu, gridMeasurement.iPu) annotation( + Line(points = {{204, -48}, {220, -48}, {220, 70}, {206, 70}}, color = {85, 170, 255})); + connect(injectorCurrentSource.uPu, gridMeasurement.uPu) annotation( + Line(points = {{204, -60}, {230, -60}, {230, 100}, {206, 100}}, color = {85, 170, 255})); + connect(plantCommunication.uRefPu, controlAndProtection.uRefPu) annotation( + Line(points = {{-136, -160}, {-60, -160}, {-60, -106}, {-44, -106}}, color = {0, 0, 127})); + annotation( + Icon(graphics = {Rectangle(extent = {{-240, 240}, {240, -240}}), Text(extent = {{-240, 240}, {240, -240}}, textString = "Converter +Based +Generating +Unit")}, coordinateSystem(extent = {{-240, -240}, {240, 240}})), + Diagram(coordinateSystem(extent = {{-240, -240}, {240, 240}}))); +end ConverterCurrentSourceIEC63406; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/ConverterVoltageSourceIEC63406.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/ConverterVoltageSourceIEC63406.mo new file mode 100644 index 00000000000..16c8e13b044 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/ConverterVoltageSourceIEC63406.mo @@ -0,0 +1,368 @@ +within Dynawo.Electrical.Sources; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model ConverterVoltageSourceIEC63406 + + //Nominal parameter + parameter Types.ApparentPowerModule SNom "Nominal converter apparent power in MVA"; + parameter Types.Time tS "Integration time step in s"; + + //General parameters + parameter Types.PerUnit IMaxPu "Maximum current" annotation( + Dialog(tab = "General")); + parameter Types.PerUnit IPMaxPu "Maximum active current" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit IQMaxPu "Maximum reactive current" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit IPMinPu "Minimum active current" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit IQMinPu "Minimum reactive current" annotation( + Dialog(tab = "FRT")); + + //Communication Interface Parameters + parameter Types.Time Tcom "Time constant for communication delay between the plant-level controller and the generating unit-level controller" annotation( + Dialog(tab = "PlantCommunication")); + parameter Types.Time Tlead "Time constant for communication lead between the plant-level controller and the generating unit-level controller" annotation( + Dialog(tab = "PlantCommunication")); + parameter Types.Time Tlag "Time constant for communication lag between the plant-level controller and the generating unit-level controller" annotation( + Dialog(tab = "PlantCommunication")); + parameter Integer ComFlag "0 if the communication delay is relatively long and affects the control, 1 if accurate modeling of the communication delay is provided, 2 for linear communication and 3 for 1st order lag communication" annotation( + Dialog(tab = "PlantCommunication")); + + //Storage parameters + parameter Boolean StorageFlag "1 if it is a storage unit, 0 if not" annotation( + Dialog(tab = "General")); + parameter Boolean SOCFlag "0 for battery energy storage systems, 1 for supercapacitor energy storage systems and flywheel energy storage systems" annotation( + Dialog(tab = "Storage")); + parameter Real SOCInit(unit = "%") "Initial SOC amount" annotation( + Dialog(tab = "Storage")); + parameter Real SOCMax(unit = "%") "Maximum SOC amount for charging" annotation( + Dialog(tab = "Storage")); + parameter Real SOCMin(unit = "%") "Minimum SOC amount for charging" annotation( + Dialog(tab = "Storage")); + parameter Types.Time Tess "Equivalent time constant for the battery, supercapacitor, + or flywheel energy storage systems" annotation( + Dialog(tab = "Storage")); + parameter Types.Time Tconv "Equivalent time for primary energy conversion" annotation( + Dialog(tab = "Storage")); + parameter Types.PerUnit PMaxPu "Maximum capacity of the CBGU" annotation( + Dialog(tab = "General")); + + //PControl Parameters + parameter Real KIp "Integral gain in the active power PI controller" annotation( + Dialog(tab = "PControl")); + parameter Real KPp "Proportional gain in the active power PI controller" annotation( + Dialog(tab = "PControl")); + parameter Types.Time TpRef "Time constant in the active power filter" annotation( + Dialog(tab = "PControl")); + parameter Boolean PFlag "1 for closed-loop active power control, 0 for open-loop active power control" annotation( + Dialog(tab = "PControl")); + parameter Boolean PriorityFlag "0 for active current priority, 1 for reactive current priority"; + parameter Types.Time Trocof "Time constant for frequency differential operation" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit fThresholdPu "Threshold at which the frequency is considered" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit f0Pu "Frequency setpoint for FFR control" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit PffrMaxPu "Maximum output power utilized for FFR control" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit PffrMinPu "Maximum absorbing power utilized for FFR control" annotation( + Dialog(tab = "FFR")); + parameter Boolean FFRflag "1 to enable the fast frequency response, 0 to disable the fast frequency response" annotation( + Dialog(tab = "FFR")); + parameter Real InertialTable[:, :] = [Pi11, Pi12; Pi21, Pi22] "Pair of points for frequence dependant powers piecewise linear curve [u1,y1; u2,y2;...]" annotation( + Dialog(tab = "FFR")); + parameter Real FFRTable[:, :] = [Pf11, Pf12; Pf21, Pf22] "Pair of points for frequence dependant powers piecewise linear curve [u1,y1; u2,y2;...]" annotation( + Dialog(tab = "FFR")); + parameter Types.PerUnit Pi11 = -1 annotation( + Dialog(tab = "FFR tables")); + parameter Types.PerUnit Pi12 = -1 annotation( + Dialog(tab = "FFR tables")); + parameter Types.PerUnit Pi21 = 1 annotation( + Dialog(tab = "FFR tables")); + parameter Types.PerUnit Pi22 = 1 annotation( + Dialog(tab = "FFR tables")); + parameter Types.PerUnit Pf11 = -1 annotation( + Dialog(tab = "FFR tables")); + parameter Types.PerUnit Pf12 = -1 annotation( + Dialog(tab = "FFR tables")); + parameter Types.PerUnit Pf21 = 1 annotation( + Dialog(tab = "FFR tables")); + parameter Types.PerUnit Pf22 = 1 annotation( + Dialog(tab = "FFR tables")); + + //QControl Parameters + parameter Types.PerUnit QMaxUd "Maximum reactive power defined by users" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit QMinUd "Minimum reactive power defined by users" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit UMaxPu "Maximum voltage defined by users" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit UMinPu "Minimum voltage defined by users" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KPqu "Proportional gain in the reactive power PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KIqu "Integral gain in the reactive power PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KPuq "Proportional gain in the outer voltage PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KIuq "Integral gain in the outer voltage PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KPui "Proportional gain in the inner voltage PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KIui "Integral gain in the inner voltage PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KPqi "Proportional gain in the inner reactive power PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KIqi "Integral gain in the inner reactive power PI controller" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit KDroop "Q/U droop gain" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit DUdb1Pu "Voltage change dead band lower limit (typically negative) in pu (base UNom)" annotation( + Dialog(tab = "QControl")); + parameter Types.PerUnit DUdb2Pu "Voltage change dead band upper limit (typically positive) in pu (base UNom)" annotation( + Dialog(tab = "QControl")); + parameter Real TanPhi = Q0Pu / P0Pu "Power factor used in the power factor control" annotation( + Dialog(tab = "QControl")); + parameter Integer PFFlag annotation( + Dialog(tab = "QControl")); + parameter Integer LFlag annotation( + Dialog(tab = "QControl")); + parameter Boolean QLimFlag "0 to use the defined lookup tables, 1 to use the constant values" annotation( + Dialog(tab = "QControl")); + parameter Boolean UFlag annotation( + Dialog(tab = "QControl")); + parameter Types.Time Tiq "Time constant in reactive power order lag" annotation( + Dialog(tab = "QControl")); + + //LVRT and HVRT parameters + parameter Types.PerUnit uLVRTPu "LVRT threshold value" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit uHVRTPu "HVRT threshold value" annotation( + Dialog(tab = "FRT")); + parameter Boolean LVRTinPFlag = PFlag "Active current flag during LVRT, 0/1" annotation( + Dialog(tab = "FRT")); + parameter Boolean LVRTinQFlag "Reactive current flag during LVRT, 0/1" annotation( + Dialog(tab = "FRT")); + parameter Boolean HVRTinPFlag = PFlag "Active current flag during HVRT, 0/1" annotation( + Dialog(tab = "FRT")); + parameter Boolean HVRTinQFlag "Reactive current flag during HVRT, 0/1" annotation( + Dialog(tab = "FRT")); + parameter Real K1IpLV "Active current factor 1 during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2IpLV "Active current factor 2 during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K1IqLV "Reactive current factor 1 during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2IqLV "Reactive current factor 2 during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KpLVRT "Active power factor during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KqLVRT "Reactive power factor during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iPSetLVPu "Active current setting during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iQSetLVPu "Reactive current setting during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit pSetLVPu "Active power setting during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit qSetLVPu "Reactive power setting during LVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K1IpHV "Active current factor 1 during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2IpHV "Active current factor 2 during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K1IqHV "Reactive current factor 1 during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real K2IqHV "Reactive current factor 2 during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KpHVRT "Active power factor during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Real KqHVRT "Reactive power factor during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iPSetHVPu "Active current setting during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit iQSetHVPu "Reactive current setting during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit pSetHVPu "Active power setting during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Types.PerUnit qSetHVPu "Reactive power setting during HVRT" annotation( + Dialog(tab = "FRT")); + parameter Boolean pqFRTFlag "Active/reactive control priority, 0/1" annotation( + Dialog(tab = "FRT")); + + //Circuit parameters + parameter Types.PerUnit BesPu "Shunt susceptance in pu (base UNom, SNom)" annotation( + Dialog(tab = "Electrical")); + parameter Types.PerUnit GesPu "Shunt conductance in pu (base UNom, SNom)" annotation( + Dialog(tab = "Electrical")); + parameter Types.PerUnit ResPu "Serial resistance in pu (base UNom, SNom)" annotation( + Dialog(tab = "Electrical")); + parameter Types.PerUnit XesPu "Serial reactance in pu (base UNom, SNom)" annotation( + Dialog(tab = "Electrical")); + parameter Types.Time Tg "Time constant to represent the control delay effect of the inner current control loop (larger than twice of the time step of 1/20 cycle [3]. Alternatively set it to zero to bypass this delay." annotation( + Dialog(tab = "CurrentSource")); + + //Grid measurement Parameters + parameter Types.Time TpFilt "Time constant in active power measurement filter" annotation( + Dialog(tab = "GridMeasurement")); + parameter Types.Time TqFilt "Time constant in reactive power measurement filter" annotation( + Dialog(tab = "GridMeasurement")); + parameter Types.Time TiFilt "Time constant in current measurement filter" annotation( + Dialog(tab = "GridMeasurement")); + parameter Types.Time TuFilt "Time constant in voltage measurement filter" annotation( + Dialog(tab = "GridMeasurement")); + + //PLL parameters + parameter Integer PLLFlag "0 for the case when the phase angle can be read from the calculation result of the simulation program, 1 for the case of adding a filter based on case 1, 2 for the case where the dynamics of the PLL need to be considered" annotation( + Dialog(tab = "PLL")); + parameter Types.Time TpllFilt "Time constant in PLL angle filter. Put 0 if no filter for the PLL (PLLFlag=2 in the norm)" annotation( + Dialog(tab = "PLL")); + parameter Types.Time TfFilt "Time constant in PLL angle filter. Put 0 if no filter for the PLL (PLLFlag=2 in the norm)" annotation( + Dialog(tab = "PLL")); + parameter Types.Time DeltaT "Integral time step" annotation( + Dialog(tab = "PLL")); + parameter Types.Frequency fref "Rated frequency (50/60 Hz)" annotation( + Dialog(tab = "PLL")); + parameter Real KPpll "Proportional gain in PI controller" annotation( + Dialog(tab = "PLL")); + parameter Real KIpll "Integral gain in PI controller" annotation( + Dialog(tab = "PLL")); + parameter Types.PerUnit UpllPu "Voltage below which the frequency of the voltage is filtered and the angle of the voltage is possibly frozen" annotation( + Dialog(tab = "PLL")); + parameter Types.AngularVelocity Wref = 2 * Modelica.Constants.pi * fref "Rated angular velocity" annotation( + Dialog(tab = "PLL")); + parameter Types.PerUnit WMaxPu "Maximum PLL frequency deviation" annotation( + Dialog(tab = "PLL")); + parameter Types.PerUnit WMinPu "Minimum PLL frequency deviation" annotation( + Dialog(tab = "PLL")); + parameter Types.AngularVelocityPu DfMaxPu = Wref "Maximum angle rotation ramp rate in rad/s" annotation( + Dialog(tab = "PLL")); + + //Input variables + Modelica.Blocks.Interfaces.RealInput pCmdPu(start = -P0Pu) annotation( + Placement(visible = true, transformation(origin = {-250, -120}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-260, 60}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput qCmdPu(start = -Q0Pu) annotation( + Placement(visible = true, transformation(origin = {-250, -140}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-260, -60}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput uCmdPu(start = U0Pu) annotation( + Placement(visible = true, transformation(origin = {-250, -160}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-260, -180}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput pPrimPu(start = -P0Pu) annotation( + Placement(visible = true, transformation(origin = {-260, 160}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-260, 180}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + + //Interfaces + Dynawo.Connectors.ACPower terminal(V(re(start = u0Pu.re), im(start = u0Pu.im)), i(re(start = i0Pu.re), im(start = i0Pu.im))) annotation( + Placement(visible = true, transformation(origin = {260, -80}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {250, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + Dynawo.Electrical.Controls.IEC.IEC63406.Measurement.GridMeasurement gridMeasurement(DeltaT = DeltaT, DfMaxPu = DfMaxPu, KIpll = KIpll, KPpll = KPpll, P0Pu = P0Pu, PLLFlag = PLLFlag, Q0Pu = Q0Pu, SNom = SNom, TfFilt = TfFilt, TpllFilt = TpllFilt, U0Pu = U0Pu, UPhase0 = UPhase0, UpllPu = UpllPu, WMaxPu = WMaxPu, WMinPu = WMinPu, fInitPu = fInitPu, fref = fref, i0Pu = i0Pu, tIFilt = TiFilt, tPFilt = TpFilt, tQFilt = TqFilt, tS = tS, tUFilt = TuFilt, thetaPLL(start = UPhase0), u0Pu = u0Pu) annotation( + Placement(visible = true, transformation(origin = {150, 70}, extent = {{50, -50}, {-50, 50}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.ControlAndProtection controlAndProtection(DUdb1Pu = DUdb1Pu, DUdb2Pu = DUdb2Pu, FFRflag = FFRflag, HVRTinQFlag = HVRTinQFlag, IMaxPu = IMaxPu, IPMax0Pu = IPMax0Pu, IPMaxPu = IPMaxPu, IPMin0Pu = IPMin0Pu, IPMinPu = IPMinPu, IQMax0Pu = IQMax0Pu, IQMaxPu = IQMaxPu, IQMin0Pu = IQMin0Pu, IQMinPu = IQMinPu, K1IpHV = K1IpHV, K1IpLV = K1IpLV, K1IqHV = K1IqHV, K1IqLV = K1IqLV, K2IpHV = K2IpHV, K2IpLV = K2IpLV, K2IqHV = K2IqHV, K2IqLV = K2IqLV, KDroop = KDroop, KIp = KIp, KIqi = KIqi, KIqu = KIqu, KIui = KIui, KIuq = KIuq, KPp = KPp, KPqi = KPqi, KPqu = KPqu, KPui = KPui, KPuq = KPuq, KpHVRT = KpHVRT, KpLVRT = KpLVRT, KqHVRT = KqHVRT, KqLVRT = KqLVRT, LFlag = LFlag, LVRTinQFlag = LVRTinQFlag, P0Pu = P0Pu, PAvailIn0Pu = PAvailIn0Pu, PAvailOut0Pu = PAvailOut0Pu, PFFR0Pu = PFFR0Pu, PFFlag = PFFlag, PFlag = PFlag, Pf11 = Pf11, Pf12 = Pf12, Pf21 = Pf21, Pf22 = Pf22, PffrMaxPu = PffrMaxPu, PffrMinPu = PffrMinPu, Pi11 = Pi11, Pi12 = Pi12, Pi21 = Pi21, Pi22 = Pi22, PriorityFlag = PriorityFlag, Q0Pu = Q0Pu, QLimFlag = QLimFlag, QMax0Pu = QMax0Pu, QMaxUd = QMaxUd, QMin0Pu = QMin0Pu, QMinUd = QMinUd, SNom = SNom, TanPhi = TanPhi, Tiq = Tiq, TpRef = TpRef, Trocof = Trocof, U0Pu = U0Pu, UFlag = UFlag, UMaxPu = UMaxPu, UMinPu = UMinPu, UPhase0 = UPhase0, f0Pu = f0Pu, fInitPu = fInitPu, fThresholdPu = fThresholdPu, iPSetHVPu = iPSetHVPu, iPSetLVPu = iPSetLVPu, iQSetHVPu = iQSetHVPu, iQSetLVPu = iQSetLVPu, pSetHVPu = pSetHVPu, pSetLVPu = pSetLVPu, pqFRTFlag = pqFRTFlag, qSetHVPu = qSetHVPu, qSetLVPu = qSetLVPu, uHVRTPu = uHVRTPu, uLVRTPu = uLVRTPu) annotation( + Placement(visible = true, transformation(origin = {-3.55271e-15, -80}, extent = {{-40, -40}, {40, 40}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.PrimaryEnergy.EnergyConversion energyConversion(P0Pu = P0Pu, PMaxPu = PMaxPu, SNom = SNom, SOCFlag = SOCFlag, SOCInit = SOCInit, SOCMax = SOCMax, SOCMin = SOCMin, StorageFlag = StorageFlag, Tconv = Tconv, Tess = Tess) annotation( + Placement(visible = true, transformation(origin = {-70, 150}, extent = {{-30, -30}, {30, 30}}, rotation = 0))); + Dynawo.Electrical.Controls.IEC.IEC63406.PlantCommunication plantCommunication(ComFlag = ComFlag, P0Pu = P0Pu, Q0Pu = Q0Pu, Tcom = Tcom, Tlag = Tlag, Tlead = Tlead, U0Pu = U0Pu) annotation( + Placement(visible = true, transformation(origin = {-180, -140}, extent = {{-40, -40}, {40, 40}}, rotation = 0))); + + //Initial parameters + parameter Types.ComplexVoltagePu u0Pu "Initial complex voltage at grid terminal in pu (base UNom)" annotation( + Dialog(group = "Operating point")); + parameter Types.ComplexCurrentPu i0Pu "Initial complex current at grid terminal in pu (base UNom, SnRef) (receptor convention)" annotation( + Dialog(group = "Operating point")); + parameter Types.ActivePowerPu P0Pu "Initial active power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.ReactivePowerPu Q0Pu "Initial reactive power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.VoltageModulePu U0Pu "Initial voltage amplitude at grid terminal in pu (base UNom)" annotation( + Dialog(group = "Operating point")); + parameter Types.PerUnit UsIm0Pu "Initial imaginary component of the voltage at converter terminal in pu (base UNom)" annotation( + Dialog(group = "Operating point")); + parameter Types.PerUnit UsRe0Pu "Initial real component of the voltage at converter terminal in pu (base UNom)" annotation( + Dialog(group = "Operating point")); + parameter Types.PerUnit IsIm0Pu "Initial imaginary component of the current at converter terminal in pu (base UNom, SNom) (generator convention)" annotation( + Dialog(group = "Operating point")); + parameter Types.PerUnit IsRe0Pu "Initial real component of the current at converter terminal in pu (base UNom, SNom) (generator convention)" annotation( + Dialog(group = "Operating point")); + parameter Types.PerUnit fInitPu "Initial frequency" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit PAvailOut0Pu "Initial maximum output electrical power available to the active power control module" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit PAvailIn0Pu "Initial minimum output electrical power available to the active power control module" annotation( + Dialog(tab = "Operating point")); + parameter Types.Angle UPhase0 "Initial Phase angle outputted by phase-locked loop" annotation( + Dialog(group = "Operating point")); + parameter Types.PerUnit IPMin0Pu annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IPMax0Pu annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IQMax0Pu "Initial maximum reactive current" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit IQMin0Pu "Initial minimum reactive current" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit QMax0Pu "Initial maximum reactive power" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit QMin0Pu "Initial minimum reactive power" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit PFFR0Pu "Initial output power utilized for FFR control" annotation( + Dialog(tab = "Operating point")); + Dynawo.Electrical.Controls.IEC.IEC63406.InjectorVoltageSource injectorVoltageSource(BesPu = BesPu, GesPu = GesPu, IsIm0Pu = IsIm0Pu, IsRe0Pu = IsRe0Pu, P0Pu = P0Pu, Q0Pu = Q0Pu, ResPu = ResPu, SNom = SNom, Tg = Tg, U0Pu = U0Pu, UPhase0 = UPhase0, UsIm0Pu = UsIm0Pu, UsRe0Pu = UsRe0Pu, XesPu = XesPu, i0Pu = i0Pu, u0Pu = u0Pu) annotation( + Placement(visible = true, transformation(origin = {160, -80}, extent = {{-40, -40}, {40, 40}}, rotation = 0))); +equation + connect(pCmdPu, plantCommunication.pCmdPu) annotation( + Line(points = {{-250, -120}, {-224, -120}}, color = {0, 0, 127})); + connect(qCmdPu, plantCommunication.qCmdPu) annotation( + Line(points = {{-250, -140}, {-224, -140}}, color = {0, 0, 127})); + connect(uCmdPu, plantCommunication.uCmdPu) annotation( + Line(points = {{-250, -160}, {-224, -160}}, color = {0, 0, 127})); + connect(pPrimPu, energyConversion.pPrimPu) annotation( + Line(points = {{-260, 160}, {-106, 160}}, color = {0, 0, 127})); + connect(gridMeasurement.PFiltPu, controlAndProtection.pMeasPu) annotation( + Line(points = {{95, 110}, {-80, 110}, {-80, -62}, {-44, -62}}, color = {0, 0, 127})); + connect(gridMeasurement.QFiltPu, controlAndProtection.qMeasPu) annotation( + Line(points = {{95, 100}, {-120, 100}, {-120, -80}, {-44, -80}}, color = {0, 0, 127})); + connect(gridMeasurement.UFiltPu, controlAndProtection.uMeasPu) annotation( + Line(points = {{95, 60}, {-100, 60}, {-100, -71}, {-44, -71}}, color = {0, 0, 127})); + connect(gridMeasurement.fFiltPu, controlAndProtection.fMeasPu) annotation( + Line(points = {{95, 40}, {-60, 40}, {-60, -53}, {-44, -53}}, color = {0, 0, 127})); + connect(gridMeasurement.thetaPLL, controlAndProtection.thetaPLL) annotation( + Line(points = {{95, 30}, {-20, 30}, {-20, -36}}, color = {0, 0, 127})); + connect(plantCommunication.pRefPu, controlAndProtection.pRefPu) annotation( + Line(points = {{-136, -120}, {-100, -120}, {-100, -89}, {-44, -89}}, color = {0, 0, 127})); + connect(plantCommunication.qRefPu, controlAndProtection.qRefPu) annotation( + Line(points = {{-136, -140}, {-80, -140}, {-80, -98}, {-44, -98}}, color = {0, 0, 127})); + connect(gridMeasurement.PFiltPu, energyConversion.pMeasPu) annotation( + Line(points = {{95, 110}, {-120, 110}, {-120, 140}, {-106, 140}}, color = {0, 0, 127})); + connect(energyConversion.pAvailOutPu, controlAndProtection.pAvailOutPu) annotation( + Line(points = {{-36, 140}, {20, 140}, {20, -36}}, color = {0, 0, 127})); + connect(energyConversion.pAvailInPu, controlAndProtection.pAvailInPu) annotation( + Line(points = {{-36, 160}, {0, 160}, {0, -36}}, color = {0, 0, 127})); + connect(plantCommunication.uRefPu, controlAndProtection.uRefPu) annotation( + Line(points = {{-136, -160}, {-60, -160}, {-60, -106}, {-44, -106}}, color = {0, 0, 127})); + connect(controlAndProtection.ipRefPu, injectorVoltageSource.ipRefPu) annotation( + Line(points = {{44, -72}, {80, -72}, {80, -60}, {112, -60}}, color = {0, 0, 127})); + connect(controlAndProtection.iqRefPu, injectorVoltageSource.iqRefPu) annotation( + Line(points = {{44, -88}, {80, -88}, {80, -100}, {112, -100}}, color = {0, 0, 127})); + connect(gridMeasurement.thetaPLL, injectorVoltageSource.thetaPLL) annotation( + Line(points = {{96, 30}, {80, 30}, {80, 0}, {160, 0}, {160, -32}}, color = {0, 0, 127})); + connect(injectorVoltageSource.terminal, terminal) annotation( + Line(points = {{204, -80}, {260, -80}}, color = {0, 0, 255})); + connect(injectorVoltageSource.iPu, gridMeasurement.iPu) annotation( + Line(points = {{204, -48}, {220, -48}, {220, 70}, {206, 70}}, color = {85, 170, 255})); + connect(injectorVoltageSource.uPu, gridMeasurement.uPu) annotation( + Line(points = {{204, -60}, {230, -60}, {230, 100}, {206, 100}}, color = {85, 170, 255})); + annotation( + Icon(graphics = {Rectangle(extent = {{-240, 240}, {240, -240}}), Text(extent = {{-240, 240}, {240, -240}}, textString = "Converter +Based +Generating +Unit")}, coordinateSystem(extent = {{-240, -240}, {240, 240}})), + Diagram(coordinateSystem(extent = {{-240, -240}, {240, 240}}))); +end ConverterVoltageSourceIEC63406; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/IEC/BaseConverters/CurrentSourceIEC63406.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/IEC/BaseConverters/CurrentSourceIEC63406.mo new file mode 100644 index 00000000000..e5c523b7053 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/IEC/BaseConverters/CurrentSourceIEC63406.mo @@ -0,0 +1,87 @@ +within Dynawo.Electrical.Sources.IEC.BaseConverters; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model CurrentSourceIEC63406 "Converter system module with current source interface (IEC TS 63406 ED1)" + + //Nominal parameter + parameter Types.ApparentPowerModule SNom "Nominal converter apparent power in MVA"; + + //Control parameters + parameter Types.Time Tg "Time constant to represent the control delay effect of the inner current control loop (larger than twice of the time step of 1/20 cycle [3]. Alternatively set it to zero to bypass this delay." annotation( + Dialog(tab = "CurrentSource")); + + //Interface + Dynawo.Connectors.ACPower terminal(V(re(start = UGsRe0Pu), im(start = UGsIm0Pu)), i(re(start = -IGsRe0Pu * SNom / SystemBase.SnRef), im(start = -IGsIm0Pu * SNom / SystemBase.SnRef))) "Converter terminal, complex voltage and current in pu (base UNom, SnRef) (receptor convention)" annotation( + Placement(visible = true, transformation(origin = {150, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + //Input variables + Modelica.Blocks.Interfaces.RealInput ipRefPu(start = -P0Pu * SystemBase.SnRef / (SNom * U0Pu)) "Active current command at converter terminal in pu (base UNom, SNom) (generator convention)" annotation( + Placement(visible = true, transformation(origin = {-150, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-110, 40}, extent = {{10, -10}, {-10, 10}}, rotation = 180))); + Modelica.Blocks.Interfaces.RealInput iqRefPu(start = Q0Pu * SystemBase.SnRef / (SNom * U0Pu)) "Reactive current command at converter terminal in pu (base UNom, SNom) (generator convention)" annotation( + Placement(visible = true, transformation(origin = {-150, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-110, -40}, extent = {{10, -10}, {-10, 10}}, rotation = 180))); + input Boolean running(start = true) "True if the converter is running"; + Modelica.Blocks.Interfaces.RealInput thetaPLL(start = UPhase0) "Phase shift between the converter and the grid rotating frames in rad" annotation( + Placement(visible = true, transformation(origin = {-150, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {0, 110}, extent = {{10, -10}, {-10, 10}}, rotation = 90))); + + //Output variable + Dynawo.Electrical.Sources.IEC.BaseConverters.RefFrameRotation iECFrameRotation(IGsIm0Pu = IGsIm0Pu, IGsRe0Pu = IGsRe0Pu, P0Pu = P0Pu, Q0Pu = Q0Pu, SNom = SNom, U0Pu = U0Pu, UPhase0 = UPhase0) annotation( + Placement(visible = true, transformation(origin = {1.58946e-07, -4.76837e-07}, extent = {{-20, -60}, {20, 60}}, rotation = 0))); + Modelica.ComplexBlocks.ComplexMath.RealToComplex realToComplex annotation( + Placement(visible = true, transformation(origin = {70, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + Modelica.Blocks.Continuous.FirstOrder firstOrder(T = Tg, y_start = -P0Pu * SystemBase.SnRef / (SNom * U0Pu)) annotation( + Placement(visible = true, transformation(origin = {-90, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Continuous.FirstOrder firstOrder1(T = Tg, y_start = Q0Pu * SystemBase.SnRef / (SNom * U0Pu)) annotation( + Placement(visible = true, transformation(origin = {-90, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + //Initial parameters + parameter Types.PerUnit IGsIm0Pu "Initial imaginary component of the current at converter terminal in pu (base UNom, SNom) (generator convention)" annotation( + Dialog(group = "Initialization")); + parameter Types.PerUnit IGsRe0Pu "Initial real component of the current at converter terminal in pu (base UNom, SNom) (generator convention)" annotation( + Dialog(group = "Initialization")); + parameter Types.ActivePowerPu P0Pu "Initial active power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.ReactivePowerPu Q0Pu "Initial reactive power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.VoltageModulePu U0Pu "Initial voltage amplitude at grid terminal in pu (base UNom)" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit UGsIm0Pu "Initial imaginary component of the voltage at converter terminal in pu (base UNom)" annotation( + Dialog(group = "Initialization")); + parameter Types.PerUnit UGsRe0Pu "Initial real component of the voltage at converter terminal in pu (base UNom)" annotation( + Dialog(group = "Initialization")); + parameter Types.Angle UPhase0 "Initial voltage angle at grid terminal in rad" annotation( + Dialog(tab = "Operating point")); + +equation + Complex(iECFrameRotation.iGsRePu, iECFrameRotation.iGsImPu) = -terminal.i * (SystemBase.SnRef / SNom); + + connect(iECFrameRotation.iGsImPu, realToComplex.im) annotation( + Line(points = {{26, -30}, {40, -30}, {40, -6}, {58, -6}}, color = {0, 0, 127})); + connect(iECFrameRotation.iGsRePu, realToComplex.re) annotation( + Line(points = {{26, 30}, {40, 30}, {40, 6}, {58, 6}}, color = {0, 0, 127})); + connect(firstOrder.y, iECFrameRotation.ipCmdPu) annotation( + Line(points = {{-78, 60}, {-60, 60}, {-60, 54}, {-26, 54}}, color = {0, 0, 127})); + connect(firstOrder1.y, iECFrameRotation.iqCmdPu) annotation( + Line(points = {{-78, 0}, {-26, 0}}, color = {0, 0, 127})); + connect(ipRefPu, firstOrder.u) annotation( + Line(points = {{-150, 60}, {-102, 60}}, color = {0, 0, 127})); + connect(iqRefPu, firstOrder1.u) annotation( + Line(points = {{-150, 0}, {-102, 0}}, color = {0, 0, 127})); + connect(thetaPLL, iECFrameRotation.theta) annotation( + Line(points = {{-150, -60}, {-60, -60}, {-60, -54}, {-26, -54}}, color = {0, 0, 127})); + annotation( + preferredView = "diagram", + Diagram(graphics = {Line(origin = {90.7207, -0.279255}, points = {{-9, 0}, {9, 0}, {51, 0}}, color = {114, 159, 207})}, coordinateSystem(extent = {{-140, -100}, {140, 100}})), + Icon(coordinateSystem(grid = {1, 1}, initialScale = 0.1), graphics = {Rectangle(fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-100, 100}, {100, -100}}), Text(origin = {0, 30}, extent = {{-100, -20}, {100, 20}}, textString = "Generator"), Text(origin = {0, -30}, extent = {{-100, -20}, {100, 20}}, textString = "System")})); +end CurrentSourceIEC63406; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/IEC/BaseConverters/UgridToUconverter.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/IEC/BaseConverters/UgridToUconverter.mo new file mode 100644 index 00000000000..8288e2be993 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/IEC/BaseConverters/UgridToUconverter.mo @@ -0,0 +1,45 @@ +within Dynawo.Electrical.Sources.IEC.BaseConverters; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model UgridToUconverter + + //Parameters + parameter Types.PerUnit XesPu "Coupling inductance in the filter or the transformer at the grid side" annotation( + Dialog(tab = "Electrical")); + parameter Types.PerUnit ResPu "Coupling resistance in the filter or the transformer at the grid side" annotation( + Dialog(tab = "Electrical")); + + //Input variables + Modelica.Blocks.Interfaces.RealInput idPu annotation( + Placement(visible = true, transformation(origin = {-120, 40}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, 40}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput iqPu annotation( + Placement(visible = true, transformation(origin = {-120, -40}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-120, -40}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealInput ugqPu annotation( + Placement(visible = true, transformation(origin = {-40, -120}, extent = {{-20, -20}, {20, 20}}, rotation = 90), iconTransformation(origin = {-40, -120}, extent = {{-20, -20}, {20, 20}}, rotation = 90))); + Modelica.Blocks.Interfaces.RealInput ugdPu annotation( + Placement(visible = true, transformation(origin = {40, -120}, extent = {{-20, -20}, {20, 20}}, rotation = 90), iconTransformation(origin = {40, -120}, extent = {{-20, -20}, {20, 20}}, rotation = 90))); + + //Output variable + Modelica.Blocks.Interfaces.RealOutput uedPu annotation( + Placement(visible = true, transformation(origin = {110, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Interfaces.RealOutput ueqPu annotation( + Placement(visible = true, transformation(origin = {110, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + +equation + uedPu = ugdPu + idPu * ResPu - iqPu * XesPu; + ueqPu = ugqPu + iqPu * ResPu + idPu * XesPu; + +annotation( + Icon(graphics = {Rectangle(extent = {{-100, 100}, {100, -100}}), Text(origin = {1, 0}, extent = {{-97, 96}, {97, -96}}, textString = "Ugrid\nTo\nUconverter")})); +end UgridToUconverter; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/IEC/BaseConverters/VoltageSourceIEC63406.mo b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/IEC/BaseConverters/VoltageSourceIEC63406.mo new file mode 100644 index 00000000000..d612378794c --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/IEC/BaseConverters/VoltageSourceIEC63406.mo @@ -0,0 +1,118 @@ +within Dynawo.Electrical.Sources.IEC.BaseConverters; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model VoltageSourceIEC63406 "Converter system module with current source interface (IEC TS 63406 ED1)" + + //Nominal parameter + parameter Types.ApparentPowerModule SNom "Nominal converter apparent power in MVA"; + + //Control parameters + parameter Types.Time Tg "Time constant to represent the control delay effect of the inner current control loop (larger than twice of the time step of 1/20 cycle [3]. Alternatively set it to zero to bypass this delay." annotation( + Dialog(tab = "CurrentSource")); + parameter Types.PerUnit XesPu "Coupling inductance in the filter or the transformer at the grid side" annotation( + Dialog(tab = "Electrical")); + parameter Types.PerUnit ResPu "Coupling resistance in the filter or the transformer at the grid side" annotation( + Dialog(tab = "Electrical")); + + //Interface + Dynawo.Connectors.ACPower terminal(V(re(start = UGsRe0Pu), im(start = UGsIm0Pu)), i(re(start = -IGsRe0Pu * SNom / SystemBase.SnRef), im(start = -IGsIm0Pu * SNom / SystemBase.SnRef))) "Converter terminal, complex voltage and current in pu (base UNom, SnRef) (receptor convention)" annotation( + Placement(visible = true, transformation(origin = {210, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + //Input variables + Modelica.Blocks.Interfaces.RealInput ipRefPu(start = -P0Pu * SystemBase.SnRef / (SNom * U0Pu)) "Active current command at converter terminal in pu (base UNom, SNom) (generator convention)" annotation( + Placement(visible = true, transformation(origin = {-210, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-110, 40}, extent = {{10, -10}, {-10, 10}}, rotation = 180))); + Modelica.Blocks.Interfaces.RealInput iqRefPu(start = Q0Pu * SystemBase.SnRef / (SNom * U0Pu)) "Reactive current command at converter terminal in pu (base UNom, SNom) (generator convention)" annotation( + Placement(visible = true, transformation(origin = {-210, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-110, -40}, extent = {{10, -10}, {-10, 10}}, rotation = 180))); + input Boolean running(start = true) "True if the converter is running"; + Modelica.Blocks.Interfaces.RealInput thetaPLL(start = UPhase0) "Phase shift between the converter and the grid rotating frames in rad" annotation( + Placement(visible = true, transformation(origin = {-210, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {0, 110}, extent = {{10, -10}, {-10, 10}}, rotation = 90))); + + //Output variable + Dynawo.Electrical.Sources.IEC.BaseConverters.RefFrameRotation iECFrameRotation(IGsIm0Pu = IGsIm0Pu, IGsRe0Pu = IGsRe0Pu, P0Pu = P0Pu, Q0Pu = Q0Pu, SNom = SNom, U0Pu = U0Pu, UPhase0 = UPhase0) annotation( + Placement(visible = true, transformation(origin = {40, 20}, extent = {{-20, -60}, {20, 60}}, rotation = 0))); + Modelica.ComplexBlocks.ComplexMath.RealToComplex realToComplex annotation( + Placement(visible = true, transformation(origin = {110, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + Modelica.Blocks.Continuous.FirstOrder firstOrder(T = Tg, y_start = -P0Pu * SystemBase.SnRef / (SNom * U0Pu)) annotation( + Placement(visible = true, transformation(origin = {-170, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Continuous.FirstOrder firstOrder1(T = Tg, y_start = Q0Pu * SystemBase.SnRef / (SNom * U0Pu)) annotation( + Placement(visible = true, transformation(origin = {-170, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + //Initial parameters + parameter Types.PerUnit IGsIm0Pu "Initial imaginary component of the current at converter terminal in pu (base UNom, SNom) (generator convention)" annotation( + Dialog(group = "Initialization")); + parameter Types.PerUnit IGsRe0Pu "Initial real component of the current at converter terminal in pu (base UNom, SNom) (generator convention)" annotation( + Dialog(group = "Initialization")); + parameter Types.ActivePowerPu P0Pu "Initial active power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.ReactivePowerPu Q0Pu "Initial reactive power at grid terminal in pu (base SnRef) (receptor convention)" annotation( + Dialog(tab = "Operating point")); + parameter Types.VoltageModulePu U0Pu "Initial voltage amplitude at grid terminal in pu (base UNom)" annotation( + Dialog(tab = "Operating point")); + parameter Types.PerUnit UGsIm0Pu "Initial imaginary component of the voltage at converter terminal in pu (base UNom)" annotation( + Dialog(group = "Initialization")); + parameter Types.PerUnit UGsRe0Pu "Initial real component of the voltage at converter terminal in pu (base UNom)" annotation( + Dialog(group = "Initialization")); + parameter Types.Angle UPhase0 "Initial voltage angle at grid terminal in rad" annotation( + Dialog(tab = "Operating point")); + + Dynawo.Electrical.Sources.IEC.BaseConverters.UgridToUconverter ugridToUconverter(ResPu = ResPu, XesPu = XesPu) annotation( + Placement(visible = true, transformation(origin = {-100, 40}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); + Modelica.Blocks.Continuous.FirstOrder firstOrder2(T = Tg, y_start = -P0Pu * SystemBase.SnRef / (SNom * U0Pu)) annotation( + Placement(visible = true, transformation(origin = {-30, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Continuous.FirstOrder firstOrder3(T = Tg, y_start = Q0Pu * SystemBase.SnRef / (SNom * U0Pu)) annotation( + Placement(visible = true, transformation(origin = {-30, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.ComplexBlocks.Sources.ComplexExpression uGs(y = terminal.V) annotation( + Placement(visible = true, transformation(origin = {160, -60}, extent = {{20, -14}, {-20, 14}}, rotation = 0))); + Dynawo.Electrical.Controls.WECC.Utilities.TransformRItoDQ transformRItoDQ annotation( + Placement(visible = true, transformation(origin = {-40, -72}, extent = {{20, 20}, {-20, -20}}, rotation = 0))); + +equation + Complex(iECFrameRotation.iGsRePu, iECFrameRotation.iGsImPu) = terminal.V * (SystemBase.SnRef / SNom); //iGs is actually a voltage in this equation + + connect(iECFrameRotation.iGsImPu, realToComplex.im) annotation( + Line(points = {{66.6667, -10}, {80.6667, -10}, {80.6667, 14}, {98.6667, 14}}, color = {0, 0, 127})); + connect(iECFrameRotation.iGsRePu, realToComplex.re) annotation( + Line(points = {{66.6667, 50}, {80.6667, 50}, {80.6667, 26}, {98.6667, 26}}, color = {0, 0, 127})); + connect(ipRefPu, firstOrder.u) annotation( + Line(points = {{-210, 60}, {-182, 60}}, color = {0, 0, 127})); + connect(iqRefPu, firstOrder1.u) annotation( + Line(points = {{-210, 20}, {-182, 20}}, color = {0, 0, 127})); + connect(firstOrder1.y, ugridToUconverter.iqPu) annotation( + Line(points = {{-159, 20}, {-141, 20}, {-141, 32}, {-125, 32}}, color = {0, 0, 127})); + connect(firstOrder.y, ugridToUconverter.idPu) annotation( + Line(points = {{-159, 60}, {-140, 60}, {-140, 48}, {-124, 48}}, color = {0, 0, 127})); + connect(ugridToUconverter.uedPu, firstOrder2.u) annotation( + Line(points = {{-78, 48}, {-60, 48}, {-60, 60}, {-42, 60}}, color = {0, 0, 127})); + connect(ugridToUconverter.ueqPu, firstOrder3.u) annotation( + Line(points = {{-78, 32}, {-60, 32}, {-60, 20}, {-42, 20}}, color = {0, 0, 127})); + connect(firstOrder3.y, iECFrameRotation.iqCmdPu) annotation( + Line(points = {{-19, 20}, {13, 20}}, color = {0, 0, 127})); + connect(firstOrder2.y, iECFrameRotation.ipCmdPu) annotation( + Line(points = {{-18, 60}, {0, 60}, {0, 74}, {14, 74}}, color = {0, 0, 127})); + connect(uGs.y, transformRItoDQ.uPu) annotation( + Line(points = {{138, -60}, {40, -60}, {40, -84}, {-18, -84}}, color = {85, 170, 255})); + connect(transformRItoDQ.uqPu, ugridToUconverter.ugqPu) annotation( + Line(points = {{-62, -60}, {-108, -60}, {-108, 16}}, color = {0, 0, 127})); + connect(transformRItoDQ.udPu, ugridToUconverter.ugdPu) annotation( + Line(points = {{-62, -84}, {-92, -84}, {-92, 16}}, color = {0, 0, 127})); + connect(thetaPLL, transformRItoDQ.phi) annotation( + Line(points = {{-210, -40}, {0, -40}, {0, -60}, {-18, -60}}, color = {0, 0, 127})); + connect(thetaPLL, iECFrameRotation.theta) annotation( + Line(points = {{-210, -40}, {0, -40}, {0, -34}, {14, -34}}, color = {0, 0, 127})); + annotation( + preferredView = "diagram", + Diagram(graphics = {Line(origin = {130.991, 20.068}, points = {{-9, 0}, {9, 0}, {69, 0}}, color = {114, 159, 207})}, coordinateSystem(extent = {{-200, -100}, {200, 100}})), + Icon(coordinateSystem(extent = {{-200, -100}, {200, 100}}), graphics = {Rectangle(fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-100, 100}, {100, -100}}), Text(origin = {0, 30}, extent = {{-100, -20}, {100, 20}}, textString = "Generator"), Text(origin = {0, -30}, extent = {{-100, -20}, {100, 20}}, textString = "System")})); +end VoltageSourceIEC63406; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/IEC/BaseConverters/package.order b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/IEC/BaseConverters/package.order index 6318a6944bf..45d6b144cd4 100644 --- a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/IEC/BaseConverters/package.order +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/IEC/BaseConverters/package.order @@ -1,3 +1,6 @@ ElecSystem GenSystem4 RefFrameRotation +CurrentSourceIEC63406 +VoltageSourceIEC63406 +UgridToUconverter diff --git a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/package.order b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/package.order index 78c86d66c53..8e7d65a1e44 100644 --- a/dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/package.order +++ b/dynawo/sources/Models/Modelica/Dynawo/Electrical/Sources/package.order @@ -6,3 +6,5 @@ InjectorBG_INIT InjectorIDQ InjectorIDQ_INIT InjectorURI +ConverterCurrentSourceIEC63406 +ConverterVoltageSourceIEC63406 diff --git a/dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/IEC/CurrentSourceIEC63406.mo b/dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/IEC/CurrentSourceIEC63406.mo new file mode 100644 index 00000000000..154a8983703 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/IEC/CurrentSourceIEC63406.mo @@ -0,0 +1,99 @@ +within Dynawo.Examples.Converters.IEC; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model CurrentSourceIEC63406 + extends Icons.Example; + + Dynawo.Electrical.Lines.Line line2(BPu = 0.005, GPu = 0, RPu = 0.005, XPu = 0.05) annotation( + Placement(visible = true, transformation(origin = {90, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.Electrical.Events.NodeFault nodeFault1(RPu = 0, XPu = 0.4, tBegin = 12, tEnd = 12.15) annotation( + Placement(visible = true, transformation(origin = {-90, -40}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Dynawo.Electrical.Lines.Line line4(BPu = 0.005, GPu = 0, RPu = 0.015, XPu = 0.025) annotation( + Placement(visible = true, transformation(origin = {-30, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.Electrical.Lines.Line line(BPu = 0.005, GPu = 0, RPu = 0.005, XPu = 0.05) annotation( + Placement(visible = true, transformation(origin = {50, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.Electrical.Lines.Line line1(BPu = 0, GPu = 0, RPu = 0, XPu = 0.0457) annotation( + Placement(visible = true, transformation(origin = {130, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.Electrical.Transformers.TransformerFixedRatio transformer1(BPu = 0, GPu = 0, RPu = 0, XPu = 0.05, rTfoPu = 1) annotation( + Placement(visible = true, transformation(origin = {-70, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.Electrical.Lines.Line line3(BPu = 0.01, GPu = 0, RPu = 0.01, XPu = 0.1) annotation( + Placement(visible = true, transformation(origin = {70, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.Electrical.Transformers.TransformerFixedRatio transformer(BPu = 0, GPu = 0, RPu = 0, XPu = 0.1, rTfoPu = 1) annotation( + Placement(visible = true, transformation(origin = {10, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.Electrical.Buses.InfiniteBusWithVariations infiniteBusWithVariations(U0Pu = 1.0678, UEvtPu = 0, UPhase = -0.04, omega0Pu = 1, omegaEvtPu = 1.01, tOmegaEvtEnd = 14, tOmegaEvtStart = 13, tUEvtEnd = 0, tUEvtStart = 0) annotation( + Placement(visible = true, transformation(origin = {160, 0}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Modelica.Blocks.Sources.Step PRefPu(height = -0.5, offset = 1, startTime = 2) annotation( + Placement(visible = true, transformation(origin = {-210, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Step QRefPu(height = -0.1, offset = -0.21, startTime = 4) annotation( + Placement(visible = true, transformation(origin = {-210, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Step URefPu(height = -0.05, offset = 1, startTime = 4) annotation( + Placement(visible = true, transformation(origin = {-190, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Step pPrimPu(height = 0, offset = 1, startTime = 2) annotation( + Placement(visible = true, transformation(origin = {-190, 70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Electrical.Events.NodeFault nodeFault(RPu = 0, XPu = 0, tBegin = 6, tEnd = 6.25) annotation( + Placement(visible = true, transformation(origin = {70, -40}, extent = {{10, -10}, {-10, 10}}, rotation = 180))); + Dynawo.Electrical.Sources.ConverterCurrentSourceIEC63406 converterCurrentSourceIEC63406(BesPu = 0.7,ComFlag = 3, DUdb1Pu = -0.01, DUdb2Pu = 0.01, DeltaT = 0.001, FFRflag = false, GesPu = 0, HVRTinQFlag = false, IMaxPu = 1.3, IPMax0Pu = 1.2, IPMaxPu = 1.2, IPMin0Pu = -1.2, IPMinPu = -1.2, IQMax0Pu = 0.4, IQMaxPu = 1.2, IQMin0Pu = -0.4, IQMinPu = -1.2, IsIm0Pu = 0.423168, IsRe0Pu = 0.930069, K1IpHV = 0, K1IpLV = 0, K1IqHV = -2, K1IqLV = -2, K2IpHV = 1, K2IpLV = 1, K2IqHV = 0, K2IqLV = 0, KDroop = 1, KIp = 10, KIpll = 20, KIqi = 10, KIqu = 10, KIui = 10, KIuq = 10, KPp = 2, KPpll = 3, KPqi = 2, KPqu = 2, KPui = 2, KPuq = 2, KpHVRT = 1, KpLVRT = 1, KqHVRT = 1, KqLVRT = 1, LFlag = 2, LVRTinQFlag = false, P0Pu = -1, PAvailIn0Pu = 0, PAvailOut0Pu = 999, PFFR0Pu = 0, PFFlag = 1, PFlag = false, PLLFlag = 0, PMaxPu = 1, PffrMaxPu = 0.05, PffrMinPu = -0.05, PriorityFlag = true, Q0Pu = 0.21, QLimFlag = true, QMax0Pu = 0.8, QMaxUd = 0.8, QMin0Pu = -0.8, QMinUd = -0.8, ResPu = 0, SNom = 100, SOCFlag = false, SOCInit = 50, SOCMax = 100, SOCMin = 10, StorageFlag = false, Tcom = 0.01, Tconv = 1, Tess = 10, TfFilt = 0.01, Tg = 0.01, TiFilt = 0.01, Tiq = 0.01, Tlag = 1, Tlead = 1, TpFilt = 0.01, TpRef = 0.1, TpllFilt = 0.01, TqFilt = 0.01, Trocof = 0.01, TuFilt = 0.01, U0Pu = 1, UFlag = false, UMaxPu = 1.1, UMinPu = 0.9, UPhase0 = 0.21949, UpllPu = 0.1, UsIm0Pu = 0.2183, UsRe0Pu = 0.975897, WMaxPu = 0.5, WMinPu = -0.5, XesPu = 0, f0Pu = 1, fInitPu = 1, fThresholdPu = 0.001, fref = 50, i0Pu = Complex(-0.930069, -0.423168), iPSetHVPu = 0, iPSetLVPu = 0, iQSetHVPu = 0, iQSetLVPu = 0, pSetHVPu = 0, pSetLVPu = 0, pqFRTFlag = true, qSetHVPu = 0, qSetLVPu = 0, tS = 0.001, u0Pu = Complex(0.975897, 0.2183), uHVRTPu = 1.1, uLVRTPu = 0.9) annotation( + Placement(visible = true, transformation(origin = {-120, 1.77636e-15}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); +equation + converterCurrentSourceIEC63406.injectorCurrentSource.switchOffSignal1.value = false; + converterCurrentSourceIEC63406.injectorCurrentSource.switchOffSignal2.value = false; + converterCurrentSourceIEC63406.injectorCurrentSource.switchOffSignal3.value = false; + line.switchOffSignal1.value = false; + line.switchOffSignal2.value = false; + line1.switchOffSignal1.value = false; + line1.switchOffSignal2.value = false; + line2.switchOffSignal1.value = false; + line2.switchOffSignal2.value = false; + line3.switchOffSignal1.value = false; + line3.switchOffSignal2.value = false; + line4.switchOffSignal1.value = false; + line4.switchOffSignal2.value = false; + transformer.switchOffSignal1.value = false; + transformer.switchOffSignal2.value = false; + transformer1.switchOffSignal1.value = false; + transformer1.switchOffSignal2.value = false; + connect(transformer1.terminal2, line4.terminal1) annotation( + Line(points = {{-60, 0}, {-40, 0}}, color = {0, 0, 255})); + connect(line.terminal2, line2.terminal1) annotation( + Line(points = {{60, -20}, {80, -20}}, color = {0, 0, 255})); + connect(infiniteBusWithVariations.terminal, line1.terminal2) annotation( + Line(points = {{160, 0}, {140, 0}}, color = {0, 0, 255})); + connect(transformer.terminal2, line.terminal1) annotation( + Line(points = {{20, 0}, {40, 0}, {40, -20}}, color = {0, 0, 255})); + connect(line1.terminal1, line2.terminal2) annotation( + Line(points = {{120, 0}, {100, 0}, {100, -20}}, color = {0, 0, 255})); + connect(transformer.terminal2, line3.terminal1) annotation( + Line(points = {{20, 0}, {40, 0}, {40, 20}, {60, 20}}, color = {0, 0, 255})); + connect(line3.terminal2, line1.terminal1) annotation( + Line(points = {{80, 20}, {100, 20}, {100, 0}, {120, 0}}, color = {0, 0, 255})); + connect(line4.terminal2, transformer.terminal1) annotation( + Line(points = {{-20, 0}, {0, 0}}, color = {0, 0, 255})); + connect(line.terminal2, nodeFault.terminal) annotation( + Line(points = {{60, -20}, {70, -20}, {70, -40}}, color = {0, 0, 255})); + connect(pPrimPu.y, converterCurrentSourceIEC63406.pPrimPu) annotation( + Line(points = {{-178, 70}, {-160, 70}, {-160, 15}, {-142, 15}}, color = {0, 0, 127})); + connect(PRefPu.y, converterCurrentSourceIEC63406.pCmdPu) annotation( + Line(points = {{-198, 30}, {-180, 30}, {-180, 5}, {-142, 5}}, color = {0, 0, 127})); + connect(QRefPu.y, converterCurrentSourceIEC63406.qCmdPu) annotation( + Line(points = {{-198, -30}, {-180, -30}, {-180, -5}, {-142, -5}}, color = {0, 0, 127})); + connect(URefPu.y, converterCurrentSourceIEC63406.uCmdPu) annotation( + Line(points = {{-178, -70}, {-160, -70}, {-160, -15}, {-142, -15}}, color = {0, 0, 127})); + connect(converterCurrentSourceIEC63406.terminal, transformer1.terminal1) annotation( + Line(points = {{-100, 0}, {-80, 0}}, color = {0, 0, 255})); + connect(converterCurrentSourceIEC63406.terminal, nodeFault1.terminal) annotation( + Line(points = {{-100, 0}, {-90, 0}, {-90, -40}}, color = {0, 0, 255})); +protected + annotation( + experiment(StartTime = 0, StopTime = 15, Tolerance = 1e-06, Interval = 0.001)); +end CurrentSourceIEC63406; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/IEC/VoltageSourceIEC63406.mo b/dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/IEC/VoltageSourceIEC63406.mo new file mode 100644 index 00000000000..718232c5c84 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/IEC/VoltageSourceIEC63406.mo @@ -0,0 +1,99 @@ +within Dynawo.Examples.Converters.IEC; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +model VoltageSourceIEC63406 + extends Icons.Example; + + Dynawo.Electrical.Lines.Line line2(BPu = 0.005, GPu = 0, RPu = 0.005, XPu = 0.05) annotation( + Placement(visible = true, transformation(origin = {90, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.Electrical.Events.NodeFault nodeFault1(RPu = 0, XPu = 0.4, tBegin = 12, tEnd = 12.15) annotation( + Placement(visible = true, transformation(origin = {-90, -40}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Dynawo.Electrical.Lines.Line line4(BPu = 0.005, GPu = 0, RPu = 0.015, XPu = 0.025) annotation( + Placement(visible = true, transformation(origin = {-30, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.Electrical.Lines.Line line(BPu = 0.005, GPu = 0, RPu = 0.005, XPu = 0.05) annotation( + Placement(visible = true, transformation(origin = {50, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.Electrical.Lines.Line line1(BPu = 0, GPu = 0, RPu = 0, XPu = 0.0457) annotation( + Placement(visible = true, transformation(origin = {130, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.Electrical.Transformers.TransformerFixedRatio transformer1(BPu = 0, GPu = 0, RPu = 0, XPu = 0.05, rTfoPu = 1) annotation( + Placement(visible = true, transformation(origin = {-70, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.Electrical.Lines.Line line3(BPu = 0.01, GPu = 0, RPu = 0.01, XPu = 0.1) annotation( + Placement(visible = true, transformation(origin = {70, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.Electrical.Transformers.TransformerFixedRatio transformer(BPu = 0, GPu = 0, RPu = 0, XPu = 0.1, rTfoPu = 1) annotation( + Placement(visible = true, transformation(origin = {10, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Dynawo.Electrical.Buses.InfiniteBusWithVariations infiniteBusWithVariations(U0Pu = 1.0678, UEvtPu = 0, UPhase = -0.04, omega0Pu = 1, omegaEvtPu = 1.01, tOmegaEvtEnd = 14, tOmegaEvtStart = 13, tUEvtEnd = 0, tUEvtStart = 0) annotation( + Placement(visible = true, transformation(origin = {160, 0}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Modelica.Blocks.Sources.Step PRefPu(height = -0.5, offset = 1, startTime = 2) annotation( + Placement(visible = true, transformation(origin = {-210, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Step QRefPu(height = -0.1, offset = -0.21, startTime = 4) annotation( + Placement(visible = true, transformation(origin = {-210, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Step URefPu(height = -0.05, offset = 1, startTime = 4) annotation( + Placement(visible = true, transformation(origin = {-190, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Sources.Step pPrimPu(height = 0, offset = 1, startTime = 2) annotation( + Placement(visible = true, transformation(origin = {-190, 70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Electrical.Events.NodeFault nodeFault(RPu = 0, XPu = 0, tBegin = 6, tEnd = 6.25) annotation( + Placement(visible = true, transformation(origin = {70, -40}, extent = {{10, -10}, {-10, 10}}, rotation = 180))); + Dynawo.Electrical.Sources.ConverterVoltageSourceIEC63406 converterVoltageSourceIEC63406(BesPu = 0, ComFlag = 3, DUdb1Pu = -0.01, DUdb2Pu = 0.01, DeltaT = 0.001, FFRflag = false, GesPu = 0,HVRTinQFlag = false, IMaxPu = 1.3, IPMax0Pu = 1.2, IPMaxPu = 1.2, IPMin0Pu = -1.2, IPMinPu = -1.2, IQMax0Pu = 0.4, IQMaxPu = 1.2, IQMin0Pu = -0.4, IQMinPu = -1.2, IsIm0Pu = 0.423168, IsRe0Pu = 0.930069, K1IpHV = 0, K1IpLV = 0, K1IqHV = -2, K1IqLV = -2, K2IpHV = 1, K2IpLV = 1, K2IqHV = 0, K2IqLV = 0, KDroop = 1, KIp = 10, KIpll = 20, KIqi = 10, KIqu = 10, KIui = 10, KIuq = 10, KPp = 2, KPpll = 3, KPqi = 2, KPqu = 2, KPui = 2, KPuq = 2, KpHVRT = 1, KpLVRT = 1, KqHVRT = 1, KqLVRT = 1, LFlag = 2, LVRTinQFlag = false, P0Pu = -1, PAvailIn0Pu = 0, PAvailOut0Pu = 999, PFFR0Pu = 0, PFFlag = 1, PFlag = false, PLLFlag = 0, PMaxPu = 1, PffrMaxPu = 0.05, PffrMinPu = -0.05, PriorityFlag = true, Q0Pu = 0.21, QLimFlag = true, QMax0Pu = 0.8, QMaxUd = 0.8, QMin0Pu = -0.8, QMinUd = -0.8, ResPu = 0, SNom = 100, SOCFlag = false, SOCInit = 50, SOCMax = 100, SOCMin = 10, StorageFlag = false, Tcom = 0.01, Tconv = 1, Tess = 10, TfFilt = 0.01, Tg = 0.01, TiFilt = 0.01, Tiq = 0.01, Tlag = 1, Tlead = 1, TpFilt = 0.01, TpRef = 0.1, TpllFilt = 0.01, TqFilt = 0.01, Trocof = 0.01, TuFilt = 0.01, U0Pu = 1, UFlag = true, UMaxPu = 1.1, UMinPu = 0.9, UPhase0 = 0.21949, UpllPu = 0.1, UsIm0Pu = 0.2183, UsRe0Pu = 0.975897, WMaxPu = 0.5, WMinPu = -0.5, XesPu = 0, f0Pu = 1, fInitPu = 1, fThresholdPu = 0.001, fref = 50, i0Pu = Complex(-0.930069, -0.423168), iPSetHVPu = 0, iPSetLVPu = 0, iQSetHVPu = 0, iQSetLVPu = 0, pSetHVPu = 0, pSetLVPu = 0, pqFRTFlag = true, qSetHVPu = 0, qSetLVPu = 0, tS = 0.001, u0Pu = Complex(0.975897, 0.2183), uHVRTPu = 1.1, uLVRTPu = 0.9) annotation( + Placement(visible = true, transformation(origin = {-120, 0}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); +equation + converterVoltageSourceIEC63406.injectorVoltageSource.switchOffSignal1.value = false; + converterVoltageSourceIEC63406.injectorVoltageSource.switchOffSignal2.value = false; + converterVoltageSourceIEC63406.injectorVoltageSource.switchOffSignal3.value = false; + line.switchOffSignal1.value = false; + line.switchOffSignal2.value = false; + line1.switchOffSignal1.value = false; + line1.switchOffSignal2.value = false; + line2.switchOffSignal1.value = false; + line2.switchOffSignal2.value = false; + line3.switchOffSignal1.value = false; + line3.switchOffSignal2.value = false; + line4.switchOffSignal1.value = false; + line4.switchOffSignal2.value = false; + transformer.switchOffSignal1.value = false; + transformer.switchOffSignal2.value = false; + transformer1.switchOffSignal1.value = false; + transformer1.switchOffSignal2.value = false; + connect(transformer1.terminal2, line4.terminal1) annotation( + Line(points = {{-60, 0}, {-40, 0}}, color = {0, 0, 255})); + connect(line.terminal2, line2.terminal1) annotation( + Line(points = {{60, -20}, {80, -20}}, color = {0, 0, 255})); + connect(infiniteBusWithVariations.terminal, line1.terminal2) annotation( + Line(points = {{160, 0}, {140, 0}}, color = {0, 0, 255})); + connect(transformer.terminal2, line.terminal1) annotation( + Line(points = {{20, 0}, {40, 0}, {40, -20}}, color = {0, 0, 255})); + connect(line1.terminal1, line2.terminal2) annotation( + Line(points = {{120, 0}, {100, 0}, {100, -20}}, color = {0, 0, 255})); + connect(transformer.terminal2, line3.terminal1) annotation( + Line(points = {{20, 0}, {40, 0}, {40, 20}, {60, 20}}, color = {0, 0, 255})); + connect(line3.terminal2, line1.terminal1) annotation( + Line(points = {{80, 20}, {100, 20}, {100, 0}, {120, 0}}, color = {0, 0, 255})); + connect(line4.terminal2, transformer.terminal1) annotation( + Line(points = {{-20, 0}, {0, 0}}, color = {0, 0, 255})); + connect(line.terminal2, nodeFault.terminal) annotation( + Line(points = {{60, -20}, {70, -20}, {70, -40}}, color = {0, 0, 255})); + connect(pPrimPu.y, converterVoltageSourceIEC63406.pPrimPu) annotation( + Line(points = {{-178, 70}, {-160, 70}, {-160, 16}, {-142, 16}}, color = {0, 0, 127})); + connect(PRefPu.y, converterVoltageSourceIEC63406.pCmdPu) annotation( + Line(points = {{-198, 30}, {-180, 30}, {-180, 6}, {-142, 6}}, color = {0, 0, 127})); + connect(QRefPu.y, converterVoltageSourceIEC63406.qCmdPu) annotation( + Line(points = {{-198, -30}, {-180, -30}, {-180, -6}, {-142, -6}}, color = {0, 0, 127})); + connect(URefPu.y, converterVoltageSourceIEC63406.uCmdPu) annotation( + Line(points = {{-178, -70}, {-160, -70}, {-160, -16}, {-142, -16}}, color = {0, 0, 127})); + connect(converterVoltageSourceIEC63406.terminal, transformer1.terminal1) annotation( + Line(points = {{-100, 0}, {-80, 0}}, color = {0, 0, 255})); + connect(converterVoltageSourceIEC63406.terminal, nodeFault1.terminal) annotation( + Line(points = {{-100, 0}, {-90, 0}, {-90, -40}}, color = {0, 0, 255})); +protected + annotation( + experiment(StartTime = 0, StopTime = 15, Tolerance = 1e-06, Interval = 0.001)); +end VoltageSourceIEC63406; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/IEC/package.mo b/dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/IEC/package.mo new file mode 100644 index 00000000000..28b8b202ee2 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/IEC/package.mo @@ -0,0 +1,17 @@ +within Dynawo.Examples.Converters; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +package IEC + extends Icons.Package; +end IEC; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/IEC/package.order b/dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/IEC/package.order new file mode 100644 index 00000000000..df80dd95d3f --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/IEC/package.order @@ -0,0 +1,2 @@ +CurrentSourceIEC63406 +VoltageSourceIEC63406 diff --git a/dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/package.mo b/dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/package.mo new file mode 100644 index 00000000000..27905d22f31 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/package.mo @@ -0,0 +1,17 @@ +within Dynawo.Examples; + +/* +* Copyright (c) 2024, RTE (http://www.rte-france.com) +* See AUTHORS.txt +* All rights reserved. +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, you can obtain one at http://mozilla.org/MPL/2.0/. +* SPDX-License-Identifier: MPL-2.0 +* +* This file is part of Dynawo, an hybrid C++/Modelica open source suite of simulation tools for power systems. +*/ + +package Converters + extends Icons.Package; +end Converters; diff --git a/dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/package.order b/dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/package.order new file mode 100644 index 00000000000..ad1a83d1b64 --- /dev/null +++ b/dynawo/sources/Models/Modelica/Dynawo/Examples/Converters/package.order @@ -0,0 +1 @@ +IEC diff --git a/dynawo/sources/Models/Modelica/Dynawo/Examples/package.order b/dynawo/sources/Models/Modelica/Dynawo/Examples/package.order index 5ed3b633bf7..61da4d8bb56 100644 --- a/dynawo/sources/Models/Modelica/Dynawo/Examples/package.order +++ b/dynawo/sources/Models/Modelica/Dynawo/Examples/package.order @@ -10,3 +10,4 @@ SVarC Photovoltaics Wind DynaFlow +Converters