4、SVPWM原理与实现:空间矢量调制原理、扇区判断与作用时间、七段式与五段式SVPWM、代码实现与波形分析
好,咱们今天来啃一块硬骨头——SVPWM。
说实话,我刚入行那会儿,看到SVPWM的矢量图就头大。什么αβ坐标系、扇区判断、作用时间计算,感觉像在看天书。后来在项目里被波形畸变折磨了几个通宵,才真正搞明白这东西到底是怎么回事。
你想想看,FOC的核心目标是什么?就是让电机转得又稳又顺。而SVPWM,就是那个把理想电压矢量变成实际PWM波形的关键桥梁。没有它,你算出来的Ud、Uq再漂亮,也只是一堆没用的数字。
4.1 空间矢量调制原理
咱们先抛开公式,用直觉来理解。
三相逆变器有6个开关管,上下桥臂互补导通。所以一共就8种开关状态:6个非零矢量和2个零矢量(000和111)。
这6个非零矢量,在空间上把360°分成了6个扇区,每个扇区60°。你想想看,这就像你手里有6把尺子,但你要量出任意角度和长度的矢量——怎么办?
核心思想:用相邻的两个基本电压矢量,通过时间加权合成任意目标矢量。这就是「伏秒平衡」原则。
举个例子。假设你想要的电压矢量在扇区I,那就用V1(100)和V2(110)来合成。T1时间给V1,T2时间给V2,剩下的时间给零矢量。只要PWM周期足够短,电机看到的平均效果就是你想要的那个矢量。
我在项目中遇到过一个问题:当调制比接近1时,波形开始失真。后来才发现,是没处理好过调制的情况。嗯,这个后面会细说。
4.2 扇区判断与作用时间
好,理论说完了,咱们来点实际的。
4.2.1 扇区判断
怎么判断目标矢量在哪个扇区?
我个人的习惯是用Uα、Uβ的符号和大小关系来判断。其实很简单,你只需要三个中间变量:
// 扇区判断辅助变量
B1 = Ubeta;
B2 = (sqrt(3)/2)*Ualpha - 0.5*Ubeta;
B3 = (-sqrt(3)/2)*Ualpha - 0.5*Ubeta;
然后根据这三个值的正负,查表就能得到扇区号:
| B1 | B2 | B3 | 扇区 |
|---|---|---|---|
| >0 | >0 | <0 | I |
| >0 | <0 | <0 | II |
| >0 | <0 | >0 | III |
| <0 | <0 | >0 | IV |
| <0 | >0 | >0 | V |
| <0 | >0 | <0 | VI |
小技巧:实际代码里,我一般用查表法而不是if-else链。查表更快,而且代码更整洁。扇区号 = (B1>0) + 2*(B2>0) + 4*(B3>0),然后查一个6元素的表就行。
4.2.2 作用时间计算
扇区判断完了,接下来就是算T1和T2。
每个扇区的计算公式其实是对称的,只是符号和变量名不同。以扇区I为例:
// 扇区I的作用时间
T1 = (sqrt(3)*Tpwm/Udc) * (Ualpha*sin(60°) - Ubeta*cos(60°));
T2 = (sqrt(3)*Tpwm/Udc) * (-Ualpha*sin(0°) + Ubeta*cos(0°));
// 简化后
T1 = (Tpwm/Udc) * (Ualpha + Ubeta/sqrt(3));
T2 = (Tpwm/Udc) * (2*Ubeta/sqrt(3));
你可能会问:为什么每个扇区公式不一样?
其实本质是一样的,只是坐标系旋转了60°。我建议你把6个扇区的公式统一成一种形式,用查表法处理符号和变量交换。这样代码量能减少一半。
注意:算出来的T1+T2如果大于Tpwm,说明进入了过调制区。这时候需要等比例缩小:T1' = T1 * Tpwm/(T1+T2),T2' = T2 * Tpwm/(T1+T2)。我曾经在这个坑里摔过,波形直接削顶了。
4.3 七段式与五段式SVPWM
好,时间算出来了,怎么安排PWM波形?
这里有两种主流方式:七段式和五段式。
4.3.1 七段式SVPWM
七段式,顾名思义,一个PWM周期里分成7段。以扇区I为例:
// 七段式开关序列(扇区I)
// 000 -> 100 -> 110 -> 111 -> 110 -> 100 -> 000
// 零矢量分布在两端和中间
这样做的好处是:每个周期开关次数固定,谐波特性好。但缺点是开关损耗大——每次切换都有6次开关动作。
我个人习惯在低速时用七段式。因为低速时电流大,谐波引起的发热更明显,七段式的谐波性能更好。
4.3.2 五段式SVPWM
五段式就「偷懒」了。它把其中一个零矢量去掉,只保留一个:
// 五段式开关序列(扇区I)
// 000 -> 100 -> 110 -> 111 -> 110 -> 100
// 或者
// 100 -> 110 -> 111 -> 110 -> 100
开关次数从6次降到4次,开关损耗直接减少1/3。但代价是谐波含量增加,电流纹波变大。
| 对比项 | 七段式 | 五段式 |
|---|---|---|
| 开关次数/周期 | 6次 | 4次 |
| 开关损耗 | 高 | 低(降33%) |
| 谐波性能 | 好 | 较差 |
| 适用场景 | 低速、高精度 | 高速、高效率 |
我的建议:量产项目中,我一般会根据转速动态切换。1000rpm以下用七段式,以上用五段式。这样既保证了低速的平稳性,又兼顾了高速的效率。
4.4 代码实现与波形分析
光说不练假把式。咱们直接上代码。
4.4.1 核心代码实现
// SVPWM主函数
void svpwm_calc(SVPWM_Handle *h)
{
float Ualpha = h->Ualpha;
float Ubeta = h->Ubeta;
float Tpwm = h->Tpwm;
float Udc = h->Udc;
// 1. 扇区判断
float B1 = Ubeta;
float B2 = 0.866f*Ualpha - 0.5f*Ubeta; // sqrt(3)/2 ≈ 0.866
float B3 = -0.866f*Ualpha - 0.5f*Ubeta;
uint8_t sector = 0;
if(B1 > 0) sector |= 0x01;
if(B2 > 0) sector |= 0x02;
if(B3 > 0) sector |= 0x04;
// 查表得到实际扇区号(0-5)
const uint8_t sector_table[8] = {0,1,5,0,3,2,4,0};
sector = sector_table[sector];
// 2. 计算X,Y,Z
float X = (sqrt3*Ubeta*Tpwm) / Udc;
float Y = (1.5f*Ualpha + 0.866f*Ubeta) * Tpwm / Udc;
float Z = (-1.5f*Ualpha + 0.866f*Ubeta) * Tpwm / Udc;
// 3. 根据扇区查T1,T2
float T1, T2;
switch(sector)
{
case 0: T1 = Z; T2 = Y; break;
case 1: T1 = Y; T2 = -X; break;
case 2: T1 = -Z; T2 = X; break;
case 3: T1 = -X; T2 = Z; break;
case 4: T1 = X; T2 = -Y; break;
case 5: T1 = -Y; T2 = -Z; break;
}
// 4. 过调制处理
float Ts = T1 + T2;
if(Ts > Tpwm)
{
float scale = Tpwm / Ts;
T1 *= scale;
T2 *= scale;
}
// 5. 计算占空比(七段式)
float Ta = (Tpwm - T1 - T2) * 0.5f;
float Tb = Ta + T1;
float Tc = Tb + T2;
// 6. 根据扇区分配三相占空比
switch(sector)
{
case 0: h->Ta = Tb; h->Tb = Ta; h->Tc = Tc; break;
case 1: h->Ta = Ta; h->Tb = Tc; h->Tc = Tb; break;
case 2: h->Ta = Ta; h->Tb = Tb; h->Tc = Tc; break;
// ... 其他扇区类似
}
}
4.4.2 波形分析
代码写完了,怎么验证对不对?
我的习惯是先用仿真看波形。重点关注三个地方:
- 相电压波形:应该是马鞍形,而不是正弦波。这是SVPWM的特征——它在正弦波上叠加了三次谐波,提高了母线电压利用率。
- 线电压波形:应该是正弦波。如果线电压有畸变,说明扇区切换有问题。
- 电流波形:正弦度好不好?有没有明显的6次谐波?
关键指标:SVPWM的母线电压利用率比SPWM高15.47%。也就是说,同样的母线电压,SVPWM能让电机跑得更快。这也是为什么FOC几乎都用SVPWM的原因。
我记得有一次调试,电流波形总是有毛刺。查了半天,发现是PWM死区时间设置不对。死区补偿没做好,电流过零点附近就会出现畸变。嗯,这个后面专门有一章讲死区补偿。
4.5 本章小结
好,咱们捋一捋今天的内容:
- SVPWM的本质:用相邻矢量合成目标矢量,遵循伏秒平衡
- 扇区判断:用Uα、Uβ的符号组合查表,简单高效
- 作用时间:每个扇区公式对称,建议统一处理
- 七段式 vs 五段式:低速用七段,高速用五段,灵活切换
- 代码实现:注意过调制处理和扇区查表
下一章咱们聊电流采样和重构。采样时序搞不好,FOC就是空中楼阁。到时候我会分享一个我在采样上踩过的坑——保证让你印象深刻。
课后练习:试着把上面的代码改成五段式SVPWM。提示:只需要修改占空比计算部分,把零矢量的分配方式改一下就行。