DPsim
Loading...
Searching...
No Matches
EMT_Ph3_SynchronGeneratorDQ.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_SynchronGeneratorDQ.h>
10
11using namespace CPS;
12
13// !!! TODO: Adaptions to use in EMT_Ph3 models phase-to-ground peak variables
14// !!! with initialization from phase-to-phase RMS variables
15
17 Logger::Level logLevel)
18 : MNASimPowerComp<Real>(uid, name, true, true, logLevel),
20 mPhaseType = PhaseType::ABC;
21 setTerminalNumber(1);
22 **mIntfVoltage = Matrix::Zero(3, 1);
23 **mIntfCurrent = Matrix::Zero(3, 1);
24}
25
27 Logger::Level logLevel)
28 : SynchronGeneratorDQ(name, name, logLevel) {}
29
30EMT::Ph3::SynchronGeneratorDQ::~SynchronGeneratorDQ() {}
31
32Real EMT::Ph3::SynchronGeneratorDQ::electricalTorque() const {
33 return **mElecTorque * mBase_T;
34}
35
36Real EMT::Ph3::SynchronGeneratorDQ::rotationalSpeed() const {
37 return **mOmMech * mBase_OmMech;
38}
39
40Real EMT::Ph3::SynchronGeneratorDQ::rotorPosition() const { return mThetaMech; }
41
43 Real nomPower, Real nomVolt, Real nomFreq, Int poleNumber, Real nomFieldCur,
44 Real Rs, Real Ll, Real Lmd, Real Lmq, Real Rfd, Real Llfd, Real Rkd,
45 Real Llkd, Real Rkq1, Real Llkq1, Real Rkq2, Real Llkq2, Real inertia,
46 Real initActivePower, Real initReactivePower, Real initTerminalVolt,
47 Real initVoltAngle, Real initMechPower) {
48
50 nomPower, nomVolt, nomFreq, nomFieldCur, poleNumber, Rs, Ll, Lmd, Lmq,
51 Rfd, Llfd, Rkd, Llkd, Rkq1, Llkq1, Rkq2, Llkq2, inertia);
52
53 SPDLOG_LOGGER_INFO(mSLog,
54 "Set base and fundamental parameters in per unit: \n"
55 "nomPower: {:e}\nnomVolt: {:e}\nnomFreq: "
56 "{:e}\npoleNumber: {:d}\nnomFieldCur: {:e}\n"
57 "Rs: {:e}\nLl: {:e}\nLmd: {:e}\nLmq: {:e}\nRfd: "
58 "{:e}\nLlfd: {:e}\nRkd: {:e}\n"
59 "Llkd: {:e}\nRkq1: {:e}\nLlkq1: {:e}\nRkq2: {:e}\nLlkq2: "
60 "{:e}\ninertia: {:e}",
61 nomPower, nomVolt, nomFreq, poleNumber, nomFieldCur, Rs,
62 Ll, Lmd, Lmq, Rfd, Llfd, Rkd, Llkd, Rkq1, Llkq1, Rkq2,
63 Llkq2, inertia);
64
65 Base::SynchronGenerator::setInitialValues(initActivePower, initReactivePower,
66 initTerminalVolt, initVoltAngle,
67 initMechPower);
68
69 SPDLOG_LOGGER_INFO(
70 mSLog,
71 "Set initial values: \n"
72 "initActivePower: {:e} [W]\n"
73 "initReactivePower: {:e} [VAr]\n"
74 "initTerminalVolt: {:e} [V] (initTerminalVolt: {:e} [pu])\n"
75 "initVoltAngle: {:e} [deg] \n"
76 "initMechPower: {:e} [W]",
77 mInitElecPower.real(), mInitElecPower.imag(), mInitTerminalVoltage,
78 mInitTerminalVoltage / mBase_V, CPS::Math::radtoDeg(mInitVoltAngle),
79 mInitMechPower);
80}
81
82void EMT::Ph3::SynchronGeneratorDQ::setParametersOperationalPerUnit(
83 Real nomPower, Real nomVolt, Real nomFreq, Int poleNumber, Real nomFieldCur,
84 Real Rs, Real Ld, Real Lq, Real Ld_t, Real Lq_t, Real Ld_s, Real Lq_s,
85 Real Ll, Real Td0_t, Real Tq0_t, Real Td0_s, Real Tq0_s, Real inertia) {
86
87 setBaseParameters(nomPower, nomVolt, nomFreq, nomFieldCur);
88 SPDLOG_LOGGER_INFO(
89 mSLog,
90 "Set base parameters: \n"
91 "nomPower: {:e}\nnomVolt: {:e}\nnomFreq: {:e}\n nomFieldCur: {:e}\n",
92 nomPower, nomVolt, nomFreq, nomFieldCur);
93
94 setOperationalPerUnitParameters(poleNumber, inertia, Rs, Ld, Lq, Ll, Ld_t,
95 Lq_t, Ld_s, Lq_s, Td0_t, Tq0_t, Td0_s, Tq0_s);
96 SPDLOG_LOGGER_INFO(mSLog,
97 "Set operational parameters in per unit: \n"
98 "poleNumber: {:d}\ninertia: {:e}\n"
99 "Rs: {:e}\nLd: {:e}\nLq: {:e}\nLl: {:e}\n"
100 "Ld_t: {:e}\nLq_t: {:e}\nLd_s: {:e}\nLq_s: {:e}\n"
101 "Td0_t: {:e}\nTq0_t: {:e}\nTd0_s: {:e}\nTq0_s: {:e}\n",
102 poleNumber, inertia, Rs, Ld, Lq, Ll, Ld_t, Lq_t, Ld_s,
103 Lq_s, Td0_t, Tq0_t, Td0_s, Tq0_s);
104
105 Base::SynchronGenerator::calculateFundamentalFromOperationalParameters();
106 SPDLOG_LOGGER_INFO(
107 mSLog,
108 "Set fundamental parameters in per unit: \n"
109 "Rs: {:e}\nLl: {:e}\nLmd: {:e}\nLmq: {:e}\nRfd: {:e}\nLlfd: {:e}\nRkd: "
110 "{:e}\n"
111 "Llkd: {:e}\nRkq1: {:e}\nLlkq1: {:e}\nRkq2: {:e}\nLlkq2: {:e}\n",
112 **mRs, **mLl, mLmd, mLmq, mRfd, mLlfd, mRkd, mLlkd, mRkq1, mLlkq1, mRkq2,
113 mLlkq2);
114}
115
117 Real initReactivePower,
118 Real initTerminalVolt,
119 Real initVoltAngle,
120 Real initMechPower) {
121
122 Base::SynchronGenerator::setInitialValues(initActivePower, initReactivePower,
123 initTerminalVolt, initVoltAngle,
124 initMechPower);
125
126 SPDLOG_LOGGER_INFO(
127 mSLog,
128 "Set initial values: \n"
129 "initActivePower: {:e} [W]\n"
130 "initReactivePower: {:e} [VAr]\n"
131 "initTerminalVolt: {:e} [V] (initTerminalVolt: {:e} [pu])\n"
132 "initVoltAngle: {:e} [deg] \n"
133 "initMechPower: {:e} [W]",
134 mInitElecPower.real(), mInitElecPower.imag(), mInitTerminalVoltage,
135 mInitTerminalVoltage / mBase_V, CPS::Math::radtoDeg(mInitVoltAngle),
136 mInitMechPower);
137}
138
140
141 SPDLOG_LOGGER_INFO(mSLog,
142 "Apply operational parameters in per unit: \n"
143 "poleNumber: {:d}\ninertia: {:e}\n"
144 "Rs: {:e}\nLd: {:e}\nLq: {:e}\nLl: {:e}\n"
145 "Ld_t: {:e}\nLq_t: {:e}\nLd_s: {:e}\nLq_s: {:e}\n"
146 "Td0_t: {:e}\nTq0_t: {:e}\nTd0_s: {:e}\nTq0_s: {:e}\n",
147 mPoleNumber, **mInertia, **mRs, **mLd, **mLq, **mLl,
148 **mLd_t, **mLq_t, **mLd_s, **mLq_s, **mTd0_t, **mTq0_t,
149 **mTd0_s, **mTq0_s);
150
151 Base::SynchronGenerator::calculateFundamentalFromOperationalParameters();
152 SPDLOG_LOGGER_INFO(
153 mSLog,
154 "Updated fundamental parameters in per unit: \n"
155 "Rs: {:e}\nLl: {:e}\nLmd: {:e}\nLmq: {:e}\nRfd: {:e}\nLlfd: {:e}\nRkd: "
156 "{:e}\n"
157 "Llkd: {:e}\nRkq1: {:e}\nLlkq1: {:e}\nRkq2: {:e}\nLlkq2: {:e}\n",
159 mLlkq2);
160}
161
163 Real frequency) {
164 if (!mInitialValuesSet) {
165 SPDLOG_LOGGER_INFO(mSLog, "--- Initialization from powerflow ---");
166
167 // terminal powers in consumer system -> convert to generator system
168 Real activePower = -terminal(0)->singlePower().real();
169 Real reactivePower = -terminal(0)->singlePower().imag();
170
171 // voltage magnitude in phase-to-phase RMS -> convert to phase-to-ground peak expected by setInitialValues
172 Real voltMagnitude = RMS3PH_TO_PEAK1PH * Math::abs(initialSingleVoltage(0));
173
174 this->setInitialValues(activePower, reactivePower, voltMagnitude,
175 Math::phase(initialSingleVoltage(0)), activePower);
176
177 SPDLOG_LOGGER_INFO(mSLog,
178 "\nTerminal 0 voltage: {:s}"
179 "\nTerminal 0 power: {:s}"
180 "\n--- Initialization from powerflow finished ---",
181 Logger::phasorToString(initialSingleVoltage(0)),
182 Logger::complexToString(terminal(0)->singlePower()));
183 } else {
184 SPDLOG_LOGGER_INFO(mSLog, "Initial values already set, skipping "
185 "initializeFromNodesAndTerminals.");
186 }
187 mSLog->flush();
188}
189
192}
193
195 // #### Compensation ####
196 mCompensationOn = false;
197 mCompensationCurrent = Matrix::Zero(3, 1);
198 // Calculate real compensation resistance from per unit
200
201 // #### General setup ####
202 // Create matrices for state space representation
203 calcStateSpaceMatrixDQ();
204
205 // steady state per unit initial value
207
208 mVdq0 = Matrix::Zero(3, 1);
209 mIdq0 = Matrix::Zero(3, 1);
210 if (mNumDampingWindings == 2) {
211 mVdq0 << mVsr(0, 0), mVsr(3, 0), mVsr(6, 0);
212 mIdq0 << mIsr(0, 0), mIsr(3, 0), mIsr(6, 0);
213 } else {
214 mVdq0 << mVsr(0, 0), mVsr(3, 0), mVsr(5, 0);
215 mIdq0 << mIsr(0, 0), mIsr(3, 0), mIsr(5, 0);
216 }
217
220}
221
222void EMT::Ph3::SynchronGeneratorDQ::mnaCompApplySystemMatrixStamp(
223 SparseMatrixRow &systemMatrix) {
224 if (!mCompensationOn)
225 return;
226
227 Real conductance = 1. / mRcomp;
228
229 if (terminalNotGrounded(0)) {
230 Math::addToMatrixElement(systemMatrix, matrixNodeIndex(0, 0),
231 matrixNodeIndex(0, 0), conductance);
232 Math::addToMatrixElement(systemMatrix, matrixNodeIndex(0, 1),
233 matrixNodeIndex(0, 1), conductance);
234 Math::addToMatrixElement(systemMatrix, matrixNodeIndex(0, 2),
235 matrixNodeIndex(0, 2), conductance);
236 SPDLOG_LOGGER_INFO(mSLog, "Add {} to {}, {}", conductance,
237 matrixNodeIndex(0, 0), matrixNodeIndex(0, 0));
238 SPDLOG_LOGGER_INFO(mSLog, "Add {} to {}, {}", conductance,
239 matrixNodeIndex(0, 1), matrixNodeIndex(0, 1));
240 SPDLOG_LOGGER_INFO(mSLog, "Add {} to {}, {}", conductance,
241 matrixNodeIndex(0, 2), matrixNodeIndex(0, 2));
242 }
243}
244
245void EMT::Ph3::SynchronGeneratorDQ::mnaCompApplyRightSideVectorStamp(
246 Matrix &rightVector) {
247 if (mCompensationOn)
248 mCompensationCurrent = **mIntfVoltage / mRcomp;
249
250 // If the interface current is positive, it is flowing out of the connected node and into ground.
251 // Therefore, the generator is interfaced as a consumer but since the currents are reversed the equations
252 // are in generator mode.
253 if (terminalNotGrounded(0)) {
254 Math::setVectorElement(rightVector, matrixNodeIndex(0, 0),
255 -(**mIntfCurrent)(0, 0) +
256 mCompensationCurrent(0, 0));
257 Math::setVectorElement(rightVector, matrixNodeIndex(0, 1),
258 -(**mIntfCurrent)(1, 0) +
259 mCompensationCurrent(1, 0));
260 Math::setVectorElement(rightVector, matrixNodeIndex(0, 2),
261 -(**mIntfCurrent)(2, 0) +
262 mCompensationCurrent(2, 0));
263 }
264}
265
267 const Matrix &leftVector) {
268 (**mIntfVoltage)(0, 0) =
269 Math::realFromVectorElement(leftVector, matrixNodeIndex(0, 0));
270 (**mIntfVoltage)(1, 0) =
271 Math::realFromVectorElement(leftVector, matrixNodeIndex(0, 1));
272 (**mIntfVoltage)(2, 0) =
273 Math::realFromVectorElement(leftVector, matrixNodeIndex(0, 2));
274}
275
277 AttributeBase::List &prevStepDependencies,
278 AttributeBase::List &attributeDependencies,
279 AttributeBase::List &modifiedAttributes,
280 Attribute<Matrix>::Ptr &leftVector) {
281 attributeDependencies.push_back(leftVector);
282 modifiedAttributes.push_back(mIntfVoltage);
283}
284
285void EMT::Ph3::SynchronGeneratorDQ::mnaCompPostStep(
286 Real time, Int timeStepCount, Attribute<Matrix>::Ptr &leftVector) {
287 mnaCompUpdateVoltage(**leftVector);
288}
289
291 Matrix &abcVector) {
292 Matrix dq0Vector(3, 1);
293 Matrix abcToDq0(3, 3);
294
295 // Park transform according to Kundur
296 abcToDq0 << 2. / 3. * cos(theta), 2. / 3. * cos(theta - 2. * PI / 3.),
297 2. / 3. * cos(theta + 2. * PI / 3.), -2. / 3. * sin(theta),
298 -2. / 3. * sin(theta - 2. * PI / 3.),
299 -2. / 3. * sin(theta + 2. * PI / 3.), 1. / 3., 1. / 3., 1. / 3.;
300
301 dq0Vector = abcToDq0 * abcVector;
302
303 return dq0Vector;
304}
305
307 Matrix &dq0Vector) {
308 Matrix abcVector(3, 1);
309 Matrix dq0ToAbc(3, 3);
310
311 // Park transform according to Kundur
312 dq0ToAbc << cos(theta), -sin(theta), 1., cos(theta - 2. * PI / 3.),
313 -sin(theta - 2. * PI / 3.), 1., cos(theta + 2. * PI / 3.),
314 -sin(theta + 2. * PI / 3.), 1.;
315
316 abcVector = dq0ToAbc * dq0Vector;
317
318 return abcVector;
319}
Matrix mIsr
Vector of stator and rotor currents.
const Attribute< Real >::Ptr mLq_t
Transient q-axis inductance [H].
Real mRkq1
q-axis damper resistance 1 Rkq1 [Ohm]
Real mRcomp
Compensation Resistance.
Real mLmd
d-axis mutual inductance Lmd [H]
Real mBase_I
base stator current peak
Bool mCompensationOn
Determines if compensation elements are used.
const Attribute< Real >::Ptr mTq0_s
Subtransient time constant of q-axis [s].
Real mLmq
q-axis mutual inductance Lmq [H]
SynchronGenerator(CPS::AttributeList::Ptr attributeList)
Constructor.
Real mLlfd
field leakage inductance Llfd [H]
Bool mInitialValuesSet
Flag to remember when initial values are set.
const Attribute< Real >::Ptr mTq0_t
Transient time constant of q-axis [s].
Real mLlkd
d-axis damper leakage inductance Llkd [H]
Matrix mVsr
Vector of stator and rotor voltages.
const Attribute< Real >::Ptr mLq
q-axis inductance Lq [H]
Real mBase_Z
base stator impedance
const Attribute< Real >::Ptr mRs
stator resistance Rs [Ohm]
Real mLlkq1
q-axis damper leakage inductance 1 Llkq1 [H]
Matrix mIdq0
dq0 current calculated from terminal current
const Attribute< Real >::Ptr mLq_s
Subtransient q-axis inductance [H].
void setBaseAndFundamentalPerUnitParameters(Real nomPower, Real nomVolt, Real nomFreq, Real nomFieldCur, Int poleNumber, Real Rs, Real Ll, Real Lmd, Real Lmq, Real Rfd, Real Llfd, Real Rkd, Real Llkd, Real Rkq1, Real Llkq1, Real Rkq2, Real Llkq2, Real inertia)
Initializes the base and fundamental machine parameters in per unit.
Real mRkd
d-axis damper resistance Rkd [Ohm]
Real mRfd
field resistance Rfd [Ohm]
Matrix mVdq0
dq0 voltage calculated from terminal voltage
const Attribute< Real >::Ptr mLl
leakage inductance Ll [H]
const Attribute< Real >::Ptr mTd0_s
Subtransient time constant of d-axis [s].
Real mRkq2
q-axis damper resistance 2 Rkq2 [Ohm]
const Attribute< Real >::Ptr mTd0_t
Transient time constant of d-axis [s].
Int mNumDampingWindings
Number of damping windings in q.
Real mBase_V
base stator voltage (phase-to-ground peak)
const Attribute< Real >::Ptr mLd
d-axis inductance Ld [H]
const Attribute< Real >::Ptr mLd_t
Transient d-axis inductance [H].
Real mLlkq2
q-axis damper leakage inductance 2 Llkq2 [H]
const Attribute< Real >::Ptr mLd_s
Subtransient d-axis inductance [H].
const Attribute< Real >::Ptr mInertia
inertia constant H [s] for per unit or moment of inertia J [kg*m^2]
void initialize(Matrix frequencies) override
Initialize components with correct network frequencies.
Matrix dq0ToAbcTransform(Real theta, Matrix &dq0)
Inverse Park transform as described in Krause.
virtual void mnaCompUpdateVoltage(const Matrix &leftVector) override
Retrieves calculated voltage from simulation for next step.
void applyParametersOperationalPerUnit()
Calculates fundamental from operational parameters and applies them to the model.
void initializeMatrixAndStates()
Initializes internal states and matrix.
void mnaCompAddPostStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, Attribute< Matrix >::Ptr &leftVector) override
Add MNA post step dependencies.
void setInitialValues(Real initActivePower, Real initReactivePower, Real initTerminalVolt, Real initVoltAngle, Real initMechPower)
Initialize states according to desired initial electrical powerflow and mechanical input power.
Matrix mCompensationCurrent
Compensation current source set point.
void setParametersFundamentalPerUnit(Real nomPower, Real nomVolt, Real nomFreq, Int poleNumber, Real nomFieldCur, Real Rs, Real Ll, Real Lmd, Real Lmq, Real Rfd, Real Llfd, Real Rkd, Real Llkd, Real Rkq1, Real Llkq1, Real Rkq2, Real Llkq2, Real inertia, Real initActivePower, Real initReactivePower, Real initTerminalVolt, Real initVoltAngle, Real initMechPower)
Matrix abcToDq0Transform(Real theta, Matrix &abc)
Park transform as described in Krause.
void initializeFromNodesAndTerminals(Real frequency) override
Initializes component from power flow data.
SynchronGeneratorDQ(String name, String uid, Logger::Level logLevel=Logger::Level::off)
Defines UID, name and logging level.
String uid()
Returns unique id.
AttributeList::Ptr mAttributes
Attribute List.
MNASimPowerComp(String uid, String name, Bool hasPreStep, Bool hasPostStep, Logger::Level logLevel)
const Attribute< MatrixVar< Real > >::Ptr mIntfCurrent
virtual void initialize(Matrix frequencies)
Initialize components with correct network frequencies.
SimTerminal< Real >::Ptr terminal(UInt index)
const Attribute< MatrixVar< Real > >::Ptr mIntfVoltage
Logger::Log mSLog
Component logger.