فهرست منبع

feat:负载观测模块单元测试通过
增加电机仿真MBD模型与代码

CN\guohui27 2 سال پیش
والد
کامیت
aab6c79508
38فایلهای تغییر یافته به همراه3270 افزوده شده و 16 حذف شده
  1. 7 1
      User project/2.MotorDrive/Include/asr.h
  2. 7 1
      User project/2.MotorDrive/Include/pwrlim.h
  3. 8 1
      User project/2.MotorDrive/Include/torqobs.h
  4. 1 1
      User project/2.MotorDrive/Source/packed
  5. 4 4
      User project/3.BasicFunction/Source/power.c
  6. 6 1
      User project/4.BasicHardwSoftwLayer/2.BasicSoftwLayer/Include/mathtool.h
  7. 2 2
      unit_test/main.cpp
  8. 19 0
      unit_test/mc_pu_base.c
  9. 68 0
      unit_test/mc_pu_base.h
  10. 93 0
      unit_test/mc_status.c
  11. 132 0
      unit_test/mc_status.h
  12. 859 0
      unit_test/motor_sim/PmsmSimUt.cpp
  13. 478 0
      unit_test/motor_sim/PmsmSimUt.h
  14. 432 0
      unit_test/motor_sim/PmsmSimUt_data.cpp
  15. 27 0
      unit_test/motor_sim/PmsmSimUt_private.h
  16. 102 0
      unit_test/motor_sim/PmsmSimUt_types.h
  17. 47 0
      unit_test/motor_sim/builtin_typeid_types.h
  18. 105 0
      unit_test/motor_sim/ert_main.cpp
  19. 11 0
      unit_test/motor_sim/model/.gitignore
  20. BIN
      unit_test/motor_sim/model/PmsmSimUt.slx
  21. 2 0
      unit_test/motor_sim/model/copy_file.m
  22. BIN
      unit_test/motor_sim/model/private.sldd
  23. 31 0
      unit_test/motor_sim/multiword_types.h
  24. 97 0
      unit_test/motor_sim/rtGetInf.cpp
  25. 41 0
      unit_test/motor_sim/rtGetInf.h
  26. 63 0
      unit_test/motor_sim/rtGetNaN.cpp
  27. 39 0
      unit_test/motor_sim/rtGetNaN.h
  28. 99 0
      unit_test/motor_sim/rt_nonfinite.cpp
  29. 67 0
      unit_test/motor_sim/rt_nonfinite.h
  30. 156 0
      unit_test/motor_sim/rtwtypes.h
  31. 134 0
      unit_test/test_torqobs.cpp
  32. 2 0
      unit_test/test_torquesensor.cpp
  33. 25 0
      unit_test/test_typedefine.h
  34. 5 2
      unit_test/test_user.c
  35. 8 0
      unit_test/test_user.h
  36. 64 0
      unit_test/tools/motor_sim_helper.cpp
  37. 18 0
      unit_test/tools/motor_sim_helper.h
  38. 11 3
      xmake.lua

+ 7 - 1
User project/2.MotorDrive/Include/asr.h

@@ -21,6 +21,9 @@ Revising History (ECL of this file):
 #ifndef ASR_H
 #define ASR_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
 /************************************************************************
  Compiler Directives (N/A)
 *************************************************************************/
@@ -135,8 +138,11 @@ _ASR_EXT void asr_voSpdPIInit(void);
 /************************************************************************
  Flag Define (N/A)
 *************************************************************************/
-#endif
+#ifdef __cplusplus
+}
+#endif // __cplusplus
 
+#endif
 /************************************************************************
  Copyright (c) 2018 Welling Motor Technology(Shanghai) Co. Ltd.
  All rights reserved.

+ 7 - 1
User project/2.MotorDrive/Include/pwrlim.h

@@ -21,6 +21,9 @@
 #ifndef PWRLIM_H
 #define PWRLIM_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
 /************************************************************************
  Compiler Directives (N/A)
 ************************************************************************/
@@ -136,7 +139,10 @@ _PWRLIM_EXT void pwr_voPwrLim2(const PWRLIM_IN *in, const PWRLIM_COF *cof, PWRLI
  Flag Define (N/A)
 ************************************************************************/
 
-/***********************************************************************/
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
 #endif
 /************************************************************************
  Copyright (c) 2018 Welling Motor Technology(Shanghai) Co. Ltd.

+ 8 - 1
User project/2.MotorDrive/Include/torqobs.h

@@ -22,6 +22,10 @@ Revising History (ECL of this file):
 #define TORQOBS_H
 
 #include "typedefine.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
 /************************************************************************
  Definitions & Macros (#define ...)
 *************************************************************************/
@@ -106,8 +110,11 @@ void torqobs_voCal(const TORQOBS_IN *in, const TORQOBS_COEFOUT *cof, TORQOBS_OUT
 /************************************************************************
  Flag Define (N/A)
 *************************************************************************/
-#endif
+#ifdef __cplusplus
+}
+#endif // __cplusplus
 
+#endif
 /************************************************************************
  Copyright (c) 2018 Welling Motor Technology(Shanghai) Co. Ltd.
  All rights reserved.

+ 1 - 1
User project/2.MotorDrive/Source/packed

@@ -1 +1 @@
-Subproject commit cbefbcaa0f012fe049a449241ab03895cd035aa2
+Subproject commit 31ea0d9cb25aef4602413c9e8deb40d634ddecb4

+ 4 - 4
User project/3.BasicFunction/Source/power.c

@@ -65,7 +65,7 @@ void power_voPowerManagement(ULONG ulAutoPowerOffDelayTime, ULONG SysTickCnt, UL
 {    
     switch(power_stPowStateOut.powerstate)
     {
-        case POWER_START: //��Դ�����£�����1s����POWER ON
+        case POWER_START: // 电源键按下,超过1s进入POWER ON
         {
             if(IO_POWER_STATE != 0)
             {
@@ -81,7 +81,7 @@ void power_voPowerManagement(ULONG ulAutoPowerOffDelayTime, ULONG SysTickCnt, UL
             AutoPowerOffTimeCnt = SysTickCnt;
             break;
         }
-        case POWER_ON: // 3s�󣬼��PC0�����Ƿ���PC0��������POWER_ON_END
+        case POWER_ON: // 3s后,检测PC0按键是否弹起,PC0弹起后进入POWER_ON_END
         {
             power_stPowStateOut.uwPowerOn2OffCnt++;
             if (power_stPowStateOut.uwPowerOn2OffCnt >= power_stPowStateCof.uwPowerOn2OffTimeCnt)
@@ -96,7 +96,7 @@ void power_voPowerManagement(ULONG ulAutoPowerOffDelayTime, ULONG SysTickCnt, UL
             }          
             break;
         }
-        case POWER_ON_END: //��Դ�����½���POWER_OFF��������趨ʱ����Զ�����POWER_OFF
+        case POWER_ON_END: // 电源键按下进入POWER_OFF,或待机设定时候后自动进入POWER_OFF
         {
             //The key pushed down for "uwPowerShutTouchTimeCnt" to POWER_OFF
             if (IO_POWER_STATE != 0)
@@ -139,7 +139,7 @@ void power_voPowerManagement(ULONG ulAutoPowerOffDelayTime, ULONG SysTickCnt, UL
             }  
             break;
         }  
-        case POWER_OFF: //�ػ������ȴ����ݴ洢��ɣ��ر�LOCK
+        case POWER_OFF: // 关机处理,等待数据存储完成,关闭LOCK
         { 
             //Finish save and wait 1s, or delay for 3s
             if (((EESaveFinishFlg == TRUE) && (ParaSaveEEFlg == FALSE) && ((SysTickCnt - PowerOffDTimeOut) > 1000)) || 

+ 6 - 1
User project/4.BasicHardwSoftwLayer/2.BasicSoftwLayer/Include/mathtool.h

@@ -21,6 +21,9 @@ Revising History (ECL of this file):
 #ifndef MATHTOOL_H
 #define MATHTOOL_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
 /************************************************************************
  Modules used (included header files)
 *************************************************************************/
@@ -106,8 +109,10 @@ _MATHTOOL_EXT UWORD mth_voArctan(const ARCTAN_IN *in);
 /************************************************************************
  Flag Define (N/A)
 *************************************************************************/
+#ifdef __cplusplus
+}
+#endif // __cplusplus
 
-/************************************************************************/
 #endif
 /*************************************************************************
  Copyright (c) 2011 Welling Motor Technology(Shanghai) Co. Ltd.

+ 2 - 2
unit_test/main.cpp

@@ -1,6 +1,6 @@
 #include <gtest/gtest.h>
 #include "scope.h"
-// #include "motor_sim_helper.h"
+#include "motor_sim_helper.h"
 
 // int main(void)
 // {
@@ -20,7 +20,7 @@ int main(int argc, char **argv)
     // ::testing::GTEST_FLAG(output) = "xml:unittest.xml";
     ::testing::InitGoogleTest(&argc, argv);
     UdpScope::Init(50000);
-    // MotorSimHelper::StoreDefaultParam();
+    MotorSimHelper::StoreDefaultParam();
     auto res = RUN_ALL_TESTS();
     UdpScope::Deinit();
     return res;

+ 19 - 0
unit_test/mc_pu_base.c

@@ -0,0 +1,19 @@
+#include "mc_pu_base.h"
+
+void McPuBaseInit(McPuBase *base, McPuBaseIn *in)
+{
+    base->uwPairsb   = in->Pairsb;
+    base->uwUbVt     = in->UbVt;
+    base->uwIbAp     = in->IbAp;
+    base->uwFbHz     = in->FbHz;
+    base->uwVbRpm    = (u16)((u32)60 * base->uwFbHz / base->uwPairsb);
+    base->uwPbW      = (u16)((u32)3 * base->uwUbVt * base->uwIbAp / 100 >> 1);
+    base->uwRbOhm    = (u16)((u32)base->uwUbVt * 100000 / base->uwIbAp);
+    base->uwWeb      = (u16)((u32)2 * 31416 * base->uwFbHz / 1000);
+    base->uwTbUs     = (u16)((u32)100000000 / base->uwWeb);
+    base->uwLbHm     = (u16)((u32)base->uwRbOhm * 100000 / base->uwWeb);
+    base->uwFluxbWeb = (u16)((u32)1000000 * base->uwUbVt / base->uwWeb);
+    base->uwTqbNm    = (u16)((u32)3 * base->uwUbVt * base->uwIbAp * base->uwPairsb * 10 / base->uwWeb >> 1);
+    base->uwJbKgm2 =
+        (u16)((((u64)base->uwPairsb * base->uwPairsb * base->uwUbVt * base->uwIbAp * 10000000 * 3 / base->uwWeb / base->uwWeb) >> 1) / base->uwWeb * 1000);
+}

+ 68 - 0
unit_test/mc_pu_base.h

@@ -0,0 +1,68 @@
+/**
+ * @file motor_pu_base.h
+ * @author Xiao Lifan (xiaolf6@midea.com)
+ * @brief 基值系统定义
+ * @version 0.1
+ * @date 2023-03-22
+ *
+ * @copyright Copyright (c) 2023
+ *
+ */
+
+#ifndef _MOTOR_PU_BASE_H_
+#define _MOTOR_PU_BASE_H_
+
+#include "test_typedefine.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+/**
+ * @brief 电机基值系统输入量/基本基值
+ * @note 所有值均为Q0
+ *
+ */
+typedef struct McPuBaseIn
+{
+    u16 Pairsb; /**< Unit: None */
+    u16 UbVt;   /**< Unit: 0.1 V */
+    u16 IbAp;   /**< Unit: 0.01 A */
+    u16 FbHz;   /**< Unit: Hz */
+} McPuBaseIn;
+
+/**
+ * @brief 电机基值
+ * @note 所有值均为Q0
+ *
+ */
+typedef struct McPuBase
+{
+    u16 uwPairsb;   /**< Unit: None */
+    u16 uwUbVt;     /**< Unit: 0.1 V */
+    u16 uwIbAp;     /**< Unit: 0.01 A */
+    u16 uwFbHz;     /**< Unit: Hz */
+    u16 uwVbRpm;    /**< Unit: RPM */
+    u16 uwPbW;      /**< Unit: 0.1 W */
+    u16 uwRbOhm;    /**< Unit: 0.01 Ohm */
+    u16 uwWeb;      /**< Unit: s^-1 */
+    u16 uwTbUs;     /**< Unit: 0.1 us */
+    u16 uwLbHm;     /**< Unit: 0.01 mH */
+    u16 uwFluxbWeb; /**< Unit: 0.01 mWb */
+    u16 uwTqbNm;    /**< Unit: Nm */
+    u16 uwJbKgm2;   /**< Unit: 1e-10 kg.m^2 */
+} McPuBase;
+
+/**
+ * @brief 初始化电机基值
+ *
+ * @param base 电机基本基值与推导基值
+ * @param in 电机基本基值
+ */
+void McPuBaseInit(McPuBase *base, McPuBaseIn *in);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif

+ 93 - 0
unit_test/mc_status.c

@@ -0,0 +1,93 @@
+#include "mc_status.h"
+#include "string.h"
+
+void McStatusInit(McStatus *s, McPuBase *base)
+{
+    s->Base = base;
+    memset(&s->Named, 0, sizeof(McStatusNamed));
+    memset(&s->Pu, 0, sizeof(McStatusPu));
+}
+
+void McStatusSyncNamed(McStatus *s)
+{
+    McPuBase      *b = s->Base;
+    McStatusNamed *n = &s->Named;
+    McStatusPu    *p = &s->Pu;
+
+    n->Ia    = (s16)((p->swIa * b->uwIbAp) >> 14);
+    n->Ib    = (s16)((p->swIb * b->uwIbAp) >> 14);
+    n->Ic    = (s16)((p->swIc * b->uwIbAp) >> 14);
+    n->IpeakAbs = (s16)((p->swIpeakAbs * b->uwIbAp) >> 14);
+
+    n->Ialpha = (s16)((p->swIalpha * b->uwIbAp) >> 14);
+    n->Ibeta  = (s16)((p->swIbeta * b->uwIbAp) >> 14);
+    n->Izero  = (s16)((p->swIzero * b->uwIbAp) >> 14);
+
+    n->Id = (s16)(((s32)p->swId * b->uwIbAp) >> 14);
+    n->Iq = (s16)(((s32)p->swIq * b->uwIbAp) >> 14);
+    n->I0 = (s16)(((s32)p->swI0 * b->uwIbAp) >> 14);
+
+    n->Ua = (s16)(((s32)p->swUa * b->uwUbVt) >> 14);
+    n->Ub = (s16)(((s32)p->swUb * b->uwUbVt) >> 14);
+    n->Uc = (s16)(((s32)p->swUc * b->uwUbVt) >> 14);
+
+    n->Ualpha = (s16)(((s32)p->swUalpha * b->uwUbVt) >> 14);
+    n->Ubeta  = (s16)(((s32)p->swUbeta * b->uwUbVt) >> 14);
+    n->Uzero  = (s16)(((s32)p->swUzero * b->uwUbVt) >> 14);
+
+    n->ElecAngle = (s16)(((s32)p->swElecAngle * 360) >> 15);
+    n->ElecOmega = (s16)(((s32)p->swElecOmega * b->uwWeb) >> 15);
+    n->MechAngle = (s16)(((s32)p->swMechAngle * 360) >> 15);
+    n->MechOmega = (s16)(((s32)p->swMechOmega * b->uwWeb) >> 15);
+
+    n->ElecFreq = (s16)(((s32)p->swElecFreq * b->uwFbHz) >> 15);
+
+    n->Uac = (s16)(((s32)p->swUac * b->uwUbVt) >> 14);
+    n->Udc = (s16)(((s32)p->swUdc * b->uwUbVt) >> 14);
+
+    n->TempIgbt  = p->swTempIgbt;
+    n->TempMotor = p->swTempMotor;
+    n->TempInv   = p->swTempInv;
+}
+
+void McStatusSyncPu(McStatus *s)
+{
+    McPuBase      *b = s->Base;
+    McStatusNamed *n = &s->Named;
+    McStatusPu    *p = &s->Pu;
+
+    p->swIa    = (s16)(((s32)n->Ia << 14) / b->uwIbAp);
+    p->swIb    = (s16)(((s32)n->Ib << 14) / b->uwIbAp);
+    p->swIc    = (s16)(((s32)n->Ic << 14) / b->uwIbAp);
+    p->swIpeakAbs = (s16)(((s32)n->IpeakAbs << 14) / b->uwIbAp);
+
+    p->swIalpha = (s16)(((s32)n->Ialpha << 14) / b->uwIbAp);
+    p->swIalpha = (s16)(((s32)n->Ibeta << 14) / b->uwIbAp);
+    p->swIzero  = (s16)(((s32)n->Izero << 14) / b->uwIbAp);
+
+    p->swId = (s16)(((s32)n->Id << 14) / b->uwIbAp);
+    p->swIq = (s16)(((s32)n->Iq << 14) / b->uwIbAp);
+    p->swI0 = (s16)(((s32)n->I0 << 14) / b->uwIbAp);
+
+    p->swUa = (s16)(((s32)n->Ua << 14) / b->uwUbVt);
+    p->swUb = (s16)(((s32)n->Ub << 14) / b->uwUbVt);
+    p->swUc = (s16)(((s32)n->Uc << 14) / b->uwUbVt);
+
+    p->swUalpha = (s16)(((s32)n->Ualpha << 14) / b->uwUbVt);
+    p->swUbeta  = (s16)(((s32)n->Ubeta << 14) / b->uwUbVt);
+    p->swUzero  = (s16)(((s32)n->Uzero << 14) / b->uwUbVt);
+
+    p->swElecAngle = (s16)((s32)(n->ElecAngle << 15) / 360);
+    p->swElecOmega = (s16)((s32)(n->ElecOmega << 15) / b->uwWeb / 10);
+    p->swMechAngle = (s16)((s32)(n->MechAngle << 15) / 360);
+    p->swMechOmega = (s16)((s32)(n->MechOmega << 15) / b->uwWeb / 10);
+
+    p->swElecFreq = (s16)(((s32)n->ElecFreq << 15) / b->uwFbHz / 10);
+
+    p->swUac = (s16)(((s32)n->Uac << 14) / b->uwUbVt);
+    p->swUdc = (s16)(((s32)n->Udc << 14) / b->uwUbVt);
+
+    p->swTempIgbt  = n->TempIgbt;
+    p->swTempMotor = n->TempMotor;
+    p->swTempInv   = n->TempInv;
+}

