3. 扇区判断与作用时间:参考电压矢量扇区判断、相邻矢量作用时间计算、零矢量分配策略
好,咱们进入SVPWM最核心的实操环节。前面讲了基本原理,现在要解决一个实际问题:给定一个目标电压矢量,我怎么知道它在哪个扇区?该用哪两个基本矢量去合成?每个矢量要作用多久?零矢量又该怎么插进去?
这些问题,说白了就是SVPWM的“调度算法”。我在调试第一版SVPWM代码时,就是在这块栽了跟头——扇区判断写错了,电机转起来嗡嗡响,电流波形跟锯齿似的。后来老老实实把逻辑理清楚,才搞定。
3.1 扇区判断:三值逻辑的妙用
拿到Vα和Vβ后,第一步就是判断目标矢量落在哪个扇区。你可能会想,是不是要用反正切算角度?千万别!嵌入式里算atan2太慢了,而且没必要。
我习惯用三值逻辑法,只需要三个中间变量:
// 定义三个中间变量
float B1 = Vbeta;
float B2 = 0.866f * Valpha - 0.5f * Vbeta; // sqrt(3)/2 ≈ 0.866
float B3 = -0.866f * Valpha - 0.5f * Vbeta;
// 判断正负,得到三个标志位
uint8_t A = (B1 > 0) ? 1 : 0;
uint8_t B = (B2 > 0) ? 1 : 0;
uint8_t C = (B3 > 0) ? 1 : 0;
// 合成扇区号
uint8_t sector = A + (B << 1) + (C << 2);
为什么这么算?你看,B1对应Vβ的正负,B2和B3其实是把Vα和Vβ投影到另外两个60°轴线上。三个比较器的结果组合起来,正好能唯一确定6个扇区。
sector = (sector == 0) ? 6 : sector;。
扇区判断的流程图如下,你可以对照代码理解:
3.2 相邻矢量作用时间计算
扇区判断完了,接下来就是算时间。每个扇区里,目标矢量由两个相邻的基本矢量合成。比如扇区I,用U4(100)和U6(110)。
时间计算的核心公式其实就一个——伏秒平衡:
Vref * Ts = Tx * Ux + Ty * Uy + T0 * U0
其中Tx和Ty是两个相邻矢量的作用时间,T0是零矢量时间。我习惯先把Tx和Ty算出来,再拿T0 = Ts - Tx - Ty。
实际代码里,我不会每个扇区都写一遍公式。那样太啰嗦,而且容易写错。我一般用查表法,先算三个通用时间:
float X = sqrt3 * Vbeta * Ts / Vdc;
float Y = (1.5f * Valpha + 0.866f * Vbeta) * Ts / Vdc;
float Z = (-1.5f * Valpha + 0.866f * Vbeta) * Ts / Vdc;
然后根据扇区号查表:
| 扇区 | Tx | Ty |
|---|---|---|
| I | Z | Y |
| II | Y | -X |
| III | -Z | X |
| IV | -X | Z |
| V | X | -Y |
| VI | -Y | -Z |
Tx = Tx * Ts / (Tx+Ty),Ty = Ty * Ts / (Tx+Ty),零矢量时间 T0 直接置 0。我遇到过有人忘了做限幅,结果电流波形直接崩了。
3.3 零矢量分配策略
时间算完了,还有个关键问题:零矢量怎么放?
零矢量有两个:U0(000)和U7(111)。不同的分配方式,直接影响谐波含量和开关损耗。
我常用的策略有三种:
- 七段式SVPWM: 零矢量在中间和两边各放一半,
U0和U7各占T0/2。谐波性能最好,但开关次数多。 - 五段式SVPWM: 只用一个零矢量,比如只用
U7。开关次数减少1/3,适合对损耗敏感的场景。 - 交替零矢量: 在相邻周期交替使用
U0和U7。谐波性能接近七段式,但实现稍复杂。
我个人最常用七段式,因为谐波特性好,电机运行更平稳。下面是七段式的开关序列示例(扇区I):
// 扇区I:U0(000) → U4(100) → U6(110) → U7(111) → U6(110) → U4(100) → U0(000)
// 各段时间分配:
// T0/4 | Tx/2 | Ty/2 | T0/2 | Ty/2 | Tx/2 | T0/4
// 计算三相占空比
float Ta = (Ts - Tx - Ty) / 4.0f; // A相先导时间
float Tb = Ta + Tx / 2.0f; // B相
float Tc = Tb + Ty / 2.0f; // C相
// 根据扇区映射到实际三相
switch(sector) {
case 1: // 扇区I
dutyA = Tb; dutyB = Ta; dutyC = Tc; break;
case 2: // 扇区II
dutyA = Ta; dutyB = Tc; dutyC = Tb; break;
// ... 其他扇区类似
}
嗯,到这里,扇区判断、时间计算、零矢量分配这三步就走通了。你想想看,整个SVPWM的调度逻辑,其实就是这三板斧。代码写起来也就几十行,但每一步都有坑。我当年在零矢量分配上纠结了好几天,后来发现是占空比映射表写错了——扇区号和相序没对应上。
所以我的建议是:先画个扇区图,把每个扇区对应的开关序列手写一遍,再对照代码检查。别嫌麻烦,这一步省了,后面调试更痛苦。