DPsim
Loading...
Searching...
No Matches
EMT_Ph3_SynchronGeneratorTrStab.cpp
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
9#include <dpsim-models/EMT/EMT_Ph3_SynchronGeneratorTrStab.h>
10using namespace CPS;
11
12Matrix EMT::Ph3::SynchronGeneratorTrStab::parkTransformPowerInvariant(
13 Real theta, const Matrix &fabc) {
14 // Calculates fdq = Tdq * fabc
15 // Assumes that d-axis starts aligned with phase a
16 Matrix Tdq = getParkTransformMatrixPowerInvariant(theta);
17 Matrix dqvector = Tdq * fabc;
18 return dqvector;
19}
20
21Matrix EMT::Ph3::SynchronGeneratorTrStab::getParkTransformMatrixPowerInvariant(
22 Real theta) {
23 // Return park matrix for theta
24 // Assumes that d-axis starts aligned with phase a
25 Matrix Tdq = Matrix::Zero(2, 3);
26 Real k = sqrt(2. / 3.);
27 Tdq << k * cos(theta), k * cos(theta - 2. * M_PI / 3.),
28 k * cos(theta + 2. * M_PI / 3.), -k * sin(theta),
29 -k * sin(theta - 2. * M_PI / 3.), -k * sin(theta + 2. * M_PI / 3.);
30 return Tdq;
31}
32
33EMT::Ph3::SynchronGeneratorTrStab::SynchronGeneratorTrStab(
34 String uid, String name, Logger::Level logLevel)
35 : Base::SynchronGenerator(mAttributes),
36 CompositePowerComp<Real>(uid, name, true, true, logLevel),
37 mEp(mAttributes->create<Complex>("Ep")),
38 mEp_abs(mAttributes->create<Real>("Ep_mag")),
39 mEp_phase(mAttributes->create<Real>("Ep_phase")),
40 mDelta_p(mAttributes->create<Real>("delta_r")),
41 mRefOmega(mAttributes->createDynamic<Real>("w_ref")),
42 mRefDelta(mAttributes->createDynamic<Real>("delta_ref")) {
43 setVirtualNodeNumber(2);
44 setTerminalNumber(1);
45 **mIntfVoltage = Matrix::Zero(3, 1);
46 **mIntfCurrent = Matrix::Zero(3, 1);
47
48 mStates = Matrix::Zero(10, 1);
49}
50
51SimPowerComp<Real>::Ptr EMT::Ph3::SynchronGeneratorTrStab::clone(String name) {
52 auto copy = SynchronGeneratorTrStab::make(name, mLogLevel);
53 copy->setStandardParametersPU(mNomPower, mNomVolt, mNomFreq, mXpd / mBase_Z,
54 **mInertia, **mRs, mKd);
55 return copy;
56}
57
59 Real nomPower, Real nomVolt, Real nomFreq, Real Ll, Real Lmd, Real Llfd,
60 Real inertia, Real D) {
61 setBaseParameters(nomPower, nomVolt, nomFreq);
62
63 // Input is in per unit but all values are converted to absolute values.
64 mParameterType = ParameterType::statorReferred;
65 mStateType = StateType::statorReferred;
66
67 **mLl = Ll;
68 mLmd = Lmd;
69 **mLd = **mLl + mLmd;
70 mLlfd = Llfd;
71 mLfd = mLlfd + mLmd;
72 // M = 2*H where H = inertia
73 **mInertia = inertia;
74 // X'd in absolute values
75 mXpd = mNomOmega * (**mLd - mLmd * mLmd / mLfd) * mBase_L;
76 mLpd = (**mLd - mLmd * mLmd / mLfd) * mBase_L;
77
78 SPDLOG_LOGGER_INFO(mSLog,
79 "\n--- Parameters ---"
80 "\nimpedance: {:f}"
81 "\ninductance: {:f}",
82 mXpd, mLpd);
83}
84
86 Real nomPower, Real nomVolt, Real nomFreq, Int polePairNumber, Real Rs,
87 Real Lpd, Real inertiaJ, Real Kd) {
88 setBaseParameters(nomPower, nomVolt, nomFreq);
89
90 mParameterType = ParameterType::statorReferred;
91 mStateType = StateType::statorReferred;
92
93 // M = 2*H where H = inertia
94 // H = J * 0.5 * omegaNom^2 / polePairNumber
95 **mInertia = calcHfromJ(inertiaJ, 2 * PI * nomFreq, polePairNumber);
96 // X'd in absolute values
97 mXpd = mNomOmega * Lpd;
98 mLpd = Lpd;
99
100 SPDLOG_LOGGER_INFO(mSLog,
101 "\n--- Parameters ---"
102 "\nimpedance: {:f}"
103 "\ninductance: {:f}",
104 mXpd, mLpd);
105}
106
108 Real nomPower, Real nomVolt, Real nomFreq, Real Xpd, Real inertia, Real Rs,
109 Real D) {
110 setBaseParameters(nomPower, nomVolt, nomFreq);
111
112 // Input is in per unit but all values are converted to absolute values.
113 mParameterType = ParameterType::statorReferred;
114 mStateType = StateType::statorReferred;
115
116 // M = 2*H where H = inertia
117 **mInertia = inertia;
118 // X'd in absolute values
119 mXpd = Xpd * mBase_Z;
120 mLpd = Xpd * mBase_L;
121
122 **mRs = Rs;
123 //The units of D are per unit power divided by per unit speed deviation.
124 // D is transformed to an absolute value to obtain Kd, which will be used in the swing equation
125 mKd = D * mNomPower / mNomOmega;
126
127 SPDLOG_LOGGER_INFO(mSLog,
128 "\n--- Parameters ---"
129 "\nimpedance: {:f}"
130 "\ninductance: {:f}",
131 mXpd, mLpd);
132}
133
134void EMT::Ph3::SynchronGeneratorTrStab::setInitialValues(Complex elecPower,
135 Real mechPower) {
136 mInitElecPower = elecPower;
137 mInitMechPower = mechPower;
138}
139
141 Real frequency) {
142
143 // Initialize omega mech with nominal system frequency
144 **mOmMech = mNomOmega;
145
146 mInitElecPower = (mInitElecPower == Complex(0, 0))
147 ? -terminal(0)->singlePower()
148 : mInitElecPower;
149 mInitMechPower = (mInitElecPower == Complex(0, 0)) ? mInitElecPower.real()
150 : mInitMechPower;
151
152 // use complex interface quantities for initialization calculations
153 MatrixComp intfVoltageComplex = MatrixComp::Zero(3, 1);
154 MatrixComp intfCurrentComplex = MatrixComp::Zero(3, 1);
155 // // derive complex threephase initialization from single phase initial values (only valid for balanced systems)
156 // intfVoltageComplex(0, 0) = RMS3PH_TO_PEAK1PH * initialSingleVoltage(0);
157 intfVoltageComplex(0, 0) = initialSingleVoltage(0);
158 intfVoltageComplex(1, 0) = intfVoltageComplex(0, 0) * SHIFT_TO_PHASE_B;
159 intfVoltageComplex(2, 0) = intfVoltageComplex(0, 0) * SHIFT_TO_PHASE_C;
160 intfCurrentComplex(0, 0) =
161 std::conj(-2. / 3. * mInitElecPower / intfVoltageComplex(0, 0));
162 intfCurrentComplex(1, 0) = intfCurrentComplex(0, 0) * SHIFT_TO_PHASE_B;
163 intfCurrentComplex(2, 0) = intfCurrentComplex(0, 0) * SHIFT_TO_PHASE_C;
164
165 //save real interface quantities calculated from complex ones
166 **mIntfVoltage = intfVoltageComplex.real();
167 **mIntfCurrent = intfCurrentComplex.real();
168
169 mImpedance = Complex(**mRs, mXpd);
170
171 // Calculate initial emf behind reactance from power flow results
172 **mEp = intfVoltageComplex(0, 0) - mImpedance * intfCurrentComplex(0, 0);
173
174 // The absolute value of Ep is constant, only delta_p changes every step
175 **mEp_abs = Math::abs(**mEp);
176 // Delta_p is the angular position of mEp with respect to the synchronously rotating reference
177 **mDelta_p = Math::phase(**mEp);
178
179 // // Update active electrical power that is compared with the mechanical power
180 **mElecActivePower = (3. / 2. * intfVoltageComplex(0, 0) *
181 std::conj(-intfCurrentComplex(0, 0)))
182 .real();
183 // mElecActivePower = ( (mEp - (**mIntfVoltage)(0,0)) / mImpedance * (**mIntfVoltage)(0,0) ).real();
184 // For infinite power bus
185 // mElecActivePower = (Math::abs(mEp) * Math::abs((**mIntfVoltage)(0,0)) / mXpd) * sin(mDelta_p);
186
187 // Start in steady state so that electrical and mech. power are the same
188 // because of the initial condition mOmMech = mNomOmega the damping factor is not considered at the initialisation
190
191 // Initialize node between X'd and Ep
192 mVirtualNodes[0]->setInitialVoltage(PEAK1PH_TO_RMS3PH * **mEp);
193
194 MatrixComp vref = MatrixComp::Zero(3, 1);
196
197 // Create sub voltage source for emf
199 EMT::Ph3::VoltageSource::make(**mName + "_src", mLogLevel);
200 mSubVoltageSource->setParameters(vref, frequency);
201 mSubVoltageSource->connect({SimNode::GND, mVirtualNodes[0]});
202 mSubVoltageSource->setVirtualNodeAt(mVirtualNodes[1], 0);
203 mSubVoltageSource->initialize(mFrequencies);
204 mSubVoltageSource->initializeFromNodesAndTerminals(frequency);
206 MNA_SUBCOMP_TASK_ORDER::TASK_AFTER_PARENT,
207 MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, true);
208
209 // Create sub inductor as Xpd
210 mSubInductor = EMT::Ph3::Inductor::make(**mName + "_ind", mLogLevel);
211 mSubInductor->setParameters(
213 mSubInductor->connect({mVirtualNodes[0], terminal(0)->node()});
214 mSubInductor->initialize(mFrequencies);
215 mSubInductor->initializeFromNodesAndTerminals(frequency);
216 addMNASubComponent(mSubInductor, MNA_SUBCOMP_TASK_ORDER::TASK_AFTER_PARENT,
217 MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, true);
218
219 SPDLOG_LOGGER_INFO(mSLog,
220 "\n--- Initialize according to powerflow ---"
221 "\nTerminal 0 voltage: {:e}<{:e}"
222 "\nVoltage behind reactance: {:e}<{:e}"
223 "\ninitial electrical power: {:e}+j{:e}"
224 "\nactive electrical power: {:e}"
225 "\nmechanical power: {:e}"
226 "\n--- End of powerflow initialization ---",
227 Math::abs((**mIntfVoltage)(0, 0)),
228 Math::phaseDeg((**mIntfVoltage)(0, 0)), Math::abs(**mEp),
229 Math::phaseDeg(**mEp), mInitElecPower.real(),
230 mInitElecPower.imag(), **mElecActivePower, **mMechPower);
231}
232
233void EMT::Ph3::SynchronGeneratorTrStab::step(Real time) {
234 // #### Calculations on input of time step k ####
235 // Transform interface quantities to synchronously rotating DQ reference frame
236 Matrix intfVoltageDQ = parkTransformPowerInvariant(mThetaN, **mIntfVoltage);
237 Matrix intfCurrentDQ = parkTransformPowerInvariant(mThetaN, **mIntfCurrent);
238 // Update electrical power (minus sign to calculate generated power from consumed current)
239 **mElecActivePower = -1. * (intfVoltageDQ(0, 0) * intfCurrentDQ(0, 0) +
240 intfVoltageDQ(1, 0) * intfCurrentDQ(1, 0));
241
242 // The damping factor Kd is adjusted to obtain a damping ratio of 0.3
243 // Real MaxElecActivePower= Math::abs(mEp) * Math::abs((**mIntfVoltage)(0,0)) / mXpd;
244 // mKd=4*0.3*sqrt(mNomOmega*mInertia*MaxElecActivePower*0.5);
245 mKd = 1 * mNomPower;
246
247 // #### Calculate state for time step k+1 ####
248 // semi-implicit Euler or symplectic Euler method for mechanical equations
249 Real dOmMech =
250 mNomOmega / (2. * **mInertia * mNomPower) *
251 (**mMechPower - **mElecActivePower - mKd * (**mOmMech - mNomOmega));
252 if (mBehaviour == Behaviour::MNASimulation)
253 **mOmMech = **mOmMech + mTimeStep * dOmMech;
254 Real dDelta_p = **mOmMech - mNomOmega;
255 if (mBehaviour == Behaviour::MNASimulation)
256 **mDelta_p = **mDelta_p + mTimeStep * dDelta_p;
257 // Update emf - only phase changes
258 if (mBehaviour == Behaviour::MNASimulation)
259 **mEp = Complex(**mEp_abs * cos(**mDelta_p), **mEp_abs * sin(**mDelta_p));
260
261 // Update nominal system angle
262 mThetaN = mThetaN + mTimeStep * mNomOmega;
263
264 // mStates << Math::abs(mEp), Math::phaseDeg(mEp), mElecActivePower, mMechPower,
265 // mDelta_p, mOmMech, dOmMech, dDelta_p, (**mIntfVoltage)(0,0).real(), (**mIntfVoltage)(0,0).imag();
266 // SPDLOG_LOGGER_DEBUG(mSLog, "\nStates, time {:f}: \n{:s}", time, Logger::matrixToString(mStates));
267}
268
270 Real omega, Real timeStep, Attribute<Matrix>::Ptr leftVector) {
271 mTimeStep = timeStep;
272 mMnaTasks.push_back(std::make_shared<AddBStep>(*this));
273}
274
275void EMT::Ph3::SynchronGeneratorTrStab::mnaParentAddPreStepDependencies(
276 AttributeBase::List &prevStepDependencies,
277 AttributeBase::List &attributeDependencies,
278 AttributeBase::List &modifiedAttributes) {
279 prevStepDependencies.push_back(mIntfVoltage);
280};
281
282void EMT::Ph3::SynchronGeneratorTrStab::mnaParentAddPostStepDependencies(
283 AttributeBase::List &prevStepDependencies,
284 AttributeBase::List &attributeDependencies,
285 AttributeBase::List &modifiedAttributes,
286 Attribute<Matrix>::Ptr &leftVector) {
287 attributeDependencies.push_back(leftVector);
288 modifiedAttributes.push_back(mIntfVoltage);
289};
290
292 Int timeStepCount) {
293 step(time);
294 //change magnitude of subvoltage source
295 MatrixComp vref = MatrixComp::Zero(3, 1);
296 vref = CPS::Math::singlePhaseVariableToThreePhase(PEAK1PH_TO_RMS3PH * **mEp);
297 mSubVoltageSource->mVoltageRef->set(vref);
298}
299
300void EMT::Ph3::SynchronGeneratorTrStab::AddBStep::execute(Real time,
301 Int timeStepCount) {
302 **mGenerator.mRightVector = **mGenerator.mSubInductor->mRightVector +
303 **mGenerator.mSubVoltageSource->mRightVector;
304}
305
307 Real time, Int timeStepCount, Attribute<Matrix>::Ptr &leftVector) {
308 mnaCompUpdateVoltage(**leftVector);
309 mnaCompUpdateCurrent(**leftVector);
310}
311
312void EMT::Ph3::SynchronGeneratorTrStab::mnaCompUpdateVoltage(
313 const Matrix &leftVector) {
314 SPDLOG_LOGGER_DEBUG(mSLog, "Read voltage from {:d}", matrixNodeIndex(0));
315 (**mIntfVoltage)(0, 0) =
316 Math::realFromVectorElement(leftVector, matrixNodeIndex(0, 0));
317 (**mIntfVoltage)(1, 0) =
318 Math::realFromVectorElement(leftVector, matrixNodeIndex(0, 1));
319 (**mIntfVoltage)(2, 0) =
320 Math::realFromVectorElement(leftVector, matrixNodeIndex(0, 2));
321}
322
323void EMT::Ph3::SynchronGeneratorTrStab::mnaCompUpdateCurrent(
324 const Matrix &leftVector) {
325 SPDLOG_LOGGER_DEBUG(mSLog, "Read current from {:d}", matrixNodeIndex(0));
326
327 **mIntfCurrent = **mSubInductor->mIntfCurrent;
328}
Real mNomFreq
nominal frequency fn [Hz]
Real mTimeStep
Simulation time step.
Real mLmd
d-axis mutual inductance Lmd [H]
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]
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
const Attribute< Real >::Ptr mInertia
inertia constant H [s] for per unit or moment of inertia J [kg*m^2]
void addMNASubComponent(typename SimPowerComp< Real >::Ptr subc, MNA_SUBCOMP_TASK_ORDER preStepOrder, MNA_SUBCOMP_TASK_ORDER postStepOrder, Bool contributeToRightVector)
void setStandardParametersPU(Real nomPower, Real nomVolt, Real nomFreq, Real Xpd, Real inertia, Real Rs=0, Real D=0)
Initializes the machine parameters.
void mnaParentInitialize(Real omega, Real timeStep, Attribute< Matrix >::Ptr leftVector) override
Initializes variables of component.
void setStandardParametersSI(Real nomPower, Real nomVolt, Real nomFreq, Int polePairNumber, Real Rs, Real Lpd, Real inertiaJ, Real Kd=0)
Initializes the machine parameters.
std::shared_ptr< VoltageSource > mSubVoltageSource
Inner voltage source that represents the generator.
SimPowerComp< Real >::Ptr clone(String name) override
Returns a modified copy of the component with the given suffix added to the name and without.
void mnaParentPostStep(Real time, Int timeStepCount, Attribute< Matrix >::Ptr &leftVector) override
Retrieves calculated voltage from simulation for next step.
const Attribute< Complex >::Ptr mEp
emf behind transient reactance
void mnaParentPreStep(Real time, Int timeStepCount) override
Complex mImpedance
Equivalent impedance for loadflow calculation.
std::shared_ptr< Inductor > mSubInductor
Inner inductor that represents the generator impedance.
void initializeFromNodesAndTerminals(Real frequency) override
Initializes Component variables according to power flow data stored in Nodes.
const Attribute< Real >::Ptr mDelta_p
Angle by which the emf Ep is leading the terminal voltage.
void setFundamentalParametersPU(Real nomPower, Real nomVolt, Real nomFreq, Real Ll, Real Lmd, Real Llfd, Real inertia, Real D=0)
Initializes the machine parameters.
Real mLpd
Absolute d-axis transient inductance.
Real mXpd
Absolute d-axis transient reactance X'd.
const Attribute< String >::Ptr mName
Human readable name.
static Matrix singlePhaseParameterToThreePhase(Real parameter)
To convert single phase parameters to symmetrical three phase ones.
static MatrixComp singlePhaseVariableToThreePhase(Complex var_1ph)
To convert single phase complex variables (voltages, currents) to symmetrical three phase ones.
const Attribute< MatrixVar< Real > >::Ptr mIntfCurrent
SimTerminal< Real >::Ptr terminal(UInt index)
const Attribute< MatrixVar< Real > >::Ptr mIntfVoltage
SimNode< Real >::List mVirtualNodes
Logger::Level mLogLevel
Component logger control for internal variables.
Logger::Log mSLog
Component logger.