DPsim
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 using namespace CPS;
12 
13 // #### Angular Operations ####
14 Real Math::radtoDeg(Real rad) { return rad * 180 / PI; }
15 
16 Real Math::degToRad(Real deg) { return deg * PI / 180; }
17 
18 Real Math::phase(Complex value) { return std::arg(value); }
19 
20 Real Math::phaseDeg(Complex value) { return radtoDeg(phase(value)); }
21 
22 Real Math::abs(Complex value) { return std::abs(value); }
23 
24 Matrix 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 
37 Matrix 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 
50 Complex Math::polar(Real abs, Real phase) {
51  return std::polar<Real>(abs, phase);
52 }
53 
54 Complex Math::polarDeg(Real abs, Real phase) {
55  return std::polar<Real>(abs, radtoDeg(phase));
56 }
57 
58 void 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 
68 void 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 
79 Complex 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 
88 void Math::addToVectorElement(Matrix &mat, Matrix::Index row, Real value) {
89  mat(row, 0) = mat(row, 0) + value;
90 }
91 
92 void Math::setVectorElement(Matrix &mat, Matrix::Index row, Real value) {
93  mat(row, 0) = value;
94 }
95 
96 Real Math::realFromVectorElement(const Matrix &mat, Matrix::Index row) {
97  return mat(row, 0);
98 }
99 
100 void 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 
115 void 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 
131 void 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 
146 void Math::setMatrixElement(SparseMatrixRow &mat, Matrix::Index row,
147  Matrix::Index column, Real value) {
148  mat.coeffRef(row, column) = value;
149 }
150 
151 void 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 
157 void 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 
162 void 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 
168 void 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 
205 MatrixComp 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 
223 Matrix 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 
235 Matrix 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 
248 Matrix 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 
260 Real 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 
269 Matrix 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 
281 Matrix 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 
293 Real 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 
301 Matrix Math::StateSpaceEuler(Matrix states, Matrix A, Matrix B, Real dt,
302  Matrix u) {
303  return states + dt * (A * states + B * u);
304 }
305 
306 Real Math::StateSpaceEuler(Real states, Real A, Real B, Real dt, Real u) {
307  return states + dt * (A * states + B * u);
308 }
309 
310 Matrix 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 
315 Real 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 
320 Matrix 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 
350 void 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 
390 Complex 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.
Definition: MathUtils.cpp:217
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.
Definition: MathUtils.cpp:324
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...
Definition: MathUtils.cpp:341
static Matrix singlePhaseParameterToThreePhase(Real parameter)
To convert single phase parameters to symmetrical three phase ones.
Definition: MathUtils.cpp:211
static MatrixComp singlePhaseVariableToThreePhase(Complex var_1ph)
To convert single phase complex variables (voltages, currents) to symmetrical three phase ones.
Definition: MathUtils.cpp:205