+ 132 - 0
unit_test/mc_status.h

@@ -0,0 +1,132 @@
+/**
+ * @file mc_status.h
+ * @author Xiao Lifan (xiaolf6@midea.com)
+ * @brief 电机状态描述定义
+ * @version 0.1
+ * @date 2023-03-22
+ *
+ * @copyright Copyright (c) 2023
+ *
+ */
+
+#ifndef _MC_STATUS_H_
+#define _MC_STATUS_H_
+
+#include "test_typedefine.h"
+#include "mc_pu_base.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+/**
+ * @brief 电机控制状态信息有名值
+ *
+ */
+typedef struct McStatusNamed
+{
+    /* 电机状态 */
+    s16 Ia;        /**< Unit: 0.01 A */
+    s16 Ib;        /**< Unit: 0.01 A */
+    s16 Ic;        /**< Unit: 0.01 A */
+    s16 IpeakAbs;     /**< Unit: 0.01 A */
+    s16 Ialpha;    /**< Unit: 0.01 A */
+    s16 Ibeta;     /**< Unit: 0.01 A */
+    s16 Izero;     /**< Unit: 0.01 A */
+    s16 Id;        /**< Unit: 0.01 A */
+    s16 Iq;        /**< Unit: 0.01 A */
+    s16 I0;        /**< Unit: 0.01 A */
+    s16 Ua;        /**< Unit: 0.1 V */
+    s16 Ub;        /**< Unit: 0.1 V */
+    s16 Uc;        /**< Unit: 0.1 V */
+    s16 Ualpha;    /**< Unit: 0.1 V */
+    s16 Ubeta;     /**< Unit: 0.1 V */
+    s16 Uzero;     /**< Unit: 0.1 V */
+    s16 ElecAngle; /**< Unit: 0.1 Degree */
+    s16 ElecOmega; /**< Unit: 0.1 s^-1 */
+    s16 MechAngle; /**< Unit: 0.1 Degree */
+    s16 MechOmega; /**< Unit: 0.1 s^-1 */
+    s16 ElecFreq;  /**< Unit: 0.1 Hz */
+
+    /* 逆变器状态 */
+    s16 Uac; /**< Unit: 0.1 V */
+    s16 Udc; /**< Unit: 0.1 V */
+
+    /* 温度 */
+    s16 TempIgbt;  /**< Unit: 0.1 C */
+    s16 TempMotor; /**< Unit: 0.1 C */
+    s16 TempInv;   /**< Unit: 0.1 C */
+} McStatusNamed;
+
+/**
+ * @brief 电机控制状态信息Pu值
+ *
+ * @note 温度信息不进行标幺,仍为有名值
+ */
+typedef struct McStatusPu
+{
+    /* 电机状态 */
+    s16 swIa;        /**< Q14 */
+    s16 swIb;        /**< Q14 */
+    s16 swIc;        /**< Q14 */
+    s16 swIpeakAbs;     /**< Q14 */
+    s16 swIalpha;    /**< Q14 */
+    s16 swIbeta;     /**< Q14 */
+    s16 swIzero;     /**< Q14 */
+    s16 swId;        /**< Q14 */
+    s16 swIq;        /**< Q14 */
+    s16 swI0;        /**< Q14 */
+    s16 swUa;        /**< Q14 */
+    s16 swUb;        /**< Q14 */
+    s16 swUc;        /**< Q14 */
+    s16 swUalpha;    /**< Q14 */
+    s16 swUbeta;     /**< Q14 */
+    s16 swUzero;     /**< Q14 */
+    s16 swElecAngle; /**< Q15, Base 2Pi */
+    s16 swElecOmega; /**< Q15 */
+    s16 swMechAngle; /**< Q15, Base 2Pi */
+    s16 swMechOmega; /**< Q15 */
+    s16 swElecFreq;  /**< Q15 */
+
+    /* 逆变器状态 */
+    s16 swUac; /**< Q14 */
+    s16 swUdc; /**< Q14 */
+
+    /* 温度 */
+    s16 swTempIgbt;  /**< Unit: 0.1 C */
+    s16 swTempMotor; /**< Unit: 0.1 C */
+    s16 swTempInv;   /**< Unit: 0.1 C */
+} McStatusPu;
+
+/**
+ * @brief 电机及逆变器状态结构体
+ *
+ */
+typedef struct McStatus
+{
+    McStatusNamed Named; /**< 有名值 */
+    McStatusPu    Pu;    /**< 标幺值 */
+    McPuBase     *Base;  /**< 基值指针 */
+} McStatus;
+
+void McStatusInit(McStatus *s, McPuBase *base);
+
+/**
+ * @brief 从电机状态标幺值计算有名值
+ *
+ * @param s 电机状态结构体
+ */
+void McStatusSyncNamed(McStatus *s);
+
+/**
+ * @brief 从电机状有名值计算标幺值
+ *
+ * @param s 电机状态结构体
+ */
+void McStatusSyncPu(McStatus *s);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif

+ 859 - 0
unit_test/motor_sim/PmsmSimUt.cpp

