从SPWM到SVPWM:高性能电机FOC控制的核心调制技术详解

从SPWM到SVPWM:高性能电机FOC控制的核心调制技术详解 1. 从SPWM到SVPWM为什么我们需要换一种思路调制搞电机控制尤其是玩FOC磁场定向控制的朋友绕不开的一个核心环节就是PWM调制。你可能听说过SPWM正弦脉宽调制它简单直观就是把一个正弦波和三角载波比较生成占空比按正弦规律变化的PWM波。在早期逆变器和一些对性能要求不高的场合SPWM确实够用。但当你真正想把一个永磁同步电机PMSM或者无刷直流电机BLDC的性能榨干追求更高的电压利用率、更低的谐波和更精准的矢量控制时SPWM就显得有些力不从心了。这里就引出了SVPWM空间矢量脉宽调制。我第一次接触SVPWM时也被那一堆扇区、矢量、作用时间计算搞得头大。但后来想明白了SVPWM本质上是一种更“聪明”的调制策略。它不再盯着三相独立的波形而是把三相逆变器输出的八个基本电压矢量六个有效矢量两个零矢量看作一个整体在一个复平面α-β坐标系上玩拼图。我们的目标就是用这八个基本矢量去合成任意一个我们期望的电压空间矢量。这种思维方式天然就和FOC中在α-β坐标系下计算出的电压指令Uα和Uβ完美对接。最直观的好处有两个一是直流母线电压利用率更高。理论上SVPWM能比SPWM的电压利用率高出约15.5%。这意味着同样的电池电压SVPWM能让电机转出更高的转速或者输出更大的转矩相当于把电源的“每一滴油”都榨干了。二是谐波特性更好电流波形更正弦电机运行起来噪音更小效率也更高。所以在追求高性能的FOC系统中SVPWM几乎是标配。2. SVPWM的核心原理八个矢量与扇区拼图要理解SVPWM我们必须先忘掉U、V、W三相独立的视角进入α-β坐标系的“上帝视角”。一个三相逆变桥上下桥臂不能同时导通所以每相的输出对直流母线负端N的电压只能是Vdc或0。这样三相组合起来就有2^3 8种开关状态。每一种开关状态对应一个基本的电压空间矢量。我们通常用[A, B, C]来表示上桥臂的导通状态1代表导通0代表关断。例如[1,0,0]表示A相上桥臂开下桥臂关此时A相输出VdcB、C相输出0。这八个矢量如下开关状态 [A, B, C]电压矢量符号α轴分量 (Uα)β轴分量 (Uβ)[0,0,0]V000[1,1,1]V700[1,0,0]V1(2/3) * Vdc0[1,1,0]V2(1/3) * Vdc(√3/3) * Vdc[0,1,0]V3-(1/3) * Vdc(√3/3) * Vdc[0,1,1]V4-(2/3) * Vdc0[0,0,1]V5-(1/3) * Vdc-(√3/3) * Vdc[1,0,1]V6(1/3) * Vdc-(√3/3) * Vdc注意这里的系数2/3是等幅值变换的系数也有用等功率变换系数的但在SVPWM合成中我们更关心矢量的相对比例最终会归一化处理所以系数选择不影响最终合成逻辑。V0和V7是零矢量它们的作用是“填充时间”不产生有效的电机转矩。另外六个矢量V1到V6幅值相等相位依次相差60度均匀地分布在复平面上把整个平面分成了六个扇区Sector I 到 VI。SVPWM要解决的问题是给定一个目标电压矢量Uref由FOC的电流环输出Uα, Uβ构成它落在哪个扇区然后用这个扇区相邻的两个基本矢量比如扇区I就用V1和V2以及零矢量按照“伏秒平衡”的原则在一个PWM周期Ts内合成它。“伏秒平衡”是核心V1的作用时间T1乘以V1加上V2的作用时间T2乘以V2再加上零矢量的作用时间T0其矢量和应该等于Uref * Ts。用公式表示就是Uref * Ts V1 * T1 V2 * T2 V0 * T0(或V7 * T0) 其中T1 T2 T0 Ts。接下来的任务就是根据Uref的坐标(Uα, Uβ)计算出它所在的扇区以及T1和T2。3. 扇区判断与作用时间计算一步步拆解这是SVPWM算法里最需要厘清的部分很多代码看起来复杂但拆解后逻辑很清晰。我们假设Uα和Uβ是已知的来自电流环PI控制器的输出。3.1 扇区判断三个中间变量的妙用我们定义三个中间变量A, B, CA Uβ B (√3 * Uα - Uβ) / 2 C (-√3 * Uα - Uβ) / 2然后再定义三个判断变量U1 (A 0) ? 1 : 0 U2 (B 0) ? 1 : 0 U3 (C 0) ? 1 : 0最后扇区号N可以通过一个简单的公式得到N U1 2*U2 4*U3计算出的N值对应关系为N3- 扇区 IN1- 扇区 IIN5- 扇区 IIIN4- 扇区 IVN6- 扇区 VN2- 扇区 VI。这个方法的几何意义是用A, B, C的正负来判断Uref矢量位于哪两条60度分隔线的哪一侧从而唯一确定扇区。这是我实践下来最稳定、计算量也较小的方法避免了复杂的反正切计算。3.2 作用时间计算扇区归一化处理不同扇区的计算看似不同但其实可以通过坐标变换统一到第一扇区I来处理这样代码会非常简洁。我们定义两个中间时间变量X和YX (√3 * Ts / Vdc) * Uβ Y (√3 * Ts / Vdc) * ( (√3/2) * Uα (1/2) * Uβ ) Z (√3 * Ts / Vdc) * ( (-√3/2) * Uα (1/2) * Uβ )注意这里的Vdc是直流母线电压Ts是PWM周期。X, Y, Z对应了某种投影关系。然后根据前面判断出的扇区N我们按下面这个表来分配T1和T2扇区IIIIIIIVVVIT1-ZZX-X-YYT2X-YYZ-Z-X注意这里计算出的T1和T2可能是负数也可能加起来超过Ts。所以必须进行饱和处理如果T1 T2 Ts则需要按比例缩放T1 T1 * Ts / (T1T2),T2 T2 * Ts / (T1T2)。缩放后T0 Ts - T1 - T2。这个表需要死记硬背吗完全不用。它的本质是在任何扇区我们总是选择该扇区对应的两个相邻基本矢量并将目标矢量Uref分解到这两个矢量的方向上。上面的X, Y, Z和查表法只是这种几何分解的一种快速计算实现。理解了这个你甚至可以自己推导出每个扇区的公式。4. 七段式与五段式PWM波形生成的两种编排艺术算出了T1,T2,T0怎么把它们变成实际控制六个功率管MOSFET/IGBT的PWM信号呢这里就有两种主流的编排方式七段式和五段式也叫中心对齐和边缘对齐。4.1 七段式SVPWM中心对齐这是最常用、特性最好的一种方式。在一个PWM周期Ts内开关状态变化七次因此得名。它对称地安排两个有效矢量和一个零矢量的作用顺序并且每个桥臂的PWM波形都是中心对称的。以扇区I为例其开关序列为V0(000) - V1(100) - V2(110) - V7(111) - V2(110) - V1(100) - V0(000)。它的优点非常突出谐波特性最优因为波形对称谐波能量主要集中在开关频率的偶数倍附近而电机绕组本身是感性负载对高频谐波有很好的滤波作用因此实际电流的纹波更小正弦度更好。开关损耗相对均衡每个周期内每个功率管只开关一次总开关次数固定便于散热设计。与定时器中心对齐模式完美匹配像STM32的高级定时器其中心对齐计数模式Up-Down天生就是为了生成这种对称的PWM波形而设计的配置起来非常方便。具体如何将T1, T2, T0转化为比较寄存器的值呢我们通常将零矢量时间T0平分两半放在周期开头和结尾。那么对于三相比较寄存器CCR_A,CCR_B,CCR_C对应A、B、C三相在扇区I的计算公式为T_CM1 T0 / 4 T_CM2 T_CM1 T1 / 2 T_CM3 T_CM2 T2 / 2然后赋值假设计数器从0向上计数到ARR再向下计数ARR对应Ts/2CCR_A (T_CM1 T_CM2 T_CM3) / 2等等这里容易出错。更通用的方法是先计算各相高电平的切换点时间。对于七段式我们需要计算三个时间点Ta, Tb, Tc。在扇区ITa (Ts - T1 - T2) / 4 // 第一个切换点 Tb Ta T1 / 2 // 第二个切换点 Tc Tb T2 / 2 // 第三个切换点然后根据中心对齐模式比较寄存器的值应设置为Tc因为波形是从低到高再到低Tc是第一个下降沿点。但实际操作中我们常直接计算占空比。一个更稳妥的实践是定义T1, T2为对应矢量的半周期作用时间因为中心对齐模式一个矢量会作用两次那么CCR_A (Ts - T1 - T2) / 2 CCR_B CCR_A T1 CCR_C CCR_B T2这个公式需要根据扇区进行变换。网上有很多现成的“扇区-比较值”对应表我建议在初期直接采用并充分测试。理解其对称性原理后可以尝试自己推导。4.2 五段式SVPWM边缘对齐五段式在一个周期内开关状态变化五次。同样以扇区I为例序列为V1(100) - V2(110) - V7(111) - V2(110) - V1(100)。可以看到它少用了两个零矢量V0。它的特点是开关损耗更低每个周期每个管子还是开关一次但有些序列下开关次数分布可能不均。计算和实现稍简单。谐波特性略差于七段式因为波形不对称。可与定时器边缘对齐模式配合。在大多数对电流波形质量要求高的FOC应用如伺服、无人机电调中七段式是首选。它的电流纹波和噪音表现明显更好。五段式可能在一些对开关损耗极度敏感的超高频开关场合会考虑。5. 代码实现与工程实践从公式到寄存器理论通了最终要落地到代码。这里以STM32系列MCU的高级定时器如TIM1, TIM8为例分享我的实现步骤和坑点。5.1 基础配置定时器模式配置为中央对齐模式1Up-Down counting。ARR寄存器设置为PWM周期值例如20kHz开关频率系统时钟72MHz预分频PSC0则ARR 72e6 / (20e3 * 2) - 1 1799。PWM输出通道配置三个通道CH1, CH2, CH3为PWM模式1或2输出极性根据你的硬件驱动逻辑设定是高电平有效还是低电平有效这决定了互补输出的死区插入方式。务必使能预装载寄存器。死区时间至关重要必须根据你使用的MOSFET/IGBT驱动芯片的导通/关断时间设置合适的死区时间Dead Time防止上下桥臂直通烧管。在STM32中通过BDTR寄存器的DTG位设置。刹车功能连接硬件过流保护信号如通过比较器到定时器的刹车输入确保故障时能快速关闭所有PWM输出。触发ADC采样利用定时器的更新事件UEV或比较事件CCx触发ADC对相电流进行同步采样。这是实现高精度FOC的关键。通常选择在PWM周期中心点计数器为0或ARR时采样此时电流纹波最小采样值最准确。对于七段式中心点就是零矢量作用的中点。5.2 SVPWM算法函数你需要实现一个函数输入是Uα和Uβ通常来自电流环PI控制器的输出且经过了幅值限幅输出是三个比较寄存器值CCR1, CCR2, CCR3。步骤一标幺化与限幅Uα, Uβ是电压值我们需要将其转换为时间。首先进行标幺化处理将其缩放到-Umax ~ Umax之间其中Umax Vdc / √3这是SVPWM线性调制区的极限即六边形内切圆半径。如果Uref的幅值超过Umax就需要进行限幅Over Modulation过调制这里先不展开。 一种常见的做法是Ualpha Ualpha * K; // K是一个缩放系数与Vdc和PWM周期相关 Ubeta Ubeta * K;然后计算合成矢量幅值Umag sqrt(Ualpha*Ualpha Ubeta*Ubeta)如果Umag Umax则Ualpha Ualpha * (Umax/Umag); Ubeta Ubeta * (Umax/Umag);。步骤二扇区判断使用前面介绍的A, B, C和U1, U2, U3方法计算出扇区号Sector1~6。步骤三计算X, Y, Z和时间T1, T2T PWM_Period; // 对应定时器ARR值注意是半周期还是全周期这里假设为半周期值 X (SQRT3 * Ubeta) * T / Vdc; Y ( (SQRT3/2) * Ualpha (1/2) * Ubeta ) * SQRT3 * T / Vdc; Z ( (-SQRT3/2) * Ualpha (1/2) * Ubeta ) * SQRT3 * T / Vdc;根据扇区查表得到T1和T2。步骤四时间饱和处理if((T1 T2) T) { T1 T1 * T / (T1 T2); T2 T2 * T / (T1 T2); } T0 T - T1 - T2; // 零矢量总时间步骤五计算比较值对于七段式中心对齐模式我们需要计算三个时间点tA, tB, tC。不同的扇区这三个点与T1, T2, T0的关系不同。网上有标准的变换公式。这里给出一种常见的计算方式先计算uint32_t t1 (uint32_t)(T1 / 2); uint32_t t2 (uint32_t)(T2 / 2); uint32_t t0 (uint32_t)(T0 / 2); // 因为对称零矢量时间也平分然后根据扇区计算CCR值。例如对于扇区ICCR1_Val t0 t1 t2; CCR2_Val t0 t2; CCR3_Val t0;对于扇区IICCR1_Val t0 t1; CCR2_Val t0 t1 t2; CCR3_Val t0;... 以此类推。你需要为6个扇区准备6组赋值语句。最后将CCR1_Val, CCR2_Val, CCR3_Val写入对应的捕获比较寄存器。关键经验务必搞清楚你的T,T1,T2的时间单位和定时器计数器的对应关系。是微秒还是定时器计数值我强烈建议在算法内部全部使用“定时器计数单位”进行计算避免浮点运算。例如Vdc可以用ADC采样的原始值表示Ualpha/Ubeta也使用标幺化的整型数。整个SVPWM函数用定点数运算完成速度极快。5.3 过调制与弱磁突破电压极限当电机转速升高反电动势增大所需的Uref幅值可能超过SVPWM线性调制区的极限Umax。此时单纯的限幅会导致指令失真电流控制环路饱和。这时就需要引入过调制策略。过调制的核心思想是当Uref超出内切圆时不再保持其方向不变地缩放到圆上而是允许合成矢量的轨迹沿着六边形的边运动。这样在部分周期内实际输出的电压矢量幅值可以大于Umax从而提高了直流母线电压的利用率。实现过调制算法会更复杂一些需要修改T1, T2的计算规则通常是通过一个过调制因子来调整。当转速继续升高即使过调制也无法提供足够电压时就需要进入“弱磁”控制。弱磁的本质是通过注入负的d轴电流来抵消永磁体产生的磁场从而降低反电动势使得在现有电压下能驱动电机达到更高转速。FOC MTPA最大转矩每安培和弱磁通常是结合使用的先通过MTPA找到最优的id, iq组合在高速区再切换到弱磁控制。这部分是FOC算法中比较高级的话题需要精确的电机参数和观测器。6. 调试与问题排查让电机真正转起来算法写完下载到板子给电电机可能不转或者振动、异响。别慌按以下步骤排查先开环验证在闭环FOC跑起来之前一定要先验证SVPWM本身和驱动电路是否正确。写一个开环测试程序让Uref以一个恒定的幅值和缓慢递增的角度旋转例如每秒转一圈。用示波器测量电机三相线间的电压最好用差分探头应该能看到一个幅值恒定、频率缓慢增加的三相正弦波实际上是PWM调制后的马鞍波。同时观察相电流应该是平滑的正弦波。如果波形严重畸变或电流很大检查死区时间是否足够MOSFET驱动是否正常。检查扇区切换在开环旋转时可以在代码中打印当前的扇区号。它应该按1-2-3-4-5-6-1...的顺序平滑切换。如果出现跳变或不连续检查扇区判断算法和Uα, Uβ的计算。电流采样与对齐这是闭环能否稳定的重中之重。确保ADC的采样时刻在PWM周期的中心点七段式的零矢量中点。用示波器同时抓取一相PWM的高电平信号和该相电流采样ADC的触发信号确认触发点在PWM波形的中心。电流采样的硬件电路也要校准包括运放偏移、增益以及ADC本身的偏移。可以在电机静止时读取三相电流ADC值理论上应该接近零点如果有较大偏移需要在软件中补偿。观测器与启动对于无感FOC开环启动到切换闭环的瞬间是最容易失败的。确保开环启动阶段注入的电压矢量幅值足够克服静摩擦和负载频率递增要平滑。切换到闭环的时机很重要通常是在电机反电动势足够被观测器如滑模观测器、扩展卡尔曼滤波器可靠估算之后。扩展卡尔曼滤波EKF对电机参数和噪声统计特性比较敏感调参需要耐心。过流保护一定要实现可靠的硬件过流保护并在软件中做二次保护。STM32的FOC库中通常有MC_FOC_CurrProcessing函数里面会计算电流并检查是否过流。确保你的过流阈值设置合理并且保护反应速度够快。我个人的调试习惯是先用一个非常低的电压比如12V系统用5V和空载来调试这样即使出错也不容易烧器件。每一步都先用示波器看波形确保和理论一致再逐步增加电压和负载。SVPWM和FOC是一个系统性的工程任何一个环节的微小错误都可能导致整个系统失效耐心和细致的排查是关键。