EMT_Ph3_Transformer.cpp 13.5 KB
Newer Older
1
2
/* Copyright 2017-2020 Institute for Automation of Complex Power Systems,
 *                     EONERC, RWTH Aachen University
Markus Mirz's avatar
Markus Mirz committed
3
 *
4
5
6
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
Markus Mirz's avatar
Markus Mirz committed
7
8
9
10
11
12
13
 *********************************************************************************/

#include <cps/EMT/EMT_Ph3_Transformer.h>

using namespace CPS;

EMT::Ph3::Transformer::Transformer(String uid, String name,
14
	Logger::Level logLevel, Bool withResistiveLosses)
15
	: SimPowerComp<Real>(uid, name, logLevel) {
Markus Mirz's avatar
Markus Mirz committed
16
	mPhaseType = PhaseType::ABC;
17
	if (withResistiveLosses)
18
19
20
21
		setVirtualNodeNumber(3);
	else
		setVirtualNodeNumber(2);

Markus Mirz's avatar
Markus Mirz committed
22
	setTerminalNumber(2);
23
24

	mSLog->info("Create {} {}", this->type(), name);
Markus Mirz's avatar
Markus Mirz committed
25
26
27
28
29
30
	mIntfVoltage = Matrix::Zero(3, 1);
	mIntfCurrent = Matrix::Zero(1, 1);

	addAttribute<Complex>("ratio", &mRatio, Flags::write | Flags::read);
	addAttribute<Matrix>("R", &mResistance, Flags::write | Flags::read);
	addAttribute<Matrix>("L", &mInductance, Flags::write | Flags::read);
31
	addAttribute<Matrix>("Rsnubber", &mSnubberResistance, Flags::write | Flags::read);
Markus Mirz's avatar
Markus Mirz committed
32
33
}

Markus Mirz's avatar
Markus Mirz committed
34
SimPowerComp<Real>::Ptr EMT::Ph3::Transformer::clone(String name) {
Markus Mirz's avatar
Markus Mirz committed
35
36
37
38
39
40
41
42
43
	auto copy = Transformer::make(name, mLogLevel);
	copy->setParameters(std::abs(mRatio), std::arg(mRatio), mResistance, mInductance);
	return copy;
}

void EMT::Ph3::Transformer::setParameters(Real ratioAbs, Real ratioPhase,
	Matrix resistance, Matrix inductance) {
	Base::Ph3::Transformer::setParameters(ratioAbs, ratioPhase, resistance, inductance);

44
45
	mSLog->info("Resistance={} [Ohm] Inductance={} [Ohm] (referred to primary side)", resistance, inductance);
    mSLog->info("Tap Ratio={} [ ] Phase Shift={} [deg]", ratioAbs, ratioPhase);
46
	mParametersSet = true;
Markus Mirz's avatar
Markus Mirz committed
47
48
}

