From 5e51db089c3d72b681bcd3ee6ecc31408755b649 Mon Sep 17 00:00:00 2001 From: Marko Hinkkanen Date: Thu, 24 Apr 2025 23:50:32 +0300 Subject: [PATCH] Minor fixes --- docs/source/control/common/control_system.rst | 4 ++-- docs/source/control/drive/current_ctrl.rst | 4 ++-- docs/source/control/drive/observers.rst | 12 +++++------- docs/source/control/drive/speed_ctrl.rst | 2 +- docs/source/control/grid/index.rst | 2 +- docs/source/model/drive/ac_filter.rst | 2 +- docs/source/model/drive/diode_bridge.rst | 2 +- docs/source/model/drive/machines.rst | 8 ++++---- docs/source/model/drive/mechanics.rst | 4 ++-- examples/drive/current_vector/README.txt | 2 +- ..._ctrl_im_2kw.py => plot_current_vector_im_2kw.py} | 0 ...mode.py => plot_current_vector_im_2kw_tq_mode.py} | 0 ...l_pmsm_2kw.py => plot_current_vector_pmsm_2kw.py} | 0 ...iode.py => plot_current_vector_pmsm_2kw_diode.py} | 0 ...sat.py => plot_current_vector_pmsyrm_thor_sat.py} | 0 ...l_syrm_7kw.py => plot_current_vector_syrm_7kw.py} | 0 examples/drive/vhz/README.txt | 2 +- ...obs_vhz_ctrl_im_2kw.py => plot_obs_vhz_im_2kw.py} | 0 ...vhz_ctrl_pmsm_2kw.py => plot_obs_vhz_pmsm_2kw.py} | 0 ...two_mass.py => plot_obs_vhz_pmsm_2kw_two_mass.py} | 0 ..._syrm_7kw_sat.py => plot_obs_vhz_syrm_7kw_sat.py} | 2 +- .../{plot_vhz_ctrl_im_2kw.py => plot_vhz_im_2kw.py} | 0 ...t_vhz_ctrl_im_2kw_lc.py => plot_vhz_im_2kw_lc.py} | 0 examples/grid/grid_forming/plot_gfm_rfpsc_13kva.py | 2 +- motulator/__init__.py | 8 +++----- motulator/drive/control/__init__.py | 3 +-- motulator/drive/control/_sm_observers.py | 4 ++-- motulator/drive/control/sm.py | 8 +++++++- motulator/drive/utils/__init__.py | 2 +- motulator/grid/control/__init__.py | 6 +++--- motulator/grid/control/_gfm_psc.py | 6 +++--- motulator/grid/utils/__init__.py | 2 +- 32 files changed, 44 insertions(+), 43 deletions(-) rename examples/drive/current_vector/{plot_vector_ctrl_im_2kw.py => plot_current_vector_im_2kw.py} (100%) rename examples/drive/current_vector/{plot_vector_ctrl_im_2kw_tq_mode.py => plot_current_vector_im_2kw_tq_mode.py} (100%) rename examples/drive/current_vector/{plot_vector_ctrl_pmsm_2kw.py => plot_current_vector_pmsm_2kw.py} (100%) rename examples/drive/current_vector/{plot_vector_ctrl_pmsm_2kw_diode.py => plot_current_vector_pmsm_2kw_diode.py} (100%) rename examples/drive/current_vector/{plot_vector_ctrl_pmsyrm_thor_sat.py => plot_current_vector_pmsyrm_thor_sat.py} (100%) rename examples/drive/current_vector/{plot_vector_ctrl_syrm_7kw.py => plot_current_vector_syrm_7kw.py} (100%) rename examples/drive/vhz/{plot_obs_vhz_ctrl_im_2kw.py => plot_obs_vhz_im_2kw.py} (100%) rename examples/drive/vhz/{plot_obs_vhz_ctrl_pmsm_2kw.py => plot_obs_vhz_pmsm_2kw.py} (100%) rename examples/drive/vhz/{plot_obs_vhz_ctrl_pmsm_2kw_two_mass.py => plot_obs_vhz_pmsm_2kw_two_mass.py} (100%) rename examples/drive/vhz/{plot_obs_vhz_ctrl_syrm_7kw_sat.py => plot_obs_vhz_syrm_7kw_sat.py} (97%) rename examples/drive/vhz/{plot_vhz_ctrl_im_2kw.py => plot_vhz_im_2kw.py} (100%) rename examples/drive/vhz/{plot_vhz_ctrl_im_2kw_lc.py => plot_vhz_im_2kw_lc.py} (100%) diff --git a/docs/source/control/common/control_system.rst b/docs/source/control/common/control_system.rst index e9801b0fd..10eb065cb 100644 --- a/docs/source/control/common/control_system.rst +++ b/docs/source/control/common/control_system.rst @@ -1,5 +1,5 @@ -Protocol -======== +Control System Framework +======================== Main Control Loop ----------------- diff --git a/docs/source/control/drive/current_ctrl.rst b/docs/source/control/drive/current_ctrl.rst index a85204ddb..d4bebf04e 100644 --- a/docs/source/control/drive/current_ctrl.rst +++ b/docs/source/control/drive/current_ctrl.rst @@ -114,7 +114,7 @@ An internal change of the state variable from the stator current to the stator f \hat{\boldsymbol{\psi}_\mathrm{s}} &= \hat{L}_\mathrm{d}\mathrm{Re}\{\boldsymbol{i}_\mathrm{s}\} + \mathrm{j} \hat{L}_\mathrm{q}\mathrm{Im}\{\boldsymbol{i}_\mathrm{s}\} :label: flux_mapping_sm -This choice of using the flux linkage as the internal state has some advantages: the gain expressions become simpler; the magnetic saturation would be more convenient to take into account; and the same control structure can be used for salient and non-salient machines. +This choice of using the flux linkage as the internal state has some advantages: the gain expressions become simpler; the magnetic saturation is easier to take into account; and the same control structure can be used for salient and non-salient machines. Here, the complex vector design is considered. Hence, the controller :eq:`cc` can be rewritten as @@ -138,7 +138,7 @@ The gain selection analogous to :eq:`complex_vector_gains` becomes Assume accurate parameter estimates and perfect alignment of the controller coordinate system with the rotor coordinate system. Then, using :eq:`sm_model`, :eq:`flux_mapping_sm`, and :eq:`cc_flux`, the closed-loop system can be shown to be analogous to the induction machine case. -This control design corresponds to the implementation in the :class:`motulator.drive.control.sm.CurrentController` class. In the case of saturated synchronous machine, the nonlinear flux linkage map can be used to replace the linear magnetics in :eq:`flux_mapping_sm`, see :class:`motulator.drive.control.sm.CurrentController` and :class:`motulator.drive.control.sm.SaturatedSynchronousMachinePars`. +This control design corresponds to the implementation in the :class:`motulator.drive.control.sm.CurrentController` class. In the case of saturated synchronous machine, the nonlinear flux linkage map can be used to replace the linear magnetics in :eq:`flux_mapping_sm`, see :class:`motulator.drive.control.sm.SaturatedSynchronousMachinePars`. .. rubric:: References diff --git a/docs/source/control/drive/observers.rst b/docs/source/control/drive/observers.rst index 87e13b234..ce002442b 100644 --- a/docs/source/control/drive/observers.rst +++ b/docs/source/control/drive/observers.rst @@ -153,7 +153,7 @@ In sensorless control of synchronous machine drives, the rotor position and spee Machine Model in General Coordinates ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -In :doc:`/model/drive/machines`, the synchronous machine model is given in rotor coordinates. For the observer design and analysis, it is convenient to express this model in general coordinates, aligned at :math:`\vartheta_\mathrm{s}` and rotating at :math:`\omega_\mathrm{s} = \mathrm{d} \vartheta_\mathrm{s}/\mathrm{d} t` with respect to stator coordinates. Furthermore, the rotor is aligned at :math:`\vartheta_\mathrm{m}` and rotates at :math:`\omega_\mathrm{m} = \mathrm{d} \vartheta_\mathrm{m}/\mathrm{d} t` with respect to stator coordinates. This coordinate transformation results in +In the :ref:`synchronous-machine` document, the synchronous machine model is given in rotor coordinates. For the observer design and analysis, it is convenient to express this model in general coordinates, aligned at :math:`\vartheta_\mathrm{s}` and rotating at :math:`\omega_\mathrm{s} = \mathrm{d} \vartheta_\mathrm{s}/\mathrm{d} t` with respect to stator coordinates. Furthermore, the rotor is aligned at :math:`\vartheta_\mathrm{m}` and rotates at :math:`\omega_\mathrm{m} = \mathrm{d} \vartheta_\mathrm{m}/\mathrm{d} t` with respect to stator coordinates. This coordinate transformation results in .. math:: \frac{\mathrm{d}\boldsymbol{\psi}_\mathrm{s}}{\mathrm{d} t} &= \boldsymbol{u}_\mathrm{s} - R_\mathrm{s}\boldsymbol{i}_\mathrm{s} - \mathrm{j}\omega_\mathrm{s}\boldsymbol{\psi}_\mathrm{s} \\ @@ -189,7 +189,7 @@ where :math:`\hat{\boldsymbol{\psi}}_\mathrm{s}` is the stator flux estimate. Th where :math:`\boldsymbol{k}_1` and :math:`\boldsymbol{k}_2` are gains (complex in a general case), the estimates are marked with the hat, and :math:`^*` marks the complex conjugate. -In the sensored mode, :math:`\omega_\mathrm{s} = \omega_\mathrm{m}` is used. In the sensorless mode, the speed-adaptive structure (which would correspond to the phase-locked loop if the observer were implemented in stator coordinates) can be used to estimate the rotor angle and speed, respectively, as +In sensored mode, :math:`\omega_\mathrm{s} = \omega_\mathrm{m}` is used. In the sensorless mode, the speed-adaptive structure (which would correspond to the phase-locked loop if the observer were implemented in stator coordinates) can be used to estimate the rotor angle and speed, respectively, as .. math:: \frac{\mathrm{d} \hat{\omega}_\mathrm{m}}{\mathrm{d} t} &= \mathrm{Im}\{\boldsymbol{k}_\mathrm{i} \boldsymbol{e}\} \\ @@ -211,7 +211,7 @@ Gain Selection Sensored Case """"""""""""" -In the sensored case, the gain :math:`\boldsymbol{k}_2=0` can be set in :eq:`sm_flux_observer`. Furthermore, :math:`\delta=0` holds. Therefore, using :eq:`sm` and :eq:`sm_flux_observer`, the linearized estimation error dynamics become +In sensored case, the gain :math:`\boldsymbol{k}_2=0` can be set in :eq:`sm_flux_observer`. Furthermore, :math:`\delta=0` holds. Therefore, using :eq:`sm` and :eq:`sm_flux_observer`, the linearized estimation error dynamics become .. math:: \frac{\mathrm{d} \Delta\tilde{\boldsymbol{\psi}}_\mathrm{s}}{\mathrm{d} t} = -(\boldsymbol{k}_1 + \mathrm{j}\omega_\mathrm{m0})\Delta\tilde{\boldsymbol{\psi}}_\mathrm{s} @@ -230,7 +230,7 @@ To decouple the flux estimation from the rotor angle, the gains of :eq:`sm_flux_ \boldsymbol{k}_1 = \sigma \qquad \boldsymbol{k}_2 = \frac{\sigma\hat{\boldsymbol{\psi}}_\mathrm{a}}{\hat{\boldsymbol{\psi}}_\mathrm{a}^*} :label: k1k2_sensorless -where :math:`\sigma` is the desired decay rate of the flux estimation error and +where :math:`\sigma` is the desired decay rate of the flux estimation error and the auxiliary flux is defined as .. math:: \hat{\boldsymbol{\psi}}_\mathrm{a} = \psi_\mathrm{f} + (L_\mathrm{d} - L_\mathrm{q}) \boldsymbol{i}_\mathrm{s}^* @@ -257,7 +257,7 @@ where :math:`\alpha_\mathrm{o}` is the desired speed-estimation bandwidth. The c :label: speed_est_dyn .. note:: - The flux linkage :math:`\boldsymbol{\psi}_\mathrm{a}` is called the auxiliary flux linkage in [#Hin2018]_. It is also linked to the maximum-torque-per-ampere (MTPA) condition, which can be compactly expressed as :math:`\mathrm{Re}\{\boldsymbol{i}_\mathrm{s}\boldsymbol{\psi}_\mathrm{a}^*\}=0` [#Var2021]_. + The auxiliary flux is also linked to the maximum-torque-per-ampere (MTPA) condition that can be compactly expressed as :math:`\mathrm{Re}\{\boldsymbol{i}_\mathrm{s}\boldsymbol{\psi}_\mathrm{a}^*\}=0`, see :eq:`sm_mtpa`. .. rubric:: References @@ -266,5 +266,3 @@ where :math:`\alpha_\mathrm{o}` is the desired speed-estimation bandwidth. The c .. [#Cap2001] Capecchi, Guglielmo, Pastorelli, Vagati, “Position-sensorless control of the transverse-laminated synchronous reluctance motor,” IEEE Trans. Ind. Appl., 2001, https://doi.org/10.1109/28.968190 .. [#Hin2018] Hinkkanen, Saarakkala, Awan, Mölsä, Tuovinen, "Observers for sensorless synchronous motor drives: Framework for design and analysis," IEEE Trans. Ind. Appl., 2018, https://doi.org/10.1109/TIA.2018.2858753 - -.. [#Var2021] Varatharajan, Pellegrino, Armando, “Direct flux vector control of synchronous motor drives: A small-signal model for optimal reference generation,” IEEE Trans. Power Electron., 2021, https://doi.org/10.1109/TPEL.2021.3067694 diff --git a/docs/source/control/drive/speed_ctrl.rst b/docs/source/control/drive/speed_ctrl.rst index 3d00ac19c..7b74f3c73 100644 --- a/docs/source/control/drive/speed_ctrl.rst +++ b/docs/source/control/drive/speed_ctrl.rst @@ -1,7 +1,7 @@ Speed Control ============= -A speed controller is implemented in the :class:`motulator.drive.control.SpeedController` class, whose base class is :class:`motulator.common.control.PIController`. In the following, the tuning of the speed controller is discussed. The presented approach can be extended to many other control tasks as well. +A speed controller is implemented in the :class:`motulator.drive.control.im.SpeedController` class, whose base class is :class:`motulator.common.control.PIController`. In the following, the tuning of the speed controller is discussed. The presented approach can be extended to many other control tasks as well. .. _2dof-pi-controller: diff --git a/docs/source/control/grid/index.rst b/docs/source/control/grid/index.rst index 4e4a3f0e0..104936049 100644 --- a/docs/source/control/grid/index.rst +++ b/docs/source/control/grid/index.rst @@ -2,7 +2,7 @@ Grid Converters *************** -Design notes for selected control methods for grid-connected converters are provided in this section. The aim of these notes is to link the implemented methods to the theory and to provide a reference for the implementation. Further details are available in the references provided. +Design notes for selected control methods of grid converters are provided in this section. The aim of these notes is to link the implemented methods to the theory and to provide a reference for the implementation. Further details are available in the references provided. .. toctree:: :titlesonly: diff --git a/docs/source/model/drive/ac_filter.rst b/docs/source/model/drive/ac_filter.rst index 3c41624dd..18532e445 100644 --- a/docs/source/model/drive/ac_filter.rst +++ b/docs/source/model/drive/ac_filter.rst @@ -33,7 +33,7 @@ A dynamic model of the filter is where :math:`L_\mathrm{f}` is the filter inductance, :math:`R_\mathrm{f}` is the series resistance of the filter inductor, and :math:`C_\mathrm{f}` the filter capacitance. Furthermore, :math:`\boldsymbol{i}_\mathrm{c}^\mathrm{s}` is the converter current, :math:`\boldsymbol{i}_\mathrm{s}^\mathrm{s}` is the stator current, :math:`\boldsymbol{u}_\mathrm{c}^\mathrm{s}` is the converter voltage, and :math:`\boldsymbol{u}_\mathrm{s}^\mathrm{s}` is the capacitor voltage (corresponding to the stator voltage). -The filter model is implemented in the class :class:`motulator.drive.model.LCFilter`. For its usage, see the example :doc:`/drive_examples/vhz/plot_vhz_ctrl_im_2kw_lc`. +The filter model is implemented in the class :class:`motulator.drive.model.LCFilter`. For its usage, see the example :doc:`/drive_examples/vhz/plot_vhz_im_2kw_lc`. .. rubric:: References diff --git a/docs/source/model/drive/diode_bridge.rst b/docs/source/model/drive/diode_bridge.rst index 3e75ee065..432d2f4dd 100644 --- a/docs/source/model/drive/diode_bridge.rst +++ b/docs/source/model/drive/diode_bridge.rst @@ -28,4 +28,4 @@ where :math:`i_\mathrm{L}` is the DC-bus current, :math:`u_\mathrm{di}` is the v Six-pulse diode bridge rectifier. -The voltage-source converter described in the :doc:`/model/common/converters` document is extended with this diode bridge model in the :class:`motulator.drive.model.FrequencyConverter` class. Examples using the six-pulse diode bridge can be found in :doc:`/drive_examples/vhz/plot_vhz_ctrl_im_2kw` and :doc:`/drive_examples/current_vector/plot_vector_ctrl_pmsm_2kw_diode`. +The voltage-source converter described in the :doc:`/model/common/converters` document is extended with this diode bridge model in the :class:`motulator.drive.model.FrequencyConverter` class. Examples using the six-pulse diode bridge can be found in :doc:`/drive_examples/vhz/plot_vhz_im_2kw` and :doc:`/drive_examples/current_vector/plot_current_vector_pmsm_2kw_diode`. diff --git a/docs/source/model/drive/machines.rst b/docs/source/model/drive/machines.rst index f4c06b656..c04d6f43f 100644 --- a/docs/source/model/drive/machines.rst +++ b/docs/source/model/drive/machines.rst @@ -64,7 +64,7 @@ where :math:`L_\mathrm{s}` is the stator inductance and :math:`L_\ell` is the le \tau_\mathrm{M} = \frac{3 n_\mathrm{p}}{2}\mathrm{Im} \left\{\boldsymbol{i}_\mathrm{s}^\mathrm{s} (\boldsymbol{\psi}_\mathrm{s}^\mathrm{s})^* \right\} :label: im_torque -The same class can also be used with the main-flux saturation models, such as :math:`L_\mathrm{s} = L_\mathrm{s}(\psi_\mathrm{s})` [#Qu2012]_. See also the example :doc:`/drive_examples/current_vector/plot_vector_ctrl_im_2kw`. +The same class can also be used with the main-flux saturation models, such as :math:`L_\mathrm{s} = L_\mathrm{s}(\psi_\mathrm{s})` [#Qu2012]_. See also the example :doc:`/drive_examples/current_vector/plot_current_vector_im_2kw`. .. note:: If the magnetic saturation is omitted, the Γ model is mathematically identical to the inverse-Γ and T models. For example, the parameters of the Γ model can be transformed to those of the inverse-Γ model parameters as follows: @@ -173,7 +173,7 @@ The linear magnetic model :eq:`sm_flux` can be replaced with :math:`\boldsymbol{ \psi_\mathrm{q} &= \psi_\mathrm{q}(i_\mathrm{d}, i_\mathrm{q}) :label: sm_flux_sat -are nonlinear in the components of the current vector :math:`\boldsymbol{i}_\mathrm{s} = i_\mathrm{d} + \mathrm{j} i_\mathrm{q}`. Other equations of the model remain the same. The flux linkage maps are numerically invertible. These maps are often modeled either in a form of lookup tables or explicit functions [#Hin2017]_, [#Lel2024]_. The magnetic saturation can be parametrized using the data class :class:`motulator.drive.model.SaturatedSynchronousMachinePars`. Furthermore, methods for manipulating and plotting the flux map data are provided, see the class :class:`motulator.drive.utils.MagneticModel`, :func:`motulator.drive.utils.plot_maps`, and :func:`motulator.drive.utils.plot_flux_vs_current`. See also the examples :doc:`/drive_examples/flux_vector/plot_flux_vector_pmsyrm_5kw_sat`, :doc:`/drive_examples/flux_vector/plot_flux_vector_syrm_7kw_sat`, and :doc:`/drive_examples/current_vector/plot_vector_ctrl_pmsyrm_thor_sat`. +are nonlinear in the components of the current vector :math:`\boldsymbol{i}_\mathrm{s} = i_\mathrm{d} + \mathrm{j} i_\mathrm{q}`. Other equations of the model remain the same. The flux linkage maps are numerically invertible. These maps are often modeled either in a form of lookup tables or explicit functions [#Hin2017]_, [#Lel2024]_. The magnetic saturation can be parametrized using the data class :class:`motulator.drive.model.SaturatedSynchronousMachinePars`. Furthermore, methods for manipulating and plotting the flux map data are provided, see the class :class:`motulator.drive.utils.MagneticModel`, :func:`motulator.drive.utils.plot_maps`, and :func:`motulator.drive.utils.plot_flux_vs_current`. See also the examples :doc:`/drive_examples/flux_vector/plot_flux_vector_pmsyrm_5kw_sat`, :doc:`/drive_examples/flux_vector/plot_flux_vector_syrm_7kw_sat`, and :doc:`/drive_examples/current_vector/plot_current_vector_pmsyrm_thor_sat`. MTPA and MTPV Conditions ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -190,7 +190,7 @@ where the star operator denotes the complex conjugate. The auxiliary flux vector \boldsymbol{\psi}_\mathrm{a} = \boldsymbol{\psi}_\mathrm{s} - L_\mathrm{qq} i_\mathrm{d} - \mathrm{j} L_\mathrm{dd} i_\mathrm{q} + \mathrm{j} L_\mathrm{dq} \boldsymbol{i}_\mathrm{s}^* :label: sm_mtpa_aux -where :math:`L_\mathrm{dd} = \partial \psi_\mathrm{d}/\partial i_\mathrm{d}`, :math:`L_\mathrm{qq} = \partial \psi_\mathrm{q}/\partial i_\mathrm{q}`, and :math:`L_\mathrm{dq} = \partial \psi_\mathrm{d}/\partial i_\mathrm{q}` are the incremental inductances obtained from :eq:`sm_flux_sat`. Notice that the auxiliary flux is a function of the stator current, :math:`\boldsymbol{\psi}_\mathrm{a} = \boldsymbol{\psi}_\mathrm{a}(\boldsymbol{i}_\mathrm{s})`. +where :math:`L_\mathrm{dd} = \partial \psi_\mathrm{d}/\partial i_\mathrm{d}`, :math:`L_\mathrm{qq} = \partial \psi_\mathrm{q}/\partial i_\mathrm{q}`, and :math:`L_\mathrm{dq} = \partial \psi_\mathrm{d}/\partial i_\mathrm{q}` are the incremental inductances obtained from :eq:`sm_flux_sat`. Notice that the auxiliary flux is a function of the stator current, :math:`\boldsymbol{\psi}_\mathrm{a} = \boldsymbol{\psi}_\mathrm{a}(\boldsymbol{i}_\mathrm{s})`. The maximum-torque-per-volt (MTPV) condition can be derived similarly, resulting in @@ -206,7 +206,7 @@ The auxiliary current vector :math:`\boldsymbol{\psi}_\mathrm{a}` is defined as where :math:`\Gamma_\mathrm{dd} = \partial i_\mathrm{d}/\partial \psi_\mathrm{d}`, :math:`\Gamma_\mathrm{qq} = \partial i_\mathrm{q}/\partial \psi_\mathrm{q}`, and :math:`\Gamma_\mathrm{dq} = \partial i_\mathrm{d}/\partial \psi_\mathrm{q}` are the incremental inverse inductances. The auxiliary current is a function of the flux linkage, :math:`\boldsymbol{i}_\mathrm{a} = \boldsymbol{i}_\mathrm{a}(\boldsymbol{\psi}_\mathrm{s})`. The data class :class:`motulator.drive.model.SaturatedSynchronousMachinePars` contains methods for computing auxiliary flux and current vectors based on the given magnetic model. In addition to optimal reference generation, these vectors are useful in sensorless observers and flux-vector control [#Tii2025a]_. -The MTPA and MTPV conditions in :eq:`sm_mtpa` and :eq:`sm_mtpv` are realized in the class :class:`motulator.drive.utils.ControlLoci` that provides methods for computing the MTPA, MTPV, and constant current loci for magnetically linear as well as saturated machines. The class :class:`motulator.drive.utils.MachineCharacteristics` provides methods for visualizing these loci. See also the examples :doc:`/drive_examples/flux_vector/plot_flux_vector_pmsyrm_5kw_sat`, :doc:`/drive_examples/flux_vector/plot_flux_vector_syrm_7kw_sat`, and :doc:`/drive_examples/current_vector/plot_vector_ctrl_pmsyrm_thor_sat`. +The MTPA and MTPV conditions in :eq:`sm_mtpa` and :eq:`sm_mtpv` are realized in the class :class:`motulator.drive.utils.ControlLoci` that provides methods for computing the MTPA, MTPV, and constant current loci for magnetically linear as well as saturated machines. The class :class:`motulator.drive.utils.MachineCharacteristics` provides methods for visualizing these loci. See also the examples :doc:`/drive_examples/flux_vector/plot_flux_vector_pmsyrm_5kw_sat`, :doc:`/drive_examples/flux_vector/plot_flux_vector_syrm_7kw_sat`, and :doc:`/drive_examples/current_vector/plot_current_vector_pmsyrm_thor_sat`. .. note:: Here, we define the auxiliary vectors according to the conventions used in [#Hin2018]_, which differ from the conventions in [#Var2022]_, i.e., the vectors defined here are 90 degrees rotated as compared to [#Var2022]_. diff --git a/docs/source/model/drive/mechanics.rst b/docs/source/model/drive/mechanics.rst index ff74c457b..661b0daa3 100644 --- a/docs/source/model/drive/mechanics.rst +++ b/docs/source/model/drive/mechanics.rst @@ -54,7 +54,7 @@ where :math:`\omega_\mathrm{L}` is the angular speed of the load, :math:`\varthe \tau_\mathrm{S} = K_\mathrm{S}\vartheta_\mathrm{ML} + C_\mathrm{S}(\omega_\mathrm{M} - \omega_\mathrm{L}) :label: shaft_torque -where :math:`K_\mathrm{S}` is the torsional stiffness of the shaft, and :math:`C_\mathrm{S}` is the torsional damping of the shaft. The other quantities correspond to those defined for the stiff mechanical system. A two-mass mechanical system is modeled in the class :class:`motulator.drive.model.TwoMassMechanicalSystem`. See also the example in :doc:`/drive_examples/vhz/plot_obs_vhz_ctrl_pmsm_2kw_two_mass`. +where :math:`K_\mathrm{S}` is the torsional stiffness of the shaft, and :math:`C_\mathrm{S}` is the torsional damping of the shaft. The other quantities correspond to those defined for the stiff mechanical system. A two-mass mechanical system is modeled in the class :class:`motulator.drive.model.TwoMassMechanicalSystem`. See also the example in :doc:`/drive_examples/vhz/plot_obs_vhz_pmsm_2kw_two_mass`. .. figure:: ../figs/two_mass_block.svg :figclass: only-light @@ -77,4 +77,4 @@ where :math:`K_\mathrm{S}` is the torsional stiffness of the shaft, and :math:`C Externally Specified Rotor Speed -------------------------------- -It is also possible to omit the mechanical dynamics and directly specify the actual rotor speed :math:`\omega_\mathrm{M}` as a function of time, see the class :class:`motulator.drive.model.ExternalRotorSpeed`. This feature is typically needed when torque-control mode is studied, see the example :doc:`/drive_examples/current_vector/plot_vector_ctrl_im_2kw_tq_mode`. +It is also possible to omit the mechanical dynamics and directly specify the actual rotor speed :math:`\omega_\mathrm{M}` as a function of time, see the class :class:`motulator.drive.model.ExternalRotorSpeed`. This feature is typically needed when torque-control mode is studied, see the example :doc:`/drive_examples/current_vector/plot_current_vector_im_2kw_tq_mode`. diff --git a/examples/drive/current_vector/README.txt b/examples/drive/current_vector/README.txt index 5219193d4..d3b76e76f 100644 --- a/examples/drive/current_vector/README.txt +++ b/examples/drive/current_vector/README.txt @@ -1,4 +1,4 @@ Current-Vector Control ---------------------- -These examples are for current-vector control of induction and synchronous machines. The magnetic saturation model of an induction machine is also demonstrated (:doc:`/drive_examples/current_vector/plot_vector_ctrl_im_2kw`) as well as computation of control lookup tables for synchronous machines (:doc:`/drive_examples/current_vector/plot_vector_ctrl_pmsyrm_thor_sat`). +These examples are for current-vector control of induction and synchronous machines. The magnetic saturation model of an induction machine is also demonstrated (:doc:`/drive_examples/current_vector/plot_current_vector_im_2kw`) as well as computation of control lookup tables for synchronous machines (:doc:`/drive_examples/current_vector/plot_current_vector_pmsyrm_thor_sat`). diff --git a/examples/drive/current_vector/plot_vector_ctrl_im_2kw.py b/examples/drive/current_vector/plot_current_vector_im_2kw.py similarity index 100% rename from examples/drive/current_vector/plot_vector_ctrl_im_2kw.py rename to examples/drive/current_vector/plot_current_vector_im_2kw.py diff --git a/examples/drive/current_vector/plot_vector_ctrl_im_2kw_tq_mode.py b/examples/drive/current_vector/plot_current_vector_im_2kw_tq_mode.py similarity index 100% rename from examples/drive/current_vector/plot_vector_ctrl_im_2kw_tq_mode.py rename to examples/drive/current_vector/plot_current_vector_im_2kw_tq_mode.py diff --git a/examples/drive/current_vector/plot_vector_ctrl_pmsm_2kw.py b/examples/drive/current_vector/plot_current_vector_pmsm_2kw.py similarity index 100% rename from examples/drive/current_vector/plot_vector_ctrl_pmsm_2kw.py rename to examples/drive/current_vector/plot_current_vector_pmsm_2kw.py diff --git a/examples/drive/current_vector/plot_vector_ctrl_pmsm_2kw_diode.py b/examples/drive/current_vector/plot_current_vector_pmsm_2kw_diode.py similarity index 100% rename from examples/drive/current_vector/plot_vector_ctrl_pmsm_2kw_diode.py rename to examples/drive/current_vector/plot_current_vector_pmsm_2kw_diode.py diff --git a/examples/drive/current_vector/plot_vector_ctrl_pmsyrm_thor_sat.py b/examples/drive/current_vector/plot_current_vector_pmsyrm_thor_sat.py similarity index 100% rename from examples/drive/current_vector/plot_vector_ctrl_pmsyrm_thor_sat.py rename to examples/drive/current_vector/plot_current_vector_pmsyrm_thor_sat.py diff --git a/examples/drive/current_vector/plot_vector_ctrl_syrm_7kw.py b/examples/drive/current_vector/plot_current_vector_syrm_7kw.py similarity index 100% rename from examples/drive/current_vector/plot_vector_ctrl_syrm_7kw.py rename to examples/drive/current_vector/plot_current_vector_syrm_7kw.py diff --git a/examples/drive/vhz/README.txt b/examples/drive/vhz/README.txt index a53314e0a..b57b99319 100644 --- a/examples/drive/vhz/README.txt +++ b/examples/drive/vhz/README.txt @@ -1,7 +1,7 @@ V/Hz Control ------------ -These examples demonstrate observer-based V/Hz control for synchronous machines [#Tii2025aa]_ and induction machines [#Tii2025bb]_. The example :doc:`/drive_examples/vhz/plot_obs_vhz_ctrl_pmsm_2kw_two_mass` demonstrates the use of a two-mass mechanics model. Furthermore, the examples :doc:`/drive_examples/vhz/plot_vhz_ctrl_im_2kw` and :doc:`/drive_examples/vhz/plot_vhz_ctrl_im_2kw_lc` show operation of an induction machine under pure open-loop V/Hz control with a diode front-end rectifier and with an LC filter, respectively. +These examples demonstrate observer-based V/Hz control for synchronous machines [#Tii2025aa]_ and induction machines [#Tii2025bb]_. The example :doc:`/drive_examples/vhz/plot_obs_vhz_pmsm_2kw_two_mass` demonstrates the use of a two-mass mechanics model. Furthermore, the examples :doc:`/drive_examples/vhz/plot_vhz_im_2kw` and :doc:`/drive_examples/vhz/plot_vhz_im_2kw_lc` show operation of an induction machine under pure open-loop V/Hz control with a diode front-end rectifier and with an LC filter, respectively. .. rubric:: References diff --git a/examples/drive/vhz/plot_obs_vhz_ctrl_im_2kw.py b/examples/drive/vhz/plot_obs_vhz_im_2kw.py similarity index 100% rename from examples/drive/vhz/plot_obs_vhz_ctrl_im_2kw.py rename to examples/drive/vhz/plot_obs_vhz_im_2kw.py diff --git a/examples/drive/vhz/plot_obs_vhz_ctrl_pmsm_2kw.py b/examples/drive/vhz/plot_obs_vhz_pmsm_2kw.py similarity index 100% rename from examples/drive/vhz/plot_obs_vhz_ctrl_pmsm_2kw.py rename to examples/drive/vhz/plot_obs_vhz_pmsm_2kw.py diff --git a/examples/drive/vhz/plot_obs_vhz_ctrl_pmsm_2kw_two_mass.py b/examples/drive/vhz/plot_obs_vhz_pmsm_2kw_two_mass.py similarity index 100% rename from examples/drive/vhz/plot_obs_vhz_ctrl_pmsm_2kw_two_mass.py rename to examples/drive/vhz/plot_obs_vhz_pmsm_2kw_two_mass.py diff --git a/examples/drive/vhz/plot_obs_vhz_ctrl_syrm_7kw_sat.py b/examples/drive/vhz/plot_obs_vhz_syrm_7kw_sat.py similarity index 97% rename from examples/drive/vhz/plot_obs_vhz_ctrl_syrm_7kw_sat.py rename to examples/drive/vhz/plot_obs_vhz_syrm_7kw_sat.py index bd172487a..8e0bb629b 100644 --- a/examples/drive/vhz/plot_obs_vhz_ctrl_syrm_7kw_sat.py +++ b/examples/drive/vhz/plot_obs_vhz_syrm_7kw_sat.py @@ -50,7 +50,7 @@ t_stop = 8 times = np.array([0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1]) * t_stop -values = np.array([0, 0, 1, 1, 0, -1, -1, 0, 0]) * base.w / base.n_p +values = np.array([0, 0, 1, 1, 0, -1, -1, 0, 0]) * base.w_M ctrl.set_speed_ref(utils.SequenceGenerator(times, values)) times = np.array([0, 0.125, 0.125, 0.875, 0.875, 1]) * t_stop diff --git a/examples/drive/vhz/plot_vhz_ctrl_im_2kw.py b/examples/drive/vhz/plot_vhz_im_2kw.py similarity index 100% rename from examples/drive/vhz/plot_vhz_ctrl_im_2kw.py rename to examples/drive/vhz/plot_vhz_im_2kw.py diff --git a/examples/drive/vhz/plot_vhz_ctrl_im_2kw_lc.py b/examples/drive/vhz/plot_vhz_im_2kw_lc.py similarity index 100% rename from examples/drive/vhz/plot_vhz_ctrl_im_2kw_lc.py rename to examples/drive/vhz/plot_vhz_im_2kw_lc.py diff --git a/examples/grid/grid_forming/plot_gfm_rfpsc_13kva.py b/examples/grid/grid_forming/plot_gfm_rfpsc_13kva.py index e0b4ac19e..a431cef14 100644 --- a/examples/grid/grid_forming/plot_gfm_rfpsc_13kva.py +++ b/examples/grid/grid_forming/plot_gfm_rfpsc_13kva.py @@ -28,7 +28,7 @@ # Configure the control system. # Control configuration parameters -inner_ctrl = control.PowerSynchronizationControl( +inner_ctrl = control.PowerSynchronizationController( u_nom=base.u, w_nom=base.w, i_max=1.3 * base.i, R=0.05 * base.Z, R_a=0.2 * base.Z ) ctrl = control.GridConverterControlSystem(inner_ctrl) diff --git a/motulator/__init__.py b/motulator/__init__.py index fc088807a..17d44e323 100644 --- a/motulator/__init__.py +++ b/motulator/__init__.py @@ -1,8 +1,6 @@ """ -*motulator*: Motor Drive and Grid Converter Simulator in Python - -This software includes continuous-time simulation models for electric machines -drives and grid-connected converters. Furthermore, selected examples of -discrete-time control algorithms are included. +This software includes continuous-time simulation models for electric machines drives +and grid converters. Furthermore, selected examples of discrete-time control algorithms +are included. """ diff --git a/motulator/drive/control/__init__.py b/motulator/drive/control/__init__.py index cf71ae369..3f5fd6df7 100644 --- a/motulator/drive/control/__init__.py +++ b/motulator/drive/control/__init__.py @@ -1,6 +1,5 @@ """Controllers for machine drives.""" from motulator.drive.control import im, sm -from motulator.drive.control._base import SpeedController -__all__ = ["im", "sm", "SpeedController"] +__all__ = ["im", "sm"] diff --git a/motulator/drive/control/_sm_observers.py b/motulator/drive/control/_sm_observers.py index 859d8e9f1..60f254d9d 100644 --- a/motulator/drive/control/_sm_observers.py +++ b/motulator/drive/control/_sm_observers.py @@ -57,8 +57,8 @@ class FluxObserver: the PM-flux linkage. The design is based on [#Hin2018]_ and [#Tuo2018]. The observer gain decouples the electrical and mechanical dynamics and allows placing the poles of the corresponding linearized estimation error dynamics. The PM-flux linkage can - also be estimated [#Tuo2018]_. The observer can also be used in the sensored mode, - in which case the control system is fixed to the measured rotor angle. The magnetic + also be estimated [#Tuo2018]_. The observer can also be used in sensored mode, in + which case the control system is fixed to the measured rotor angle. The magnetic saturation is taken into account. Parameters diff --git a/motulator/drive/control/sm.py b/motulator/drive/control/sm.py index 6a8aa2db4..00bf2c0a1 100644 --- a/motulator/drive/control/sm.py +++ b/motulator/drive/control/sm.py @@ -17,7 +17,11 @@ ObserverBasedVHzController, ObserverBasedVHzControllerCfg, ) -from motulator.drive.control._sm_observers import ObserverOutputs +from motulator.drive.control._sm_observers import ( + FluxObserver, + ObserverOutputs, + SpeedFluxObserver, +) from motulator.drive.control._sm_reference_gen import ReferenceGenerator from motulator.drive.control._sm_signal_inj import SignalInjectionController from motulator.drive.utils._parameters import ( @@ -30,6 +34,8 @@ "CurrentVectorControllerCfg", "VHzControlSystem", "VectorControlSystem", + "FluxObserver", + "SpeedFluxObserver", "CurrentController", "CurrentVectorController", "FluxVectorController", diff --git a/motulator/drive/utils/__init__.py b/motulator/drive/utils/__init__.py index ba0d70fe2..4a4a5009d 100644 --- a/motulator/drive/utils/__init__.py +++ b/motulator/drive/utils/__init__.py @@ -1,4 +1,4 @@ -"""This module contains utility functions for machine drives.""" +"""Utility functions for machine drives.""" from motulator.common.utils._utils import ( BaseValues, diff --git a/motulator/grid/control/__init__.py b/motulator/grid/control/__init__.py index 54eead39e..5219647aa 100644 --- a/motulator/grid/control/__init__.py +++ b/motulator/grid/control/__init__.py @@ -1,4 +1,4 @@ -"""Controllers for grid-connected converters.""" +"""Controllers for grid converters.""" from motulator.grid.control._base import GridConverterControlSystem from motulator.grid.control._controllers import CurrentLimiter, DCBusVoltageController @@ -8,7 +8,7 @@ CurrentVectorController, ) from motulator.grid.control._gfm_observer import ObserverBasedGridFormingController -from motulator.grid.control._gfm_psc import PowerSynchronizationControl +from motulator.grid.control._gfm_psc import PowerSynchronizationController __all__ = [ "CurrentController", @@ -18,5 +18,5 @@ "GridConverterControlSystem", "ObserverBasedGridFormingController", "PLL", - "PowerSynchronizationControl", + "PowerSynchronizationController", ] diff --git a/motulator/grid/control/_gfm_psc.py b/motulator/grid/control/_gfm_psc.py index b66640642..037d2910c 100644 --- a/motulator/grid/control/_gfm_psc.py +++ b/motulator/grid/control/_gfm_psc.py @@ -1,4 +1,4 @@ -"""Power-synchronization control for grid-connected converters.""" +"""Power-synchronization control for grid converters.""" from cmath import exp from dataclasses import dataclass, field @@ -38,9 +38,9 @@ class Feedbacks: p_g: float = 0.0 -class PowerSynchronizationControl: +class PowerSynchronizationController: """ - Reference-feedforward power-synchronization control. + Reference-feedforward power-synchronization controller. This implements the reference-feedforward power-synchronization control [#Har2020]_. diff --git a/motulator/grid/utils/__init__.py b/motulator/grid/utils/__init__.py index 62a0eb083..16785c295 100644 --- a/motulator/grid/utils/__init__.py +++ b/motulator/grid/utils/__init__.py @@ -1,4 +1,4 @@ -"""This module contains utility functions for grid converters.""" +"""Utility functions for grid converters.""" from motulator.common.utils._utils import ( BaseValues,