133 Real nomFreq, Real H, Real Ld,
134 Real Lq, Real L0, Real Ld_t,
135 Real Lq_t, Real Td0_t,
149 SPDLOG_LOGGER_INFO(this->
mSLog,
150 "Set base parameters: \n"
151 "nomPower: {:e}\nnomVolt: {:e}\nnomFreq: {:e}\n",
154 SPDLOG_LOGGER_INFO(this->
mSLog,
155 "Set operational parameters in per unit: \n"
157 "Ld: {:e}\nLq: {:e}\nL0: {:e}\n"
158 "Ld_t: {:e}\nLq_t: {:e}\n"
159 "Td0_t: {:e}\nTq0_t: {:e}\n",
163template <
typename VarType>
166 Real nomFreq, Real H, Real Ld,
167 Real Lq, Real L0, Real Ld_t,
168 Real Lq_t, Real Td0_t, Real Tq0_t,
169 Real Ld_s, Real Lq_s, Real Td0_s,
170 Real Tq0_s, Real Taa) {
188 SPDLOG_LOGGER_INFO(this->
mSLog,
189 "Set base parameters: \n"
190 "nomPower: {:e}\nnomVolt: {:e}\nnomFreq: {:e}\n",
193 SPDLOG_LOGGER_INFO(this->
mSLog,
194 "Set operational parameters in per unit: \n"
196 "Ld: {:e}\nLq: {:e}\nL0: {:e}\n"
197 "Ld_t: {:e}\nLq_t: {:e}\n"
198 "Td0_t: {:e}\nTq0_t: {:e}\n"
199 "Ld_s: {:e}\nLq_s: {:e}\n"
200 "Td0_s: {:e}\nTq0_s: {:e}\n"
206template <
typename VarType>
208 Real scalingFactor) {
209 mH =
mH * scalingFactor;
212 "Scaling inertia with factor {:e}:\n resulting inertia: {:e}\n",
216template <
typename VarType>
217void Base::ReducedOrderSynchronGenerator<VarType>::calculateVBRconstants() {
220 if (mSGOrder == SGOrder::SG5Order) {
221 mYd = (mTd0_s / mTd0_t) * (mLd_s / mLd_t) * (mLd - mLd_t);
224 }
else if (mSGOrder == SGOrder::SG6aOrder) {
225 mYd = (mTd0_s / mTd0_t) * (mLd_s / mLd_t) * (mLd - mLd_t);
226 mYq = (mTq0_s / mTq0_t) * (mLq_s / mLq_t) * (mLq - mLq_t);
233 Real Zq_t = mLd - mLd_t - mYd;
234 Real Zd_t = mLq - mLq_t - mYq;
235 Real Zq_s = mLd_t - mLd_s + mYd;
236 Real Zd_s = mLq_t - mLq_s + mYq;
238 mAd_t = mTimeStep * Zd_t / (2 * mTq0_t + mTimeStep);
239 mBd_t = (2 * mTq0_t - mTimeStep) / (2 * mTq0_t + mTimeStep);
240 mAq_t = -mTimeStep * Zq_t / (2 * mTd0_t + mTimeStep);
241 mBq_t = (2 * mTd0_t - mTimeStep) / (2 * mTd0_t + mTimeStep);
242 mDq_t = mTimeStep * (1 - Tf) / (2 * mTd0_t + mTimeStep);
244 if (mSGOrder == SGOrder::SG5Order) {
245 mAd_s = (mTimeStep * (mLq - mLq_s)) / (2 * mTq0_s + mTimeStep);
246 mCd_s = (2 * mTq0_s - mTimeStep) / (2 * mTq0_s + mTimeStep);
247 mAq_s = (-mTimeStep * Zq_s + mTimeStep * mAq_t) / (2 * mTd0_s + mTimeStep);
248 mBq_s = (mTimeStep * mBq_t + mTimeStep) / (2 * mTd0_s + mTimeStep);
249 mCq_s = (2 * mTd0_s - mTimeStep) / (2 * mTd0_s + mTimeStep);
250 mDq_s = (mTimeStep * mDq_t + Tf * mTimeStep) / (2 * mTd0_s + mTimeStep);
251 }
else if (mSGOrder == SGOrder::SG6aOrder || mSGOrder == SGOrder::SG6bOrder) {
252 mAd_s = (mTimeStep * Zd_s + mTimeStep * mAd_t) / (2 * mTq0_s + mTimeStep);
253 mBd_s = (mTimeStep * mBd_t + mTimeStep) / (2 * mTq0_s + mTimeStep);
254 mCd_s = (2 * mTq0_s - mTimeStep) / (2 * mTq0_s + mTimeStep);
255 mAq_s = (-mTimeStep * Zq_s + mTimeStep * mAq_t) / (2 * mTd0_s + mTimeStep);
256 mBq_s = (mTimeStep * mBq_t + mTimeStep) / (2 * mTd0_s + mTimeStep);
257 mCq_s = (2 * mTd0_s - mTimeStep) / (2 * mTd0_s + mTimeStep);
258 mDq_s = (mTimeStep * mDq_t + Tf * mTimeStep) / (2 * mTd0_s + mTimeStep);
262template <
typename VarType>
264 VarType>::calculateResistanceMatrixConstants() {
265 if (mSGOrder == SGOrder::SG3Order) {
269 if (mSGOrder == SGOrder::SG4Order) {
273 if (mSGOrder == SGOrder::SG5Order || mSGOrder == SGOrder::SG6aOrder ||
274 mSGOrder == SGOrder::SG6bOrder) {
280template <
typename VarType>
281void Base::ReducedOrderSynchronGenerator<VarType>::setInitialValues(
282 Complex initComplexElectricalPower, Real initMechanicalPower,
283 Complex initTerminalVoltage) {
285 mInitElecPower = initComplexElectricalPower;
286 mInitMechPower = initMechanicalPower;
288 mInitVoltage = initTerminalVoltage;
289 mInitVoltageAngle = Math::phase(mInitVoltage);
291 mInitCurrent = std::conj(mInitElecPower / mInitVoltage);
292 mInitCurrentAngle = Math::phase(mInitCurrent);
294 mInitVoltage = mInitVoltage / mBase_V_RMS;
295 mInitCurrent = mInitCurrent / mBase_I_RMS;
297 mInitialValuesSet =
true;
299 SPDLOG_LOGGER_DEBUG(this->mSLog,
300 "\n--- Set initial values ---"
301 "\nInitial active power: {:}W = {:} p.u."
302 "\nInitial reactive power W: {:}W = {:} p.u."
303 "\nInitial terminal voltage magnitude: {:} p.u."
304 "\nInitial terminal voltage phase: {:} rad = ({:}°)"
305 "\nInitial current magnitude: {:} p.u."
306 "\nInitial current phase: {:} rad = ({:}°)"
307 "\n--- Set initial values finished ---\n",
309 mInitElecPower.real(), mInitElecPower.real() / mNomPower,
310 mInitElecPower.imag(), mInitElecPower.imag() / mNomPower,
311 Math::abs(mInitVoltage), Math::phase(mInitVoltage),
312 Math::phaseDeg(mInitVoltage), Math::abs(mInitCurrent),
313 Math::phase(mInitCurrent), Math::phaseDeg(mInitCurrent));
314 this->mSLog->flush();
321 this->updateMatrixNodeIndices();
323 if (!mInitialValuesSet)
324 this->setInitialValues(-this->terminal(0)->singlePower(),
325 -this->terminal(0)->singlePower().real(),
326 this->initialSingleVoltage(0));
329 **mMechTorque = mInitMechPower / mNomPower;
330 mMechTorque_prev = **mMechTorque;
333 Complex Eq0 = mInitVoltage + Complex(0, mLq) * mInitCurrent;
336 **mDelta = Math::phase(Eq0);
339 (**mIdq0)(0, 0) = Math::abs(mInitCurrent) * sin(**mDelta - mInitCurrentAngle);
340 (**mIdq0)(1, 0) = Math::abs(mInitCurrent) * cos(**mDelta - mInitCurrentAngle);
343 (**mVdq0)(0, 0) = Math::abs(mInitVoltage) * sin(**mDelta - mInitVoltageAngle);
344 (**mVdq0)(1, 0) = Math::abs(mInitVoltage) * cos(**mDelta - mInitVoltageAngle);
347 **mEf = Math::abs(Eq0) + (mLd - mLq) * (**mIdq0)(0, 0);
352 mExciter->initialize(Math::abs(mInitVoltage), **mEf);
354 if (mHasTurbineGovernor) {
355 mTurbineGovernor->initialize(**mMechTorque);
360 (**mVdq0)(0, 0) * (**mIdq0)(0, 0) + (**mVdq0)(1, 0) * (**mIdq0)(1, 0);
363 **mOmMech = mNomOmega / mBase_OmMech;
366 **mThetaMech = **mDelta - PI / 2.;
369 (**mIntfCurrent)(0, 0) = (mInitCurrent * mBase_I).real();
370 (**mIntfCurrent)(1, 0) = (mInitCurrent * mBase_I * SHIFT_TO_PHASE_B).real();
371 (**mIntfCurrent)(2, 0) = (mInitCurrent * mBase_I * SHIFT_TO_PHASE_C).real();
374 (**mIntfVoltage)(0, 0) = (mInitVoltage * mBase_V).real();
375 (**mIntfVoltage)(1, 0) = (mInitVoltage * mBase_V * SHIFT_TO_PHASE_B).real();
376 (**mIntfVoltage)(2, 0) = (mInitVoltage * mBase_V * SHIFT_TO_PHASE_C).real();
378 SPDLOG_LOGGER_DEBUG(this->mSLog,
379 "\n--- Initialization from power flow ---"
380 "\nInitial Vd (per unit): {:f}"
381 "\nInitial Vq (per unit): {:f}"
382 "\nInitial Id (per unit): {:f}"
383 "\nInitial Iq (per unit): {:f}"
384 "\nInitial Ef (per unit): {:f}"
385 "\nInitial mechanical torque (per unit): {:f}"
386 "\nInitial electrical torque (per unit): {:f}"
387 "\nInitial initial mechanical theta (per unit): {:f}"
388 "\nInitial delta (per unit): {:f} (= {:f}°)"
389 "\n--- Initialization from power flow finished ---",
391 (**mVdq0)(0, 0), (**mVdq0)(1, 0), (**mIdq0)(0, 0),
392 (**mIdq0)(1, 0), **mEf, **mMechTorque, **mElecTorque,
393 **mThetaMech, **mDelta, **mDelta * 180 / PI);
394 this->mSLog->flush();
399 Complex>::initializeFromNodesAndTerminals(Real frequency) {
401 this->updateMatrixNodeIndices();
403 if (!mInitialValuesSet)
404 this->setInitialValues(-this->terminal(0)->singlePower(),
405 -this->terminal(0)->singlePower().real(),
406 this->initialSingleVoltage(0));
409 **mMechTorque = mInitMechPower / mNomPower;
410 mMechTorque_prev = **mMechTorque;
413 Complex Eq0 = mInitVoltage + Complex(0, mLq) * mInitCurrent;
416 **mDelta = Math::phase(Eq0);
419 (**mIdq)(0, 0) = Math::abs(mInitCurrent) * sin(**mDelta - mInitCurrentAngle);
420 (**mIdq)(1, 0) = Math::abs(mInitCurrent) * cos(**mDelta - mInitCurrentAngle);
423 (**mVdq)(0, 0) = Math::abs(mInitVoltage) * sin(**mDelta - mInitVoltageAngle);
424 (**mVdq)(1, 0) = Math::abs(mInitVoltage) * cos(**mDelta - mInitVoltageAngle);
427 **mEf = Math::abs(Eq0) + (mLd - mLq) * (**mIdq)(0, 0);
432 mExciter->initialize(Math::abs(mInitVoltage), **mEf);
434 if (mHasTurbineGovernor) {
435 mTurbineGovernor->initialize(**mMechTorque);
440 (**mVdq)(0, 0) * (**mIdq)(0, 0) + (**mVdq)(1, 0) * (**mIdq)(1, 0);
443 **mOmMech = mNomOmega / mBase_OmMech;
446 **mThetaMech = **mDelta - PI / 2.;
449 (**mIntfCurrent)(0, 0) = mInitCurrent * mBase_I_RMS;
452 (**mIntfVoltage)(0, 0) = mInitVoltage * mBase_V_RMS;
454 SPDLOG_LOGGER_DEBUG(this->mSLog,
455 "\n--- Initialization from power flow ---"
456 "\nInitial Vd (per unit): {:f}"
457 "\nInitial Vq (per unit): {:f}"
458 "\nInitial Id (per unit): {:f}"
459 "\nInitial Iq (per unit): {:f}"
460 "\nInitial Ef (per unit): {:f}"
461 "\nInitial mechanical torque (per unit): {:f}"
462 "\nInitial electrical torque (per unit): {:f}"
463 "\nInitial initial mechanical theta (per unit): {:f}"
464 "\nInitial delta (per unit): {:f} (= {:f}°)"
465 "\n--- Initialization from power flow finished ---",
467 (**mVdq)(0, 0), (**mVdq)(1, 0), (**mIdq)(0, 0),
468 (**mIdq)(1, 0), **mEf, **mMechTorque, **mElecTorque,
469 **mThetaMech, **mDelta, **mDelta * 180 / PI);
470 this->mSLog->flush();
473template <
typename VarType>
474void Base::ReducedOrderSynchronGenerator<VarType>::mnaCompInitialize(
475 Real omega, Real timeStep, Attribute<Matrix>::Ptr leftVector) {
477 this->updateMatrixNodeIndices();
478 mTimeStep = timeStep;
479 calculateVBRconstants();
480 calculateResistanceMatrixConstants();
481 initializeResistanceMatrix();
482 specificInitialization();
486void Base::ReducedOrderSynchronGenerator<Complex>::mnaCompPreStep(
487 Real time, Int timeStepCount) {
493 **mEf = mExciter->step((**mVdq)(0, 0), (**mVdq)(1, 0), mTimeStep);
495 if (mHasTurbineGovernor) {
496 mMechTorque_prev = **mMechTorque;
497 **mMechTorque = mTurbineGovernor->step(**mOmMech, mTimeStep);
502 (**mVdq)(0, 0) * (**mIdq)(0, 0) + (**mVdq)(1, 0) * (**mIdq)(1, 0);
503 **mOmMech = **mOmMech +
504 mTimeStep * (1. / (2. * mH) * (mMechTorque_prev - **mElecTorque));
505 **mThetaMech = **mThetaMech + mTimeStep * (**mOmMech * mBase_OmMech);
506 **mDelta = **mDelta + mTimeStep * (**mOmMech - 1.) * mBase_OmMech;
512 (**mRightVector).setZero();
513 mnaCompApplyRightSideVectorStamp(**mRightVector);
517void Base::ReducedOrderSynchronGenerator<Real>::mnaCompPreStep(
518 Real time, Int timeStepCount) {
524 **mEf = mExciter->step((**mVdq0)(0, 0), (**mVdq0)(1, 0), mTimeStep);
526 if (mHasTurbineGovernor) {
527 mMechTorque_prev = **mMechTorque;
528 **mMechTorque = mTurbineGovernor->step(**mOmMech, mTimeStep);
533 ((**mVdq0)(0, 0) * (**mIdq0)(0, 0) + (**mVdq0)(1, 0) * (**mIdq0)(1, 0));
534 **mOmMech = **mOmMech +
535 mTimeStep * (1. / (2. * mH) * (mMechTorque_prev - **mElecTorque));
536 **mThetaMech = **mThetaMech + mTimeStep * (**mOmMech * mBase_OmMech);
537 **mDelta = **mDelta + mTimeStep * (**mOmMech - 1.) * mBase_OmMech;
543 (**mRightVector).setZero();
544 mnaCompApplyRightSideVectorStamp(**mRightVector);
547template <
typename VarType>
550 AttributeBase::List &attributeDependencies,
551 AttributeBase::List &modifiedAttributes) {
556template <
typename VarType>
557void Base::ReducedOrderSynchronGenerator<VarType>::mnaCompPreStep(
558 Real time, Int timeStepCount) {
561 (**mRightVector).setZero();
562 mnaCompApplyRightSideVectorStamp(**mRightVector);
565template <
typename VarType>
568 AttributeBase::List &attributeDependencies,
569 AttributeBase::List &modifiedAttributes,
570 Attribute<Matrix>::Ptr &leftVector) {
571 attributeDependencies.push_back(leftVector);