DPsim
Loading...
Searching...
No Matches
DP_Ph1_SVC.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
10
11using namespace CPS;
12
14 : CompositePowerComp<Complex>(uid, name, true, true, logLevel),
15 mVpcc(mAttributes->create<Real>("Vpcc", 0)),
16 mVmeasPrev(mAttributes->create<Real>("Vmeas", 0)) {
19 **mIntfVoltage = MatrixComp::Zero(1, 1);
20 **mIntfCurrent = MatrixComp::Zero(1, 1);
21
22 mDeltaV = mAttributes->create<Real>("DeltaV", 0);
23 mBPrev = mAttributes->create<Real>("B");
24 mViolationCounter = mAttributes->create<Real>("ViolationCounter", 0);
25}
26
28
31 return;
32 mSubCompCreated = true;
33
34 // Inductor/capacitor values depend on omega computed from the simulation
35 // frequency in initializeParentFromNodesAndTerminals(). They are created
36 // here (topology) and parametrized there (values).
37
38 // Inductor with Switch
40 std::make_shared<DP::Ph1::Inductor>(**mName + "_ind", mLogLevel);
44
46 std::make_shared<DP::Ph1::Switch>(**mName + "_Lswitch", mLogLevel);
47 mSubInductorSwitch->setParameters(mSwitchROpen, mSwitchRClosed, false);
48 mSubInductorSwitch->connect({mVirtualNodes[0], mTerminals[0]->node()});
52
53 // Capacitor with Switch
55 std::make_shared<DP::Ph1::Capacitor>(**mName + "_cap", mLogLevel);
59
61 std::make_shared<DP::Ph1::Switch>(**mName + "_Cswitch", mLogLevel);
62 mSubCapacitorSwitch->setParameters(mSwitchROpen, mSwitchRClosed, false);
63 mSubCapacitorSwitch->connect({mVirtualNodes[1], mTerminals[0]->node()});
67}
68
70 // initial state is both switches are open
71 Real omega = 2. * PI * frequency;
72 // init L and C with small/high values (both have high impedance)
73 Real LInit = 1e6 / omega;
74 Real CInit = 1e-6 / omega;
75 mLPrev = LInit;
76 mCPrev = CInit;
77
78 // impedances of both branches
79 Complex LImpedance = {mSwitchROpen, omega * LInit};
80 Complex CImpedance = {mSwitchROpen, -1 / (omega * CInit)};
81 Complex impedance = LImpedance * CImpedance / (LImpedance + CImpedance);
82
83 (**mIntfVoltage)(0, 0) = initialSingleVoltage(0);
84 (**mIntfCurrent)(0, 0) = (**mIntfVoltage)(0, 0) / impedance;
85
86 **mBPrev = 0;
87 mPrevVoltage = (**mIntfVoltage)(0, 0).real();
89
90 if (mMechMode) {
91 SPDLOG_LOGGER_INFO(mSLog, "Using Mechanical Model");
92 }
93
94 SPDLOG_LOGGER_INFO(mSLog,
95 "\n --- Parameters ---"
96 "\n Controller: T = {} K = {}"
97 "\n Reference Voltage {} [kV]"
98 "\n Qmax = {} [var] -> BN = {} [S]"
99 "\n Bmax = {} Bmin = {} [p.u.]"
100 "\n Initial B: {}",
102
103 // set voltages at virtual nodes
104 Complex VLSwitch =
105 (**mIntfVoltage)(0, 0) - LImpedance * (**mIntfCurrent)(0, 0);
106 mVirtualNodes[0]->setInitialVoltage(VLSwitch);
107 Complex VCSwitch =
108 (**mIntfVoltage)(0, 0) - CImpedance * (**mIntfCurrent)(0, 0);
109 mVirtualNodes[1]->setInitialVoltage(VCSwitch);
110
111 mSubInductor->setParameters(LInit);
112 mSubCapacitor->setParameters(CInit);
113
114 SPDLOG_LOGGER_INFO(mSLog,
115 "\n--- Initialization from powerflow ---"
116 "\nImpedance: {}"
117 "\nVoltage across: {:s}"
118 "\nCurrent: {:s}"
119 "\nTerminal 0 voltage: {:s}"
120 "\n--- Initialization from powerflow finished ---",
121 impedance, Logger::phasorToString((**mIntfVoltage)(0, 0)),
124}
125
126// #### MNA functions ####
127
129 AttributeBase::List &prevStepDependencies,
130 AttributeBase::List &attributeDependencies,
131 AttributeBase::List &modifiedAttributes) {
132 modifiedAttributes.push_back(mRightVector);
133}
134
135void DP::Ph1::SVC::mnaParentPreStep(Real time, Int timeStepCount) {
137
138 if (time > 0.1 && !mDisconnect) {
139 if (mMechMode) {
141 } else {
143 }
144 checkProtection(time);
145 }
146}
147
149 AttributeBase::List &prevStepDependencies,
150 AttributeBase::List &attributeDependencies,
151 AttributeBase::List &modifiedAttributes,
152 Attribute<Matrix>::Ptr &leftVector) {
153 attributeDependencies.push_back(leftVector);
154 modifiedAttributes.push_back(mIntfVoltage);
155 modifiedAttributes.push_back(mIntfCurrent);
156}
157
158void DP::Ph1::SVC::mnaParentPostStep(Real time, Int timeStepCount,
159 Attribute<Matrix>::Ptr &leftVector) {
160 mnaCompUpdateVoltage(**leftVector);
161 mnaCompUpdateCurrent(**leftVector);
162
163 mDeltaT = time - mPrevTimeStep;
164 mPrevTimeStep = time;
165 mValueChange = false;
166}
167
170 mNumFreqs, 0)
171 .real();
172 (**mIntfVoltage)(0, 0) =
174}
175
177 (**mIntfCurrent)(0, 0) = 0;
178 (**mIntfCurrent)(0, 0) += mSubInductor->intfCurrent()(0, 0);
179 (**mIntfCurrent)(0, 0) += mSubCapacitor->intfCurrent()(0, 0);
180}
181
183 // check states for violation of protection values
184 // get inverse protection curve value (time delay value)
185
186 Real Vpu = **mVmeasPrev / mNomVolt;
187 if (Vpu > 1.4) {
189 if (mProtCount1 > 0.1) {
190 mDisconnect = true;
191 }
192 } else {
193 mProtCount1 = 0;
194 }
195 if (Vpu > 1.25) {
197 if (mProtCount2 > 1) {
198 mDisconnect = true;
199 }
200 } else {
201 mProtCount2 = 0;
202 }
203 if (Vpu > 1.15) {
205 if (mProtCount3 > 5) {
206 mDisconnect = true;
207 }
208 } else {
209 mProtCount3 = 0;
210 }
211
212 if (mDisconnect) {
213 SPDLOG_LOGGER_INFO(mSLog, "Disconnect SVC because of overvoltage at {}",
214 time);
215 mSubCapacitorSwitch->open();
216 mSubInductorSwitch->open();
217 mValueChange = true;
218 }
219}
220
222 // calculate new B value
223 // summarize some constants
224 Real Fac1 = mDeltaT / (2 * mTr);
225 Real Fac2 = mDeltaT * mKr / (2 * mTr);
226
227 Real V = Math::abs((**mIntfVoltage)(0, 0).real());
228
229 // Pt1 with trapez rule for voltage measurement
230 Real Fac3 = mDeltaT / (2 * mTm);
231 Real Vmeas = (1 / (1 + Fac3)) * (V + mPrevVoltage - **mVmeasPrev);
232
233 **mDeltaV = (Vmeas - mRefVolt) / mNomVolt;
234 Real deltaVPrev = (**mVmeasPrev - mRefVolt) / mNomVolt;
235
236 // calc new B with trapezoidal rule
237 Real B = (1 / (1 + Fac1)) *
238 (Fac2 * (**mDeltaV + deltaVPrev) + (1 - Fac1) * **mBPrev);
239
240 // check bounds
241 if (B > mBMax) {
242 B = mBMax;
243 } else if (B < mBMin) {
244 B = mBMin;
245 }
246
247 // set new B if it has a new value and difference is big enough
248 if (B != **mBPrev) {
249 Real omega = 2 * M_PI * mFrequencies(0, 0);
250
251 if (B > 0) {
252 // model inductive behaviour (decrease voltage)
253 Real inductance = 1 / (omega * B * mBN);
254 //check if change in reactance is sufficient to trigger a change
255 if (Math::abs(1 - inductance / mLPrev) > 0.01) {
256 mInductiveMode = true;
257 mSubInductor->updateInductance(inductance, mDeltaT);
258 mLPrev = inductance;
259
260 mValueChange = true;
261 mBSetCounter = 0;
262 }
263 } else {
264 // model capacitive behaviour (increase voltage)
265 Real capacitance = B * mBN / (-omega);
266 //check if change in reactance is sufficient to trigger a change
267 if (Math::abs(1 - capacitance / mCPrev) > 0.01) {
268 mInductiveMode = false;
269 mSubCapacitor->updateCapacitance(capacitance, mDeltaT);
270 mCPrev = capacitance;
271
272 mValueChange = true;
273 mBSetCounter = 0;
274 }
275 }
276
277 // update inductance model
279 } else {
281 }
282
283 // save values
284 **mBPrev = B;
285 mPrevVoltage = V;
286 **mVmeasPrev = Vmeas;
287}
288
289// model SVC with a mechanical component and discrete
291 // current voltage
292 Real V = Math::abs((**mIntfVoltage)(0, 0).real());
293 Real omega = 2 * M_PI * mFrequencies(0, 0);
294
295 // Pt1 with trapez rule for voltage measurement
296 Real Fac3 = mDeltaT / (2 * mTm);
297 Real Vmeas = (1 / (1 + Fac3)) * (V + mPrevVoltage - **mVmeasPrev);
298
299 // V diff in pu
300 Real deltaV = (mRefVolt - Vmeas) / mRefVolt;
301
302 if (Math::abs(deltaV) > mDeadband) {
304 // change suszeptance one step
305 if (deltaV > 0 && (mTapPos > mMinPos)) {
306 // undervoltage
307
308 mTapPos = mTapPos - 1;
310 **mViolationCounter = 0;
311 SPDLOG_LOGGER_INFO(mSLog,
312 "Time: {}"
313 "\nDecreasing Tap. Reason: Undervoltage"
314 "\nNew Tap Position: {}",
315 time, mTapPos);
316 } else if (deltaV < 0 && (mTapPos < mMaxPos)) {
317 // overvoltage
318 mTapPos = mTapPos + 1;
320 **mViolationCounter = 0;
321 SPDLOG_LOGGER_INFO(mSLog,
322 "Time: {}"
323 "\nIncreasing Tap. Reason: Overvoltag"
324 "\nNew Tap Position: {}",
325 time, mTapPos);
326 }
327
328 if (**mViolationCounter == 0) {
329 // new value for suszeptance
330 if (mTapPos > 0) {
331 // inductor is active
332 mInductiveMode = true;
333 Real inductance = 1 / ((mTapPos / mMaxPos) * mBN * omega);
334 SPDLOG_LOGGER_INFO(mSLog, "New inductance: {}", inductance);
335 mSubInductor->updateInductance(inductance, mDeltaT);
336 mValueChange = true;
338 } else if (mTapPos < 0) {
339 // capacitor is active
340 mInductiveMode = false;
341 Real capacitance = ((mTapPos / mMinPos) * mBN) / omega;
342 SPDLOG_LOGGER_INFO(mSLog, "New capacitance: {}", capacitance);
343 mSubCapacitor->updateCapacitance(capacitance, mDeltaT);
344 mValueChange = true;
346
347 } else if (mTapPos = 0) {
348 // open both
349 SPDLOG_LOGGER_INFO(mSLog,
350 "Time: {}"
351 "Tap Position: 0. Open both elements",
352 time);
353 mSubInductorSwitch->open();
354 mSubCapacitorSwitch->open();
355 }
356 }
357 } else {
358 // increase counter
360 }
361 } else {
362 // reset counter
363 **mViolationCounter = 0;
364 }
365
366 // save states
367 mPrevVoltage = V;
368 **mVmeasPrev = Vmeas;
369}
370
372 // set switches according to current mode of svc
373 if (mInductiveMode) {
374 if (!mSubInductorSwitch->mnaIsClosed()) {
375 SPDLOG_LOGGER_INFO(mSLog, "Inductive Mode: Closed Inductor Switch");
376 mSubInductorSwitch->close();
377 }
378 if (mSubCapacitorSwitch->mnaIsClosed()) {
379 mSubCapacitorSwitch->open();
380 SPDLOG_LOGGER_INFO(mSLog, "Inductive Mode: Opened Capacitor Switch");
381 }
382 } else {
383 if (mSubInductorSwitch->mnaIsClosed()) {
384 mSubInductorSwitch->open();
385 SPDLOG_LOGGER_INFO(mSLog, "Capacitive Mode: Openend Inductor Switch");
386 }
387 if (!mSubCapacitorSwitch->mnaIsClosed()) {
388 mSubCapacitorSwitch->close();
389 SPDLOG_LOGGER_INFO(mSLog, "Capacitive Mode: Closed Capcitor Switch");
390 }
391 }
392}
std::vector< Ptr > List
Definition Attribute.h:123
AttributePointer< Attribute< T > > Ptr
Definition Attribute.h:250
Attribute< Real >::Ptr mDeltaV
Real mTr
Time Constant.
Attribute< Real >::Ptr mBPrev
Real mBMax
Maximium susceptance [p.u.].
Real mBN
rated B [S]
Attribute< Real >::Ptr mViolationCounter
Real mNomVolt
Nominal Voltage.
Real mBMin
Minimium susceptance [p.u.].
Real mRefVolt
Reference Voltage.
Real mQN
maximum Q
void addMNASubComponent(typename SimPowerComp< Complex >::Ptr subc, MNA_SUBCOMP_TASK_ORDER preStepOrder, MNA_SUBCOMP_TASK_ORDER postStepOrder, Bool contributeToRightVector)
void mnaCompApplyRightSideVectorStamp(Matrix &rightVector) override
CompositePowerComp(String uid, String name, Bool hasPreStep, Bool hasPostStep, Logger::Level logLevel)
void initializeParentFromNodesAndTerminals(Real frequency) override
Initializes states from power flow data (parent-specific part).
void mnaParentPostStep(Real time, Int timeStepCount, Attribute< Matrix >::Ptr &leftVector) override
MNA post step operations (parent-specific)
void mnaCompUpdateCurrent(const Matrix &leftVector) override
Update interface current from MNA system results.
const Attribute< Real >::Ptr mVpcc
Definition DP_Ph1_SVC.h:66
void createSubComponents() override
Constructs subcomponents; idempotent.
std::shared_ptr< DP::Ph1::Capacitor > mSubCapacitor
Internal capacitor.
Definition DP_Ph1_SVC.h:38
std::shared_ptr< DP::Ph1::Switch > mSubCapacitorSwitch
Definition DP_Ph1_SVC.h:39
void mnaCompUpdateVoltage(const Matrix &leftVector) override
Update interface voltage from MNA system results.
const Attribute< Real >::Ptr mVmeasPrev
Definition DP_Ph1_SVC.h:67
void mechanicalModelUpdateSusceptance(Real time)
void checkProtection(Real time)
std::shared_ptr< DP::Ph1::Inductor > mSubInductor
Internal inductor.
Definition DP_Ph1_SVC.h:35
void mnaParentAddPostStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, Attribute< Matrix >::Ptr &leftVector) override
add MNA post step dependencies (parent-specific)
void mnaParentPreStep(Real time, Int timeStepCount) override
MNA pre step operations (parent-specific)
std::shared_ptr< DP::Ph1::Switch > mSubInductorSwitch
Definition DP_Ph1_SVC.h:36
SVC(String uid, String name, Logger::Level logLevel=Logger::Level::off)
Defines UID, name and log level.
void mnaParentAddPreStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes) override
add MNA pre step dependencies (parent-specific)
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 phasorToString(const Complex &num)
Definition Logger.cpp:57
Attribute< Matrix >::Ptr mRightVector
static Complex complexFromVectorElement(const Matrix &mat, Matrix::Index row, Int maxFreq=1, Int freqIdx=0)
Definition MathUtils.cpp:94
static Real abs(Complex value)
Definition MathUtils.cpp:27
UInt matrixNodeIndex(UInt nodeIndex)
const Attribute< MatrixVar< Complex > >::Ptr mIntfCurrent
SimTerminal< Complex >::List mTerminals
const Attribute< MatrixVar< Complex > >::Ptr mIntfVoltage
SimNode< Complex >::List mVirtualNodes
Complex initialSingleVoltage(UInt index)
Logger::Level mLogLevel
Component logger control for internal variables.
Logger::Log mSLog
Component logger.
#define PI
Definition Definitions.h:43
#define M_PI
Definition Definitions.h:41
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