SPWM单极性逆变器设计全解析:从原理到STM32实现与调试避坑
做了这么多年电力电子接触过的逆变方案少说也有十几种但要说最值得新手从头到尾啃一遍的还是SPWM单极性逆变。这个方案看起来简单里头藏的门道却不少死区怎么加、滤波怎么算、为什么单极性比双极性好、86.6%那个数到底怎么来的串起来就是一套完整的逆变器设计思路。这篇文章就把我调试过程中踩过的坑、验证过的参数、以及单极性和双极性的本质区别一次讲清楚东西有点干建议边看边动手。1. SPWM的基本原理正弦波是如何“切”出来的1.1 面积等效与冲量定理逆变器的本质是把直流电变成交流电但简单地把开关管按50Hz的频率轮流导通得到的是方波方波里有大量的谐波根本不能直接带负载。要让输出接近正弦就得让开关管在导通和关断之间快速切换让负载看到的“平均电压”按正弦规律变化。这就是SPWM的核心思想——冲量等效。冲量等效原理说得很明白把正弦波分成N个等宽的窄脉冲每个脉冲的面积如果和对应时刻的正弦波面积相等那这一串脉冲加在惯性负载上产生的效果和原正弦波几乎一样。换句话说我用宽度按正弦变化的矩形脉冲去逼近正弦波负载端接上滤波器之后就能还原出干净的正弦。实际工程里我们不用真的去积分算面积。我们把一个高频三角波和一个低频正弦波送进比较器三角波频率就是载波频率决定开关管的开关频率正弦波频率就是调制波频率决定输出交流电的频率。比较器的输出规律是正弦波幅值大于三角波时输出高电平小于时输出低电平。这样自然就得到一组“中间宽、两边窄”的脉冲序列这就是SPWM波。理解这个生成过程很重要因为后面所有的分析——谐波分布、调制比限制、死区影响——都建立在这个“比较”模型上。1.2 调制比与电压利用率调制比m是SPWM里第一个必须搞清楚的参数它是正弦调制波幅值Ur与三角载波幅值Uc的比值m Ur / Ucm的取值范围是0到1。m越小输出脉冲宽度变化越平缓谐波含量低但输出电压也低m越大输出电压越高到m1时达到最大此时如果继续增大Ur让正弦波顶部超出三角波范围输出脉冲就会在小角度内保持常通进入过调制区。过调制会带来额外的低次谐波一般不建议长期工作在这个区域。单相全桥SPWM逆变器的输出基波电压幅值可以近似写成Uo1m m × Udc双极性调制这个公式很好记调制比m直接决定了输出电压。m1时输出基波幅值等于直流母线电压Udc。但对于三相系统情况略有不同这个我在第4章专门讲86.6%的问题时再展开。1.3 单极性与双极性的本质区别单极性和双极性的区别很多初学者第一反应是“输出电压的极性”这个理解方向对但不完整。我现在给你一个更本质的对比两者输出的电平状态数量不同。双极性SPWM同一桥臂的上下管交替导通全桥对角线上的两对管子同时切换。输出端电压要么是Udc要么是-Udc只有两种电平。单极性SPWM有两个桥臂分工一个桥臂负责高频斩波另一个桥臂负责低频换向。输出端电压在正半周要么是Udc、要么是0负半周要么是-Udc、要么是0三种电平。多了一个0电平看起来只是小事但带来的连锁反应非常大输出电压的跳变幅度从双极性的2Udc降为单极性的Udc这意味着输出滤波前的电压谐波含量更低EMI更小开关损耗更小电感的电流纹波也更小。这些咱们到第4章做详细对比时再展开。2. 单极性逆变主电路设计拓扑选型与参数计算2.1 H桥拓扑与开关逻辑分析做单极性逆变主电路就是一个标准的H桥全桥四个开关管Q1~Q4负载接在桥臂中点之间。直流母线电压Udc在输入端输出端通过LC滤波器接负载。H桥的四个管子怎么配合是关键。单极性调制的开关逻辑我总结成一句话高频臂做斩波低频臂做换向两者各干各的活。以输出电压正半周为例Q4保持导通把输出端“接地”到负母线Q1以载波频率高频斩波正弦波大于三角波时导通输出端被拉到Udc此时负载两端电压要么是Udc要么是0。负半周正好反过来Q2保持导通把输出端接地到正母线Q3高频斩波负载两端电压要么是-Udc要么是0。整个过程里输出端对母线中点的电位有“正、零、负”三种状态但负载两端的电压永远只有两种幅值正半周是Udc和0负半周是-Udc和0且方向不会突变这就是“单极性”名字的由来。2.2 关键参数选型载波频率、死区时间与开关管参数选型是做逆变器最先要决定的一批事选错后面全白干。我根据家用逆变器2kW级的常见配置给出一套经过验证的参数组合首先载波频率。工程上单极性SPWM的载波频率一般取10kHz到20kHz。10kHz以上可以避开音频噪声20kHz是IGBT和普通MOSFET能兼顾损耗的常见上限。我用的是16kHz原因有三一是噪声早已超出人耳范围二是开关损耗在MOSFET上可控三是LC滤波器体积不需要做得太大。如果你用IGBT建议降到10kHzIGBT的关断拖尾电流在20kHz下损耗会明显偏高。其次死区时间。H桥的上下管如果同时导通母线直接短路瞬间大电流能把管子炸开花。所以必须先关断一个管子、等待一段时间再开通另一个这个等待时间叫死区。死区时间不是拍脑袋定的要配合开关管的关断延迟和栅极电阻td td(off) tr 裕量td(off)开关管关断延迟时间数据手册里有普通MOSFET大约50~100nsIGBT约300~500nstr关断过程中电压上升时间大约50~200ns裕量一般取上述总和的1.5~2倍。我用的是IRFP460这类MOSFET死区取1.5μs稳得很。取太大也不好死区会造成输出电压波形畸变产生低次谐波和基波电压损失后面会细说。最后开关管耐压与电流。开关管耐压要留至少1.5倍裕量比如母线电压400V用600V的管子比较安全尖峰电压冲到500V时还有余量。电流额定按最大输出功率的峰值电流再加2倍以上裕量不要卡着算感性负载启动瞬间的电流冲击远比稳态大得多。2.3 LC滤波器设计截止频率与阻尼系数SPWM的输出是一串高频脉冲必须经过LC低通滤波器才能得到光滑的正弦波。LC的参数直接影响波形质量也影响系统的动态响应。我的设计思路是这样的第一步确定截止频率。LC滤波器的截止频率一般取载波频率的1/10到1/20目的是让50Hz基波顺利通过同时把开关频率附近的高频分量压下去。以载波16kHz为例我取截止频率1kHz折中滤波效果和动态响应。如果截止频率太低电感电容体积大动态响应差太高高频纹波压不住示波器上能看到明显的毛刺。第二步算LC乘积。对于一个LC低通滤波器fc 1 / (2π√(LC))把fc1000Hz代入解得LC ≈ 2.53×10^-8。有了乘积还需要一个约束条件才能分别确定L和C。纯阻性负载下我习惯从电感电流纹波的角度先把L定下来。单极性SPWM输出加在电感上的电压脉动幅值是Udc允许的纹波电流峰峰值设为额定电流的15%~20%。于是ΔI (Udc × D × (1-D)) / (L × fs)其中D是占空比。取最恶劣情况D0.5Udc360Vfs16kHz额定输出功率2kW时220V有效值对应峰值电流约12.8A纹波取20%就是2.56A。代入公式L (360 × 0.5 × 0.5) / (2.56 × 16000) ≈ 2.2mH电感定了2.2mH电容自然就定了C 2.53×10^-8 / (2.2×10^-3) ≈ 11.5μF取标称值10μF。如果你发现滤波后波形还有可见的高频分量可以把电容加大到15μF试试但要留意电容电流带来的额外损耗。电感最好用铁硅铝磁环饱和磁密高不容易在过载时饱和。这里要给个提醒LC滤波器有个不好的特性就是轻载时可能会谐振。特别是在空载或感性负载下系统的阻尼很低如果控制里没有额外的阻尼措施输出可能会振荡。解决办法是在输出端并联一个几百欧的泄放电阻或者用较大的输出电容来压低谐振峰值。我在样机里并了一个470Ω的电阻波形稳定很多。3. STM32生成SPWM的三种实现方式与代码解析3.1 方案选型查表法、实时计算法与DMA法对比微控制器生成SPWM波常见的有三种做法我挑一种最合适你项目的下面分别说清楚。查表法把正弦函数值预先算好存成一张表放在Flash里每次定时器中断时查表取一个值更新比较寄存器。优点是中断里做的事情最少CPU负载低速度快缺点是修改频率和相位不方便表是死的。实时计算法每次中断里现场算sin(ωtθ)优点是灵活想改频率改相位随时改但CPU会被三角函数计算吃掉不少资源开关频率高了容易忙不过来。DMA法用DMA把正弦表里的数据自动搬运到定时器的比较寄存器里CPU完全不参与适合追求极致效率的场景。缺点是调试起来不够直观改参数要重新配置DMA。我在实际开发里推荐用查表法配合DMA的效果更好。STM32的Flash容量大存1024点的正弦表才4KB完全没压力。查表速度极快一次查表加一次寄存器写入的耗时绝大部分是寄存器写入的时间CPU开销小到你甚至可以同时跑显示和控制算法。3.2 用STM32定时器实现SPWM输出的核心代码我用的是STM32F103系列因为它是市面上最普及、资料最多的芯片你手头如果是其它型号思路完全通用。核心思路是用高级定时器TIM1产生频率可变的PWM比较寄存器值按正弦表变化同时利用定时器的死区插入功能生成互补的带死区的PWM对。先初始化定时器和GPIO// 使用TIM1的CH1和CH1N配置为PWM模式1 // 载波频率16kHz定时器时钟72MHz // ARR 72MHz / 16000 4500周期对应16kHz TIM_TimeBaseInitTypeDef TIM_BaseInitStructure; TIM_OCInitTypeDef TIM_OCInitStructure; TIM_BDTRInitTypeDef TIM_BDTRInitStructure; // 定时器基础配置ARR4500向上计数 TIM_BaseInitStructure.TIM_Period 4500 - 1; TIM_BaseInitStructure.TIM_Prescaler 0; TIM_BaseInitStructure.TIM_ClockDivision 0; TIM_BaseInitStructure.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseInit(TIM1, TIM_BaseInitStructure); // PWM模式1占空比初始为0 TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OutputNState TIM_OutputNState_Enable; TIM_OCInitStructure.TIM_Pulse 0; TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; TIM_OCInitStructure.TIM_OCNPolarity TIM_OCNPolarity_High; TIM_OC1Init(TIM1, TIM_OCInitStructure); // 死区时间72MHz时钟下1个死区计数单位约为13.9ns // 设置为108个单位约1.5μs死区 TIM_BDTRInitStructure.TIM_OSSRState TIM_OSSRState_Enable; TIM_BDTRInitStructure.TIM_OSSIState TIM_OSSIState_Disable; TIM_BDTRInitStructure.TIM_LOCKLevel TIM_LOCKLevel_OFF; TIM_BDTRInitStructure.TIM_DeadTime 108; TIM_BDTRInitStructure.TIM_Break TIM_Break_Disable; TIM_BDTRInitStructure.TIM_BreakPolarity TIM_BreakPolarity_High; TIM_BDTRInitStructure.TIM_AutomaticOutput TIM_AutomaticOutput_Enable; TIM_BDTRInit(TIM1, TIM_BDTRInitStructure); TIM_Cmd(TIM1, ENABLE); TIM_CtrlPWMOutputs(TIM1, ENABLE);这里有个关键点TIM1的PWM输出必须同时开启TIM_CtrlPWMOutputs否则主输出使能位没置位CH1和CH1N都不会有输出。我第一次调试时漏了这句折腾了半天以为初始化顺序不对。然后生成正弦表。为了节省计算量我提前算好一个周期的正弦表用Python脚本生成C语言数组# 生成1024点正弦表值域映射到0~4500中心值为2250 import math N 1024 max_duty 4500 center 2250 amplitude center * 0.9 # 调制比约0.9留一点死区补偿的余量 print(const uint16_t sin_table[%d] { % N) for i in range(N): val int(center amplitude * math.sin(2 * math.pi * i / N)) if i % 8 0: print( , end) print(%d, % val, end ) if i % 8 7: print() print(};)注意这里我把正弦表中心值设在了2250对应50%占空比幅值设为2025对应调制比0.9。为什么不拉满到1.0因为死区会吃掉一部分有效占空比且满载时母线电压会有跌落留10%的余地可以保证输出波形在极限工况下不失真。接着利用定时器的更新中断每次进入中断就把正弦表的下一个值写入比较寄存器。为了让输出频率稳定我建议把正弦表的步进设计成可配置// 在16kHz的更新中断里以固定步进取正弦表 // 正弦表一个周期1024点对应载波周期个数为1024/步进 // 输出频率 16000 / (1024 / 步进) // 例如输出50Hz步进 16000 / 50 / 1024 ≈ 0.3125用小数定点逼近 volatile uint32_t phase_accumulator 0; const uint32_t phase_step (uint32_t)(0.3125f * 65536); // Q16格式的步进 void TIM1_UP_IRQHandler(void) { if (TIM_GetITStatus(TIM1, TIM_IT_Update) ! RESET) { TIM_ClearITPendingBit(TIM1, TIM_IT_Update); uint32_t index (phase_accumulator 16) 0x3FF; // 取高10位查表 TIM_SetCompare1(TIM1, sin_table[index]); phase_accumulator phase_step; } }用累加器和Q16定点运算的好处是输出频率可以做到很高的精度而且调整输出频率只需要修改phase_step不用改中断逻辑。这套思路我用了很多年稳定可靠。3.3 单极性调制与双极性在代码上的区别如果你只生成一组互补PWM给全桥那是双极性要做单极性代码上需要两路不同的PWM高频臂比如Q1/Q3用TIM1的CH1输出PWM占空比按正弦表更新低频臂比如Q4/Q2用一个低频GPIO翻转50Hz换向。我这里用的方案是高频臂做PWM输出低频臂用GPIO控制。具体来看// 低频换向臂的控制50Hz方波 // 正半周Q4导通负半周Q2导通 void update_low_freq_arm(float phase_angle) { if (sin(phase_angle) 0) { GPIO_SetBits(GPIOA, GPIO_Pin_5); // Q4 gate high GPIO_ResetBits(GPIOA, GPIO_Pin_6); // Q2 gate low } else { GPIO_ResetBits(GPIOA, GPIO_Pin_5); // Q4 gate low GPIO_SetBits(GPIOA, GPIO_Pin_6); // Q2 gate high } }低频臂的切换最好安排在正弦波过零点附近。一个很实用的小技巧是让低频臂比高频臂的过零切换提前或者滞后几个载波周期避免高频臂和低频臂在同一瞬间切换导致输出端出现极窄的毛刺脉冲。我在工程里让低频臂提前约200μs翻转波形干净很多。3.4 驱动电路与隔离从PWM信号到功率管的最后一公里MCU输出的3.3V/5V PWM信号直接驱动MOSFET是不够的必须经过驱动电路。驱动方案有两种常见选择自举半桥驱动芯片例如IR2108、IR2110一颗芯片可以驱动一个桥臂的高低管成本低适合做小功率样机。缺点是需要高侧自举电容低端输出占空比接近100%时自举电容可能得不到足够充电时间高侧驱动会欠压。隔离式驱动例如Si823x、TLP250配合独立隔离电源高压侧和低压侧完全隔离可靠性和抗干扰能力都更强适合做工业级产品。我个人建议如果只是学习和验证用IR2108加自举电容完全足够但要注意电容选100nF到470nF的X7R陶瓷电容并且尽量靠近芯片的VB和VS引脚放置。如果要在恶劣电磁环境下运行直接上隔离驱动一步到位。驱动电路还有一个细节就是栅极串联电阻。这个阻值决定了开关速度阻值小开关快开关损耗低但电压电流变化率大EMI严重阻值大开关慢EMI好但开关损耗高。我一般取10Ω到51Ω之间配合实验波形微调。国产模块常用22Ω这个值在多数800V以下的MOSFET上是一个很好的折中点。4. 单极性vs双极性从波形到损耗的硬核对比4.1 输出电平、THD与等效开关频率先给一张对比表格这张表是我测了无数波形后总结的对比维度单极性SPWM双极性SPWM输出电压电平Udc、0、-Udc三种Udc、-Udc两种电压跳变幅度Udc2Udc等效开关频率输出端2倍载波频率载波频率滤波前电流纹波较小较大输出THD同滤波参数较低较高开关损耗约一半桥臂高频工作四个管子全高频EMI较小较大控制复杂度稍高需换向逻辑低逻辑简单动态响应稍慢较快为什么单极性THD更低因为它的“等效开关频率”翻倍了。从负载端往回看单极性SPWM在正半周只有Q1在高速切换输出端在Udc和0之间跳变而双极性SPWM是两对管子同时切换输出端在Udc和-Udc之间跳变等效的频率就是载波频率。同样的LC滤波器单极性因为等效开关频率翻倍对高频纹波的衰减能力大幅提升滤波后波形更接近理想正弦。4.2 开关损耗与效率的定量分析很多人忽略了一个事实双极性SPWM四个管子全部都以载波频率高频动作而单极性SPWM只有两个管子工作在载波频率另外两个只工作在50Hz。开关损耗近似正比于开关频率和电压电流乘积。假设载波频率16kHz双极性下每个管子每周期开关一次单极性下平均只有一半的管子每周期开关一次。以H桥为例双极性4个管子×16kHz高频开关单极性2个管子×16kHz 2个管子×50Hz低频开关50Hz开关的损耗几乎可以忽略。也就是说单极性方案的开关损耗大约是双极性的一半。在大功率场合这个差距直接体现在散热器的尺寸上。同样是2kW输出双极性方案的散热器可能要比单极性大三分之一。代价是什么单极性需要额外的换向逻辑而且换向时刻如果把握不好输出波形会产生缺口畸变。但这个问题通过软件很容易解决用我的“提前换向”法即可。4.3 电源电压利用率86.6%的推导过程关于SPWM的电压利用率网上说法比较乱这里统一理清楚。对于三相SPWM逆变器直流母线电压Udc输出相电压的基波幅值在调制比m1时最大等于Udc/2。线电压的基波幅值是相电压的√3倍Ull1m √3 × Udc/2 ≈ 0.866 × Udc也就是说线电压基波幅值最高只能达到直流母线电压的86.6%。这个数就是√3/2也就是三相SPWM逆变器电压利用率的上限。这也是SVPWM之所以重要的原因——SVPWM可以将电压利用率提升到100%超过SPWM的86.6%。如果你看到资料上说“SPWM利用率只有86.6%”指的就是三相系统下线电压基波幅值与直流母线电压的比值不要和单相混淆。单相全桥的情况不同全桥SPWM输出基波幅值可以达到Udc利用率接近100%。如果输出220V有效值幅值311V那直流母线电压理论最低只要311V。但实际上因为死区、滤波电感压降、母线纹波等因素母线电压我建议取360V~400V留足裕量。4.4 EMI表现与感性负载适配性EMI方面单极性有明显优势。因为单极性输出电压的du/dt只有双极性的一半共模电流和辐射干扰都会降低。我做EMC预测试时对比过同样的Layout、同样的输出功率单极性方案的传导骚扰在开关频率及其倍频处普遍比双极性低6~10dB这对家庭光伏逆变器和家电产品要过认证的场景来说非常关键。负载适配性上单极性带非线性负载或者电机类负载时动态响应不如双极性。原因在于单极性调制的输出电压在过零点附近切换电平少等效增益略有下降。对此我的处理是不要用纯开环加快电压环的PI响应或者用瞬时值闭环把动态响应补回来。5. 调试实录常见问题与避坑经验5.1 上电就炸管的背后原因做逆变器调试第一关就是防止上电炸管。我见过太多人第一步就烧了管子原因基本集中在三点死区没设置或设置太短。MCU初始化时死区寄存器写0或者写的值不够导致上下管直通。这个在STM32上比较容易踩因为复用功能配置不正确时CH1和CH1N可能同时输出高电平。母线电容没有预充电。上电瞬间母线电容相当于短路充电电流极大不经过限流直接冲击整流桥和开关管炸管的概率极高。控制程序跑飞。程序还没稳定输出PWM就对功率级供电控制管脚输出不确定电平致上下管同时导通。我的调试顺序是先只给MCU供电用示波器检查各桥臂驱动波形确认死区时间和占空比正常然后接上驱动电路功率级先不接母线大电容用直流稳压电源将母线电压从50V慢慢往上加一边加一边观察输出波形。第一次上高压时串联一个100W的灯泡在母线上作为限流保护如果电路有短路灯泡会亮起来而不是直接炸管。这个土办法救了我好几块板子。5.2 输出波形不正常的排查思路输出波形如果出现明显失真我按以下顺序排查看MOSFET的栅源波形确认PWM信号是否正常。重点检查死区时间是否足够、驱动芯片自举电压是否稳定。如果自举电容太小或充电时间不够高侧驱动会出现输出幅值不足的问题。看输出端波形是否带有明显的阶梯状毛刺。这是死区造成的死区期间电感电流需要通过体二极管续流输出电压会偏离理想值。毛刺宽度等于死区时间150μs的死区只会造成很小的缺口但如果死区设置到5μs以上示波器就能看见明显的凹陷。看空载波形是否震荡。前面说过LC滤波器和负载形成的谐振峰没有阻尼时空载或轻载就会出现振荡。这时先别怀疑SPWM算法多半是LC阻尼不够加个泄放电阻或者增大输出电容就好了。看带载后波形是否塌陷。如果带一点负载输出电压就明显下降说明变压器如果有的话容量不够或者调制比没有留够裕量又或者直流母线电压在负载下下跌严重。5.3 实用调试技巧示波器设置与波形判读调试SPWM逆变器示波器的用法直接决定效率。我分享几个自己的习惯测PWM波时用单次触发抓取上升边能直接测量死区时间把时基设到1μs/div测两路互补PWM的间隔这个值就是实际死区。看输出正弦波形时别直接看PWM电压波形要看LC滤波后的负载端电压同时用电流探头看电感电流确认电流连续与否。如果电感电流断续说明电感量偏大或者负载太轻波形会失真。测谐波时用示波器的FFT功能看频谱重点看2倍开关频率处是否有异常尖峰。如果2倍频分量过高说明单极性换向逻辑可能存在毛刺。5.4 从实验室样机到稳定运行的几个细节最后补充几个我后来做产品时沉淀下来的细节一是电感不要用普通铁氧体铁氧体饱和磁密只有0.3T左右大电流下容易饱和电感量骤降后电流纹波会飙升。我用铁硅铝磁环饱和磁密能到1.05T尺寸和损耗都更可控。二是低压控制电路和功率电路的地要单点连接避免功率地上的大电流在控制地上产生压降把MCU的参考地抬高导致采样和驱动误动作。这个在IGBT开关时特别明显地弹电压能到好几伏。三是监控母线电压和电感电流。母线过压、电感过流这些故障信号一旦触发必须在几微秒内封锁PWM输出等不到CPU去处理。我是用硬件比较器直接接到驱动芯片的使能脚或MCU的刹车引脚实现硬件级的快速保护。STM32的TIM1有刹车(Break)功能这个特性就是为了逆变器设计的一定要用起来。设置TIM_Break为TIM_Break_Enable外部故障信号一拉低输出立即变为安全状态。根据我个人反复调试的经验SPWM单极性逆变器的坑主要集中在前期的硬件调试阶段一旦把死区、自举电容、LC参数这三关过了后面的工作主要就是心态活——慢慢调参数、对比波形、优化效率。你要是有条件建议把双极性也调一遍两种方案各跑一轮负载测试你对SPWM的理解会深一个层次。毕竟控制策略这东西光看波形图和数据表记不住亲手调出来的感觉才是最扎实的。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →