4. SVPWM扇区判断:Clark变换、扇区判定算法、N值计算

好,咱们进入SVPWM的核心环节——扇区判断。

你想想看,SVPWM要输出一个旋转的电压矢量,第一步就得知道这个矢量当前落在哪个扇区里。不知道扇区,后面的开关管导通时序根本没法算。这就像你开车去一个陌生城市,首先得搞清楚自己在哪个区,才能规划路线。

我个人习惯把扇区判断拆成三步走:Clark变换 → 扇区判定算法 → N值计算。咱们一个一个来。

4.1 为什么需要Clark变换?

电机控制里,我们通常拿到的是三相电流或电压(U、V、W),或者两相静止坐标系下的αβ分量。但SVPWM的扇区判断,直接基于αβ坐标系最方便。

说白了,Clark变换就是把三相静止坐标系(abc)映射到两相静止坐标系(αβ)。公式很简单:

Uα = Ua
Uβ = (Ua + 2*Ub) / √3

这里Ua、Ub、Uc是三相电压。实际项目中,我们通常只采样两相(比如Ua和Ub),第三相通过Uc = -(Ua+Ub)算出来。嗯,这里要注意,采样精度直接影响扇区判断的准确性。

我在项目里遇到过采样噪声导致扇区频繁跳变的情况,后来加了低通滤波才稳住。所以建议你在做Clark变换前,先对采样值做一下滤波处理。

4.2 扇区判定算法

有了Uα和Uβ,接下来就是判断扇区。SVPWM把空间分成了6个扇区,每个扇区60度。判断的依据是Uα和Uβ的符号以及它们之间的比例关系。

我常用的方法是引入三个中间变量:

B0 = Uβ
B1 = (√3/2)*Uα - (1/2)*Uβ
B2 = -(√3/2)*Uα - (1/2)*Uβ

然后根据这三个值的正负,就能唯一确定扇区。具体规则如下:

B0 B1 B2 扇区
>0 >0 <0 I
>0 <0 <0 II
>0 <0 >0 III
<0 <0 >0 IV
<0 >0 >0 V
<0 >0 <0 VI

你看,其实就是三个布尔值的组合。用代码实现的话,效率非常高。

我的小技巧: 实际写代码时,我习惯把B0、B1、B2的符号位打包成一个3位的二进制数,然后查表得到扇区号。这样比if-else嵌套快得多,尤其是在中断里执行时。

4.3 N值计算——扇区编号的数字化

刚才的表格虽然直观,但嵌入式系统里我们更喜欢用数字。所以就有了N值计算。

N值的定义很简单:

N = 4*sign(B2) + 2*sign(B1) + 1*sign(B0)

其中sign(x)表示取符号位:x>0时返回1,x<0时返回0。

这样算出来的N值范围是1~6,正好对应6个扇区。对应关系如下:

N值 扇区
1 II
2 VI
3 I
4 IV
5 III
6 V

这个映射关系不是随便定的,它跟后面计算电压矢量作用时间时的查表顺序有关。我刚开始学的时候,自己推导了一遍才理解为什么这么映射。

曾经踩过的坑: 有一次我直接用N值作为扇区号去查时间表,结果电机转起来一顿一顿的。后来发现是N值和扇区号的映射关系搞反了。所以建议你写代码时,把这张映射表放在注释里,方便调试。

4.4 扇区判断的完整流程

把上面三步串起来,就是完整的扇区判断流程。我画了一张图,帮你理清思路:

扇区判断完整流程图 三相电压 Ua, Ub, Uc Clark变换 → Uα, Uβ 计算中间变量 B0, B1, B2 N = 4*sign(B2)+2*sign(B1)+1*sign(B0) 输出扇区号 (1~6) 关键点 B0, B1, B2 的符号位 决定了扇区归属 N值查表得到扇区号

你看,整个流程非常清晰。从三相电压输入,到Clark变换得到αβ分量,再计算三个中间变量,最后通过N值查表得到扇区号。每一步都是确定的,没有模糊地带。

4.5 代码实现示例

最后,给你一个我常用的C语言实现片段。这段代码我用了很多年,在STM32和TMS320上都跑过,稳定可靠。

// 扇区判断函数
// 输入:Ualpha, Ubeta(经过Clark变换后的值)
// 输出:扇区号(1~6)
int svpwm_sector_calc(float Ualpha, float Ubeta)
{
    float B0, B1, B2;
    int N;
    
    // 计算中间变量
    B0 = Ubeta;
    B1 = 0.866025f * Ualpha - 0.5f * Ubeta;  // √3/2 ≈ 0.866025
    B2 = -0.866025f * Ualpha - 0.5f * Ubeta;
    
    // 计算N值
    N = 0;
    if (B0 > 0) N |= 1;    // 位0
    if (B1 > 0) N |= 2;    // 位1
    if (B2 > 0) N |= 4;    // 位2
    
    // 查表得到扇区号
    static const int sector_table[8] = {0, 2, 6, 1, 4, 3, 5, 0};
    return sector_table[N & 0x07];
}

代码说明:

  • B0、B1、B2的计算用了浮点数,如果你对性能要求高,可以全部转成定点数运算。
  • N值的计算用了位操作,比乘除法快很多。
  • sector_table数组的索引是N值,值是扇区号。注意数组大小是8,但N值范围是0~7,其中0和7是无效值(理论上不会出现)。

嗯,扇区判断这部分就讲到这里。你把这个流程吃透了,后面计算电压矢量作用时间就会轻松很多。记住,扇区判断是SVPWM的基石,这里出问题,后面全白搭。