9#include <dpsim-models/MathUtils.h>
17Real Math::radtoDeg(Real rad) {
return rad * 180 / PI; }
19Real Math::degToRad(Real deg) {
return deg * PI / 180; }
21Real Math::phase(Complex value) {
return std::arg(value); }
23Real Math::phaseDeg(Complex value) {
return radtoDeg(phase(value)); }
25Real Math::abs(Complex value) {
return std::abs(value); }
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());
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));
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());
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));
53Complex Math::polar(Real abs, Real phase) {
54 return std::polar<Real>(abs, phase);
57Complex Math::polarDeg(Real abs, Real phase) {
58 return std::polar<Real>(abs, degToRad(phase));
61bool Math::isFinite(Real value) {
63 std::memcpy(&bits, &value,
sizeof(bits));
64 return (bits & 0x7FF0000000000000ULL) != 0x7FF0000000000000ULL;
67bool Math::isFinite(Complex value) {
68 return isFinite(value.real()) && isFinite(value.imag());
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;
77 mat(harmRow, colOffset) = value.real();
78 mat(harmRow + complexOffset, colOffset) = value.imag();
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;
87 mat(harmRow, 0) = mat(harmRow, 0) + value.real();
88 mat(harmRow + complexOffset, 0) =
89 mat(harmRow + complexOffset, 0) + value.imag();
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;
98 return Complex(mat(harmRow, 0), mat(harmRow + complexOffset, 0));
101void Math::addToVectorElement(Matrix &mat, Matrix::Index row, Real value) {
102 mat(row, 0) = mat(row, 0) + value;
105void Math::setVectorElement(Matrix &mat, Matrix::Index row, Real value) {
109Real Math::realFromVectorElement(
const Matrix &mat, Matrix::Index row) {
113void Math::setMatrixElement(SparseMatrixRow &mat, Matrix::Index row,
114 Matrix::Index column, Complex value, Int maxFreq,
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;
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();
128void Math::addToMatrixElement(SparseMatrixRow &mat, Matrix::Index row,
129 Matrix::Index column, Complex value, Int maxFreq,
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;
137 mat.coeffRef(harmRow, harmCol) += value.real();
138 mat.coeffRef(harmRow + complexOffset, harmCol + complexOffset) +=
140 mat.coeffRef(harmRow, harmCol + complexOffset) -= value.imag();
141 mat.coeffRef(harmRow + complexOffset, harmCol) += value.imag();
144void Math::addToMatrixElement(SparseMatrixRow &mat, Matrix::Index row,
145 Matrix::Index column, Matrix value, Int maxFreq,
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;
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);
159void Math::setMatrixElement(SparseMatrixRow &mat, Matrix::Index row,
160 Matrix::Index column, Real value) {
161 mat.coeffRef(row, column) = value;
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);
170void Math::addToMatrixElement(SparseMatrixRow &mat, Matrix::Index row,
171 Matrix::Index column, Real value) {
172 mat.coeffRef(row, column) = mat.coeff(row, column) + value;
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);
181void Math::invertMatrix(
const Matrix &mat, Matrix &matInv) {
182 const Int n = Eigen::internal::convert_index<Int>(mat.cols());
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;
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));
196 (mat(1, 1) * mat(2, 2) - mat(1, 2) * mat(2, 1)) / determinant;
198 (mat(0, 2) * mat(2, 1) - mat(0, 1) * mat(2, 2)) / determinant;
200 (mat(0, 1) * mat(1, 2) - mat(0, 2) * mat(1, 1)) / determinant;
202 (mat(1, 2) * mat(2, 0) - mat(1, 0) * mat(2, 2)) / determinant;
204 (mat(0, 0) * mat(2, 2) - mat(0, 2) * mat(2, 0)) / determinant;
206 (mat(0, 2) * mat(1, 0) - mat(0, 0) * mat(1, 2)) / determinant;
208 (mat(1, 0) * mat(2, 1) - mat(1, 1) * mat(2, 0)) / determinant;
210 (mat(0, 1) * mat(2, 0) - mat(0, 0) * mat(2, 1)) / determinant;
212 (mat(0, 0) * mat(1, 1) - mat(0, 1) * mat(1, 0)) / determinant;
214 matInv = mat.inverse();
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;
225 Matrix param_3ph = Matrix::Zero(3, 3);
226 param_3ph << parameter, 0., 0., 0., parameter, 0., 0, 0., parameter;
231 Matrix power_3ph = Matrix::Zero(3, 3);
232 power_3ph << power / 3., 0., 0., 0., power / 3., 0., 0, 0., power / 3.;
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);
241 Matrix F1 = I + (dt / 2.) * A;
242 Matrix F2 = I - (dt / 2.) * A;
243 Matrix F2inv = F2.inverse();
245 return F2inv * F1 * states + F2inv * (dt / 2.) * B * (u_new + u_old);
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);
253 Matrix F1 = I + (dt / 2.) * A;
254 Matrix F2 = I - (dt / 2.) * A;
255 Matrix F2inv = F2.inverse();
257 return F2inv * F1 * states + F2inv * (dt / 2.) * B * (u_new + u_old) +
261Matrix Math::StateSpaceTrapezoidal(Matrix states, Matrix A, Matrix B, Matrix C,
263 Matrix::Index n = states.rows();
264 Matrix I = Matrix::Identity(n, n);
266 Matrix F1 = I + (dt / 2.) * A;
267 Matrix F2 = I - (dt / 2.) * A;
268 Matrix F2inv = F2.inverse();
270 return F2inv * F1 * states + F2inv * dt * B * u + F2inv * dt * C;
273Real Math::StateSpaceTrapezoidal(Real states, Real A, Real B, Real C, Real dt,
275 Real F1 = 1. + (dt / 2.) * A;
276 Real F2 = 1. - (dt / 2.) * A;
277 Real F2inv = 1. / F2;
279 return F2inv * F1 * states + F2inv * dt * B * u + F2inv * dt * C;
282Matrix Math::StateSpaceTrapezoidal(Matrix states, Matrix A, Matrix B, Real dt,
284 Matrix::Index n = states.rows();
285 Matrix I = Matrix::Identity(n, n);
287 Matrix F1 = I + (dt / 2.) * A;
288 Matrix F2 = I - (dt / 2.) * A;
289 Matrix F2inv = F2.inverse();
291 return F2inv * F1 * states + F2inv * dt * B * u;
294Matrix Math::StateSpaceTrapezoidal(Matrix states, Matrix A, Matrix input,
296 Matrix::Index n = states.rows();
297 Matrix I = Matrix::Identity(n, n);
299 Matrix F1 = I + (dt / 2.) * A;
300 Matrix F2 = I - (dt / 2.) * A;
301 Matrix F2inv = F2.inverse();
303 return F2inv * F1 * states + F2inv * dt * input;
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;
311 return F2inv * F1 * states + F2inv * dt * B * u;
314Matrix Math::StateSpaceEuler(Matrix states, Matrix A, Matrix B, Real dt,
316 return states + dt * (A * states + B * u);
319Real Math::StateSpaceEuler(Real states, Real A, Real B, Real dt, Real u) {
320 return states + dt * (A * states + B * u);
323Matrix Math::StateSpaceEuler(Matrix states, Matrix A, Matrix B, Matrix C,
325 return states + dt * (A * states + B * u + C);
328Real Math::StateSpaceEuler(Real states, Real A, Real B, Real C, Real dt,
330 return states + dt * (A * states + B * u + C);
333Matrix Math::StateSpaceEuler(Matrix states, Matrix A, Matrix input, Real dt) {
334 return states + dt * (A * states + input);
340 const Real &dt, Matrix &Ad,
341 Matrix &Bd, Matrix &Cd) {
342 Matrix::Index n = A.rows();
343 Matrix I = Matrix::Identity(n, n);
345 Matrix F1 = I + (dt / 2.) * A;
346 Matrix F2 = I - (dt / 2.) * A;
347 Matrix F2inv = F2.inverse();
350 Bd = F2inv * (dt / 2.) * B;
356 const Real &dt, Matrix &Ad,
358 Matrix::Index n = A.rows();
359 Matrix I = Matrix::Identity(n, n);
361 Matrix F1 = I + (dt / 2.) * A;
362 Matrix F2 = I - (dt / 2.) * A;
363 Matrix F2inv = F2.inverse();
366 Bd = F2inv * (dt / 2.) * B;
372 const Matrix &statesPrevStep,
373 const Matrix &inputCurrStep,
374 const Matrix &inputPrevStep) {
375 return Ad * statesPrevStep + Bd * (inputCurrStep + inputPrevStep) + Cd;
378void Math::FFT(std::vector<Complex> &samples) {
380 size_t N = samples.size();
383 double thetaT = M_PI / N;
384 Complex phiT = Complex(cos(thetaT), -sin(thetaT)), T;
390 for (
size_t l = 0; l < k; l++) {
391 for (
size_t a = l; a < N; a += n) {
393 Complex t = samples[a] - samples[b];
394 samples[a] += samples[b];
401 UInt m =
static_cast<UInt
>(log2(N));
402 for (UInt a = 0; a < N; a++) {
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);
411 Complex t = samples[a];
412 samples[a] = samples[b];
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);
425Matrix Math::parkTransformPowerInvariant(Real theta,
const Matrix &fabc) {
426 return parkTransformMatrixPowerInvariant(theta) * fabc;
429Matrix Math::parkTransformMatrixPowerInvariant(Real theta) {
430 Matrix transform = Matrix::Zero(2, 3);
432 const Real k = std::sqrt(2.0 / 3.0);
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);
442Matrix Math::inverseParkTransformPowerInvariant(Real theta,
const Matrix &fdq) {
443 return inverseParkTransformMatrixPowerInvariant(theta) * fdq;
446Matrix Math::inverseParkTransformMatrixPowerInvariant(Real theta) {
447 Matrix transform = Matrix::Zero(3, 2);
449 const Real k = std::sqrt(2.0 / 3.0);
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);
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.