4. 扇区判断:扇区划分原理、基于αβ分量的扇区判断算法、扇区判断的C代码实现
好,咱们接着聊SVPWM。前面我们把Clark变换讲清楚了,得到了αβ坐标系下的电压分量Uα和Uβ。那下一步是什么?
说白了,你得知道当前这个电压矢量落在哪个扇区里。为什么?因为不同的扇区,逆变器的开关管导通组合是不一样的。你连目标在哪个房间都不知道,怎么走路?
4.1 扇区划分原理
先说说扇区是怎么划分的。
三相逆变器有6个功率管,上桥臂三个,下桥臂三个。每个桥臂只能有一个管子导通,所以一共有2³=8种开关状态。其中6种是有效矢量,2种是零矢量(000和111)。
这6个有效矢量,在空间上把360°的平面均匀分成了6份。每份60°,这就是一个扇区。
关键点:扇区编号从I到VI,按逆时针方向排列。第I扇区在0°~60°之间,第II扇区在60°~120°之间,以此类推。
我刚开始学的时候,总记不住哪个扇区对应哪个角度范围。后来我习惯把扇区编号和基本电压矢量对应起来记:U1(100)对应0°,U2(110)对应60°,U3(010)对应120°...这样就好记多了。
下面这张图,是我用SVG画的扇区划分示意图,你可以直观感受一下:
我的小技巧:在实际项目中,我习惯把扇区编号和三相的导通状态联系起来。比如第I扇区,A相上桥臂导通,B相下桥臂导通,C相下桥臂导通——这就是U1(100)。你多画几次这个六边形,自然就记住了。
4.2 基于αβ分量的扇区判断算法
好了,扇区划分清楚了。那怎么用程序判断呢?
你想想看,我们手头只有Uα和Uβ两个值。怎么从这两个值算出扇区号?
最直接的方法是用角度。先算出θ = arctan(Uβ / Uα),然后看θ落在哪个区间。但问题是,反正切函数计算量太大,在嵌入式MCU上跑起来很慢。我早期在一个项目里用过这种方法,结果PWM频率只能跑到5kHz,根本不够用。
后来我换了一种方法——用Uα和Uβ的符号和比例关系来判断。不需要三角函数,只需要加减法和比较运算。
具体怎么做?
先定义三个中间变量:
B1 = Uβ
B2 = (√3/2) * Uα - (1/2) * Uβ
B3 = -(√3/2) * Uα - (1/2) * Uβ
然后看这三个变量的符号:
- 如果B1 > 0,记A=1,否则A=0
- 如果B2 > 0,记B=1,否则B=0
- 如果B3 > 0,记C=1,否则C=0
最后扇区号N = A + 2B + 4C。
嗯,这里要注意:算出来的N是1~6之间的数,分别对应扇区I~VI。但N的值和扇区编号不是一一对应的,需要查表转换。
| N值 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|
| 扇区号 | II | VI | I | IV | III | V |
我曾经踩过的坑:一开始我直接用N值当扇区号,结果电机转起来一顿一顿的。查了半天才发现是扇区映射表搞错了。后来我学乖了,每次写完扇区判断代码,先用几个已知角度的手算验证一遍,确认映射关系正确再往下走。
4.3 扇区判断的C代码实现
理论讲完了,上代码。这是我在实际项目中用过的扇区判断函数,经过多次优化,计算量很小:
/**
* @brief 扇区判断函数
* @param Ualpha α轴电压分量(标幺值)
* @param Ubeta β轴电压分量(标幺值)
* @return 扇区编号(1~6)
*/
uint8_t SVPWM_CalcSector(float Ualpha, float Ubeta)
{
uint8_t sector = 0;
float B1, B2, B3;
uint8_t A = 0, B = 0, C = 0;
/* 计算三个中间变量 */
B1 = Ubeta;
B2 = 0.8660254f * Ualpha - 0.5f * Ubeta; /* √3/2 ≈ 0.8660254 */
B3 = -0.8660254f * Ualpha - 0.5f * Ubeta;
/* 判断符号 */
if (B1 > 0.0f) A = 1;
if (B2 > 0.0f) B = 1;
if (B3 > 0.0f) C = 1;
/* 计算N值 */
uint8_t N = A + 2 * B + 4 * C;
/* 查表映射到扇区号 */
switch(N)
{
case 1: sector = 2; break; /* N=1 → 扇区II */
case 2: sector = 6; break; /* N=2 → 扇区VI */
case 3: sector = 1; break; /* N=3 → 扇区I */
case 4: sector = 4; break; /* N=4 → 扇区IV */
case 5: sector = 3; break; /* N=5 → 扇区III */
case 6: sector = 5; break; /* N=6 → 扇区V */
default: sector = 1; break; /* 异常情况,默认扇区I */
}
return sector;
}
我个人的优化建议:如果你用的MCU不支持硬件浮点运算,可以把所有系数都转成Q15或Q24格式的定点数。我在一个Cortex-M0的项目里这么干过,扇区判断从原来的2.3μs降到了0.8μs,效果很明显。
这段代码的核心思想,其实就是用三个直线方程把平面分成6个区域。每个区域对应一个扇区。你想想看,这比算反正切快了多少倍?
另外,代码里我加了一个default分支。虽然正常情况下不会走到那里,但做嵌入式开发嘛,防呆设计不能少。万一ADC采出来的数据异常,至少不会让程序跑飞。
好了,扇区判断就讲到这里。下一节我们聊聊如何计算每个扇区里的作用时间,那才是SVPWM的精髓所在。
公众号:蓝海资料掘金营,微信deep3321