From e23c3151f884a345300e38af15db035d8d4b8c9f Mon Sep 17 00:00:00 2001 From: Marko Hinkkanen <76600872+mhinkkan@users.noreply.github.com> Date: Tue, 11 Jun 2024 20:39:38 +0300 Subject: [PATCH] Improve the class names (#134) * Minor corrections in docstrings * Minor correction in docstring * Improve the naming of classes --- docs/source/conf.py | 2 +- docs/source/control/current_ctrl.rst | 4 +-- docs/source/control/speed_ctrl.rst | 6 ++--- docs/source/usage.rst | 2 +- .../flux_vector/plot_flux_vector_pmsm_2kw.py | 2 +- .../plot_flux_vector_pmsyrm_5kw.py | 2 +- .../flux_vector/plot_flux_vector_syrm_7kw.py | 2 +- examples/obs_vhz/plot_obs_vhz_ctrl_im_2kw.py | 4 +-- .../obs_vhz/plot_obs_vhz_ctrl_pmsm_2kw.py | 4 +-- .../plot_obs_vhz_ctrl_pmsm_2kw_two_mass.py | 4 +-- .../obs_vhz/plot_obs_vhz_ctrl_pmsyrm_thor.py | 4 +-- .../obs_vhz/plot_obs_vhz_ctrl_syrm_7kw.py | 4 +-- .../signal_inj/plot_signal_inj_pmsm_2kw.py | 4 +-- .../signal_inj/plot_signal_inj_syrm_7kw.py | 4 +-- examples/vector/plot_vector_ctrl_im_2kw.py | 7 +++--- .../vector/plot_vector_ctrl_im_2kw_tq_mode.py | 2 +- examples/vector/plot_vector_ctrl_pmsm_2kw.py | 3 ++- .../vector/plot_vector_ctrl_pmsm_2kw_diode.py | 3 ++- .../vector/plot_vector_ctrl_pmsyrm_thor.py | 4 +-- examples/vector/plot_vector_ctrl_syrm_7kw.py | 3 ++- examples/vhz/plot_vhz_ctrl_6step_im_2kw.py | 5 ++-- examples/vhz/plot_vhz_ctrl_im_2kw.py | 4 +-- examples/vhz/plot_vhz_ctrl_im_2kw_lc.py | 8 +++--- motulator/common/control/__init__.py | 8 +++--- motulator/common/control/_control.py | 6 ++--- motulator/common/model/_simulation.py | 2 +- motulator/drive/control/__init__.py | 4 +-- motulator/drive/control/_common.py | 10 ++++---- motulator/drive/control/im/__init__.py | 23 +++++++++-------- motulator/drive/control/im/_current_vector.py | 22 ++++++++-------- motulator/drive/control/im/_obs_vhz.py | 8 +++--- motulator/drive/control/im/_vhz.py | 7 +++--- motulator/drive/control/sm/__init__.py | 25 ++++++++++--------- motulator/drive/control/sm/_current_vector.py | 22 ++++++++-------- motulator/drive/control/sm/_flux_vector.py | 8 +++--- motulator/drive/control/sm/_obs_vhz.py | 8 +++--- motulator/drive/control/sm/_signal_inj.py | 12 ++++----- pyproject.toml | 2 +- 38 files changed, 130 insertions(+), 124 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 1378edb77..23bc9bbc0 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -25,7 +25,7 @@ author = "Aalto Electric Drives" # The full version, including alpha/beta/rc tags -release = "0.3.0" +release = "0.3.1" # -- General configuration --------------------------------------------------- diff --git a/docs/source/control/current_ctrl.rst b/docs/source/control/current_ctrl.rst index 0bc0f9451..a525c4ca3 100644 --- a/docs/source/control/current_ctrl.rst +++ b/docs/source/control/current_ctrl.rst @@ -159,7 +159,7 @@ where :math:`\mathrm{sat}(\cdot)` is the saturation function. The limited voltag .. math:: \frac{\mathrm{d} \boldsymbol{u}_\mathrm{i}}{\mathrm{d} t} = \boldsymbol{\alpha}_\mathrm{i}\left(\bar{\boldsymbol{u}}_\mathrm{s,ref} - \hat{\boldsymbol{v}}_\mathrm{s}\right) -The other parts of the above controller are not affected by the saturation. The implementation in the :class:`motulator.common.control.ComplexPICtrl` class is based on this disturbance-observer form. +The other parts of the above controller are not affected by the saturation. The implementation in the :class:`motulator.common.control.ComplexPIController` class is based on this disturbance-observer form. Synchronous Machines -------------------- @@ -184,7 +184,7 @@ The discrete-time variant of the disturbance-observer form :eq:`cc_disturbance` \boldsymbol{u}_\mathrm{s,ref}(k) &= \boldsymbol{k}_\mathrm{t}\left[\boldsymbol{\psi}_{\mathrm{ref}}(k) - \hat{\boldsymbol{\psi}}(k)\right] + \hat{\boldsymbol{v}}_\mathrm{s} \\ \bar{\boldsymbol{u}}_\mathrm{s,ref}(k) &= \mathrm{sat}\left[\boldsymbol{u}_\mathrm{s,ref}(k)\right] -where :math:`T_\mathrm{s}` is the sampling period and :math:`k` is the discrete-time index. Depending on the machine type, either :eq:`flux_mapping_im` or :eq:`flux_mapping_sm` is used to map the stator current to the flux linkage. This discrete-time algorithm corresponds to the implementation in the :class:`motulator.drive.control.sm.CurrentCtrl` class. The default gain selection corresponds to the complex-vector gains in :eq:`complex_vector_gains_flux`. +where :math:`T_\mathrm{s}` is the sampling period and :math:`k` is the discrete-time index. Depending on the machine type, either :eq:`flux_mapping_im` or :eq:`flux_mapping_sm` is used to map the stator current to the flux linkage. This discrete-time algorithm corresponds to the implementation in the :class:`motulator.drive.control.sm.CurrentController` class. The default gain selection corresponds to the complex-vector gains in :eq:`complex_vector_gains_flux`. .. rubric:: References diff --git a/docs/source/control/speed_ctrl.rst b/docs/source/control/speed_ctrl.rst index 3a160c51d..92492a9b6 100644 --- a/docs/source/control/speed_ctrl.rst +++ b/docs/source/control/speed_ctrl.rst @@ -1,7 +1,7 @@ Speed Control ============= -Proportional-integral (PI) control is widely used in machine drives. A standard one-degree-of-freedom (1DOF) PI controller manipulates only the control error, i.e., it has single input and single output. Its two-degrees-of-freedom (2DOF) variants have two inputs (reference signal and feedback signal), which allows to design disturbance rejection and reference tracking separately [#Sko1996]_. In the following, we will use a speed controller as an example, cf. the :class:`motulator.drive.control.SpeedCtrl` class. The presented control design can be extended to many other control tasks as well. +Proportional-integral (PI) control is widely used in machine drives. A standard one-degree-of-freedom (1DOF) PI controller manipulates only the control error, i.e., it has single input and single output. Its two-degrees-of-freedom (2DOF) variants have two inputs (reference signal and feedback signal), which allows to design disturbance rejection and reference tracking separately [#Sko1996]_. In the following, we will use a speed controller as an example, cf. the :class:`motulator.drive.control.SpeedController` class. The presented control design can be extended to many other control tasks as well. Continuous-Time Design ---------------------- @@ -52,7 +52,7 @@ where :math:`\mathrm{sat}(\cdot)` is the saturation function. If this saturation .. math:: \frac{\mathrm{d} \tau_\mathrm{i}}{\mathrm{d} t} = \alpha_\mathrm{i}\left(\bar{\tau}_\mathrm{M,ref} - \hat \tau_\mathrm{L}\right) -The other parts of the above controller are not affected by the saturation. The implementation in the :class:`motulator.drive.control.SpeedCtrl` class is based on this disturbance-observer form. +The other parts of the above controller are not affected by the saturation. The implementation in the :class:`motulator.drive.control.SpeedController` class is based on this disturbance-observer form. Gain Selection Example ^^^^^^^^^^^^^^^^^^^^^^ @@ -94,7 +94,7 @@ The discrete-time variant of the controller is given by \tau_\mathrm{M,ref}(k) &= k_\mathrm{t}\left[\omega_\mathrm{M,ref}(k) - \omega_\mathrm{M}(k)\right] + \hat \tau_\mathrm{L}(k) \\ \bar{\tau}_\mathrm{M,ref}(k) &= \mathrm{sat}[\tau_\mathrm{M,ref}(k)] -where :math:`T_\mathrm{s}` is the sampling period and :math:`k` is the discrete-time index. This corresponds to the implementation in the :class:`motulator.drive.control.SpeedCtrl` class. +where :math:`T_\mathrm{s}` is the sampling period and :math:`k` is the discrete-time index. This corresponds to the implementation in the :class:`motulator.drive.control.SpeedController` class. .. rubric:: References diff --git a/docs/source/usage.rst b/docs/source/usage.rst index abb4599ba..8cb8557fe 100644 --- a/docs/source/usage.rst +++ b/docs/source/usage.rst @@ -21,7 +21,7 @@ After :doc:`installation`, *motulator* can be used by creating a continuous-time par = control.ModelPars( R_s=3.7, R_R=2.1, L_sgm=.021, L_M=.224, n_p=2, J=.015) cfg = control.CurrentReferenceCfg(par, max_i_s=1.5*np.sqrt(2)*5) - ctrl = control.VectorCtrl(par, cfg) + ctrl = control.VectorControl(par, cfg) # Acceleration at t = 0.2 s and load torque step of 14 Nm at t = 0.75 s ctrl.ref.w_m = lambda t: (t > .2)*(2*np.pi*50) diff --git a/examples/flux_vector/plot_flux_vector_pmsm_2kw.py b/examples/flux_vector/plot_flux_vector_pmsm_2kw.py index 11875aaae..afc874c74 100644 --- a/examples/flux_vector/plot_flux_vector_pmsm_2kw.py +++ b/examples/flux_vector/plot_flux_vector_pmsm_2kw.py @@ -33,7 +33,7 @@ par = mdl_par # Assume accurate machine model parameter estimates cfg = control.FluxTorqueReferenceCfg(par, max_i_s=1.5*base.i, k_u=.9) -ctrl = control.FluxVectorCtrl(par, cfg, J=.015, T_s=250e-6, sensorless=True) +ctrl = control.FluxVectorControl(par, cfg, J=.015, T_s=250e-6, sensorless=True) # %% # Set the speed reference and the external load torque. diff --git a/examples/flux_vector/plot_flux_vector_pmsyrm_5kw.py b/examples/flux_vector/plot_flux_vector_pmsyrm_5kw.py index bbda5c367..e55509897 100644 --- a/examples/flux_vector/plot_flux_vector_pmsyrm_5kw.py +++ b/examples/flux_vector/plot_flux_vector_pmsyrm_5kw.py @@ -163,7 +163,7 @@ def i_s(psi_s): # Limit the maximum reference flux to the base value cfg = control.FluxTorqueReferenceCfg( par, max_i_s=2*base.i, k_u=1, max_psi_s=base.psi) -ctrl = control.FluxVectorCtrl(par, cfg, J=.015, sensorless=True) +ctrl = control.FluxVectorControl(par, cfg, J=.015, sensorless=True) # Select a lower speed-estimation bandwidth to mitigate the saturation effects ctrl.observer = control.Observer( control.ObserverCfg(par, alpha_o=2*np.pi*40, sensorless=True)) diff --git a/examples/flux_vector/plot_flux_vector_syrm_7kw.py b/examples/flux_vector/plot_flux_vector_syrm_7kw.py index f3095d2c3..6a306c41b 100644 --- a/examples/flux_vector/plot_flux_vector_syrm_7kw.py +++ b/examples/flux_vector/plot_flux_vector_syrm_7kw.py @@ -69,7 +69,7 @@ def i_s(psi_s): # Disable MTPA since the control system does not consider the saturation cfg = control.FluxTorqueReferenceCfg( par, max_i_s=2*base.i, k_u=.9, min_psi_s=base.psi, max_psi_s=base.psi) -ctrl = control.FluxVectorCtrl(par, cfg, J=.015, sensorless=True) +ctrl = control.FluxVectorControl(par, cfg, J=.015, sensorless=True) # Since the saturation is not considered in the control system, the speed # estimation bandwidth is set to a lower value. Furthermore, the PM-flux # disturbance estimation is enabled at speeds above 2*pi*20 rad/s (electrical). diff --git a/examples/obs_vhz/plot_obs_vhz_ctrl_im_2kw.py b/examples/obs_vhz/plot_obs_vhz_ctrl_im_2kw.py index 70b18e8c6..edd44571a 100644 --- a/examples/obs_vhz/plot_obs_vhz_ctrl_im_2kw.py +++ b/examples/obs_vhz/plot_obs_vhz_ctrl_im_2kw.py @@ -39,9 +39,9 @@ # Inverse-Γ model parameter estimates par = mdl_ig_par # Assume accurate machine model parameter estimates -cfg = control.ObserverBasedVHzCtrlCfg( +cfg = control.ObserverBasedVHzControlCfg( nom_psi_s=base.psi, max_i_s=1.5*base.i, slip_compensation=False) -ctrl = control.ObserverBasedVHzCtrl(par, cfg, T_s=250e-6) +ctrl = control.ObserverBasedVHzControl(par, cfg, T_s=250e-6) # %% # Set the speed reference. diff --git a/examples/obs_vhz/plot_obs_vhz_ctrl_pmsm_2kw.py b/examples/obs_vhz/plot_obs_vhz_ctrl_pmsm_2kw.py index b40b219c6..a08a5503b 100644 --- a/examples/obs_vhz/plot_obs_vhz_ctrl_pmsm_2kw.py +++ b/examples/obs_vhz/plot_obs_vhz_ctrl_pmsm_2kw.py @@ -34,8 +34,8 @@ # Configure the control system. par = mdl_par # Assume accurate machine model parameter estimates -cfg = control.ObserverBasedVHzCtrlCfg(par, max_i_s=1.5*base.i) -ctrl = control.ObserverBasedVHzCtrl(par, cfg, T_s=250e-6) +cfg = control.ObserverBasedVHzControlCfg(par, max_i_s=1.5*base.i) +ctrl = control.ObserverBasedVHzControl(par, cfg, T_s=250e-6) #ctrl.rate_limiter = control.RateLimiter(2*np.pi*120) # %% diff --git a/examples/obs_vhz/plot_obs_vhz_ctrl_pmsm_2kw_two_mass.py b/examples/obs_vhz/plot_obs_vhz_ctrl_pmsm_2kw_two_mass.py index 664eae394..c53fa30b0 100644 --- a/examples/obs_vhz/plot_obs_vhz_ctrl_pmsm_2kw_two_mass.py +++ b/examples/obs_vhz/plot_obs_vhz_ctrl_pmsm_2kw_two_mass.py @@ -41,8 +41,8 @@ # Configure the control system. par = mdl_par # Assume accurate machine model parameter estimates -cfg = control.ObserverBasedVHzCtrlCfg(par, max_i_s=1.5*base.i) -ctrl = control.ObserverBasedVHzCtrl(par, cfg, T_s=250e-6) +cfg = control.ObserverBasedVHzControlCfg(par, max_i_s=1.5*base.i) +ctrl = control.ObserverBasedVHzControl(par, cfg, T_s=250e-6) #ctrl.rate_limiter = control.RateLimiter(2*np.pi*120) # %% diff --git a/examples/obs_vhz/plot_obs_vhz_ctrl_pmsyrm_thor.py b/examples/obs_vhz/plot_obs_vhz_ctrl_pmsyrm_thor.py index f0043dd21..5fdf77f95 100644 --- a/examples/obs_vhz/plot_obs_vhz_ctrl_pmsyrm_thor.py +++ b/examples/obs_vhz/plot_obs_vhz_ctrl_pmsyrm_thor.py @@ -105,8 +105,8 @@ def i_s(psi_s): # Configure the control system. par = SynchronousMachinePars(n_p=2, R_s=.2, L_d=4e-3, L_q=17e-3, psi_f=.134) -cfg = control.ObserverBasedVHzCtrlCfg(par, max_i_s=2*base.i) -ctrl = control.ObserverBasedVHzCtrl(par, cfg, T_s=250e-6) +cfg = control.ObserverBasedVHzControlCfg(par, max_i_s=2*base.i) +ctrl = control.ObserverBasedVHzControl(par, cfg, T_s=250e-6) # %% # Set the speed reference and the external load torque. diff --git a/examples/obs_vhz/plot_obs_vhz_ctrl_syrm_7kw.py b/examples/obs_vhz/plot_obs_vhz_ctrl_syrm_7kw.py index c59cc4129..adc14cac7 100644 --- a/examples/obs_vhz/plot_obs_vhz_ctrl_syrm_7kw.py +++ b/examples/obs_vhz/plot_obs_vhz_ctrl_syrm_7kw.py @@ -90,9 +90,9 @@ def i_s(psi_s): # Configure the control system. par = SynchronousMachinePars(n_p=2, R_s=.54, L_d=37e-3, L_q=6.2e-3, psi_f=0) -cfg = control.ObserverBasedVHzCtrlCfg( +cfg = control.ObserverBasedVHzControlCfg( par, max_i_s=2*base.i, min_psi_s=base.psi, max_psi_s=base.psi) -ctrl = control.ObserverBasedVHzCtrl(par, cfg) +ctrl = control.ObserverBasedVHzControl(par, cfg) # %% # Set the speed reference and the external load torque. diff --git a/examples/signal_inj/plot_signal_inj_pmsm_2kw.py b/examples/signal_inj/plot_signal_inj_pmsm_2kw.py index f2cd852d2..3f484c60f 100644 --- a/examples/signal_inj/plot_signal_inj_pmsm_2kw.py +++ b/examples/signal_inj/plot_signal_inj_pmsm_2kw.py @@ -37,8 +37,8 @@ par = mdl_par # Assume accurate machine model parameter estimates cfg = control.CurrentReferenceCfg(par, nom_w_m=base.w, max_i_s=2*base.i) -ctrl = control.SignalInjectionCtrl(par, cfg, J=.015, T_s=250e-6) -# ctrl.current_ctrl = control.sm.CurrentCtrl(par, 2*np.pi*100) +ctrl = control.SignalInjectionControl(par, cfg, J=.015, T_s=250e-6) +# ctrl.current_ctrl = control.sm.CurrentControl(par, 2*np.pi*100) # %% # Set the speed reference and the external load torque. diff --git a/examples/signal_inj/plot_signal_inj_syrm_7kw.py b/examples/signal_inj/plot_signal_inj_syrm_7kw.py index 6bc6ae0d9..f2255a101 100644 --- a/examples/signal_inj/plot_signal_inj_syrm_7kw.py +++ b/examples/signal_inj/plot_signal_inj_syrm_7kw.py @@ -38,8 +38,8 @@ par = mdl_par # Assume accurate machine model parameter estimates cfg = control.CurrentReferenceCfg( par, nom_w_m=base.w, max_i_s=2*base.i, min_psi_s=.5*base.psi) -ctrl = control.SignalInjectionCtrl(par, cfg, J=.015, T_s=250e-6) -# ctrl.current_ctrl = control.sm.CurrentCtrl(par, 2*np.pi*100) +ctrl = control.SignalInjectionControl(par, cfg, J=.015, T_s=250e-6) +# ctrl.current_ctrl = control.sm.CurrentControl(par, 2*np.pi*100) # ctrl.signal_inj = control.sm.SignalInjection(par, U_inj=200) # %% diff --git a/examples/vector/plot_vector_ctrl_im_2kw.py b/examples/vector/plot_vector_ctrl_im_2kw.py index 08d4df2a2..999700610 100644 --- a/examples/vector/plot_vector_ctrl_im_2kw.py +++ b/examples/vector/plot_vector_ctrl_im_2kw.py @@ -57,11 +57,12 @@ def L_s(psi, L_su=.34, beta=.84, S=7): cfg = control.CurrentReferenceCfg( par, max_i_s=1.5*base.i, nom_u_s=base.u, nom_w_s=base.w) # Create the control system -ctrl = control.CurrentVectorCtrl(par, cfg, J=.015, T_s=250e-6, sensorless=True) +ctrl = control.CurrentVectorControl( + par, cfg, J=.015, T_s=250e-6, sensorless=True) # As an example, you may replace the default 2DOF PI speed controller with the # regular PI speed controller by uncommenting the following line -# from motulator.common.control import PICtrl -# ctrl.speed_ctrl = PICtrl(k_p=1, k_i=1) +# from motulator.common.control import PIController +# ctrl.speed_ctrl = PIController(k_p=1, k_i=1) # %% # Set the speed reference and the external load torque. You may also try to diff --git a/examples/vector/plot_vector_ctrl_im_2kw_tq_mode.py b/examples/vector/plot_vector_ctrl_im_2kw_tq_mode.py index 0fa3f3635..c305e7b6e 100644 --- a/examples/vector/plot_vector_ctrl_im_2kw_tq_mode.py +++ b/examples/vector/plot_vector_ctrl_im_2kw_tq_mode.py @@ -44,7 +44,7 @@ cfg = control.CurrentReferenceCfg( par, max_i_s=1.5*base.i, nom_u_s=base.u, nom_w_s=base.w) # Create the control system -ctrl = control.CurrentVectorCtrl(par, cfg, T_s=250e-6, sensorless=True) +ctrl = control.CurrentVectorControl(par, cfg, T_s=250e-6, sensorless=True) # %% # Set the torque reference and the actual speed. diff --git a/examples/vector/plot_vector_ctrl_pmsm_2kw.py b/examples/vector/plot_vector_ctrl_pmsm_2kw.py index 16f0c4f5a..6251d903f 100644 --- a/examples/vector/plot_vector_ctrl_pmsm_2kw.py +++ b/examples/vector/plot_vector_ctrl_pmsm_2kw.py @@ -36,7 +36,8 @@ par = mdl_par # Assume accurate machine model parameter estimates cfg = control.CurrentReferenceCfg(par, nom_w_m=base.w, max_i_s=1.5*base.i) -ctrl = control.CurrentVectorCtrl(par, cfg, J=.015, T_s=250e-6, sensorless=True) +ctrl = control.CurrentVectorControl( + par, cfg, J=.015, T_s=250e-6, sensorless=True) # %% # Set the speed reference and the external load torque. diff --git a/examples/vector/plot_vector_ctrl_pmsm_2kw_diode.py b/examples/vector/plot_vector_ctrl_pmsm_2kw_diode.py index c8f777046..b07dbdad8 100644 --- a/examples/vector/plot_vector_ctrl_pmsm_2kw_diode.py +++ b/examples/vector/plot_vector_ctrl_pmsm_2kw_diode.py @@ -35,7 +35,8 @@ par = mdl_par # Assume accurate machine model parameter estimates ref = control.CurrentReferenceCfg(par, nom_w_m=base.w, max_i_s=1.5*base.i) -ctrl = control.CurrentVectorCtrl(par, ref, J=.015, T_s=250e-6, sensorless=True) +ctrl = control.CurrentVectorControl( + par, ref, J=.015, T_s=250e-6, sensorless=True) # %% # Set the speed reference and the external load torque. diff --git a/examples/vector/plot_vector_ctrl_pmsyrm_thor.py b/examples/vector/plot_vector_ctrl_pmsyrm_thor.py index 0fae87971..dc4122f2a 100644 --- a/examples/vector/plot_vector_ctrl_pmsyrm_thor.py +++ b/examples/vector/plot_vector_ctrl_pmsyrm_thor.py @@ -40,11 +40,11 @@ par = mdl_par # Assume accurate machine model parameter estimates cfg = control.CurrentReferenceCfg( par, nom_w_m=base.w, max_i_s=2*base.i, k_u=.9) -ctrl = control.CurrentVectorCtrl( +ctrl = control.CurrentVectorControl( par, cfg, T_s=125e-6, J=.0042, sensorless=True) ctrl.observer = control.Observer( control.ObserverCfg(par, sensorless=True, alpha_o=2*np.pi*200)) -ctrl.speed_ctrl = control.SpeedCtrl( +ctrl.speed_ctrl = control.SpeedController( J=.0042, alpha_s=2*np.pi*4, max_tau_M=1.5*nom.tau) # %% diff --git a/examples/vector/plot_vector_ctrl_syrm_7kw.py b/examples/vector/plot_vector_ctrl_syrm_7kw.py index f8cc03b12..b7ba4a20d 100644 --- a/examples/vector/plot_vector_ctrl_syrm_7kw.py +++ b/examples/vector/plot_vector_ctrl_syrm_7kw.py @@ -37,7 +37,8 @@ par = mdl_par # Assume accurate machine model parameter estimates cfg = control.CurrentReferenceCfg( par, nom_w_m=base.w, max_i_s=1.5*base.i, min_psi_s=.5*base.psi, k_u=.9) -ctrl = control.CurrentVectorCtrl(par, cfg, J=.015, T_s=125e-6, sensorless=True) +ctrl = control.CurrentVectorControl( + par, cfg, J=.015, T_s=125e-6, sensorless=True) # %% # Set the speed reference and the external load torque. diff --git a/examples/vhz/plot_vhz_ctrl_6step_im_2kw.py b/examples/vhz/plot_vhz_ctrl_6step_im_2kw.py index 952abcf5b..153d51328 100644 --- a/examples/vhz/plot_vhz_ctrl_6step_im_2kw.py +++ b/examples/vhz/plot_vhz_ctrl_6step_im_2kw.py @@ -44,8 +44,9 @@ # Control system (parametrized as open-loop V/Hz control). par = InductionMachineInvGammaPars(R_s=0*3.7, R_R=0*2.1, L_sgm=.021, L_M=.224) -ctrl = control.VHzCtrl( - control.VHzCtrlCfg(par, nom_psi_s=base.psi, k_u=0, k_w=0, six_step=True)) +ctrl = control.VHzControl( + control.VHzControlCfg( + par, nom_psi_s=base.psi, k_u=0, k_w=0, six_step=True)) # %% # Set the speed reference and the external load torque. diff --git a/examples/vhz/plot_vhz_ctrl_im_2kw.py b/examples/vhz/plot_vhz_ctrl_im_2kw.py index 896de75f9..9e6d3c91d 100644 --- a/examples/vhz/plot_vhz_ctrl_im_2kw.py +++ b/examples/vhz/plot_vhz_ctrl_im_2kw.py @@ -43,8 +43,8 @@ # Inverse-Γ model parameter estimates par = InductionMachineInvGammaPars(R_s=0*3.7, R_R=0*2.1, L_sgm=.021, L_M=.224) -ctrl = control.VHzCtrl( - control.VHzCtrlCfg(par, nom_psi_s=base.psi, k_u=0, k_w=0)) +ctrl = control.VHzControl( + control.VHzControlCfg(par, nom_psi_s=base.psi, k_u=0, k_w=0)) # %% # Set the speed reference and the external load torque. diff --git a/examples/vhz/plot_vhz_ctrl_im_2kw_lc.py b/examples/vhz/plot_vhz_ctrl_im_2kw_lc.py index d44bb55a2..bb147fa16 100644 --- a/examples/vhz/plot_vhz_ctrl_im_2kw_lc.py +++ b/examples/vhz/plot_vhz_ctrl_im_2kw_lc.py @@ -43,8 +43,8 @@ # Inverse-Γ model parameter estimates par = InductionMachineInvGammaPars(R_s=0*3.7, R_R=0*2.1, L_sgm=.021, L_M=.224) -ctrl = control.VHzCtrl( - control.VHzCtrlCfg(par, nom_psi_s=base.psi, k_u=0, k_w=0)) +ctrl = control.VHzControl( + control.VHzControlCfg(par, nom_psi_s=base.psi, k_u=0, k_w=0)) # %% # Set the speed reference. The external load torque is zero (by default). @@ -75,7 +75,7 @@ mdl.converter.data.u_cs.real/base.u, label=r"$u_\mathrm{ca}$") ax1.plot( - mdl.converter.data.t, + mdl.machine.data.t, mdl.machine.data.u_ss.real/base.u, label=r"$u_\mathrm{sa}$") ax1.set_xlim(t_span) @@ -88,7 +88,7 @@ mdl.converter.data.i_cs.real/base.i, label=r"$i_\mathrm{ca}$") ax2.plot( - mdl.converter.data.t, + mdl.machine.data.t, mdl.machine.data.i_ss.real/base.i, label=r"$i_\mathrm{sa}$") ax2.set_xlim(t_span) diff --git a/motulator/common/control/__init__.py b/motulator/common/control/__init__.py index 5cd391e7e..730a6e20a 100644 --- a/motulator/common/control/__init__.py +++ b/motulator/common/control/__init__.py @@ -1,11 +1,11 @@ """Common control functions and classes.""" from motulator.common.control._control import ( - Ctrl, ComplexPICtrl, PICtrl, PWM, RateLimiter) + ControlSystem, ComplexPIController, PIController, PWM, RateLimiter) __all__ = [ - "Ctrl", - "ComplexPICtrl", - "PICtrl", + "ControlSystem", + "ComplexPIController", + "PIController", "PWM", "RateLimiter", ] diff --git a/motulator/common/control/_control.py b/motulator/common/control/_control.py index 35219507a..f31ec5f9f 100644 --- a/motulator/common/control/_control.py +++ b/motulator/common/control/_control.py @@ -206,7 +206,7 @@ def __call__(self, T_s, ref_u_cs, u_dc, w): # %% -class PICtrl: +class PIController: """ 2DOF PI controller. @@ -292,7 +292,7 @@ def update(self, T_s, u): # %% -class ComplexPICtrl: +class ComplexPIController: """ 2DOF synchronous-frame complex-vector PI controller. @@ -456,7 +456,7 @@ def update(self, T_s): # %% -class Ctrl(ABC): +class ControlSystem(ABC): """ Base class for control systems. diff --git a/motulator/common/model/_simulation.py b/motulator/common/model/_simulation.py index c2f575598..613634535 100644 --- a/motulator/common/model/_simulation.py +++ b/motulator/common/model/_simulation.py @@ -193,7 +193,7 @@ class Simulation: ---------- mdl : Model Continuous-time system model. - ctrl : Ctrl + ctrl : ControlSystem Discrete-time controller. """ diff --git a/motulator/drive/control/__init__.py b/motulator/drive/control/__init__.py index 3b0a85130..bcbe595ea 100644 --- a/motulator/drive/control/__init__.py +++ b/motulator/drive/control/__init__.py @@ -1,4 +1,4 @@ """Controllers for machine drives.""" -from motulator.drive.control._common import DriveCtrl, SpeedCtrl +from motulator.drive.control._common import DriveControlSystem, SpeedController -__all__ = ["DriveCtrl", "SpeedCtrl"] +__all__ = ["DriveControlSystem", "SpeedController"] diff --git a/motulator/drive/control/_common.py b/motulator/drive/control/_common.py index 15340a41f..07c5e1f53 100644 --- a/motulator/drive/control/_common.py +++ b/motulator/drive/control/_common.py @@ -5,12 +5,12 @@ import numpy as np -from motulator.common.control import Ctrl, PICtrl +from motulator.common.control import ControlSystem, PIController from motulator.common.utils import abc2complex, wrap # %% -class SpeedCtrl(PICtrl): +class SpeedController(PIController): """ 2DOF PI speed controller. @@ -36,9 +36,9 @@ def __init__(self, J, alpha_s, max_tau_M=np.inf): # %% -class DriveCtrl(Ctrl, ABC): +class DriveControlSystem(ControlSystem, ABC): """ - Base class for control of electric machine drives. + Base class for drive control systems. This base class provides typical functionalities for control of electric machine drives. This can be used both in speed-control and torque-control @@ -72,7 +72,7 @@ class DriveCtrl(Ctrl, ABC): `motulator.drive.control.im.Observer` or `motulator.drive.control.sm.Observer` depending on the machine type. The default is None. - speed_ctrl : SpeedCtrl | None + speed_ctrl : SpeedController | None Speed controller. The default is None. """ diff --git a/motulator/drive/control/im/__init__.py b/motulator/drive/control/im/__init__.py index cfcce36a7..5b6b39f9a 100644 --- a/motulator/drive/control/im/__init__.py +++ b/motulator/drive/control/im/__init__.py @@ -2,24 +2,25 @@ from motulator.drive.control.im._common import ( FullOrderObserver, FullOrderObserverCfg, Observer, ObserverCfg) from motulator.drive.control.im._current_vector import ( - CurrentCtrl, CurrentReference, CurrentReferenceCfg, CurrentVectorCtrl) + CurrentController, CurrentReference, CurrentReferenceCfg, + CurrentVectorControl) from motulator.drive.control.im._obs_vhz import ( - ObserverBasedVHzCtrl, ObserverBasedVHzCtrlCfg) -from motulator.drive.control.im._vhz import VHzCtrl, VHzCtrlCfg -from motulator.drive.control._common import SpeedCtrl + ObserverBasedVHzControl, ObserverBasedVHzControlCfg) +from motulator.drive.control.im._vhz import VHzControl, VHzControlCfg +from motulator.drive.control._common import SpeedController __all__ = [ "FullOrderObserver", "FullOrderObserverCfg", "Observer", "ObserverCfg", - "CurrentCtrl", + "CurrentController", "CurrentReference", "CurrentReferenceCfg", - "CurrentVectorCtrl", - "ObserverBasedVHzCtrl", - "ObserverBasedVHzCtrlCfg", - "VHzCtrl", - "VHzCtrlCfg", - "SpeedCtrl", + "CurrentVectorControl", + "ObserverBasedVHzControl", + "ObserverBasedVHzControlCfg", + "VHzControl", + "VHzControlCfg", + "SpeedController", ] diff --git a/motulator/drive/control/im/_current_vector.py b/motulator/drive/control/im/_current_vector.py index 9ad4ab515..6920d7c50 100644 --- a/motulator/drive/control/im/_current_vector.py +++ b/motulator/drive/control/im/_current_vector.py @@ -8,14 +8,14 @@ import numpy as np -from motulator.drive.control import DriveCtrl, SpeedCtrl -from motulator.common.control import ComplexPICtrl +from motulator.drive.control import DriveControlSystem, SpeedController +from motulator.common.control import ComplexPIController from motulator.drive.control.im._common import Observer, ObserverCfg from motulator.drive.utils import InductionMachineInvGammaPars # %% -class CurrentVectorCtrl(DriveCtrl): +class CurrentVectorControl(DriveControlSystem): """ Current-vector control for induction machine drives. @@ -30,7 +30,7 @@ class CurrentVectorCtrl(DriveCtrl): cfg : CurrentReferenceCfg Current reference generator configuration. J : float, optional - Moment of inertia (kgm^2). Needed only for the speed controller. + Moment of inertia (kgm²). Needed only for the speed controller. T_s : float, optional Sampling time (s). The default is 250e-6. sensorless : bool, optional @@ -42,19 +42,19 @@ class CurrentVectorCtrl(DriveCtrl): Flux observer. current_reference : CurrentReference Current reference generator. - current_ctrl : CurrentCtrl - Current controller. The default is CurrentCtrl(par, 2*np.pi*200). - speed_ctrl : SpeedCtrl | None - Speed controller. The default is SpeedCtrl(J, 2*np.pi*4) + current_ctrl : CurrentController + Current controller. The default is CurrentController(par, 2*np.pi*200). + speed_ctrl : SpeedController | None + Speed controller. The default is SpeedController(J, 2*np.pi*4) """ def __init__(self, par, cfg, J=None, T_s=250e-6, sensorless=True): super().__init__(par, T_s, sensorless) self.current_reference = CurrentReference(par, cfg) - self.current_ctrl = CurrentCtrl(par, 2*np.pi*200) + self.current_ctrl = CurrentController(par, 2*np.pi*200) if J is not None: - self.speed_ctrl = SpeedCtrl(J, 2*np.pi*4) + self.speed_ctrl = SpeedController(J, 2*np.pi*4) else: self.speed_ctrl = None self.observer = Observer(ObserverCfg(par, T_s, sensorless=sensorless)) @@ -76,7 +76,7 @@ def update(self, fbk, ref): # %% -class CurrentCtrl(ComplexPICtrl): +class CurrentController(ComplexPIController): """ 2DOF PI current controller for induction machines. diff --git a/motulator/drive/control/im/_obs_vhz.py b/motulator/drive/control/im/_obs_vhz.py index f85dc82e3..de188d06c 100644 --- a/motulator/drive/control/im/_obs_vhz.py +++ b/motulator/drive/control/im/_obs_vhz.py @@ -6,14 +6,14 @@ import numpy as np -from motulator.drive.control import DriveCtrl +from motulator.drive.control import DriveControlSystem from motulator.common.control import RateLimiter from motulator.common.utils import wrap # %% @dataclass -class ObserverBasedVHzCtrlCfg: +class ObserverBasedVHzControlCfg: """ Control system configuration. @@ -46,7 +46,7 @@ class ObserverBasedVHzCtrlCfg: # %% -class ObserverBasedVHzCtrl(DriveCtrl): +class ObserverBasedVHzControl(DriveControlSystem): """ Observer-based V/Hz control for induction machines. @@ -58,7 +58,7 @@ class ObserverBasedVHzCtrl(DriveCtrl): ---------- par : ModelPars Machine model parameters. - cfg : ObserverBasedVHzCtrlCfg + cfg : ObserverBasedVHzControlCfg Control system configuration. T_s : float, optional Sampling period (s). The default is 250e-6. diff --git a/motulator/drive/control/im/_vhz.py b/motulator/drive/control/im/_vhz.py index 8967ddbba..ddc3b25c4 100644 --- a/motulator/drive/control/im/_vhz.py +++ b/motulator/drive/control/im/_vhz.py @@ -6,7 +6,7 @@ import numpy as np -from motulator.drive.control import DriveCtrl +from motulator.drive.control import DriveControlSystem from motulator.drive.utils import InductionMachineInvGammaPars from motulator.common.control import PWM, RateLimiter from motulator.common.utils import wrap @@ -14,7 +14,7 @@ # %% @dataclass -class VHzCtrlCfg: +class VHzControlCfg: """V/Hz control configuration.""" par: InductionMachineInvGammaPars @@ -38,7 +38,7 @@ def __post_init__(self, k_u, k_w, alpha_f, alpha_i): # %% -class VHzCtrl(DriveCtrl): +class VHzControl(DriveControlSystem): """ V/Hz control with the stator current feedback. @@ -77,7 +77,6 @@ def get_feedback_signals(self, mdl): def output(self, fbk): """Extend the base class method.""" - # Unpack par, gain = self.par, self.gain par.alpha = par.R_R/par.L_M diff --git a/motulator/drive/control/sm/__init__.py b/motulator/drive/control/sm/__init__.py index 1eae0e95e..827d5b84c 100644 --- a/motulator/drive/control/sm/__init__.py +++ b/motulator/drive/control/sm/__init__.py @@ -1,30 +1,31 @@ """Controls for synchronous machines.""" from motulator.drive.control.sm._common import Observer, ObserverCfg from motulator.drive.control.sm._flux_vector import ( - FluxTorqueReference, FluxTorqueReferenceCfg, FluxVectorCtrl) + FluxTorqueReference, FluxTorqueReferenceCfg, FluxVectorControl) from motulator.drive.control.sm._current_vector import ( - CurrentCtrl, CurrentReference, CurrentReferenceCfg, CurrentVectorCtrl) + CurrentController, CurrentReference, CurrentReferenceCfg, + CurrentVectorControl) from motulator.drive.control.sm._obs_vhz import ( - ObserverBasedVHzCtrl, ObserverBasedVHzCtrlCfg) + ObserverBasedVHzControl, ObserverBasedVHzControlCfg) from motulator.drive.control.sm._signal_inj import ( - SignalInjection, SignalInjectionCtrl) + SignalInjection, SignalInjectionControl) from motulator.drive.control.sm._torque import TorqueCharacteristics -from motulator.drive.control._common import SpeedCtrl +from motulator.drive.control._common import SpeedController __all__ = [ "Observer", "ObserverCfg", "FluxTorqueReference", "FluxTorqueReferenceCfg", - "FluxVectorCtrl", - "CurrentCtrl", + "FluxVectorControl", + "CurrentController", "CurrentReference", "CurrentReferenceCfg", - "CurrentVectorCtrl", - "ObserverBasedVHzCtrl", - "ObserverBasedVHzCtrlCfg", + "CurrentVectorControl", + "ObserverBasedVHzControl", + "ObserverBasedVHzControlCfg", "SignalInjection", - "SignalInjectionCtrl", + "SignalInjectionControl", "TorqueCharacteristics", - "SpeedCtrl", + "SpeedController", ] diff --git a/motulator/drive/control/sm/_current_vector.py b/motulator/drive/control/sm/_current_vector.py index 2a4d4eccb..543207014 100644 --- a/motulator/drive/control/sm/_current_vector.py +++ b/motulator/drive/control/sm/_current_vector.py @@ -4,15 +4,15 @@ import numpy as np -from motulator.drive.control import DriveCtrl, SpeedCtrl -from motulator.common.control import ComplexPICtrl +from motulator.drive.control import DriveControlSystem, SpeedController +from motulator.common.control import ComplexPIController from motulator.drive.utils import SynchronousMachinePars from motulator.drive.control.sm._common import Observer, ObserverCfg from motulator.drive.control.sm._torque import TorqueCharacteristics # %% -class CurrentVectorCtrl(DriveCtrl): +class CurrentVectorControl(DriveControlSystem): """ Current vector control for synchronous machine drives. @@ -28,7 +28,7 @@ class CurrentVectorCtrl(DriveCtrl): T_s : float, optional Sampling period (s). The default is 250e-6. J : float, optional - Moment of inertia (kgm^2). Needed only for the speed controller. + Moment of inertia (kgm²). Needed only for the speed controller. alpha_c : float, optional Current controller bandwidth (rad/s). The default is 2*pi*200. alpha_o : float, optional @@ -42,10 +42,10 @@ class CurrentVectorCtrl(DriveCtrl): Current reference generator. observer : Observer | None Flux and rotor position observer, used in the sensorless mode only. - current_ctrl : CurrentCtrl - Current controller. The default is CurrentCtrl(par, 2*np.pi*200). - speed_ctrl : SpeedCtrl | None - Speed controller. The default is SpeedCtrl(par.J, 2*np.pi*4). + current_ctrl : CurrentController + Current controller. The default is CurrentController(par, 2*np.pi*200). + speed_ctrl : SpeedController | None + Speed controller. The default is SpeedController(par.J, 2*np.pi*4). """ @@ -60,9 +60,9 @@ def __init__( sensorless=True): super().__init__(par, T_s, sensorless) self.current_reference = CurrentReference(par, cfg) - self.current_ctrl = CurrentCtrl(par, alpha_c) + self.current_ctrl = CurrentController(par, alpha_c) if J is not None: - self.speed_ctrl = SpeedCtrl(J, 2*np.pi*4) + self.speed_ctrl = SpeedController(J, 2*np.pi*4) else: self.speed_ctrl = None if sensorless: @@ -100,7 +100,7 @@ def update(self, fbk, ref): # %% -class CurrentCtrl(ComplexPICtrl): +class CurrentController(ComplexPIController): """ Current controller for synchronous machines. diff --git a/motulator/drive/control/sm/_flux_vector.py b/motulator/drive/control/sm/_flux_vector.py index 8d614629e..2137944df 100644 --- a/motulator/drive/control/sm/_flux_vector.py +++ b/motulator/drive/control/sm/_flux_vector.py @@ -4,14 +4,14 @@ import numpy as np -from motulator.drive.control import DriveCtrl, SpeedCtrl +from motulator.drive.control import DriveControlSystem, SpeedController from motulator.drive.utils import SynchronousMachinePars from motulator.drive.control.sm._common import Observer, ObserverCfg from motulator.drive.control.sm._torque import TorqueCharacteristics # %% -class FluxVectorCtrl(DriveCtrl): +class FluxVectorControl(DriveControlSystem): """ Flux-vector control of synchronous machine drives. @@ -35,7 +35,7 @@ class FluxVectorCtrl(DriveCtrl): alpha_o : float, optional Observer bandwidth (rad/s). The default is 2*pi*100. J : float, optional - Moment of inertia (kg*m^2). Needed only for the speed controller. + Moment of inertia (kgm²). Needed only for the speed controller. T_s : float Sampling period (s). The default is 250e-6. sensorless : bool, optional @@ -68,7 +68,7 @@ def __init__( # Subsystems self.flux_torque_reference = FluxTorqueReference(cfg) if J is not None: - self.speed_ctrl = SpeedCtrl(J, 2*np.pi*4) + self.speed_ctrl = SpeedController(J, 2*np.pi*4) else: self.speed_ctrl = None self.observer = Observer( diff --git a/motulator/drive/control/sm/_obs_vhz.py b/motulator/drive/control/sm/_obs_vhz.py index 18146014d..2573db2ee 100644 --- a/motulator/drive/control/sm/_obs_vhz.py +++ b/motulator/drive/control/sm/_obs_vhz.py @@ -5,7 +5,7 @@ import numpy as np -from motulator.drive.control import DriveCtrl +from motulator.drive.control import DriveControlSystem from motulator.common.control import RateLimiter from motulator.drive.control.sm._flux_vector import ( FluxTorqueReference, FluxTorqueReferenceCfg) @@ -14,7 +14,7 @@ # %% @dataclass -class ObserverBasedVHzCtrlCfg(FluxTorqueReferenceCfg): +class ObserverBasedVHzControlCfg(FluxTorqueReferenceCfg): """ Control system configuration. @@ -45,7 +45,7 @@ def __post_init__(self, par, alpha_tau): # %% -class ObserverBasedVHzCtrl(DriveCtrl): +class ObserverBasedVHzControl(DriveControlSystem): """ Observer-based V/Hz control for synchronous motors. @@ -55,7 +55,7 @@ class ObserverBasedVHzCtrl(DriveCtrl): ---------- par : SynchronousMachinePars Machine model parameters. - cfg : ObserverBasedVHzCtrlCfg + cfg : ObserverBasedVHzControlCfg Control system configuration. T_s : float, optional Sampling period (s). The default is 250e-6. diff --git a/motulator/drive/control/sm/_signal_inj.py b/motulator/drive/control/sm/_signal_inj.py index a9426580c..55c25468a 100644 --- a/motulator/drive/control/sm/_signal_inj.py +++ b/motulator/drive/control/sm/_signal_inj.py @@ -3,14 +3,14 @@ from types import SimpleNamespace import numpy as np -from motulator.drive.control import DriveCtrl, SpeedCtrl +from motulator.drive.control import DriveControlSystem, SpeedController from motulator.drive.control.sm._current_vector import ( - CurrentCtrl, CurrentReference) + CurrentController, CurrentReference) from motulator.common.utils import wrap # %% -class SignalInjectionCtrl(DriveCtrl): +class SignalInjectionControl(DriveControlSystem): """ Sensorless control with signal injection for synchronous machine drives. @@ -37,7 +37,7 @@ class SignalInjectionCtrl(DriveCtrl): cfg : CurrentReferenceCfg Reference generation configuration. J : float, optional - Moment of inertia (kg*m^2). Needed only for the speed controller. + Moment of inertia (kgm²). Needed only for the speed controller. T_s : float Sampling period (s). @@ -46,11 +46,11 @@ class SignalInjectionCtrl(DriveCtrl): def __init__(self, par, cfg, J=None, T_s=250e-6): super().__init__(par, T_s, sensorless=True) self.current_ref = CurrentReference(par, cfg) - self.current_ctrl = CurrentCtrl(par, 2*np.pi*200) + self.current_ctrl = CurrentController(par, 2*np.pi*200) self.pll = PhaseLockedLoop(w_o=2*np.pi*40) self.signal_inj = SignalInjection(par, U_inj=250) if J is not None: - self.speed_ctrl = SpeedCtrl(J, 2*np.pi*4) + self.speed_ctrl = SpeedController(J, 2*np.pi*4) else: self.speed_ctrl = None self.observer = None diff --git a/pyproject.toml b/pyproject.toml index 38457fecc..a53e2c034 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "motulator" -version = "0.3.0" +version = "0.3.1" dependencies = [ "numpy", "scipy",