@@ -0,0 +1,859 @@
+//
+// File: PmsmSimUt.cpp
+//
+// Code generated for Simulink model 'PmsmSimUt'.
+//
+// Model version                  : 1.15
+// Simulink Coder version         : 9.4 (R2020b) 29-Jul-2020
+// C/C++ source code generated on : Fri Jul 28 01:40:47 2023
+//
+// Target selection: ert.tlc
+// Embedded hardware selection: Intel->x86-64 (Windows64)
+// Code generation objectives: Unspecified
+// Validation result: Not run
+//
+#include "PmsmSimUt.h"
+#include "PmsmSimUt_private.h"
+
+real_T rt_modd_snf(real_T u0, real_T u1)
+{
+  real_T q;
+  real_T y;
+  boolean_T yEq;
+  y = u0;
+  if (u1 == 0.0) {
+    if (u0 == 0.0) {
+      y = u1;
+    }
+  } else if (rtIsNaN(u0) || rtIsNaN(u1) || rtIsInf(u0)) {
+    y = (rtNaN);
+  } else if (u0 == 0.0) {
+    y = 0.0 / u1;
+  } else if (rtIsInf(u1)) {
+    if ((u1 < 0.0) != (u0 < 0.0)) {
+      y = u1;
+    }
+  } else {
+    y = std::fmod(u0, u1);
+    yEq = (y == 0.0);
+    if ((!yEq) && (u1 > std::floor(u1))) {
+      q = std::abs(u0 / u1);
+      yEq = !(std::abs(q - std::floor(q + 0.5)) > DBL_EPSILON * q);
+    }
+
+    if (yEq) {
+      y = u1 * 0.0;
+    } else {
+      if ((u0 < 0.0) != (u1 < 0.0)) {
+        y += u1;
+      }
+    }
+  }
+
+  return y;
+}
+
+// Model step function
+void PmsmSimUtModelClass::step()
+{
+  real_T rtb_Gain1_c[3];
+  real_T rtb_Add1;
+  real_T rtb_Add2;
+  real_T rtb_Fcn1;
+  real_T rtb_Gain;
+  real_T rtb_Gain1_i;
+  real_T rtb_Gain2_k;
+  real_T rtb_Mod;
+  real_T rtb_Relay2;
+  real_T rtb_Switch_h;
+  real_T rtb_Switch_idx_0;
+  real_T rtb_Switch_idx_1;
+  real_T rtb_a;
+  real_T rtb_a_tmp_tmp;
+  real_T rtb_a_tmp_tmp_0;
+  real_T rtb_id;
+  real_T rtb_iq;
+  int32_T i;
+  uint8_T rtb_Compare;
+
+  // Math: '<S17>/Mod' incorporates:
+  //   Constant: '<S17>/Constant'
+  //   DiscreteIntegrator: '<S17>/Discrete-Time Integrator'
+
+  rtb_Mod = rt_modd_snf(PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE,
+                        PmsmSimUt_P.Constant_Value);
+
+  // Fcn: '<S16>/id' incorporates:
+  //   Constant: '<S16>/Constant1'
+  //   Constant: '<S16>/Constant2'
+  //   DiscreteIntegrator: '<S16>/Discrete-Time Integrator'
+
+  rtb_id = (PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_c -
+            PmsmSimUt_P.Params.Flux) / PmsmSimUt_P.Params.Ld;
+
+  // Fcn: '<S16>/iq' incorporates:
+  //   Constant: '<S16>/Constant3'
+  //   DiscreteIntegrator: '<S16>/Discrete-Time Integrator1'
+
+  rtb_iq = PmsmSimUt_DW.DiscreteTimeIntegrator1_DSTATE / PmsmSimUt_P.Params.Lq;
+
+  // Outputs for Enabled SubSystem: '<S20>/Subsystem - pi//2 delay' incorporates:
+  //   EnablePort: '<S24>/Enable'
+
+  // Outputs for Enabled SubSystem: '<S20>/Subsystem1' incorporates:
+  //   EnablePort: '<S25>/Enable'
+
+  // Fcn: '<S28>/Fcn' incorporates:
+  //   Fcn: '<S24>/Fcn'
+  //   Fcn: '<S24>/Fcn1'
+  //   Fcn: '<S25>/Fcn'
+
+  rtb_a_tmp_tmp = std::sin(rtb_Mod);
+  rtb_a_tmp_tmp_0 = std::cos(rtb_Mod);
+
+  // End of Outputs for SubSystem: '<S20>/Subsystem1'
+  // End of Outputs for SubSystem: '<S20>/Subsystem - pi//2 delay'
+  rtb_a = rtb_a_tmp_tmp_0 * rtb_id - rtb_a_tmp_tmp * rtb_iq;
+
+  // Fcn: '<S28>/Fcn1' incorporates:
+  //   Fcn: '<S28>/Fcn'
+
+  rtb_Gain1_i = rtb_a_tmp_tmp * rtb_id + rtb_a_tmp_tmp_0 * rtb_iq;
+
+  // Gain: '<S29>/K1' incorporates:
+  //   Constant: '<S9>/Constant'
+
+  rtb_Gain2_k = PmsmSimUt_P.K1_Gain * PmsmSimUt_P.Constant_Value_e;
+
+  // Fcn: '<S29>/a'
+  rtb_Add2 = rtb_a + rtb_Gain2_k;
+
+  // Fcn: '<S29>/b'
+  rtb_Fcn1 = (-0.5 * rtb_a + 0.8660254037844386 * rtb_Gain1_i) + rtb_Gain2_k;
+
+  // Fcn: '<S29>/c'
+  rtb_a = (-0.5 * rtb_a - 0.8660254037844386 * rtb_Gain1_i) + rtb_Gain2_k;
+
+  // Outport: '<Root>/Out' incorporates:
+  //   Gain: '<S29>/K2'
+
+  PmsmSimUt_Y.Out.Iabc[0] = PmsmSimUt_P.K2_Gain * rtb_Add2;
+  PmsmSimUt_Y.Out.Iabc[1] = PmsmSimUt_P.K2_Gain * rtb_Fcn1;
+  PmsmSimUt_Y.Out.Iabc[2] = PmsmSimUt_P.K2_Gain * rtb_a;
+
+  // Switch: '<Root>/Switch2' incorporates:
+  //   Inport: '<Root>/ObsIn'
+
+  if (PmsmSimUt_U.ObsIn.Enable > PmsmSimUt_P.Switch2_Threshold) {
+    rtb_Fcn1 = PmsmSimUt_U.ObsIn.Theta;
+  } else {
+    rtb_Fcn1 = rtb_Mod;
+  }
+
+  // End of Switch: '<Root>/Switch2'
+
+  // RelationalOperator: '<S10>/Compare' incorporates:
+  //   Constant: '<S10>/Constant'
+  //   Constant: '<S1>/Constant'
+
+  rtb_Compare = (PmsmSimUt_P.AlphaBetaZerotodq0_Alignment ==
+                 PmsmSimUt_P.CompareToConstant_const);
+
+  // Sum: '<Root>/Add' incorporates:
+  //   Inport: '<Root>/ObsIn'
+
+  rtb_Add2 = PmsmSimUt_U.ObsIn.Theta - rtb_Mod;
+
+  // Outputs for Enabled SubSystem: '<S1>/Subsystem1' incorporates:
+  //   EnablePort: '<S13>/Enable'
+
+  if (rtb_Compare > 0) {
+    // Fcn: '<S13>/Fcn' incorporates:
+    //   Fcn: '<S13>/Fcn1'
+
+    rtb_Gain1_i = std::sin(rtb_Add2);
+    rtb_Add1 = std::cos(rtb_Add2);
+
+    // Fcn: '<S13>/Fcn'
+    PmsmSimUt_B.Fcn_g = rtb_id * rtb_Add1 + rtb_iq * rtb_Gain1_i;
+
+    // Fcn: '<S13>/Fcn1'
+    PmsmSimUt_B.Fcn1_e = -rtb_id * rtb_Gain1_i + rtb_iq * rtb_Add1;
+  }
+
+  // End of Outputs for SubSystem: '<S1>/Subsystem1'
+
+  // Outputs for Enabled SubSystem: '<S1>/Subsystem - pi//2 delay' incorporates:
+  //   EnablePort: '<S12>/Enable'
+
+  // RelationalOperator: '<S11>/Compare' incorporates:
+  //   Constant: '<S11>/Constant'
+  //   Constant: '<S1>/Constant'
+
+  if (PmsmSimUt_P.AlphaBetaZerotodq0_Alignment ==
+      PmsmSimUt_P.CompareToConstant1_const) {
+    // Fcn: '<S12>/Fcn'
+    PmsmSimUt_B.Fcn_b = rtb_id * std::sin(rtb_Add2) - rtb_iq * std::cos(rtb_Add2);
+
+    // Fcn: '<S12>/Fcn1'
+    PmsmSimUt_B.Fcn1_n = rtb_id * std::cos(rtb_Add2) + rtb_iq * std::sin
+      (rtb_Add2);
+  }
+
+  // End of RelationalOperator: '<S11>/Compare'
+  // End of Outputs for SubSystem: '<S1>/Subsystem - pi//2 delay'
+
+  // Switch: '<S1>/Switch'
+  if (rtb_Compare != 0) {
+    rtb_Switch_idx_0 = PmsmSimUt_B.Fcn_g;
+    rtb_Switch_idx_1 = PmsmSimUt_B.Fcn1_e;
+  } else {
+    rtb_Switch_idx_0 = PmsmSimUt_B.Fcn_b;
+    rtb_Switch_idx_1 = PmsmSimUt_B.Fcn1_n;
+  }
+
+  // End of Switch: '<S1>/Switch'
+
+  // Switch: '<Root>/Switch5' incorporates:
+  //   Inport: '<Root>/ObsIn'
+
+  if (PmsmSimUt_U.ObsIn.Enable > PmsmSimUt_P.Switch5_Threshold) {
+    rtb_Add2 = rtb_Switch_idx_1;
+  } else {
+    rtb_Add2 = rtb_iq;
+  }
+
+  // End of Switch: '<Root>/Switch5'
+
+  // Gain: '<S16>/Gain' incorporates:
+  //   DiscreteIntegrator: '<S16>/Discrete-Time Integrator'
+  //   DiscreteIntegrator: '<S16>/Discrete-Time Integrator1'
+  //   Fcn: '<S16>/Te//p=(3//2)*(Flux_d*iq-Flux_q*id)'
+
+  rtb_Gain = (PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_c * rtb_iq -
+              PmsmSimUt_DW.DiscreteTimeIntegrator1_DSTATE * rtb_id) * 1.5 *
+    PmsmSimUt_P.Params.Pn;
+
+  // Outputs for Enabled SubSystem: '<S17>/Subsystem' incorporates:
+  //   EnablePort: '<S18>/Enable'
+
+  // Constant: '<Root>/Constant2'
+  if (PmsmSimUt_P.Params.SpdCtrl > 0.0) {
+    // DiscreteIntegrator: '<S18>/Discrete-Time Integrator1'
+    PmsmSimUt_B.DiscreteTimeIntegrator1 =
+      PmsmSimUt_DW.DiscreteTimeIntegrator1_DSTAT_d;
+
+    // Update for DiscreteIntegrator: '<S18>/Discrete-Time Integrator1' incorporates:
+    //   Constant: '<S18>/Constant1'
+    //   Gain: '<S18>/Gain'
+    //   Gain: '<S18>/Gain1'
+    //   Inport: '<Root>/CtrlIn'
+    //   Product: '<S18>/Divide'
+    //   Sum: '<S18>/Sum'
+
+    PmsmSimUt_DW.DiscreteTimeIntegrator1_DSTAT_d += ((rtb_Gain -
+      PmsmSimUt_P.Params.B * PmsmSimUt_B.DiscreteTimeIntegrator1) -
+      PmsmSimUt_U.CtrlIn.Tm) / PmsmSimUt_P.Params.Jm * PmsmSimUt_P.Params.Ts *
+      PmsmSimUt_P.DiscreteTimeIntegrator1_gainval;
+  }
+
+  // End of Outputs for SubSystem: '<S17>/Subsystem'
+
+  // Switch: '<S17>/Switch' incorporates:
+  //   Constant: '<Root>/Constant2'
+  //   Constant: '<Root>/Constant4'
+  //   Gain: '<S17>/Gain3'
+
+  if (PmsmSimUt_P.Params.SpdCtrl > PmsmSimUt_P.Switch_Threshold) {
+    rtb_Gain2_k = PmsmSimUt_B.DiscreteTimeIntegrator1;
+  } else {
+    rtb_Gain2_k = PmsmSimUt_P.Gain3_Gain * PmsmSimUt_P.Params.SpdRpm;
+  }
+
+  // End of Switch: '<S17>/Switch'
+
+  // Gain: '<S17>/Gain1'
+  rtb_Gain1_i = PmsmSimUt_P.Params.Pn * rtb_Gain2_k;
+
+  // Switch: '<Root>/Switch3' incorporates:
+  //   Inport: '<Root>/ObsIn'
+
+  if (PmsmSimUt_U.ObsIn.Enable > PmsmSimUt_P.Switch3_Threshold) {
+    rtb_a = PmsmSimUt_U.ObsIn.We;
+  } else {
+    rtb_a = rtb_Gain1_i;
+  }
+
+  // End of Switch: '<Root>/Switch3'
+
+  // Switch: '<Root>/Switch4' incorporates:
+  //   Inport: '<Root>/ObsIn'
+
+  if (PmsmSimUt_U.ObsIn.Enable > PmsmSimUt_P.Switch4_Threshold) {
+    rtb_Add1 = rtb_Switch_idx_0;
+  } else {
+    rtb_Add1 = rtb_id;
+  }
+
+  // End of Switch: '<Root>/Switch4'
+
+  // ManualSwitch: '<Root>/Manual Switch1' incorporates:
+  //   Constant: '<Root>/Constant5'
+  //   Constant: '<Root>/Constant6'
+
+  if (PmsmSimUt_P.ManualSwitch1_CurrentSetting == 1) {
+    rtb_Switch_idx_0 = PmsmSimUt_P.Constant5_Value;
+  } else {
+    rtb_Switch_idx_0 = PmsmSimUt_P.Constant6_Value;
+  }
+
+  // End of ManualSwitch: '<Root>/Manual Switch1'
+
+  // Product: '<S5>/Product' incorporates:
+  //   Fcn: '<S5>/Fcn'
+
+  rtb_Switch_idx_1 = (8.1e-5 * rtb_Add1 + 0.0789) * rtb_a * rtb_Switch_idx_0;
+
+  // Sum: '<Root>/Add1' incorporates:
+  //   Inport: '<Root>/CtrlIn'
+
+  rtb_Add1 = PmsmSimUt_U.CtrlIn.IdCmd - rtb_Add1;
+
+  // Switch: '<Root>/Switch1' incorporates:
+  //   Fcn: '<S5>/Fcn1'
+  //   Inport: '<Root>/ICtrlIn'
+  //   Product: '<S5>/Product'
+  //   Sum: '<Root>/Sum1'
+
+  if (PmsmSimUt_U.ICtrlIn.Enable > PmsmSimUt_P.Switch1_Threshold) {
+    rtb_Switch_idx_0 = PmsmSimUt_U.ICtrlIn.UdCtrl;
+  } else {
+    // Sum: '<S15>/Sum6' incorporates:
+    //   DiscreteIntegrator: '<S15>/Discrete-Time Integrator'
+    //   Gain: '<S15>/Kp4'
+
+    rtb_Relay2 = PmsmSimUt_P.Params.CKpd * rtb_Add1 +
+      PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_j;
+
+    // Saturate: '<S15>/Saturation2'
+    if (rtb_Relay2 > PmsmSimUt_P.Saturation2_UpperSat_o) {
+      rtb_Relay2 = PmsmSimUt_P.Saturation2_UpperSat_o;
+    } else {
+      if (rtb_Relay2 < PmsmSimUt_P.Saturation2_LowerSat_o) {
+        rtb_Relay2 = PmsmSimUt_P.Saturation2_LowerSat_o;
+      }
+    }
+
+    // End of Saturate: '<S15>/Saturation2'
+    rtb_Switch_idx_0 = -rtb_a * 8.1e-5 * rtb_Add2 * rtb_Switch_idx_0 +
+      rtb_Relay2;
+  }
+
+  // End of Switch: '<Root>/Switch1'
+
+  // Outputs for Enabled SubSystem: '<Root>/Subsystem' incorporates:
+  //   EnablePort: '<S4>/Enable'
+
+  // Logic: '<Root>/AND' incorporates:
+  //   Constant: '<Root>/Constant1'
+  //   Constant: '<Root>/Constant3'
+  //   Logic: '<Root>/NOT'
+
+  if ((!(PmsmSimUt_P.Params.CustomSpdCtrl != 0.0)) &&
+      (PmsmSimUt_P.Params.SpdCtrl != 0.0)) {
+    PmsmSimUt_DW.Subsystem_MODE = true;
+
+    // Saturate: '<Root>/Saturation2' incorporates:
+    //   Memory: '<S6>/Memory'
+
+    if (PmsmSimUt_DW.Memory_PreviousInput > PmsmSimUt_P.Saturation2_UpperSat_p)
+    {
+      rtb_Switch_h = PmsmSimUt_P.Saturation2_UpperSat_p;
+    } else if (PmsmSimUt_DW.Memory_PreviousInput <
+               PmsmSimUt_P.Saturation2_LowerSat_f) {
+      rtb_Switch_h = PmsmSimUt_P.Saturation2_LowerSat_f;
+    } else {
+      rtb_Switch_h = PmsmSimUt_DW.Memory_PreviousInput;
+    }
+
+    // End of Saturate: '<Root>/Saturation2'
+
+    // Sum: '<S4>/Add4' incorporates:
+    //   Gain: '<Root>/Gain1'
+
+    rtb_Relay2 = rtb_Switch_h - 9.5492965855137211 / PmsmSimUt_P.Params.Pn *
+      rtb_a;
+
+    // DiscreteIntegrator: '<S19>/Discrete-Time Integrator'
+    PmsmSimUt_B.DiscreteTimeIntegrator =
+      PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_n;
+
+    // Sum: '<S19>/Sum6' incorporates:
+    //   Gain: '<S19>/Kp4'
+
+    PmsmSimUt_B.Iq_ref = PmsmSimUt_P.Params.SKp * rtb_Relay2 +
+      PmsmSimUt_B.DiscreteTimeIntegrator;
+
+    // Saturate: '<S19>/Saturation2'
+    if (PmsmSimUt_B.Iq_ref > PmsmSimUt_P.Saturation2_UpperSat) {
+      // Sum: '<S19>/Sum6' incorporates:
+      //   Saturate: '<S19>/Saturation2'
+
+      PmsmSimUt_B.Iq_ref = PmsmSimUt_P.Saturation2_UpperSat;
+    } else {
+      if (PmsmSimUt_B.Iq_ref < PmsmSimUt_P.Saturation2_LowerSat) {
+        // Sum: '<S19>/Sum6' incorporates:
+        //   Saturate: '<S19>/Saturation2'
+
+        PmsmSimUt_B.Iq_ref = PmsmSimUt_P.Saturation2_LowerSat;
+      }
+    }
+
+    // End of Saturate: '<S19>/Saturation2'
+
+    // Update for DiscreteIntegrator: '<S19>/Discrete-Time Integrator' incorporates:
+    //   Gain: '<S19>/Gain'
+    //   Gain: '<S19>/Kp5'
+
+    PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_n += PmsmSimUt_P.Params.SKi *
+      rtb_Relay2 * PmsmSimUt_P.Params.Ts *
+      PmsmSimUt_P.DiscreteTimeIntegrator_gainval;
+    if (PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_n >=
+        PmsmSimUt_P.DiscreteTimeIntegrator_UpperSat) {
+      PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_n =
+        PmsmSimUt_P.DiscreteTimeIntegrator_UpperSat;
+    } else {
+      if (PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_n <=
+          PmsmSimUt_P.DiscreteTimeIntegrator_LowerSat) {
+        PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_n =
+          PmsmSimUt_P.DiscreteTimeIntegrator_LowerSat;
+      }
+    }
+
+    // End of Update for DiscreteIntegrator: '<S19>/Discrete-Time Integrator'
+
+    // Switch: '<Root>/Switch'
+    rtb_Switch_h = PmsmSimUt_B.Iq_ref;
+  } else {
+    if (PmsmSimUt_DW.Subsystem_MODE) {
+      // Disable for DiscreteIntegrator: '<S19>/Discrete-Time Integrator'
+      PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_n =
+        PmsmSimUt_B.DiscreteTimeIntegrator;
+      PmsmSimUt_DW.Subsystem_MODE = false;
+    }
+
+    // Switch: '<Root>/Switch' incorporates:
+    //   Inport: '<Root>/CtrlIn'
+
+    rtb_Switch_h = PmsmSimUt_U.CtrlIn.IqCmd;
+  }
+
+  // End of Logic: '<Root>/AND'
+  // End of Outputs for SubSystem: '<Root>/Subsystem'
+
+  // Sum: '<Root>/Add2'
+  rtb_Add2 = rtb_Switch_h - rtb_Add2;
+
+  // Switch: '<Root>/Switch6' incorporates:
+  //   Inport: '<Root>/ICtrlIn'
+  //   Sum: '<Root>/Sum'
+
+  if (PmsmSimUt_U.ICtrlIn.Enable > PmsmSimUt_P.Switch6_Threshold) {
+    rtb_a = PmsmSimUt_U.ICtrlIn.UqCtrl;
+  } else {
+    // Sum: '<S14>/Sum6' incorporates:
+    //   DiscreteIntegrator: '<S14>/Discrete-Time Integrator'
+    //   Gain: '<S14>/Kp4'
+
+    rtb_Relay2 = PmsmSimUt_P.Params.CKpq * rtb_Add2 +
+      PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_g;
+
+    // Saturate: '<S14>/Saturation2'
+    if (rtb_Relay2 > PmsmSimUt_P.Saturation2_UpperSat_b) {
+      rtb_Relay2 = PmsmSimUt_P.Saturation2_UpperSat_b;
+    } else {
+      if (rtb_Relay2 < PmsmSimUt_P.Saturation2_LowerSat_j) {
+        rtb_Relay2 = PmsmSimUt_P.Saturation2_LowerSat_j;
+      }
+    }
+
+    // End of Saturate: '<S14>/Saturation2'
+    rtb_a = rtb_Switch_idx_1 + rtb_Relay2;
+  }
+
+  // End of Switch: '<Root>/Switch6'
+
+  // Fcn: '<S26>/Fcn' incorporates:
+  //   Fcn: '<S26>/Fcn1'
+
+  rtb_Relay2 = std::sin(rtb_Fcn1);
+  rtb_Fcn1 = std::cos(rtb_Fcn1);
+  rtb_Switch_idx_1 = rtb_Fcn1 * rtb_Switch_idx_0 - rtb_Relay2 * rtb_a;
+
+  // Fcn: '<S26>/Fcn1'
+  rtb_Fcn1 = rtb_Relay2 * rtb_Switch_idx_0 + rtb_Fcn1 * rtb_a;
+
+  // Gain: '<S27>/K1' incorporates:
+  //   Constant: '<S8>/Constant'
+
+  rtb_Switch_idx_0 = PmsmSimUt_P.K1_Gain_j * PmsmSimUt_P.Constant_Value_p;
+
+  // Fcn: '<S27>/a'
+  rtb_a = rtb_Switch_idx_1 + rtb_Switch_idx_0;
+
+  // Fcn: '<S27>/b'
+  rtb_Relay2 = (-0.5 * rtb_Switch_idx_1 + 0.8660254037844386 * rtb_Fcn1) +
+    rtb_Switch_idx_0;
+
+  // Fcn: '<S27>/c'
+  rtb_Switch_idx_1 = (-0.5 * rtb_Switch_idx_1 - 0.8660254037844386 * rtb_Fcn1) +
+    rtb_Switch_idx_0;
+
+  // Gain: '<S27>/K2'
+  rtb_Fcn1 = PmsmSimUt_P.K2_Gain_b * rtb_a;
+  rtb_a = PmsmSimUt_P.K2_Gain_b * rtb_Relay2;
+  rtb_Relay2 = PmsmSimUt_P.K2_Gain_b * rtb_Switch_idx_1;
+  for (i = 0; i < 3; i++) {
+    // Gain: '<S21>/Gain1' incorporates:
+    //   Gain: '<S21>/Gain3'
+
+    rtb_Gain1_c[i] = PmsmSimUt_P.Gain1_Gain * (PmsmSimUt_P.Gain3_Gain_j[i + 6] *
+      rtb_Relay2 + (PmsmSimUt_P.Gain3_Gain_j[i + 3] * rtb_a +
+                    PmsmSimUt_P.Gain3_Gain_j[i] * rtb_Fcn1));
+  }
+
+  // RelationalOperator: '<S22>/Compare' incorporates:
+  //   Constant: '<S20>/Constant'
+  //   Constant: '<S22>/Constant'
+
+  rtb_Compare = (PmsmSimUt_P.AlphaBetaZerotodq0_Alignment_e ==
+                 PmsmSimUt_P.CompareToConstant_const_a);
+
+  // Outputs for Enabled SubSystem: '<S20>/Subsystem1' incorporates:
+  //   EnablePort: '<S25>/Enable'
+
+  if (rtb_Compare > 0) {
+    // Fcn: '<S25>/Fcn'
+    PmsmSimUt_B.Fcn = rtb_Gain1_c[0] * rtb_a_tmp_tmp_0 + rtb_Gain1_c[1] *
+      rtb_a_tmp_tmp;
+
+    // Fcn: '<S25>/Fcn1'
+    PmsmSimUt_B.Fcn1 = -rtb_Gain1_c[0] * rtb_a_tmp_tmp + rtb_Gain1_c[1] *
+      rtb_a_tmp_tmp_0;
+  }
+
+  // End of Outputs for SubSystem: '<S20>/Subsystem1'
+
+  // Outputs for Enabled SubSystem: '<S20>/Subsystem - pi//2 delay' incorporates:
+  //   EnablePort: '<S24>/Enable'
+
+  // RelationalOperator: '<S23>/Compare' incorporates:
+  //   Constant: '<S20>/Constant'
+  //   Constant: '<S23>/Constant'
+
+  if (PmsmSimUt_P.AlphaBetaZerotodq0_Alignment_e ==
+      PmsmSimUt_P.CompareToConstant1_const_o) {
+    // Fcn: '<S24>/Fcn'
+    PmsmSimUt_B.Fcn_a = rtb_Gain1_c[0] * rtb_a_tmp_tmp - rtb_Gain1_c[1] *
+      rtb_a_tmp_tmp_0;
+
+    // Fcn: '<S24>/Fcn1'
+    PmsmSimUt_B.Fcn1_p = rtb_Gain1_c[0] * rtb_a_tmp_tmp_0 + rtb_Gain1_c[1] *
+      rtb_a_tmp_tmp;
+  }
+
+  // End of RelationalOperator: '<S23>/Compare'
+  // End of Outputs for SubSystem: '<S20>/Subsystem - pi//2 delay'
+
+  // Switch: '<S20>/Switch'
+  if (rtb_Compare != 0) {
+    rtb_Switch_idx_0 = PmsmSimUt_B.Fcn;
+    rtb_Switch_idx_1 = PmsmSimUt_B.Fcn1;
+  } else {
+    rtb_Switch_idx_0 = PmsmSimUt_B.Fcn_a;
+    rtb_Switch_idx_1 = PmsmSimUt_B.Fcn1_p;
+  }
+
+  // End of Switch: '<S20>/Switch'
+
+  // Outport: '<Root>/Out' incorporates:
+  //   BusCreator: '<Root>/Bus Creator'
+  //   DiscreteIntegrator: '<S16>/Discrete-Time Integrator'
+  //   DiscreteIntegrator: '<S16>/Discrete-Time Integrator1'
+  //   Gain: '<S17>/Gain2'
+  //   Inport: '<Root>/CtrlIn'
+  //   SignalConversion generated from: '<Root>/Bus Creator'
+
+  PmsmSimUt_Y.Out.WmRpm = PmsmSimUt_P.Gain2_Gain * rtb_Gain2_k;
+  PmsmSimUt_Y.Out.Uabc[0] = rtb_Fcn1;
+  PmsmSimUt_Y.Out.Uabc[1] = rtb_a;
+  PmsmSimUt_Y.Out.Uabc[2] = rtb_Relay2;
+  PmsmSimUt_Y.Out.Idq[0] = rtb_id;
+  PmsmSimUt_Y.Out.Idq[1] = rtb_iq;
+  PmsmSimUt_Y.Out.Te = rtb_Gain;
+  PmsmSimUt_Y.Out.Theta = rtb_Mod;
+  PmsmSimUt_Y.Out.We = rtb_Gain1_i;
+  PmsmSimUt_Y.Out.FluxDq[0] = PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_c;
+  PmsmSimUt_Y.Out.FluxDq[1] = PmsmSimUt_DW.DiscreteTimeIntegrator1_DSTATE;
+  PmsmSimUt_Y.Out.IdRef = PmsmSimUt_U.CtrlIn.IdCmd;
+  PmsmSimUt_Y.Out.IqRef = rtb_Switch_h;
+
+  // Gain: '<S16>/Gain2' incorporates:
+  //   Constant: '<S16>/Constant'
+  //   DiscreteIntegrator: '<S16>/Discrete-Time Integrator'
+  //   Fcn: '<S16>/d(Flux_q)//dt'
+
+  rtb_Mod = ((rtb_Switch_idx_1 - PmsmSimUt_P.Params.R * rtb_iq) - rtb_Gain1_i *
+             PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_c) *
+    PmsmSimUt_P.Params.Ts;
+
+  // Sum: '<S6>/Sum' incorporates:
+  //   Inport: '<Root>/CtrlIn'
+  //   Memory: '<S6>/Memory'
+
+  rtb_Relay2 = PmsmSimUt_U.CtrlIn.WmRpm - PmsmSimUt_DW.Memory_PreviousInput;
+
+  // DeadZone: '<S6>/Dead Zone'
+  if (rtb_Relay2 > PmsmSimUt_P.DeadZone_End) {
+    rtb_Relay2 -= PmsmSimUt_P.DeadZone_End;
+  } else if (rtb_Relay2 >= PmsmSimUt_P.DeadZone_Start) {
+    rtb_Relay2 = 0.0;
+  } else {
+    rtb_Relay2 -= PmsmSimUt_P.DeadZone_Start;
+  }
+
+  // End of DeadZone: '<S6>/Dead Zone'
+
+  // Relay: '<S6>/Relay1'
+  PmsmSimUt_DW.Relay1_Mode = ((rtb_Relay2 >= PmsmSimUt_P.Relay1_OnVal) ||
+    ((!(rtb_Relay2 <= PmsmSimUt_P.Relay1_OffVal)) && PmsmSimUt_DW.Relay1_Mode));
+
+  // Relay: '<S6>/Relay2'
+  PmsmSimUt_DW.Relay2_Mode = ((rtb_Relay2 >= PmsmSimUt_P.Relay2_OnVal) ||
+    ((!(rtb_Relay2 <= PmsmSimUt_P.Relay2_OffVal)) && PmsmSimUt_DW.Relay2_Mode));
+
+  // Update for DiscreteIntegrator: '<S17>/Discrete-Time Integrator' incorporates:
+  //   Gain: '<S17>/Gain'
+
+  PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE += PmsmSimUt_P.Params.Ts *
+    rtb_Gain1_i * PmsmSimUt_P.DiscreteTimeIntegrator_gainva_p;
+
+  // Update for DiscreteIntegrator: '<S16>/Discrete-Time Integrator' incorporates:
+  //   Constant: '<S16>/Constant'
+  //   DiscreteIntegrator: '<S16>/Discrete-Time Integrator1'
+  //   Fcn: '<S16>/d(Flux_d)//dt'
+  //   Gain: '<S16>/Gain1'
+
+  PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_c += ((rtb_Switch_idx_0 -
+    PmsmSimUt_P.Params.R * rtb_id) + rtb_Gain1_i *
+    PmsmSimUt_DW.DiscreteTimeIntegrator1_DSTATE) * PmsmSimUt_P.Params.Ts *
+    PmsmSimUt_P.DiscreteTimeIntegrator_gainv_pq;
+
+  // Update for DiscreteIntegrator: '<S16>/Discrete-Time Integrator1'
+  PmsmSimUt_DW.DiscreteTimeIntegrator1_DSTATE +=
+    PmsmSimUt_P.DiscreteTimeIntegrator1_gainv_b * rtb_Mod;
+
+  // Update for DiscreteIntegrator: '<S15>/Discrete-Time Integrator' incorporates:
+  //   Gain: '<S15>/Gain'
+  //   Gain: '<S15>/Kp5'
+
+  PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_j += PmsmSimUt_P.Params.CKid *
+    rtb_Add1 * PmsmSimUt_P.Params.Ts *
+    PmsmSimUt_P.DiscreteTimeIntegrator_gainva_b;
+  if (PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_j >=
+      PmsmSimUt_P.DiscreteTimeIntegrator_UpperS_b) {
+    PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_j =
+      PmsmSimUt_P.DiscreteTimeIntegrator_UpperS_b;
+  } else {
+    if (PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_j <=
+        PmsmSimUt_P.DiscreteTimeIntegrator_LowerS_l) {
+      PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_j =
+        PmsmSimUt_P.DiscreteTimeIntegrator_LowerS_l;
+    }
+  }
+
+  // End of Update for DiscreteIntegrator: '<S15>/Discrete-Time Integrator'
+
+  // Relay: '<S6>/Relay1'
+  if (PmsmSimUt_DW.Relay1_Mode) {
+    rtb_Switch_h = PmsmSimUt_P.Relay1_YOn;
+  } else {
+    rtb_Switch_h = PmsmSimUt_P.Relay1_YOff;
+  }
+
+  // Relay: '<S6>/Relay2'
+  if (PmsmSimUt_DW.Relay2_Mode) {
+    rtb_id = PmsmSimUt_P.Relay2_YOn;
+  } else {
+    rtb_id = PmsmSimUt_P.Relay2_YOff;
+  }
+
+  // Update for Memory: '<S6>/Memory' incorporates:
+  //   Gain: '<S6>/Gain'
+  //   Sum: '<S6>/Add'
+  //   Sum: '<S6>/Sum1'
+
+  PmsmSimUt_DW.Memory_PreviousInput += (rtb_Switch_h + rtb_id) *
+    PmsmSimUt_P.Params.Ts;
+
+  // Update for DiscreteIntegrator: '<S14>/Discrete-Time Integrator' incorporates:
+  //   Gain: '<S14>/Gain'
+  //   Gain: '<S14>/Kp5'
+
+  PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_g += PmsmSimUt_P.Params.CKiq *
+    rtb_Add2 * PmsmSimUt_P.Params.Ts *
+    PmsmSimUt_P.DiscreteTimeIntegrator_gainva_c;
+  if (PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_g >=
+      PmsmSimUt_P.DiscreteTimeIntegrator_UpperS_k) {
+    PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_g =
+      PmsmSimUt_P.DiscreteTimeIntegrator_UpperS_k;
+  } else {
+    if (PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_g <=
+        PmsmSimUt_P.DiscreteTimeIntegrator_LowerS_a) {
+      PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_g =
+        PmsmSimUt_P.DiscreteTimeIntegrator_LowerS_a;
+    }
+  }
+
+  // End of Update for DiscreteIntegrator: '<S14>/Discrete-Time Integrator'
+}
+
+// Model initialize function
+void PmsmSimUtModelClass::initialize()
+{
+  // Registration code
+
+  // initialize non-finites
+  rt_InitInfAndNaN(sizeof(real_T));
+
+  // InitializeConditions for DiscreteIntegrator: '<S17>/Discrete-Time Integrator' 
+  PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE =
+    PmsmSimUt_P.DiscreteTimeIntegrator_IC;
+
+  // InitializeConditions for DiscreteIntegrator: '<S16>/Discrete-Time Integrator' 
+  PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_c = PmsmSimUt_P.Params.Flux;
+
+  // InitializeConditions for DiscreteIntegrator: '<S16>/Discrete-Time Integrator1' 
+  PmsmSimUt_DW.DiscreteTimeIntegrator1_DSTATE =
+    PmsmSimUt_P.DiscreteTimeIntegrator1_IC_a;
+
+  // InitializeConditions for DiscreteIntegrator: '<S15>/Discrete-Time Integrator' 
+  PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_j = PmsmSimUt_P.Subsystem1_Init;
+
+  // InitializeConditions for Memory: '<S6>/Memory'
+  PmsmSimUt_DW.Memory_PreviousInput = PmsmSimUt_P.Memory_InitialCondition;
+
+  // InitializeConditions for DiscreteIntegrator: '<S14>/Discrete-Time Integrator' 
+  PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_g = PmsmSimUt_P.Subsystem_Init_c;
+
+  // SystemInitialize for Enabled SubSystem: '<S1>/Subsystem1'
+  // SystemInitialize for Fcn: '<S13>/Fcn' incorporates:
+  //   Outport: '<S13>/dq'
+
+  PmsmSimUt_B.Fcn_g = PmsmSimUt_P.dq_Y0_e[0];
+
+  // SystemInitialize for Fcn: '<S13>/Fcn1' incorporates:
+  //   Outport: '<S13>/dq'
+
+  PmsmSimUt_B.Fcn1_e = PmsmSimUt_P.dq_Y0_e[1];
+
+  // End of SystemInitialize for SubSystem: '<S1>/Subsystem1'
+
+  // SystemInitialize for Enabled SubSystem: '<S1>/Subsystem - pi//2 delay'
+  // SystemInitialize for Fcn: '<S12>/Fcn' incorporates:
+  //   Outport: '<S12>/dq'
+
+  PmsmSimUt_B.Fcn_b = PmsmSimUt_P.dq_Y0[0];
+
+  // SystemInitialize for Fcn: '<S12>/Fcn1' incorporates:
+  //   Outport: '<S12>/dq'
+
+  PmsmSimUt_B.Fcn1_n = PmsmSimUt_P.dq_Y0[1];
+
+  // End of SystemInitialize for SubSystem: '<S1>/Subsystem - pi//2 delay'
+
+  // SystemInitialize for Enabled SubSystem: '<S17>/Subsystem'
+  // InitializeConditions for DiscreteIntegrator: '<S18>/Discrete-Time Integrator1' 
+  PmsmSimUt_DW.DiscreteTimeIntegrator1_DSTAT_d =
+    PmsmSimUt_P.DiscreteTimeIntegrator1_IC;
+
+  // SystemInitialize for DiscreteIntegrator: '<S18>/Discrete-Time Integrator1' incorporates:
+  //   Outport: '<S18>/Wm'
+
+  PmsmSimUt_B.DiscreteTimeIntegrator1 = PmsmSimUt_P.Wm_Y0;
+
+  // End of SystemInitialize for SubSystem: '<S17>/Subsystem'
+
+  // SystemInitialize for Enabled SubSystem: '<Root>/Subsystem'
+  // InitializeConditions for DiscreteIntegrator: '<S19>/Discrete-Time Integrator' 
+  PmsmSimUt_DW.DiscreteTimeIntegrator_DSTATE_n = PmsmSimUt_P.Subsystem_Init;
+
+  // SystemInitialize for Sum: '<S19>/Sum6' incorporates:
+  //   Outport: '<S4>/Iq_ref'
+  //   Saturate: '<S19>/Saturation2'
+
+  PmsmSimUt_B.Iq_ref = PmsmSimUt_P.Iq_ref_Y0;
+
+  // End of SystemInitialize for SubSystem: '<Root>/Subsystem'
+
+  // SystemInitialize for Enabled SubSystem: '<S20>/Subsystem1'
+  // SystemInitialize for Fcn: '<S25>/Fcn' incorporates:
+  //   Outport: '<S25>/dq'
+
+  PmsmSimUt_B.Fcn = PmsmSimUt_P.dq_Y0_f[0];
+
+  // SystemInitialize for Fcn: '<S25>/Fcn1' incorporates:
+  //   Outport: '<S25>/dq'
+
+  PmsmSimUt_B.Fcn1 = PmsmSimUt_P.dq_Y0_f[1];
+
+  // End of SystemInitialize for SubSystem: '<S20>/Subsystem1'
+
+  // SystemInitialize for Enabled SubSystem: '<S20>/Subsystem - pi//2 delay'
+  // SystemInitialize for Fcn: '<S24>/Fcn' incorporates:
+  //   Outport: '<S24>/dq'
+
+  PmsmSimUt_B.Fcn_a = PmsmSimUt_P.dq_Y0_l[0];
+
+  // SystemInitialize for Fcn: '<S24>/Fcn1' incorporates:
+  //   Outport: '<S24>/dq'
+
+  PmsmSimUt_B.Fcn1_p = PmsmSimUt_P.dq_Y0_l[1];
+
+  // End of SystemInitialize for SubSystem: '<S20>/Subsystem - pi//2 delay'
+}
+
+// Model terminate function
+void PmsmSimUtModelClass::terminate()
+{
+  // (no terminate code required)
+}
+
+// Constructor
+PmsmSimUtModelClass::PmsmSimUtModelClass() :
+  PmsmSimUt_U(),
+  PmsmSimUt_Y(),
+  PmsmSimUt_B(),
+  PmsmSimUt_DW(),
+  PmsmSimUt_M()
+{
+  // Currently there is no constructor body generated.
+}
+
+// Destructor
+PmsmSimUtModelClass::~PmsmSimUtModelClass()
+{
+  // Currently there is no destructor body generated.
+}
+
+// Real-Time Model get method
+PmsmSimUtModelClass::RT_MODEL_PmsmSimUt_T * PmsmSimUtModelClass::getRTM()
+{
+  return (&PmsmSimUt_M);
+}
+
+//
+// File trailer for generated code.
+//
+// [EOF]
+//