Markus Mirz's avatar
Markus Mirz committed
49
void EMT::Ph3::Transformer::initializeFromNodesAndTerminals(Real frequency) {
Markus Mirz's avatar
Markus Mirz committed
50
51
52
53
54

	// Component parameters are referred to high voltage side.
	// Switch terminals if transformer is connected the other way around.
	if (Math::abs(mRatio) < 1.) {
		mRatio = 1. / mRatio;
Markus Mirz's avatar
Markus Mirz committed
55
		std::shared_ptr<SimTerminal<Real>> tmp = mTerminals[0];
Markus Mirz's avatar
Markus Mirz committed
56
57
58
59
60
61
62
63
64
65
66
67
68
69
		mTerminals[0] = mTerminals[1];
		mTerminals[1] = tmp;
	}

	// Set initial voltage of virtual node in between
	mVirtualNodes[0]->setInitialVoltage(initialSingleVoltage(1) * mRatio);

	// Static calculations from load flow data
	Real omega = 2. * PI * frequency;
	MatrixComp impedance = MatrixComp::Zero(3, 3);
	impedance <<
		Complex(mResistance(0, 0), omega * mInductance(0, 0)), Complex(mResistance(0, 1), omega * mInductance(0, 1)), Complex(mResistance(0, 2), omega * mInductance(0, 2)),
		Complex(mResistance(1, 0), omega * mInductance(1, 0)), Complex(mResistance(1, 1), omega * mInductance(1, 1)), Complex(mResistance(1, 2), omega * mInductance(1, 2)),
		Complex(mResistance(2, 0), omega * mInductance(2, 0)), Complex(mResistance(2, 1), omega * mInductance(2, 1)), Complex(mResistance(2, 2), omega * mInductance(2, 2));
70
	mSLog->info("Reactance={} [Ohm] (referred to primary side)", Logger::matrixToString(omega * mInductance));
Markus Mirz's avatar
Markus Mirz committed
71
72

	MatrixComp vInitABC = MatrixComp::Zero(3, 1);
73
	vInitABC(0, 0) = mVirtualNodes[0]->initialSingleVoltage() - RMS3PH_TO_PEAK1PH * initialSingleVoltage(0);
Markus Mirz's avatar
Markus Mirz committed
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
	vInitABC(1, 0) = vInitABC(0, 0) * SHIFT_TO_PHASE_B;
	vInitABC(2, 0) = vInitABC(0, 0) * SHIFT_TO_PHASE_C;

	MatrixComp iInit = impedance.inverse() * vInitABC;
	mIntfCurrent = iInit.real();
	mIntfVoltage = vInitABC.real();

	// Create series sub components
	mSubInductor = std::make_shared<EMT::Ph3::Inductor>(mName + "_ind", mLogLevel);
	mSubInductor->setParameters(mInductance);

	if (mNumVirtualNodes == 3) {
		mVirtualNodes[2]->setInitialVoltage(initialSingleVoltage(0));
		mSubResistor = std::make_shared<EMT::Ph3::Resistor>(mName + "_res", mLogLevel);
		mSubResistor->setParameters(mResistance);
		mSubResistor->connect({ node(0), mVirtualNodes[2] });
		mSubResistor->initialize(mFrequencies);
Markus Mirz's avatar
Markus Mirz committed
91
		mSubResistor->initializeFromNodesAndTerminals(frequency);
Markus Mirz's avatar
Markus Mirz committed
92
93
94
95
96
97
		mSubInductor->connect({ mVirtualNodes[2], mVirtualNodes[0] });
	}
	else {
		mSubInductor->connect({ node(0), mVirtualNodes[0] });
	}
	mSubInductor->initialize(mFrequencies);
Markus Mirz's avatar
Markus Mirz committed
98
	mSubInductor->initializeFromNodesAndTerminals(frequency);
Markus Mirz's avatar
Markus Mirz committed
99
100

	// Create parallel sub components
101
102
	// A snubber conductance is added on the low voltage side (resistance approximately scaled with LV side voltage)
	mSnubberResistance = Matrix::Identity(3,3)*std::abs(node(1)->initialSingleVoltage())*1e6;
Markus Mirz's avatar
Markus Mirz committed
103
	mSubSnubResistor = std::make_shared<EMT::Ph3::Resistor>(mName + "_snub_res", mLogLevel);
104
	mSubSnubResistor->setParameters(mSnubberResistance);
Markus Mirz's avatar
Markus Mirz committed
105
	mSubSnubResistor->connect({ node(1), EMT::SimNode::GND });
Markus Mirz's avatar
Markus Mirz committed
106
	mSubSnubResistor->initialize(mFrequencies);
Markus Mirz's avatar
Markus Mirz committed
107
	mSubSnubResistor->initializeFromNodesAndTerminals(frequency);
108
	mSLog->info("Snubber Resistance={} [Ohm] (connected to LV side)", Logger::matrixToString(mSnubberResistance));
Markus Mirz's avatar
Markus Mirz committed
109
110
111
112
113
114
115
116
117
118
119

	mSLog->info(
		"\n--- Initialization from powerflow ---"
		"\nVoltage across: {:s}"
		"\nCurrent: {:s}"
		"\nTerminal 0 voltage: {:s}"
		"\nTerminal 1 voltage: {:s}"
		"\nVirtual Node 1 voltage: {:s}"
		"\n--- Initialization from powerflow finished ---",
		Logger::matrixToString(mIntfVoltage),
		Logger::matrixToString(mIntfCurrent),
120
121
		Logger::phasorToString(RMS3PH_TO_PEAK1PH * initialSingleVoltage(0)),
		Logger::phasorToString(RMS3PH_TO_PEAK1PH * initialSingleVoltage(1)),
122
		Logger::phasorToString(RMS3PH_TO_PEAK1PH * mVirtualNodes[0]->initialSingleVoltage()));
Markus Mirz's avatar
Markus Mirz committed
123
124
125
126
}

