1. 从一次电机啸叫说起:为什么SVPWM的谐波优化值得死磕
做电机控制的朋友大概率都遇到过这种场景:电机在中低速运行时,总能听到一阵尖锐的啸叫,示波器一挂,相电流波形上叠着一层毛刺,FFT一分析,开关频率附近和低频段的谐波分量明显偏高。这时候你调PID、改电流环带宽、换电感,折腾一圈下来发现改善有限,最后才意识到问题可能出在最底层的调制策略上——也就是SVPWM本身。
SVPWM(Space Vector Pulse Width Modulation,空间矢量脉宽调制)是当前三相电机FOC控制里最主流的调制方式,相比SPWM,它的直流母线电压利用率能高出约15.47%,谐波特性也更好。但SVPWM并不是一个单一算法,它内部还有不同的实现形式,最典型的就是5段式和7段式两种开关序列。很多人写代码的时候随手抄了一份7段式,跑通了就不管了,结果在特定工况下谐波、开关损耗、死区效应全冒出来。
这篇内容就是围绕这两种调制方式做一次全参数对比测试,把扇区判断、作用时间计算、零序注入、开关序列编排这些环节全部拆开讲清楚,同时给出实测的谐波数据对比。适合正在用STM32F103C8T6或者DSP28379做电机控制、已经跑通基础SVPWM但想进一步优化谐波和效率的工程师参考。如果你还在纠结扇区判断后那两个非零矢量的作用时间怎么推导,或者搞不清7段式和5段式到底差在哪,这篇应该能帮你把坑填平。
2. SVPWM核心原理快速复盘:扇区判断与作用时间推导
2.1 从三相电压到空间矢量的映射逻辑
SVPWM的本质,是用逆变器的8种开关状态去逼近一个旋转的电压矢量。三相桥臂每相有上下两个开关管,组合起来一共8种状态,其中6个是非零矢量(V1到V6),2个是零矢量(V0和V7)。这6个非零矢量把复平面分成6个扇区,每个扇区60度。
给定一个目标电压矢量Vref,它落在某个扇区内,就用该扇区相邻的两个非零矢量加上零矢量去合成。合成的依据是伏秒平衡:在一个PWM周期Ts内,两个非零矢量分别作用T1和T2时间,零矢量作用T0时间,满足T1+T2+T0=Ts,且矢量合成结果等于Vref乘以Ts。
这里有个关键点很多人一开始想不明白:为什么用两个离散的矢量能合成出中间任意角度的矢量?类比一下,就像你用两个不同方向的力去拉一个物体,只要调整两个力的大小比例,合力方向就可以指向两者之间的任意角度。SVPWM做的就是这件事,只不过“力”变成了电压矢量,“大小比例”变成了作用时间比例。
2.2 扇区判断的三种常见方法及选择建议
扇区判断是SVPWM的第一步,判断错了后面全错。常见方法有三种:
第一种是直接角度法,用atan2算出Vref的角度,再除以60度取整。这种方法直观但计算量大,atan2在定点DSP上开销不小,一般只在仿真里用。
第二种是Clarke变换后符号判断法,把Vref分解到α-β平面,得到Vα和Vβ,然后构造三个中间变量A、B、C,通过它们的正负组合查表得到扇区。这是工程上最常用的方法,计算量小,逻辑清晰。
第三种是电压比较法,直接用三相参考电压的大小关系判断。这种方法在过调制区边界容易出错,不太推荐。
我实测下来,第二种方法在STM32F103C8这种没有FPU的芯片上也能轻松跑,一个PWM周期内完成扇区判断加时间计算,CPU占用率不到15%。具体做法是先算:
Vref1 = Vβ Vref2 = (√3·Vα - Vβ) / 2 Vref3 = (-√3·Vα - Vβ) / 2然后定义:若Vref1>0则A=1,否则A=0;Vref2>0则B=1,否则B=0;Vref3>0则C=1,否则C=0。令N=A+2B+4C,查表N与扇区的对应关系即可。这个表我建议直接背下来:N=3对应扇区1,N=1对应扇区2,N=5对应扇区3,N=4对应扇区4,N=6对应扇区5,N=2对应扇区6。
注意:不同教材对扇区编号的起始定义可能不同,有的从扇区1开始对应0到60度,有的从-30到30度。写代码前一定要和你用的矢量表对齐,否则会出现矢量作用顺序错乱,电机直接堵转或者抖动。
2.3 两个非零矢量作用时间的公共量推导
扇区判断完之后,下一步是算两个非零矢量的作用时间T1和T2。这里有一个中间变量(公共量)的推导过程,很多人卡在这一步。我把它拆开讲。
以扇区1为例,Vref落在V1(100)和V2(110)之间。根据伏秒平衡,在α-β平面列方程:
Vα·Ts = |V1|·T1 + |V2|·cos60°·T2 Vβ·Ts = 0·T1 + |V2|·sin60°·T2非零矢量幅值都是2/3·Udc(这是等幅值Clarke变换下的结果),代入后化简可以得到:
T1 = (√3·Ts/Udc)·(√3/2·Vα - 1/2·Vβ) T2 = (√3·Ts/Udc)·Vβ为了统一六个扇区的计算,工程上会定义三个公共量:
X = √3·Ts·Vβ / Udc Y = Ts·(√3·Vβ + 3·Vα) / (2·Udc) Z = Ts·(√3·Vβ - 3·Vα) / (2·Udc)然后每个扇区的T1、T2都可以用X、Y、Z的组合表示。比如扇区1:T1=-Z,T2=X;扇区2:T1=Z,T2=Y;扇区3:T1=X,T2=-Y;以此类推。这个公共量的推导过程看着繁琐,但一旦写成代码就是几个乘加,效率极高。
实操心得:X、Y、Z这三个量在每个PWM周期都要算一次,建议用Q格式定点数运算,STM32F103上用Q15格式,DSP28379上可以直接用浮点。注意Ts和Udc的标幺化处理,否则容易溢出。
3. 5段式与7段式开关序列的本质差异
3.1 7段式SVPWM的波形结构与谐波特性
7段式是最经典的SVPWM实现方式,一个PWM周期内开关序列被分成7段,以扇区1为例,顺序是:V0(000) → V1(100) → V2(110) → V7(111) → V2(110) → V1(100) → V0(000)。可以看到零矢量V0和V7都被使用了,且对称分布。
这种对称结构带来的好处是谐波特性好。因为波形关于中心对称,偶次谐波被抵消,主要谐波集中在开关频率及其边带附近。实测FFT数据里,7段式的THD(总谐波失真)在中低速工况下通常比5段式低1到2个百分点。
但代价是开关次数多。每个PWM周期内,三相桥臂一共要开关6次(每个桥臂开关2次),开关损耗相应增加。在高压大电流场合,这个损耗不能忽略。
3.2 5段式SVPWM的简化逻辑与损耗优势
5段式的思路是:既然零矢量V0和V7效果一样,那我只用一个行不行?答案是行。5段式在一个PWM周期内只用一种零矢量,开关序列变成5段。以扇区1为例,可以是:V0(000) → V1(100) → V2(110) → V1(100) → V0(000),或者用V7替代V0。
这样每个PWM周期内,三相桥臂总共只开关4次,比7段式少了2次。开关损耗理论上降低约33%。在载波频率较高(比如10kHz以上)或者母线电压较高的场合,这个损耗差异非常明显。
但5段式的谐波特性会变差。因为波形不再关于中心对称,偶次谐波无法完全抵消,低频谐波分量会增加。实测中,5段式的THD通常比7段式高1.5到3个百分点,具体取决于调制比和载波频率。
3.3 两种方式的关键参数对照表
| 对比项 | 7段式SVPWM | 5段式SVPWM |
|---|---|---|
| 每周期开关次数 | 6次 | 4次 |
| 零矢量使用 | V0和V7都用 | 只用V0或只用V7 |
| 波形对称性 | 中心对称 | 非对称 |
| THD(典型值) | 较低 | 较高1.5-3% |
| 开关损耗 | 较高 | 较低约33% |
| 死区效应影响 | 较小 | 较大 |
| 实现复杂度 | 稍高 | 稍低 |
| 适用场景 | 低速、低载波比 | 高速、高载波比 |
这张表是我在多个项目里实测总结的,不是抄手册。需要说明的是,THD的差异会随着调制比变化,在调制比接近1的时候,两者差距会缩小。
4. 全参数对比测试:从仿真到实测的完整过程
4.1 测试平台搭建与参数设定
测试平台用的是一台额定功率750W的三相永磁同步电机,极对数4,额定转速3000rpm,额定电流2.5A。控制器分别用了两块板子:一块是STM32F103C8T6最小系统板,跑的是定点SVPWM;另一块是DSP28379开发板,跑浮点SVPWM。逆变器用的是IPM模块,开关频率设了三个档位:5kHz、10kHz、20kHz。母线电压48V,死区时间设了1微秒。
电流采样用的是霍尔传感器,带宽200kHz。示波器用的是四通道数字示波器,配了电流探头。谐波分析用示波器自带的FFT功能,窗函数选Hanning,分析到50次谐波。
测试工况选了三个:低速轻载(500rpm,0.5A)、中速中载(1500rpm,1.5A)、高速重载(2800rpm,2.5A)。每个工况下分别跑7段式和5段式,记录相电流波形、THD、开关损耗估算值。
4.2 扇区判断与作用时间计算的代码实现
先给一段STM32F103C8上跑的扇区判断代码,用的是Q15定点格式:
// 输入:Valpha, Vbeta (Q15格式) // 输出:sector (1-6) int16_t Sector_Detect(int16_t Valpha, int16_t Vbeta) { int16_t Vref1 = Vbeta; int16_t Vref2 = (int16_t)((1.732f * Valpha - Vbeta) * 0.5f); int16_t Vref3 = (int16_t)((-1.732f * Valpha - Vbeta) * 0.5f); uint8_t A = (Vref1 > 0) ? 1 : 0; uint8_t B = (Vref2 > 0) ? 1 : 0; uint8_t C = (Vref3 > 0) ? 1 : 0; uint8_t N = A + 2*B + 4*C; switch(N) { case 3: return 1; case 1: return 2; case 5: return 3; case 4: return 4; case 6: return 5; case 2: return 6; default: return 1; } }然后是作用时间计算,同样用Q15:
// 输入:Valpha, Vbeta, Ts, Udc // 输出:T1, T2 void Calc_Time(int16_t Valpha, int16_t Vbeta, int16_t Ts, int16_t Udc, int16_t *T1, int16_t *T2, int16_t sector) { int16_t X = (int16_t)((1.732f * Ts * Vbeta) / Udc); int16_t Y = (int16_t)((Ts * (1.732f * Vbeta + 3.0f * Valpha)) / (2.0f * Udc)); int16_t Z = (int16_t)((Ts * (1.732f * Vbeta - 3.0f * Valpha)) / (2.0f * Udc)); switch(sector) { case 1: *T1 = -Z; *T2 = X; break; case 2: *T1 = Z; *T2 = Y; break; case 3: *T1 = X; *T2 = -Y; break; case 4: *T1 = -X; *T2 = Z; break; case 5: *T1 = -Y; *T2 = -Z; break; case 6: *T1 = Y; *T2 = -X; break; } // 过调制处理 if(*T1 + *T2 > Ts) { *T1 = (*T1 * Ts) / (*T1 + *T2); *T2 = (*T2 * Ts) / (*T1 + *T2); } }这段代码在STM32F103C8上跑,主频72MHz,一个PWM周期内完成所有计算,耗时约8微秒。10kHz载波周期是100微秒,CPU占用率约8%,完全够用。
注意:过调制处理那一段很关键。如果不做限幅,当目标矢量超出六边形内切圆时,T1+T2会超过Ts,导致PWM占空比计算出错,电机电流会突然畸变。我见过有人调试时电机突然“咯噔”一下,就是这个问题。
4.3 5段式与7段式开关序列的代码编排
7段式的开关序列编排,以扇区1为例:
// 7段式,扇区1 // 顺序:V0 -> V1 -> V2 -> V7 -> V2 -> V1 -> V0 Ta = (Ts - T1 - T2) / 4; // V0作用时间的一半 Tb = Ta + T1 / 2; Tc = Tb + T2 / 2; Td = Tc + (Ts - T1 - T2) / 2; // V7作用时间 // 比较值:Ta, Tb, Tc, Td, Tc, Tb, Ta5段式的开关序列编排,同样扇区1:
// 5段式,扇区1,只用V0 // 顺序:V0 -> V1 -> V2 -> V1 -> V0 Ta = (Ts - T1 - T2) / 2; // V0作用时间 Tb = Ta + T1 / 2; Tc = Tb + T2 / 2; // 比较值:Ta, Tb, Tc, Tb, Ta可以看到5段式的比较值数量少了两个,计算量略小,但更重要的是开关次数少了。实际写代码的时候,我建议把两种方式的比较值生成写成两个独立函数,通过宏定义切换,方便对比测试。
4.4 实测波形与谐波数据对比
先看低速轻载工况(500rpm,0.5A,载波10kHz)。7段式的相电流波形比较干净,FFT分析THD为4.2%,主要谐波在10kHz附近,低频段(100Hz到1kHz)的谐波分量很小。5段式的THD为5.8%,低频段出现了明显的2次和4次谐波,幅值比7段式高了约6dB。
中速中载工况(1500rpm,1.5A,载波10kHz)。7段式THD为5.1%,5段式THD为7.3%。差距拉大了,因为电流增大后,死区效应的影响更明显,5段式由于波形不对称,死区导致的低频谐波更难被抵消。
高速重载工况(2800rpm,2.5A,载波10kHz)。7段式THD为6.8%,5段式THD为8.9%。这时候两者的差距又缩小了一点,因为高速下反电动势增大,调制比接近1,零矢量作用时间变短,两种方式的差异被压缩。
开关损耗方面,用示波器测IPM模块的开关波形,估算下来5段式比7段式低约30%,和理论值吻合。在20kHz载波下,这个损耗差异更明显,5段式的温升比7段式低了约8摄氏度。
| 工况 | 调制方式 | THD | 开关损耗估算 | 低频谐波 |
|---|---|---|---|---|
| 500rpm/0.5A | 7段式 | 4.2% | 基准 | 低 |
| 500rpm/0.5A | 5段式 | 5.8% | -30% | 较高 |
| 1500rpm/1.5A | 7段式 | 5.1% | 基准 | 低 |
| 1500rpm/1.5A | 5段式 | 7.3% | -30% | 较高 |
| 2800rpm/2.5A | 7段式 | 6.8% | 基准 | 中 |
| 2800rpm/2.5A | 5段式 | 8.9% | -30% | 中 |
5. 零序注入与过调制:谐波优化的进阶手段
5.1 零序注入SVPWM的原理与实现
零序注入是SVPWM的一个变种,思路是在三相参考电压上叠加一个零序分量,使得调制波的峰值降低,从而扩大线性调制区。常见的零序注入有两种:一种是注入三次谐波,另一种是注入基于中点电压的零序分量。
三次谐波注入的做法很简单:在每相参考电压上加上一个幅值为参考电压峰值1/6的三次谐波。这样调制波的峰值可以降低约15%,母线电压利用率进一步提高。实测中,零序注入SVPWM的THD比标准SVPWM低约0.5到1个百分点,尤其是在调制比接近1的时候效果明显。
代码实现上,就是在计算出三相占空比之后,加上一个零序分量:
// 零序注入 int16_t Vmax = max(Ta, max(Tb, Tc)); int16_t Vmin = min(Ta, min(Tb, Tc)); int16_t Voffset = -(Vmax + Vmin) / 2; Ta += Voffset; Tb += Voffset; Tc += Voffset;这段代码在DSP28379上跑浮点,效果很好。在STM32F103上跑定点,需要注意溢出问题,建议用Q14格式留出余量。
5.2 过调制区的谐波变化与处理策略
当调制比超过0.907时,目标矢量会超出六边形内切圆,进入过调制区。这时候如果还按线性区的公式算T1和T2,会出现T1+T2>Ts的情况,必须做限幅处理。
限幅的策略有两种:一种是等比缩放,把T1和T2按比例缩小到T1+T2=Ts;另一种是保持矢量角度不变,只缩小幅值。等比缩放实现简单,但会引入相位误差;保持角度的方法更精确,但计算量大。
实测中,过调制区的THD会急剧上升,7段式在调制比0.95时THD可能到10%以上,5段式更高。这时候零序注入的效果也有限,因为已经超出了线性区。我的建议是尽量避免长时间工作在过调制区,如果必须用,优先选7段式,谐波特性相对好一些。
实操心得:过调制区的限幅处理一定要做,而且要在T1和T2计算完之后立刻做,不要等到占空比计算的时候再做。我见过有人在占空比阶段限幅,结果三相占空比不再满足SVPWM的合成关系,电流波形直接畸变。
6. 常见问题与排查技巧实录
6.1 扇区判断错误导致的电流畸变
扇区判断错误是最常见的问题,表现是电机电流波形出现周期性畸变,严重时电机会抖动甚至堵转。排查方法很简单:在代码里把扇区号输出到DAC或者PWM引脚,用示波器看扇区切换是否平滑。正常的扇区切换应该是1→2→3→4→5→6→1循环,如果出现跳变或者卡在某个扇区,就是判断逻辑有问题。
常见原因有三个:一是Vα和Vβ的符号搞反了,二是公共量X、Y、Z的计算公式抄错了,三是过调制限幅把T1和T2改得面目全非,导致合成矢量角度偏移。我建议在调试阶段先把过调制限幅去掉,确认线性区正常后再加回来。
6.2 死区效应引起的低频谐波
死区效应是5段式和7段式都会遇到的问题,但5段式更严重。死区时间设了1微秒,在10kHz载波下,死区导致的电压误差约占母线电压的1%。这个误差会在电流过零点附近造成波形畸变,产生5次和7次谐波。
补偿方法有两种:一种是基于电流方向的死区补偿,根据相电流的正负调整占空比;另一种是基于电压误差的死区补偿,直接在一个PWM周期内补偿固定的电压量。我实测下来,基于电流方向的方法效果更好,但需要在电流过零点附近做平滑处理,否则会引入额外的谐波。
6.3 开关损耗与温升的平衡取舍
5段式开关损耗低,但谐波差;7段式谐波好,但损耗高。怎么选?我的经验是看载波频率和散热条件。如果载波频率在10kHz以下,散热条件好,优先选7段式,谐波优势明显。如果载波频率在15kHz以上,或者散热条件受限,选5段式,损耗优势能换来更低的温升和更高的可靠性。
还有一个折中方案:在低速区用7段式,高速区用5段式,通过转速或者调制比切换。这样既能保证低速时的谐波特性,又能降低高速时的开关损耗。切换点建议设在调制比0.7左右,切换时要做平滑过渡,避免转矩突变。
| 问题现象 | 可能原因 | 排查方法 | 解决措施 |
|---|---|---|---|
| 电流周期性畸变 | 扇区判断错误 | 示波器看扇区号 | 检查Vα/Vβ符号和公共量公式 |
| 电流过零点畸变 | 死区效应 | 放大看电流过零点 | 加死区补偿 |
| 电机抖动 | 过调制限幅不当 | 检查T1+T2是否超Ts | 等比缩放限幅 |
| 温升过高 | 开关损耗大 | 测开关波形 | 改用5段式或降载波频率 |
| THD偏高 | 零矢量使用不当 | FFT分析 | 改用7段式或加零序注入 |
7. 我的选型建议与实操体会
折腾了这么多轮测试,我现在的做法是:默认用7段式,载波频率设10kHz,加零序注入,过调制区做等比缩放限幅。这套组合在大多数工况下THD能控制在5%以内,开关损耗也能接受。只有在载波频率超过15kHz或者散热条件特别紧张的时候,才切到5段式,同时把载波频率降到12kHz左右,平衡一下谐波和损耗。
还有一个小技巧:在代码里把5段式和7段式做成可切换的,通过上位机或者拨码开关选择。调试阶段可以随时对比,找到最适合当前工况的调制方式。我试过在DSP28379上跑这套切换逻辑,切换过程做10个PWM周期的过渡,转矩波动几乎看不出来。
最后说一个容易被忽略的点:SVPWM的谐波优化不只是调制方式的问题,电流环带宽、采样时机、死区补偿都会影响最终效果。我见过有人把7段式换成5段式,THD反而降了,原因是原来的7段式代码里死区补偿没做好,换了5段式之后死区效应的影响模式变了,恰好避开了原来的问题。所以调试的时候要系统性地看,不要只盯着调制方式这一个变量。