+ 478 - 0
unit_test/motor_sim/PmsmSimUt.h

@@ -0,0 +1,478 @@
+//
+// File: PmsmSimUt.h
+//
+// Code generated for Simulink model 'PmsmSimUt'.
+//
+// Model version                  : 1.15
+// Simulink Coder version         : 9.4 (R2020b) 29-Jul-2020
+// C/C++ source code generated on : Fri Jul 28 01:40:47 2023
+//
+// Target selection: ert.tlc
+// Embedded hardware selection: Intel->x86-64 (Windows64)
+// Code generation objectives: Unspecified
+// Validation result: Not run
+//
+#ifndef RTW_HEADER_PmsmSimUt_h_
+#define RTW_HEADER_PmsmSimUt_h_
+#include <cfloat>
+#include <cmath>
+#include "rtwtypes.h"
+#include "PmsmSimUt_types.h"
+#include "rt_nonfinite.h"
+#include "rtGetInf.h"
+
+// Macros for accessing real-time model data structure
+#ifndef rtmGetErrorStatus
+#define rtmGetErrorStatus(rtm)         ((rtm)->errorStatus)
+#endif
+
+#ifndef rtmSetErrorStatus
+#define rtmSetErrorStatus(rtm, val)    ((rtm)->errorStatus = (val))
+#endif
+
+// Class declaration for model PmsmSimUt
+class PmsmSimUtModelClass {
+  // public data and function members
+ public:
+  // Block signals (default storage)
+  typedef struct {
+    real_T Fcn;                        // '<S25>/Fcn'
+    real_T Fcn1;                       // '<S25>/Fcn1'
+    real_T Fcn_a;                      // '<S24>/Fcn'
+    real_T Fcn1_p;                     // '<S24>/Fcn1'
+    real_T DiscreteTimeIntegrator;     // '<S19>/Discrete-Time Integrator'
+    real_T Iq_ref;                     // '<S19>/Saturation2'
+    real_T DiscreteTimeIntegrator1;    // '<S18>/Discrete-Time Integrator1'
+    real_T Fcn_g;                      // '<S13>/Fcn'
+    real_T Fcn1_e;                     // '<S13>/Fcn1'
+    real_T Fcn_b;                      // '<S12>/Fcn'
+    real_T Fcn1_n;                     // '<S12>/Fcn1'
+  } B_PmsmSimUt_T;
+
+  // Block states (default storage) for system '<Root>'
+  typedef struct {
+    real_T DiscreteTimeIntegrator_DSTATE;// '<S17>/Discrete-Time Integrator'
+    real_T DiscreteTimeIntegrator_DSTATE_c;// '<S16>/Discrete-Time Integrator'
+    real_T DiscreteTimeIntegrator1_DSTATE;// '<S16>/Discrete-Time Integrator1'
+    real_T DiscreteTimeIntegrator_DSTATE_j;// '<S15>/Discrete-Time Integrator'
+    real_T DiscreteTimeIntegrator_DSTATE_g;// '<S14>/Discrete-Time Integrator'
+    real_T DiscreteTimeIntegrator_DSTATE_n;// '<S19>/Discrete-Time Integrator'
+    real_T DiscreteTimeIntegrator1_DSTAT_d;// '<S18>/Discrete-Time Integrator1'
+    real_T Memory_PreviousInput;       // '<S6>/Memory'
+    boolean_T Relay1_Mode;             // '<S6>/Relay1'
+    boolean_T Relay2_Mode;             // '<S6>/Relay2'
+    boolean_T Subsystem_MODE;          // '<Root>/Subsystem'
+  } DW_PmsmSimUt_T;
+
+  // External inputs (root inport signals with default storage)
+  typedef struct {
+    InputBus CtrlIn;                   // '<Root>/CtrlIn'
+    ObsInputBus ObsIn;                 // '<Root>/ObsIn'
+    ICtrlInputBus ICtrlIn;             // '<Root>/ICtrlIn'
+  } ExtU_PmsmSimUt_T;
+
+  // External outputs (root outports fed by signals with default storage)
+  typedef struct {
+    OutputBus Out;                     // '<Root>/Out'
+  } ExtY_PmsmSimUt_T;
+
+  // Parameters (default storage)
+  struct P_PmsmSimUt_T {
+    struct_tYah6PAnMSQyhFn3I8nH0C Params;// Variable: Params
+                                            //  Referenced by:
+                                            //    '<Root>/Constant1'
+                                            //    '<Root>/Constant2'
+                                            //    '<Root>/Constant3'
+                                            //    '<Root>/Constant4'
+                                            //    '<Root>/Gain1'
+                                            //    '<S6>/Gain'
+                                            //    '<S14>/Gain'
+                                            //    '<S14>/Kp4'
+                                            //    '<S14>/Kp5'
+                                            //    '<S15>/Gain'
+                                            //    '<S15>/Kp4'
+                                            //    '<S15>/Kp5'
+                                            //    '<S16>/Constant'
+                                            //    '<S16>/Constant1'
+                                            //    '<S16>/Constant2'
+                                            //    '<S16>/Constant3'
+                                            //    '<S16>/Discrete-Time Integrator'
+                                            //    '<S16>/Gain'
+                                            //    '<S16>/Gain1'
+                                            //    '<S16>/Gain2'
+                                            //    '<S17>/Gain'
+                                            //    '<S17>/Gain1'
+                                            //    '<S19>/Gain'
+                                            //    '<S19>/Kp4'
+                                            //    '<S19>/Kp5'
+                                            //    '<S18>/Constant1'
+                                            //    '<S18>/Gain'
+                                            //    '<S18>/Gain1'
+
+    real_T AlphaBetaZerotodq0_Alignment;
+                                 // Mask Parameter: AlphaBetaZerotodq0_Alignment
+                                    //  Referenced by: '<S1>/Constant'
+
+    real_T AlphaBetaZerotodq0_Alignment_e;
+                               // Mask Parameter: AlphaBetaZerotodq0_Alignment_e
+                                  //  Referenced by: '<S20>/Constant'
+
+    real_T Subsystem_Init;             // Mask Parameter: Subsystem_Init
+                                          //  Referenced by: '<S19>/Discrete-Time Integrator'
+
+    real_T Subsystem1_Init;            // Mask Parameter: Subsystem1_Init
+                                          //  Referenced by: '<S15>/Discrete-Time Integrator'
+
+    real_T Subsystem_Init_c;           // Mask Parameter: Subsystem_Init_c
+                                          //  Referenced by: '<S14>/Discrete-Time Integrator'
+
+    real_T CompareToConstant_const;   // Mask Parameter: CompareToConstant_const
+                                         //  Referenced by: '<S10>/Constant'
+
+    real_T CompareToConstant1_const; // Mask Parameter: CompareToConstant1_const
+                                        //  Referenced by: '<S11>/Constant'
+
+    real_T CompareToConstant_const_a;
+                                    // Mask Parameter: CompareToConstant_const_a
+                                       //  Referenced by: '<S22>/Constant'
+
+    real_T CompareToConstant1_const_o;
+                                   // Mask Parameter: CompareToConstant1_const_o
+                                      //  Referenced by: '<S23>/Constant'
+
+    real_T dq_Y0[2];                   // Expression: [0,0]
+                                          //  Referenced by: '<S12>/dq'
+
+    real_T dq_Y0_e[2];                 // Expression: [0,0]
+                                          //  Referenced by: '<S13>/dq'
+
+    real_T Wm_Y0;                      // Computed Parameter: Wm_Y0
+                                          //  Referenced by: '<S18>/Wm'
+
+    real_T DiscreteTimeIntegrator1_gainval;
+                          // Computed Parameter: DiscreteTimeIntegrator1_gainval
+                             //  Referenced by: '<S18>/Discrete-Time Integrator1'
+
+    real_T DiscreteTimeIntegrator1_IC; // Expression: 0
+                                          //  Referenced by: '<S18>/Discrete-Time Integrator1'
+
+    real_T Gain3_Gain;                 // Expression: pi/30
+                                          //  Referenced by: '<S17>/Gain3'
+
+    real_T Iq_ref_Y0;                  // Computed Parameter: Iq_ref_Y0
+                                          //  Referenced by: '<S4>/Iq_ref'
+
+    real_T DiscreteTimeIntegrator_gainval;
+                           // Computed Parameter: DiscreteTimeIntegrator_gainval
+                              //  Referenced by: '<S19>/Discrete-Time Integrator'
+
+    real_T DiscreteTimeIntegrator_UpperSat;// Expression: Limits(1)
+                                              //  Referenced by: '<S19>/Discrete-Time Integrator'
+
+    real_T DiscreteTimeIntegrator_LowerSat;// Expression: Limits(2)
+                                              //  Referenced by: '<S19>/Discrete-Time Integrator'
+
+    real_T Saturation2_UpperSat;       // Expression: Limits(1)
+                                          //  Referenced by: '<S19>/Saturation2'
+
+    real_T Saturation2_LowerSat;       // Expression: Limits(2)
+                                          //  Referenced by: '<S19>/Saturation2'
+
+    real_T Constant5_Value;            // Expression: 0
+                                          //  Referenced by: '<Root>/Constant5'
+
+    real_T Constant6_Value;            // Expression: 1
+                                          //  Referenced by: '<Root>/Constant6'
+
+    real_T Saturation2_UpperSat_o;     // Expression: Limits(1)
+                                          //  Referenced by: '<S15>/Saturation2'
+
+    real_T Saturation2_LowerSat_o;     // Expression: Limits(2)
+                                          //  Referenced by: '<S15>/Saturation2'
+
+    real_T Saturation2_UpperSat_b;     // Expression: Limits(1)
+                                          //  Referenced by: '<S14>/Saturation2'
+
+    real_T Saturation2_LowerSat_j;     // Expression: Limits(2)
+                                          //  Referenced by: '<S14>/Saturation2'
+
+    real_T dq_Y0_l[2];                 // Expression: [0,0]
+                                          //  Referenced by: '<S24>/dq'
+
+    real_T dq_Y0_f[2];                 // Expression: [0,0]
+                                          //  Referenced by: '<S25>/dq'
+
+    real_T DiscreteTimeIntegrator_gainva_p;
+                          // Computed Parameter: DiscreteTimeIntegrator_gainva_p
+                             //  Referenced by: '<S17>/Discrete-Time Integrator'
+
+    real_T DiscreteTimeIntegrator_IC;  // Expression: 0
+                                          //  Referenced by: '<S17>/Discrete-Time Integrator'
+
+    real_T Constant_Value;             // Expression: 2*pi
+                                          //  Referenced by: '<S17>/Constant'
+
+    real_T DiscreteTimeIntegrator_gainv_pq;
+                          // Computed Parameter: DiscreteTimeIntegrator_gainv_pq
+                             //  Referenced by: '<S16>/Discrete-Time Integrator'
+
+    real_T DiscreteTimeIntegrator1_gainv_b;
+                          // Computed Parameter: DiscreteTimeIntegrator1_gainv_b
+                             //  Referenced by: '<S16>/Discrete-Time Integrator1'
+
+    real_T DiscreteTimeIntegrator1_IC_a;// Expression: 0
+                                           //  Referenced by: '<S16>/Discrete-Time Integrator1'
+
+    real_T Constant_Value_e;           // Expression: 0
+                                          //  Referenced by: '<S9>/Constant'
+
+    real_T K1_Gain;                    // Expression: K1
+                                          //  Referenced by: '<S29>/K1'
+
+    real_T K2_Gain;                    // Expression: K2
+                                          //  Referenced by: '<S29>/K2'
+
+    real_T Switch2_Threshold;          // Expression: 0
+                                          //  Referenced by: '<Root>/Switch2'
+
+    real_T Switch5_Threshold;          // Expression: 0
+                                          //  Referenced by: '<Root>/Switch5'
+
+    real_T Switch_Threshold;           // Expression: 0
+                                          //  Referenced by: '<S17>/Switch'
+
+    real_T Switch3_Threshold;          // Expression: 0
+                                          //  Referenced by: '<Root>/Switch3'
+
+    real_T Switch4_Threshold;          // Expression: 0
+                                          //  Referenced by: '<Root>/Switch4'
+
+    real_T DiscreteTimeIntegrator_gainva_b;
+                          // Computed Parameter: DiscreteTimeIntegrator_gainva_b
+                             //  Referenced by: '<S15>/Discrete-Time Integrator'
+
+    real_T DiscreteTimeIntegrator_UpperS_b;// Expression: Limits(1)
+                                              //  Referenced by: '<S15>/Discrete-Time Integrator'
+
+    real_T DiscreteTimeIntegrator_LowerS_l;// Expression: Limits(2)
+                                              //  Referenced by: '<S15>/Discrete-Time Integrator'
+
+    real_T Switch1_Threshold;          // Expression: 0
+                                          //  Referenced by: '<Root>/Switch1'
+
+    real_T Memory_InitialCondition;    // Expression: 0
+                                          //  Referenced by: '<S6>/Memory'
+
+    real_T Saturation2_UpperSat_p;     // Expression: 10000
+                                          //  Referenced by: '<Root>/Saturation2'
+
+    real_T Saturation2_LowerSat_f;     // Expression: -10000
+                                          //  Referenced by: '<Root>/Saturation2'
+
+    real_T DiscreteTimeIntegrator_gainva_c;
+                          // Computed Parameter: DiscreteTimeIntegrator_gainva_c
+                             //  Referenced by: '<S14>/Discrete-Time Integrator'
+
+    real_T DiscreteTimeIntegrator_UpperS_k;// Expression: Limits(1)
+                                              //  Referenced by: '<S14>/Discrete-Time Integrator'
+
+    real_T DiscreteTimeIntegrator_LowerS_a;// Expression: Limits(2)
+                                              //  Referenced by: '<S14>/Discrete-Time Integrator'
+
+    real_T Switch6_Threshold;          // Expression: 0
+                                          //  Referenced by: '<Root>/Switch6'
+
+    real_T Constant_Value_p;           // Expression: 0
+                                          //  Referenced by: '<S8>/Constant'
+
+    real_T K1_Gain_j;                  // Expression: K1
+                                          //  Referenced by: '<S27>/K1'
+
+    real_T K2_Gain_b;                  // Expression: K2
+                                          //  Referenced by: '<S27>/K2'
+
+    real_T Gain3_Gain_j[9];
+    // Expression: [ 1   -1/2   -1/2; 0   sqrt(3)/2   -sqrt(3)/2; 1/2  1/2  1/2 ]
+       //  Referenced by: '<S21>/Gain3'
+
+    real_T Gain1_Gain;                 // Expression: 2/3
+                                          //  Referenced by: '<S21>/Gain1'
+
+    real_T Gain2_Gain;                 // Expression: 30/pi
+                                          //  Referenced by: '<S17>/Gain2'
+
+    real_T DeadZone_Start;             // Expression: -0.01
+                                          //  Referenced by: '<S6>/Dead Zone'
+
+    real_T DeadZone_End;               // Expression: 0.01
+                                          //  Referenced by: '<S6>/Dead Zone'
+
+    real_T Relay1_OnVal;               // Expression: 0.1
+                                          //  Referenced by: '<S6>/Relay1'
+
+    real_T Relay1_OffVal;              // Expression: 0
+                                          //  Referenced by: '<S6>/Relay1'
+
+    real_T Relay1_YOn;                 // Expression: 1000
+                                          //  Referenced by: '<S6>/Relay1'
+
+    real_T Relay1_YOff;                // Expression: 0
+                                          //  Referenced by: '<S6>/Relay1'
+
+    real_T Relay2_OnVal;               // Expression: 0
+                                          //  Referenced by: '<S6>/Relay2'
+
+    real_T Relay2_OffVal;              // Expression: -0.1
+                                          //  Referenced by: '<S6>/Relay2'
+
+    real_T Relay2_YOn;                 // Expression: 0
+                                          //  Referenced by: '<S6>/Relay2'
+
+    real_T Relay2_YOff;                // Expression: -1000
+                                          //  Referenced by: '<S6>/Relay2'
+
+    uint8_T ManualSwitch1_CurrentSetting;
+                             // Computed Parameter: ManualSwitch1_CurrentSetting
+                                //  Referenced by: '<Root>/Manual Switch1'
+
+  };
+
+  // Real-time Model Data Structure
+  struct RT_MODEL_PmsmSimUt_T {
+    const char_T * volatile errorStatus;
+  };
+
+  // Tunable parameters
+  static P_PmsmSimUt_T PmsmSimUt_P;
+
+  // External inputs
+  ExtU_PmsmSimUt_T PmsmSimUt_U;
+
+  // External outputs
+  ExtY_PmsmSimUt_T PmsmSimUt_Y;
+
+  // model initialize function
+  void initialize();
+
+  // model step function
+  void step();
+
+  // model terminate function
+  void terminate();
+
+  // Constructor
+  PmsmSimUtModelClass();
+
+  // Destructor
+  ~PmsmSimUtModelClass();
+
+  // Block parameters get method
+  const PmsmSimUtModelClass::P_PmsmSimUt_T & getBlockParameters() const
+  {
+    return PmsmSimUt_P;
+  }
+
+  // Block parameters set method
+  void setBlockParameters(const P_PmsmSimUt_T *pPmsmSimUt_P)
+  {
+    PmsmSimUt_P = *pPmsmSimUt_P;
+  }
+
+  // Root-level structure-based inputs set method
+
+  // Root inports set method
+  void setExternalInputs(const ExtU_PmsmSimUt_T* pExtU_PmsmSimUt_T)
+  {
+    PmsmSimUt_U = *pExtU_PmsmSimUt_T;
+  }
+
+  // Root-level structure-based outputs get method
+
+  // Root outports get method
+  const PmsmSimUtModelClass::ExtY_PmsmSimUt_T & getExternalOutputs() const
+  {
+    return PmsmSimUt_Y;
+  }
+
+  // Real-Time Model get method
+  PmsmSimUtModelClass::RT_MODEL_PmsmSimUt_T * getRTM();
+
+  // private data and function members
+ private:
+  // Block signals
+  B_PmsmSimUt_T PmsmSimUt_B;
+
+  // Block states
+  DW_PmsmSimUt_T PmsmSimUt_DW;
+
+  // Real-Time Model
+  RT_MODEL_PmsmSimUt_T PmsmSimUt_M;
+};
+
+//-
+//  These blocks were eliminated from the model due to optimizations:
+//
+//  Block '<Root>/Constant' : Unused code path elimination
+//  Block '<S16>/Scope' : Unused code path elimination
+//  Block '<S16>/Scope1' : Unused code path elimination
+//  Block '<S17>/Scope' : Unused code path elimination
+//  Block '<Root>/Scope' : Unused code path elimination
+//  Block '<Root>/Scope1' : Unused code path elimination
+//  Block '<Root>/Scope3' : Unused code path elimination
+//  Block '<Root>/Scope4' : Unused code path elimination
+//  Block '<Root>/Scope5' : Unused code path elimination
+//  Block '<S5>/Scope' : Unused code path elimination
+
+
+//-
+//  The generated code includes comments that allow you to trace directly
+//  back to the appropriate location in the model.  The basic format
+//  is <system>/block_name, where system is the system number (uniquely
+//  assigned by Simulink) and block_name is the name of the block.
+//
+//  Use the MATLAB hilite_system command to trace the generated code back
+//  to the model.  For example,
+//
+//  hilite_system('<S3>')    - opens system 3
+//  hilite_system('<S3>/Kp') - opens and selects block Kp which resides in S3
+//
+//  Here is the system hierarchy for this model
+//
+//  '<Root>' : 'PmsmSimUt'
+//  '<S1>'   : 'PmsmSimUt/Alpha-Beta-Zero to dq0'
+//  '<S2>'   : 'PmsmSimUt/PI Controller'
+//  '<S3>'   : 'PmsmSimUt/PM_Motor in dq frame '
+//  '<S4>'   : 'PmsmSimUt/Subsystem'
+//  '<S5>'   : 'PmsmSimUt/Subsystem1'
+//  '<S6>'   : 'PmsmSimUt/Subsystem2'
+//  '<S7>'   : 'PmsmSimUt/abc to dq0'
+//  '<S8>'   : 'PmsmSimUt/dq to abc'
+//  '<S9>'   : 'PmsmSimUt/dq to abc1'
+//  '<S10>'  : 'PmsmSimUt/Alpha-Beta-Zero to dq0/Compare To Constant'
+//  '<S11>'  : 'PmsmSimUt/Alpha-Beta-Zero to dq0/Compare To Constant1'
+//  '<S12>'  : 'PmsmSimUt/Alpha-Beta-Zero to dq0/Subsystem - pi//2 delay'
+//  '<S13>'  : 'PmsmSimUt/Alpha-Beta-Zero to dq0/Subsystem1'
+//  '<S14>'  : 'PmsmSimUt/PI Controller/Subsystem'
+//  '<S15>'  : 'PmsmSimUt/PI Controller/Subsystem1'
+//  '<S16>'  : 'PmsmSimUt/PM_Motor in dq frame /Electrical Modelling'
+//  '<S17>'  : 'PmsmSimUt/PM_Motor in dq frame /Mechanical Modelling'
+//  '<S18>'  : 'PmsmSimUt/PM_Motor in dq frame /Mechanical Modelling/Subsystem'
+//  '<S19>'  : 'PmsmSimUt/Subsystem/Subsystem'
+//  '<S20>'  : 'PmsmSimUt/abc to dq0/Alpha-Beta-Zero to dq0'
+//  '<S21>'  : 'PmsmSimUt/abc to dq0/abc to Alpha-Beta-Zero'
+//  '<S22>'  : 'PmsmSimUt/abc to dq0/Alpha-Beta-Zero to dq0/Compare To Constant'
+//  '<S23>'  : 'PmsmSimUt/abc to dq0/Alpha-Beta-Zero to dq0/Compare To Constant1'
+//  '<S24>'  : 'PmsmSimUt/abc to dq0/Alpha-Beta-Zero to dq0/Subsystem - pi//2 delay'
+//  '<S25>'  : 'PmsmSimUt/abc to dq0/Alpha-Beta-Zero to dq0/Subsystem1'
+//  '<S26>'  : 'PmsmSimUt/dq to abc/An_Park'
+//  '<S27>'  : 'PmsmSimUt/dq to abc/Inverse Clarke Transform2'
+//  '<S28>'  : 'PmsmSimUt/dq to abc1/An_Park'
+//  '<S29>'  : 'PmsmSimUt/dq to abc1/Inverse Clarke Transform2'
+
+#endif                                 // RTW_HEADER_PmsmSimUt_h_
+
+//
+// File trailer for generated code.
+//
+// [EOF]
+//