void EMT::Ph3::Transformer::mnaInitialize(Real omega, Real timeStep, Attribute<Matrix>::Ptr leftVector) {
	MNAInterface::mnaInitialize(omega, timeStep);
Markus Mirz's avatar
Markus Mirz committed
127
	updateMatrixNodeIndices();
Markus Mirz's avatar
Markus Mirz committed
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144

	mRightVector = Matrix::Zero(leftVector->get().rows(), 1);
	auto subComponents = MNAInterface::List({ mSubInductor, mSubSnubResistor });
	if (mSubResistor)
		subComponents.push_back(mSubResistor);
	for (auto comp : subComponents) {
		comp->mnaInitialize(omega, timeStep, leftVector);
		for (auto task : comp->mnaTasks()) {
			mMnaTasks.push_back(task);
		}
	}
	mMnaTasks.push_back(std::make_shared<MnaPreStep>(*this));
	mMnaTasks.push_back(std::make_shared<MnaPostStep>(*this, leftVector));

	mSLog->info(
		"\nTerminal 0 connected to {:s} = sim node {:d}"
		"\nTerminal 1 connected to {:s} = sim node {:d}",
Markus Mirz's avatar
Markus Mirz committed
145
146
		mTerminals[0]->node()->name(), mTerminals[0]->node()->matrixNodeIndex(),
		mTerminals[1]->node()->name(), mTerminals[1]->node()->matrixNodeIndex());
Markus Mirz's avatar
Markus Mirz committed
147
148
149
150
151
}

void EMT::Ph3::Transformer::mnaApplySystemMatrixStamp(Matrix& systemMatrix) {
	// Ideal transformer equations
	if (terminalNotGrounded(0)) {
Markus Mirz's avatar
Markus Mirz committed
152
153
154
		Math::setMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(PhaseType::A), mVirtualNodes[1]->matrixNodeIndex(PhaseType::A), -1.);
		Math::setMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(PhaseType::B), mVirtualNodes[1]->matrixNodeIndex(PhaseType::B), -1.);
		Math::setMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(PhaseType::C), mVirtualNodes[1]->matrixNodeIndex(PhaseType::C), -1.);
Markus Mirz's avatar
Markus Mirz committed
155

Markus Mirz's avatar
Markus Mirz committed
156
157
158
		Math::setMatrixElement(systemMatrix, mVirtualNodes[1]->matrixNodeIndex(PhaseType::A), mVirtualNodes[0]->matrixNodeIndex(PhaseType::A), 1.);
		Math::setMatrixElement(systemMatrix, mVirtualNodes[1]->matrixNodeIndex(PhaseType::B), mVirtualNodes[0]->matrixNodeIndex(PhaseType::B), 1.);
		Math::setMatrixElement(systemMatrix, mVirtualNodes[1]->matrixNodeIndex(PhaseType::C), mVirtualNodes[0]->matrixNodeIndex(PhaseType::C), 1.);
