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