第四节:基本电压矢量与扇区划分
好,咱们今天聊点实在的。SVPWM 的核心,说白了就是怎么用八个开关状态去逼近一个旋转的电压圆。这八个状态,就是六个非零矢量和两个零矢量。你想想看,一个三相逆变器,六个开关管,能组合出多少种状态?2³ = 8 种。没错,就是这八种。
4.1 六个非零矢量与两个零矢量
这八个状态,我习惯把它们画在一个复平面上。六个非零矢量,每个相隔 60°,正好把 360° 的圆分成六等份。两个零矢量呢?就是所有上桥臂全通或者全断,输出电压为零。
具体来说,非零矢量 V1(100) 到 V6(101),每个矢量对应一个特定的开关组合。比如 V1(100) 表示 A 相上桥臂导通,B、C 相下桥臂导通。这时候合成的电压矢量指向 0° 方向。V2(110) 指向 60°,以此类推。
关键点:六个非零矢量的幅值都是 (2/3)Vdc,方向固定。两个零矢量 V0(000) 和 V7(111) 幅值为零,位于原点。
我记得刚做电机控制那会儿,总搞不清为什么是 (2/3)Vdc。后来推导了一遍 Clarke 变换才明白——这是等幅值变换的必然结果。你如果做等功率变换,幅值就是 √(2/3)Vdc。嗯,这里要注意,不同变换下的系数不一样,别搞混了。
| 矢量 | 开关状态 (A B C) | 幅值 | 角度 |
|---|---|---|---|
| V0 | 000 | 0 | - |
| V1 | 100 | 2/3 Vdc | 0° |
| V2 | 110 | 2/3 Vdc | 60° |
| V3 | 010 | 2/3 Vdc | 120° |
| V4 | 011 | 2/3 Vdc | 180° |
| V5 | 001 | 2/3 Vdc | 240° |
| V6 | 101 | 2/3 Vdc | 300° |
| V7 | 111 | 0 | - |
我的小技巧:记不住矢量顺序?看开关状态二进制数,从 V1(100) 开始,每次只改变一个 bit,沿着六边形走一圈。V1→V2→V3→V4→V5→V6,刚好一个循环。
4.2 扇区划分方法
六个非零矢量把平面分成六个扇区,每个扇区 60°。扇区 I 在 0°~60°,扇区 II 在 60°~120°,依此类推。为什么要分扇区?因为我们要用相邻的两个非零矢量去合成任意方向的目标矢量。
判断目标矢量在哪个扇区,我见过三种方法:
- 角度法:直接算目标矢量的角度 θ,看落在哪个区间。最简单,但需要反正切运算,DSP 里比较费时间。
- Clark 分量法:用 Vα、Vβ 的正负和比值来判断。不用算角度,快很多。
- 三值逻辑法:通过三个参考值 A、B、C 的符号组合直接查表。我最常用这个,一个 if-else 就搞定。
我个人推荐第三种。为什么?因为嵌入式里最怕浮点运算。三值逻辑法只用比较和移位,纯整数操作,跑起来飞快。
曾经踩过的坑:有一次我用角度法判断扇区,atan2 函数在边界处有 ±1° 的误差,导致扇区判断偶尔跳变,电流波形出现毛刺。后来换成三值逻辑法,问题立刻解决。边界处理一定要留余量,别卡在 0°、60° 这些临界点上。
4.3 三值逻辑法详解
具体怎么做?先定义三个中间变量:
// 假设 Vα、Vβ 已经通过 Clark 变换得到
// 定义三个参考值
B1 = Vβ
B2 = (√3/2)*Vα - (1/2)*Vβ
B3 = -(√3/2)*Vα - (1/2)*Vβ
// 然后判断符号
if (B1 > 0) A = 1 else A = 0
if (B2 > 0) B = 1 else B = 0
if (B3 > 0) C = 1 else C = 0
// 扇区号 = A + 2*B + 4*C
sector = A + (B << 1) + (C << 2)
算出来的 sector 值 1~6 分别对应扇区 I~VI。你可能会问,为什么是这三个公式?其实它们对应的是三条直线:Vβ=0、Vβ=√3 Vα、Vβ=-√3 Vα。这三条线正好把平面分成六个 60° 扇区。
下面这张图把整个结构画清楚了:
4.4 扇区判断的工程实现
在实际代码里,我一般这么写:
// 扇区判断函数,输入 Vα, Vβ,输出扇区号 1~6
uint8_t svpwm_sector_calc(float Valpha, float Vbeta)
{
uint8_t sector = 0;
float B1, B2, B3;
uint8_t A, B, C;
// 计算三个参考值
B1 = Vbeta;
B2 = 0.866025f * Valpha - 0.5f * Vbeta; // √3/2 ≈ 0.866
B3 = -0.866025f * Valpha - 0.5f * Vbeta;
// 符号判断
A = (B1 > 0.0f) ? 1 : 0;
B = (B2 > 0.0f) ? 1 : 0;
C = (B3 > 0.0f) ? 1 : 0;
// 组合扇区号
sector = A + (B << 1) + (C << 2);
return sector;
}
这段代码在 C2000 或者 STM32 上跑,大概只需要几十个时钟周期。我曾经在一个 60MHz 的 MCU 上做过测试,扇区判断加矢量作用时间计算,总共不到 5μs。对于 10kHz 的开关频率来说,绰绰有余。
优化建议:如果 MCU 没有硬件浮点单元,可以把 √3/2 和 1/2 转成 Q15 或 Q12 格式的定点数。这样比较和移位都是整数运算,速度还能再快一倍。
4.5 扇区与矢量作用时间的关系
知道目标矢量在哪个扇区后,下一步就是计算相邻两个非零矢量的作用时间。比如目标矢量在扇区 I,就用 V1 和 V2 来合成。作用时间 T1、T2 由伏秒平衡原理决定:
T1 = Ts * (Vref / Vdc) * sin(60° - θ) / sin(60°)
T2 = Ts * (Vref / Vdc) * sin(θ) / sin(60°)
T0 = Ts - T1 - T2
其中 Ts 是开关周期,Vref 是目标矢量幅值,θ 是目标矢量在扇区内的相对角度(0°~60°)。T0 是零矢量作用时间,用来补满整个周期。
这里有个细节:当 Vref 超过六边形内切圆半径时,T1+T2 会大于 Ts。这就是过调制区。我在做伺服驱动器时遇到过这个问题,电机在高速区转矩突然下降。后来加了过调制处理,把超出部分按比例压缩,才把高速性能提上来。
重要提醒:扇区判断的边界值一定要做滞回处理。比如在 0° 附近,由于采样噪声,Vβ 可能在 0 附近来回跳,导致扇区在 I 和 VI 之间频繁切换。加一个 0.01Vdc 的滞回区间,就能避免这个问题。
好了,扇区划分这部分就聊到这儿。记住三个核心点:六个非零矢量、两个零矢量、三值逻辑判断法。下节课咱们接着聊矢量作用时间的计算和 PWM 占空比的生成。