Markus Mirz's avatar
Markus Mirz committed
159
160
161

	}
	if (terminalNotGrounded(1)) {
Markus Mirz's avatar
Markus Mirz committed
162
163
164
165
166
167
		Math::setMatrixElement(systemMatrix, matrixNodeIndex(1, 0), mVirtualNodes[1]->matrixNodeIndex(PhaseType::A), mRatio.real());
		Math::setMatrixElement(systemMatrix, matrixNodeIndex(1, 1), mVirtualNodes[1]->matrixNodeIndex(PhaseType::B), mRatio.real());
		Math::setMatrixElement(systemMatrix, matrixNodeIndex(1, 2), mVirtualNodes[1]->matrixNodeIndex(PhaseType::C), mRatio.real());
		Math::setMatrixElement(systemMatrix, mVirtualNodes[1]->matrixNodeIndex(PhaseType::A), matrixNodeIndex(1, 0), -mRatio.real());
		Math::setMatrixElement(systemMatrix, mVirtualNodes[1]->matrixNodeIndex(PhaseType::B), matrixNodeIndex(1, 1), -mRatio.real());
		Math::setMatrixElement(systemMatrix, mVirtualNodes[1]->matrixNodeIndex(PhaseType::C), matrixNodeIndex(1, 2), -mRatio.real());
Markus Mirz's avatar
Markus Mirz committed
168
169
170
171
172
173
174
175
176
177
178
179
	}

	// Add inductive part to system matrix
	mSubInductor->mnaApplySystemMatrixStamp(systemMatrix);
	mSubSnubResistor->mnaApplySystemMatrixStamp(systemMatrix);

	if (mNumVirtualNodes == 3) {
		mSubResistor->mnaApplySystemMatrixStamp(systemMatrix);
	}

	if (terminalNotGrounded(0)) {
		mSLog->info("Add {:s} to system at ({:d},{:d})", Logger::complexToString(Complex(-1.0, 0)),
Markus Mirz's avatar
Markus Mirz committed
180
			mVirtualNodes[0]->matrixNodeIndex(PhaseType::A), mVirtualNodes[1]->matrixNodeIndex(PhaseType::A));
Markus Mirz's avatar
Markus Mirz committed
181
		mSLog->info("Add {:s} to system at ({:d},{:d})", Logger::complexToString(Complex(-1.0, 0)),
Markus Mirz's avatar
Markus Mirz committed
182
			mVirtualNodes[0]->matrixNodeIndex(PhaseType::B), mVirtualNodes[1]->matrixNodeIndex(PhaseType::B));
Markus Mirz's avatar
Markus Mirz committed
183
		mSLog->info("Add {:s} to system at ({:d},{:d})", Logger::complexToString(Complex(-1.0, 0)),
Markus Mirz's avatar
Markus Mirz committed
184
			mVirtualNodes[0]->matrixNodeIndex(PhaseType::C), mVirtualNodes[1]->matrixNodeIndex(PhaseType::C));
Markus Mirz's avatar
Markus Mirz committed
185
186

		mSLog->info("Add {:s} to system at ({:d},{:d})", Logger::complexToString(Complex(1.0, 0)),
Markus Mirz's avatar
Markus Mirz committed
187
			mVirtualNodes[1]->matrixNodeIndex(PhaseType::A), mVirtualNodes[0]->matrixNodeIndex(PhaseType::A));
Markus Mirz's avatar
Markus Mirz committed
188
		mSLog->info("Add {:s} to system at ({:d},{:d})", Logger::complexToString(Complex(1.0, 0)),
Markus Mirz's avatar
Markus Mirz committed
189
			mVirtualNodes[1]->matrixNodeIndex(PhaseType::B), mVirtualNodes[0]->matrixNodeIndex(PhaseType::B));
Markus Mirz's avatar
Markus Mirz committed
190
		mSLog->info("Add {:s} to system at ({:d},{:d})", Logger::complexToString(Complex(1.0, 0)),
Markus Mirz's avatar
Markus Mirz committed
191
			mVirtualNodes[1]->matrixNodeIndex(PhaseType::C), mVirtualNodes[0]->matrixNodeIndex(PhaseType::C));
Markus Mirz's avatar
Markus Mirz committed
192
193
194
	}
	if (terminalNotGrounded(1)) {
		mSLog->info("Add {:s} to system at ({:d},{:d})", Logger::complexToString(mRatio),
Markus Mirz's avatar
Markus Mirz committed
195
			matrixNodeIndex(1, 0), mVirtualNodes[1]->matrixNodeIndex(PhaseType::A));
Markus Mirz's avatar
Markus Mirz committed
196
		mSLog->info("Add {:s} to system at ({:d},{:d})", Logger::complexToString(mRatio),
Markus Mirz's avatar
Markus Mirz committed
197
			matrixNodeIndex(1, 1), mVirtualNodes[1]->matrixNodeIndex(PhaseType::B));
Markus Mirz's avatar
Markus Mirz committed
198
		mSLog->info("Add {:s} to system at ({:d},{:d})", Logger::complexToString(mRatio),
Markus Mirz's avatar
Markus Mirz committed
199
			matrixNodeIndex(1, 2), mVirtualNodes[1]->matrixNodeIndex(PhaseType::C));
Markus Mirz's avatar
Markus Mirz committed
200
201

		mSLog->info("Add {:s} to system at ({:d},{:d})", Logger::complexToString(-mRatio),
Markus Mirz's avatar
Markus Mirz committed
202
			mVirtualNodes[1]->matrixNodeIndex(PhaseType::A), matrixNodeIndex(1, 0));
Markus Mirz's avatar
Markus Mirz committed
203
		mSLog->info("Add {:s} to system at ({:d},{:d})", Logger::complexToString(-mRatio),
Markus Mirz's avatar
Markus Mirz committed
204
			mVirtualNodes[1]->matrixNodeIndex(PhaseType::B), matrixNodeIndex(1, 1));
Markus Mirz's avatar
Markus Mirz committed
205
		mSLog->info("Add {:s} to system at ({:d},{:d})", Logger::complexToString(-mRatio),
Markus Mirz's avatar
Markus Mirz committed
206
			mVirtualNodes[1]->matrixNodeIndex(PhaseType::C), matrixNodeIndex(1, 2));
Markus Mirz's avatar
Markus Mirz committed
207
208
209
210
211
212
213
	}
}

