motulator_bearingless.gradnet
=============================

.. py:module:: motulator_bearingless.gradnet

.. autoapi-nested-parse::

   Gradient-network magnetic maps of six-phase bearingless synchronous machines.

   This module corresponds to :mod:`motulator.drive.gradnet` and it uses the same softmax
   gradient networks [#Li2026]_, [#Cha2025]_, which are the gradients of a convex scalar
   state function, since `A_0` is positive semidefinite::

       z = A*x + b
       g(x) = A_0*x + b_0 + A.T*softmax(beta*z)

   As in *motulator*, the machine model uses the energy-based current map and the
   controller the co-energy-based flux map. The inputs are extended with the rotor
   displacement. The maps follow from the energy `W(psi_s, q_M, theta_M)` and the co-energy
   `W_c(i_s, q_M)`, cf. [#Das2026]_::

       i_s = (1/3)*dW/dpsi_s       f_M = -dW/dq_M
       psi_s = (1/3)*dW_c/di_s     f_M = dW_c/dq_M

   The maps differ from those of *motulator* in two ways. First, the output of the network
   is averaged over the symmetry group of the bearingless machine, see
   :func:`symmetry_group`, which contains the mirror symmetry about the d-axis. Second,
   checks of the finite-element model at selected operating points indicate that the
   unbalanced magnetic pull is destabilizing also at constant flux linkages, so that the
   energy is concave in the displacement. Therefore, the network of the current map
   approximates the shifted energy `W + k_q*abs(q_M)**2/2` by a convex function. The
   shifted energy is convex where `k_q` exceeds the stiffness of the pull at constant
   currents.

   .. rubric:: References

   .. [#Li2026] Li, Foissner, Martin, Piippo, Hinkkanen, "Gradient networks for universal
      magnetic modeling of synchronous machines," 2026, https://arxiv.org/abs/2602.14947

   .. [#Cha2025] Chaudhari, Pranav, Moura, "Gradient networks," IEEE Trans. Signal
      Process., 2025, https://doi.org/10.1109/TSP.2024.3496692

   .. [#Das2026] Das, Martin, Kontodinas, Hinkkanen, "Direct force control of six-phase
      bearingless synchronous machines," Proc. ICEM, 2026,
      https://doi.org/10.1109/ICEM68283.2026.11757980

   ..
       !! processed by numpydoc !!


Classes
-------

.. autoapisummary::

   motulator_bearingless.gradnet.CurrentMap
   motulator_bearingless.gradnet.CurrentMapWithHarmonics
   motulator_bearingless.gradnet.FluxMap
   motulator_bearingless.gradnet.GradNetFunction


Functions
---------

.. autoapisummary::

   motulator_bearingless.gradnet.load_gradnet
   motulator_bearingless.gradnet.symmetry_group


Module Contents
---------------

.. py:class:: CurrentMap(model)

   Bases: :py:obj:`_SymmetrizedMap`


   
   Energy-based current map for the machine model, without spatial harmonics.

   The map corresponds to :class:`motulator.drive.gradnet.CurrentMap`.

   :param model: Trained GradNet for the current map, see :func:`load_gradnet`.
   :type model: GradNetFunction















   ..
       !! processed by numpydoc !!

.. py:class:: CurrentMapWithHarmonics(model)

   Bases: :py:obj:`_SymmetrizedMap`


   
   Energy-based current map for the machine model, with spatial harmonics.

   The map corresponds to :class:`motulator.drive.gradnet.CurrentMapWithHarmonics`. The
   rotor angle enters as the periodic features `exp(1j*k*theta_M)`, whose orders `k`
   are saved with the network.

   :param model: Trained GradNet for the current map with harmonics, see :func:`load_gradnet`.
   :type model: GradNetFunction















   ..
       !! processed by numpydoc !!

.. py:class:: FluxMap(model)

   Bases: :py:obj:`_SymmetrizedMap`


   
   Co-energy-based flux map for the controller, without spatial harmonics.

   The map corresponds to :class:`motulator.drive.gradnet.FluxMap`. The network is
   trained without the rotor angle on data at different rotor angles, so that it
   approximates the average over the angle.

   :param model: Trained GradNet for the flux map, see :func:`load_gradnet`.
   :type model: GradNetFunction















   ..
       !! processed by numpydoc !!

   .. py:method:: jacobian(i_s1, i_s2, q_M)

      
      Jacobian matrix of the map.

      :returns: Jacobian matrix of the outputs `(psi_s1, psi_s2, f_M)` with respect to the
                inputs `(i_s1, i_s2, q_M)` as pairs of real numbers in SI units.
      :rtype: ndarray, shape (..., 6, 6)















      ..
          !! processed by numpydoc !!


.. py:class:: GradNetFunction

   Bases: :py:obj:`motulator.drive.gradnet.GradNetFunction`


   
   Trained GradNet of a bearingless machine as a numpy function.

   This function extends :class:`motulator.drive.gradnet.GradNetFunction` with the
   quantities needed by the maps of this module, so that they are saved together with
   the network. It also computes the Jacobian of a softmax module as
   `beta*(sum(s_j*a_j*a_j.T) - h*h.T)`, where `s` is the activation and `h = A.T*s`,
   without matrix products of the size of the number of the hidden units.

   :param map_type: Type of the map, `"current_map"` or `"flux_map"`, defaults to the latter.
   :type map_type: str, optional
   :param k: Orders of the periodic features of the rotor angle, defaults to no features.
   :type k: tuple[int, ...], optional
   :param q_base: Base value of the displacement (m), defaults to 1.
   :type q_base: float, optional
   :param k_q: Per-unit coefficient of the quadratic term of the energy, zero in the flux maps.
   :type k_q: float, optional















   ..
       !! processed by numpydoc !!

.. py:function:: load_gradnet(model_path)

   
   Load a trained GradNet from an npz file.

   :param model_path: Path to the saved model file, see
                      :meth:`motulator.drive.gradnet.GradNetFunction.save`.
   :type model_path: Path | str

   :returns: Trained network as a numpy function.
   :rtype: GradNetFunction















   ..
       !! processed by numpydoc !!

.. py:function:: symmetry_group(k = ())

   
   Symmetry group of the machine acting on the inputs of the network.

   The rotor-coordinate inputs are `(x_s1, x_s2, q_M, exp(1j*k*theta_M))` as pairs of
   real numbers, where `x_s` is the flux linkage or the current. The state function of
   a four-pole rotor in a symmetrical six-phase stator without zero-sequence currents
   is periodic in the rotor angle with the period of 60 deg and invariant under the
   following generators:

   - reversal of the currents, `(-i_s1, -i_s2, q_M, theta_M)`,
   - mirroring about the d-axis, `(conj(i_s1), conj(i_s2), conj(q_M), -theta_M)`, and
   - turning the rotor by 90 deg and the stator by 60 deg in the opposite direction,
     `(-1j*i_s1, -i_s2, -1j*q_M, theta_M + 30 deg)`.

   :param k: Orders of the periodic features of the rotor angle, multiples of 6.
   :type k: tuple[int, ...], optional

   :returns: Orthogonal matrices acting on the input vector of the dimension
             `n = 6 + 2*len(k)`.
   :rtype: ndarray, shape (16, n, n)

   .. rubric:: Examples

   >>> import numpy as np
   >>> from motulator_bearingless.gradnet import symmetry_group
   >>> G = symmetry_group((6, 36))
   >>> G.shape
   (16, 10, 10)
   >>> bool(np.allclose(G @ G.transpose(0, 2, 1), np.eye(10)))
   True















   ..
       !! processed by numpydoc !!

