ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SVPWM算法详解:从扇区判断到Matlab仿真,吃透电机控制核心

SVPWM算法详解:从扇区判断到Matlab仿真,吃透电机控制核心 搞电机控制、做伺服驱动、搞变频器的工程师几乎没有能绕过SVPWM的。刚接触那会儿看着一堆电压矢量扇区图、作用时间公式、七段式时序确实容易懵。但真正把原理吃透之后你会发现SVPWM不仅不难反而是理解PMSM矢量控制、三电平拓扑、甚至PWM整流器的一块关键踏板。这篇文章我把SVPWM的来龙去脉、每个扇区的中间变量推导、以及Matlab仿真怎么落地一次讲透。不堆公式但核心推导也不省尽量用说人话的方式把表格、代码和波形都给你适合刚入门电机控制的方向也适合已经有基础但想把扇区计算细节补齐的同学参考。1. 从一个逆变器的“力不从心”说起SVPWM到底解决了什么搞SVPWM之前先得搞清楚一件事三相逆变器的控制目标到底是什么桥臂只有上管和下管导通两种状态三个桥臂组合起来最多8个状态。可我们要输出的是一个旋转的圆形电压矢量。怎么用有限的开关状态逼近一个无限旋转的目标这就是SVPWM诞生的出发点。1.1 SPWM的天然缺陷电压利用率瓶颈传统SPWM正弦脉宽调制的思路很直觉让每相占空比按正弦规律变化再经过逆变器滤波后得到三相对称正弦电压。这个方案实现简单但有一个绕不开的缺点——母线电压利用率低。以定义相电压调制比 m Vph / (Vdc/2) 来看正弦调制下相电压峰值最多只能达到 Vdc/2。也就是说逆变器输送给电机的最大相电压有效值是 Vdc/(2√2)而线电压有效值就是 √3 × Vdc/(2√2) ≈ 0.612Vdc。很多教材直接说SPWM的直流电压利用率只有78.5%指的是逆变器输出线电压基波有效值与直流母线电压之比即 U_line / Vdc 0.612。剩下的能量去哪了并没有凭空消失而是因为正弦波顶峰处调制比接近1时占空比接近0或100%产生不了足够的电压增量。但电机反电动势本身就随转速上升母线电压一定时SPWM模式下电机能跑到的最高转速就受限了。为了压榨母线电压传统做法有注入三次谐波但最系统的解决方案还是空间矢量调制。1.2 空间矢量调制的本质用6个基本电压矢量逼近任意目标矢量三相逆变器的8种开关状态对应8个基本电压矢量包括6个非零矢量 V1(001)、V2(010)、V3(011)、V4(100)、V5(101)、V6(110) 和两个零矢量 V0(000)、V7(111)。按桥臂状态编号通常把 V4(100) 定义为0°六个非零矢量依次间隔60°在复平面上形成一个六边形。任何时刻我们要的期望电压矢量 us (2/3)(ua ub·e^(j2π/3) uc·e^(j4π/3))只要落在六边形内部就能用所在扇区相邻的两个非零矢量和零矢量按伏秒平衡原则合成出来。采样周期Ts足够短时一个Ts内用相邻矢量各自作用一段时间平均值等效于目标矢量。这正是SVPWM时域平均的思想。关键点是SVPWM每个开关周期都在做矢量合成得到的相电压波形不再是纯正弦而是马鞍波——顶部被压平、底部被抬高。马鞍波里的三次谐波分量在电机线电压里相互抵消不会增加额外转矩脉动但有效值却比正弦波更高因此电压利用率从0.612提升到了0.707也就是提高了15.47%。这个数值不是凭空来的本质是内切圆半径从正六边形内切圆变成了六边形外接圆而SVPWM存在的唯一目的就是让合成矢量的轨迹尽可能接近六边形的内切圆。1.3 坐标变换后的合成关系经典流程是先把三相电压 ua、ub、uc 变换到两相静止坐标系 αβ。等幅值变换下uα ua - 0.5×(ubuc)uβ (√3/2)×(ub-uc)对应的等效关系如果用相电压峰值表示为 us uα j·uβ幅值 |us| (2/3)×Vdc×? 不对这里要注意非零矢量幅值为 (2/3)Vdc但通常在使用标幺值或归一化时做处理。实际推导时直接利用αβ分量来判断扇区、计算时间代码里常用 uα 和 uβ 两个变量。仿真时常见的办法是先给定目标电压的幅值和角度通过 Vα Vref×cos(θ)Vβ Vref×sin(θ) 得到然后送入SVPWM函数。到这里基础建立了接下来进入硬核部分怎么判断目标矢量在哪个扇区。2. 扇区判断先知道目标矢量在哪再说怎么合成扎实的空间矢量分解必须建立在正确的扇区判断上。扇区判断错了相邻矢量选错后面的伏秒平衡完全失效输出波形会直接乱掉。2.1 从两相静止坐标到三个中间变量最常用的判断方法有三类角度判断法算 atan2 后查角度区间、坐标比较法以及本小节要用的 ua、ub、uc 中间量法。第三种是目前工程代码里最流行的因为它只需要几次比较运算不需要三角函数特别适合单片机实时计算。令u1 uβu2 (√3/2)×uα - (1/2)×uβu3 -(√3/2)×uα - (1/2)×uβ这几个中间量的几何含义其实是把目标矢量分别往三条60°间隔的轴线方向上投影转换关系来源于把三相坐标轴重构到αβ平面上。你可以把 u1、u2、u3 理解为三个“虚拟相电压比较值”它们决定了目标矢量相对于各扇区边界的位置。2.2 扇区号查表规则传统公式里定义A 1 (u10)否则 0B 1 (u20)否则 0C 1 (u30)否则 0然后扇区号 N A 2×B 4×C。这个N只是0~7之间的数和物理扇区1~6之间有一个对应表。不同参考资料给的映射可能不一样取决于u1、u2、u3正方向的约定。通常约定如下表我已按常用约定整理N物理扇区3扇区11扇区25扇区34扇区46扇区52扇区6为什么不用A、B、C直接对应扇区因为N是二进制组合天然方便查表而且芯片上执行位运算很快。实际项目中很多人会省掉A、B、C布尔量直接用分段判定写if-else效果一样但查表写起来更规整。验证方法很简单当 θ0° 即 uα0, uβ≈0 时u10 边界约等于0可能误判工程上往往加一个小滞环后面说。当 θ30° 时目标矢量在第一扇区你代入uα、uβ计算N应该得到对应扇区1的N值。2.3 用代码实现扇区判断Matlab脚本里写起来很简练function sector calcSector(ualpha, ubeta) u1 ubeta; u2 sqrt(3)/2 * ualpha - 0.5 * ubeta; u3 -sqrt(3)/2 * ualpha - 0.5 * ubeta; A u1 0; B u2 0; C u3 0; N A 2*B 4*C; sectors [3, 1, 5, 4, 6, 2]; % 表项对应 N1~6索引从1开始 sector sectors(N); end注意matlab下标从1开始而N理论上可能是0或7但物理上不可能所有u1、u2、u3都小于0所以N不会为0或7。实际运行如果出现0或7一般是角度/坐标变换环节有bug。3. 每个扇区的矢量作用时间X、Y、Z公共量推导扇区定下来之后核心问题就变成一个Ts内相邻两个非零矢量各作用多久。所有扇区的时间计算不用各自重新推导只要先算出三个公共量X、Y、Z再查表映射到各扇区的T1、T2。这是SVPWM代码优雅的关键。3.1 X、Y、Z的推导思路伏秒平衡方程组长这样目标矢量在扇区1中相邻矢量为 V4(100) 和 V6(110)假设PWM周期Ts内V4作用T1V6作用T2零矢量作用T0Ts-T1-T2。在αβ轴上写出方程T1×V4_α T2×V6_α Ts×uα T1×V4_β T2×V6_β Ts×uβV4 (2/3)Vdc在α轴上V6 (1/3)Vdc在α轴上且 (√3/3)Vdc 在β轴上。代入解二元一次方程T1 ( (√3×Ts×uα)/Vdc ) - ( (Ts×uβ)/Vdc ) 等系数算了比较繁琐。为了让所有扇区统一定义三个公共变量注意公式中Vdc以伏特为单位uα/uβ也以伏特为单位X (√3×Ts×uβ) / Vdc Y ( (3/2)×Ts×uα (√3/2)×Ts×uβ ) / VdcZ ( -(3/2)×Ts×uα (√3/2)×Ts×uβ ) / Vdc我故意不把它们化简成0.866之类的小数便于看清楚几何关系。X本质是uβ对时间的贡献Y、Z则是把αβ分量重新投影到两条斜向的边界方向上。3.2 各扇区T1、T2的映射关系根据相邻矢量选择可以得到如下映射表这是我最常用的一份验证过很多次扇区T1T21ZY2Y-X3-ZX4-XZ5X-Y6-Y-Z这个表建议自己推一遍。怎么推以扇区2为例相邻矢量为 V2(010) 和 V6(110)列伏秒平衡解完会发现 T1Y, T2-X。其他扇区同理。死记表容易记混推三遍后基本刻在脑子里了。工程里常见写法是switch sector case 1 T1 Z; T2 Y; case 2 T1 Y; T2 -X; % ... end时间单位是秒注意Ts如果取1e-4算出来的T1、T2也是秒级单位。后面计算占空比时转为0~1之间。3.3 过调制处理与调制比限制当合成矢量幅值超过六边形边界时T1T2会大于Ts。这时候如果不处理占空比会溢出转速环给定大时波形发散、母线电流过冲。必须做限幅。常用方法是等比例缩小if T1 T2 Ts inv_sum Ts / (T1 T2); T1 T1 * inv_sum; T2 T2 * inv_sum; end这样保持矢量方向不变只是幅值收缩到边界。也正因如此SVPWM最大能输出的相电压基波幅值就是 Vdc/√3对应线电压有效值 Vdc/√2 ≈ 0.707Vdc。这就是为什么很多人说SVPWM比SPWM电压利用率高。过调制更精细的方式是加入“过调制策略”把幅值超过六边形边界的部分做幅相修正比如最小相位差法但一般电机驱动里的电流环电压指令不会长期超过边界等比例限幅已经够用。做深层控制研究时再去啃过调制也不迟。4. 七段式SVPWM的占空比分配知道T1、T2只完成了上半场。实际输出到逆变器的是三相桥臂的开关信号还要把非零矢量和零矢量的作用时间排成一个开关周期内不产生额外噪声的开关顺序。4.1 为什么要插入零矢量如果整个Ts只让两个非零矢量轮流导通那么一个周期内至少有120°扇区切换时桥臂状态跳变巨大导致电流纹波增加还有可能在某些模式下三个桥臂全高或全低的时间不均衡。零矢量的作用就是在非零矢量之间插入“休息时间”让相电压平均值落在期望值上同时通过分配两个零矢量的比例来优化开关次数。经典做法是七段式SVPWM每个Ts内开关顺序安排为 000 → 相邻矢量1 → 相邻矢量2 → 111 → 相邻矢量2 → 相邻矢量1 → 000或反向对称。每个周期开关6次三相桥臂各动作两次谐波集中在开关频率整数倍附近方便滤波。零矢量分配方式一般取 T0 Ts - T1 - T2并平均分配给000和111即 T0/2 放在开头T0/2 放在中间或两边这就是中心对称Seven-Segment。这样做的优点是PWM波形对称谐波小电流纹波小。缺点是每个周期固定6次开关。4.2 切换时刻的计算与查表定义三个比较值 Taon、Tbon、TconTaon (Ts - T1 - T2) / 4Tbon Taon T1/2Tcon Tbon T2/2这是以三角载波对称调制为基础的。如果DSP的EPWM模块工作在增/减计数模式用这三个比较值装载比较寄存器就能产生对称PWM。PWM计数器的计数值需要在0~TBPRD之间所以有时需要把时间换算成计数值乘上定时器时钟频率。按照不同扇区三相桥臂切换点与比较值的关系不同。常用映射表如下以通用工业代码为准注意不同文档变量名差异扇区A相比较值B相比较值C相比较值1TbonTaonTcon2TaonTconTbon3TaonTbonTcon4TconTbonTaon5TconTaonTbon6TbonTconTaon至于为什么扇区1是Tbon/Taon/Tcon而不是其他排列本质是因为该扇区非零矢量是100和110A相先开、B相后开、C相保持低对应派生出的比较值序列就是B相切换点位于A相和C相切换点之间。建议结合矢量图和七段时序一起核对。有的代码喜欢先算公式再查表有的直接if-else判断扇区给三个比较值。两种都没问题。4.3 三相占空比输出与PWM产生实际工程里比较值写进定时器比较寄存器后还要配置PWM模式为增减计数强制高有效或强制低有效。通常先让计数器从0增到TBPRD再减到0TBPRD对应半个开关周期。当计数器的值小于比较值时输出高这样产生的每相PWM在扇区内呈马鞍波。这里有个容易踩的坑有些单片机的PWM模块计数模式是“递减计数周期重载”那就不是七段式对称时序需要用双边沿模式。比如STM32高级定时器输出比较模式设置为PWM模式1或2选择中心对齐计数。如果错用边沿对齐开关次数和纹波特性都会变化。5. Matlab仿真从脚本到SimulinkMatlab是验证SVPWM算法性价比最高的环境。你可以纯m脚本快速跑通算法、看波形也可以在Simulink里搭模型甚至用S-Function把C语言代码直接跑起来为移植做准备。这里给一套我调通过的标准流程。5.1 纯m脚本搭建SVPWM算法框架脚本思路设置PWM周期Ts、母线电压Vdc、目标电压幅值Vref、输出电压频率freq、仿真时长。生成离散时间序列或连续时间步长。每个时间点计算目标电压空间矢量的角度得到uα、uβ。调用扇区判断函数。计算X、Y、Z查表得到T1、T2做限幅。算三个比较值Taon/Tbon/Tcon。根据扇区查表得到三相切换点再转为0~1的占空比。绘制三相占空比、相电压可用桥臂状态乘以Vdc再平均波形。仿真步长可以取Ts/100也可以取Ts本身但后者看不到开关纹波细节。为了显示PWM脉冲建议步长尽量小。5.2 完整代码扇区判断时间计算切换点这里给一个可直接运行的核心函数matlab function 或 m文件function [Ta, Tb, Tc] svpwm(ualpha, ubeta, Vdc, Ts) % SVPWM核心函数 % 输入ualpha, ubeta - 目标电压的αβ轴分量Vdc - 直流母线电压Ts - 开关周期 % 输出Ta, Tb, Tc - 三相占空比范围0~1 % 1. 扇区判断 u1 ubeta; u2 sqrt(3)/2 * ualpha - 0.5 * ubeta; u3 -sqrt(3)/2 * ualpha - 0.5 * ubeta; A u1 0; B u2 0; C u3 0; N A 2*B 4*C; % 已知N到扇区映射N1..6 sector_map [3,1,5,4,6,2]; sector sector_map(N); % 2. 计算公共变量X Y Z X sqrt(3)*Ts*ubeta / Vdc; Y (3/2*Ts*ualpha sqrt(3)/2*Ts*ubeta) / Vdc; Z (-3/2*Ts*ualpha sqrt(3)/2*Ts*ubeta) / Vdc; % 3. 根据扇区确定T1 T2 switch sector case 1, T1 Z; T2 Y; case 2, T1 Y; T2 -X; case 3, T1 -Z; T2 X; case 4, T1 -X; T2 Z; case 5, T1 X; T2 -Y; case 6, T1 -Y; T2 -Z; end % 4. 过调制限制 if (T1 T2) Ts inv_sum Ts/(T1 T2); T1 T1 * inv_sum; T2 T2 * inv_sum; end % 5. 计算三个比较值 Taon (Ts - T1 - T2) / 4; Tbon Taon T1/2; Tcon Tbon T2/2; % 6. 根据扇区查表输出三相比较值占空比 switch sector case 1, Ta Tbon; Tb Taon; Tc Tcon; case 2, Ta Taon; Tb Tcon; Tc Tbon; case 3, Ta Taon; Tb Tbon; Tc Tcon; case 4, Ta Tcon; Tb Tbon; Tc Taon; case 5, Ta Tcon; Tb Taon; Tc Tbon; case 6, Ta Tbon; Tb Tcon; Tc Taon; end % 归一化到0~1占空比 Ta Ta / Ts; Tb Tb / Ts; Tc Tc / Ts; end这个函数返回的三相值已经是0~1的占空比但前提是三角载波范围按0~Ts对映。如果Simulink里用PWM发生器需要把占空比放大到载波幅值。测试脚本示例clear; clc; Vdc 300; Ts 1e-4; freq 50; Vref 0.7 * Vdc/sqrt(3); % 调制比0.7 t 0:Ts/50:0.04; % 2个工频周期 theta 2*pi*freq*t; ualpha Vref * cos(theta); ubeta Vref * sin(theta); Ta zeros(size(t)); Tb Ta; Tc Ta; for i 1:length(t) [Ta(i), Tb(i), Tc(i)] svpwm(ualpha(i), ubeta(i), Vdc, Ts); end % 看一个周期的占空比波形 plot(t*1000, Ta, t*1000, Tb, t*1000, Tc, LineWidth, 1.2); legend(Ta,Tb,Tc); xlabel(t (ms)); ylabel(占空比); grid on;运行后你应该能看到三个马鞍波这是SVPWM的主要标志。如果三个波形是纯正弦那说明你的调制比太低或者扇区判断写错了也可能是把比较值和占空比直接混用了。5.3 Simulink模型搭建要点Simulink里搭SVPWM核心流程是用正弦波发生器或常数斜坡生成目标电压角频率通过sin/cos模块得到Vα、Vβ。将Vα、Vβ送入MATLAB Function模块里面直接复制上面核心函数的代码只不过函数声明改成 function [Ta,Tb,Tc] svpwm(u_alpha, u_beta) 并定义 Vdc 和 Ts 为参数或常量。把Ta/Tb/Tc输出给PWM Generator或自己搭比较器与三角波比较再接三相桥臂和阻感负载/电机模块。自己搭PWM环节的建议用“Repeating Sequence Staircase”生成频率为1/Ts、范围0~Ts的三角波然后用比较器将占空比×Ts与三角波比较大于则输出1小于则0。这样能直观看到开关脉冲。再用平均值模块或“PWM”测量模块观察相电压基波。还有一个技巧为了验证矢量合成是否正确可以在仿真里同时测量负载端相电压然后做FFT分析。如果FFT里基波幅值等于设定的Vref且3次谐波很小实际上线电压三次谐波为0说明算法正确。5.4 仿真波形观察什么我给新手列一个“检查清单”三相占空比波形是马鞍形且两两对称每相峰值在0.5±0.5×调制比附近而不是正弦波。相电压波形有明显开关脉冲经过平均后基波幅值接近给定。线电压波形只在0和±Vdc之间切换没有负值对地看可能是双极性。电流波形接RL负载接近正弦且THD低。FFT频谱基波在50Hz处开关频率及其边带处有尖峰但基波附近的杂散小。如果电流波形有明显低频振荡多半是扇区判断在边界处抖动如果电流畸变但FFT里基波幅值不足多半是过调制限制没配对。6. 工程调试中的几个坑与经验6.1 扇区判断边界值处理纯数学比较 u1 0 在浮点运算下当θ接近0°或60°时很容易在两个扇区间反复抖动因为此时uβ或u2接近0微小的数值噪声就会改变符号。这会导致T1、T2跳变电流波形出现毛刺。处理办法有两个加滞回比较给u1、u2、u3设置一个很小的阈值e比如e0.001V只有大于e才判1小于-e判0在±e之间保持上一拍的值。这个对数字控制尤其重要。改用角度法判断扇区先算atan2(uβ,uα)然后用角度范围。但会引入三角函数增加CPU负担。很多工程师在MCU里用查表法替代。我实际项目里都建议用中间变量滞回因为计算量小而且扇区跳变对控制系统影响较大。6.2 过调制限制后的波形畸变当你把Vref设得比Vdc/√3还高限幅后占空比会出现方波化趋势相电流畸变率急剧上升。这不是算法bug是物理解释逆变器输出能力已经到极限。如果在仿真里看到明显的每60°削顶就是进入了过调制区。工程上应避免长时间工作在过调制区否则电机会发热、噪声变大。不过也有一个“伪过调制”现象有些人把Vref的单位和Vdc弄错以为调制比1.0时输出相电压峰值等于Vdc/2实际上SVPWM下相电压峰值最高是Vdc/√3≈0.577Vdc等幅值变换下习惯上调制比定义不同会导致Vref超过限幅值。做仿真时先统一坐标系。6.3 死区对电流波形的影响真实逆变器上下桥臂不能同时导通必须插入死区时间。但死区会让实际输出电压失真特别是在电流过零点附近产生电压误差进而导致低次谐波增加。仿真里如果直接用理想桥臂看不到这个现象。工程调机时SVPWM的波形在示波器上看可能和仿真差异不小就是死区和器件压降造成的。如果想在Simulink里模拟死区可以在PWM驱动信号上加“On/Off Delay”模块设置time delay为死区时间。加上后观察电流波形在过零点的畸变再理解死区补偿为什么存在。6.4 从Matlab算法到C语言移植要点Matlab调试通过只是第一步。移植到STM32、TMS320F28379D这类MCU时要注意几个细节用浮点还是定点Cortex-M7或DSP带FPU的可以直接float但若用的低端MCU建议把所有三角函数、开方换成查表或近似公式。SVPWM核心里只有乘法和加减本身对FPU要求不高。定时器周期匹配Ts对应PWM定时器的周期值比如定时器时钟90MHzPWM频率10kHz那么TBPRD 90e6/(2×10e3) 4500会增加中心对齐模式需要换算成计数值。注意半周期问题。比较值寄存器更新时机必须在PWM周期中断里更新比较值否则会出现输出毛刺。很多芯片支持影子寄存器在匹配周期时自动重载。扇区判断里的N要作为局部变量避免在中断里调用耗时函数。电流环和SVPWM通常放在同一个中断里先采样电流再执行坐标变换、PI调节最后更新SVPWM比较值。我当初从Matlab搬到DSP时卡在计数周期换算上花了半天。后来总结出通用公式// TBPRD TBCLK / (2 * f_pwm) - 1 // 比较值 (Ts/2) * (1 - 占空比) * 2 * something...更简单的是直接把SVPWM的时间先算好再转换为计数值需要映射到0~TBPRD那么从切换点时间tA转换成比较计数器的值是CMPA (int)(tA / Ts * TBPRD_)。中心对齐下占空比与比较值成线性所以这个转换不会错只要注意方向。再提一个在工程中很常见的花式问题把占空比0.0到1.0直接乘TBPRD之后占空比为0对应全低但有些定时器逻辑是“计数到比较值输出低高于输出高”方向反过来导致波形正好反向180°电机反转或电流震荡。这时候检查PWM极性配置别死磕算法。我个人调试SVPWM的经验是先在开环下给一个固定频率、固定Vref用示波器或Simulink里的Scope看三相电流波形正常是平滑正弦再快速把调制比从0.1线性加到0.6观察电流幅值随调制比变化确认在低调制比下扇区判断、时间计算没问题。最后才闭环跑FOC否则闭环一塌糊涂时根本分不清是电流环问题还是SVPWM问题。如果想把SVPWM进一步玩深推荐三个方向一是用SVPWM实现五相或双三相电机控制扇区表变成十边形思路类似但每个扇区多加一个虚拟矢量二是研究随机开关频率SVPWM把频谱的尖峰打散降低噪声三是结合RLS在线辨识做无传感器控制SVPWM的电压利用率优势会更加突出。找时间我把三电平NPC的SVPWM扇区划分也整理出来那个比两电平更绕但也更有意思。
返回列表