+ 432 - 0
unit_test/motor_sim/PmsmSimUt_data.cpp

@@ -0,0 +1,432 @@
+//
+// File: PmsmSimUt_data.cpp
+//
+// Code generated for Simulink model 'PmsmSimUt'.
+//
+// Model version                  : 1.15
+// Simulink Coder version         : 9.4 (R2020b) 29-Jul-2020
+// C/C++ source code generated on : Fri Jul 28 01:40:47 2023
+//
+// Target selection: ert.tlc
+// Embedded hardware selection: Intel->x86-64 (Windows64)
+// Code generation objectives: Unspecified
+// Validation result: Not run
+//
+#include "PmsmSimUt.h"
+#include "PmsmSimUt_private.h"
+
+// Block parameters (default storage)
+PmsmSimUtModelClass::P_PmsmSimUt_T PmsmSimUtModelClass::PmsmSimUt_P = {
+  // Variable: Params
+  //  Referenced by:
+  //    '<Root>/Constant1'
+  //    '<Root>/Constant2'
+  //    '<Root>/Constant3'
+  //    '<Root>/Constant4'
+  //    '<Root>/Gain1'
+  //    '<S6>/Gain'
+  //    '<S14>/Gain'
+  //    '<S14>/Kp4'
+  //    '<S14>/Kp5'
+  //    '<S15>/Gain'
+  //    '<S15>/Kp4'
+  //    '<S15>/Kp5'
+  //    '<S16>/Constant'
+  //    '<S16>/Constant1'
+  //    '<S16>/Constant2'
+  //    '<S16>/Constant3'
+  //    '<S16>/Discrete-Time Integrator'
+  //    '<S16>/Gain'
+  //    '<S16>/Gain1'
+  //    '<S16>/Gain2'
+  //    '<S17>/Gain'
+  //    '<S17>/Gain1'
+  //    '<S19>/Gain'
+  //    '<S19>/Kp4'
+  //    '<S19>/Kp5'
+  //    '<S18>/Constant1'
+  //    '<S18>/Gain'
+  //    '<S18>/Gain1'
+
+  {
+    0.0001,
+    1.0,
+    0.0,
+    1000.0,
+    0.1,
+    0.002,
+    0.25,
+    1.8,
+    0.25,
+    1.8,
+    0.0,
+    0.0008,
+    2.0,
+    0.00056,
+    8.1e-5,
+    8.1e-5,
+    0.0789
+  },
+
+  // Mask Parameter: AlphaBetaZerotodq0_Alignment
+  //  Referenced by: '<S1>/Constant'
+
+  1.0,
+
+  // Mask Parameter: AlphaBetaZerotodq0_Alignment_e
+  //  Referenced by: '<S20>/Constant'
+
+  1.0,
+
+  // Mask Parameter: Subsystem_Init
+  //  Referenced by: '<S19>/Discrete-Time Integrator'
+
+  0.0,
+
+  // Mask Parameter: Subsystem1_Init
+  //  Referenced by: '<S15>/Discrete-Time Integrator'
+
+  0.0,
+
+  // Mask Parameter: Subsystem_Init_c
+  //  Referenced by: '<S14>/Discrete-Time Integrator'
+
+  0.0,
+
+  // Mask Parameter: CompareToConstant_const
+  //  Referenced by: '<S10>/Constant'
+
+  1.0,
+
+  // Mask Parameter: CompareToConstant1_const
+  //  Referenced by: '<S11>/Constant'
+
+  2.0,
+
+  // Mask Parameter: CompareToConstant_const_a
+  //  Referenced by: '<S22>/Constant'
+
+  1.0,
+
+  // Mask Parameter: CompareToConstant1_const_o
+  //  Referenced by: '<S23>/Constant'
+
+  2.0,
+
+  // Expression: [0,0]
+  //  Referenced by: '<S12>/dq'
+
+  { 0.0, 0.0 },
+
+  // Expression: [0,0]
+  //  Referenced by: '<S13>/dq'
+
+  { 0.0, 0.0 },
+
+  // Computed Parameter: Wm_Y0
+  //  Referenced by: '<S18>/Wm'
+
+  0.0,
+
+  // Computed Parameter: DiscreteTimeIntegrator1_gainval
+  //  Referenced by: '<S18>/Discrete-Time Integrator1'
+
+  1.0,
+
+  // Expression: 0
+  //  Referenced by: '<S18>/Discrete-Time Integrator1'
+
+  0.0,
+
+  // Expression: pi/30
+  //  Referenced by: '<S17>/Gain3'
+
+  0.10471975511965977,
+
+  // Computed Parameter: Iq_ref_Y0
+  //  Referenced by: '<S4>/Iq_ref'
+
+  0.0,
+
+  // Computed Parameter: DiscreteTimeIntegrator_gainval
+  //  Referenced by: '<S19>/Discrete-Time Integrator'
+
+  1.0,
+
+  // Expression: Limits(1)
+  //  Referenced by: '<S19>/Discrete-Time Integrator'
+
+  500.0,
+
+  // Expression: Limits(2)
+  //  Referenced by: '<S19>/Discrete-Time Integrator'
+
+  -500.0,
+
+  // Expression: Limits(1)
+  //  Referenced by: '<S19>/Saturation2'
+
+  500.0,
+
+  // Expression: Limits(2)
+  //  Referenced by: '<S19>/Saturation2'
+
+  -500.0,
+
+  // Expression: 0
+  //  Referenced by: '<Root>/Constant5'
+
+  0.0,
+
+  // Expression: 1
+  //  Referenced by: '<Root>/Constant6'
+
+  1.0,
+
+  // Expression: Limits(1)
+  //  Referenced by: '<S15>/Saturation2'
+
+  10000.0,
+
+  // Expression: Limits(2)
+  //  Referenced by: '<S15>/Saturation2'
+
+  -10000.0,
+
+  // Expression: Limits(1)
+  //  Referenced by: '<S14>/Saturation2'
+
+  10000.0,
+
+  // Expression: Limits(2)
+  //  Referenced by: '<S14>/Saturation2'
+
+  -10000.0,
+
+  // Expression: [0,0]
+  //  Referenced by: '<S24>/dq'
+
+  { 0.0, 0.0 },
+
+  // Expression: [0,0]
+  //  Referenced by: '<S25>/dq'
+
+  { 0.0, 0.0 },
+
+  // Computed Parameter: DiscreteTimeIntegrator_gainva_p
+  //  Referenced by: '<S17>/Discrete-Time Integrator'
+
+  1.0,
+
+  // Expression: 0
+  //  Referenced by: '<S17>/Discrete-Time Integrator'
+
+  0.0,
+
+  // Expression: 2*pi
+  //  Referenced by: '<S17>/Constant'
+
+  6.2831853071795862,
+
+  // Computed Parameter: DiscreteTimeIntegrator_gainv_pq
+  //  Referenced by: '<S16>/Discrete-Time Integrator'
+
+  1.0,
+
+  // Computed Parameter: DiscreteTimeIntegrator1_gainv_b
+  //  Referenced by: '<S16>/Discrete-Time Integrator1'
+
+  1.0,
+
+  // Expression: 0
+  //  Referenced by: '<S16>/Discrete-Time Integrator1'
+
+  0.0,
+
+  // Expression: 0
+  //  Referenced by: '<S9>/Constant'
+
+  0.0,
+
+  // Expression: K1
+  //  Referenced by: '<S29>/K1'
+
+  1.0,
+
+  // Expression: K2
+  //  Referenced by: '<S29>/K2'
+
+  1.0,
+
+  // Expression: 0
+  //  Referenced by: '<Root>/Switch2'
+
+  0.0,
+
+  // Expression: 0
+  //  Referenced by: '<Root>/Switch5'
+
+  0.0,
+
+  // Expression: 0
+  //  Referenced by: '<S17>/Switch'
+
+  0.0,
+
+  // Expression: 0
+  //  Referenced by: '<Root>/Switch3'
+
+  0.0,
+
+  // Expression: 0
+  //  Referenced by: '<Root>/Switch4'
+
+  0.0,
+
+  // Computed Parameter: DiscreteTimeIntegrator_gainva_b
+  //  Referenced by: '<S15>/Discrete-Time Integrator'
+
+  1.0,
+
+  // Expression: Limits(1)
+  //  Referenced by: '<S15>/Discrete-Time Integrator'
+
+  10000.0,
+
+  // Expression: Limits(2)
+  //  Referenced by: '<S15>/Discrete-Time Integrator'
+
+  -10000.0,
+
+  // Expression: 0
+  //  Referenced by: '<Root>/Switch1'
+
+  0.0,
+
+  // Expression: 0
+  //  Referenced by: '<S6>/Memory'
+
+  0.0,
+
+  // Expression: 10000
+  //  Referenced by: '<Root>/Saturation2'
+
+  10000.0,
+
+  // Expression: -10000
+  //  Referenced by: '<Root>/Saturation2'
+
+  -10000.0,
+
+  // Computed Parameter: DiscreteTimeIntegrator_gainva_c
+  //  Referenced by: '<S14>/Discrete-Time Integrator'
+
+  1.0,
+
+  // Expression: Limits(1)
+  //  Referenced by: '<S14>/Discrete-Time Integrator'
+
+  10000.0,
+
+  // Expression: Limits(2)
+  //  Referenced by: '<S14>/Discrete-Time Integrator'
+
+  -10000.0,
+
+  // Expression: 0
+  //  Referenced by: '<Root>/Switch6'
+
+  0.0,
+
+  // Expression: 0
+  //  Referenced by: '<S8>/Constant'
+
+  0.0,
+
+  // Expression: K1
+  //  Referenced by: '<S27>/K1'
+
+  1.0,
+
+  // Expression: K2
+  //  Referenced by: '<S27>/K2'
+
+  1.0,
+
+  // Expression: [ 1   -1/2   -1/2; 0   sqrt(3)/2   -sqrt(3)/2; 1/2  1/2  1/2 ]
+  //  Referenced by: '<S21>/Gain3'
+
+  { 1.0, 0.0, 0.5, -0.5, 0.8660254037844386, 0.5, -0.5, -0.8660254037844386, 0.5
+  },
+
+  // Expression: 2/3
+  //  Referenced by: '<S21>/Gain1'
+
+  0.66666666666666663,
+
+  // Expression: 30/pi
+  //  Referenced by: '<S17>/Gain2'
+
+  9.5492965855137211,
+
+  // Expression: -0.01
+  //  Referenced by: '<S6>/Dead Zone'
+
+  -0.01,
+
+  // Expression: 0.01
+  //  Referenced by: '<S6>/Dead Zone'
+
+  0.01,
+
+  // Expression: 0.1
+  //  Referenced by: '<S6>/Relay1'
+
+  0.1,
+
+  // Expression: 0
+  //  Referenced by: '<S6>/Relay1'
+
+  0.0,
+
+  // Expression: 1000
+  //  Referenced by: '<S6>/Relay1'
+
+  1000.0,
+
+  // Expression: 0
+  //  Referenced by: '<S6>/Relay1'
+
+  0.0,
+
+  // Expression: 0
+  //  Referenced by: '<S6>/Relay2'
+
+  0.0,
+
+  // Expression: -0.1
+  //  Referenced by: '<S6>/Relay2'
+
+  -0.1,
+
+  // Expression: 0
+  //  Referenced by: '<S6>/Relay2'
+
+  0.0,
+
+  // Expression: -1000
+  //  Referenced by: '<S6>/Relay2'
+
+  -1000.0,
+
+  // Computed Parameter: ManualSwitch1_CurrentSetting
+  //  Referenced by: '<Root>/Manual Switch1'
+
+  0U
+};
+
+//
+// File trailer for generated code.
+//
+// [EOF]
+//

