DPsim
Loading...
Searching...
No Matches
DP_Ph1_SynchronGeneratorTrStab.cpp
Go to the documentation of this file.
1/* Copyright 2017-2021 Institute for Automation of Complex Power Systems,
2 * EONERC, RWTH Aachen University
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
7 *********************************************************************************/
8
10using namespace CPS;
11
15 CompositePowerComp<Complex>(uid, name, true, true, logLevel),
16 mEp(mAttributes->create<Complex>("Ep")),
17 mEp_abs(mAttributes->create<Real>("Ep_mag")),
18 mEp_phase(mAttributes->create<Real>("Ep_phase")),
19 mDelta_p(mAttributes->create<Real>("delta_r")),
20 mRefOmega(mAttributes->createDynamic<Real>("w_ref")),
21 mRefDelta(mAttributes->createDynamic<Real>("delta_ref")) {
24 **mIntfVoltage = MatrixComp::Zero(1, 1);
25 **mIntfCurrent = MatrixComp::Zero(1, 1);
26
27 mStates = Matrix::Zero(10, 1);
28}
29
33 copy->setStandardParametersPU(mNomPower, mNomVolt, mNomFreq, mXpd / mBase_Z,
34 **mInertia, **mRs, mKd);
35 return copy;
36}
37
39 Real nomPower, Real nomVolt, Real nomFreq, Real Ll, Real Lmd, Real Llfd,
40 Real inertia, Real D) {
41 setBaseParameters(nomPower, nomVolt, nomFreq);
42 SPDLOG_LOGGER_INFO(mSLog,
43 "\n--- Base Parameters ---"
44 "\nnomPower: {:f}"
45 "\nnomVolt: {:f}"
46 "\nnomFreq: {:f}",
48
49 // Input is in per unit but all values are converted to absolute values.
52
53 **mLl = Ll;
54 mLmd = Lmd;
55 **mLd = **mLl + mLmd;
56 mLlfd = Llfd;
57 mLfd = mLlfd + mLmd;
58 // M = 2*H where H = inertia
59 **mInertia = inertia;
60 // X'd in absolute values
61 mXpd = mNomOmega * (**mLd - mLmd * mLmd / mLfd) * mBase_L;
62 mLpd = (**mLd - mLmd * mLmd / mLfd) * mBase_L;
63
64 //The units of D are per unit power divided by per unit speed deviation.
65 // D is transformed to an absolute value to obtain Kd, which will be used in the swing equation
66 mKd = D * mNomPower / mNomOmega;
67
68 SPDLOG_LOGGER_INFO(mSLog,
69 "\n--- Parameters ---"
70 "\nimpedance: {:f}"
71 "\ninductance: {:f}"
72 "\ninertia: {:f}"
73 "\ndamping: {:f}",
74 mXpd, mLpd, **mInertia, mKd);
75}
76
78 Real nomPower, Real nomVolt, Real nomFreq, Int polePairNumber, Real Rs,
79 Real Lpd, Real inertiaJ, Real Kd) {
80 setBaseParameters(nomPower, nomVolt, nomFreq);
81 SPDLOG_LOGGER_INFO(mSLog,
82 "\n--- Base Parameters ---"
83 "\nnomPower: {:f}"
84 "\nnomVolt: {:f}"
85 "\nnomFreq: {:f}",
87
90
91 // M = 2*H where H = inertia
92 // H = J * 0.5 * omegaNom^2 / polePairNumber
93 **mInertia = calcHfromJ(inertiaJ, 2 * PI * nomFreq, polePairNumber);
94 // X'd in absolute values
95 mXpd = mNomOmega * Lpd;
96 mLpd = Lpd;
97
98 SPDLOG_LOGGER_INFO(mSLog,
99 "\n--- Parameters ---"
100 "\nimpedance: {:f}"
101 "\ninductance: {:f}"
102 "\ninertia: {:f}"
103 "\ndamping: {:f}",
104 mXpd, mLpd, **mInertia, mKd);
105}
106
108 Real nomPower, Real nomVolt, Real nomFreq, Real Xpd, Real inertia, Real Rs,
109 Real D) {
110 setBaseParameters(nomPower, nomVolt, nomFreq);
111 SPDLOG_LOGGER_INFO(mSLog,
112 "\n--- Base Parameters ---"
113 "\nnomPower: {:f}"
114 "\nnomVolt: {:f}"
115 "\nnomFreq: {:f}",
117
118 // Input is in per unit but all values are converted to absolute values.
121
122 // M = 2*H where H = inertia
123 **mInertia = inertia;
124 // X'd in absolute values
125 mXpd = Xpd * mBase_Z;
126 mLpd = Xpd * mBase_L;
127
128 **mRs = Rs;
129 //The units of D are per unit power divided by per unit speed deviation.
130 // D is transformed to an absolute value to obtain Kd, which will be used in the swing equation
131 mKd = D * mNomPower / mNomOmega;
132
133 SPDLOG_LOGGER_INFO(mSLog,
134 "\n--- Parameters ---"
135 "\nimpedance: {:f}"
136 "\ninductance: {:f}"
137 "\ninertia: {:f}"
138 "\ndamping: {:f}",
139 mXpd, mLpd, **mInertia, mKd);
140}
141
143 Bool convertWithOmegaMech) {
144 mConvertWithOmegaMech = convertWithOmegaMech;
145
146 SPDLOG_LOGGER_INFO(mSLog,
147 "\n--- Model flags ---"
148 "\nconvertWithOmegaMech: {:s}",
149 std::to_string(mConvertWithOmegaMech));
150}
151
153 Real mechPower) {
154 mInitElecPower = elecPower;
155 mInitMechPower = mechPower;
156}
157
159 if (mSubCompCreated)
160 return;
161 mSubCompCreated = true;
162
163 // Create the inner voltage source (Ep). Parameters (mEp) depend on the
164 // power-flow solution and are not yet known here; they are applied in
165 // initializeFromNodesAndTerminals after the static calculation.
168 // Alias the sub-source's virtual node to parent VN1 so the KCL row in the
169 // system matrix uses the same node index as the parent's VN1.
170 mSubVoltageSource->setVirtualNodeAt(mVirtualNodes[1], 0);
174
175 // Create the inner inductor representing X'd.
177 mSubInductor->setParameters(mLpd);
178 mSubInductor->connect({mVirtualNodes[0], terminal(0)->node()});
181}
182
184 Real frequency) {
185 // Initialize omega mech with nominal system frequency
186 **mOmMech = mNomOmega;
187
188 // Static calculation based on load flow
189 (**mIntfVoltage)(0, 0) = initialSingleVoltage(0);
191 ? -terminal(0)->singlePower()
195
196 //I_intf is the current which is flowing into the Component, while mInitElecPower is flowing out of it
197 (**mIntfCurrent)(0, 0) = std::conj(-mInitElecPower / (**mIntfVoltage)(0, 0));
198
200
201 // Calculate initial emf behind reactance from power flow results
202 **mEp = (**mIntfVoltage)(0, 0) - mImpedance * (**mIntfCurrent)(0, 0);
203
204 // The absolute value of Ep is constant, only delta_p changes every step
205 **mEp_abs = Math::abs(**mEp);
206 // Delta_p is the angular position of mEp with respect to the synchronously rotating reference
207 **mDelta_p = Math::phase(**mEp);
208
209 // Update active electrical power that is compared with the mechanical power
211 ((**mIntfVoltage)(0, 0) * std::conj(-(**mIntfCurrent)(0, 0))).real();
212
213 // Start in steady state so that electrical and mech. power are the same
214 // because of the initial condition mOmMech = mNomOmega the damping factor is not considered at the initialisation
216
217 // Initialize node between X'd and Ep
218 mVirtualNodes[0]->setInitialVoltage(**mEp);
219
220 // Set emf on the already-created voltage source; the framework's generic
221 // sub-init loop will initialize it after this hook returns.
222 mSubVoltageSource->setParameters(**mEp);
223
224 SPDLOG_LOGGER_INFO(mSLog,
225 "\n--- Initialize according to powerflow ---"
226 "\nTerminal 0 voltage: {:e}<{:e}"
227 "\nVoltage behind reactance: {:e}<{:e}"
228 "\ninitial electrical power: {:e}+j{:e}"
229 "\nactive electrical power: {:e}"
230 "\nmechanical power: {:e}"
231 "\n--- End of powerflow initialization ---",
232 Math::abs((**mIntfVoltage)(0, 0)),
236}
237
239
240 // #### Calculations based on values from time step k ####
241 // Electrical power at time step k
243 ((**mIntfVoltage)(0, 0) * std::conj(-(**mIntfCurrent)(0, 0))).real();
244
245 // Mechanical speed derivative at time step k
246 // convert torque to power with actual rotor angular velocity or nominal omega
247 Real dOmMech;
249 dOmMech =
250 mNomOmega * mNomOmega / (2. * **mInertia * mNomPower * **mOmMech) *
252 else
253 dOmMech =
254 mNomOmega / (2. * **mInertia * mNomPower) *
256
257 // #### Calculate states for time step k+1 applying semi-implicit Euler ####
258 // Mechanical speed at time step k+1 applying Euler forward
260 **mOmMech = **mOmMech + mTimeStep * dOmMech;
261
262 // Derivative of rotor angle at time step k + 1
263 // if reference omega is set, calculate delta with respect to reference
264 Real dDelta_p = **mOmMech - (mUseOmegaRef ? **mRefOmega : mNomOmega);
265
266 // Rotor angle at time step k + 1 applying Euler backward
267 // Update emf - only phase changes
269 **mDelta_p = **mDelta_p + mTimeStep * dDelta_p;
270 **mEp = Complex(**mEp_abs * cos(**mDelta_p), **mEp_abs * sin(**mDelta_p));
271 }
272
274 **mMechPower, **mDelta_p, **mOmMech, dOmMech, dDelta_p,
275 (**mIntfVoltage)(0, 0).real(), (**mIntfVoltage)(0, 0).imag();
276 SPDLOG_LOGGER_DEBUG(mSLog, "\nStates, time {:f}: \n{:s}", time,
278}
279
281 Real omega, Real timeStep, Attribute<Matrix>::Ptr leftVector) {
282 mTimeStep = timeStep;
283 mMnaTasks.push_back(std::make_shared<AddBStep>(*this));
284}
285
287 AttributeBase::List &prevStepDependencies,
288 AttributeBase::List &attributeDependencies,
289 AttributeBase::List &modifiedAttributes) {
290 // other attributes generally also influence the pre step,
291 // but aren't marked as writable anyway
293 prevStepDependencies.push_back(mIntfVoltage);
294}
295
297 AttributeBase::List &prevStepDependencies,
298 AttributeBase::List &attributeDependencies,
299 AttributeBase::List &modifiedAttributes,
300 Attribute<Matrix>::Ptr &leftVector) {
301 attributeDependencies.push_back(leftVector);
302 modifiedAttributes.push_back(mIntfVoltage);
303}
304
306 Int timeStepCount) {
307 step(time);
308 //change V_ref of subvoltage source
309 mSubVoltageSource->mVoltageRef->set(**mEp);
310}
311
313 Int timeStepCount) {
314 **mGenerator.mRightVector = mGenerator.mSubInductor->mRightVector->get() +
315 mGenerator.mSubVoltageSource->mRightVector->get();
316}
317
319 Real time, Int timeStepCount, Attribute<Matrix>::Ptr &leftVector) {
320 mnaCompUpdateVoltage(**leftVector);
321 mnaCompUpdateCurrent(**leftVector);
322}
323
325 const Matrix &leftVector) {
326 SPDLOG_LOGGER_DEBUG(mSLog, "Read voltage from {:d}", matrixNodeIndex(0));
327 (**mIntfVoltage)(0, 0) =
329}
330
332 const Matrix &leftVector) {
333 SPDLOG_LOGGER_DEBUG(mSLog, "Read current from {:d}", matrixNodeIndex(0));
334 //Current flowing out of component
335 **mIntfCurrent = mSubInductor->mIntfCurrent->get();
336}
337
339 Attribute<Real>::Ptr refOmegaPtr, Attribute<Real>::Ptr refDeltaPtr) {
340 mRefOmega->setReference(refOmegaPtr);
341 mRefDelta->setReference(refDeltaPtr);
342 mUseOmegaRef = true;
343
344 SPDLOG_LOGGER_INFO(mSLog, "Use of reference omega.");
345}
std::vector< Ptr > List
Definition Attribute.h:123
AttributePointer< Attribute< T > > Ptr
Definition Attribute.h:250
Real mNomFreq
nominal frequency fn [Hz]
Real mTimeStep
Simulation time step.
Real mLmd
d-axis mutual inductance Lmd [H]
SynchronGenerator(CPS::AttributeList::Ptr attributeList)
Constructor.
Real mLlfd
field leakage inductance Llfd [H]
const Attribute< Real >::Ptr mMechPower
mechanical Power Pm [W]
Real mNomVolt
nominal voltage Vn [V] (phase-to-phase RMS)
Real mBase_L
base stator inductance
Real mBase_Z
base stator impedance
const Attribute< Real >::Ptr mRs
stator resistance Rs [Ohm]
const Attribute< Real >::Ptr mElecActivePower
Active part of the electrical power.
StateType mStateType
specifies if the machine parameters are transformed to per unit
Real mNomOmega
nominal angular frequency wn [Hz]
const Attribute< Real >::Ptr mLl
leakage inductance Ll [H]
void setBaseParameters(Real nomPower, Real nomVolt, Real nomFreq)
Real mLfd
field inductance Lfd [H]
const Attribute< Real >::Ptr mLd
d-axis inductance Ld [H]
Real mNomPower
nominal power Pn [VA]
const Attribute< Real >::Ptr mOmMech
rotor speed omega_r
Real calcHfromJ(Real J, Real omegaNominal, Int polePairNumber)
const Attribute< Real >::Ptr mInertia
inertia constant H [s] for per unit or moment of inertia J [kg*m^2]
void addMNASubComponent(typename SimPowerComp< Complex >::Ptr subc, MNA_SUBCOMP_TASK_ORDER preStepOrder, MNA_SUBCOMP_TASK_ORDER postStepOrder, Bool contributeToRightVector)
CompositePowerComp(String uid, String name, Bool hasPreStep, Bool hasPostStep, Logger::Level logLevel)
void mnaParentPostStep(Real time, Int timeStepCount, Attribute< Matrix >::Ptr &leftVector) override
Retrieves calculated voltage from simulation for next step.
void mnaCompUpdateCurrent(const Matrix &leftVector) override
std::shared_ptr< Inductor > mSubInductor
Inner inductor that represents the generator impedance.
void setStandardParametersSI(Real nomPower, Real nomVolt, Real nomFreq, Int polePairNumber, Real Rs, Real Lpd, Real inertiaJ, Real Kd=0)
Initializes the machine parameters.
Complex mImpedance
Equivalent impedance for loadflow calculation.
void mnaParentAddPostStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, Attribute< Matrix >::Ptr &leftVector) override
const Attribute< Complex >::Ptr mEp
True after createSubComponents() runs; prevents double-construction.
void mnaParentAddPreStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes) override
SimPowerComp< Complex >::Ptr clone(String name) override
Returns a modified copy of the component with the given suffix added to the name and without.
void setStandardParametersPU(Real nomPower, Real nomVolt, Real nomFreq, Real Xpd, Real inertia, Real Rs=0, Real D=0)
Initializes the machine parameters.
const Attribute< Real >::Ptr mDelta_p
Angle by which the emf Ep is leading the terminal voltage.
void mnaParentInitialize(Real omega, Real timeStep, Attribute< Matrix >::Ptr leftVector) override
Initializes variables of component.
void setInitialValues(Complex elecPower, Real mechPower)
void setModelFlags(Bool convertWithOmegaMech)
Flags to modify model behavior.
Real mXpd
Absolute d-axis transient reactance X'd.
Bool mConvertWithOmegaMech
Flag for usage of actual mechanical speed for torque conversion (otherwise mNomOmega is used)
Bool mUseOmegaRef
Flag for usage of attribute of w_ref (otherwise mNomOmega is used)
void setFundamentalParametersPU(Real nomPower, Real nomVolt, Real nomFreq, Real Ll, Real Lmd, Real Llfd, Real inertia, Real D=0)
Initializes the machine parameters.
void createSubComponents() override
Constructs and registers MNA subcomponents without emf value; idempotent.
SynchronGeneratorTrStab(String uid, String name, Logger::Level logLevel=Logger::Level::off)
void setReferenceOmega(Attribute< Real >::Ptr refOmegaPtr, Attribute< Real >::Ptr refDeltaPtr)
void initializeParentFromNodesAndTerminals(Real frequency) override
std::shared_ptr< VoltageSource > mSubVoltageSource
Inner voltage source that represents the generator.
void mnaParentPreStep(Real time, Int timeStepCount) override
void mnaCompUpdateVoltage(const Matrix &leftVector) override
Real mLpd
Absolute d-axis transient inductance.
const Attribute< String >::Ptr mName
Human readable name.
String uid()
Returns unique id.
AttributeList::Ptr mAttributes
Attribute List.
spdlog::level::level_enum Level
Definition Logger.h:33
static String matrixToString(const Matrix &mat)
Definition Logger.cpp:31
static Complex complexFromVectorElement(const Matrix &mat, Matrix::Index row, Int maxFreq=1, Int freqIdx=0)
Definition MathUtils.cpp:94
static Real phaseDeg(Complex value)
Definition MathUtils.cpp:25
static Real phase(Complex value)
Definition MathUtils.cpp:23
static Real abs(Complex value)
Definition MathUtils.cpp:27
UInt matrixNodeIndex(UInt nodeIndex)
const Attribute< MatrixVar< Complex > >::Ptr mIntfCurrent
SimTerminal< Complex >::Ptr terminal(UInt index)
const Attribute< MatrixVar< Complex > >::Ptr mIntfVoltage
std::shared_ptr< SimPowerComp< VarType > > Ptr
SimNode< Complex >::List mVirtualNodes
Complex initialSingleVoltage(UInt index)
Logger::Level mLogLevel
Component logger control for internal variables.
Logger::Log mSLog
Component logger.
static std::shared_ptr< SynchronGeneratorTrStab > make(Args &&...args)
Definition PtrFactory.h:19
#define PI
Definition Definitions.h:43
Eigen::Matrix< Real, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor > Matrix
Dense matrix for real numbers.
Definition Definitions.h:81
std::string String
Definition Definitions.h:65
double Real
Definition Definitions.h:62
int Int
Definition Definitions.h:61
std::complex< Real > Complex
Definition Definitions.h:63
bool Bool
Definition Definitions.h:64