EMT_Ph3_Transformer.cpp 11.3 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
	mParametersSet = true;
Markus Mirz's avatar
Markus Mirz committed
45
46
}

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

	// 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
53
		std::shared_ptr<SimTerminal<Real>> tmp = mTerminals[0];
Markus Mirz's avatar
Markus Mirz committed
54
55
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));

	MatrixComp vInitABC = MatrixComp::Zero(3, 1);
70
	vInitABC(0, 0) = mVirtualNodes[0]->initialSingleVoltage() - RMS3PH_TO_PEAK1PH * initialSingleVoltage(0);
Markus Mirz's avatar
Markus Mirz committed
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
	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
88
		mSubResistor->initializeFromNodesAndTerminals(frequency);
Markus Mirz's avatar
Markus Mirz committed
89
90
91
92
93
94
		mSubInductor->connect({ mVirtualNodes[2], mVirtualNodes[0] });
	}
	else {
		mSubInductor->connect({ node(0), mVirtualNodes[0] });
	}
	mSubInductor->initialize(mFrequencies);
Markus Mirz's avatar
Markus Mirz committed
95
	mSubInductor->initializeFromNodesAndTerminals(frequency);
Markus Mirz's avatar
Markus Mirz committed
96
97

	// Create parallel sub components
98
99
	// 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
100
	mSubSnubResistor = std::make_shared<EMT::Ph3::Resistor>(mName + "_snub_res", mLogLevel);
101
	mSubSnubResistor->setParameters(mSnubberResistance);
Markus Mirz's avatar
Markus Mirz committed
102
	mSubSnubResistor->connect({ node(1), EMT::SimNode::GND });
Markus Mirz's avatar
Markus Mirz committed
103
	mSubSnubResistor->initialize(mFrequencies);
Markus Mirz's avatar
Markus Mirz committed
104
	mSubSnubResistor->initializeFromNodesAndTerminals(frequency);
Markus Mirz's avatar
Markus Mirz committed
105
106
107
108
109
110
111
112
113
114
115

	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),
116
117
		Logger::phasorToString(RMS3PH_TO_PEAK1PH * initialSingleVoltage(0)),
		Logger::phasorToString(RMS3PH_TO_PEAK1PH * initialSingleVoltage(1)),
Markus Mirz's avatar
Markus Mirz committed
118
119
120
121
122
		Logger::phasorToString(mVirtualNodes[0]->initialSingleVoltage()));
}

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

	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
141
142
		mTerminals[0]->node()->name(), mTerminals[0]->node()->matrixNodeIndex(),
		mTerminals[1]->node()->name(), mTerminals[1]->node()->matrixNodeIndex());
Markus Mirz's avatar
Markus Mirz committed
143
144
145
146
147
}

void EMT::Ph3::Transformer::mnaApplySystemMatrixStamp(Matrix& systemMatrix) {
	// Ideal transformer equations
	if (terminalNotGrounded(0)) {
Markus Mirz's avatar
Markus Mirz committed
148
149
150
		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
151

Markus Mirz's avatar
Markus Mirz committed
152
153
154
		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
155
156
157

	}
	if (terminalNotGrounded(1)) {
Markus Mirz's avatar
Markus Mirz committed
158
159
160
161
162
163
		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
164
165
166
167
168
169
170
171
172
173
174
175
	}

	// 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
176
			mVirtualNodes[0]->matrixNodeIndex(PhaseType::A), mVirtualNodes[1]->matrixNodeIndex(PhaseType::A));
Markus Mirz's avatar
Markus Mirz committed
177
		mSLog->info("Add {:s} to system at ({:d},{:d})", Logger::complexToString(Complex(-1.0, 0)),
Markus Mirz's avatar
Markus Mirz committed
178
			mVirtualNodes[0]->matrixNodeIndex(PhaseType::B), mVirtualNodes[1]->matrixNodeIndex(PhaseType::B));
Markus Mirz's avatar
Markus Mirz committed
179
		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::C), mVirtualNodes[1]->matrixNodeIndex(PhaseType::C));
Markus Mirz's avatar
Markus Mirz committed
181
182

		mSLog->info("Add {:s} to system at ({:d},{:d})", Logger::complexToString(Complex(1.0, 0)),
Markus Mirz's avatar
Markus Mirz committed
183
			mVirtualNodes[1]->matrixNodeIndex(PhaseType::A), mVirtualNodes[0]->matrixNodeIndex(PhaseType::A));
Markus Mirz's avatar
Markus Mirz committed
184
		mSLog->info("Add {:s} to system at ({:d},{:d})", Logger::complexToString(Complex(1.0, 0)),
Markus Mirz's avatar
Markus Mirz committed
185
			mVirtualNodes[1]->matrixNodeIndex(PhaseType::B), mVirtualNodes[0]->matrixNodeIndex(PhaseType::B));
Markus Mirz's avatar
Markus Mirz committed
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::C), mVirtualNodes[0]->matrixNodeIndex(PhaseType::C));
Markus Mirz's avatar
Markus Mirz committed
188
189
190
	}
	if (terminalNotGrounded(1)) {
		mSLog->info("Add {:s} to system at ({:d},{:d})", Logger::complexToString(mRatio),
Markus Mirz's avatar
Markus Mirz committed
191
			matrixNodeIndex(1, 0), mVirtualNodes[1]->matrixNodeIndex(PhaseType::A));
Markus Mirz's avatar
Markus Mirz committed
192
		mSLog->info("Add {:s} to system at ({:d},{:d})", Logger::complexToString(mRatio),
Markus Mirz's avatar
Markus Mirz committed
193
			matrixNodeIndex(1, 1), mVirtualNodes[1]->matrixNodeIndex(PhaseType::B));
Markus Mirz's avatar
Markus Mirz committed
194
		mSLog->info("Add {:s} to system at ({:d},{:d})", Logger::complexToString(mRatio),
Markus Mirz's avatar
Markus Mirz committed
195
			matrixNodeIndex(1, 2), mVirtualNodes[1]->matrixNodeIndex(PhaseType::C));
Markus Mirz's avatar
Markus Mirz committed
196
197

		mSLog->info("Add {:s} to system at ({:d},{:d})", Logger::complexToString(-mRatio),
Markus Mirz's avatar
Markus Mirz committed
198
			mVirtualNodes[1]->matrixNodeIndex(PhaseType::A), matrixNodeIndex(1, 0));
Markus Mirz's avatar
Markus Mirz committed
199
		mSLog->info("Add {:s} to system at ({:d},{:d})", Logger::complexToString(-mRatio),
Markus Mirz's avatar
Markus Mirz committed
200
			mVirtualNodes[1]->matrixNodeIndex(PhaseType::B), matrixNodeIndex(1, 1));
Markus Mirz's avatar
Markus Mirz committed
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::C), matrixNodeIndex(1, 2));
Markus Mirz's avatar
Markus Mirz committed
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
	}
}

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

void EMT::Ph3::Transformer::MnaPreStep::execute(Real time, Int timeStepCount) {
	mTransformer.mnaApplyRightSideVectorStamp(mTransformer.mRightVector);
}

void EMT::Ph3::Transformer::MnaPostStep::execute(Real time, Int timeStepCount) {
	mTransformer.mnaUpdateVoltage(*mLeftVector);
	mTransformer.mnaUpdateCurrent(*mLeftVector);
}

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
227
228
229
		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
230
231
	}
	if (terminalNotGrounded(0)) {
Markus Mirz's avatar
Markus Mirz committed
232
233
234
		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
235
236
237
	}
}