+ 27 - 0
unit_test/motor_sim/PmsmSimUt_private.h

@@ -0,0 +1,27 @@
+//
+// File: PmsmSimUt_private.h
+//
+// Code generated for Simulink model 'PmsmSimUt'.
+//
+// Model version                  : 1.15
+// Simulink Coder version         : 9.4 (R2020b) 29-Jul-2020
+// C/C++ source code generated on : Fri Jul 28 01:40:47 2023
+//
+// Target selection: ert.tlc
+// Embedded hardware selection: Intel->x86-64 (Windows64)
+// Code generation objectives: Unspecified
+// Validation result: Not run
+//
+#ifndef RTW_HEADER_PmsmSimUt_private_h_
+#define RTW_HEADER_PmsmSimUt_private_h_
+#include "rtwtypes.h"
+
+extern real_T rt_modd_snf(real_T u0, real_T u1);
+
+#endif                                 // RTW_HEADER_PmsmSimUt_private_h_
+
+//
+// File trailer for generated code.
+//
+// [EOF]
+//

+ 102 - 0
unit_test/motor_sim/PmsmSimUt_types.h

@@ -0,0 +1,102 @@
+//
+// File: PmsmSimUt_types.h
+//
+// Code generated for Simulink model 'PmsmSimUt'.
+//
+// Model version                  : 1.15
+// Simulink Coder version         : 9.4 (R2020b) 29-Jul-2020
+// C/C++ source code generated on : Fri Jul 28 01:40:47 2023
+//
+// Target selection: ert.tlc
+// Embedded hardware selection: Intel->x86-64 (Windows64)
+// Code generation objectives: Unspecified
+// Validation result: Not run
+//
+#ifndef RTW_HEADER_PmsmSimUt_types_h_
+#define RTW_HEADER_PmsmSimUt_types_h_
+#include "rtwtypes.h"
+
+// Model Code Variants
+#ifndef DEFINED_TYPEDEF_FOR_InputBus_
+#define DEFINED_TYPEDEF_FOR_InputBus_
+
+typedef struct {
+  real_T Tm;
+  real_T WmRpm;
+  real_T IdCmd;
+  real_T IqCmd;
+} InputBus;
+
+#endif
+
+#ifndef DEFINED_TYPEDEF_FOR_ObsInputBus_
+#define DEFINED_TYPEDEF_FOR_ObsInputBus_
+
+typedef struct {
+  real_T Enable;
+  real_T Theta;
+  real_T We;
+} ObsInputBus;
+
+#endif
+
+#ifndef DEFINED_TYPEDEF_FOR_ICtrlInputBus_
+#define DEFINED_TYPEDEF_FOR_ICtrlInputBus_
+
+typedef struct {
+  real_T Enable;
+  real_T UdCtrl;
+  real_T UqCtrl;
+} ICtrlInputBus;
+
+#endif
+
+#ifndef DEFINED_TYPEDEF_FOR_OutputBus_
+#define DEFINED_TYPEDEF_FOR_OutputBus_
+
+typedef struct {
+  real_T Uabc[3];
+  real_T Iabc[3];
+  real_T Idq[2];
+  real_T Te;
+  real_T Theta;
+  real_T We;
+  real_T WmRpm;
+  real_T FluxDq[2];
+  real_T IdRef;
+  real_T IqRef;
+} OutputBus;
+
+#endif
+
+#ifndef DEFINED_TYPEDEF_FOR_struct_tYah6PAnMSQyhFn3I8nH0C_
+#define DEFINED_TYPEDEF_FOR_struct_tYah6PAnMSQyhFn3I8nH0C_
+
+typedef struct {
+  real_T Ts;
+  real_T SpdCtrl;
+  real_T CustomSpdCtrl;
+  real_T SpdRpm;
+  real_T SKp;
+  real_T SKi;
+  real_T CKpd;
+  real_T CKid;
+  real_T CKpq;
+  real_T CKiq;
+  real_T B;
+  real_T Jm;
+  real_T Pn;
+  real_T R;
+  real_T Ld;
+  real_T Lq;
+  real_T Flux;
+} struct_tYah6PAnMSQyhFn3I8nH0C;
+
+#endif
+#endif                                 // RTW_HEADER_PmsmSimUt_types_h_
+
+//
+// File trailer for generated code.
+//
+// [EOF]
+//

+ 47 - 0
unit_test/motor_sim/builtin_typeid_types.h

@@ -0,0 +1,47 @@
+//
+// File: builtin_typeid_types.h
+//
+// Code generated for Simulink model 'PmsmSimUt'.
+//
+// Model version                  : 1.10
+// Simulink Coder version         : 9.4 (R2020b) 29-Jul-2020
+// C/C++ source code generated on : Sun Apr 23 10:19:13 2023
+//
+// Target selection: ert.tlc
+// Embedded hardware selection: Intel->x86-64 (Windows64)
+// Code generation objectives: Unspecified
+// Validation result: Not run
+//
+
+#ifndef BUILTIN_TYPEID_TYPES_H
+#define BUILTIN_TYPEID_TYPES_H
+#include "rtwtypes.h"
+#ifndef BUILTIN_TYPEID_TYPES
+#define BUILTIN_TYPEID_TYPES
+
+// Enumeration of built-in data types
+typedef enum {
+  SS_DOUBLE = 0,                       // real_T
+  SS_SINGLE = 1,                       // real32_T
+  SS_INT8 = 2,                         // int8_T
+  SS_UINT8 = 3,                        // uint8_T
+  SS_INT16 = 4,                        // int16_T
+  SS_UINT16 = 5,                       // uint16_T
+  SS_INT32 = 6,                        // int32_T
+  SS_UINT32 = 7,                       // uint32_T
+  SS_BOOLEAN = 8                       // boolean_T
+} BuiltInDTypeId;
+
+#define SS_NUM_BUILT_IN_DTYPE          ((int_T)SS_BOOLEAN+1)
+
+// Enumeration for MAT-file logging code
+typedef int_T DTypeId;
+
+#endif                                 // BUILTIN_TYPEID_TYPES
+#endif                                 // BUILTIN_TYPEID_TYPES_H
+
+//
+// File trailer for generated code.
+//
+// [EOF]
+//

+ 105 - 0
unit_test/motor_sim/ert_main.cpp

@@ -0,0 +1,105 @@
+//
+// File: ert_main.cpp
+//
+// Code generated for Simulink model 'PmsmSimUt'.
+//
+// Model version                  : 1.15
+// Simulink Coder version         : 9.4 (R2020b) 29-Jul-2020
+// C/C++ source code generated on : Fri Jul 28 01:40:47 2023
+//
+// Target selection: ert.tlc
+// Embedded hardware selection: Intel->x86-64 (Windows64)
+// Code generation objectives: Unspecified
+// Validation result: Not run
+//
+#include <stddef.h>
+#include <stdio.h>                // This ert_main.c example uses printf/fflush
+#include "PmsmSimUt.h"                 // Model's header file
+#include "rtwtypes.h"
+
+static PmsmSimUtModelClass PmsmSimUt_Obj;// Instance of model class
+
+//
+// Associating rt_OneStep with a real-time clock or interrupt service routine
+// is what makes the generated code "real-time".  The function rt_OneStep is
+// always associated with the base rate of the model.  Subrates are managed
+// by the base rate from inside the generated code.  Enabling/disabling
+// interrupts and floating point context switches are target specific.  This
+// example code indicates where these should take place relative to executing
+// the generated code step function.  Overrun behavior should be tailored to
+// your application needs.  This example simply sets an error status in the
+// real-time model and returns from rt_OneStep.
+//
+void rt_OneStep(void);
+void rt_OneStep(void)
+{
+  static boolean_T OverrunFlag = false;
+
+  // Disable interrupts here
+
+  // Check for overrun
+  if (OverrunFlag) {
+    rtmSetErrorStatus(PmsmSimUt_Obj.getRTM(), "Overrun");
+    return;
+  }
+
+  OverrunFlag = true;
+
+  // Save FPU context here (if necessary)
+  // Re-enable timer or interrupt here
+  // Set model inputs here
+
+  // Step the model
+  PmsmSimUt_Obj.step();
+
+  // Get model outputs here
+
+  // Indicate task complete
+  OverrunFlag = false;
+
+  // Disable interrupts here
+  // Restore FPU context here (if necessary)
+  // Enable interrupts here
+}
+
+//
+// The example "main" function illustrates what is required by your
+// application code to initialize, execute, and terminate the generated code.
+// Attaching rt_OneStep to a real-time clock is target specific.  This example
+// illustrates how you do this relative to initializing the model.
+//
+int_T main(int_T argc, const char *argv[])
+{
+  // Unused arguments
+  (void)(argc);
+  (void)(argv);
+
+  // Initialize model
+  PmsmSimUt_Obj.initialize();
+
+  // Attach rt_OneStep to a timer or interrupt service routine with
+  //  period 0.0001 seconds (the model's base sample time) here.  The
+  //  call syntax for rt_OneStep is
+  //
+  //   rt_OneStep();
+
+  printf("Warning: The simulation will run forever. "
+         "Generated ERT main won't simulate model step behavior. "
+         "To change this behavior select the 'MAT-file logging' option.\n");
+  fflush((NULL));
+  while (rtmGetErrorStatus(PmsmSimUt_Obj.getRTM()) == (NULL)) {
+    //  Perform other application tasks here
+  }
+
+  // Disable rt_OneStep() here
+
+  // Terminate model
+  PmsmSimUt_Obj.terminate();
+  return 0;
+}
+
+//
+// File trailer for generated code.
+//
+// [EOF]
+//

+ 11 - 0
unit_test/motor_sim/model/.gitignore

@@ -0,0 +1,11 @@
+# Matlab Autosave File
+*.original
+*.autosave
+*.asv
+*.slxc
+*.mex*
+
+# Simulink Build File
+slprj/
+*_rtw/
+

BIN
unit_test/motor_sim/model/PmsmSimUt.slx


