.. _transforms: =============== Transformations =============== This chapter describes all electrical transformations implemented in the VSlib. General interface ----------------- All of the classes described below derive from and implement the :ref:`Component ` interface. They all have a single access method, called :code:`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. .. _abcToDq0Transform_component: abc to dq0 transformation ------------------------- :code:`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 :code:`transform` method takes four obligatory and one optional :code:`double`-type arguments, one for each phase, the :math:`theta` (:math:`=\omega t`) angle in radians between the `q` and `a` axes, and an optional offset (:math:`\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 :math:`\frac{\pi}{2}`. The method returns a tuple of d, q, zero values. The transformation algorithm is as follows: .. math:: d &= \frac{2}{3} \left( a \cdot sin(\theta + \phi) + b \cdot sin \left( \theta + \phi - \frac{2}{3} \pi \right) + c \cdot sin \left(\theta + \phi + \frac{2}{3} \pi \right) \right) \\ q &= \frac{2}{3} \left(a \cdot cos(\theta + \phi) + b \cdot cos \left(\theta + \phi - \frac{2}{3} \pi \right) + c \cdot cos \left(\theta + \phi + \frac{2}{3} \pi \right) \right) \\ zero &= \frac{1}{3} \left( a + b + c \right) \\ 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: 1. Transform `abc` to :math:`\alpha \beta 0` frame, and then 2. Transform :math:`\alpha\beta 0` to `dq0`. For more details regarding the API, see the :ref:`API documentation for AbcToDq0Transform `. Usage example ^^^^^^^^^^^^^ .. code-block:: cpp #include #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: .. code-block:: cpp #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 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 m_data{0.0}; }; } // namespace fgc::user .. _dq0ToAbcTransform_component: dq0 to abc transformation ------------------------- :code:`Dq0ToAbcTransform` implements the transformation from `dq0` reference frame to three-phase system (`abc`) `dq0`, an inverse of :ref:`AbcToDq0Transform `. The algorithm follows the implementation and nomeclature of the `Inverse Park transformation Matlab implementation `_. The :code:`transform` method takes four obligatory and one optional :code:`double`-type arguments, one for each `dq0` component, the :math:`theta` (:math:`=\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 :math:`\frac{\pi}{2}`. The method returns a tuple of a, b, and c values. The transformation algorithm is as follows: .. math:: a &= d \cdot sin(\theta + \phi) + q \cdot cos(theta + \phi) + zero \\ b &= d \cdot sin(\theta + \phi - \frac{2}{3} \pi) + q \cdot cos(\theta + \phi - \frac{2}{3} \pi) + zero; \\ c &= d \cdot sin(\theta + \phi + \frac{2}{3} \pi) + q \cdot cos(\theta + \phi + \frac{2}{3} \pi) + zero; \\ 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: 1. Transform `dq0` to :math:`\alpha\beta 0` frame, and then 2. Transform :math:`\alpha\beta 0` to `abc`. For more details regarding the API, see the :ref:`API documentation for Dq0ToAbcTransform `. Usage example ^^^^^^^^^^^^^ .. code-block:: cpp #include #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: .. code-block:: cpp #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 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 m_data{0.0}; }; } // namespace fgc::user .. _abcToAlphaBetaTransform_component: abc to alpha-beta transformation -------------------------------- :code:`AbcToAlphaBetaTransform` implements the `abc` to :math:`\alpha\beta0` (Clarke) transformation from three-phase components in the `abc` reference frame to the rotating :math:`\alpha\beta0` frame. The algorithm follows the implementation and nomeclature of the `Inverse Clarke Matlab implementation `_. The :code:`transform` method takes three obligatory :code:`double`-type arguments, one for each `a`, `b`, and `c` component in the `abc` frame of reference. The method returns a tuple of :math:`\alpha`, :math:`\beta`, and `0` values. The calculation is as follows: .. math:: \alpha &= \frac{2}{3} \left( a - \frac{b+c}{2} \right) \\ \beta &= \frac{\sqrt{3}}{3} (b - c) \\ zero &= \frac{1}{3} (a + b + c) For more details regarding the API, see the :ref:`API documentation for AbcToAlphaBetaTransform `. Usage example ^^^^^^^^^^^^^ .. code-block:: cpp #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: .. code-block:: cpp #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 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 m_data{0.0}; }; } // namespace fgc::user .. _alphaBetaToAbcTransform_component: alpha-beta to abc transformation -------------------------------- :code:`AbcToAlphaBetaTransform` implements the :math:`\alpha\beta0` to abc (inverse Clarke) transformation from the rotating :math:`\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 :code:`transform` method takes three obligatory :code:`double`-type arguments, one for each :math:`\alpha`, :math:`\beta`, and `zero` components in the rotating :math:`\alpha\beta0` frame of reference. The method returns a tuple of `a`, `b`, and `c` values. The calculation is as follows: .. math:: a &= \left( \alpha + zero \right) \\ b &= -\frac{1}{2} \alpha + \frac{\sqrt{3}}{2} \beta + zero \\ c &= -\frac{1}{2} \alpha - \frac{\sqrt{3}}{2} \beta + zero For more details regarding the API, see the :ref:`API documentation for AlphaBetaToAbcTransform `. Usage example ^^^^^^^^^^^^^ .. code-block:: cpp #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 } .. _alphaBetaToDq0Transform_component: Alpha-beta to dq0 ----------------- :code:`alphaBetaToDq0Transform` implements the :math:`\alpha\beta0` transformation from three stationary components in the :math:`\alpha\beta0` reference frame to the rotating `dq0` reference frame, an equivalent of the inverse Clarke and then Park transform. The :code:`transform` method takes four obligatory :code:`double`-type arguments and one optional boolean argument: one for each :math:`\alpha`, :math:`\beta`, and `0` component in the :math:`\alpha\beta0` frame of reference, the :math:`theta` angle (in radians) between `q` and :math:`alpha`, and optionally specify alignment: :code:`true` for a-axis alignment or :code:`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: .. math:: d &= \alpha \cdot cos(\theta) + \beta \cdot sin(\theta) \\ q &= -\alpha \cdot sin(\theta) + \beta \cdot cos(\theta) \\ zero &= zero and if the the 90-degrees behind a-axis alignment is preferred: .. math:: d &= \alpha \cdot sin(\theta) - \beta \cdot cos(\theta) \\ q &= \alpha \cdot cos(\theta) + \beta \cdot sin(\theta) \\ zero &= zero For more details regarding the API, see the :ref:`API documentation for AlphaBetaToDq0Transform `. Usage example ^^^^^^^^^^^^^ .. code-block:: cpp #include #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); } .. _dq0ToAlphaBetaTransform_component: dq0 to alpha-beta ----------------- :code:`Dq0ToAlphaBetaTransform` implements the transformation of components in `dq0` frame of reference to the :math:`\alpha\beta0` reference frame, an inverse of :ref:`AlphaBetaToDq0Transformation `. The :code:`transform` method takes four obligatory :code:`double`-type arguments and one optional boolean argument: one for each `d`, `q`, `zero`, and `theta`, and optionally a boolean alignment argument: :code:`true` for a-axis alignment or :code:`false` for 90 degrees behind a-axis. :math:`theta` is the angle (in radians) between `q` and :math:`alpha`. The method returns a tuple of :math:`\alpha`, :math:`\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: .. math:: \alpha &= d \cdot cos(\theta) - q \cdot sin(\theta) \\ \beta &= d \cdot sin(\theta) + q \cdot cos(\theta) \\ zero &= i_zero and if the the 90-degrees behind a-axis alignment is preferred: .. math:: \alpha &= d \cdot sin(\theta) + q \cdot cos(\theta) \\ \beta &= -d \cdot cos(\theta) + q \cdot sin(\theta) \\ zero &= i_zero For more details regarding the API, see the :ref:`API documentation for Dq0ToAlphaBetaTransform `. Usage example ^^^^^^^^^^^^^ .. code-block:: cpp #include #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 :code:`Component` depends on a number of factors. In the case of :ref:`AbcToAlphaBetaTransform `, there no look-up tables and the execution time is independent of the inputs. For :ref:`AbcToDq0Transform ` and :ref:`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 :code:`Components`. .. list-table:: :header-rows: 1 * - Class - Access time [ns] * - AbcToAlphaBetaTransform - 33 * - AbcToDq0Transform - 263 * - AlphaBetaToDq0Transform - 197 * - AlphaBetaToAbcTransform - 27 * - Dq0ToAbcTransform - 270 * - Dq0ToAlphaBetaTransform - 230