赞
踩
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
今天同步一下微信公众号的内容。上次介绍了坐标变换(Clarke,Park)的原理和软件代码实现,时隔两个多月,我们接着分享FOC电机控制相关的经验,这次我们介绍SVPWM的原理和软件代码实现…
SVPWM(Space Vector Pulse Width Modulation),即空间矢量脉宽调制。SVPWM的理论基础是平均值等效原理,即在一个开关周期Ts内,对基本矢量电压加以组合,使其平均值与给定电压矢量相等。通过控制基本矢量电压的作用时间,使合成的目标矢量电压在空间位置按照接近圆形轨迹旋转,所产生的实际磁通去逼近一个理想的磁通圆。模型如下图所示,采样点数越多,就越逼近理想磁通圆,理论上采样点数无穷多时就是理想磁通圆了。
左图:基本电压矢量图; 右图:实际磁通圆轨迹示意图
加在三相绕组线圈上的端电压都为正弦电压,设峰值为Um,两两相位差120°,记为:
U
A
(
t
)
=
U
m
cos
θ
U
B
(
t
)
=
U
m
cos
(
θ
−
2
3
π
)
U
C
(
t
)
=
U
m
cos
(
θ
−
4
3
π
)
=
U
m
cos
(
θ
+
2
3
π
)
注意:这里的电压是标量,只是电压幅值按正弦变化。
在二维平面上,三相绕组ABC构成的坐标系,两两坐标轴相差120°,则三相基本电压用矢量表示为:
u
A
(
t
)
=
U
A
(
t
)
⋅
e
j
0
=
U
m
cos
θ
⋅
e
j
0
u
B
(
t
)
=
U
B
(
t
)
⋅
e
j
2
3
π
=
U
m
cos
(
θ
−
2
3
π
)
⋅
e
j
2
3
π
u
C
(
t
)
=
U
C
(
t
)
⋅
e
j
4
3
π
=
U
m
cos
(
θ
+
2
3
π
)
⋅
e
j
4
3
π
用欧拉公式
e
i
x
=
cos
x
+
i
sin
x
;
e
−
i
x
=
cos
x
−
i
sin
x
;
cos
x
=
1
2
(
e
i
x
+
e
−
i
x
)
{e^{ix}} = \cos x + i\sin x;{e^{ - ix}} = \cos x - i\sin x;\cos x = \frac{1}{2}({e^{ix}} + {e^{ - ix}})
eix=cosx+isinx;e−ix=cosx−isinx;cosx=21(eix+e−ix)展开上式,并计算其矢量和:
u
s
=
u
A
+
u
B
+
u
C
{\boldsymbol{u}_s} = {\boldsymbol{u}_A} + {\boldsymbol{u}_B} + {\boldsymbol{u}_C}
us=uA+uB+uC
下面是展开计算的过程:
在计算过程中用到了三角函数的展开公式:
cos
(
α
+
β
)
=
cos
α
cos
β
−
sin
α
sin
β
cos
(
α
−
β
)
=
cos
α
cos
β
+
sin
α
sin
β
原理总结:
通过在空间位置上两两相差120°的三个基本电压来合成目标电压。三个基本电压的方向不变,幅值按正弦规律变化,相位两两相差120°;合成的目标矢量电压其幅值固定不变,为相电压峰值的1.5倍,方向在空间旋转,旋转的角速度等于相电压幅值变化的角速度。
如下图所示,逆变器的三相桥臂共有6个开关管(Q1,Q2,Q3,Q4,Q5,Q6),对于每一个半桥,同一时刻只能有一个开关管导通,即控制信号G1和G2反相,G3和G4反相,G5和G6反相,如果同一个半桥的上下桥臂同时导通则会导致电源Udc短路。逆变器三个半桥的输出分别加到电机的ABC三相绕上,三相绕组在空间位置上两两相差120°。
定义开关函数
如S(A)=1表示Q1导通Q2截止,母线电压Udc加到A相绕组;
再比如S(B)=1表示Q3截止Q4导通,B相绕组连接到电源负极,即GND。
ABC三个开关函数的状态(S(A),S(B),S©)共有8种组合,分别是{(0,0,0),(0,0,1),(0,1,0),(0,1,1),(1,0,0),(1,0,1),(1,1,0),(1,1,1),},分别对应8个矢量电压,其中2个零矢量电压是 U 0 ( 0 , 0 , 0 ) {U_0}(0,0,0) U0(0,0,0)和 U 7 ( 1 , 1 , 1 ) {U_7}(1,1,1) U7(1,1,1),6个非零矢量电压分别是 U 1 ( 0 , 0 , 1 ) , U 2 ( 0 , 1 , 0 ) , U 3 ( 0 , 1 , 1 ) , U 4 ( 1 , 0 , 0 ) , U 5 ( 1 , 0 , 1 ) , U 6 ( 1 , 1 , 0 ) {U_1}(0,0,1),{U_2}(0,1,0),{U_3}(0,1,1),{U_4}(1,0,0),{U_5}(1,0,1),{U_6}(1,1,0) U1(0,0,1),U2(0,1,0),U3(0,1,1),U4(1,0,0),U5(1,0,1),U6(1,1,0),它们在空间位置上相邻间隔60°,将平面等分为6个扇区。
以三相绕组的公共端N点作为参考零电位,各基本矢量电压的方向如上图所示,在三相坐标系下,这6个非零基本矢量电压的幅值为Udc,具体如下表所示。
容易想到,通过控制开关管的状态,可以合成6个方向中任意一个方向的矢量电压;通过控制该状态下开关管的PWM占空比,可以改变该方向的矢量电压的幅值的有效值(占空比从0到100%对应矢量电压有效值从0到Udc)。比如要合成一个方向和U4相同,幅值为Udc/2的矢量电压,只需要控制G1的占空比为50%,G3,G5的占空比为0%即可;再比如要合成一个方向和U6相同,幅值为3Udc/4的矢量电压,只需要控制G1,G3的占空比为75%,G5的占空比为0%即可。
在三相坐标系下,6个基本矢量电压的幅值都为Udc,转换到αβ两相坐标系下,基本矢量电压的幅值为2*Udc/3(为什么是2/3倍这个问题困扰了我好久才弄清楚了,下面简单说明一下)。
以基本矢量电压U1为例,U1(001)在abc三相坐标系下的幅值为Udc,他由
U
a
=
−
1
3
U
d
c
,
U
b
=
−
1
3
U
d
c
,
U
c
=
2
3
U
d
c
{U_a} = - \frac{1}{3}{U_{dc}},{U_b} = - \frac{1}{3}{U_{dc}},{U_c} = \frac{2}{3}{U_{dc}}
Ua=−31Udc,Ub=−31Udc,Uc=32Udc合成。经过clarke变换,得到在αβ两相坐标系下的电压
[
U
α
U
β
]
=
2
3
[
1
−
1
2
−
1
2
0
3
2
−
3
2
]
⋅
[
U
a
U
b
U
c
]
=
[
−
1
3
U
d
c
−
3
3
U
d
c
]
\left[ {
下面的介绍都是在两相坐标系下的,注意!
经过上面的步骤,已经能合成6个方向,幅值为0 ~ 2Udc/3的基本矢量电压了。接下来我们用这6个基本的矢量电压,合成一个任意方向0-360°,任意幅值0~Umax的矢量电压,即我们最终的目标矢量电压,下面计算Umax的值。
容易知道,通过这6个基本矢量电压,能够合成的最大旋转圆形目标电压,其幅值为正六边形的内切圆的半径,即
U
max
=
3
2
⋅
2
3
U
d
c
=
3
3
U
d
c
{U_{\max }} = \frac{{\sqrt 3 }}{2} \cdot \frac{2}{3}{U_{dc}} = \frac{{\sqrt 3 }}{3}{U_{dc}}
Umax=23
⋅32Udc=33
Udc
回顾一下数学知识:在一个平面内,两个不共线的非零向量可以作为一个基底,两个基底的线性组合可以合成该平面内任意方向和任意大小的第三个向量。(不懂没关系,看下面就够了)
容易想到,任意一个目标电压矢量,可以由该矢量所在扇区的相邻两个基本矢量电压合成。比如扇区I的任意矢量电压Us都可以由相邻的U4和U6两个基本矢量电压合成。
这里的Us就是坐标变换里的Uq和Ud的矢量和,(PS:在电机控制应用中,Uq由q轴电流环PI控制器计算输出得到,同时d轴电流环还会计算输出得到一个Ud,Ud滞后Uq90°)
然后回到坐标变换去了,另一篇文章有详细讲解[另一篇文章的链接],这里只简单说明结果。
先是park逆变换,由期望输出的Uq,Ud和当前的空间位置即角度θ[在电机控制里面这里是指电角度,并不是旋转平面的角度(后面讲电角度、电机极对数和旋转角度的关系)],通过park逆变换计算Uα,Uβ。
[
U
α
U
β
]
=
[
cos
θ
−
sin
θ
sin
θ
cos
θ
]
⋅
[
U
d
U
q
]
\left[ {
得到Uα,Uβ后,接着就是判断所在扇区
目标矢量电压Uref就是PI控制器计算的输出Uq,Ud的矢量和,经过Park逆变换得到Uα和Uβ,空间矢量调制的第一步,就是由Uα和Uβ判断目标空间矢量电压所处的扇区。
由以上矢量图几何关系分析可以得到,所在扇区和需要满足的充分必要条件列表:
可以看出,决定扇区的基本变量有:
U
α
,
U
β
,
U
β
−
3
U
α
,
−
U
β
−
3
U
α
,
U
β
−
3
∣
U
α
∣
,
−
U
β
−
3
∣
U
α
∣
{U_\alpha },{U_\beta },{U_\beta } - \sqrt 3 {U_\alpha }, - {U_\beta } - \sqrt 3 {U_\alpha },{U_\beta } - \sqrt 3 \left| {{U_\alpha }} \right|, - {U_\beta } - \sqrt 3 \left| {{U_\alpha }} \right|
Uα,Uβ,Uβ−3
Uα,−Uβ−3
Uα,Uβ−3
∣Uα∣,−Uβ−3
∣Uα∣,其中线性无关的只有三个(也可以取其他三个线性无关的):
U
β
,
U
β
−
3
U
α
,
−
U
β
−
3
U
α
{U_\beta },{U_\beta } - \sqrt 3 {U_\alpha }, - {U_\beta } - \sqrt 3 {U_\alpha }
Uβ,Uβ−3
Uα,−Uβ−3
Uα
取
{
U
1
=
U
β
U
2
=
1
2
(
−
U
β
+
3
U
α
)
U
3
=
1
2
(
−
U
β
−
3
U
α
)
则(A,B,C)有8种状态000,001,…………… ,111
其中(A,B,C)=(000)和(111)并不存在,另外6个状态对应6个扇区,下面做简单分析。
(A,B,C) =000时:
即U1<0,U2<0,U3<0,
即Uβ<0,由式2式3叠加得-Uβ<0,Uβ>0,和 式1冲突,故该状态不存在。
(A,B,C) =111时:
即U1>0,U2>0,U3>0,
即Uβ>0,由式2式3叠加得-Uβ>0,Uβ<0,和 式1冲突,故该状态不存在。
综上,可以列出(A,B,C)的值和所对应的扇区关系如下表;
然后在程序里里面查表,根据计算的N查找对应的扇区。
扇区判断结束后,就是计算相邻两个基本矢量电压的作用时间T1,T2。
到这里,计算出来的公式看着有点复杂,所以我们通过下面的方式稍稍简化一下,记:
{
K
=
3
T
s
U
d
c
U
x
=
U
β
U
y
=
3
2
U
α
−
1
2
U
β
U
z
=
3
2
U
α
+
1
2
U
β
到这里,合成目标矢量电压Uref需要的两个相邻矢量电压Ux,Uy以及分别作用的时间Tx,Ty就计算好了,但这里计算出来的时间不一定刚好满足
T
x
+
T
y
=
T
s
{T_x} + {T_y} = {T_s}
Tx+Ty=Ts,
当
T
x
+
T
y
>
T
s
{T_x} + {T_y}> {T_s}
Tx+Ty>Ts时需要进行等比例缩小处理,处理方式如下:
T
x
=
T
x
T
x
+
T
y
,
T
y
=
T
y
T
x
+
T
y
{T_x} = \frac{{{T_x}}}{{{T_x} + {T_y}}},{T_y} = \frac{{{T_y}}}{{{T_x} + {T_y}}}
Tx=Tx+TyTx,Ty=Tx+TyTy
当
T
x
+
T
y
<
T
s
{T_x} + {T_y} < {T_s}
Tx+Ty<Ts时,需要引入零矢量电压:
T
0
=
T
7
=
1
2
(
T
s
−
T
x
−
T
y
)
{T_0} = {T_7} = \frac{1}{2}({T_s} - {T_x} - {T_y})
T0=T7=21(Ts−Tx−Ty)
目标矢量电压的所在扇区知道了,相邻两个基本矢量电压及其作用时间也知道了,接下来就是7段式SVPWM的生成了。所谓的7段式SVPWM,即在一个周期Ts内,基本电压矢量的作用顺序为
U
0
→
U
x
→
U
y
→
U
7
→
U
y
→
U
x
→
U
0
{U_0} \to {U_x} \to {U_y} \to {U_7} \to {U_y} \to {U_x} \to {U_0}
U0→Ux→Uy→U7→Uy→Ux→U0
作用的时间分别为:
1
2
T
0
→
1
2
T
x
→
1
2
T
y
→
T
7
→
1
2
T
y
→
1
2
T
x
→
1
2
T
0
\frac{1}{2}{T_0} \to \frac{1}{2}{T_x} \to \frac{1}{2}{T_y} \to {T_7} \to \frac{1}{2}{T_y} \to \frac{1}{2}{T_x} \to \frac{1}{2}{T_0}
21T0→21Tx→21Ty→T7→21Ty→21Tx→21T0
以在第1扇区为例:基本电压矢量作用的顺序为
U
0
→
U
4
→
U
6
→
U
7
→
U
6
→
U
4
→
U
0
{U_0} \to {U_4} \to {U_6} \to {U_7} \to {U_6} \to {U_4} \to {U_0}
U0→U4→U6→U7→U6→U4→U0,对应的三相电压波形为:
这里,可能会问,Tx,Ty和U4,U6是怎么对应的呢?为什么要先U4再U6呢?把各个扇区的作用顺序竖着列出来就能看出来了:
可以看出,从一个扇区进入相邻的另一个扇区时,只有一个基本矢量电压发生改变。即通过这样的作用顺序,可以减小开关管的切换次数,从而减少开关损耗,尤其是在负载电流较大时更应该减小开关切换次数。
然后就是根据基本矢量电压的作用时间去计算逆变H桥的占空比了,
仍然先以第1扇区为例:基本矢量电压作用的顺序为
U
0
(
000
)
→
U
4
(
100
)
→
U
6
(
110
)
→
U
7
(
111
)
→
U
6
(
110
)
→
U
4
(
100
)
→
U
0
(
000
)
{U_0}(000) \to {U_4}(100) \to {U_6}(110) \to {U_7}(111) \to {U_6}(110) \to {U_4}(100) \to {U_0}(000)
U0(000)→U4(100)→U6(110)→U7(111)→U6(110)→U4(100)→U0(000)
即在一个周期Ts时间内,前面定义的开关函数
S(C)=1的时间为
T
c
=
T
7
=
1
2
(
T
s
−
T
4
−
T
6
)
{T_c} = {T_7} = \frac{1}{2}({T_s} - {T_4} - {T_6})
Tc=T7=21(Ts−T4−T6)
S(B)=1的时间为
T
b
=
T
7
+
T
6
=
T
c
+
T
6
{T_b} = {T_7} + {T_6} = {T_c} + {T_6}
Tb=T7+T6=Tc+T6
S(A)=1的时间为
T
a
=
T
7
+
T
6
+
T
4
=
T
b
+
T
4
{T_a} = {T_7} + {T_6} + {T_4} = {T_b} + {T_4}
Ta=T7+T6+T4=Tb+T4
对应的ABC三路PWM的占空比就分别为
T
a
T
s
,
T
b
T
s
,
T
c
T
s
\frac{{{T_a}}}{{{T_s}}},\frac{{{T_b}}}{{{T_s}}},\frac{{{T_c}}}{{{T_s}}}
TsTa,TsTb,TsTc。注意的是,看上面的三相电压波形可知,输出的PWM波时高电平中间对齐,所以在对你所使用的微控制器MCU的PWM定时器进行配置的时候要注意设置好计数方向(一般先向上计数在向下计数)和输出极性(超过阈值为高电平)。
对于其他几个扇区类似,这里不再重复详细叙述,列个表出来
这里说明一下,前面进行Clarke变换和park变换的所有电压电流参数都是标幺值,这里的Uα和Uβ采用的也是标幺值。
我们合成的输出目标矢量电压也用标幺值表示(令Uref_max=1),并令Ts=1时,这里的系数K就等于常数1,这样的话,我们计算的时间Ta,Tb,Tc就等于占空比。下面简单证明一下why。
仍以第1扇区为例:
已知最终的目标矢量电压最大不失真的幅值为
U
r
e
f
_
max
=
3
3
U
d
c
{U_{ref\_\max }} = \frac{{\sqrt 3 }}{3}{U_{dc}}
Uref_max=33
Udc,则
K
=
3
T
s
U
d
c
=
T
s
U
r
e
f
_
max
K = \frac{{\sqrt 3 {T_s}}}{{{U_{dc}}}} = \frac{{{T_s}}}{{{U_{ref\_\max }}}}
K=Udc3
Ts=Uref_maxTs
我们已经计算的有
{
T
4
=
K
⋅
U
y
T
6
=
K
⋅
U
x
令 U r e f _ max = 1 {U_{ref\_\max }} = 1 Uref_max=1把目标矢量电压标幺值化,再令Ts=1,就可以把非零电压作用的时间转化为标幺值。
所以,我们在程序计算处理的时候,直接令K=1,然后按照上面列表计算出来的Ta,Tb,Tc就可以直接作为占空比了,占空比再乘以PWM定时器的计数周期值,就可以得到比较寄存器的值了,这样计算量就减小很多了,然后就完成了整个SVPWM的操作。
剩下的就是PWM定时器相关的操作了,这里不详说,后面有时间我再针对DSP和STM32这两款处理器做简要介绍。
接着上一篇的坐标变换(上一篇链接:https://mp.weixin.qq.com/s/4PbY2FbnXcN2ai4aolGVcg)
上篇已经介绍,由park逆变换计算得到Uα,Uβ
计算
{
U
1
=
U
β
U
2
=
1
2
(
−
U
β
+
3
U
α
)
U
3
=
1
2
(
−
U
β
−
3
U
α
)
C语言代码示例:
v.U1 = v.Ubeta; \
v.U2 = ( v.Ualpha*0.8660254) - (v.Ubeta*0.5); \
v.U3 = (-v.Ualpha*0.8660254) - (v.Ubeta*0.5); \
v.Sector = 0; \
if(v.U1 > 0) v.Sector += 1; \
if(v.U2 > 0) v.Sector += 2; \
if(v.U3 > 0) v.Sector += 4; \
计算
{
U
x
=
U
β
U
y
=
3
2
U
α
−
1
2
U
β
U
z
=
3
2
U
α
+
1
2
U
β
C语言代码示例:
v.Tx = v.Ubeta; \ v.Ty = ( v.Ualpha*0.8660254) + (v.Ubeta*0.5); \ v.Tz = (-v.Ualpha*0.8660254) + (v.Ubeta*0.5); \ switch(v.Sector) \ { \ case 1:{ \ v.t1=v.Tz; v.t2=v.Ty; \ if((v.t1+v.t2)>1){ \ v.t1 = v.t1/(v.t1+v.t2); \ v.t2 = v.t2/(v.t1+v.t2); \ } \ v.Tb = 0.5*(1-v.t1-v.t2); \ v.Ta = v.Tb + v.t1; \ v.Tc = v.Ta + v.t2;}break; \ case 2:{ \ v.t1=v.Ty; v.t2=-v.Tx; \ if((v.t1+v.t2)>1){ \ v.t1 = v.t1/(v.t1+v.t2); \ v.t2 = v.t2/(v.t1+v.t2); \ } \ v.Ta = 0.5*(1-v.t1-v.t2); \ v.Tc = v.Ta + v.t1; \ v.Tb = v.Tc + v.t2;}break; \ case 3:{ \ v.t1=-v.Tz; v.t2=v.Tx; \ if((v.t1+v.t2)>1){ \ v.t1 = v.t1/(v.t1+v.t2); \ v.t2 = v.t2/(v.t1+v.t2); \ } \ v.Ta = 0.5*(1-v.t1-v.t2); \ v.Tb = v.Ta + v.t1; \ v.Tc = v.Tb + v.t2;}break; \ case 4:{ \ v.t1=-v.Tx; v.t2=v.Tz; \ if((v.t1+v.t2)>1){ \ v.t1 = v.t1/(v.t1+v.t2); \ v.t2 = v.t2/(v.t1+v.t2); \ } \ v.Tc = 0.5*(1-v.t1-v.t2); \ v.Tb = v.Tc + v.t1; \ v.Ta = v.Tb + v.t2;}break; \ case 5:{ \ v.t1=v.Tx; v.t2=-v.Ty; \ if((v.t1+v.t2)>1){ \ v.t1 = v.t1/(v.t1+v.t2); \ v.t2 = v.t2/(v.t1+v.t2); \ } \ v.Tb = 0.5*(1-v.t1-v.t2); \ v.Tc = v.Tb + v.t1; \ v.Ta = v.Tc + v.t2;}break; \ case 6:{ \ v.t1=-v.Ty; v.t2=-v.Tz; \ if((v.t1+v.t2)>1){ \ v.t1 = v.t1/(v.t1+v.t2); \ v.t2 = v.t2/(v.t1+v.t2); \ } \ v.Tc = 0.5*(1-v.t1-v.t2); \ v.Ta = v.Tc + v.t1; \ v.Tb = v.Ta + v.t2;}break; \
这个很简单,就是用占空比乘以定时器的计数周期
C语言代码如下:
EPwm1Regs.CMPA.half.CMPA = (int16)(MPeriod * Svpwm1.Ta);
EPwm2Regs.CMPA.half.CMPA = (int16)(MPeriod * Svpwm1.Tb);
EPwm3Regs.CMPA.half.CMPA = (int16)(MPeriod * Svpwm1.Tc);
tips:由于这篇文章用到的公式有点多,而公众号的文章编辑器又不支持插入公式,无奈我只能插入图片了,所以看起来排版不是很协调。感兴趣的可以留言或私信,分享PDF源文档哦。
(附上我整理的笔记链接:https://download.csdn.net/download/weixin_42887190/85812369)
最后,推销一下自己,关注一下我的微信公众号,可以更及时的收到在下的分享哦。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。