Transformations
This chapter describes all electrical transformations implemented in the VSlib.
General interface
All of the classes described below derive from and implement the Component interface.
They all have a single access method, called transform. The number of arguments each implementation
takes depends on the use-case, as well as the returned structure may vary. This method is intended to perform
transformation on the set of values at a point of time rather than arrays or vectors of values in one execution.
abc to dq0 transformation
AbcToDq0Transform implements the from three time-domain signals of a three-phase
system (abc) to an dq0 reference frame. The algorithm follows the implementation
and nomeclature of the Park transformation matlab implementation.
The transform method takes four obligatory and one optional double-type arguments, one for each phase,
the \(theta\) (\(=\omega t\)) angle in radians between the q and a axes, and an optional offset (\(\phi\)) in radians.
The offset can be used to change the default alignment from q and a axis alignment to d and a by setting the offset
to be equal to \(\frac{\pi}{2}\). The method returns a tuple of d, q, zero values. The transformation algorithm is as follows:
However, during benchmarking it was found that due to the overhead of the look-ups of the sine and cosine functions, it is preferable to perform the abc to dq0 transformation in two steps:
Transform abc to \(\alpha \beta 0\) frame, and then
Transform \(\alpha\beta 0\) to dq0.
For more details regarding the API, see the API documentation for AbcToDq0Transform.
Usage example
#include <numbers>
#include "abcToDq0Transform.h"
#include "rootComponent.h"
using namespace vslib;
void your_function(RootComponent& root)
{
AbcToDq0Transform abc_to_dq0("abc_to_dq0", root);
// no Parameter needs setting
const double i_a = 1.0;
const double i_b = -0.5;
const double i_c = -0.5;
const double theta = 0.0;
const double offset = std::numbers::pi / 2.0;
// no offset, q and a alignment:
auto [d_1, q_1, zero_1] = abc_to_dq0.transform(i_a, i_b, i_c, theta);
// 90 degrees offset, d and a alignment:
auto [d_2, q_2, zero_2] = abc_to_dq0.transform(i_a, i_b, i_c, theta, offset);
}
Example usage in a vloop:
#include "vslib.hpp"
namespace fgc::user
{
class Converter : public vslib::RootComponent
{
public:
Converter() noexcept
: vslib::RootComponent("example"),
interrupt_1("stg", *this, 128, vslib::InterruptPriority::high, RTTask),
abc_to_dq0("abc_to_dq0", *this)
{
}
// Define your interrupts here
vslib::PeripheralInterrupt<Converter> interrupt_1;
// Define your public Components here
vslib::AbcToDq0Transform abc_to_dq0;
void init() override
{
interrupt_1.start();
}
void backgroundTask() override
{
}
static void RTTask(Converter& converter)
{
// Read the input 3-phase voltage values:
const double v_a = converter.m_data[0];
const double v_b = converter.m_data[1];
const double v_c = converter.m_data[2];
const double theta = converter.m_data[3];
const double offset = converter.m_data[4];
// no offset, q and a alignment:
auto [d_1, q_1, zero_1] = abc_to_dq0.transform(v_a, v_b, v_c, theta);
// 90 degrees offset, d and a alignment:
auto [d_2, q_2, zero_2] = abc_to_dq0.transform(v_a, v_b, v_c, theta, offset);
}
private:
// actual source of data omitted for simplicity
std::array<double, 5> m_data{0.0};
};
} // namespace fgc::user
dq0 to abc transformation
Dq0ToAbcTransform implements the transformation from dq0 reference frame to three-phase
system (abc) dq0, an inverse of AbcToDq0Transform. The algorithm follows the implementation
and nomeclature of the Inverse Park transformation Matlab implementation.
The transform method takes four obligatory and one optional double-type arguments, one for each dq0 component,
the \(theta\) (\(=\omega t\)) angle in radians between the q and a axes, and an optional offset in radians.
The offset can be used to change the default alignment from q and a axis alignment to d and a by setting the offset
to be equal to \(\frac{\pi}{2}\). The method returns a tuple of a, b, and c values. The transformation algorithm is as follows:
However, during benchmarking it was found that due to the overhead of the look-ups of the sine and cosine functions, it is preferable to perform the dq0 to abc transformation in two steps:
Transform dq0 to \(\alpha\beta 0\) frame, and then
Transform \(\alpha\beta 0\) to abc.
For more details regarding the API, see the API documentation for Dq0ToAbcTransform.
Usage example
#include <numbers>
#include "dq0ToAbcTransform.h"
#include "rootComponent.h"
using namespace vslib;
void your_function(RootComponent& root)
{
Dq0ToAbcTransform dq0_to_abc("dq0_to_abc", root);
// no Parameter needs setting
const double d = 1.0;
const double q = 0.05;
const double zero = 0.05;
const double theta = 0.0;
const double offset = std::numbers::pi / 2.0;
// no offset, q and a alignment:
auto [a_1, b_2, c_2] = dq0_to_abc.transform(d, q, zero, theta);
// 90 degrees offset, d and a alignment:
auto [a_2, b_2, c_2] = dq0_to_abc.transform(d, q, zero, theta, offset);
}
Example usage in a vloop:
#include "vslib.hpp"
namespace fgc::user
{
class Converter : public vslib::RootComponent
{
public:
Converter() noexcept
: vslib::RootComponent("example"),
interrupt_1("stg", *this, 128, vslib::InterruptPriority::high, RTTask),
dq0_to_abc("dq0_to_abc", *this)
{
}
// Define your interrupts here
vslib::PeripheralInterrupt<Converter> interrupt_1;
// Define your public Components here
vslib::Dq0ToAbcTransform dq0_to_abc;
void init() override
{
interrupt_1.start();
}
void backgroundTask() override
{
}
static void RTTask(Converter& converter)
{
// Read the input 3-phase voltage values:
const double d = converter.m_data[0];
const double q = converter.m_data[1];
const double zero = converter.m_data[2];
const double theta = converter.m_data[3];
const double offset = converter.m_data[4];
// no offset, q and a alignment:
auto [a_1, b_2, c_2] = dq0_to_abc.transform(d, q, zero, theta);
// 90 degrees offset, d and a alignment:
auto [a_2, b_2, c_2] = dq0_to_abc.transform(d, q, zero, theta, offset);
}
private:
// actual source of data omitted for simplicity
std::array<double, 5> m_data{0.0};
};
} // namespace fgc::user
abc to alpha-beta transformation
AbcToAlphaBetaTransform implements the abc to \(\alpha\beta0\) (Clarke) transformation from three-phase components in the abc
reference frame to the rotating \(\alpha\beta0\) frame. The algorithm follows the implementation
and nomeclature of the Inverse Clarke Matlab implementation.
The transform method takes three obligatory double-type arguments, one for each a, b, and c component in the abc
frame of reference. The method returns a tuple of \(\alpha\), \(\beta\), and 0 values. The calculation is as follows:
For more details regarding the API, see the API documentation for AbcToAlphaBetaTransform.
Usage example
#include "abcToAlphaBetaTransform.h"
#include "rootComponent.h"
using namespace vslib;
void your_function(RootComponent& root)
{
AbcToAlphaBetaTransform abc_to_alphabeta("abc_to_alphabeta", root);
// no Parameters need setting
const double i_a = 2.0;
const double i_b = -1.0;
const double i_c = -1.0;
auto [alpha, beta, zero] = abc_to_alphabeta.transform(i_a, i_b, i_c);
// alpha = 2.0, beta = 0, zero = 0
}
Example usage in a vloop:
#include "vslib.hpp"
namespace fgc::user
{
class Converter : public vslib::RootComponent
{
public:
Converter() noexcept
: vslib::RootComponent("example"),
interrupt_1("stg", *this, 128, vslib::InterruptPriority::high, RTTask),
abc_to_alphabeta("abc_to_alphabeta", *this)
{
}
// Define your interrupts here
vslib::PeripheralInterrupt<Converter> interrupt_1;
// Define your public Components here
vslib::AbcToAlphaBetaTransform abc_to_alphabeta;
void init() override
{
interrupt_1.start();
}
void backgroundTask() override
{
}
static void RTTask(Converter& converter)
{
// Read the input 3-phase voltage values:
const double v_a = converter.m_data[0];
const double v_b = converter.m_data[1];
const double v_c = converter.m_data[2];
// no offset, q and a alignment:
auto [alpha, beta, zero] = abc_to_alphabeta.transform(v_a, v_b, v_c);
}
private:
// actual source of data omitted for simplicity
std::array<double, 3> m_data{0.0};
};
} // namespace fgc::user
alpha-beta to abc transformation
AbcToAlphaBetaTransform implements the \(\alpha\beta0\) to abc (inverse Clarke) transformation from
the rotating \(\alpha\beta0\) frame to the three-phase components in the time domain. The algorithm follows the implementation
and nomeclature of the Inverse Clarke Matlab implementation.
The transform method takes three obligatory double-type arguments, one for each \(\alpha\), \(\beta\), and zero
components in the rotating \(\alpha\beta0\) frame of reference. The method returns a tuple of a, b, and c values.
The calculation is as follows:
For more details regarding the API, see the API documentation for AlphaBetaToAbcTransform.
Usage example
#include "alphaBetaToAbcTransform.h"
#include "rootComponent.h"
using namespace vslib;
void your_function(RootComponent& root)
{
AlphaBetaToAbcTransform transform("alphabeta_to_abc");
// no Parameters need setting
const double alpha = 2.0;
const double beta = 0.0;
const double zero = 0.0;
auto [a, b, c] = transform.transform(alpha, beta, zero);
// a = 2.0, b = -1.0, c = -1.0
}
Alpha-beta to dq0
alphaBetaToDq0Transform implements the \(\alpha\beta0\) transformation from three stationary
components in the \(\alpha\beta0\) reference frame to the rotating dq0 reference frame, an equivalent
of the inverse Clarke and then Park transform.
The transform method takes four obligatory double-type arguments and one optional boolean argument:
one for each \(\alpha\), \(\beta\), and 0 component in the \(\alpha\beta0\) frame of reference,
the \(theta\) angle (in radians) between q and \(alpha\), and optionally specify alignment: true
for a-axis alignment or false for 90 degrees behind a-axis. The method returns a tuple of d, q, and 0 values.
The algorithm follows the implementation and nomeclature of the
alpha-beta to dq0 Matlab implementation.
The calculation is as follows if the a-axis alignment is chosen:
and if the the 90-degrees behind a-axis alignment is preferred:
For more details regarding the API, see the API documentation for AlphaBetaToDq0Transform.
Usage example
#include <numbers>
#include "alphaBetaToDq0Transform.h"
#include "rootComponent.h"
using namespace vslib;
void your_function(RootComponent& root)
{
AlphaBetaToDq0Transform transform("alpha-beta_to_dq0", root);
const double i_alpha = 1.0;
const double i_beta = -0.5;
const double i_zero = 0.0;
const double theta = std::numbers::pi / 6; // 30 degrees in radians
bool a_alignment = true;
auto [d, q, zero] = transform.transform(i_alpha, i_beta, i_zero, theta, a_alignment);
}
dq0 to alpha-beta
Dq0ToAlphaBetaTransform implements the transformation of components in dq0 frame of reference to
the \(\alpha\beta0\) reference frame, an inverse of AlphaBetaToDq0Transformation.
The transform method takes four obligatory double-type arguments and one optional boolean argument:
one for each d, q, zero, and theta, and optionally a boolean alignment argument: true for a-axis
alignment or false for 90 degrees behind a-axis. \(theta\) is the angle (in radians) between q
and \(alpha\). The method returns a tuple of \(\alpha\), \(\beta\), and zero values.
The algorithm follows the implementation and nomeclature of the
alpha-beta to dq0 Matlab implementation (inverse).
The calculation is as follows if the a-axis alignment is chosen:
and if the the 90-degrees behind a-axis alignment is preferred:
For more details regarding the API, see the API documentation for Dq0ToAlphaBetaTransform.
Usage example
#include <numbers>
#include "dq0ToAlphaBetaTransform.h"
#include "rootComponent.h"
using namespace vslib;
void your_function(RootComponent& root)
{
dq0ToAlphaBetaTransform transform("dq0_to_alphabeta", root);
const double d = 1.0;
const double q = -0.5;
const double i_zero = 0.0;
const double theta = std::numbers::pi / 6; // 30 degrees in radians
bool a_alignment = true;
auto [alpha, beta, zero] = transform.transform(d, q, i_zero, theta, a_alignment);
}
Performance
The execution time of each Component depends on a number of factors. In the case of AbcToAlphaBetaTransform,
there no look-up tables and the execution time is independent of the inputs. For AbcToDq0Transform and
AlphaBetaToDq0Transform, the execution will depend on the size of the internal look-up tables.
The table below gives an overlook of the execution time that can be expected for each of the Components.
Class |
Access time [ns] |
|---|---|
AbcToAlphaBetaTransform |
33 |
AbcToDq0Transform |
263 |
AlphaBetaToDq0Transform |
197 |
AlphaBetaToAbcTransform |
27 |
Dq0ToAbcTransform |
270 |
Dq0ToAlphaBetaTransform |
230 |