精华内容
下载资源
问答
  • FOC中Clarke变换_TI和ST电机控制库的源码实现 FOC中PARK变换_TI和ST电机控制库的源码实现 FOC中反PARK变换_TI和ST电机控制库的源码实现 1.位置信息 无刷电机的控制不可脱离转子位置信息。知道转子位置反馈...

    FOC中的Clarke变换_TI和ST电机控制库的源码实现
    FOC中的PARK变换_TI和ST电机控制库的源码实现
    FOC中的反PARK变换_TI和ST电机控制库的源码实现

    1.位置信息

    无刷电机的控制不可脱离转子的位置信息。知道转子的位置反馈是对无刷电机控制的前提。通常分为有感和无感。

    有感:即为有位置传感器,像霍尔、光电增量式编码器、旋转变压器、磁编等等。

    无感:则是电机不需要位置传感器,通过电机自身的信息计算或则估计转子的位置。

    2.无感的方法

    基于模型法的位置/转速观测器有三部分,反电动势、磁链信息观测、位置误差信号解耦位置/转速观测。反电动势或磁链信息观测方法的不同,模型有自适应法、扩展卡尔曼滤波器法、磁链观测法、状态观测法、滑膜观测法。

    反电动势过零检测法应用广泛,实现简单、技术成熟。

    3.反电动势过零检测

    3.1反电动势过零检测法基本原理:

    忽略电动机电枢反应,无刷直流电动机在稳态运行过程中,通过检测关断相的反电动势过零点获得转子的位置信号,进行对逆变器开关导通顺序切换,控制电机运动。

    3.2缺点:

    电机静止和低速时,反电动势很小或者为0,无法获取转子位置信号,电机低速时性能较差,启动时需要开环启动。

    3.3硬件电路

    在这里插入图片描述
    反电动势图:
    在这里插入图片描述
    正向反电动势过零点变化:

    反电动势零点 变化趋势
    C- C相反电动势又正到负
    B+ B相反电动势又负到正
    A- A相反电动势又正到负
    C+ C相反电动势又负到正
    B- B相反电动势又正到负
    A+ A相反电动势又负到正

    3.4电路计算:

    在这里插入图片描述
    可以直接得到电机端的电压方程:
    {UA=RiA+LdiAdt+eA+UNUB=RiB+LdiBdt+eB+UNUC=RiC+LdiCdt+eC+UN \left\{ \begin{array}{l} U_A=Ri_A+L\frac{di_A}{dt}+e_A+U_N\\ U_B=Ri_B+L\frac{di_B}{dt}+e_B+U_N\\ U_C=Ri_C+L\frac{di_C}{dt}+e_C+U_N\\ \end{array} \right. ①

    假设c相不导通时有:
    {UC=eC+UNiA+iB=0eA+eB=0 \left\{ \begin{array}{l} U_C=e_C+U_N\\ i_A+i_B=0\\ e_A+e_B=0\\ \end{array} \right. ②
    可以得到反电动势:
    eC=UC12(UA+UB) e_C=U_C-\frac{1}{2}\left( U_A+U_B \right)
    同理可以得到A、B相的的反电动势
    {eA=UA12(UC+UB)eB=UB12(UA+UC)eC=UC12(UA+UB) \left\{ \begin{array}{l} e_A=U_A-\frac{1}{2}\left( U_C+U_B \right)\\ e_B=U_B-\frac{1}{2}\left( U_A+U_C \right)\\ e_C=U_C-\frac{1}{2}\left( U_A+U_B \right)\\ \end{array} \right.
    通过这三个方差去判断反电动势的正负变化得到零点。但是还可以优化一下,方便编程。
    ①和②重新组合一下合一得到:
    UA+UB+UC=eC+3UN U_A+U_B+U_C=e_C+3U_N
    当Ec=0时候满足:
    UA+UB+UC=3UN U_A+U_B+U_C=3U_N ③
    可以得到:
    {3eA=3UA3UN3eB=3UB3UN3eC=3UC3UN \left\{ \begin{array}{l} 3e_A=3U_A-3U_N\\ 3e_B=3U_B-3U_N\\ 3e_C=3U_C-3U_N\\ \end{array} \right.

    4.TI程序:

    4.1换向点电气行为

    **因为在在相位换向的瞬间,由于直流电平或电源板的寄生电感和电容,可能会出现高dV /dt和dI/dt毛刺。可能会对计算的中性点电压有错误。**通过丢弃前几次扫描来克服这问题。(比如从负到正,先一直为负,检测到4次为正时,标志到了过零点检测,算是滤波)

    在代码中,这是通过名为“NOISE_WIN”的功能实现的。持续时间取决于电源开关,电源板设计,相电感和驱动的直流电。此参数取决于系统,并且在电动机的低速范围内设置为较大的值。随着速度的增加,由于Bemf零交叉点也以更高的速度变得越来越近,所以逐渐降低了该持续时间。

    4.2换向30度延迟

    在有效的传感控制中,Bemf的零交叉点从相位换向时刻偏移了30º。因此,在借助六个过零事件来运行无传感器BLDC电动机之前,有必要计算与该30º延迟角相对应的时间延迟获得精确的换向点。这是通过实现位置插值功能来实现的。
    相应的时间延迟以采样时间段的数量表示,并存储在变量CmtnDelay中。

    Time delay = CmtnDelay .Ts = T(a/360) = VirtualTimer.Ts(a/360) = VirtualTimer . Ts/12

    其中,Ts是采样时间段,VirtualTimer是计时器,用于对转子上一圈旋转期间的采样周期数进行计数。

    4.3TI代码实现

    
    typedef  struct { Uint32 CmtnTrig;       	// Output: Commutation trigger output (0 or 0x00007FFF)       
                      _iq Va;                 	// Input: Motor phase a voltage referenced to GND (pu)  
                      _iq Vb;                 	// Input: Motor phase b voltage referenced to GND (pu)  
                      _iq Vc;                 	// Input: Motor phase c voltage referenced to GND (pu) 
                      _iq Neutral;            	// Variable: 3*Motor netural voltage (pu) 
                      Uint32 RevPeriod;      	 // Variable: revolution time counter (Q0)        
                      Uint32 ZcTrig;         	// Variable: Zero-Crossing trig flag (0 or 0x00007FFF)  
                      Uint32 CmtnPointer;     	// Input: Commutation state pointer input (0,1,2,3,4,5)
                      _iq DebugBemf;         	// Variable: 3*Back EMF = 3*(vx=vn), x=a,b,c (pu)
                      Uint32 NoiseWindowCounter;// Variable: Noise windows counter (Q0) 
                      Uint32 Delay30DoneFlag;   // Variable: 30 Deg delay flag (0 or 0x0000000F) 
                      Uint32 NewTimeStamp;  	// Variable: Time stamp (Q0) 
                      Uint32 OldTimeStamp;  	// History: Previous time stamp (Q0) 
    	              Uint32 VirtualTimer;    	// Input: Virtual timer (Q0) 
                      Uint32 CmtnDelay;      	// Variable: Time delay in terms of number of sampling time periods (Q0)    
                      Uint32 DelayTaskPointer; 	// Variable: Delay task pointer, see note below (0 or 1)
                      Uint32 NoiseWindowMax;  	// Variable: Maximum noise windows counter (Q0)
                      Uint32 CmtnDelayCounter; 	// Variable: Time delay counter (Q0) 
                      Uint32 NWDelta;      		// Variable: Noise windows delta (Q0)
                      Uint32 NWDelayThres;    	// Variable: Noise windows dynamic threshold (Q0)
    		 	 	   int32 GPR1_COM_TRIG;		// Variable: Division reminder
    		 	 	   int32 Tmp;				// Variable: Temp. variable
                    } CMTN;
    
    /*
    Note: 
    DelayTaskPointer = 0, branch for #COUNT_DWN
    DelayTaskPointer = 1, branch for #CHK_TRIGGER
    */
    
    /*-----------------------------------------------------------------------------
    Default initalizer for the CMTN object.
    -----------------------------------------------------------------------------*/                     
    #define CMTN_DEFAULTS { 0, \
                            0, \
                            0, \
                            0, \
                            0, \
                            0, \
                            0, \
                            0, \
                            0, \
                            0, \
                            0, \
                            0, \
                            0, \
                            0, \
                            0, \
                            1, \
                            0, \
                            0, \
                            0, \
                            0, \
                            0, \
                            0, \
                  		   }
    /*----------------------------------------------------------------------------------------------
    	 CMTN_TRIG Macro Definition
    ----------------------------------------------------------------------------------------------*/
    
    #define CMTN_TRIG_MACRO(v)																\
    																						\
    /* Always clear flags on entry*/														\
        v.CmtnTrig = 0;																		\
        v.ZcTrig = 0;																		\
            																				\
    /* Neutral voltage calculation (3*motor Neutral voltage)*/								\
    	v.Neutral = v.Va + v.Vb + v.Vc;														\
    																						\
    /* Commutation State table Tasks*/														\
    /* State s1: current flows to motor windings from phase A->B, de-energized phase = C*/	\
       if (v.CmtnPointer == 0)																\
        {																					\
    	  v.DebugBemf = _IQmpy(_IQ(3),v.Vc) - v.Neutral;									\
    	  if (v.DebugBemf > 0)																\
    	       v.NoiseWindowCounter = 0;													\
    	  else   /*  Zero crossing Noise window processing*/								\
               NOISE_WINDOW_CNT_MACRO(v);													\
        }   /* else if-end: State s1*/ 														\
    																						\
    /* State s2: current flows to motor windings from phase A->C, de-energized phase = B*/ 	\
        else if (v.CmtnPointer == 1)  														\
    	{																					\
    	  v.DebugBemf = _IQmpy(_IQ(3),v.Vb) - v.Neutral;									\
    	  if (v.DebugBemf < 0)																\
    	       v.NoiseWindowCounter = 0;													\
    	  else   /*  Zero crossing Noise window processing*/								\
               NOISE_WINDOW_CNT_MACRO(v);													\
        }   /* else if-end: State s2*/														\
    																						\
    /* State s3: current flows to motor windings from phase B->C, de-energized phase = A*/ 	\
        else if (v.CmtnPointer == 2)  														\
        {																					\
    	  v.DebugBemf = _IQmpy(_IQ(3),v.Va) - v.Neutral;									\
    	  if (v.DebugBemf > 0)																\
    	       v.NoiseWindowCounter = 0;													\
    	  else  /*  Zero crossing Noise window processing*/									\
               NOISE_WINDOW_CNT_MACRO(v);													\
        }   /* else if-end: State s3*/														\
    																						\
    /* State s4: current flows to motor windings from phase B->A, de-energized phase = C*/	\
        else if (v.CmtnPointer == 3)  														\
        {																					\
    	  v.DebugBemf = _IQmpy(_IQ(3),v.Vc) - v.Neutral;									\
    	  if (v.DebugBemf < 0)																\
    	       v.NoiseWindowCounter = 0;													\
    	  else   /*  Zero crossing Noise window processing*/								\
               NOISE_WINDOW_CNT_MACRO(v);													\
        }   /* else if-end: State s4*/														\
    																						\
    /* State s5: current flows to motor windings from phase C->A, de-energized phase = B*/	\
        else if (v.CmtnPointer == 4)														\
        {	
            /*计算三十度延迟的flag置位*/													\
    	  v.Delay30DoneFlag = 0;	       /* clear flag for delay calc in State 5*/		\
    	  																					\
    	  v.DebugBemf = _IQmpy(_IQ(3),v.Vb) - v.Neutral;									\
    	  if (v.DebugBemf > 0)																\
    	       v.NoiseWindowCounter = 0;													\
    	  else   /*  Zero crossing Noise window processing */								\
               NOISE_WINDOW_CNT_MACRO(v);													\
        }   /* else if-end: State s5	 */													\
    																						\
    /* State s6: current flows to motor windings from phase C->B, de-energized phase = A*/	\
        else if (v.CmtnPointer == 5)  														\
        {																					\
    	  v.DebugBemf = _IQmpy(_IQ(3),v.Va) - v.Neutral;									\
    	  if (v.DebugBemf < 0)																\
    	       v.NoiseWindowCounter = 0;													\
    	  else   /*  Zero crossing Noise window processing*/								\
               NOISE_WINDOW_CNT_MACRO(v);													\
          /*计算三十度延迟*/
          DELAY_30DEG_MACRO(v);																\
        }   /* else if-end: State s6*/														\
    																						\
    /* Zero crossing to Commutation trigger delay*/											\
       v.CmtnTrig = 0;     /* Always clear flag on entry */									\
    	
       /* 得到过零点后,进行30度延迟 */												     	\
       if (v.DelayTaskPointer > 0)     /* v.DelayTaskPointer = 1 for #CHK_TRIGGER*/			\
       { 																					\
          if (v.ZcTrig != 0)																\
          {																					\
    /* Substract NoiseWindowMax to compensate the advanced zero-crossing validation point */\
              v.CmtnDelayCounter = v.CmtnDelay - v.NoiseWindowMax;							\
              v.DelayTaskPointer = 0;     /* v.DelayTaskPointer = 0 for #COUNT_DWN*/		\
          }																					\
       }																					\
       else     /* v.DelayTaskPointer = 0 for #COUNT_DWN */									\
       {
          /* 计数减到0,得到换向点*/  										            	\
           v.CmtnDelayCounter -= 1;															\
           if (v.CmtnDelayCounter == 0) 													\
           {																				\
              v.CmtnTrig = 0x00007FFF; /* Yes!- Set trigger. This is used */				\
    /* as an input to "MOD6_CNTR" module that changes the commutation sequence.*/			\
    						             													\
              v.DelayTaskPointer = 1;       /* v.DelayTaskPointer = 1 for #CHK_TRIGGER*/	\
           }    																			\
       }
    
    /*----------------------------------------------------------------------------------------------
    	 NOISE_WINDOW_CNT Macro Definition
    ----------------------------------------------------------------------------------------------*/
    // 滤噪窗口,认为过了NoiseWindowMax个计数才算过零点
    #define NOISE_WINDOW_CNT_MACRO(v)															\
       if (v.CmtnDelay >= v.NWDelayThres)      /* noise window is fixed Value*/					\
          v.NoiseWindowMax = v.NWDelayThres - v.NWDelta;										\
       else                                       /* noise window adjusted dynamically*/		\
          v.NoiseWindowMax = v.CmtnDelay - v.NWDelta;											\
    																							\
       v.NoiseWindowCounter += 1;																\
    																							\
       if (v.NoiseWindowCounter == v.NoiseWindowMax)  /* zc must occur max_noise_window times*/	\
       {																						\
         v.ZcTrig = 0x00007FFF;       /* Yes! Set trigger */									\
         v.NoiseWindowCounter = 0;																\
       }								
    
    /*----------------------------------------------------------------------------------------------
    	DELAY_30DEG Macro Definition
    ----------------------------------------------------------------------------------------------*/
    // 30度角的延迟计算
    #define DELAY_30DEG_MACRO(v)																\
    /* Delay 30 deg calculator*/																\
       if (v.Delay30DoneFlag == 0)																\
       { 
          /*更新时间计数、计算上一圈花了多少时间*/ 								         		\
          v.OldTimeStamp = v.NewTimeStamp; 														\
          v.NewTimeStamp = v.VirtualTimer; 														\
          v.Tmp = v.NewTimeStamp - v.OldTimeStamp; 												\
          																						\
          if (v.Tmp > 0) /* Period = NewTimeStamp - OldTimeStamp*/								\
              v.RevPeriod = v.Tmp;																\
          else       /* If Period is negative, allow "wrapping"  */								\
              v.RevPeriod = 0x00007FFF + v.Tmp;													\
    																							\
          v.RevPeriod &= 0x0000FFFF;															\
    		 /* T/12算下一圈30度角延迟计数*/					         		            	\
          v.CmtnDelay = v.RevPeriod/12;                  /* Division quotient*/					\
          /* 算余数,大于6则再+1*/	
          v.GPR1_COM_TRIG = v.RevPeriod - v.CmtnDelay*12;  /* Division reminder*/				\
          if (v.GPR1_COM_TRIG >= 6) 															\
               v.CmtnDelay += 1;     /* if Division reminder >= 6, rounding division quotient*/	\
          v.Delay30DoneFlag = 0x0000000F;  /* flag indicates "gone through" once*/				\
       }   /* if-end: v.Delay30DoneFlag == 0*/    
    
    

    参考学习:
    TI Digital Motor Control,DMC MATH_V13.1
    [1]李伟.无位置传感器 BLDC 电机控制器研究[D].吉林:吉林大学.2014:7
    [2]韩芳.双模型无刷直流电动机控制器设计与实现[D].成都.电子科技大学.2015.4
    [3]刘雨锋.无刷直流电机无位置传感器关键控制技术研究[D].江西.江西理工大学.2019.5
    [4]童小健.无位置传感器永磁无刷直流电机控制策略研究[D].深圳.深圳大学.2015.4
    [5]李自成.无刷直流电机无位置传感器控制关键技术研究[D].武汉.华中科技大学.2010.3

    展开全文
  • FOC中Clarke变换_TI和ST电机控制库的源码实现 FOC中PARK变换_TI和ST电机控制库的源码实现 PARK反变换 此变换将正交旋转坐标系中矢量投影到两相正交固定框架。 ①经过clarke变换将三相电流变换为了固定...

    FOC中的Clarke变换_TI和ST电机控制库的源码实现
    FOC中的PARK变换_TI和ST电机控制库的源码实现

    PARK的反变换

    此变换将正交旋转坐标系中的矢量投影到两相正交固定框架。

    ①经过clarke变换将三相电流变换为了固定的“alpha-beta”直角坐标系下。
    ②因转子是旋转的,又经过PARK变换将固定的直角坐标系下的“alpha-beta”轴,变换为旋转坐标系“D-Q”轴。
    ③将三相相差120度的正弦信号变换为了线性的ID,IQ信号。
    ④但是我们得到反馈,计算完后。要将信号变换回去,输出对应的三相电压。
    ⑤又会经过反PARK变换,而反clarke变化可以使用另一种方式svpwm去完成输出电压。

    参考框图:
    TI参考框架图

    数学公式

    {Id=ID×cosθ+IQ×sinθIq=ID×sinθ+IQ×cosθ \left\{ \begin{array}{l} I_d=I_D\times \cos \theta +I_Q\times \sin \theta\\ I_q=I_D\times \sin \theta +I_Q\times \cos \theta\\ \end{array} \right.
    转换后波形:
    park变换后park反变换后

    TI程序:

    和park程序一样,cos(theta)和sin(theta)是参数。

    typedef struct {  _iq  Alpha;  		// Output: stationary d-axis stator variable
    				  _iq  Beta;		// Output: stationary q-axis stator variable
    				  _iq  Angle;		// Input: rotating angle (pu)
    				  _iq  Ds;			// Input: rotating d-axis stator variable
    				  _iq  Qs;			// Input: rotating q-axis stator variable
    				  _iq  Sine;		// Input: Sine term
    				  _iq  Cosine;		// Input: Cosine term
    		 	    } IPARK;	            
    /*------------------------------------------------------------------------------
    	Inverse PARK Transformation Macro Definition
    ------------------------------------------------------------------------------*/
    #define IPARK_MACRO(v)										\
    															\
    v.Alpha = _IQmpy(v.Ds,v.Cosine) - _IQmpy(v.Qs,v.Sine);		\
    v.Beta  = _IQmpy(v.Qs,v.Cosine) + _IQmpy(v.Ds,v.Sine);
    

    ST的程序:

    __weak alphabeta_t MCM_Rev_Park( qd_t Input, int16_t Theta )
    {
      int32_t alpha_tmp1, alpha_tmp2, beta_tmp1, beta_tmp2;
      Trig_Components Local_Vector_Components;
      alphabeta_t Output;
    
    	// 查表得到cos(theta)和sin(theta)
      Local_Vector_Components = MCM_Trig_Functions( Theta );
    
      /*No overflow guaranteed*/
      alpha_tmp1 = Input.q * ( int32_t )Local_Vector_Components.hCos;
      alpha_tmp2 = Input.d * ( int32_t )Local_Vector_Components.hSin;
    
    #ifdef FULL_MISRA_C_COMPLIANCY
      Output.alpha = ( int16_t )( ( ( alpha_tmp1 ) + ( alpha_tmp2 ) ) / 32768 );
    #else
      /* WARNING: the below instruction is not MISRA compliant, user should verify
        that Cortex-M3 assembly instruction ASR (arithmetic shift right) is used by
        the compiler to perform the shift (instead of LSR logical shift right) */
    	// 计算转换后的输出alpha
      Output.alpha = ( int16_t )( ( ( alpha_tmp1 ) + ( alpha_tmp2 ) ) >> 15 );
    #endif
    
      beta_tmp1 = Input.q * ( int32_t )Local_Vector_Components.hSin;
      beta_tmp2 = Input.d * ( int32_t )Local_Vector_Components.hCos;
    
    #ifdef FULL_MISRA_C_COMPLIANCY
      Output.beta = ( int16_t )( ( beta_tmp2 - beta_tmp1 ) / 32768 );
    #else
      /* WARNING: the below instruction is not MISRA compliant, user should verify
      that Cortex-M3 assembly instruction ASR (arithmetic shift right) is used by
      the compiler to perform the shift (instead of LSR logical shift right) */
      // 计算转换后的输出beta
      Output.beta = ( int16_t )( ( beta_tmp2 - beta_tmp1 ) >> 15 );
    #endif
    
      return ( Output );
    }
    

    参考:
    TI DMC MATH_13.1pdf
    STM32 FOC 软件培训库pdf

    展开全文
  • 这个变换目的是将平衡三相量转换为平衡两相正交量。 这三相电流理论上是相位相差120度正弦波: {Ia=I×cos⁡(wt)Ib=I×cos⁡(wt−2π/3)Ic=I×cos⁡(wt−4π/3) \left\{ \begin{array}{l} Ia=I\times \cos ...

    FOC中的Clarke变换_TI和ST电机控制库的源码实现
    FOC中的PARK变换_TI和ST电机控制库的源码实现
    FOC中的反PARK变换_TI和ST电机控制库的源码实现

    Clarke变换

    这个变换的目的是将平衡的三相量转换为平衡的两相正交量。

    这三相电流理论上是相位相差120度的正弦波:

    {Ia=I×cos(wt)Ib=I×cos(wt2π/3)Ic=I×cos(wt4π/3) \left\{ \begin{array}{l} Ia=I\times \cos \left( wt \right)\\ Ib=I\times \cos \left( wt-2\pi /3 \right)\\ Ic=I\times \cos \left( wt-4\pi /3 \right)\\ \end{array} \right.

    在这里插入图片描述

    空间矢量表示这a,b,c三相电流。
    在这里插入图片描述

    我们更习惯于二维平面图中的直角坐标系。可以把这(Ia,Ib,Ic)三个基向量做一个很简单的正交化。

    αβ \alpha -\beta 坐标系
    变换公式:

    {Iα=Iacos(π3)Ibcos(2π3)IcIβ=sin(π3)Ibsin(π3)Ic \left\{ \begin{array}{l} I\alpha =Ia-\cos \left( \frac{\pi}{3} \right) Ib-\cos \left( \frac{2\pi}{3} \right) Ic\\ I\beta =\sin \left( \frac{\pi}{3} \right) Ib-\sin \left( \frac{\pi}{3} \right) Ic\\ \end{array} \right.
    基尔霍夫电流定律(KCL):

    Ia+Ib+Ic=0 Ia+Ib+Ic=0
    所以我们可以得到

    {Iα=IaIβ=(2Ib+Ia3) \left\{ \begin{array}{l} I\alpha =Ia\\ I\beta =\left( \frac{2Ib+Ia}{\sqrt{3}} \right)\\ \end{array} \right.

    {Iα=I×cos(wt)Iβ=I×sin(wt) \left\{ \begin{array}{l} I\alpha =I\times \cos \left( wt \right)\\ I\beta =I\times \sin \left( wt \right)\\ \end{array} \right.
    完成转换成了两相正交量。
    在这里插入图片描述

    TI的Digital Motor Control库中的实现:

    使用了IQmath的库:把运算浮点数速度提高。定点DSP实现精确的浮点运算。

    typedef struct {  _iq  As;  		// Input: phase-a stator variable
    				  _iq  Bs;			// Input: phase-b stator variable
    				  _iq  Cs;			// Input: phase-c stator variable  
    				  _iq  Alpha;		// Output: stationary d-axis stator variable 
    				  _iq  Beta;		// Output: stationary q-axis stator variable
    		 	 	} CLARKE;	            
    /*-----------------------------------------------------------------------------
    	Default initalizer for the CLARKE object.
    -----------------------------------------------------------------------------*/  
    #define CLARKE_DEFAULTS { 0, \
                              0, \
                              0, \
                              0, \
                              0, \
                  			} 
    
    //  1/sqrt(3) = 0.57735026918963
    #define  ONEbySQRT3   0.57735026918963    /* 1/sqrt(3) */
    	
    // Clarke transform macro (with 2 currents)
    // 只采用两相电流,另一相Ia+Ib+Ic=0得到
    // beta = (2*b+a)/sqrt(3)
    //==========================================
    #define CLARKE_MACRO(v)										\
    v.Alpha = v.As;												\
    v.Beta = _IQmpy((v.As +_IQmpy2(v.Bs)),_IQ(ONEbySQRT3));
    
    // Clarke transform macro (with 3 currents)
    // 三相电流时beta = (b-c)/sqrt(3)
    //==========================================
    #define CLARKE1_MACRO(v)									\
    v.Alpha = v.As;											    \
    v.Beta  = _IQmpy((v.Bs - v.Cs),_IQ(ONEbySQRT3));
    
    

    ST的电机库的实现函数:

    st库只使用了两相电流,一堆限幅检测猛如虎。

    typedef struct
    {
      int16_t a;
      int16_t b;
    } ab_t;
    
    #define divSQRT_3 (int32_t)0x49E6    /* 1/sqrt(3) in q1.15 format=0.5773315*/
    
    /**
      * @brief  This function transforms stator values a and b (which are
      *         directed along axes each displaced by 120 degrees) into values
      *         alpha and beta in a stationary qd reference frame.
      *                               alpha = a
      *                       beta = -(2*b+a)/sqrt(3)
      * @param  Input: stator values a and b in ab_t format
      * @retval Stator values alpha and beta in alphabeta_t format
      */
    __weak alphabeta_t MCM_Clarke( ab_t Input  )
    {
      alphabeta_t Output;
    
      int32_t a_divSQRT3_tmp, b_divSQRT3_tmp ;
      int32_t wbeta_tmp;
      int16_t hbeta_tmp;
    
      /* qIalpha = qIas*/
      Output.alpha = Input.a;
    
      a_divSQRT3_tmp = divSQRT_3 * ( int32_t )Input.a;
    
      b_divSQRT3_tmp = divSQRT_3 * ( int32_t )Input.b;
    
      /*qIbeta = -(2*qIbs+qIas)/sqrt(3)*/
      // 这里的右移15位,除以32768。
      // divSQRT_3  = 0x49E6 / 32768 = 0.5773315
    #ifdef FULL_MISRA_C_COMPLIANCY
      wbeta_tmp = ( -( a_divSQRT3_tmp ) - ( b_divSQRT3_tmp ) -
                     ( b_divSQRT3_tmp ) ) / 32768;
    #else
      /* WARNING: the below instruction is not MISRA compliant, user should verify
        that Cortex-M3 assembly instruction ASR (arithmetic shift right) is used by
        the compiler to perform the shift (instead of LSR logical shift right) */
    
      wbeta_tmp = ( -( a_divSQRT3_tmp ) - ( b_divSQRT3_tmp ) -
                     ( b_divSQRT3_tmp ) ) >> 15;
    #endif
    
      /* Check saturation of Ibeta */
      if ( wbeta_tmp > INT16_MAX )
      {
        hbeta_tmp = INT16_MAX;
      }
      else if ( wbeta_tmp < ( -32768 ) )
      {
        hbeta_tmp = ( -32768 );
      }
      else
      {
        hbeta_tmp = ( int16_t )( wbeta_tmp );
      }
    
      Output.beta = hbeta_tmp;
    
      if ( Output.beta == ( int16_t )( -32768 ) )
      {
        Output.beta = -32767;
      }
    
      return ( Output );
    }
    

    __weak 前缀的函数称这个函数为“弱函数”。

    若两个或两个以上全局符号(函数或变量名)名字一样,而其中之一声明为weak属性,则这些全局符号不会引发重定义错误。链接器会忽略弱符号,去使用普通的全局符号来解析所有对这些符号的引用,但当普通的全局符号不可用时,链接器会使用弱符号

    当有函数或变量名可能被用户覆盖时,该函数或变量名可以声明为一个弱符号。

    参考:
    稚晖大佬:
    http://www.pengzhihui.xyz/2020/07/02/foc/#more
    STM32 FOC 软件培训库pdf
    TI DMC MATH_13.1pdf

    展开全文
  • 该变换将平衡两相正交平稳系统中矢量变换为正交旋转坐标系。 数学公式: {ID=Iα×cos⁡θ+Iβ×sin⁡θIQ=−Iα×sin⁡θ+Iβ×cos⁡θ \left\{ \begin{array}{l} I_D=I_{\alpha}\times \cos \theta +I_{\beta}...

    FOC中的Clarke变换_TI和ST电机控制库的源码实现
    FOC中的PARK变换_TI和ST电机控制库的源码实现
    FOC中的反PARK变换_TI和ST电机控制库的源码实现

    park变换

    该变换将平衡两相正交平稳系统中的矢量变换为正交旋转坐标系。
    参考框架_TI文档
    数学公式:

    {ID=Iα×cosθ+Iβ×sinθIQ=Iα×sinθ+Iβ×cosθ \left\{ \begin{array}{l} I_D=I_{\alpha}\times \cos \theta +I_{\beta}\times \sin \theta\\ I_Q=-I_{\alpha}\times \sin \theta +I_{\beta}\times \cos \theta\\ \end{array} \right.
    跟着转子旋转的“d-q”坐标系成功把cos,sin正余弦信号转化线性的了。
    theta角度是由位置传感器得到的已知变量。
    在这里插入图片描述在这里插入图片描述

    TI的实现

    也是很简单的两句计算,cos和sin(theta)是外部计算传入参数。对于三角函数,TI有自己的库去计算。
    而cos和sin(theta)不止只有在park中使用,其他地方也会使用,在这函数中再计算一次,未免多花时间了。st的库即比较麻烦。

    typedef struct {  _iq  Alpha;  		// Input: stationary d-axis stator variable 
    				  _iq  Beta;	 	// Input: stationary q-axis stator variable 
    				  _iq  Angle;		// Input: rotating angle (pu) 
    				  _iq  Ds;			// Output: rotating d-axis stator variable 
    				  _iq  Qs;			// Output: rotating q-axis stator variable
    				  _iq  Sine;
    				  _iq  Cosine; 	 
    		 	 	} PARK;	            
    
    /*------------------------------------------------------------------------------
    	PARK Transformation Macro Definition
    ------------------------------------------------------------------------------*/
    #define PARK_MACRO(v)											\
    																\
    	v.Ds = _IQmpy(v.Alpha,v.Cosine) + _IQmpy(v.Beta,v.Sine);	\
        v.Qs = _IQmpy(v.Beta,v.Cosine) - _IQmpy(v.Alpha,v.Sine);
    

    ST的库:

    ST的代码写很“规矩”,一步一步的。有很多限幅检测。
    在对theta求角度的查表法也绕了一下。解决浮点计算,统一后,全使用int型的。

    typedef struct
    {
      int16_t hCos;
      int16_t hSin;
    } Trig_Components;
    
    typedef struct
    {
      int16_t alpha;
      int16_t beta;
    } alphabeta_t;
    
    typedef struct
    {
      int16_t q;
      int16_t d;
    } qd_t;
    
    __weak qd_t MCM_Park( alphabeta_t Input, int16_t Theta )
    {
      qd_t Output;
      int32_t d_tmp_1, d_tmp_2, q_tmp_1, q_tmp_2;
      Trig_Components Local_Vector_Components;
      int32_t wqd_tmp;
      int16_t hqd_tmp;
    
      // 传入theta 查表计算得到 cos和sin的值
      Local_Vector_Components = MCM_Trig_Functions( Theta );
    
      // 不保证溢出,先计算一次,然后各种限幅判断,最后再做IQ的赋值
      /*No overflow guaranteed*/
      // 计算 alpha*cos(theta)
      q_tmp_1 = Input.alpha * ( int32_t )Local_Vector_Components.hCos;
    
      /*No overflow guaranteed*/
      // 计算 beta*sin(theta)
      q_tmp_2 = Input.beta * ( int32_t )Local_Vector_Components.hSin;
    
      /*Iq component in Q1.15 Format */
    #ifdef FULL_MISRA_C_COMPLIANCY
      wqd_tmp = ( q_tmp_1 - q_tmp_2 ) / 32768;
    #else
      /* WARNING: the below instruction is not MISRA compliant, user should verify
        that Cortex-M3 assembly instruction ASR (arithmetic shift right) is used by
        the compiler to perform the shift (instead of LSR logical shift right) */
        
      // IQ的计算,计算完了,去各种限幅。 右移15是sin和cos/32768得到真正的值,又回到16位以内
      wqd_tmp = ( q_tmp_1 - q_tmp_2 ) >> 15;
    #endif
    
      /* Check saturation of Iq */
      if ( wqd_tmp > INT16_MAX )
        hqd_tmp = INT16_MAX;
      else if ( wqd_tmp < ( -32768 ) )
        hqd_tmp = ( -32768 );
      else
        hqd_tmp = ( int16_t )( wqd_tmp );
    
      Output.q = hqd_tmp;
    
      if ( Output.q == ( int16_t )( -32768 ) )
      {
        Output.q = -32767;
      }
    
      /*No overflow guaranteed*/
      d_tmp_1 = Input.alpha * ( int32_t )Local_Vector_Components.hSin;
    
      /*No overflow guaranteed*/
      d_tmp_2 = Input.beta * ( int32_t )Local_Vector_Components.hCos;
    
      /*Id component in Q1.15 Format */
    #ifdef FULL_MISRA_C_COMPLIANCY
      wqd_tmp = ( d_tmp_1 + d_tmp_2 ) / 32768;
    #else
      /* WARNING: the below instruction is not MISRA compliant, user should verify
        that Cortex-M3 assembly instruction ASR (arithmetic shift right) is used by
        the compiler to perform the shift (instead of LSR logical shift right) */
      wqd_tmp = ( d_tmp_1 + d_tmp_2 ) >> 15;
    #endif
    
      /* Check saturation of Id */
      if ( wqd_tmp > INT16_MAX )
      {
        hqd_tmp = INT16_MAX;
      }
      else if ( wqd_tmp < ( -32768 ) )
      {
        hqd_tmp = ( -32768 );
      }
      else
      {
        hqd_tmp = ( int16_t )( wqd_tmp );
      }
    
      Output.d = hqd_tmp;
    
      if ( Output.d == ( int16_t )( -32768 ) )
      {
        Output.d = -32767;
      }
    
      return ( Output );
    }
    

    参考:
    TI DMC MATH_13.1pdf
    STM32 FOC 软件培训库pdf

    展开全文
  • TI旋转电机解决方案

    2011-08-05 08:26:29
    凭借自身在高级电机驱动和控制领域的深厚历史积淀与门类宽泛的模拟和微控制器产品, 可提供完整的电机系统解决方案
  • 上一节给大家分享几篇比较好介绍无刷电机无传感控制文章,不知大家学习得怎么样,其实很多芯片公司(比如TI,ST,MICROCHIP,SILICON)都有推出针对他们家控制或驱动芯片无感无刷电机控制软硬件方案(软硬件),...
  • 如何使用步进电机驱动板实现位置控制与步进电机驱动,怎样实现位置跟随控制?...使用TI的DRV8841,2.5A双路H桥电机驱动器,使用较少的外围元件即可驱动两个直流电机或一个双极步进电机。驱动器自带恒流电路...
  • 数字电机控制 (DMC) 使用 TI IQ 数学,这个支持定点和浮点数学运算。 这使得浮点至定点器件迁移变得十分容易。 这份应用报告涵盖了以下内容: • 磁场定向电机控制原理理论背景 • 基于模块化软件块...
  • 使用TI LAUNCHXL-F28069M,BOOSTXL-DRV8301逆变器和2个PMS电机的磁场定向控制 本示例说明如何使用闭环磁场定向控制(FOC)算法来调节2个三相永磁同步电动机(PMSM)速度和转矩。此示例使用了针对Texas ...
  • TI 335 永磁同步电机 PMSM FOC 矢量控制算法调试流程

    千次阅读 多人点赞 2018-12-26 15:45:10
    矢量控制又称磁场导向控制(Field Oriented ...TI提供了一个用于支持各种电机控制算法DMC,其中包含很多矢量控制中用得到功能模块,与之配套还有一份调试指南: Sensored Field Oriented Control of 3-P...
  • 本文将给大家介绍基于 TI C2000:trade_mark: 微控制器 3.3KW 车载充电机方案。此参考设计使用 C2000:trade_mark: 微控制器 (MCU) 和 LMG3410 来控制交错式连续导通模式 (CCM) 图腾柱 (TTPL) 无桥功率因数校正 ...
  • 电机控制系列文章 感应(异步)电机磁场定向控制MATLAB/Simulink建模 感应(异步)电机磁场定向控制电流环PI控制参数设计 ...在TI的controlSUITE里提供了一个叫digital motor control library的,路径
  • 关于TI公司TMS320LF2812电机控制软件方面资料
  • 基于DSP28335的三相异步电机开环V/F控制程序,主体部分使用TI的DMC中的函数,仿真调试无报错,完整工程,可直接烧写到dsp当中在线调试
  • controlSUITE 软件除免费软件产品系列常见简单演示之外,还可提供能够作为真正开发系统使用全面开源项目 —— 与示例,实现诸如电机控制等应用。此外,全新安装程序还可消除版本与依赖性等问题,使开发人员...
  • controlSUITE 软件除软件产品系列常见简单演示之外,还可提供能够作为真正开发系统使用全面开源项目 —— 与示例,实现诸如电机控制等应用。此外,全新安装程序还可消除版本与依赖性等问题,使开发人员能够在...
  • 从分析电机的等效电路,到列出其动平衡方程拉普拉斯变换。在Matlab下搭建电机模型,来调试三环PI参数的仿真调试的过程。...PI控制环部分使用的是增量式的差分方程,具体代码实现可以参考TI的库文件。
  • 过去这几年,越来越多的MCU集成了硬件的浮点运算单元,比如TI的DSP/CLA,ARM的Cortex-M4F内核等。 下面这篇文章是瑞萨的RX V2内核中集成FPU的说明,有针对电机控制常用数学运算的对比数据,也系统阐述...
  • 机器人开发过程中,对于直流电机来说,编码器至关重要,它不仅可以使我们对电极进行精确速度闭环,位置闭环,还可以通过时间积分,根据运动学关系,获得速度、位置等信息 STM32定时器有编码器模式,大大方便...
  • TI DSP MCU C2000 MSP430 & CORTEX-M3 大奖赛设计WORD论文文档+硬件设计文件+软件源码(50例合集): 430低功耗应用_智能护眼台灯 lm3s811学习套件 msp430f149学习板 MSP430F1XX单片机开发板 Real tom SmartPack...
  • HAL AB相编码器

    2021-02-24 16:27:46
    用到硬件:光电式编码器、F411RE NUCLEO板、电机 一、操作思路 1、 启用TIM5Encoder Mode 2、 启用TIM 10用作定时器,定时读取 3、 启用串口UART 2,将读取数据发送至PC 二、操作过程 启用TIM5Encoder ...
  • C 28x ---FFT变换解析

    2014-07-10 17:23:13
    用于 C2000TM 微处理器 controlSUITETM 是一套全面软件基础设施和软件工具集,旨在最大程度地缩短... TI公司C28x+FPU架构以其高速数据处理能力和简单易用编程方法,必将成为后续高性能电机控制发展趋势之
  • 工程文件及代码,语言C,使用TI 电机控制,可用CCS4.0以上版本直接打开,来源为TI的电机开发套件。 此工程针对永磁同步电机(PMSM)在无传感器的情况下进行的电机控制,PWM输出实现正弦波形,原理为磁场定向控制...
  • TI针对电机控制一个软件,好不容易才能在下载到,分享给大家,功能有点类似coutrolsuit,但是在结合高版本matlab自动代码生成时有用到

空空如也

空空如也

1 2
收藏数 35
精华内容 14
关键字:

ti的电机库