diff --git a/examples/PhasorDynamics/Tiny/TwoBus/Tgov1/TwoBusTgov1.cpp b/examples/PhasorDynamics/Tiny/TwoBus/Tgov1/TwoBusTgov1.cpp index cc76cbccd..468d8193d 100644 --- a/examples/PhasorDynamics/Tiny/TwoBus/Tgov1/TwoBusTgov1.cpp +++ b/examples/PhasorDynamics/Tiny/TwoBus/Tgov1/TwoBusTgov1.cpp @@ -131,14 +131,15 @@ int main() // Add bus fault to bus0 BusFault fault(bus0, data.bus_fault[0]); - // Create generator - Genrou gen(bus0, - omega, - pmech, - data.genrou[0]); - - // Create governor - Governor::Tgov1 gov(pmech, omega); + // Create generator and make its signal connections + Genrou gen(bus0, data.genrou[0]); + gen.getSignals().template attachSignalNode(pmech); + gen.getSignals().template assignSignalNode(omega); + + // Create governor and make its signal connections + Governor::Tgov1 gov(data.gov[0]); + gov.getSignals().template assignSignalNode(pmech); + gov.getSignals().template attachSignalNode(omega); // // Instantiate system model and add components to it diff --git a/src/Model/PhasorDynamics/Branch/Branch.hpp b/src/Model/PhasorDynamics/Branch/Branch.hpp index 5be4657c6..1128dcb03 100644 --- a/src/Model/PhasorDynamics/Branch/Branch.hpp +++ b/src/Model/PhasorDynamics/Branch/Branch.hpp @@ -9,6 +9,7 @@ #pragma once #include +#include // Forward declarations. namespace GridKit diff --git a/src/Model/PhasorDynamics/BusFault/BusFault.hpp b/src/Model/PhasorDynamics/BusFault/BusFault.hpp index 11ec32fb0..cbf7a9bb3 100644 --- a/src/Model/PhasorDynamics/BusFault/BusFault.hpp +++ b/src/Model/PhasorDynamics/BusFault/BusFault.hpp @@ -3,6 +3,7 @@ #include #include +#include // Forward declaration of BusData structure namespace GridKit diff --git a/src/Model/PhasorDynamics/Component.hpp b/src/Model/PhasorDynamics/Component.hpp index 616989fdd..7dab50b4f 100644 --- a/src/Model/PhasorDynamics/Component.hpp +++ b/src/Model/PhasorDynamics/Component.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include diff --git a/src/Model/PhasorDynamics/ComponentSignals.hpp b/src/Model/PhasorDynamics/ComponentSignals.hpp new file mode 100644 index 000000000..c1733eb8c --- /dev/null +++ b/src/Model/PhasorDynamics/ComponentSignals.hpp @@ -0,0 +1,117 @@ +#pragma once + +#include +#include +#include + +#include + +namespace GridKit +{ + namespace PhasorDynamics + { + /// Dummy `Variables` type for components with no variables + enum class NoVariables : size_t + { + MAXIMUM + }; + + /// Concept requiring an enum to have a `MAXIMUM` variant and that it have + /// the underlying type of `size_t`. This does not ensure the variant is + /// the actual maximum + template + concept EnumHasMaximumValueAndIsSizeT = std::is_enum_v + && std::is_same_v, size_t> + && requires { T::MAXIMUM; }; + + /// Extension object for `Component`s adding methods and member variables + /// related to signal bus management + /// + /// This is used by adding an instance in a field to your class and + /// exposing this field to others + template + requires EnumHasMaximumValueAndIsSizeT + && EnumHasMaximumValueAndIsSizeT + class ComponentSignals + { + public: + /// Attaches a signal node to an external variable on this component + template + auto attachSignalNode(SignalNode* signal) + { + external_variable_signals_[static_cast(variable)] = signal; + } + + /// Check if a signal node has been attached to an external variable + template + auto isAttached() -> bool + { + return static_cast(external_variable_signals_[static_cast(variable)]); + } + + /// Check if a signal node has been assigned to an internal variable + template + auto isAssigned() -> bool + { + return static_cast(internal_variable_signals_[static_cast(variable)]); + } + + /// Returns a signal node for an internal signal variable to be + /// attached to an external variable on another component + template + auto getSignalNode() -> SignalNode* + { + if (!internal_variable_signals_[static_cast(variable)]) + { + throw "A signal node has not been assigned to this internal variable"; + } + + return *internal_variable_signals_[static_cast(variable)]; + } + + /// Returns the value of the specified external variable + template + auto readExternalVariable() const -> ScalarT + { + if (!external_variable_signals_[static_cast(variable)]) + { + throw "A signal node has not been assigned to this external variable"; + } + + return (*external_variable_signals_[static_cast(variable)])->read(); + } + + /// Writes a value to the specified external variable + template + auto writeExternalVariable(ScalarT value) + { + if (!external_variable_signals_[static_cast(variable)]) + { + throw "A signal node has not been assigned to this external variable"; + } + + (*external_variable_signals_[static_cast(variable)])->init(value); + } + + /// Assign a signal node to an internal variable + template + auto assignSignalNode(SignalNode* node) + { + internal_variable_signals_[static_cast(variable)] = node; + } + + private: + /// Internal variables which may have a signal associated with them for + /// use elsewhere + std::array*>, + static_cast(InternalVariables::MAXIMUM)> + internal_variable_signals_; + + /// External variables which may have a signal associated with them for + /// use internally + std::array*>, + static_cast(ExternalVariables::MAXIMUM)> + external_variable_signals_; + }; + } // namespace PhasorDynamics +} // namespace GridKit diff --git a/src/Model/PhasorDynamics/Governor/README.md b/src/Model/PhasorDynamics/Governor/README.md index b282c0474..edd9ee218 100644 --- a/src/Model/PhasorDynamics/Governor/README.md +++ b/src/Model/PhasorDynamics/Governor/README.md @@ -1,12 +1,11 @@ -# **Governor Model** - -> [!NOTE] -> No implementation yet. +# Governor Model ## Introduction A governor models the control system that regulates the output power of a machine. ## Types + There are a few standard Governor models + - Turbine Governor (See [TGOV1](GovernorTgov1/README.md)) diff --git a/src/Model/PhasorDynamics/Governor/Tgov1/Tgov1.cpp b/src/Model/PhasorDynamics/Governor/Tgov1/Tgov1.cpp index 69ed796ee..57fa9add0 100644 --- a/src/Model/PhasorDynamics/Governor/Tgov1/Tgov1.cpp +++ b/src/Model/PhasorDynamics/Governor/Tgov1/Tgov1.cpp @@ -4,7 +4,6 @@ * @author Adam Birchfield (abirchfield@tamu.edu) * @author Wiktoria Zielinska (zielinskawa@ORNL.gov) * @brief Definition of a Turbine Governor Model (IEEET1). - * */ #include "Tgov1.hpp" @@ -25,21 +24,35 @@ namespace GridKit namespace Governor { /** + * @brief Constructs a Tgov1 governor model from its parameters * + * @param pmech $P_m$ internal variable signal node + * @param omega $\Delta_\omega$ external variable signal node */ + template + Tgov1::Tgov1(signal_type* pmech, signal_type* omega) + : R_(0.05), + Pvmin_(0), + Pvmax_(1), + T1_(0.5), + T2_(2.5), + T3_(7.5), + Dt_(0) + { + signals_.template assignSignalNode(pmech); + signals_.template attachSignalNode(omega); + + // 3 internal variables + size_ = 3; + } + /** - * @brief Constructs a Tgov1 governor model using signal inputs directly. - * - * Initializes the model parameters and sets the internal model size. + * @brief Constructs a Tgov1 governor model from its parameters * - * @param pmech Pointer to the mechanical power signal. - * @param omega Pointer to the rotor speed signal. - * @param data Model data containing parameter values for initialization. + * @param data Data to initialize the model from. */ template - Tgov1::Tgov1(signal_type* pmech, signal_type* omega, const model_data_type& data) - : pmech_(pmech), - omega_(omega) + Tgov1::Tgov1(const model_data_type& data) { initializeParameters(data); size_ = 3; @@ -48,7 +61,8 @@ namespace GridKit /** * @brief Helper function to extract and assign model parameters. * - * Parses values from the model_data_type and assigns them to internal parameters. + * Parses values from the model_data_type and assigns them to internal + * parameters. * * @param data Structure containing model parameters. */ @@ -59,51 +73,40 @@ namespace GridKit { R_ = std::get(data.parameters.at(model_data_type::Parameters::R)); } + if (data.parameters.contains(model_data_type::Parameters::Pvmin)) { Pvmin_ = std::get(data.parameters.at(model_data_type::Parameters::Pvmin)); } + if (data.parameters.contains(model_data_type::Parameters::Pvmax)) { Pvmax_ = std::get(data.parameters.at(model_data_type::Parameters::Pvmax)); } + if (data.parameters.contains(model_data_type::Parameters::T1)) { T1_ = std::get(data.parameters.at(model_data_type::Parameters::T1)); } + if (data.parameters.contains(model_data_type::Parameters::T2)) { T2_ = std::get(data.parameters.at(model_data_type::Parameters::T2)); } + if (data.parameters.contains(model_data_type::Parameters::T3)) { T3_ = std::get(data.parameters.at(model_data_type::Parameters::T3)); } + if (data.parameters.contains(model_data_type::Parameters::Dt)) { Dt_ = std::get(data.parameters.at(model_data_type::Parameters::Dt)); } } - template - Tgov1::Tgov1(signal_type* pmech, signal_type* omega) - : pmech_(pmech), - omega_(omega), - R_(0.05), - Pvmin_(0), - Pvmax_(1), - T1_(0.5), - T2_(2.5), - T3_(7.5), - Dt_(0) - { - // 3 Internal Variables - size_ = 3; - } - /*! * @brief Allocate memory for model - * */ template int Tgov1::allocate() @@ -117,10 +120,11 @@ namespace GridKit // Set output signal after allocation // The signal is accessible to the generator - if (pmech_) + if (signals_.template isAssigned()) { - pmech_->set(&y_[2]); + signals_.template getSignalNode()->set(&y_[2]); } + return 0; } @@ -134,7 +138,7 @@ namespace GridKit ScalarT p0{0}; // Initial mechanical = initial electric torque - if (pmech_) + if (signals_.template isAssigned()) { p0 = y_[2]; //<- generator needs to be initialized first } @@ -219,11 +223,13 @@ namespace GridKit int Tgov1::evaluateResidual() { // Input Variables + ScalarT omega{0}; - if (omega_) + if (signals_.template isAttached()) { - omega = omega_->read(); + omega = signals_.template readExternalVariable(); } + // Read Internal Variables ScalarT ptx = y_[0]; // y0 - Ptx ScalarT pv = y_[1]; // y1 - Pv diff --git a/src/Model/PhasorDynamics/Governor/Tgov1/Tgov1.hpp b/src/Model/PhasorDynamics/Governor/Tgov1/Tgov1.hpp index c55423798..6b993e6f2 100644 --- a/src/Model/PhasorDynamics/Governor/Tgov1/Tgov1.hpp +++ b/src/Model/PhasorDynamics/Governor/Tgov1/Tgov1.hpp @@ -10,6 +10,7 @@ #pragma once #include +#include // Forward declarations namespace GridKit @@ -37,6 +38,22 @@ namespace GridKit { namespace Governor { + /// Internal variables of a `Tgov1` + enum class Tgov1InternalVariables : size_t + { + PTX, ///< $P_{tx}$ + PV, ///< $P_v$ + PM, ///< $P_m$ + MAXIMUM, + }; + + /// External variables of a `Tgov1` + enum class Tgov1ExternalVariables : size_t + { + DELTAOMEGA, ///< $\Delta_\omega$ + PREF, ///< $P_{ref}$ + MAXIMUM, + }; template class Tgov1 : public Component @@ -55,8 +72,8 @@ namespace GridKit using signal_type = SignalNode; public: - Tgov1(signal_type* pmech, signal_type* omega, const model_data_type& data); - Tgov1(signal_type* pmech, signal_type* omega); + Tgov1(signal_type*, signal_type*); + Tgov1(const model_data_type&); ~Tgov1() = default; int allocate() override; @@ -71,11 +88,17 @@ namespace GridKit { } - private: - // Associated Machine Model - signal_type* pmech_{nullptr}; - signal_type* omega_{nullptr}; + /// Get the `ComponentSignals` from this `GenClassical` + auto getSignals() + -> ComponentSignals& + { + return signals_; + } + private: // Input parameters real_type R_{0}; real_type Pvmin_{0}; @@ -91,6 +114,9 @@ namespace GridKit // Scale of Sigmoid function (temporary local implementation) const ScalarT mu_{4000.0}; + /// Component signal extension + ComponentSignals signals_; + // Activation function (sigmoid approximation) ScalarT sigmoid(ScalarT x); diff --git a/src/Model/PhasorDynamics/Load/Load.hpp b/src/Model/PhasorDynamics/Load/Load.hpp index b45e4278f..0d0403ee9 100644 --- a/src/Model/PhasorDynamics/Load/Load.hpp +++ b/src/Model/PhasorDynamics/Load/Load.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include // Forward declarations. namespace GridKit diff --git a/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.hpp b/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.hpp index 13f846190..8cbab387f 100644 --- a/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.hpp +++ b/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.hpp @@ -9,6 +9,7 @@ #pragma once #include +#include // Forward declarations. namespace GridKit @@ -33,6 +34,38 @@ namespace GridKit { namespace PhasorDynamics { + /// Internal variables of a `Genrou` + enum class GenrouInternalVariables : size_t + { + DELTA, ///< $\delta$ + OMEGA, ///< $\omega$ + PSIPD, ///< $\psi'_d$ + PSIPQ, ///< $\psi'_q$ + EPD, ///< $E'_d$ + EPQ, ///< $E'_q$ + VD, ///< $V_d$ + VQ, ///< $V_q$ + ID, ///< $I_d$ + IQ, ///< $I_q$ + IR, ///< $I_r$ + II, ///< $I_i$ + PSIPPQ, ///< $\psi''_q$ + PSIPPD, ///< $\psi''_d$ + PSIPP, ///< $\psi''$ + TE, ///< $T_e$ + KSAT, ///< $k_{sat}$ + MAXIMUM, + }; + + /// External variables of a `Genrou` + enum class GenrouExternalVariables : size_t + { + VR, ///< $V_r$ + VI, ///< $V_i$ + PM, ///< $P_m$ + EFD, ///< $E_{fd}$ + MAXIMUM, + }; template class Genrou : public Component @@ -103,7 +136,18 @@ namespace GridKit ScalarT getSpeed(); ScalarT getTorque(); + /// Get the `ComponentSignals` from this `Genrou` + auto getSignals() + -> ComponentSignals& + { + return signals_; + } + private: + void initializeParameters(const model_data_type& data); void setDerivedParams(); ScalarT& Vr() @@ -126,14 +170,13 @@ namespace GridKit return bus_->Ii(); } - private: /* Identification */ - bus_type* bus_; - signal_type* pmech_{nullptr}; - signal_type* omega_{nullptr}; - signal_type* efd_signal_{nullptr}; - IdxT bus_id_{0}; - IdxT unit_id_; //< @todo this should be removed + bus_type* bus_; + IdxT bus_id_{0}; + IdxT unit_id_; //< @todo this should be removed + + /// Component signal extension + ComponentSignals signals_; /* Initial terminal conditions */ ScalarT p0_{0.0}; diff --git a/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/GenrouImpl.hpp b/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/GenrouImpl.hpp index 8a8484f86..4c143ccbe 100644 --- a/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/GenrouImpl.hpp +++ b/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/GenrouImpl.hpp @@ -109,100 +109,7 @@ namespace GridKit : bus_(bus), unit_id_(1) { - if (data.parameters.contains(model_data_type::Parameters::p0)) - { - p0_ = std::get(data.parameters.at(model_data_type::Parameters::p0)); - } - - if (data.parameters.contains(model_data_type::Parameters::q0)) - { - q0_ = std::get(data.parameters.at(model_data_type::Parameters::q0)); - } - - if (data.parameters.contains(model_data_type::Parameters::H)) - { - H_ = std::get(data.parameters.at(model_data_type::Parameters::H)); - } - - if (data.parameters.contains(model_data_type::Parameters::D)) - { - D_ = std::get(data.parameters.at(model_data_type::Parameters::D)); - } - - if (data.parameters.contains(model_data_type::Parameters::Ra)) - { - Ra_ = std::get(data.parameters.at(model_data_type::Parameters::Ra)); - } - - if (data.parameters.contains(model_data_type::Parameters::Tdop)) - { - Tdop_ = std::get(data.parameters.at(model_data_type::Parameters::Tdop)); - } - - if (data.parameters.contains(model_data_type::Parameters::Tdopp)) - { - Tdopp_ = std::get(data.parameters.at(model_data_type::Parameters::Tdopp)); - } - - if (data.parameters.contains(model_data_type::Parameters::Tqopp)) - { - Tqopp_ = std::get(data.parameters.at(model_data_type::Parameters::Tqopp)); - } - - if (data.parameters.contains(model_data_type::Parameters::Tqop)) - { - Tqop_ = std::get(data.parameters.at(model_data_type::Parameters::Tqop)); - } - - if (data.parameters.contains(model_data_type::Parameters::Xd)) - { - Xd_ = std::get(data.parameters.at(model_data_type::Parameters::Xd)); - } - - if (data.parameters.contains(model_data_type::Parameters::Xdp)) - { - Xdp_ = std::get(data.parameters.at(model_data_type::Parameters::Xdp)); - } - - if (data.parameters.contains(model_data_type::Parameters::Xdpp)) - { - Xdpp_ = std::get(data.parameters.at(model_data_type::Parameters::Xdpp)); - } - - if (data.parameters.contains(model_data_type::Parameters::Xq)) - { - Xq_ = std::get(data.parameters.at(model_data_type::Parameters::Xq)); - } - - if (data.parameters.contains(model_data_type::Parameters::Xqp)) - { - Xqp_ = std::get(data.parameters.at(model_data_type::Parameters::Xqp)); - } - - if (data.parameters.contains(model_data_type::Parameters::Xqpp)) - { - Xqpp_ = std::get(data.parameters.at(model_data_type::Parameters::Xqpp)); - } - - if (data.parameters.contains(model_data_type::Parameters::Xl)) - { - Xl_ = std::get(data.parameters.at(model_data_type::Parameters::Xl)); - } - - if (data.parameters.contains(model_data_type::Parameters::S10)) - { - S10_ = std::get(data.parameters.at(model_data_type::Parameters::S10)); - } - - if (data.parameters.contains(model_data_type::Parameters::S12)) - { - S12_ = std::get(data.parameters.at(model_data_type::Parameters::S12)); - } - - if (data.ports.contains(model_data_type::Ports::bus)) - { - bus_id_ = data.ports.at(model_data_type::Ports::bus); - } + initializeParameters(data); size_ = 19; setDerivedParams(); @@ -214,105 +121,11 @@ namespace GridKit template Genrou::Genrou(bus_type* bus, signal_type* omega, signal_type* pmech, const model_data_type& data) : bus_(bus), - pmech_(pmech), - omega_(omega), - efd_signal_(nullptr), unit_id_(1) { - if (data.parameters.contains(model_data_type::Parameters::p0)) - { - p0_ = std::get(data.parameters.at(model_data_type::Parameters::p0)); - } - - if (data.parameters.contains(model_data_type::Parameters::q0)) - { - q0_ = std::get(data.parameters.at(model_data_type::Parameters::q0)); - } - - if (data.parameters.contains(model_data_type::Parameters::H)) - { - H_ = std::get(data.parameters.at(model_data_type::Parameters::H)); - } - - if (data.parameters.contains(model_data_type::Parameters::D)) - { - D_ = std::get(data.parameters.at(model_data_type::Parameters::D)); - } - - if (data.parameters.contains(model_data_type::Parameters::Ra)) - { - Ra_ = std::get(data.parameters.at(model_data_type::Parameters::Ra)); - } - - if (data.parameters.contains(model_data_type::Parameters::Tdop)) - { - Tdop_ = std::get(data.parameters.at(model_data_type::Parameters::Tdop)); - } - - if (data.parameters.contains(model_data_type::Parameters::Tdopp)) - { - Tdopp_ = std::get(data.parameters.at(model_data_type::Parameters::Tdopp)); - } - - if (data.parameters.contains(model_data_type::Parameters::Tqopp)) - { - Tqopp_ = std::get(data.parameters.at(model_data_type::Parameters::Tqopp)); - } - - if (data.parameters.contains(model_data_type::Parameters::Tqop)) - { - Tqop_ = std::get(data.parameters.at(model_data_type::Parameters::Tqop)); - } - - if (data.parameters.contains(model_data_type::Parameters::Xd)) - { - Xd_ = std::get(data.parameters.at(model_data_type::Parameters::Xd)); - } - - if (data.parameters.contains(model_data_type::Parameters::Xdp)) - { - Xdp_ = std::get(data.parameters.at(model_data_type::Parameters::Xdp)); - } - - if (data.parameters.contains(model_data_type::Parameters::Xdpp)) - { - Xdpp_ = std::get(data.parameters.at(model_data_type::Parameters::Xdpp)); - } - - if (data.parameters.contains(model_data_type::Parameters::Xq)) - { - Xq_ = std::get(data.parameters.at(model_data_type::Parameters::Xq)); - } - - if (data.parameters.contains(model_data_type::Parameters::Xqp)) - { - Xqp_ = std::get(data.parameters.at(model_data_type::Parameters::Xqp)); - } - - if (data.parameters.contains(model_data_type::Parameters::Xqpp)) - { - Xqpp_ = std::get(data.parameters.at(model_data_type::Parameters::Xqpp)); - } - - if (data.parameters.contains(model_data_type::Parameters::Xl)) - { - Xl_ = std::get(data.parameters.at(model_data_type::Parameters::Xl)); - } - - if (data.parameters.contains(model_data_type::Parameters::S10)) - { - S10_ = std::get(data.parameters.at(model_data_type::Parameters::S10)); - } - - if (data.parameters.contains(model_data_type::Parameters::S12)) - { - S12_ = std::get(data.parameters.at(model_data_type::Parameters::S12)); - } - - if (data.ports.contains(model_data_type::Ports::bus)) - { - bus_id_ = data.ports.at(model_data_type::Ports::bus); - } + signals_.template attachSignalNode(pmech); + signals_.template assignSignalNode(omega); + initializeParameters(data); size_ = 19; setDerivedParams(); @@ -324,10 +137,21 @@ namespace GridKit template Genrou::Genrou(bus_type* bus, signal_type* omega, signal_type* pmech, signal_type* efd, const model_data_type& data) : bus_(bus), - pmech_(pmech), - omega_(omega), - efd_signal_(efd), unit_id_(1) + { + signals_.template attachSignalNode(pmech); + signals_.template assignSignalNode(omega); + signals_.template attachSignalNode(efd); + initializeParameters(data); + + size_ = 19; + setDerivedParams(); + } + + /// Helper function to extract and assign model parameters from the model's associated + /// data structure. + template + void Genrou::initializeParameters(const model_data_type& data) { if (data.parameters.contains(model_data_type::Parameters::p0)) { @@ -423,9 +247,6 @@ namespace GridKit { bus_id_ = data.ports.at(model_data_type::Ports::bus); } - - size_ = 19; - setDerivedParams(); } /*! @@ -439,9 +260,9 @@ namespace GridKit yp_.resize(static_cast(size_)); tag_.resize(static_cast(size_)); - if (omega_) + if (signals_.template isAssigned()) { - omega_->set(&y_[1]); + signals_.template getSignalNode()->set(&y_[1]); } return 0; @@ -510,20 +331,22 @@ namespace GridKit // Set Setpoint mechanical power, which may or may not be used pmech_set_ = Te; - if (pmech_) + if (signals_.template isAttached()) { - pmech_->init(Te); + signals_.template writeExternalVariable(Te); } // Set Efield signal (may or may not exist) efd_set_ = Eqp + Xd1_ * (id + Xd3_ * (Eqp - psidp - Xd2_ * id)) + psidpp * ksat; - if (efd_signal_) + if (signals_.template isAttached()) { - efd_signal_->init(efd_set_); + signals_.template writeExternalVariable(efd_set_); } for (IdxT i = 0; i < size_; ++i) + { yp_[static_cast(i)] = 0.0; + } return 0; } @@ -574,9 +397,9 @@ namespace GridKit // Mechanmical Power ScalarT pmech; - if (pmech_) + if (signals_.template isAttached()) { - pmech = pmech_->read(); + pmech = signals_.template readExternalVariable(); } else { @@ -585,9 +408,9 @@ namespace GridKit // Exciter Efield ScalarT efd; - if (efd_signal_) + if (signals_.template isAttached()) { - efd = efd_signal_->read(); + efd = signals_.template readExternalVariable(); } else { diff --git a/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.hpp b/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.hpp index e06ae2758..37873c21a 100644 --- a/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.hpp +++ b/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.hpp @@ -8,6 +8,7 @@ #pragma once #include +#include // Forward declarations. namespace GridKit diff --git a/src/Model/PhasorDynamics/SynchronousMachine/README.md b/src/Model/PhasorDynamics/SynchronousMachine/README.md index f3c62abd9..d1d33bca9 100644 --- a/src/Model/PhasorDynamics/SynchronousMachine/README.md +++ b/src/Model/PhasorDynamics/SynchronousMachine/README.md @@ -1,16 +1,14 @@ -# **General Synchronous Machine Model** +# General Synchronous Machine Model -> [!NOTE] -> Only the GENROU model has been implemented. +> [!NOTE] +> Only the GENROU and classical generator models have been implemented. ## Convention -
- - - Figure 1: Synchronous Machine. - Figure courtesy of + + Figure 1: Synchronous Machine. + Figure courtesy of [PowerWorld](https://www.powerworld.com/files/Synchronous-Machines.pdf)
@@ -19,7 +17,7 @@ The following conventions are used for the d-q reference frame. - The Rotor angle is w.r.t. to q-axis ## Types -There are two main variations + - Round Rotor (See [GENROU](GENROUwS/README.md)) - Salient Rotor/Pole (See [GENSAL](GENSALwS/README.md)) - GENPWS @@ -29,19 +27,22 @@ There are two main variations - GenClassical ### Per-Unit Basis + In relevant models, the terminal impedences are on the generator impedance base. - To convert to network base, the following must be performed. -``` math +To convert to network base, the following must be performed. + +```math \begin{aligned} Z_{term} & \mapsto Z_{term}\dfrac{S_{base,sys}}{S_{base,machine}} \end{aligned} ``` -For example, say the terminal impedence is $Z=0.05$ in per-unit on the -machine's base of $S_{base,machine}=50$ MW, and the system base is -$S_{base,sys}=100$ MW. Then the terminal impedence on the the system +For example, say the terminal impedence is $Z=0.05$ in per-unit on the +machine's base of $S_{base,machine}=50$ MW, and the system base is +$S_{base,sys}=100$ MW. Then the terminal impedence on the the system base is calculated as follows. + ``` math \begin{aligned} Z_{sys} = 0.05\dfrac{100 \text{MW}}{50 \text{MW}} = 0.1 @@ -49,11 +50,12 @@ base is calculated as follows. ``` #### Saturation -Saturation means increasingly large amounts of current are needed to increase + +Saturation means increasingly large amounts of current are needed to increase the flux density. The Scaled Quadratic saturation model is currently implemented. ``` math \begin{aligned} - k_{sat} = + k_{sat} = \begin{cases} S_B(\psi''-S_A)^2 &\text{if } \psi''>S_A \\ 0 &\text{if } \psi''\leq S_A