无刷直流电机反电动势过零检测_TI电机库源码

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

1.位置信息

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

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

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

2.无感的方法

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

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

3.反电动势过零检测

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

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

3.2缺点:

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

3.3硬件电路

无刷直流电机反电动势过零检测_TI电机库源码_第1张图片
反电动势图:
无刷直流电机反电动势过零检测_TI电机库源码_第2张图片
正向反电动势过零点变化:

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

3.4电路计算:

无刷直流电机反电动势过零检测_TI电机库源码_第3张图片
可以直接得到电机端的电压方程:
{ U A = R i A + L d i A d t + e A + U N U B = R i B + L d i B d t + e B + U N U C = R i C + L d i C d t + e C + U N ① \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. ① UA=RiA+LdtdiA+eA+UNUB=RiB+LdtdiB+eB+UNUC=RiC+LdtdiC+eC+UN

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

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


被抛弃的写随笔公众号改写技术文章了,感兴趣的可以关注公众号:王崇卫
在这里插入图片描述

你可能感兴趣的:(电机,反电动势过零检测,无刷电机,TI电机库,无刷电机无感)