void EMT::Ph3::Transformer::mnaApplyRightSideVectorStamp(Matrix& rightVector) {
	mSubInductor->mnaApplyRightSideVectorStamp(rightVector);
}

214
215
216
217
218
219
220
void EMT::Ph3::Transformer::mnaAddPreStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes) {
	// add pre-step dependencies of subcomponents
	mSubInductor->mnaAddPreStepDependencies(prevStepDependencies, attributeDependencies, modifiedAttributes);
	// add pre-step dependencies of component itself
	prevStepDependencies.push_back(attribute("i_intf"));
	prevStepDependencies.push_back(attribute("v_intf"));
	modifiedAttributes.push_back(attribute("right_vector"));
Markus Mirz's avatar
Markus Mirz committed
221
222
}

223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
void EMT::Ph3::Transformer::mnaPreStep(Real time, Int timeStepCount) {	
	// pre-step of subcomponents
	mSubInductor->mnaPreStep(time, timeStepCount);
	// pre-step of component itself
	mnaApplyRightSideVectorStamp(mRightVector);
}

void EMT::Ph3::Transformer::mnaAddPostStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, Attribute<Matrix>::Ptr &leftVector) {
	// add post-step dependencies of subcomponents
	if (mSubResistor)
		mSubResistor->mnaAddPostStepDependencies(prevStepDependencies, attributeDependencies, modifiedAttributes, leftVector);
	mSubInductor->mnaAddPostStepDependencies(prevStepDependencies, attributeDependencies, modifiedAttributes, leftVector);
	mSubSnubResistor->mnaAddPostStepDependencies(prevStepDependencies, attributeDependencies, modifiedAttributes, leftVector);
	// add post-step dependencies of component itself
	attributeDependencies.push_back(leftVector);
	modifiedAttributes.push_back(attribute("v_intf"));
	modifiedAttributes.push_back(attribute("i_intf"));
}

void EMT::Ph3::Transformer::mnaPostStep(Real time, Int timeStepCount, Attribute<Matrix>::Ptr &leftVector) {
	// post-step of subcomponents
	if (mSubResistor)
		mSubResistor->mnaPostStep(time, timeStepCount, leftVector);
	mSubInductor->mnaPostStep(time, timeStepCount, leftVector);
	mSubSnubResistor->mnaPostStep(time, timeStepCount, leftVector);
	// post-step of component itself
	mnaUpdateVoltage(*leftVector);
	mnaUpdateCurrent(*leftVector);
Markus Mirz's avatar
Markus Mirz committed
251
252
253
254
255
256
257
258
259
260
}

void EMT::Ph3::Transformer::mnaUpdateCurrent(const Matrix& leftVector) {
	mIntfCurrent = mSubInductor->intfCurrent();
}

void EMT::Ph3::Transformer::mnaUpdateVoltage(const Matrix& leftVector) {
	// v1 - v0
	mIntfVoltage = Matrix::Zero(3, 1);
	if (terminalNotGrounded(1)) {
Markus Mirz's avatar
Markus Mirz committed
261
262
263
		mIntfVoltage(0, 0) = Math::realFromVectorElement(leftVector, matrixNodeIndex(1, 0));
		mIntfVoltage(1, 0) = Math::realFromVectorElement(leftVector, matrixNodeIndex(1, 1));
		mIntfVoltage(2, 0) = Math::realFromVectorElement(leftVector, matrixNodeIndex(1, 2));
Markus Mirz's avatar
Markus Mirz committed
264
265
	}
	if (terminalNotGrounded(0)) {
Markus Mirz's avatar
Markus Mirz committed
266
267
268
		mIntfVoltage(0, 0) = mIntfVoltage(0, 0) - Math::realFromVectorElement(leftVector, matrixNodeIndex(0, 0));
		mIntfVoltage(1, 0) = mIntfVoltage(1, 0) - Math::realFromVectorElement(leftVector, matrixNodeIndex(0, 1));
		mIntfVoltage(2, 0) = mIntfVoltage(2, 0) - Math::realFromVectorElement(leftVector, matrixNodeIndex(0, 2));
Markus Mirz's avatar
Markus Mirz committed
269
270
271
	}
}