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
11#include <cstdint>
12#include <cstring>
13
14using namespace CPS;
15
16// #### Angular Operations ####
17Real Math::radtoDeg(Real rad) { return rad * 180 / PI; }
18
19Real Math::degToRad(Real deg) { return deg * PI / 180; }
20
21Real Math::phase(Complex value) { return std::arg(value); }
22
23Real Math::phaseDeg(Complex value) { return radtoDeg(phase(value)); }
24
25Real Math::abs(Complex value) { return std::abs(value); }
26
27Matrix Math::abs(const MatrixComp &mat) {
28 size_t nRows = mat.rows();
29 size_t nCols = mat.cols();
30 Matrix res(mat.rows(), mat.cols());
31
32 for (size_t i = 0; i < nRows; ++i) {
33 for (size_t j = 0; j < nCols; ++j) {
34 res(i, j) = std::abs(mat(i, j));
35 }
36 }
37 return res;
38}
39
40Matrix Math::phase(const MatrixComp &mat) {
41 size_t nRows = mat.rows();
42 size_t nCols = mat.cols();
43 Matrix res(mat.rows(), mat.cols());
44
45 for (size_t i = 0; i < nRows; ++i) {
46 for (size_t j = 0; j < nCols; ++j) {
47 res(i, j) = std::arg(mat(i, j));
48 }
49 }
50 return res;
51}
52
53Complex Math::polar(Real abs, Real phase) {
54 return std::polar<Real>(abs, phase);
55}
56
57Complex Math::polarDeg(Real abs, Real phase) {
58 return std::polar<Real>(abs, degToRad(phase));
59}
60
61bool Math::isFinite(Real value) {
62 uint64_t bits;
63 std::memcpy(&bits, &value, sizeof(bits));
64 return (bits & 0x7FF0000000000000ULL) != 0x7FF0000000000000ULL;
65}
66
67bool Math::isFinite(Complex value) {
68 return isFinite(value.real()) && isFinite(value.imag());
69}
70
71void Math::setVectorElement(Matrix &mat, Matrix::Index row, Complex value,
72 Int maxFreq, Int freqIdx, Matrix::Index colOffset) {
73 Eigen::Index harmonicOffset = mat.rows() / maxFreq;
74 Eigen::Index complexOffset = harmonicOffset / 2;
75 Eigen::Index harmRow = row + harmonicOffset * freqIdx;
76
77 mat(harmRow, colOffset) = value.real();
78 mat(harmRow + complexOffset, colOffset) = value.imag();
79}
80
81void Math::addToVectorElement(Matrix &mat, Matrix::Index row, Complex value,
82 Int maxFreq, Int freqIdx) {
83 Eigen::Index harmonicOffset = mat.rows() / maxFreq;
84 Eigen::Index complexOffset = harmonicOffset / 2;
85 Eigen::Index harmRow = row + harmonicOffset * freqIdx;
86
87 mat(harmRow, 0) = mat(harmRow, 0) + value.real();
88 mat(harmRow + complexOffset, 0) =
89 mat(harmRow + complexOffset, 0) + value.imag();
90}
91
92Complex Math::complexFromVectorElement(const Matrix &mat, Matrix::Index row,
93 Int maxFreq, Int freqIdx) {
94 Eigen::Index harmonicOffset = mat.rows() / maxFreq;
95 Eigen::Index complexOffset = harmonicOffset / 2;
96 Eigen::Index harmRow = row + harmonicOffset * freqIdx;
97
98 return Complex(mat(harmRow, 0), mat(harmRow + complexOffset, 0));
99}
100
101void Math::addToVectorElement(Matrix &mat, Matrix::Index row, Real value) {
102 mat(row, 0) = mat(row, 0) + value;
103}
104
105void Math::setVectorElement(Matrix &mat, Matrix::Index row, Real value) {
106 mat(row, 0) = value;
107}
108
109Real Math::realFromVectorElement(const Matrix &mat, Matrix::Index row) {
110 return mat(row, 0);
111}
112
113void Math::setMatrixElement(SparseMatrixRow &mat, Matrix::Index row,
114 Matrix::Index column, Complex value, Int maxFreq,
115 Int freqIdx) {
116 // Assume square matrix
117 Eigen::Index harmonicOffset = mat.rows() / maxFreq;
118 Eigen::Index complexOffset = harmonicOffset / 2;
119 Eigen::Index harmRow = row + harmonicOffset * freqIdx;
120 Eigen::Index harmCol = column + harmonicOffset * freqIdx;
121
122 mat.coeffRef(harmRow, harmCol) = value.real();
123 mat.coeffRef(harmRow + complexOffset, harmCol + complexOffset) = value.real();
124 mat.coeffRef(harmRow, harmCol + complexOffset) = -value.imag();
125 mat.coeffRef(harmRow + complexOffset, harmCol) = value.imag();
126}
127
128void Math::addToMatrixElement(SparseMatrixRow &mat, Matrix::Index row,
129 Matrix::Index column, Complex value, Int maxFreq,
130 Int freqIdx) {
131 // Assume square matrix
132 Eigen::Index harmonicOffset = mat.rows() / maxFreq;
133 Eigen::Index complexOffset = harmonicOffset / 2;
134 Eigen::Index harmRow = row + harmonicOffset * freqIdx;
135 Eigen::Index harmCol = column + harmonicOffset * freqIdx;
136
137 mat.coeffRef(harmRow, harmCol) += value.real();
138 mat.coeffRef(harmRow + complexOffset, harmCol + complexOffset) +=
139 value.real();
140 mat.coeffRef(harmRow, harmCol + complexOffset) -= value.imag();
141 mat.coeffRef(harmRow + complexOffset, harmCol) += value.imag();
142}
143
144void Math::addToMatrixElement(SparseMatrixRow &mat, Matrix::Index row,
145 Matrix::Index column, Matrix value, Int maxFreq,
146 Int freqIdx) {
147 // Assume square matrix
148 Eigen::Index harmonicOffset = mat.rows() / maxFreq;
149 Eigen::Index complexOffset = harmonicOffset / 2;
150 Eigen::Index harmRow = row + harmonicOffset * freqIdx;
151 Eigen::Index harmCol = column + harmonicOffset * freqIdx;
152
153 mat.coeffRef(harmRow, harmCol) += value(0, 0);
154 mat.coeffRef(harmRow + complexOffset, harmCol + complexOffset) += value(1, 1);
155 mat.coeffRef(harmRow, harmCol + complexOffset) += value(0, 1);
156 mat.coeffRef(harmRow + complexOffset, harmCol) += value(1, 0);
157}
158
159void Math::setMatrixElement(SparseMatrixRow &mat, Matrix::Index row,
160 Matrix::Index column, Real value) {
161 mat.coeffRef(row, column) = value;
162}
163
164void Math::addToMatrixElement(SparseMatrixRow &mat, std::vector<UInt> rows,
165 std::vector<UInt> columns, Complex value) {
166 for (UInt phase = 0; phase < rows.size(); phase++)
167 addToMatrixElement(mat, rows[phase], columns[phase], value);
168}
169
170void Math::addToMatrixElement(SparseMatrixRow &mat, Matrix::Index row,
171 Matrix::Index column, Real value) {
172 mat.coeffRef(row, column) = mat.coeff(row, column) + value;
173}
174
175void Math::addToMatrixElement(SparseMatrixRow &mat, std::vector<UInt> rows,
176 std::vector<UInt> columns, Real value) {
177 for (UInt phase = 0; phase < rows.size(); phase++)
178 addToMatrixElement(mat, rows[phase], columns[phase], value);
179}
180
181void Math::invertMatrix(const Matrix &mat, Matrix &matInv) {
182 const Int n = Eigen::internal::convert_index<Int>(mat.cols());
183 if (n == 2) {
184 const Real determinant = mat(0, 0) * mat(1, 1) - mat(0, 1) * mat(1, 0);
185 matInv(0, 0) = mat(1, 1) / determinant;
186 matInv(0, 1) = -mat(0, 1) / determinant;
187 matInv(1, 0) = -mat(1, 0) / determinant;
188 matInv(1, 1) = mat(0, 0) / determinant;
189 } else if (n == 3) {
190 const Real determinant =
191 (mat(0, 0) * mat(1, 1) * mat(2, 2) + mat(0, 1) * mat(1, 2) * mat(2, 0) +
192 mat(1, 0) * mat(2, 1) * mat(0, 2)) -
193 (mat(2, 0) * mat(1, 1) * mat(0, 2) + mat(1, 0) * mat(0, 1) * mat(2, 2) +
194 mat(2, 1) * mat(1, 2) * mat(0, 0));
195 matInv(0, 0) =
196 (mat(1, 1) * mat(2, 2) - mat(1, 2) * mat(2, 1)) / determinant;
197 matInv(0, 1) =
198 (mat(0, 2) * mat(2, 1) - mat(0, 1) * mat(2, 2)) / determinant;
199 matInv(0, 2) =
200 (mat(0, 1) * mat(1, 2) - mat(0, 2) * mat(1, 1)) / determinant;
201 matInv(1, 0) =
202 (mat(1, 2) * mat(2, 0) - mat(1, 0) * mat(2, 2)) / determinant;
203 matInv(1, 1) =
204 (mat(0, 0) * mat(2, 2) - mat(0, 2) * mat(2, 0)) / determinant;
205 matInv(1, 2) =
206 (mat(0, 2) * mat(1, 0) - mat(0, 0) * mat(1, 2)) / determinant;
207 matInv(2, 0) =
208 (mat(1, 0) * mat(2, 1) - mat(1, 1) * mat(2, 0)) / determinant;
209 matInv(2, 1) =
210 (mat(0, 1) * mat(2, 0) - mat(0, 0) * mat(2, 1)) / determinant;
211 matInv(2, 2) =
212 (mat(0, 0) * mat(1, 1) - mat(0, 1) * mat(1, 0)) / determinant;
213 } else {
214 matInv = mat.inverse();
215 }
216}
217
218MatrixComp Math::singlePhaseVariableToThreePhase(Complex var_1ph) {
219 MatrixComp var_3ph = MatrixComp::Zero(3, 1);
220 var_3ph << var_1ph, var_1ph * SHIFT_TO_PHASE_B, var_1ph * SHIFT_TO_PHASE_C;
221 return var_3ph;
222}
223
225 Matrix param_3ph = Matrix::Zero(3, 3);
226 param_3ph << parameter, 0., 0., 0., parameter, 0., 0, 0., parameter;
227 return param_3ph;
228}
229
231 Matrix power_3ph = Matrix::Zero(3, 3);
232 power_3ph << power / 3., 0., 0., 0., power / 3., 0., 0, 0., power / 3.;
233 return power_3ph;
234}
235
236Matrix Math::StateSpaceTrapezoidal(Matrix states, Matrix A, Matrix B, Real dt,
237 Matrix u_new, Matrix u_old) {
238 Matrix::Index n = states.rows();
239 Matrix I = Matrix::Identity(n, n);
240
241 Matrix F1 = I + (dt / 2.) * A;
242 Matrix F2 = I - (dt / 2.) * A;
243 Matrix F2inv = F2.inverse();
244
245 return F2inv * F1 * states + F2inv * (dt / 2.) * B * (u_new + u_old);
246}
247
248Matrix Math::StateSpaceTrapezoidal(Matrix states, Matrix A, Matrix B, Matrix C,
249 Real dt, Matrix u_new, Matrix u_old) {
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 / 2.) * B * (u_new + u_old) +
258 F2inv * dt * C;
259}
260
261Matrix Math::StateSpaceTrapezoidal(Matrix states, Matrix A, Matrix B, Matrix C,
262 Real dt, Matrix u) {
263 Matrix::Index n = states.rows();
264 Matrix I = Matrix::Identity(n, n);
265
266 Matrix F1 = I + (dt / 2.) * A;
267 Matrix F2 = I - (dt / 2.) * A;
268 Matrix F2inv = F2.inverse();
269
270 return F2inv * F1 * states + F2inv * dt * B * u + F2inv * dt * C;
271}
272
273Real Math::StateSpaceTrapezoidal(Real states, Real A, Real B, Real C, Real dt,
274 Real u) {
275 Real F1 = 1. + (dt / 2.) * A;
276 Real F2 = 1. - (dt / 2.) * A;
277 Real F2inv = 1. / F2;
278
279 return F2inv * F1 * states + F2inv * dt * B * u + F2inv * dt * C;
280}
281
282Matrix Math::StateSpaceTrapezoidal(Matrix states, Matrix A, Matrix B, Real dt,
283 Matrix u) {
284 Matrix::Index n = states.rows();
285 Matrix I = Matrix::Identity(n, n);
286
287 Matrix F1 = I + (dt / 2.) * A;
288 Matrix F2 = I - (dt / 2.) * A;
289 Matrix F2inv = F2.inverse();
290
291 return F2inv * F1 * states + F2inv * dt * B * u;
292}
293
294Matrix Math::StateSpaceTrapezoidal(Matrix states, Matrix A, Matrix input,
295 Real dt) {
296 Matrix::Index n = states.rows();
297 Matrix I = Matrix::Identity(n, n);
298
299 Matrix F1 = I + (dt / 2.) * A;
300 Matrix F2 = I - (dt / 2.) * A;
301 Matrix F2inv = F2.inverse();
302
303 return F2inv * F1 * states + F2inv * dt * input;
304}
305
306Real Math::StateSpaceTrapezoidal(Real states, Real A, Real B, Real dt, Real u) {
307 Real F1 = 1. + (dt / 2.) * A;
308 Real F2 = 1. - (dt / 2.) * A;
309 Real F2inv = 1. / F2;
310
311 return F2inv * F1 * states + F2inv * dt * B * u;
312}
313
314Matrix Math::StateSpaceEuler(Matrix states, Matrix A, Matrix B, Real dt,
315 Matrix u) {
316 return states + dt * (A * states + B * u);
317}
318
319Real Math::StateSpaceEuler(Real states, Real A, Real B, Real dt, Real u) {
320 return states + dt * (A * states + B * u);
321}
322
323Matrix Math::StateSpaceEuler(Matrix states, Matrix A, Matrix B, Matrix C,
324 Real dt, Matrix u) {
325 return states + dt * (A * states + B * u + C);
326}
327
328Real Math::StateSpaceEuler(Real states, Real A, Real B, Real C, Real dt,
329 Real u) {
330 return states + dt * (A * states + B * u + C);
331}
332
333Matrix Math::StateSpaceEuler(Matrix states, Matrix A, Matrix input, Real dt) {
334 return states + dt * (A * states + input);
335}
336
338 const Matrix &B,
339 const Matrix &C,
340 const Real &dt, Matrix &Ad,
341 Matrix &Bd, Matrix &Cd) {
342 Matrix::Index n = A.rows();
343 Matrix I = Matrix::Identity(n, n);
344
345 Matrix F1 = I + (dt / 2.) * A;
346 Matrix F2 = I - (dt / 2.) * A;
347 Matrix F2inv = F2.inverse();
348
349 Ad = F2inv * F1;
350 Bd = F2inv * (dt / 2.) * B;
351 Cd = F2inv * dt * C;
352}
353
355 const Matrix &B,
356 const Real &dt, Matrix &Ad,
357 Matrix &Bd) {
358 Matrix::Index n = A.rows();
359 Matrix I = Matrix::Identity(n, n);
360
361 Matrix F1 = I + (dt / 2.) * A;
362 Matrix F2 = I - (dt / 2.) * A;
363 Matrix F2inv = F2.inverse();
364
365 Ad = F2inv * F1;
366 Bd = F2inv * (dt / 2.) * B;
367}
368
370 const Matrix &Bd,
371 const Matrix &Cd,
372 const Matrix &statesPrevStep,
373 const Matrix &inputCurrStep,
374 const Matrix &inputPrevStep) {
375 return Ad * statesPrevStep + Bd * (inputCurrStep + inputPrevStep) + Cd;
376}
377
378void Math::FFT(std::vector<Complex> &samples) {
379 // DFT
380 size_t N = samples.size();
381 size_t k = N;
382 size_t n;
383 double thetaT = M_PI / N;
384 Complex phiT = Complex(cos(thetaT), -sin(thetaT)), T;
385 while (k > 1) {
386 n = k;
387 k >>= 1;
388 phiT = phiT * phiT;
389 T = 1.0L;
390 for (size_t l = 0; l < k; l++) {
391 for (size_t a = l; a < N; a += n) {
392 size_t b = a + k;
393 Complex t = samples[a] - samples[b];
394 samples[a] += samples[b];
395 samples[b] = t * T;
396 }
397 T *= phiT;
398 }
399 }
400 // Decimate
401 UInt m = static_cast<UInt>(log2(N));
402 for (UInt a = 0; a < N; a++) {
403 UInt b = a;
404 // Reverse bits
405 b = (((b & 0xaaaaaaaa) >> 1) | ((b & 0x55555555) << 1));
406 b = (((b & 0xcccccccc) >> 2) | ((b & 0x33333333) << 2));
407 b = (((b & 0xf0f0f0f0) >> 4) | ((b & 0x0f0f0f0f) << 4));
408 b = (((b & 0xff00ff00) >> 8) | ((b & 0x00ff00ff) << 8));
409 b = ((b >> 16) | (b << 16)) >> (32 - m);
410 if (b > a) {
411 Complex t = samples[a];
412 samples[a] = samples[b];
413 samples[b] = t;
414 }
415 }
416}
417
418Complex Math::rotatingFrame2to1(Complex f2, Real theta1, Real theta2) {
419 Real delta = theta2 - theta1;
420 Real f1_real = f2.real() * cos(delta) - f2.imag() * sin(delta);
421 Real f1_imag = f2.real() * sin(delta) + f2.imag() * cos(delta);
422 return Complex(f1_real, f1_imag);
423}
424
425Matrix Math::parkTransformPowerInvariant(Real theta, const Matrix &fabc) {
426 return parkTransformMatrixPowerInvariant(theta) * fabc;
427}
428
429Matrix Math::parkTransformMatrixPowerInvariant(Real theta) {
430 Matrix transform = Matrix::Zero(2, 3);
431
432 const Real k = std::sqrt(2.0 / 3.0);
433
434 transform << k * std::cos(theta), k * std::cos(theta - 2.0 * M_PI / 3.0),
435 k * std::cos(theta + 2.0 * M_PI / 3.0), -k * std::sin(theta),
436 -k * std::sin(theta - 2.0 * M_PI / 3.0),
437 -k * std::sin(theta + 2.0 * M_PI / 3.0);
438
439 return transform;
440}
441
442Matrix Math::inverseParkTransformPowerInvariant(Real theta, const Matrix &fdq) {
443 return inverseParkTransformMatrixPowerInvariant(theta) * fdq;
444}
445
446Matrix Math::inverseParkTransformMatrixPowerInvariant(Real theta) {
447 Matrix transform = Matrix::Zero(3, 2);
448
449 const Real k = std::sqrt(2.0 / 3.0);
450
451 transform << k * std::cos(theta), -k * std::sin(theta),
452 k * std::cos(theta - 2.0 * M_PI / 3.0),
453 -k * std::sin(theta - 2.0 * M_PI / 3.0),
454 k * std::cos(theta + 2.0 * M_PI / 3.0),
455 -k * std::sin(theta + 2.0 * M_PI / 3.0);
456
457 return transform;
458}
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.