做FOC时间久了,你会发现一个很有意思的现象:电流环输出Ud、Uq之后,怎么把这些电压指令变成三相桥臂上具体的导通时间,不同人的做法差别很大。有人习惯传统SVPWM,扇区判断、查表、算切换点,中断里跑得满头大汗;有人却只用几行代数运算,就能生成效果完全一致的PWM波形。后者用的就是三投影法。今天我把三投影法的基本原理和三相电压作用时间的计算过程完整拆开,讲清楚它为什么能替代传统SVPWM,以及在写代码和调波形时到底该注意哪些细节。这篇文章适合正在做PMSM FOC控制、对PWM调制环节还想深入一层的中高级开发者和相关专业学生。
1. 为什么选择三投影法:从传统SVPWM的痛点说起
1.1 传统SVPWM每一步都在做什么
传统SVPWM的核心思想是伏秒平衡。控制周期Ts内,期望电压矢量Uref不是直接加在电机上的,而是用两个相邻的基本电压矢量和一个或多个零矢量,按时间比例合成出来。具体分四步:先把Uα、Uβ折算到三相坐标系,根据坐标符号判断所处扇区;接着计算中间变量X、Y、Z,再根据扇区查表选出T1、T2;然后算出切换点Ta、Tb、Tc;最后把切换点映射到具体的定时器比较通道上。每个周期还要重置扇区标志、数组索引,一大堆条件分支。
这套流程有一个比较隐蔽的工程问题:分支多,执行时间不稳定,而且做除法的时候必须特别小心边界条件。比如Uβ刚好为零、或者扇区边界附近符号抖动时,容易造成相邻周期的PWM波形不对称。虽然这些都可以通过代码规避,但维护成本不低。
1.2 三投影法是怎么另辟蹊径的
三投影法的思路完全不一样。它不做扇区判断,也不查表。核心动作只有一个:把期望电压矢量分别投影到A、B、C三相的坐标轴上,直接得到每相应该输出的相电压参考值。这个投影在数学上只是两个乘法和一个加法,不存在任何分支。
为什么可以这样做?因为三相桥臂本来就是独立的电压源,每相都可以输出任意占空比对应的平均电压。只要这三相平均电压在线电压层面等于Uref,系统就是等效的。换句话说,传统SVPWM是先定两个非零矢量的作用时间,再推导三相占空比;三投影法是直接跳过矢量概念,从电压投影一步到位。两条路线殊途同归,但从代码和执行效率来说,三投影法的优势非常明显,尤其适合开关频率高、中断周期短、MCU算力不太充裕的场景。
2. 三投影法的数学原理与公式推导
2.1 坐标变换里的那些系数约定
说到三投影法之前,必须先把坐标变换的系数约定说清楚。电机控制里Clark变换有两种常见约定:一种是等幅值变换,一种是等功率变换。三投影法本身并没有强制要求用哪一种,但反Park变换输出的Uα、Uβ必须和后续投影公式保持一致。
通常FOC代码里,电流采样做完Clark变换之后,αβ轴上的电流幅值等于相电流幅值,这就是等幅值约定。电流环整定出来的Ud、Uq,经过反Park变换得到的Uα、Uβ,也应当保持“合成电压矢量幅值等于相电压幅值”的性质。在这个约定下,三相相电压参考可以直接用投影公式得到,不需要额外的2/3或3/2倍系数。如果你在别人的代码里看到多乘了一个系数,可以先检查他的Clark变换系数约定是不是不一样,这个坑很容易让人调半天。
2.2 投影公式的完整推导
先看坐标关系。A相绕组轴线定义为零度方向,B相滞后A相120度,C相滞后A相240度,也就是超前120度。α轴与A轴重合,β轴超前α轴90度。假设反Park输出为Uα、Uβ,那么期望电压矢量在αβ平面上就是一条从原点出发、长度为|Uref|的矢量。
把这个矢量往A轴上投影,投影长度就是Uα本身,因为A轴和α轴重合:
Va_proj = Uα
往B轴上投影,B轴的单位方向在αβ平面里是(-0.5, 0.866)。向量点乘之后得到:
Vb_proj = -0.5 × Uα + 0.866 × Uβ
往C轴上投影,C轴单位方向是(-0.5, -0.866),所以:
Vc_proj = -0.5 × Uα - 0.866 × Uβ
这就是三投影法的核心代数式。三个投影值VA、VB、VC之和恒等于零,说明它们只是一组纯交流分量,不含共模分量。
2.3 零序注入与中心对称处理
VA、VB、VC直接转成占空比能不能用?可以,但电压利用率不是最优。三相逆变器的最大不失真相电压幅值在SVPWM下可以做到Vdc/√3,而直接使用VA、VB、VC并把占空比限制在[0,1]时,最大相电压幅值只能到Vdc/2,相对减小了约13.4%。传统SVPWM之所以能提高电压利用率,是因为它在三相参考电压上注入了一个零序分量,把每相参考电压整体抬高或压低,从而让三相占空比都能落在合理区间。
三投影法也可以用同样的方式处理。最常见的做法是中心对称注入,也叫min-max注入:
offset = -0.5 × (max(VA, VB, VC) + min(VA, VB, VC))
然后把offset加到三相参考电压上。这样处理后,三相参考电压的最大值和最小值关于零点对称,占空比的中心也落在0.5附近。有人会问,零序注入会不会改变电机的相电压?不会。电机三相绕组构成的系统没有中线,零序电压不会在绕组上产生电流,真正决定电流的是线电压。只要三相参考电压两两之间的差值不变,电机上得到的电压就和没注入零序时完全一样。
3. 三相电压作用时间的计算:从参考电压到PWM占空比
3.1 逆变器桥臂的平均电压模型
三相电压作用时间,其实就是每个PWM周期里,上桥臂MOSFET导通的时间长度Ton。要算Ton,先得知道占空比D。对于一只桥臂,假设上管导通时输出点相对直流母线负极为Vdc,下管导通时为0V。如果参考电压是相对直流母线中点来说的,那么中点电位就是Vdc/2,桥臂输出的平均电压为:
Vx_avg = D × Vdc - Vdc/2 = (D - 0.5) × Vdc
反解占空比:
D = 0.5 + Vx_avg / Vdc
这一步就是把三投影法算出的三相参考电压映射到时间量的关键公式。之前投影出来的VA、VB、VC,此时就作为Vx_avg代入。注意这里Vx_avg必须是一个相对母线中点的电压,而且它的绝对值不能超过Vdc/2,超出部分就是过调制区。
3.2 作用时间的伏秒平衡表达
得到占空比之后,导通时间就是:
Ton = D × Ts
其中Ts是PWM开关周期,也就是PWM频率的倒数。如果Ts = 100us,D = 0.6,那么这一相上桥臂在这个周期内导通60us,下桥臂导通40us。三相的Ton并不独立,因为三相参考电压经过零序注入后,三相占空比之和通常不等于1.5,而是1.5加零序偏移量除以Vdc后的结果。你不要去怀疑“占空比之和为什么不是1.5”,那正是零序分量的体现。
三相电压作用时间也不一定都要在区间[0, Ts]内。如果D小于0或者大于1,实际已经超出了线性调制区,需要做限幅或者过调制处理。正常FOC运行在低速和额定速度以内时,电流环输出的Ud、Uq幅值不会超过Vdc/√3,占空比一般不会饱和。
3.3 定时器比较值的换算与采样时机
MCU的PWM定时器一般用中心对齐模式。定时器输出比较寄存器CCR决定的是翻转时刻,把占空比换算成CCR时,不同厂家、不同定时器极性有差异。比如有些芯片里,占空比和CCR的关系可以写成:
CCR = ARR × (1 - D)
或
CCR = ARR × D
具体取决于有效电平定义和计数方向。我的建议是不要死记公式,而是用一个基准信号做一次示波器标定:给一个固定的D值,看高电平时间对不对,不对就调整公式。这个操作只要一次,之后公式就稳定了。
采样时机方面,中心对齐PWM在三角波的顶点和底点处,三相桥臂处于一种固定的开关状态,非常适合触发ADC电流采样。因为此时电流等于直流母线电流的某一路径组合,对应某一相的相电流。所有FOC基本都采用顶点采样或底点采样,三投影法在这里和传统SVPWM没有任何区别。
4. 手算实例:用一组数据走完整条链路
4.1 初始条件与反Park输出
光讲公式不够直观,我拿一组真实可验证的数据走一遍全流程。假设母线电压Vdc = 300V,开关周期Ts = 100us,也就是10kHz。某一个控制周期里,电流环输出的Ud、Uq经过反Park变换后得到Uα = 120V,Uβ = 80V。这两个量已经包含了当前电角度信息。合成矢量幅值为:
|Uref| = sqrt(120² + 80²) = 144.22V
这个值小于Vdc/√3 = 173.2V,所以工作在线性区,三投影法可以直接输出正常占空比。
4.2 逐步计算三相参考电压、零序和占空比
第一步,计算三相投影参考电压:
VA = 120V
VB = -0.5 × 120 + 0.866 × 80 = -60 + 69.28 = 9.28V
VC = -0.5 × 120 - 0.866 × 80 = -60 - 69.28 = -129.28V
此时三相参考电压之和为0,符合预期。第二步,做中心对称零序注入:
max = 120V
min = -129.28V
offset = -(120 + (-129.28)) / 2 = 4.64V
注入零序后:
VA' = 124.64V
VB' = 13.92V
VC' = -124.64V
第三步,换算占空比:
DA = 0.5 + 124.64 / 300 = 0.9155
DB = 0.5 + 13.92 / 300 = 0.5464
DC = 0.5 - 124.64 / 300 = 0.0845
第四步,计算导通时间:
Ton_A = 0.9155 × 100us = 91.55us
Ton_B = 0.5464 × 100us = 54.64us
Ton_C = 0.0845 × 100us = 8.45us
三相占空比都在[0,1]内,没有饱和。如果看线电压,A-B之间瞬时输出电压为:
Vab = (DA - DB) × Vdc = (0.9155 - 0.5464) × 300 = 110.73V
这符合当前相位下相电压矢量幅值为144.22V时线电压瞬时值的合理范围。
4.3 与扇区式SVPWM输出对比
把同样的Uα = 120V、Uβ = 80V丢进传统SVPWM,先算扇区,60度以内属于第一扇区。然后算相邻矢量作用时间,再用七段式安排每个切换点,最终得到的占空比结果和上面三投影法的结果完全一致。这里的关键点是,只要零序注入策略选取一致,三投影法和传统SVPWM在数值上就是严格等价的。
所以要怎么选?如果你是在学习原理、写文档、讲课,传统SVPWM的矢量图更直观;如果是在MCU上追求稳定执行时间和简单代码,三投影法更省心。我自己在实际项目里基本都是用三投影法,配合中心对齐定时器,极大减少了中断里的运算量和分支跳变。
5. 工程实现中的补偿问题:三投影法踩坑实录
5.1 死区时间如何补偿
PWM输出必然有死区,否则上下桥臂会直通。死区会带来一个很实际的后果:实际输出电压平均值比指令值偏小,而且带有与电流方向相关的非线性。三投影法本身不会自动消除这个误差,需要额外做死区补偿。
最简单的补偿方法是电流极性判断。理想情况下,如果某相电流为正,死区时间产生的影响方向是确定的,占空比需要加上一个固定补偿量;电流为负,方向相反。补偿增量可以估算为:
delta_D = DeadTime / Ts
对应的电压补偿量大约为:
delta_V = (DeadTime / Ts) × Vdc
具体加还是减,取决于桥臂结构和电流定义方向。我的经验是先用固定补偿值跑起来,看相电流波形里的削顶畸变和过零附近的台阶。如果补偿方向正确,波形明显平滑;如果方向反了,畸变更重,把符号反过来即可。不要指望一次就完美,死区补偿是个需要从波形反馈里反复确认的过程。
5.2 母线电压波动与管压降处理
母线电压Vdc不是恒定不变的,尤其电池供电或者整流电压带纹波比较大的场合。占空比计算时必须使用实时检测到的Vdc,不能用一个固定常量,否则指令电压和实际输出不匹配,电流环会莫名抖动。三投影法在代码上只需要把Vdc变量改成ADC实时采样值,这是它比查表SVPWM更自然的优势之一。
另外一个容易被忽略的量是功率管压降。MOSFET导通电阻产生的压降,在大电流时能达到好几伏特。如果对低速力矩精度要求很高,可以在占空比上叠加一个与电流方向相关的校正项。这个校正项不是固定死区那样近似方波,而是跟电流大小成比例的,实际调的时候可以先用死区补偿加电流方向判断,再决定要不要上线性压降模型。
5.3 过调制和最小脉宽限制
三投影法输出占空比一旦超过[0,1],就进入了过调制区。简单的做法是直接饱和,但直接饱和会导致线电压波形产生削顶失真,也就是相电流的高次谐波成分增多。如果你只是把它当应急手段,比如最高转速附近稍微超过一点线性区,用简单饱和问题不大。但如果你希望保留完整的过调制能力,一般需要把超出六边形区域的电压矢量拉回到六边形边界上,这相当于一个矢量限幅器,实现复杂度明显上升。
还有一个工程细节是“最小脉宽限制”。当某相占空比很接近0或者很接近1时,器件的开关脉冲宽度会小于功率管的开关特性要求,导致波形无法正常传输。常规做法是把占空比限制在比如0.05到0.95之间。代价是牺牲一点最大输出能力,通常可以通过提高母线电压或者调整控制策略来弥补。
6. 调试方法与实践建议
6.1 开环正弦表先跑通三投影法
我的经验是,首次做三投影法验证,不要直接上FOC闭环,先开环发一组三相对称正弦波,把调制环节单独验证掉。做法很简单:让Uα = Vp × cos(θ_m),Uβ = Vp × sin(θ_m),θ_m按时匀速递增,Vp给一个安全值,比如Vdc × 0.2。用三投影法转成占空比后输出到三相桥臂,不接电机或者接一个电阻负载即可,示波器观察输出端相对母线的电压波形。
如果三投影像计算的占空比没有问题,你会在每个桥臂中点看到正弦调制的PWM脉宽变化。再把线电压波形看一遍,Uab、Ubc都是光滑的正弦包络,没有断续和台阶。这一步跑通了之后,再接电机做FOC闭环,可以把调制环节的问题从电流环问题里隔离出来。
6.2 常见波形异常排查
调试中我遇到过几种典型的波形异常,整理成表格方便对照:
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 相电压PWM脉宽不对称 | 零序注入算法写错或扇区边界抖动 | 检查offset计算与三相参考电压代数式 |
| 母线电流出现6倍频纹波 | 占空比饱和或过调制处理不当 | 降低电压指令幅值,临时代偿测试 |
| 低速大电流时电流波形台阶状 | 死区补偿方向或补偿量不合适 | 对比不同补偿方向的电流THD |
| 高速时电压输出突然畸变 | Vdc采样滞后或滤波时间过长 | 用实时Vdc,缩短采样滤波窗口 |
| 空载电流有固定频率尖峰 | 最小脉宽限制未加或开关时刻采样窗口太短 | 限制占空比范围,检查ADC触发点 |
6.3 关于代码结构的一点建议
三投影法本身只有三行代数的活,但工程代码里可以把它封装成一个独立的调制模块,输入是Uα、Uβ、Vdc,输出是三相比值或CCR。这样做的好处是,不管上层用的是VF控制、电流闭环还是无感观测器,只要最后给出Uα、Uβ,调制模块都可以复用。同时也可以把“零序注入”“死区补偿”“过调制限幅”作为独立可裁剪的配置项,调试时逐项开关,方便定位问题。
我自己在迁移传统SVPWM到三投影法时,做过一个很小的实验平台,用同一个电压指令分别跑两种调制器,对比相电流FFT。结果显示,在相同死区补偿参数下,三投影法的谐波分布和传统七段式SVPWM几乎一致。从那之后我再也没有纠结过扇区判断和查表,因为三投影法用更简单的代码得到了等价的性能。
最后再分享一个小技巧:如果你担心零序注入的浮点运算耗时,可以把offset计算简化成只看三相电压的最大值和最小值,而这两个值在三相正弦情况下是有明确规律的,完全可以用比较器硬件加速或者查表实现。实际跑下来,三投影法的计算时间通常只是传统SVPWM的一半左右,省出来的时间留给电流环或观测器,非常划算。