扇区判断:如何根据αβ轴电压分量快速定位参考电压矢量
上一章我们聊了Clark变换,把三相静止的ABC坐标系,搬到了两相静止的αβ坐标系。这一步做完,我们手里就有了Uα和Uβ这两个值。
但问题来了——SVPWM要生成的是六个扇区里的空间电压矢量。你得先知道,当前这个参考电压矢量到底落在哪个扇区,才能决定用哪两个基本矢量去合成它。
说白了,扇区判断就是SVPWM的第一道关卡。判断错了,后面全白搭。我早年调试一台伺服驱动器时,就因为扇区判断的符号位取反,电机转起来抖得像筛糠,查了整整两天才找到问题。
扇区划分的几何直觉
先看一张图,帮大家建立空间感。
六个基本矢量把平面切成六个60°的扇区。每个扇区里,任意一个Vref都可以由相邻的两个基本矢量合成。关键就是——怎么快速知道Vref落在哪个扇区。
从几何到代数:三个中间变量
你可能会想,用角度θ不就行了?atan2(Uβ, Uα)算出角度,然后除以60°取整。理论上没错,但实际工程里没人这么干。
为什么?因为反正切计算太慢了。在Cortex-M0或者DSP里,一个atan2可能要吃掉几十个时钟周期。而SVPWM的调制频率通常是10kHz~20kHz,每个周期留给扇区判断的时间窗口非常短。
所以,工业界通用的做法是——用代数不等式判断,不用三角函数。
具体怎么做?先定义三个中间变量:
// 三个中间变量,只用到Uα、Uβ和常数√3
B1 = Uβ
B2 = (√3/2) * Uα - 0.5 * Uβ
B3 = -(√3/2) * Uα - 0.5 * Uβ
这三个变量其实对应了三条扇区边界线的法向分量。你想想看,六边形的三条对角线,把平面分成了六个区域。每个B值的正负,就告诉你Vref在边界线的哪一侧。
核心思想:三个B值的符号组合,唯一确定一个扇区。不需要角度,不需要查表,只需要三次乘法和三次比较。
扇区号的计算公式
有了B1、B2、B3之后,我们定义一个临时变量N:
N = sign(B1) + 2*sign(B2) + 4*sign(B3)
这里的sign(x)是符号函数——x大于0时返回1,否则返回0。N的取值范围是0~7,但实际有效的只有6个值。然后通过一个简单的映射表,就能得到扇区号:
| N值 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|
| 扇区号 | Ⅱ | Ⅵ | Ⅰ | Ⅳ | Ⅲ | Ⅴ |
这个映射表不是拍脑袋定的,它来源于N值与扇区边界的几何对应关系。我个人习惯把这个表直接写成数组,查表比switch-case更快:
const uint8_t sectorMap[7] = {0, 2, 6, 1, 4, 3, 5};
// 下标对应N值,数组元素就是扇区号
uint8_t sector = sectorMap[N];
小技巧:如果你用的MCU没有硬件浮点,可以把√3/2和0.5预先算成Q15或Q12格式的定点数。这样乘加运算全部用整数完成,速度还能再快一截。
完整代码实现
下面给出一段完整的C代码,输入Uα和Uβ,输出扇区号。这段代码我在STM32F103上跑过,单次判断耗时不到1μs。
#include <stdint.h>
#define SQRT3_OVER_2 0.8660254f
#define ONE_HALF 0.5f
uint8_t svpwm_sector_calc(float Ualpha, float Ubeta)
{
float B1, B2, B3;
uint8_t N;
// 计算三个中间变量
B1 = Ubeta;
B2 = SQRT3_OVER_2 * Ualpha - ONE_HALF * Ubeta;
B3 = -SQRT3_OVER_2 * Ualpha - ONE_HALF * Ubeta;
// 组合成N值
N = (B1 > 0) ? 1 : 0;
N += (B2 > 0) ? 2 : 0;
N += (B3 > 0) ? 4 : 0;
// 查表得到扇区号
static const uint8_t sectorMap[7] = {0, 2, 6, 1, 4, 3, 5};
return sectorMap[N];
}
这段代码里,我用了静态常量表,避免每次调用都重新初始化。嗯,这里要注意——N值不会出现0和7,因为三个B值不可能同时为正或同时为负。所以数组第0个元素我随便填了个0,实际用不到。
边界情况与避坑指南
理论讲完了,聊聊实际中容易踩的坑。
第一个坑:浮点精度。当Vref非常接近扇区边界时,B1、B2、B3可能接近0。浮点运算的微小误差可能导致符号判断出错。我曾经在量产阶段遇到过,某批次电机在低速轻载时偶尔抖动,最后定位到就是扇区边界处的误判。
解决办法:给符号判断加一个滞回区间。
// 加一个死区,避免边界抖动
#define HYSTERESIS 0.001f
uint8_t sign_with_hyst(float x) {
if (x > HYSTERESIS) return 1;
if (x < -HYSTERESIS) return 0;
return previous_sign; // 保持上一次的结果
}
第二个坑:Uα和Uβ的标幺化。如果你的Uα和Uβ是标幺值(pu值),要确保它们的基值与SVPWM的直流母线电压一致。否则扇区边界会偏移,导致判断错误。
第三个坑:中断优先级。扇区判断通常在PWM中断里执行。如果被更高优先级的中断频繁打断,Uα和Uβ的采样时刻可能不对齐。我建议把Clark变换和扇区判断放在同一个中断里,关掉嵌套中断,保证数据一致性。
警告:不要在扇区判断中使用动态内存分配或阻塞式函数。SVPWM是实时控制,每个微秒都很宝贵。malloc、printf这些函数,在控制中断里绝对不要出现。
扇区判断的工程意义
扇区判断是整个SVPWM的入口。它决定了后续的矢量作用时间计算、比较值装载。判断错了,轻则电流畸变、转矩脉动,重则过流保护触发甚至炸管子。
我见过一些初学者,把扇区判断的映射表搞反了,结果电机反转。还有人在代码里用了switch-case,每个case里又调了子函数,导致中断执行时间超标。其实一个查表就搞定的事,别搞复杂了。
记住:扇区判断的核心就是三个不等式、一个组合值、一张映射表。简单、快速、可靠,这才是工程之道。