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高手。