3. 空间矢量调制(SVPWM):从原理到实现
好,咱们进入FOC算法中最核心、也最考验功力的部分——SVPWM。
说实话,我刚接触FOC那会儿,看到SVPWM的矢量图和扇区判断,头都是大的。但后来在项目里调了无数次波形,才真正理解它的妙处。今天我就把压箱底的经验掏出来,跟你聊聊SVPWM到底是怎么回事。
3.1 SVPWM的基本原理
SVPWM,全称是Space Vector Pulse Width Modulation。说白了,就是通过控制六个功率管的开关状态,在电机定子上合成一个旋转的电压矢量。
你可能会问:为什么要搞这么复杂?直接正弦波PWM不行吗?
嗯,正弦波PWM确实能用,但直流母线电压利用率低,只有约86.6%。而SVPWM可以做到100%的直流母线电压利用率。我在一个伺服驱动器项目里实测过,同样的母线电压,SVPWM比正弦波PWM多输出约15%的转矩。这个差距,在需要高功率密度的场合,就是天壤之别。
核心思想: 用8个基本电压矢量(6个非零矢量+2个零矢量)去合成任意方向和幅值的电压矢量。
这8个矢量怎么来的?三相逆变器有6个开关管,上管导通为1,下管导通为0。三个桥臂的状态组合起来,就是8种状态:
- U1(100)、U2(110)、U3(010)、U4(011)、U5(001)、U6(101) —— 6个非零矢量
- U0(000)、U7(111) —— 2个零矢量
这6个非零矢量在空间上互差60°,把整个平面分成6个扇区。我们要合成的目标电压矢量,就落在这6个扇区中的某一个里。
3.2 扇区判断:第一步定位
拿到目标电压矢量Uref后,第一件事就是判断它在哪个扇区。我见过不少新手在这里栽跟头,其实方法很固定。
我们通常用Uα和Uβ(经过Clark变换后的两相静止坐标系分量)来判断。具体做法是定义三个中间变量:
B1 = Uβ
B2 = (√3/2)*Uα - (1/2)*Uβ
B3 = -(√3/2)*Uα - (1/2)*Uβ
然后根据B1、B2、B3的符号,查表得到扇区号:
| B1 | B2 | B3 | 扇区 |
|---|---|---|---|
| >0 | >0 | <0 | I |
| >0 | <0 | <0 | II |
| >0 | <0 | >0 | III |
| <0 | <0 | >0 | IV |
| <0 | >0 | >0 | V |
| <0 | >0 | <0 | VI |
我的小技巧: 实际代码里,我习惯用查表法而不是if-else链。把B1、B2、B3的符号位拼成一个3位数,直接索引数组。这样代码更简洁,执行也快。
3.3 作用时间计算:核心公式
扇区确定后,就要算两个相邻非零矢量和零矢量的作用时间了。这里我直接给结论,推导过程你可以参考任何一本电力电子教材。
先定义三个通用变量X、Y、Z:
X = (√3 * T_s * Uβ) / U_dc
Y = (√3 * T_s * ( (√3/2)*Uα + (1/2)*Uβ )) / U_dc
Z = (√3 * T_s * ( -(√3/2)*Uα + (1/2)*Uβ )) / U_dc
其中T_s是PWM周期,U_dc是直流母线电压。
然后根据扇区,查表得到T1和T2:
| 扇区 | T1 | T2 |
|---|---|---|
| I | Z | Y |
| II | Y | -X |
| III | -Z | X |
| IV | -X | Z |
| V | X | -Y |
| VI | -Y | -Z |
零矢量时间T0 = T_s - T1 - T2。如果T1+T2 > T_s,说明进入了过调制区,需要等比例缩小T1和T2。
我曾经踩过的坑: 有一次在高速电机项目里,没处理好过调制的情况,结果电流波形畸变得一塌糊涂,电机嗡嗡响。后来加了饱和处理,问题才解决。记住,T1+T2绝对不能超过T_s,否则逆变器会输出错误电压。
3.4 七段式SVPWM实现
七段式,顾名思义,一个PWM周期被分成7段。它的特点是:每次切换只改变一个桥臂的状态,开关损耗小,谐波特性好。
以扇区I为例,矢量顺序是:U0(000) → U1(100) → U2(110) → U7(111) → U2(110) → U1(100) → U0(000)
各相占空比的计算公式:
Ta = (T_s - T1 - T2) / 4
Tb = Ta + T1/2
Tc = Tb + T2/2
然后根据扇区,把Ta、Tb、Tc分配给A、B、C三相:
| 扇区 | A相 | B相 | C相 |
|---|---|---|---|
| I | Ta | Tb | Tc |
| II | Tb | Ta | Tc |
| III | Tc | Ta | Tb |
| IV | Tc | Tb | Ta |
| V | Tb | Tc | Ta |
| VI | Ta | Tc | Tb |
代码实现时,我习惯用查表法,把每个扇区的分配关系存成数组,运行时直接索引。这样代码量小,也容易维护。
3.5 五段式SVPWM实现
五段式,也叫DPWM(不连续PWM)。它在一个周期内只插入一次零矢量,所以只有5段。优点是开关次数更少,开关损耗能降低约30%。
但代价是谐波含量比七段式大。我个人建议:在需要高效率的场合(比如电动汽车),用五段式;在要求电流波形平滑的场合(比如精密伺服),用七段式。
五段式的矢量顺序有两种变体:
- 方式一: 只使用U0作为零矢量,顺序为U0 → U1 → U2 → U2 → U1 → U0
- 方式二: 只使用U7作为零矢量,顺序为U7 → U2 → U1 → U1 → U2 → U7
占空比计算和七段式类似,但零矢量时间分配不同。以方式一为例:
Ta = 0
Tb = T1/2
Tc = T1/2 + T2/2
然后同样根据扇区查表分配。
我的经验: 五段式的零矢量选择会影响电流过零点的畸变。我一般会在软件里做个配置项,让用户根据实际工况选择U0还是U7。有些高端驱动器甚至会根据负载情况动态切换。
3.6 七段式 vs 五段式:怎么选?
我整理了一个对比表,方便你决策:
| 对比项 | 七段式 | 五段式 |
|---|---|---|
| 开关次数/周期 | 6次 | 4次 |
| 开关损耗 | 较高 | 低约30% |
| 谐波特性 | 好 | 较差 |
| 电流纹波 | 小 | 大 |
| 适用场景 | 精密控制、低噪声 | 高效率、大功率 |
嗯,其实没有绝对的好坏。我在一个风机项目里,为了把效率从92%提到95%,硬是花了两个星期调五段式的参数。最后效率确实上去了,但噪声也大了3dB。这就是取舍。
3.7 代码实现要点
最后,给你一个七段式SVPWM的代码骨架,我用的是C语言风格:
void svpwm_calc(float Ualpha, float Ubeta, float *Ta, float *Tb, float *Tc)
{
// 1. 扇区判断
float B1 = Ubeta;
float B2 = 0.866f * Ualpha - 0.5f * Ubeta;
float B3 = -0.866f * Ualpha - 0.5f * Ubeta;
int sector = 0;
if (B1 > 0) sector |= 1;
if (B2 > 0) sector |= 2;
if (B3 > 0) sector |= 4;
// 2. 计算X、Y、Z
float X = 1.732f * T_s * Ubeta / U_dc;
float Y = 1.732f * T_s * (0.866f*Ualpha + 0.5f*Ubeta) / U_dc;
float Z = 1.732f * T_s * (-0.866f*Ualpha + 0.5f*Ubeta) / U_dc;
// 3. 查表得T1、T2
float T1, T2;
// ... 根据sector查表 ...
// 4. 过调制处理
if (T1 + T2 > T_s) {
float scale = T_s / (T1 + T2);
T1 *= scale;
T2 *= scale;
}
// 5. 计算占空比
float Ta = (T_s - T1 - T2) * 0.25f;
float Tb = Ta + T1 * 0.5f;
float Tc = Tb + T2 * 0.5f;
// 6. 扇区分配
// ... 根据sector查表分配Ta、Tb、Tc到三相 ...
}
注意,实际工程中,浮点运算要尽量转成定点数,或者用查表法加速。我在STM32F4上跑过,纯浮点版本一个SVPWM计算大约要2μs,优化后能压到0.5μs以内。
好了,SVPWM的核心内容就这些。下一章我们聊聊电流环的PI参数整定,那又是一个让人头秃的话题。不过别怕,跟着我一步步来,你也能成为FOC高手。