DPsim
DP_Ph1_SVC.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/DP/DP_Ph1_SVC.h>
10 
11 using namespace CPS;
12 
13 DP::Ph1::SVC::SVC(String uid, String name, Logger::Level logLevel)
14  : MNASimPowerComp<Complex>(uid, name, true, true, logLevel),
15  mVpcc(mAttributes->create<Real>("Vpcc", 0)),
16  mVmeasPrev(mAttributes->create<Real>("Vmeas", 0)) {
17  setTerminalNumber(1);
18  setVirtualNodeNumber(2);
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 
27 Bool DP::Ph1::SVC::ValueChanged() { return mValueChange; }
28 
30 
31  // initial state is both switches are open
32  Real omega = 2. * PI * frequency;
33  // init L and C with small/high values (both have high impedance)
34  Real LInit = 1e6 / omega;
35  Real CInit = 1e-6 / omega;
36  mLPrev = LInit;
37  mCPrev = CInit;
38 
39  // impedances of both branches
40  Complex LImpedance = {mSwitchROpen, omega * LInit};
41  Complex CImpedance = {mSwitchROpen, -1 / (omega * CInit)};
42  Complex impedance = LImpedance * CImpedance / (LImpedance + CImpedance);
43 
44  (**mIntfVoltage)(0, 0) = initialSingleVoltage(0);
45  (**mIntfCurrent)(0, 0) = (**mIntfVoltage)(0, 0) / impedance;
46 
47  **mBPrev = 0;
48  mPrevVoltage = (**mIntfVoltage)(0, 0).real();
49  **mVmeasPrev = mPrevVoltage;
50 
51  if (mMechMode) {
52  SPDLOG_LOGGER_INFO(mSLog, "Using Mechanical Model");
53  }
54 
55  SPDLOG_LOGGER_INFO(mSLog,
56  "\n --- Parameters ---"
57  "\n Controller: T = {} K = {}"
58  "\n Reference Voltage {} [kV]"
59  "\n Qmax = {} [var] -> BN = {} [S]"
60  "\n Bmax = {} Bmin = {} [p.u.]"
61  "\n Initial B: {}",
62  mTr, mKr, mRefVolt, mQN, mBN, mBMax, mBMin, **mBPrev);
63 
64  // set voltages at virtual nodes
65  Complex VLSwitch =
66  (**mIntfVoltage)(0, 0) - LImpedance * (**mIntfCurrent)(0, 0);
67  mVirtualNodes[0]->setInitialVoltage(VLSwitch);
68  Complex VCSwitch =
69  (**mIntfVoltage)(0, 0) - CImpedance * (**mIntfCurrent)(0, 0);
70  mVirtualNodes[1]->setInitialVoltage(VCSwitch);
71 
72  // create elements
73  // Inductor with Switch
74  mSubInductor =
75  std::make_shared<DP::Ph1::Inductor>(**mName + "_ind", mLogLevel);
76  mSubInductor->setParameters(LInit);
77  mSubInductor->connect({SimNode::GND, mVirtualNodes[0]});
78  mSubInductor->initialize(mFrequencies);
79  mSubInductor->initializeFromNodesAndTerminals(frequency);
80 
81  mSubInductorSwitch =
82  std::make_shared<DP::Ph1::Switch>(**mName + "_Lswitch", mLogLevel);
83  mSubInductorSwitch->setParameters(mSwitchROpen, mSwitchRClosed, false);
84  mSubInductorSwitch->connect({mVirtualNodes[0], mTerminals[0]->node()});
85  mSubInductorSwitch->initialize(mFrequencies);
86  mSubInductorSwitch->initializeFromNodesAndTerminals(frequency);
87 
88  // Capacitor with Switch
89  mSubCapacitor =
90  std::make_shared<DP::Ph1::Capacitor>(**mName + "_cap", mLogLevel);
91  mSubCapacitor->setParameters(CInit);
92  mSubCapacitor->connect({SimNode::GND, mVirtualNodes[1]});
93  mSubCapacitor->initialize(mFrequencies);
94  mSubCapacitor->initializeFromNodesAndTerminals(frequency);
95 
96  mSubCapacitorSwitch =
97  std::make_shared<DP::Ph1::Switch>(**mName + "_Cswitch", mLogLevel);
98  mSubCapacitorSwitch->setParameters(mSwitchROpen, mSwitchRClosed, false);
99  mSubCapacitorSwitch->connect({mVirtualNodes[1], mTerminals[0]->node()});
100  mSubCapacitorSwitch->initialize(mFrequencies);
101  mSubCapacitorSwitch->initializeFromNodesAndTerminals(frequency);
102 
103  SPDLOG_LOGGER_INFO(mSLog,
104  "\n--- Initialization from powerflow ---"
105  "\nImpedance: {}"
106  "\nVoltage across: {:s}"
107  "\nCurrent: {:s}"
108  "\nTerminal 0 voltage: {:s}"
109  "\n--- Initialization from powerflow finished ---",
110  impedance, Logger::phasorToString((**mIntfVoltage)(0, 0)),
111  Logger::phasorToString((**mIntfCurrent)(0, 0)),
112  Logger::phasorToString(initialSingleVoltage(0)));
113 }
114 
115 // #### MNA functions ####
116 
117 void DP::Ph1::SVC::mnaCompInitialize(Real omega, Real timeStep,
118  Attribute<Matrix>::Ptr leftVector) {
119  updateMatrixNodeIndices();
120 
121  SPDLOG_LOGGER_INFO(mSLog, "\nTerminal 0 connected to {:s} = sim node {:d}",
122  mTerminals[0]->node()->name(),
123  mTerminals[0]->node()->matrixNodeIndex());
124 
125  mSubInductor->mnaInitialize(omega, timeStep, leftVector);
126  mRightVectorStamps.push_back(
127  &mSubInductor->attributeTyped<Matrix>("right_vector")->get());
128 
129  mSubInductorSwitch->mnaInitialize(omega, timeStep, leftVector);
130  mRighteVctorStamps.push_back(
131  &mSubInductorSwitch->attributeTyped<Matrix>("right_vector")->get());
132 
133  mSubCapacitor->mnaInitialize(omega, timeStep, leftVector);
134  mRightVectorStamps.push_back(
135  &mSubCapacitor->attributeTyped<Matrix>("right_vector")->get());
136 
137  mSubCapacitorSwitch->mnaInitialize(omega, timeStep, leftVector);
138  mRightVectorStamps.push_back(
139  &mSubCapacitorSwitch->attributeTyped<Matrix>("right_vector")->get());
140 }
141 
143  SparseMatrixRow &systemMatrix) {
144  mSubInductor->mnaApplySystemMatrixStamp(systemMatrix);
145  mSubCapacitor->mnaApplySystemMatrixStamp(systemMatrix);
146  mSubCapacitorSwitch->mnaApplySystemMatrixStamp(systemMatrix);
147  mSubInductorSwitch->mnaApplySystemMatrixStamp(systemMatrix);
148 }
149 
151  mSubInductor->mnaApplyRightSideVectorStamp(rightVector);
152  mSubCapacitor->mnaApplyRightSideVectorStamp(rightVector);
153  mSubCapacitorSwitch->mnaApplyRightSideVectorStamp(rightVector);
154  mSubInductorSwitch->mnaApplyRightSideVectorStamp(rightVector);
155 }
156 
158  AttributeBase::List &prevStepDependencies,
159  AttributeBase::List &attributeDependencies,
160  AttributeBase::List &modifiedAttributes) {
161  // add pre-step dependencies of subcomponents
162  mSubInductor->mnaAddPreStepDependencies(
163  prevStepDependencies, attributeDependencies, modifiedAttributes);
164  mSubInductorSwitch->mnaAddPreStepDependencies(
165  prevStepDependencies, attributeDependencies, modifiedAttributes);
166  mSubCapacitor->mnaAddPreStepDependencies(
167  prevStepDependencies, attributeDependencies, modifiedAttributes);
168  mSubCapacitorSwitch->mnaAddPreStepDependencies(
169  prevStepDependencies, attributeDependencies, modifiedAttributes);
170 
171  // add pre-step dependencies of component itself
172  modifiedAttributes.push_back(mRightVector);
173 }
174 
175 void DP::Ph1::SVC::mnaCompPreStep(Real time, Int timeStepCount) {
176  mSubInductor->mnaPreStep(time, timeStepCount);
177  mSubInductorSwitch->mnaPreStep(time, timeStepCount);
178  mSubCapacitor->mnaPreStep(time, timeStepCount);
179  mSubCapacitorSwitch->mnaPreStep(time, timeStepCount);
180 
181  mnaCompApplyRightSideVectorStamp(**mRightVector);
182 
183  if (time > 0.1 && !mDisconnect) {
184  if (mMechMode) {
185  mechanicalModelUpdateSusceptance(time);
186  } else {
187  updateSusceptance();
188  }
189  checkProtection(time);
190  }
191 }
192 
194  AttributeBase::List &prevStepDependencies,
195  AttributeBase::List &attributeDependencies,
196  AttributeBase::List &modifiedAttributes,
197  Attribute<Matrix>::Ptr &leftVector) {
198  // add post-step dependencies of subcomponents
199  mSubInductor->mnaAddPostStepDependencies(prevStepDependencies,
200  attributeDependencies,
201  modifiedAttributes, leftVector);
202  mSubInductorSwitch->mnaAddPostStepDependencies(
203  prevStepDependencies, attributeDependencies, modifiedAttributes,
204  leftVector);
205  mSubCapacitor->mnaAddPostStepDependencies(prevStepDependencies,
206  attributeDependencies,
207  modifiedAttributes, leftVector);
208  mSubCapacitorSwitch->mnaAddPostStepDependencies(
209  prevStepDependencies, attributeDependencies, modifiedAttributes,
210  leftVector);
211 
212  // add post-step dependencies of component itself
213  attributeDependencies.push_back(leftVector);
214  modifiedAttributes.push_back(mIntfVoltage);
215  modifiedAttributes.push_back(mIntfCurrent);
216 }
217 
218 void DP::Ph1::SVC::mnaCompPostStep(Real time, Int timeStepCount) {
219  mSubInductor->mnaPostStep(time, timeStepCount, leftVector);
220  mSubInductorSwitch->mnaPostStep(time, timeStepCount, leftVector);
221  mSubCapacitor->mnaPostStep(time, timeStepCount, leftVector);
222  mSubCapacitorSwitch->mnaPostStep(time, timeStepCount, leftVector);
223 
224  mnaCompUpdateVoltage(**mLeftVector);
225  mnaCompUpdateCurrent(**mLeftVector);
226 
227  mDeltaT = time - mPrevTimeStep;
228  mPrevTimeStep = time;
229  mValueChange = false;
230 }
231 
232 void DP::Ph1::SVC::mnaCompUpdateVoltage(const Matrix &leftVector) {
233  **mVpcc = Math::complexFromVectorElement(leftVector, matrixNodeIndex(0),
234  mNumFreqs, 0)
235  .real();
236  (**mIntfVoltage)(0, 0) =
237  Math::complexFromVectorElement(leftVector, matrixNodeIndex(0));
238 }
239 
240 void DP::Ph1::SVC::mnaCompUpdateCurrent(const Matrix &leftVector) {
241  (**mIntfCurrent)(0, 0) = 0;
242  (**mIntfCurrent)(0, 0) += mSubInductor->intfCurrent()(0, 0);
243  (**mIntfCurrent)(0, 0) += mSubCapacitor->intfCurrent()(0, 0);
244 }
245 
246 void DP::Ph1::SVC::checkProtection(Real time) {
247  // check states for violation of protection values
248  // get inverse protection curve value (time delay value)
249 
250  Real Vpu = **mVmeasPrev / mNomVolt;
251  if (Vpu > 1.4) {
252  mProtCount1 = mProtCount1 + mDeltaT;
253  if (mProtCount1 > 0.1) {
254  mDisconnect = true;
255  }
256  } else {
257  mProtCount1 = 0;
258  }
259  if (Vpu > 1.25) {
260  mProtCount2 = mProtCount2 + mDeltaT;
261  if (mProtCount2 > 1) {
262  mDisconnect = true;
263  }
264  } else {
265  mProtCount2 = 0;
266  }
267  if (Vpu > 1.15) {
268  mProtCount3 = mProtCount3 + mDeltaT;
269  if (mProtCount3 > 5) {
270  mDisconnect = true;
271  }
272  } else {
273  mProtCount3 = 0;
274  }
275 
276  if (mDisconnect) {
277  SPDLOG_LOGGER_INFO(mSLog, "Disconnect SVC because of overvoltage at {}",
278  time);
279  mSubCapacitorSwitch->open();
280  mSubInductorSwitch->open();
281  mValueChange = true;
282  }
283 }
284 
285 void DP::Ph1::SVC::updateSusceptance() {
286  // calculate new B value
287  // summarize some constants
288  Real Fac1 = mDeltaT / (2 * mTr);
289  Real Fac2 = mDeltaT * mKr / (2 * mTr);
290 
291  Complex vintf = (**mIntfVoltage)(0, 0);
292  Real V = Math::abs((**mIntfVoltage)(0, 0).real());
293 
294  // Pt1 with trapez rule for voltage measurement
295  Real Fac3 = mDeltaT / (2 * mTm);
296  Real Vmeas = (1 / (1 + Fac3)) * (V + mPrevVoltage - **mVmeasPrev);
297 
298  **mDeltaV = (Vmeas - mRefVolt) / mNomVolt;
299  Real deltaVPrev = (**mVmeasPrev - mRefVolt) / mNomVolt;
300 
301  // calc new B with trapezoidal rule
302  //Real B = (1/(1+Fac1)) * (Fac2 * (mDeltaV + deltaVPrev) + (1-Fac1) * mBPrev);
303  Real B = (1 / (1 + Fac1)) *
304  (Fac2 * (**mDeltaV + deltaVPrev) + (1 - Fac1) * **mBPrev);
305  //SPDLOG_LOGGER_INFO(mSLog, "New B value: percent={}, absolute={}", 100 * B, B * mBN);
306 
307  // check bounds
308  if (B > mBMax) {
309  B = mBMax;
310  //SPDLOG_LOGGER_DEBUG(mSLog, "New B value exceeds Bmax");
311  } else if (B < mBMin) {
312  B = mBMin;
313  //SPDLOG_LOGGER_DEBUG(mSLog, "New B value exceeds Bmin");
314  }
315 
316  // set new B if it has a new value and difference is big enough
317  if (B != **mBPrev) {
318  //if (B != mBPrev && mBSetCounter > 0.001){
319  //mValueChange = true;
320  //mBSetCounter = 0;
321  Real omega = 2 * M_PI * mFrequencies(0, 0);
322 
323  if (B > 0) {
324  // model inductive behaviour (decrease voltage)
325  Real inductance = 1 / (omega * B * mBN);
326  //check if change in reactance is sufficient to trigger a change
327  if (Math::abs(1 - inductance / mLPrev) > 0.01) {
328  mInductiveMode = true;
329  mSubInductor->updateInductance(inductance, mDeltaT);
330  //SPDLOG_LOGGER_DEBUG(mSLog, "Inductive Mode: New Inductance: L = {} [H]", inductance);
331  mLPrev = inductance;
332 
333  mValueChange = true;
334  mBSetCounter = 0;
335  }
336  } else {
337  // model capacitive behaviour (increase voltage)
338  Real capacitance = B * mBN / (-omega);
339  //check if change in reactance is sufficient to trigger a change
340  if (Math::abs(1 - capacitance / mCPrev) > 0.01) {
341  mInductiveMode = false;
342  mSubCapacitor->updateCapacitance(capacitance, mDeltaT);
343  //SPDLOG_LOGGER_DEBUG(mSLog, "Capacitive Mode: New Capacitance: C = {} [F]", capacitance);
344  mCPrev = capacitance;
345 
346  mValueChange = true;
347  mBSetCounter = 0;
348  }
349  }
350 
351  // update inductance model
352  setSwitchState();
353  } else {
354  mBSetCounter = mBSetCounter + mDeltaT;
355  }
356 
357  // save values
358  **mBPrev = B;
359  mPrevVoltage = V;
360  **mVmeasPrev = Vmeas;
361 }
362 
363 // model SVC with a mechanical component and discrete
364 void DP::Ph1::SVC::mechanicalModelUpdateSusceptance(Real time) {
365  // current voltage
366  Real V = Math::abs((**mIntfVoltage)(0, 0).real());
367  Real omega = 2 * M_PI * mFrequencies(0, 0);
368 
369  // Pt1 with trapez rule for voltage measurement
370  Real Fac3 = mDeltaT / (2 * mTm);
371  Real Vmeas = (1 / (1 + Fac3)) * (V + mPrevVoltage - **mVmeasPrev);
372 
373  // V diff in pu
374  Real deltaV = (mRefVolt - Vmeas) / mRefVolt;
375 
376  if (Math::abs(deltaV) > mDeadband) {
377  if (**mViolationCounter > mMechSwitchDelay) {
378  // change suszeptance one step
379  if (deltaV > 0 && (mTapPos > mMinPos)) {
380  // undervoltage
381 
382  mTapPos = mTapPos - 1;
383  mTapPos = (mTapPos < mMinPos) ? mMinPos : mTapPos;
384  **mViolationCounter = 0;
385  SPDLOG_LOGGER_INFO(mSLog,
386  "Time: {}"
387  "\nDecreasing Tap. Reason: Undervoltage"
388  "\nNew Tap Position: {}",
389  time, mTapPos);
390  } else if (deltaV < 0 && (mTapPos < mMaxPos)) {
391  // overvoltage
392  mTapPos = mTapPos + 1;
393  mTapPos = (mTapPos > mMaxPos) ? mMaxPos : mTapPos;
394  **mViolationCounter = 0;
395  SPDLOG_LOGGER_INFO(mSLog,
396  "Time: {}"
397  "\nIncreasing Tap. Reason: Overvoltag"
398  "\nNew Tap Position: {}",
399  time, mTapPos);
400  }
401 
402  if (**mViolationCounter == 0) {
403  // new value for suszeptance
404  if (mTapPos > 0) {
405  // inductor is active
406  mInductiveMode = true;
407  Real inductance = 1 / ((mTapPos / mMaxPos) * mBN * omega);
408  SPDLOG_LOGGER_INFO(mSLog, "New inductance: {}", inductance);
409  mSubInductor->updateInductance(inductance, mDeltaT);
410  mValueChange = true;
411  setSwitchState();
412  } else if (mTapPos < 0) {
413  // capacitor is active
414  mInductiveMode = false;
415  Real capacitance = ((mTapPos / mMinPos) * mBN) / omega;
416  SPDLOG_LOGGER_INFO(mSLog, "New capacitance: {}", capacitance);
417  mSubCapacitor->updateCapacitance(capacitance, mDeltaT);
418  mValueChange = true;
419  setSwitchState();
420 
421  } else if (mTapPos = 0) {
422  // open both
423  SPDLOG_LOGGER_INFO(mSLog,
424  "Time: {}"
425  "Tap Position: 0. Open both elements",
426  time);
427  mSubInductorSwitch->open();
428  mSubCapacitorSwitch->open();
429  }
430  }
431  } else {
432  // increase counter
433  **mViolationCounter = **mViolationCounter + mDeltaT;
434  }
435  } else {
436  // reset counter
437  **mViolationCounter = 0;
438  }
439 
440  // save states
441  mPrevVoltage = V;
442  **mVmeasPrev = Vmeas;
443 }
444 
445 void DP::Ph1::SVC::setSwitchState() {
446  // set switches according to current mode of svc
447  if (mInductiveMode) {
448  if (!mSubInductorSwitch->mnaIsClosed()) {
449  SPDLOG_LOGGER_INFO(mSLog, "Inductive Mode: Closed Inductor Switch");
450  mSubInductorSwitch->close();
451  }
452  if (mSubCapacitorSwitch->mnaIsClosed()) {
453  mSubCapacitorSwitch->open();
454  SPDLOG_LOGGER_INFO(mSLog, "Inductive Mode: Opened Capacitor Switch");
455  }
456  } else {
457  if (mSubInductorSwitch->mnaIsClosed()) {
458  mSubInductorSwitch->open();
459  SPDLOG_LOGGER_INFO(mSLog, "Capacitive Mode: Openend Inductor Switch");
460  }
461  if (!mSubCapacitorSwitch->mnaIsClosed()) {
462  mSubCapacitorSwitch->close();
463  SPDLOG_LOGGER_INFO(mSLog, "Capacitive Mode: Closed Capcitor Switch");
464  }
465  }
466 }
void mnaCompApplySystemMatrixStamp(SparseMatrixRow &systemMatrix)
Stamps system matrix.
Definition: DP_Ph1_SVC.cpp:142
void mnaCompUpdateVoltage(const Matrix &leftVector)
Update interface voltage from MNA system results.
Definition: DP_Ph1_SVC.cpp:232
void mnaCompUpdateCurrent(const Matrix &leftVector)
Update interface current from MNA system results.
Definition: DP_Ph1_SVC.cpp:240
void mnaCompAddPostStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, Attribute< Matrix >::Ptr &leftVector)
add MNA post step dependencies
Definition: DP_Ph1_SVC.cpp:193
void mnaCompAddPreStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes)
add MNA pre step dependencies
Definition: DP_Ph1_SVC.cpp:157
void mnaCompApplyRightSideVectorStamp(Matrix &rightVector)
Stamps right side (source) vector.
Definition: DP_Ph1_SVC.cpp:150
void initializeFromNodesAndTerminals(Real frequency)
Initializes states from power flow data.
Definition: DP_Ph1_SVC.cpp:29
void mnaCompPreStep(Real time, Int timeStepCount)
MNA pre step operations.
Definition: DP_Ph1_SVC.cpp:175
void mnaCompPostStep(Real time, Int timeStepCount, Attribute< Matrix >::Ptr &leftVector)
MNA post step operations.
Definition: DP_Ph1_SVC.cpp:218
SVC(String uid, String name, Logger::Level logLevel=Logger::Level::off)
Defines UID, name and log level.
Definition: DP_Ph1_SVC.cpp:13
void mnaCompInitialize(Real omega, Real timeStep, Attribute< Matrix >::Ptr leftVector)
Initializes MNA specific variables.
Definition: DP_Ph1_SVC.cpp:117
AttributeList::Ptr mAttributes
Attribute List.
Base class for all MNA components that are transmitting power.
const Attribute< MatrixVar< Complex > >::Ptr mIntfCurrent
Current through component.
Definition: SimPowerComp.h:47
const Attribute< MatrixVar< Complex > >::Ptr mIntfVoltage
Voltage between terminals.
Definition: SimPowerComp.h:45