DPsim
Loading...
Searching...
No Matches
MathUtils.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/MathUtils.h>
10
11using namespace CPS;
12
13// #### Angular Operations ####
14Real Math::radtoDeg(Real rad) { return rad * 180 / PI; }
15
16Real Math::degToRad(Real deg) { return deg * PI / 180; }
17
18Real Math::phase(Complex value) { return std::arg(value); }
19
20Real Math::phaseDeg(Complex value) { return radtoDeg(phase(value)); }
21
22Real Math::abs(Complex value) { return std::abs(value); }
23
24Matrix Math::abs(const MatrixComp &mat) {
25 size_t nRows = mat.rows();
26 size_t nCols = mat.cols();
27 Matrix res(mat.rows(), mat.cols());
28
29 for (size_t i = 0; i < nRows; ++i) {
30 for (size_t j = 0; j < nCols; ++j) {
31 res(i, j) = std::abs(mat(i, j));
32 }
33 }
34 return res;
35}
36
37Matrix Math::phase(const MatrixComp &mat) {
38 size_t nRows = mat.rows();
39 size_t nCols = mat.cols();
40 Matrix res(mat.rows(), mat.cols());
41
42 for (size_t i = 0; i < nRows; ++i) {
43 for (size_t j = 0; j < nCols; ++j) {
44 res(i, j) = std::arg(mat(i, j));
45 }
46 }
47 return res;
48}
49
50Complex Math::polar(Real abs, Real phase) {
51 return std::polar<Real>(abs, phase);
52}
53
54Complex Math::polarDeg(Real abs, Real phase) {
55 return std::polar<Real>(abs, radtoDeg(phase));
56}
57
58void Math::setVectorElement(Matrix &mat, Matrix::Index row, Complex value,
59 Int maxFreq, Int freqIdx, Matrix::Index colOffset) {
60 Eigen::Index harmonicOffset = mat.rows() / maxFreq;
61 Eigen::Index complexOffset = harmonicOffset / 2;
62 Eigen::Index harmRow = row + harmonicOffset * freqIdx;
63
64 mat(harmRow, colOffset) = value.real();
65 mat(harmRow + complexOffset, colOffset) = value.imag();
66}
67
68void Math::addToVectorElement(Matrix &mat, Matrix::Index row, Complex value,
69 Int maxFreq, Int freqIdx) {
70 Eigen::Index harmonicOffset = mat.rows() / maxFreq;
71 Eigen::Index complexOffset = harmonicOffset / 2;
72 Eigen::Index harmRow = row + harmonicOffset * freqIdx;
73
74 mat(harmRow, 0) = mat(harmRow, 0) + value.real();
75 mat(harmRow + complexOffset, 0) =
76 mat(harmRow + complexOffset, 0) + value.imag();
77}
78
79Complex Math::complexFromVectorElement(const Matrix &mat, Matrix::Index row,
80 Int maxFreq, Int freqIdx) {
81 Eigen::Index harmonicOffset = mat.rows() / maxFreq;
82 Eigen::Index complexOffset = harmonicOffset / 2;
83 Eigen::Index harmRow = row + harmonicOffset * freqIdx;
84
85 return Complex(mat(harmRow, 0), mat(harmRow + complexOffset, 0));
86}
87
88void Math::addToVectorElement(Matrix &mat, Matrix::Index row, Real value) {
89 mat(row, 0) = mat(row, 0) + value;
90}
91
92void Math::setVectorElement(Matrix &mat, Matrix::Index row, Real value) {
93 mat(row, 0) = value;
94}
95
96Real Math::realFromVectorElement(const Matrix &mat, Matrix::Index row) {
97 return mat(row, 0);
98}
99
100void Math::setMatrixElement(SparseMatrixRow &mat, Matrix::Index row,
101 Matrix::Index column, Complex value, Int maxFreq,
102 Int freqIdx) {
103 // Assume square matrix
104 Eigen::Index harmonicOffset = mat.rows() / maxFreq;
105 Eigen::Index complexOffset = harmonicOffset / 2;
106 Eigen::Index harmRow = row + harmonicOffset * freqIdx;
107 Eigen::Index harmCol = column + harmonicOffset * freqIdx;
108
109 mat.coeffRef(harmRow, harmCol) = value.real();
110 mat.coeffRef(harmRow + complexOffset, harmCol + complexOffset) = value.real();
111 mat.coeffRef(harmRow, harmCol + complexOffset) = -value.imag();
112 mat.coeffRef(harmRow + complexOffset, harmCol) = value.imag();
113}
114
115void Math::addToMatrixElement(SparseMatrixRow &mat, Matrix::Index row,
116 Matrix::Index column, Complex value, Int maxFreq,
117 Int freqIdx) {
118 // Assume square matrix
119 Eigen::Index harmonicOffset = mat.rows() / maxFreq;
120 Eigen::Index complexOffset = harmonicOffset / 2;
121 Eigen::Index harmRow = row + harmonicOffset * freqIdx;
122 Eigen::Index harmCol = column + harmonicOffset * freqIdx;
123
124 mat.coeffRef(harmRow, harmCol) += value.real();
125 mat.coeffRef(harmRow + complexOffset, harmCol + complexOffset) +=
126 value.real();
127 mat.coeffRef(harmRow, harmCol + complexOffset) -= value.imag();
128 mat.coeffRef(harmRow + complexOffset, harmCol) += value.imag();
129}
130
131void Math::addToMatrixElement(SparseMatrixRow &mat, Matrix::Index row,
132 Matrix::Index column, Matrix value, Int maxFreq,
133 Int freqIdx) {
134 // Assume square matrix
135 Eigen::Index harmonicOffset = mat.rows() / maxFreq;
136 Eigen::Index complexOffset = harmonicOffset / 2;
137 Eigen::Index harmRow = row + harmonicOffset * freqIdx;
138 Eigen::Index harmCol = column + harmonicOffset * freqIdx;
139
140 mat.coeffRef(harmRow, harmCol) += value(0, 0);
141 mat.coeffRef(harmRow + complexOffset, harmCol + complexOffset) += value(1, 1);
142 mat.coeffRef(harmRow, harmCol + complexOffset) += value(0, 1);
143 mat.coeffRef(harmRow + complexOffset, harmCol) += value(1, 0);
144}
145
146void Math::setMatrixElement(SparseMatrixRow &mat, Matrix::Index row,
147 Matrix::Index column, Real value) {
148 mat.coeffRef(row, column) = value;
149}
150
151void Math::addToMatrixElement(SparseMatrixRow &mat, std::vector<UInt> rows,
152 std::vector<UInt> columns, Complex value) {
153 for (UInt phase = 0; phase < rows.size(); phase++)
154 addToMatrixElement(mat, rows[phase], columns[phase], value);
155}
156
157void Math::addToMatrixElement(SparseMatrixRow &mat, Matrix::Index row,
158 Matrix::Index column, Real value) {
159 mat.coeffRef(row, column) = mat.coeff(row, column) + value;
160}
161
162void Math::addToMatrixElement(SparseMatrixRow &mat, std::vector<UInt> rows,
163 std::vector<UInt> columns, Real value) {
164 for (UInt phase = 0; phase < rows.size(); phase++)
165 addToMatrixElement(mat, rows[phase], columns[phase], value);
166}
167
168void Math::invertMatrix(const Matrix &mat, Matrix &matInv) {
169 const Int n = Eigen::internal::convert_index<Int>(mat.cols());
170 if (n == 2) {
171 const Real determinant = mat(0, 0) * mat(1, 1) - mat(0, 1) * mat(1, 0);
172 matInv(0, 0) = mat(1, 1) / determinant;
173 matInv(0, 1) = -mat(0, 1) / determinant;
174 matInv(1, 0) = -mat(1, 0) / determinant;
175 matInv(1, 1) = mat(0, 0) / determinant;
176 } else if (n == 3) {
177 const Real determinant =
178 (mat(0, 0) * mat(1, 1) * mat(2, 2) + mat(0, 1) * mat(1, 2) * mat(2, 0) +
179 mat(1, 0) * mat(2, 1) * mat(0, 2)) -
180 (mat(2, 0) * mat(1, 1) * mat(0, 2) + mat(1, 0) * mat(0, 1) * mat(2, 2) +
181 mat(2, 1) * mat(1, 2) * mat(0, 0));
182 matInv(0, 0) =
183 (mat(1, 1) * mat(2, 2) - mat(1, 2) * mat(2, 1)) / determinant;
184 matInv(0, 1) =
185 (mat(0, 2) * mat(2, 1) - mat(0, 1) * mat(2, 2)) / determinant;
186 matInv(0, 2) =
187 (mat(0, 1) * mat(1, 2) - mat(0, 2) * mat(1, 1)) / determinant;
188 matInv(1, 0) =
189 (mat(1, 2) * mat(2, 0) - mat(1, 0) * mat(2, 2)) / determinant;
190 matInv(1, 1) =
191 (mat(0, 0) * mat(2, 2) - mat(0, 2) * mat(2, 0)) / determinant;
192 matInv(1, 2) =
193 (mat(0, 2) * mat(1, 0) - mat(0, 0) * mat(1, 2)) / determinant;
194 matInv(2, 0) =
195 (mat(1, 0) * mat(2, 1) - mat(1, 1) * mat(2, 0)) / determinant;
196 matInv(2, 1) =
197 (mat(0, 1) * mat(2, 0) - mat(0, 0) * mat(2, 1)) / determinant;
198 matInv(2, 2) =
199 (mat(0, 0) * mat(1, 1) - mat(0, 1) * mat(1, 0)) / determinant;
200 } else {
201 matInv = mat.inverse();
202 }
203}
204
205MatrixComp Math::singlePhaseVariableToThreePhase(Complex var_1ph) {
206 MatrixComp var_3ph = MatrixComp::Zero(3, 1);
207 var_3ph << var_1ph, var_1ph * SHIFT_TO_PHASE_B, var_1ph * SHIFT_TO_PHASE_C;
208 return var_3ph;
209}
210
212 Matrix param_3ph = Matrix::Zero(3, 3);
213 param_3ph << parameter, 0., 0., 0., parameter, 0., 0, 0., parameter;
214 return param_3ph;
215}
216
218 Matrix power_3ph = Matrix::Zero(3, 3);
219 power_3ph << power / 3., 0., 0., 0., power / 3., 0., 0, 0., power / 3.;
220 return power_3ph;
221}
222
223Matrix Math::StateSpaceTrapezoidal(Matrix states, Matrix A, Matrix B, Real dt,
224 Matrix u_new, Matrix u_old) {
225 Matrix::Index n = states.rows();
226 Matrix I = Matrix::Identity(n, n);
227
228 Matrix F1 = I + (dt / 2.) * A;
229 Matrix F2 = I - (dt / 2.) * A;
230 Matrix F2inv = F2.inverse();
231
232 return F2inv * F1 * states + F2inv * (dt / 2.) * B * (u_new + u_old);
233}
234
235Matrix Math::StateSpaceTrapezoidal(Matrix states, Matrix A, Matrix B, Matrix C,
236 Real dt, Matrix u_new, Matrix u_old) {
237 Matrix::Index n = states.rows();
238 Matrix I = Matrix::Identity(n, n);
239
240 Matrix F1 = I + (dt / 2.) * A;
241 Matrix F2 = I - (dt / 2.) * A;
242 Matrix F2inv = F2.inverse();
243
244 return F2inv * F1 * states + F2inv * (dt / 2.) * B * (u_new + u_old) +
245 F2inv * dt * C;
246}
247
248Matrix Math::StateSpaceTrapezoidal(Matrix states, Matrix A, Matrix B, Matrix C,
249 Real dt, Matrix u) {
250 Matrix::Index n = states.rows();
251 Matrix I = Matrix::Identity(n, n);
252
253 Matrix F1 = I + (dt / 2.) * A;
254 Matrix F2 = I - (dt / 2.) * A;
255 Matrix F2inv = F2.inverse();
256
257 return F2inv * F1 * states + F2inv * dt * B * u + F2inv * dt * C;
258}
259
260Real Math::StateSpaceTrapezoidal(Real states, Real A, Real B, Real C, Real dt,
261 Real u) {
262 Real F1 = 1. + (dt / 2.) * A;
263 Real F2 = 1. - (dt / 2.) * A;
264 Real F2inv = 1. / F2;
265
266 return F2inv * F1 * states + F2inv * dt * B * u + F2inv * dt * C;
267}
268
269Matrix Math::StateSpaceTrapezoidal(Matrix states, Matrix A, Matrix B, Real dt,
270 Matrix u) {
271 Matrix::Index n = states.rows();
272 Matrix I = Matrix::Identity(n, n);
273
274 Matrix F1 = I + (dt / 2.) * A;
275 Matrix F2 = I - (dt / 2.) * A;
276 Matrix F2inv = F2.inverse();
277
278 return F2inv * F1 * states + F2inv * dt * B * u;
279}
280
281Matrix Math::StateSpaceTrapezoidal(Matrix states, Matrix A, Matrix input,
282 Real dt) {
283 Matrix::Index n = states.rows();
284 Matrix I = Matrix::Identity(n, n);
285
286 Matrix F1 = I + (dt / 2.) * A;
287 Matrix F2 = I - (dt / 2.) * A;
288 Matrix F2inv = F2.inverse();
289
290 return F2inv * F1 * states + F2inv * dt * input;
291}
292
293Real Math::StateSpaceTrapezoidal(Real states, Real A, Real B, Real dt, Real u) {
294 Real F1 = 1. + (dt / 2.) * A;
295 Real F2 = 1. - (dt / 2.) * A;
296 Real F2inv = 1. / F2;
297
298 return F2inv * F1 * states + F2inv * dt * B * u;
299}
300
301Matrix Math::StateSpaceEuler(Matrix states, Matrix A, Matrix B, Real dt,
302 Matrix u) {
303 return states + dt * (A * states + B * u);
304}
305
306Real Math::StateSpaceEuler(Real states, Real A, Real B, Real dt, Real u) {
307 return states + dt * (A * states + B * u);
308}
309
310Matrix Math::StateSpaceEuler(Matrix states, Matrix A, Matrix B, Matrix C,
311 Real dt, Matrix u) {
312 return states + dt * (A * states + B * u + C);
313}
314
315Real Math::StateSpaceEuler(Real states, Real A, Real B, Real C, Real dt,
316 Real u) {
317 return states + dt * (A * states + B * u + C);
318}
319
320Matrix Math::StateSpaceEuler(Matrix states, Matrix A, Matrix input, Real dt) {
321 return states + dt * (A * states + input);
322}
323
325 const Matrix &B,
326 const Matrix &C,
327 const Real &dt, Matrix &Ad,
328 Matrix &Bd, Matrix &Cd) {
329 Matrix::Index n = A.rows();
330 Matrix I = Matrix::Identity(n, n);
331
332 Matrix F1 = I + (dt / 2.) * A;
333 Matrix F2 = I - (dt / 2.) * A;
334 Matrix F2inv = F2.inverse();
335
336 Ad = F2inv * F1;
337 Bd = F2inv * (dt / 2.) * B;
338 Cd = F2inv * dt * C;
339}
340
342 const Matrix &Bd,
343 const Matrix &Cd,
344 const Matrix &statesPrevStep,
345 const Matrix &inputCurrStep,
346 const Matrix &inputPrevStep) {
347 return Ad * statesPrevStep + Bd * (inputCurrStep + inputPrevStep) + Cd;
348}
349
350void Math::FFT(std::vector<Complex> &samples) {
351 // DFT
352 size_t N = samples.size();
353 size_t k = N;
354 size_t n;
355 double thetaT = M_PI / N;
356 Complex phiT = Complex(cos(thetaT), -sin(thetaT)), T;
357 while (k > 1) {
358 n = k;
359 k >>= 1;
360 phiT = phiT * phiT;
361 T = 1.0L;
362 for (size_t l = 0; l < k; l++) {
363 for (size_t a = l; a < N; a += n) {
364 size_t b = a + k;
365 Complex t = samples[a] - samples[b];
366 samples[a] += samples[b];
367 samples[b] = t * T;
368 }
369 T *= phiT;
370 }
371 }
372 // Decimate
373 UInt m = static_cast<UInt>(log2(N));
374 for (UInt a = 0; a < N; a++) {
375 UInt b = a;
376 // Reverse bits
377 b = (((b & 0xaaaaaaaa) >> 1) | ((b & 0x55555555) << 1));
378 b = (((b & 0xcccccccc) >> 2) | ((b & 0x33333333) << 2));
379 b = (((b & 0xf0f0f0f0) >> 4) | ((b & 0x0f0f0f0f) << 4));
380 b = (((b & 0xff00ff00) >> 8) | ((b & 0x00ff00ff) << 8));
381 b = ((b >> 16) | (b << 16)) >> (32 - m);
382 if (b > a) {
383 Complex t = samples[a];
384 samples[a] = samples[b];
385 samples[b] = t;
386 }
387 }
388}
389
390Complex Math::rotatingFrame2to1(Complex f2, Real theta1, Real theta2) {
391 Real delta = theta2 - theta1;
392 Real f1_real = f2.real() * cos(delta) - f2.imag() * sin(delta);
393 Real f1_imag = f2.real() * sin(delta) + f2.imag() * cos(delta);
394 return Complex(f1_real, f1_imag);
395}
static Matrix singlePhasePowerToThreePhase(Real power)
To convert single phase power to symmetrical three phase.
static void calculateStateSpaceTrapezoidalMatrices(const Matrix &A, const Matrix &B, const Matrix &C, const Real &dt, Matrix &Ad, Matrix &Bd, Matrix &Cd)
Calculate the discretized state space matrices Ad, Bd, Cd using trapezoidal rule.
static Matrix applyStateSpaceTrapezoidalMatrices(const Matrix &Ad, const Matrix &Bd, const Matrix &Cd, const Matrix &statesPrevStep, const Matrix &inputCurrStep, const Matrix &inputPrevStep)
Apply the trapezoidal based state space matrices Ad, Bd, Cd to get the states at the current time ste...
static Matrix singlePhaseParameterToThreePhase(Real parameter)
To convert single phase parameters to symmetrical three phase ones.
static MatrixComp singlePhaseVariableToThreePhase(Complex var_1ph)
To convert single phase complex variables (voltages, currents) to symmetrical three phase ones.