+ 2 - 0
unit_test/motor_sim/model/copy_file.m

@@ -0,0 +1,2 @@
+copyfile PmsmSimUt_ert_rtw/*.cpp ../
+copyfile PmsmSimUt_ert_rtw/*.h ../

BIN
unit_test/motor_sim/model/private.sldd


+ 31 - 0
unit_test/motor_sim/multiword_types.h

@@ -0,0 +1,31 @@
+//
+// File: multiword_types.h
+//
+// Code generated for Simulink model 'PmsmSimUt'.
+//
+// Model version                  : 1.10
+// Simulink Coder version         : 9.4 (R2020b) 29-Jul-2020
+// C/C++ source code generated on : Sun Apr 23 10:19:13 2023
+//
+// Target selection: ert.tlc
+// Embedded hardware selection: Intel->x86-64 (Windows64)
+// Code generation objectives: Unspecified
+// Validation result: Not run
+//
+
+#ifndef MULTIWORD_TYPES_H
+#define MULTIWORD_TYPES_H
+#include "rtwtypes.h"
+
+//
+//  Definitions supporting external data access
+typedef int32_T chunk_T;
+typedef uint32_T uchunk_T;
+
+#endif                                 // MULTIWORD_TYPES_H
+
+//
+// File trailer for generated code.
+//
+// [EOF]
+//

+ 97 - 0
unit_test/motor_sim/rtGetInf.cpp

@@ -0,0 +1,97 @@
+//
+// File: rtGetInf.cpp
+//
+// Code generated for Simulink model 'PmsmSimUt'.
+//
+// Model version                  : 1.15
+// Simulink Coder version         : 9.4 (R2020b) 29-Jul-2020
+// C/C++ source code generated on : Fri Jul 28 01:40:47 2023
+//
+// Target selection: ert.tlc
+// Embedded hardware selection: Intel->x86-64 (Windows64)
+// Code generation objectives: Unspecified
+// Validation result: Not run
+//
+
+//
+//  Abstract:
+//       Function to initialize non-finite, Inf
+#include "rtGetInf.h"
+#define NumBitsPerChar                 8U
+
+extern "C" {
+  //
+  // Initialize rtInf needed by the generated code.
+  // Inf is initialized as non-signaling. Assumes IEEE.
+  //
+  real_T rtGetInf(void)
+  {
+    size_t bitsPerReal = sizeof(real_T) * (NumBitsPerChar);
+    real_T inf = 0.0;
+    if (bitsPerReal == 32U) {
+      inf = rtGetInfF();
+    } else {
+      union {
+        LittleEndianIEEEDouble bitVal;
+        real_T fltVal;
+      } tmpVal;
+
+      tmpVal.bitVal.words.wordH = 0x7FF00000U;
+      tmpVal.bitVal.words.wordL = 0x00000000U;
+      inf = tmpVal.fltVal;
+    }
+
+    return inf;
+  }
+
+  //
+  // Initialize rtInfF needed by the generated code.
+  // Inf is initialized as non-signaling. Assumes IEEE.
+  //
+  real32_T rtGetInfF(void)
+  {
+    IEEESingle infF;
+    infF.wordL.wordLuint = 0x7F800000U;
+    return infF.wordL.wordLreal;
+  }
+
+  //
+  // Initialize rtMinusInf needed by the generated code.
+  // Inf is initialized as non-signaling. Assumes IEEE.
+  //
+  real_T rtGetMinusInf(void)
+  {
+    size_t bitsPerReal = sizeof(real_T) * (NumBitsPerChar);
+    real_T minf = 0.0;
+    if (bitsPerReal == 32U) {
+      minf = rtGetMinusInfF();
+    } else {
+      union {
+        LittleEndianIEEEDouble bitVal;
+        real_T fltVal;
+      } tmpVal;
+
+      tmpVal.bitVal.words.wordH = 0xFFF00000U;
+      tmpVal.bitVal.words.wordL = 0x00000000U;
+      minf = tmpVal.fltVal;
+    }
+
+    return minf;
+  }
+
+  //
+  // Initialize rtMinusInfF needed by the generated code.
+  // Inf is initialized as non-signaling. Assumes IEEE.
+  //
+  real32_T rtGetMinusInfF(void)
+  {
+    IEEESingle minfF;
+    minfF.wordL.wordLuint = 0xFF800000U;
+    return minfF.wordL.wordLreal;
+  }
+}
+//
+// File trailer for generated code.
+//
+// [EOF]
+//

+ 41 - 0
unit_test/motor_sim/rtGetInf.h

@@ -0,0 +1,41 @@
+//
+// File: rtGetInf.h
+//
+// Code generated for Simulink model 'PmsmSimUt'.
+//
+// Model version                  : 1.15
+// Simulink Coder version         : 9.4 (R2020b) 29-Jul-2020
+// C/C++ source code generated on : Fri Jul 28 01:40:47 2023
+//
+// Target selection: ert.tlc
+// Embedded hardware selection: Intel->x86-64 (Windows64)
+// Code generation objectives: Unspecified
+// Validation result: Not run
+//
+#ifndef RTW_HEADER_rtGetInf_h_
+#define RTW_HEADER_rtGetInf_h_
+#include <stddef.h>
+#include "rtwtypes.h"
+#include "rt_nonfinite.h"
+#ifdef __cplusplus
+
+extern "C" {
+
+#endif
+
+  extern real_T rtGetInf(void);
+  extern real32_T rtGetInfF(void);
+  extern real_T rtGetMinusInf(void);
+  extern real32_T rtGetMinusInfF(void);
+
+#ifdef __cplusplus
+
+}                                      // extern "C"
+#endif
+#endif                                 // RTW_HEADER_rtGetInf_h_
+
+//
+// File trailer for generated code.
+//
+// [EOF]
+//

+ 63 - 0
unit_test/motor_sim/rtGetNaN.cpp

@@ -0,0 +1,63 @@
+//
+// File: rtGetNaN.cpp
+//
+// Code generated for Simulink model 'PmsmSimUt'.
+//
+// Model version                  : 1.15
+// Simulink Coder version         : 9.4 (R2020b) 29-Jul-2020
+// C/C++ source code generated on : Fri Jul 28 01:40:47 2023
+//
+// Target selection: ert.tlc
+// Embedded hardware selection: Intel->x86-64 (Windows64)
+// Code generation objectives: Unspecified
+// Validation result: Not run
+//
+
+//
+//  Abstract:
+//       Function to initialize non-finite, NaN
+#include "rtGetNaN.h"
+#define NumBitsPerChar                 8U
+
+extern "C" {
+  //
+  // Initialize rtNaN needed by the generated code.
+  // NaN is initialized as non-signaling. Assumes IEEE.
+  //
+  real_T rtGetNaN(void)
+  {
+    size_t bitsPerReal = sizeof(real_T) * (NumBitsPerChar);
+    real_T nan = 0.0;
+    if (bitsPerReal == 32U) {
+      nan = rtGetNaNF();
+    } else {
+      union {
+        LittleEndianIEEEDouble bitVal;
+        real_T fltVal;
+      } tmpVal;
+
+      tmpVal.bitVal.words.wordH = 0xFFF80000U;
+      tmpVal.bitVal.words.wordL = 0x00000000U;
+      nan = tmpVal.fltVal;
+    }
+
+    return nan;
+  }
+
+  //
+  // Initialize rtNaNF needed by the generated code.
+  // NaN is initialized as non-signaling. Assumes IEEE.
+  //
+  real32_T rtGetNaNF(void)
+  {
+    IEEESingle nanF = { { 0 } };
+
+    nanF.wordL.wordLuint = 0xFFC00000U;
+    return nanF.wordL.wordLreal;
+  }
+}
+//
+// File trailer for generated code.
+//
+// [EOF]
+//

+ 39 - 0
unit_test/motor_sim/rtGetNaN.h

@@ -0,0 +1,39 @@
+//
+// File: rtGetNaN.h
+//
+// Code generated for Simulink model 'PmsmSimUt'.
+//
+// Model version                  : 1.15
+// Simulink Coder version         : 9.4 (R2020b) 29-Jul-2020
+// C/C++ source code generated on : Fri Jul 28 01:40:47 2023
+//
+// Target selection: ert.tlc
+// Embedded hardware selection: Intel->x86-64 (Windows64)
+// Code generation objectives: Unspecified
+// Validation result: Not run
+//
+#ifndef RTW_HEADER_rtGetNaN_h_
+#define RTW_HEADER_rtGetNaN_h_
+#include <stddef.h>
+#include "rtwtypes.h"
+#include "rt_nonfinite.h"
+#ifdef __cplusplus
+
+extern "C" {
+
+#endif
+
+  extern real_T rtGetNaN(void);
+  extern real32_T rtGetNaNF(void);
+
+#ifdef __cplusplus
+
+}                                      // extern "C"
+#endif
+#endif                                 // RTW_HEADER_rtGetNaN_h_
+
+//
+// File trailer for generated code.
+//
+// [EOF]
+//

+ 99 - 0
unit_test/motor_sim/rt_nonfinite.cpp

@@ -0,0 +1,99 @@
+//
+// File: rt_nonfinite.cpp
+//
+// Code generated for Simulink model 'PmsmSimUt'.
+//
+// Model version                  : 1.15
+// Simulink Coder version         : 9.4 (R2020b) 29-Jul-2020
+// C/C++ source code generated on : Fri Jul 28 01:40:47 2023
+//
+// Target selection: ert.tlc
+// Embedded hardware selection: Intel->x86-64 (Windows64)
+// Code generation objectives: Unspecified
+// Validation result: Not run
+//
+
+//
+//  Abstract:
+//       Function to initialize non-finites,
+//       (Inf, NaN and -Inf).
+#include "rt_nonfinite.h"
+#include "rtGetNaN.h"
+#include "rtGetInf.h"
+#define NumBitsPerChar                 8U
+
+extern "C" {
+  real_T rtInf;
+  real_T rtMinusInf;
+  real_T rtNaN;
+  real32_T rtInfF;
+  real32_T rtMinusInfF;
+  real32_T rtNaNF;
+}
+  extern "C"
+{
+  //
+  // Initialize the rtInf, rtMinusInf, and rtNaN needed by the
+  // generated code. NaN is initialized as non-signaling. Assumes IEEE.
+  //
+  void rt_InitInfAndNaN(size_t realSize)
+  {
+    (void) (realSize);
+    rtNaN = rtGetNaN();
+    rtNaNF = rtGetNaNF();
+    rtInf = rtGetInf();
+    rtInfF = rtGetInfF();
+    rtMinusInf = rtGetMinusInf();
+    rtMinusInfF = rtGetMinusInfF();
+  }
+
+  // Test if value is infinite
+  boolean_T rtIsInf(real_T value)
+  {
+    return (boolean_T)((value==rtInf || value==rtMinusInf) ? 1U : 0U);
+  }
+
+  // Test if single-precision value is infinite
+  boolean_T rtIsInfF(real32_T value)
+  {
+    return (boolean_T)(((value)==rtInfF || (value)==rtMinusInfF) ? 1U : 0U);
+  }
+
+  // Test if value is not a number
+  boolean_T rtIsNaN(real_T value)
+  {
+    boolean_T result = (boolean_T) 0;
+    size_t bitsPerReal = sizeof(real_T) * (NumBitsPerChar);
+    if (bitsPerReal == 32U) {
+      result = rtIsNaNF((real32_T)value);
+    } else {
+      union {
+        LittleEndianIEEEDouble bitVal;
+        real_T fltVal;
+      } tmpVal;
+
+      tmpVal.fltVal = value;
+      result = (boolean_T)((tmpVal.bitVal.words.wordH & 0x7FF00000) ==
+                           0x7FF00000 &&
+                           ( (tmpVal.bitVal.words.wordH & 0x000FFFFF) != 0 ||
+                            (tmpVal.bitVal.words.wordL != 0) ));
+    }
+
+    return result;
+  }
+
+  // Test if single-precision value is not a number
+  boolean_T rtIsNaNF(real32_T value)
+  {
+    IEEESingle tmp;
+    tmp.wordL.wordLreal = value;
+    return (boolean_T)( (tmp.wordL.wordLuint & 0x7F800000) == 0x7F800000 &&
+                       (tmp.wordL.wordLuint & 0x007FFFFF) != 0 );
+  }
+}
+
+//
+// File trailer for generated code.
+//
+// [EOF]
+//

+ 67 - 0
unit_test/motor_sim/rt_nonfinite.h

@@ -0,0 +1,67 @@
+//
+// File: rt_nonfinite.h
+//
+// Code generated for Simulink model 'PmsmSimUt'.
+//
+// Model version                  : 1.15
+// Simulink Coder version         : 9.4 (R2020b) 29-Jul-2020
+// C/C++ source code generated on : Fri Jul 28 01:40:47 2023
+//
+// Target selection: ert.tlc
+// Embedded hardware selection: Intel->x86-64 (Windows64)
+// Code generation objectives: Unspecified
+// Validation result: Not run
+//
+#ifndef RTW_HEADER_rt_nonfinite_h_
+#define RTW_HEADER_rt_nonfinite_h_
+#include <stddef.h>
+#include "rtwtypes.h"
+#ifdef __cplusplus
+
+extern "C" {
+
+#endif
+
+  extern real_T rtInf;
+  extern real_T rtMinusInf;
+  extern real_T rtNaN;
+  extern real32_T rtInfF;
+  extern real32_T rtMinusInfF;
+  extern real32_T rtNaNF;
+  extern void rt_InitInfAndNaN(size_t realSize);
+  extern boolean_T rtIsInf(real_T value);
+  extern boolean_T rtIsInfF(real32_T value);
+  extern boolean_T rtIsNaN(real_T value);
+  extern boolean_T rtIsNaNF(real32_T value);
+  typedef struct {
+    struct {
+      uint32_T wordH;
+      uint32_T wordL;
+    } words;
+  } BigEndianIEEEDouble;
+
+  typedef struct {
+    struct {
+      uint32_T wordL;
+      uint32_T wordH;
+    } words;
+  } LittleEndianIEEEDouble;
+
+  typedef struct {
+    union {
+      real32_T wordLreal;
+      uint32_T wordLuint;
+    } wordL;
+  } IEEESingle;
+
+#ifdef __cplusplus
+
+}                                      // extern "C"
+#endif
+#endif                                 // RTW_HEADER_rt_nonfinite_h_
+
+//
+// File trailer for generated code.
+//
+// [EOF]
+//

+ 156 - 0
unit_test/motor_sim/rtwtypes.h

@@ -0,0 +1,156 @@
+//
+// File: rtwtypes.h
+//
+// Code generated for Simulink model 'PmsmSimUt'.
+//
+// Model version                  : 1.15
+// Simulink Coder version         : 9.4 (R2020b) 29-Jul-2020
+// C/C++ source code generated on : Fri Jul 28 01:40:47 2023
+//
+// Target selection: ert.tlc
+// Embedded hardware selection: Intel->x86-64 (Windows64)
+// Code generation objectives: Unspecified
+// Validation result: Not run
+//
+
+#ifndef RTWTYPES_H
+#define RTWTYPES_H
+
+// Logical type definitions
+#if (!defined(__cplusplus))
+#ifndef false
+#define false                          (0U)
+#endif
+
+#ifndef true
+#define true                           (1U)
+#endif
+#endif
+
+//=======================================================================*
+//  Target hardware information
+//    Device type: Intel->x86-64 (Windows64)
+//    Number of bits:     char:   8    short:   16    int:  32
+//                        long:  32
+//                        native word size:  64
+//    Byte ordering: LittleEndian
+//    Signed integer division rounds to: Zero
+//    Shift right on a signed integer as arithmetic shift: on
+// =======================================================================
+
+//=======================================================================*
+//  Fixed width word size data types:                                     *
+//    int8_T, int16_T, int32_T     - signed 8, 16, or 32 bit integers     *
+//    uint8_T, uint16_T, uint32_T  - unsigned 8, 16, or 32 bit integers   *
+//    real32_T, real64_T           - 32 and 64 bit floating point numbers *
+// =======================================================================
+typedef signed char int8_T;
+typedef unsigned char uint8_T;
+typedef short int16_T;
+typedef unsigned short uint16_T;
+typedef int int32_T;
+typedef unsigned int uint32_T;
+typedef float real32_T;
+typedef double real64_T;
+
+//===========================================================================*
+//  Generic type definitions: boolean_T, char_T, byte_T, int_T, uint_T,       *
+//                            real_T, time_T, ulong_T.                        *
+// ===========================================================================
+typedef double real_T;
+typedef double time_T;
+typedef unsigned char boolean_T;
+typedef int int_T;
+typedef unsigned int uint_T;
+typedef unsigned long ulong_T;
+typedef char char_T;
+typedef unsigned char uchar_T;
+typedef char_T byte_T;
+
+//===========================================================================*
+//  Complex number type definitions                                           *
+// ===========================================================================
+#define CREAL_T
+
+typedef struct {
+  real32_T re;
+  real32_T im;
+} creal32_T;
+
+typedef struct {
+  real64_T re;
+  real64_T im;
+} creal64_T;
+
+typedef struct {
+  real_T re;
+  real_T im;
+} creal_T;
+
+#define CINT8_T
+
+typedef struct {
+  int8_T re;
+  int8_T im;
+} cint8_T;
+
+#define CUINT8_T
+
+typedef struct {
+  uint8_T re;
+  uint8_T im;
+} cuint8_T;
+
+#define CINT16_T
+
+typedef struct {
+  int16_T re;
+  int16_T im;
+} cint16_T;
+
+#define CUINT16_T
+
+typedef struct {
+  uint16_T re;
+  uint16_T im;
+} cuint16_T;
+
+#define CINT32_T
+
+typedef struct {
+  int32_T re;
+  int32_T im;
+} cint32_T;
+
+#define CUINT32_T
+
+typedef struct {
+  uint32_T re;
+  uint32_T im;
+} cuint32_T;
+
+//=======================================================================*
+//  Min and Max:                                                          *
+//    int8_T, int16_T, int32_T     - signed 8, 16, or 32 bit integers     *
+//    uint8_T, uint16_T, uint32_T  - unsigned 8, 16, or 32 bit integers   *
+// =======================================================================
+#define MAX_int8_T                     ((int8_T)(127))
+#define MIN_int8_T                     ((int8_T)(-128))
+#define MAX_uint8_T                    ((uint8_T)(255U))
+#define MAX_int16_T                    ((int16_T)(32767))
+#define MIN_int16_T                    ((int16_T)(-32768))
+#define MAX_uint16_T                   ((uint16_T)(65535U))
+#define MAX_int32_T                    ((int32_T)(2147483647))
+#define MIN_int32_T                    ((int32_T)(-2147483647-1))
+#define MAX_uint32_T                   ((uint32_T)(0xFFFFFFFFU))
+
+// Block D-Work pointer type
+typedef void * pointer_T;
+
+#endif                                 // RTWTYPES_H
+
+//
+// File trailer for generated code.
+//
+// [EOF]
+//

+ 134 - 0
unit_test/test_torqobs.cpp

@@ -0,0 +1,134 @@
+#include "gtest/gtest.h"
+#include <gtest/gtest.h>
+#include <stdint.h>
+#include <tuple>
+#include "scope.h"
+#include "test_user.h"
+#include "PmsmSimUt.h"
+#include "motor_sim_helper.h"
+
+class TorqObsTest : public testing::Test
+{
+protected:
+    PmsmSimUtModelClass *sys1;
+    McStatus      McStatus1;
+    McPuBase      McPuBase1;
+
+    virtual void SetUp() override
+    {
+        sys1 = new PmsmSimUtModelClass();
+        sys1->initialize();
+        MotorSimHelper::RestoreDefaultParam(sys1);
+        sys1->PmsmSimUt_P.Params.Ts      = 1.0 / FTBC_HZ;
+        sys1->PmsmSimUt_P.Params.SpdCtrl = 1;
+        sys1->PmsmSimUt_P.Params.B       = 0;
+        sys1->PmsmSimUt_P.Params.Jm      = M_JD * 1e-7;
+        sys1->PmsmSimUt_P.Params.Pn      = M_POLE_PAIRS;
+        sys1->PmsmSimUt_P.Params.R       = M_RS_OHM * 1e-5;
+        sys1->PmsmSimUt_P.Params.Ld      = M_LD_NOLOAD_MH * 1e-8;
+        sys1->PmsmSimUt_P.Params.Lq      = M_LQ_NOLOAD_MH * 1e-8;
+        sys1->PmsmSimUt_P.Params.Flux    = M_FLUX_WB * 1e-6;
+
+        sys1->PmsmSimUt_P.Params.SKp  = (sys1->PmsmSimUt_P.Params.Jm * 15 * 2 * 3.14 / sys1->PmsmSimUt_P.Params.Flux) / 30 * 3.14;
+        sys1->PmsmSimUt_P.Params.SKi  = 15 * 2 * 3.14 * sys1->PmsmSimUt_P.Params.SKp;
+        sys1->PmsmSimUt_P.Params.CKpd = (300 * 2 * 3.14) * sys1->PmsmSimUt_P.Params.Ld;
+        sys1->PmsmSimUt_P.Params.CKid = (300 * 2 * 3.14) * sys1->PmsmSimUt_P.Params.R;
+        sys1->PmsmSimUt_P.Params.CKpq = (300 * 2 * 3.14) * sys1->PmsmSimUt_P.Params.Lq;
+        sys1->PmsmSimUt_P.Params.CKiq = (300 * 2 * 3.14) * sys1->PmsmSimUt_P.Params.R;
+
+        McPuBaseIn puBaseIn = {
+            .Pairsb = MOTOR_PAIRS,
+            .UbVt   = VBASE,
+            .IbAp   = IBASE,
+            .FbHz   = FBASE,
+        };
+        McPuBaseInit(&McPuBase1, &puBaseIn);
+
+        McStatusInit(&McStatus1, &McPuBase1);
+
+        torqobs_voInit();
+    }
+
+    virtual void TearDown() override
+    {
+        sys1->terminate();
+        delete sys1;
+
+        torqobs_voInit();
+    }
+};
+
+class TorqObsTest1 : public TorqObsTest, public testing::WithParamInterface<::std::tuple<double, double, double>>
+{};
+
+TEST_P(TorqObsTest1, TorqObs)
+{
+    double torqPuMax1 = 0, torqPuMax2 = 0;
+    double mod = get<1>(GetParam());
+    double freq = get<2>(GetParam());
+    double band = 50;
+
+    /* Coef Cal */
+    torqobs_stCoefIn.uwUbVt = VBASE;
+    torqobs_stCoefIn.uwIbAp = IBASE;
+    torqobs_stCoefIn.uwFbHz = FBASE;
+    torqobs_stCoefIn.uwFTbsHz = FTBS_HZ;
+    torqobs_stCoefIn.uwPairs = M_POLE_PAIRS;
+    torqobs_stCoefIn.uwMtJm = M_JD; 
+    torqobs_stCoefIn.uwMtFlxWb = M_FLUX_WB;
+    torqobs_stCoefIn.uwWtcHz = band; 
+    torqobs_stCoefIn.uwRatioJm = 0; // ASR_SPD_INER_RATE;
+    torqobs_voCoef(&torqobs_stCoefIn, &torqobs_stCoef);  
+
+    /* Speed Ref */
+    sys1->PmsmSimUt_P.Params.CustomSpdCtrl  = 0;
+    sys1->PmsmSimUt_U.CtrlIn.WmRpm = get<0>(GetParam());
+ 
+    for (int i = 0; i < 10 / sys1->PmsmSimUt_P.Params.Ts; i++)
+    {
+        /* Motor Load Torque */
+        double phase = 2 * 3.14 * freq * i * sys1->PmsmSimUt_P.Params.Ts;
+        sys1->PmsmSimUt_U.CtrlIn.Tm = 1 + mod * sin(phase);
+
+        /* Motor Control */
+        sys1->step();
+
+        /* Named Value to Pu Value */
+        MotorSimHelper::TransitModelOutput(sys1, &McStatus1);
+
+        /* Torque Observer */
+        if(i % (FTBC_HZ / FTBS_HZ) == 0)
+        {
+            torqobs_stCalIn.swIqMaxPu = 55 * 100 * 16384 / IBASE;
+            torqobs_stCalIn.swIqMinPu = -55 * 100 * 16384 / IBASE;
+            torqobs_stCalIn.swIqfbkPu = McStatus1.Pu.swIq;
+            torqobs_stCalIn.swSpdPu = McStatus1.Pu.swElecOmega;
+            torqobs_voCal(&torqobs_stCalIn, &torqobs_stCoef, &torqobs_stCalOut);
+        }
+
+        double torqPu = (double)sys1->PmsmSimUt_U.CtrlIn.Tm * 1000 * 16384 / McStatus1.Base->uwTqbNm;
+        
+        /* Get Torque Max */ 
+        if(i > 1 / sys1->PmsmSimUt_P.Params.Ts)
+        {
+            if(torqPuMax1 < torqobs_stCalOut.swTorqObsPu)  
+            {
+                torqPuMax1 = torqobs_stCalOut.swTorqObsPu;
+            }
+            if(torqPuMax2 < torqPu)
+            {
+                torqPuMax2 = torqPu;
+            }
+        }
+
+        //UdpScope::Send(0, torqobs_stCalOut.swSpdObsPu, McStatus1.Pu.swElecOmega, torqPu, torqobs_stCalOut.swTorqObsPu, torqobs_stCalOut.swIqLoadPu);
+    }
+
+    if(freq <= band)
+    {
+        EXPECT_TRUE((torqPuMax1 / torqPuMax2) >= 0.707 && (torqPuMax1 / torqPuMax2) <= 1.01);  ///< band处为-3dB(0.707), P控制无超调小于0dB(1)
+    }
+
+}
+
+INSTANTIATE_TEST_SUITE_P(DiffTorq, TorqObsTest1, ::testing::Combine(::testing::Values(500, 5000), ::testing::Values(0, 0.5, 1), ::testing::Values(1, 16, 50)));

