无刷直流电机反电动势过零检测_TI电机库源码
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电路计算:
可以直接得到电机端的电压方程:
{
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=UC−21(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=UA−21(UC+UB)eB=UB−21(UA+UC)eC=UC−21(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=3UA−3UN3eB=3UB−3UN3eC=3UC−3UN
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
被抛弃的写随笔公众号改写技术文章了,感兴趣的可以关注公众号:王崇卫
![Logo](https://devpress.csdnimg.cn/79de2bf0b7994defa4242ef90d5513fa.jpg)
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)