+ 2 - 0
unit_test/test_torquesensor.cpp

@@ -4,6 +4,8 @@
 #include <tuple>
 #include "scope.h"
 #include "test_user.h"
+#include "PmsmSimUt.h"
+#include "motor_sim_helper.h"
 
 
 class TorqueSensorTest : public testing::Test

+ 25 - 0
unit_test/test_typedefine.h

@@ -0,0 +1,25 @@
+#include <stdint.h>
+
+#ifndef _TEST_TYPEDEFINE_H_
+#define _TEST_TYPEDEFINE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+
+typedef int8_t   s8;
+typedef int16_t  s16;
+typedef int32_t  s32;
+typedef int64_t  s64;
+typedef uint8_t  u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif

+ 5 - 2
unit_test/test_user.c

@@ -9,7 +9,9 @@ int testCh2CapValue[2];
 int testCh3CapValue[2];
 int testGpioBValue[2];
 
-
+/* Variables and Functions mock */
+LPF_OUT scm_stMotoPwrInLpf;
+LPF_OUT scm_stIqLoadLpf;
 UWORD scm_uwSpdFbkLpfAbsPu;
 UWORD hw_uwADC0[ADC0_DMA_NUM];
 MC_UpperPCInfo_Struct_t MC_UpcInfo;
@@ -22,4 +24,5 @@ int timer_interrupt_flag_get(int timer_periph, int interrupt)
 void timer_interrupt_flag_clear(int timer_periph, int interrupt)
 {
     testTimerIntFlg[timer_periph][interrupt] = 0;
-}
+}
+

+ 8 - 0
unit_test/test_user.h

@@ -3,9 +3,15 @@
 #include "torquesensor.h"
 #include "adc.h"
 #include "pwm.h"
+#include "torqobs.h"
+#include "pwrlim.h"
+#include "asr.h"
 
+
+#include "glbcof.h"
 #include "typedefine.h"
 #include "CodePara.h"
+#include "mathtool.h"
 #include "macroequ.h"
 #include "canAppl.h"
 #include "hwsetup.h"
@@ -13,6 +19,8 @@
 #include "spdctrmode.h"
 #include "user.h"
 
+
+
 #ifndef _TEST_USER_H_
 #define _TEST_USER_H_
 

+ 64 - 0
unit_test/tools/motor_sim_helper.cpp

@@ -0,0 +1,64 @@
+#include "motor_sim_helper.h"
+
+PmsmSimUtModelClass::P_PmsmSimUt_T MotorSimHelper::DefaultParameter;
+
+void MotorSimHelper::StoreDefaultParam()
+{
+    DefaultParameter = PmsmSimUtModelClass::PmsmSimUt_P;
+}
+
+void MotorSimHelper::RestoreDefaultParam(PmsmSimUtModelClass *sys)
+{
+    sys->PmsmSimUt_P = DefaultParameter;
+}
+
+void MotorSimHelper::TransitModelOutput(PmsmSimUtModelClass *sys, McStatus *status)
+{
+    McPuBase      *b = status->Base;
+    McStatusNamed *n = &status->Named;
+    McStatusPu    *p = &status->Pu;
+
+    p->swIa = (s16)((sys->PmsmSimUt_Y.Out.Iabc[0] * 100 * 16384) / b->uwIbAp);
+    p->swIb = (s16)((sys->PmsmSimUt_Y.Out.Iabc[1] * 100 * 16384) / b->uwIbAp);
+    p->swIc = (s16)((sys->PmsmSimUt_Y.Out.Iabc[2] * 100 * 16384) / b->uwIbAp);
+
+    double ialpha = 0.6667 * (sys->PmsmSimUt_Y.Out.Iabc[0] - 0.5 * sys->PmsmSimUt_Y.Out.Iabc[1] - 0.5 * sys->PmsmSimUt_Y.Out.Iabc[2]);
+    double ibeta  = 0.57735 * (sys->PmsmSimUt_Y.Out.Iabc[1] - sys->PmsmSimUt_Y.Out.Iabc[2]);
+
+    p->swIalpha = (s16)((ialpha * 100 * 16384) / b->uwIbAp);
+    p->swIalpha = (s16)((ibeta * 100 * 16384) / b->uwIbAp);
+    p->swIzero  = 0;
+
+    p->swId = (s16)((sys->PmsmSimUt_Y.Out.Idq[0] * 100 * 16384) / b->uwIbAp);
+    p->swIq = (s16)((sys->PmsmSimUt_Y.Out.Idq[1] * 100 * 16384) / b->uwIbAp);
+    p->swI0 = 0;
+
+    p->swUa = (s16)((sys->PmsmSimUt_Y.Out.Uabc[0] * 10 * 16384) / b->uwUbVt);
+    p->swUb = (s16)((sys->PmsmSimUt_Y.Out.Uabc[1] * 10 * 16384) / b->uwUbVt);
+    p->swUc = (s16)((sys->PmsmSimUt_Y.Out.Uabc[2] * 10 * 16384) / b->uwUbVt);
+
+    double ualpha = 0.6667 * (sys->PmsmSimUt_Y.Out.Uabc[0] - 0.5 * sys->PmsmSimUt_Y.Out.Uabc[1] - 0.5 * sys->PmsmSimUt_Y.Out.Uabc[2]);
+    double ubeta  = 0.57735 * (sys->PmsmSimUt_Y.Out.Uabc[1] - sys->PmsmSimUt_Y.Out.Uabc[2]);
+
+    p->swUalpha = (s16)((ualpha * 10 * 16384) / b->uwUbVt);
+    p->swUbeta  = (s16)((ubeta * 10 * 16384) / b->uwUbVt);
+    p->swUzero  = 0;
+
+    p->swElecAngle = (s16)(sys->PmsmSimUt_Y.Out.Theta / 2 / 3.1415926 * 32768);
+    p->swElecOmega = (s16)((sys->PmsmSimUt_Y.Out.We * 10 * 32768) / b->uwWeb);
+
+    p->swUac = (s16)(((s32)5400 << 14) / b->uwUbVt);
+    p->swUdc = (s16)(((s32)5400 << 14) / b->uwUbVt);
+}
+
+void MotorSimHelper::SetModelICmdPu(PmsmSimUtModelClass *sys, double id_pu, double iq_pu, McPuBase *base)
+{
+    sys->PmsmSimUt_U.CtrlIn.IdCmd = (double)id_pu / (double)(1 << 14) * (double)base->uwIbAp / 100.0;
+    sys->PmsmSimUt_U.CtrlIn.IqCmd = (double)iq_pu / (double)(1 << 14) * (double)base->uwIbAp / 100.0;
+}
+
+void MotorSimHelper::SetModelUCmdPu(PmsmSimUtModelClass *sys, double ud_pu, double uq_pu, McPuBase *base)
+{
+    sys->PmsmSimUt_U.ICtrlIn.UdCtrl = (double)ud_pu / (double)(1 << 14) * ((double)base->uwUbVt / 10.0);
+    sys->PmsmSimUt_U.ICtrlIn.UqCtrl = (double)uq_pu / (double)(1 << 14) * ((double)base->uwUbVt / 10.0);
+}

+ 18 - 0
unit_test/tools/motor_sim_helper.h

@@ -0,0 +1,18 @@
+#include "PmsmSimUt.h"
+#include "mc_status.h"
+
+class MotorSimHelper
+{
+public:
+    static PmsmSimUtModelClass::P_PmsmSimUt_T DefaultParameter;
+
+    static void StoreDefaultParam();
+
+    static void RestoreDefaultParam(PmsmSimUtModelClass *sys);
+
+    static void TransitModelOutput(PmsmSimUtModelClass *sys, McStatus *status);
+
+    static void SetModelICmdPu(PmsmSimUtModelClass *sys, double id_pu, double iq_pu, McPuBase *base);
+
+    static void SetModelUCmdPu(PmsmSimUtModelClass *sys, double ud_pu, double uq_pu, McPuBase *base);
+};

+ 11 - 3
xmake.lua

@@ -7,12 +7,20 @@ target("unittest")
     set_languages("c++20")
 
     add_files("unit_test/*.cpp","unit_test/tools/*.cpp","unit_test/tools/*.c", "unit_test/*.c")
+    add_files("unit_test/motor_sim/PmsmSimUt.cpp")
+    add_files("unit_test/motor_sim/PmsmSimUt_data.cpp")
+    add_files("unit_test/motor_sim/rt_nonfinite.cpp")
+    add_files("unit_test/motor_sim/rtGetInf.cpp")
+    add_files("unit_test/motor_sim/rtGetNaN.cpp")
+    
     add_files("User project/4.BasicHardwSoftwLayer/2.BasicSoftwLayer/Source/CodePara.c", "User project/4.BasicHardwSoftwLayer/2.BasicSoftwLayer/Source/mathtool.c")
-    add_files("User project/4.BasicHardwSoftwLayer/2.BasicSoftwLayer/Source/macroequ.c")
+    add_files("User project/4.BasicHardwSoftwLayer/2.BasicSoftwLayer/Source/macroequ.c","User project/4.BasicHardwSoftwLayer/2.BasicSoftwLayer/Source/glbcof.c")
     add_files("User project/3.BasicFunction/Source/Cadence.c", "User project/3.BasicFunction/Source/bikespeed.c", "User project/3.BasicFunction/Source/torquesensor.c")
-    add_files("User project/2.MotorDrive/Source/adc.c", "User project/2.MotorDrive/Source/pwm.c")
+    add_files("User project/2.MotorDrive/Source/adc.c", "User project/2.MotorDrive/Source/pwm.c", "User project/2.MotorDrive/Source/packed/torqobs.c")
+    add_files("User project/2.MotorDrive/Source/packed/pwrlim.c", "User project/2.MotorDrive/Source/packed/asr.c")
     add_files("User project/3.BasicFunction/Source/Temp.c")
 
+
     -- add_includedirs("Std project/CMSIS")
     -- add_includedirs("Std project/CMSIS/GD/GD32F30x/Inc_GD")
     -- add_includedirs("Std project/GD32F30x_standard_peripheral/Inc_Peri")
@@ -23,7 +31,7 @@ target("unittest")
     add_includedirs("User project/3.BasicFunction/Include")
     add_includedirs("User project/4.BasicHardwSoftwLayer/1.BasicHardwLayer/Include")
     add_includedirs("User project/4.BasicHardwSoftwLayer/2.BasicSoftwLayer/Include")
-    add_includedirs("unit_test/tools")
+    add_includedirs("unit_test/tools", "unit_test/motor_sim")
     add_includedirs("unit_test")
 
     add_defines("RUN_ARCH_SIM")