1. 从一个“看不见摸不着”的旋转矢量说起如果你做过电机控制、逆变器开发,或者玩过三相PWM调制,大概率听过“旋转电压矢量”这个词。我第一次接触这个概念时,脑子里全是问号:电压不是标量吗?怎么还能旋转?后来在实验室里用DSP跑了一遍SVPWM算法,盯着示波器上那三路马鞍波和旋转的合成矢量,才真正理解了这个东西的物理意义。所谓“产生一个旋转的电压矢量”,本质上就是通过三个相位互差120度的电压分量,在空间上合成一个幅值恒定、角度随时间匀速变化的电压矢量。这个矢量在复平面上转一圈,对应的时间就是一个基波周期。听起来简单,但真到动手实现的时候,坑一个接一个:三相占空比怎么算?扇区判断为什么老出错?死区时间设多少合适?载波频率和基波频率什么关系?这篇文章就是把我自己从零搭这套东西的过程完整拆一遍。不管你是刚学电机控制的学生,还是需要快速验证算法的工程师,或者只是对电力电子感兴趣想动手试试的爱好者,下面这些内容应该都能帮你少走弯路。我会从整体设计思路讲起,然后拆解核心细节,再给出一套可以直接复现的实操流程,最后把我在调试中遇到的典型问题和排查方法整理出来。2. 整体设计思路与方案选型2.1 为什么不用模拟电路而选数字方案产生旋转电压矢量,最直观的思路是用三个正弦波发生器加功率放大器。模拟方案确实能出结果,但问题很明显:三路正弦波的相位一致性很难保证,幅值随温度漂移,频率调整也不方便。更关键的是,如果你想改变调制方式或者加死区补偿,模拟电路几乎没法灵活调整。数字方案就不一样了。用一颗MCU或者DSP,配合定时器和PWM模块,所有参数都在代码里,改一个变量就能看到效果。我选的是“定时器中断+查表/实时计算”的混合方式:基波频率低的时候用查表省CPU,频率高或者需要动态调整的时候切到实时计算。这样既保证了实时性,又留了足够的灵活性。具体来说,核心思路是这样的:设定一个目标电压矢量的幅值和旋转频率,在每个PWM周期里计算当前角度,然后根据角度算出三相占空比,最后通过定时器的比较寄存器输出三路PWM。功率级用三相桥式电路,后面接LC滤波或者直接接电机负载。2.2 载波频率与基波频率的取舍载波频率的选择直接决定了输出波形的质量和开关损耗。我一开始图省事,把载波频率设成10kHz,基波频率设成50Hz,结果发现电流波形还行,但开关管发热明显。后来算了一下:10kHz载波下,每个基波周期有200个PWM周期,对于一般的风机水泵类负载够用了,但如果要做高动态响应的伺服控制,这个比值偏低。一般来说,载波频率和基波频率的比值建议在100到500之间。比值太低,低次谐波含量高,电流波形畸变大;比值太高,开关损耗上去了,效率下降。我最后选的是载波频率20kHz,基波频率50Hz,比值400。这个配置下,开关管用的是IGBT模块,加了散热片,温升控制在合理范围内。注意:载波频率超过20kHz后,普通IGBT的开关损耗会急剧增加,这时候要考虑用SiC或者GaN器件。如果只是做实验验证算法,10kHz到15kHz完全够用。2.3 调制方式的对比与选择产生旋转电压矢量,调制方式有好几种:正弦波PWM(SPWM)、空间矢量PWM(SVPWM)、三次谐波注入PWM等等。我一开始用的是SPWM,实现简单,但直流母线电压利用率只有86.6%。后来换成SVPWM,同样的母线电压下,输出线电压基波幅值能提高15%左右。SVPWM的核心思想是把逆变器的八个开关状态对应到复平面上的八个基本矢量,然后通过两个相邻基本矢量和零矢量的时间组合来逼近目标矢量。具体来说,每个PWM周期里,目标矢量落在哪个扇区,就用那个扇区的两个边界矢量和零矢量去合成。这样做的另一个好处是,开关次数比SPWM少三分之一,开关损耗更低。不过SVPWM的实现复杂度比SPWM高不少,尤其是扇区判断和矢量作用时间的计算,很容易出错。我建议如果是第一次做,可以先用SPWM把整个链路跑通,确认硬件没问题、采样没问题,再换成SVPWM优化性能。3. 核心细节解析与实操要点3.1 三相占空比的数学推导假设目标电压矢量在复平面上的角度为θ,幅值为Vref,直流母线电压为Vdc。对于SPWM,三相占空比可以写成:da = 0.5 + (Vref / Vdc) * sin(θ) db = 0.5 + (Vref / Vdc) * sin(θ - 2π/3) dc = 0.5 + (Vref / Vdc) * sin(θ + 2π/3)这里的0.5是偏置,保证占空比在0到1之间。Vref / Vdc这个比值决定了调制比,最大不能超过0.5,否则会出现过调制。如果是SVPWM,计算就复杂一些。首先要判断目标矢量在哪个扇区,然后计算两个相邻基本矢量的作用时间T1和T2,以及零矢量作用时间T0。以第一扇区为例:T1 = (√3 * Ts / Vdc) * (Vref * sin(π/3 - θ)) T2 = (√3 * Ts / Vdc) * (Vref * sin(θ)) T0 = Ts - T1 - T2其中Ts是PWM周期。算出T1、T2、T0之后,再根据七段式或者五段式对称排列,分配到三个比较寄存器里。我实际写代码的时候,把扇区判断和矢量作用时间计算放在一个定时器中断里,中断频率就是载波频率。每次进中断先更新角度θ,然后算占空比,最后写比较寄存器。整个过程在20kHz中断下,用主频100MHz的MCU跑,耗时大概2微秒左右,CPU占用率不到5%。3.2 角度累加的精度问题角度θ的累加看起来简单,但里面有个精度陷阱。如果直接用浮点数累加,比如θ += 2π * f * Ts,时间长了之后,浮点数的舍入误差会累积,导致角度漂移。我实测过,用单精度浮点数跑一个小时,角度漂移大概有0.1度左右。对于一般的电机控制,这个误差可以接受,但如果要做高精度的位置控制,就不行了。解决办法有两个:一是用定点数,把角度映射到0到2^16或者0到2^32的整数范围,每次累加一个固定的增量,溢出后自动回绕。这样没有累积误差,而且计算速度快。二是用双精度浮点数,但会牺牲一些计算速度。我最后用的是定点数方案,角度用16位无符号整数表示,0对应0度,65535对应接近360度。每次中断累加的角度增量根据基波频率和载波频率算出来:angle_increment = (uint16_t)(65536.0 * f_fundamental / f_carrier)比如基波50Hz,载波20kHz,增量就是65536 * 50 / 20000 = 163.84,取整为164。这样每进一次中断,角度加164,溢出后自动回绕。实测下来,角度精度完全够用,而且没有漂移。3.3 死区时间的设置与补偿死区时间是为了防止上下桥臂直通而设置的。我一开始设了2微秒,结果发现输出电压明显偏低,电流波形也有畸变。后来用示波器看了下桥臂的驱动信号,发现死区期间输出电压由负载电流方向决定,如果电流为正,输出电压被拉低;如果电流为负,输出电压被拉高。这个畸变在电流过零点附近最明显。死区时间的设置要根据开关管的特性来。IGBT的关断时间一般在1到2微秒,MOSFET快一些,几百纳秒。我用的IGBT模块,死区设了1.5微秒。补偿的方法有两种:一是根据电流方向调整占空比,电流为正时占空比加一点,电流为负时减一点;二是用硬件补偿电路,但比较麻烦。我用的软件补偿,在中断里读电流采样值,判断方向,然后对占空比做修正。补偿量大概等于死区时间除以PWM周期。实测下来,补偿后输出电压的基波幅值恢复了大概5%左右,电流波形的过零点畸变也明显改善。提示:死区补偿不需要做得很精确,因为死区造成的误差本身就不大。如果调试时间有限,可以先不做补偿,等基本功能跑通了再优化。3.4 采样时机与噪声抑制电流采样和电压采样的时机很关键。如果采样时刻正好在开关管切换的瞬间,会采到很大的开关噪声。我一开始没注意这个问题,采到的电流波形上全是尖刺,后来把采样时刻挪到PWM周期的中间,也就是开关管都稳定导通或关断的时候,噪声就小多了。具体来说,我用的是中心对齐的PWM模式,计数器从0往上数到峰值再往下数到0。在计数器等于峰值的时候触发ADC采样,这时候开关管的状态是稳定的。另外,ADC采样之前加了一级RC低通滤波,截止频率设在大约10kHz,把高频开关噪声滤掉。还有一点,ADC的采样保持时间要足够长,让采样电容充分充电。我用的ADC采样保持时间设了大概1微秒,对于一般的电流传感器输出阻抗,这个时间够了。如果传感器输出阻抗高,采样保持时间还要加长。4. 实操过程与核心环节实现4.1 硬件平台搭建我用的硬件平台是一块三相逆变器板,上面有六个IGBT、三个栅极驱动芯片、直流母线电容、电流传感器和电压采样电路。控制板是一块带DSP的板子,主频100MHz,有专门的PWM模块和ADC模块。接线的时候要注意几点:直流母线电容要尽量靠近逆变器,减小寄生电感;栅极驱动电阻要根据开关管的特性选,太大开关慢损耗大,太小开关快但容易振荡;电流传感器要放在下桥臂,这样采样的是相电流,而且共模电压低。我一开始把电流传感器放在上桥臂,结果共模电压太高,传感器输出饱和了。后来挪到下桥臂,问题解决。另外,直流母线电压不要一上来就加满,先用低压测试,确认PWM输出正常了再慢慢升压。4.2 软件框架与中断服务程序软件框架很简单:主循环里做初始化和状态机,定时器中断里做角度更新和占空比计算。中断服务程序的伪代码如下:void PWM_ISR(void) { // 1. 更新角度 angle += angle_increment; // 2. 计算三相占空比 calculate_duty(angle, Vref, &da, &db, &dc); // 3. 死区补偿 deadtime_compensate(&da, &db, &dc); // 4. 写比较寄存器 PWM_REG_A = (uint16_t)(da * PWM_PERIOD); PWM_REG_B = (uint16_t)(db * PWM_PERIOD); PWM_REG_C = (uint16_t)(dc * PWM_PERIOD); // 5. 清中断标志 clear_interrupt_flag(); }calculate_duty函数里就是前面说的数学推导。如果是SPWM,直接算正弦;如果是SVPWM,先判断扇区再算作用时间。我建议把扇区判断做成查表法,根据角度的高几位直接查表得到扇区号,比用if-else判断快得多。写比较寄存器的时候要注意,比较值不能超过PWM周期的计数值,否则会丢失脉冲。我在代码里加了限幅,把占空比限制在0.05到0.95之间,留一点余量。4.3 参数计算与配置实例以基波频率50Hz、载波频率20kHz、直流母线电压300V、目标输出电压幅值150V为例,算一下关键参数。调制比m = Vref / (Vdc / 2) = 150 / 150 = 1.0。对于SPWM,最大调制比是1.0,对应占空比从0到1。对于SVPWM,最大调制比可以到1.1547,所以150V的目标电压用SVPWM完全没问题。PWM周期Ts = 1 / 20000 = 50微秒。如果定时器主频100MHz,那么一个PWM周期对应5000个计数。比较寄存器的值就是占空比乘以5000。角度增量前面算过了,164。每进一次中断,角度加164,大概400次中断转一圈,对应50Hz。死区时间1.5微秒,对应计数150。补偿量就是150 / 5000 = 0.03,也就是占空比修正3%。4.4 调试步骤与波形观测调试分几步走。第一步,不接功率级,只用示波器看MCU输出的三路PWM,确认占空比按正弦规律变化,相位互差120度。第二步,接上功率级和直流电源,用低压(比如30V)测试,看输出电压波形。第三步,加上LC滤波,看滤波后的正弦波。第四步,接上负载,看电流波形。我调试的时候,第一步就发现了问题:三路PWM的相位不对,B相和C相反了。查了半天代码,发现是数组索引写错了。所以第一步一定要仔细看波形,确认相位关系。第二步的时候,输出电压波形上有很大的尖刺,后来发现是死区时间设得太短,上下桥臂有轻微直通。把死区从1微秒加到1.5微秒,尖刺就没了。第三步,滤波后的正弦波有明显的三次谐波,后来换成SVPWM,三次谐波就小多了。第四步,接上感性负载,电流波形基本正弦,THD大概3%左右,满足一般应用要求。5. 常见问题与排查技巧实录5.1 扇区判断错误导致输出异常SVPWM的扇区判断是最容易出错的地方。我一开始用if-else判断角度范围,结果在扇区边界附近老是跳变,导致输出波形上有毛刺。后来改成查表法,把0到360度分成六个扇区,每个扇区60度,用角度的高几位直接查表,问题解决。还有一个坑是角度定义和扇区定义的对应关系。有的资料里角度从0开始对应第一扇区,有的从-30度开始。我建议自己画一遍基本矢量的分布图,把每个扇区的角度范围标清楚,然后再写代码。5.2 过调制导致的波形削顶如果目标电压幅值设得太大,超过了调制比上限,就会出现过调制,输出电压波形削顶,电流波形畸变。我一开始把Vref设成180V,母线电压300V,调制比1.2,超过了SPWM的1.0上限,结果波形削顶严重。解决办法有两个:一是降低Vref,保证调制比不超过上限;二是换成SVPWM,调制比上限提高到1.1547。如果还需要更高的输出电压,就得用过调制算法,但那样波形质量会下降。5.3 电流采样噪声与滤波参数电流采样噪声大是常见问题。除了前面说的采样时机和RC滤波,还可以在软件里加滑动平均滤波。我用的是四点滑动平均,每进一次中断更新一次,滤波后的电流波形明显平滑。但滑动平均会引入相位滞后,对于高动态响应的应用,滞后会影响控制性能。所以滤波参数要根据应用需求来定。如果只是做实验验证,滤波可以重一点;如果是做闭环控制,滤波要轻一点,或者用更复杂的滤波器。5.4 常见问题速查表问题现象可能原因排查方法解决措施输出电压偏低死区时间过长示波器看桥臂波形减小死区或加补偿电流波形有尖刺采样时机不对调整采样时刻到PWM周期中间加RC滤波或软件滤波扇区边界输出跳变扇区判断逻辑错误打印扇区号观察改用查表法波形削顶调制比过高计算调制比降低Vref或换SVPWM角度漂移浮点累加误差长时间运行观察改用定点数开关管发热严重载波频率过高测开关损耗降低载波频率或换器件提示:这张表是我自己调试过程中总结的,不一定覆盖所有情况,但大部分常见问题都能在里面找到线索。遇到新问题的时候,先别急着改代码,用示波器把关键波形看一遍,往往能很快定位。5.5 几个容易被忽略的细节第一个细节是PWM输出的死区插入方式。有的MCU硬件自动插入死区,有的需要软件设置。硬件插入的死区精度高,但灵活性差;软件插入灵活,但占用CPU时间。我用的是硬件插入,在初始化的时候配置好死区寄存器就行。第二个细节是ADC采样的触发源。我用的是PWM模块的周期中断触发ADC,这样采样时刻和PWM周期严格同步。如果用的是软件触发,采样时刻会抖动,影响控制精度。第三个细节是中断优先级。PWM中断的优先级要设得高一些,避免被其他中断打断导致PWM输出异常。我把PWM中断设成最高优先级,其他中断比如串口中断设成低优先级。第四个细节是故障保护。逆变器最怕的是上下桥臂直通,一旦发生,开关管瞬间烧毁。所以硬件上要有过流保护,软件上要有故障检测和快速关断。我在代码里加了过流中断,一旦触发,立刻封锁PWM输出。6. 从实验到产品的几个扩展方向这套东西跑通之后,可以往几个方向扩展。第一个方向是闭环控制,加上电流环和速度环,做成完整的电机驱动器。第二个方向是提高开关频率,用SiC器件把载波频率提到100kHz以上,减小滤波器的体积。第三个方向是优化调制算法,比如用不连续PWM降低开关损耗,或者用预测控制提高动态响应。我自己后续做的是第一个方向,加了电流环和速度环,用编码器做位置反馈,跑了一个小功率的永磁同步电机。调试过程中又遇到了不少新问题,比如电流环带宽不够、速度环振荡等等,但那是另一个话题了。如果你也在做类似的东西,我的建议是先把开环跑通,把波形调好,再考虑闭环。开环都跑不好的话,闭环只会更乱。另外,多动手,多测波形,很多问题看波形比看代码快得多。
1. 从一个“看不见摸不着”的旋转矢量说起如果你做过电机控制、逆变器开发,或者玩过三相PWM调制,大概率听过“旋转电压矢量”这个词。我第一次接触这个概念时,脑子里全是问号:电压不是标量吗?怎么还能旋转?后来在实验室里用DSP跑了一遍SVPWM算法,盯着示波器上那三路马鞍波和旋转的合成矢量,才真正理解了这个东西的物理意义。所谓“产生一个旋转的电压矢量”,本质上就是通过三个相位互差120度的电压分量,在空间上合成一个幅值恒定、角度随时间匀速变化的电压矢量。这个矢量在复平面上转一圈,对应的时间就是一个基波周期。听起来简单,但真到动手实现的时候,坑一个接一个:三相占空比怎么算?扇区判断为什么老出错?死区时间设多少合适?载波频率和基波频率什么关系?这篇文章就是把我自己从零搭这套东西的过程完整拆一遍。不管你是刚学电机控制的学生,还是需要快速验证算法的工程师,或者只是对电力电子感兴趣想动手试试的爱好者,下面这些内容应该都能帮你少走弯路。我会从整体设计思路讲起,然后拆解核心细节,再给出一套可以直接复现的实操流程,最后把我在调试中遇到的典型问题和排查方法整理出来。2. 整体设计思路与方案选型2.1 为什么不用模拟电路而选数字方案产生旋转电压矢量,最直观的思路是用三个正弦波发生器加功率放大器。模拟方案确实能出结果,但问题很明显:三路正弦波的相位一致性很难保证,幅值随温度漂移,频率调整也不方便。更关键的是,如果你想改变调制方式或者加死区补偿,模拟电路几乎没法灵活调整。数字方案就不一样了。用一颗MCU或者DSP,配合定时器和PWM模块,所有参数都在代码里,改一个变量就能看到效果。我选的是“定时器中断+查表/实时计算”的混合方式:基波频率低的时候用查表省CPU,频率高或者需要动态调整的时候切到实时计算。这样既保证了实时性,又留了足够的灵活性。具体来说,核心思路是这样的:设定一个目标电压矢量的幅值和旋转频率,在每个PWM周期里计算当前角度,然后根据角度算出三相占空比,最后通过定时器的比较寄存器输出三路PWM。功率级用三相桥式电路,后面接LC滤波或者直接接电机负载。2.2 载波频率与基波频率的取舍载波频率的选择直接决定了输出波形的质量和开关损耗。我一开始图省事,把载波频率设成10kHz,基波频率设成50Hz,结果发现电流波形还行,但开关管发热明显。后来算了一下:10kHz载波下,每个基波周期有200个PWM周期,对于一般的风机水泵类负载够用了,但如果要做高动态响应的伺服控制,这个比值偏低。一般来说,载波频率和基波频率的比值建议在100到500之间。比值太低,低次谐波含量高,电流波形畸变大;比值太高,开关损耗上去了,效率下降。我最后选的是载波频率20kHz,基波频率50Hz,比值400。这个配置下,开关管用的是IGBT模块,加了散热片,温升控制在合理范围内。注意:载波频率超过20kHz后,普通IGBT的开关损耗会急剧增加,这时候要考虑用SiC或者GaN器件。如果只是做实验验证算法,10kHz到15kHz完全够用。2.3 调制方式的对比与选择产生旋转电压矢量,调制方式有好几种:正弦波PWM(SPWM)、空间矢量PWM(SVPWM)、三次谐波注入PWM等等。我一开始用的是SPWM,实现简单,但直流母线电压利用率只有86.6%。后来换成SVPWM,同样的母线电压下,输出线电压基波幅值能提高15%左右。SVPWM的核心思想是把逆变器的八个开关状态对应到复平面上的八个基本矢量,然后通过两个相邻基本矢量和零矢量的时间组合来逼近目标矢量。具体来说,每个PWM周期里,目标矢量落在哪个扇区,就用那个扇区的两个边界矢量和零矢量去合成。这样做的另一个好处是,开关次数比SPWM少三分之一,开关损耗更低。不过SVPWM的实现复杂度比SPWM高不少,尤其是扇区判断和矢量作用时间的计算,很容易出错。我建议如果是第一次做,可以先用SPWM把整个链路跑通,确认硬件没问题、采样没问题,再换成SVPWM优化性能。3. 核心细节解析与实操要点3.1 三相占空比的数学推导假设目标电压矢量在复平面上的角度为θ,幅值为Vref,直流母线电压为Vdc。对于SPWM,三相占空比可以写成:da = 0.5 + (Vref / Vdc) * sin(θ) db = 0.5 + (Vref / Vdc) * sin(θ - 2π/3) dc = 0.5 + (Vref / Vdc) * sin(θ + 2π/3)这里的0.5是偏置,保证占空比在0到1之间。Vref / Vdc这个比值决定了调制比,最大不能超过0.5,否则会出现过调制。如果是SVPWM,计算就复杂一些。首先要判断目标矢量在哪个扇区,然后计算两个相邻基本矢量的作用时间T1和T2,以及零矢量作用时间T0。以第一扇区为例:T1 = (√3 * Ts / Vdc) * (Vref * sin(π/3 - θ)) T2 = (√3 * Ts / Vdc) * (Vref * sin(θ)) T0 = Ts - T1 - T2其中Ts是PWM周期。算出T1、T2、T0之后,再根据七段式或者五段式对称排列,分配到三个比较寄存器里。我实际写代码的时候,把扇区判断和矢量作用时间计算放在一个定时器中断里,中断频率就是载波频率。每次进中断先更新角度θ,然后算占空比,最后写比较寄存器。整个过程在20kHz中断下,用主频100MHz的MCU跑,耗时大概2微秒左右,CPU占用率不到5%。3.2 角度累加的精度问题角度θ的累加看起来简单,但里面有个精度陷阱。如果直接用浮点数累加,比如θ += 2π * f * Ts,时间长了之后,浮点数的舍入误差会累积,导致角度漂移。我实测过,用单精度浮点数跑一个小时,角度漂移大概有0.1度左右。对于一般的电机控制,这个误差可以接受,但如果要做高精度的位置控制,就不行了。解决办法有两个:一是用定点数,把角度映射到0到2^16或者0到2^32的整数范围,每次累加一个固定的增量,溢出后自动回绕。这样没有累积误差,而且计算速度快。二是用双精度浮点数,但会牺牲一些计算速度。我最后用的是定点数方案,角度用16位无符号整数表示,0对应0度,65535对应接近360度。每次中断累加的角度增量根据基波频率和载波频率算出来:angle_increment = (uint16_t)(65536.0 * f_fundamental / f_carrier)比如基波50Hz,载波20kHz,增量就是65536 * 50 / 20000 = 163.84,取整为164。这样每进一次中断,角度加164,溢出后自动回绕。实测下来,角度精度完全够用,而且没有漂移。3.3 死区时间的设置与补偿死区时间是为了防止上下桥臂直通而设置的。我一开始设了2微秒,结果发现输出电压明显偏低,电流波形也有畸变。后来用示波器看了下桥臂的驱动信号,发现死区期间输出电压由负载电流方向决定,如果电流为正,输出电压被拉低;如果电流为负,输出电压被拉高。这个畸变在电流过零点附近最明显。死区时间的设置要根据开关管的特性来。IGBT的关断时间一般在1到2微秒,MOSFET快一些,几百纳秒。我用的IGBT模块,死区设了1.5微秒。补偿的方法有两种:一是根据电流方向调整占空比,电流为正时占空比加一点,电流为负时减一点;二是用硬件补偿电路,但比较麻烦。我用的软件补偿,在中断里读电流采样值,判断方向,然后对占空比做修正。补偿量大概等于死区时间除以PWM周期。实测下来,补偿后输出电压的基波幅值恢复了大概5%左右,电流波形的过零点畸变也明显改善。提示:死区补偿不需要做得很精确,因为死区造成的误差本身就不大。如果调试时间有限,可以先不做补偿,等基本功能跑通了再优化。3.4 采样时机与噪声抑制电流采样和电压采样的时机很关键。如果采样时刻正好在开关管切换的瞬间,会采到很大的开关噪声。我一开始没注意这个问题,采到的电流波形上全是尖刺,后来把采样时刻挪到PWM周期的中间,也就是开关管都稳定导通或关断的时候,噪声就小多了。具体来说,我用的是中心对齐的PWM模式,计数器从0往上数到峰值再往下数到0。在计数器等于峰值的时候触发ADC采样,这时候开关管的状态是稳定的。另外,ADC采样之前加了一级RC低通滤波,截止频率设在大约10kHz,把高频开关噪声滤掉。还有一点,ADC的采样保持时间要足够长,让采样电容充分充电。我用的ADC采样保持时间设了大概1微秒,对于一般的电流传感器输出阻抗,这个时间够了。如果传感器输出阻抗高,采样保持时间还要加长。4. 实操过程与核心环节实现4.1 硬件平台搭建我用的硬件平台是一块三相逆变器板,上面有六个IGBT、三个栅极驱动芯片、直流母线电容、电流传感器和电压采样电路。控制板是一块带DSP的板子,主频100MHz,有专门的PWM模块和ADC模块。接线的时候要注意几点:直流母线电容要尽量靠近逆变器,减小寄生电感;栅极驱动电阻要根据开关管的特性选,太大开关慢损耗大,太小开关快但容易振荡;电流传感器要放在下桥臂,这样采样的是相电流,而且共模电压低。我一开始把电流传感器放在上桥臂,结果共模电压太高,传感器输出饱和了。后来挪到下桥臂,问题解决。另外,直流母线电压不要一上来就加满,先用低压测试,确认PWM输出正常了再慢慢升压。4.2 软件框架与中断服务程序软件框架很简单:主循环里做初始化和状态机,定时器中断里做角度更新和占空比计算。中断服务程序的伪代码如下:void PWM_ISR(void) { // 1. 更新角度 angle += angle_increment; // 2. 计算三相占空比 calculate_duty(angle, Vref, &da, &db, &dc); // 3. 死区补偿 deadtime_compensate(&da, &db, &dc); // 4. 写比较寄存器 PWM_REG_A = (uint16_t)(da * PWM_PERIOD); PWM_REG_B = (uint16_t)(db * PWM_PERIOD); PWM_REG_C = (uint16_t)(dc * PWM_PERIOD); // 5. 清中断标志 clear_interrupt_flag(); }calculate_duty函数里就是前面说的数学推导。如果是SPWM,直接算正弦;如果是SVPWM,先判断扇区再算作用时间。我建议把扇区判断做成查表法,根据角度的高几位直接查表得到扇区号,比用if-else判断快得多。写比较寄存器的时候要注意,比较值不能超过PWM周期的计数值,否则会丢失脉冲。我在代码里加了限幅,把占空比限制在0.05到0.95之间,留一点余量。4.3 参数计算与配置实例以基波频率50Hz、载波频率20kHz、直流母线电压300V、目标输出电压幅值150V为例,算一下关键参数。调制比m = Vref / (Vdc / 2) = 150 / 150 = 1.0。对于SPWM,最大调制比是1.0,对应占空比从0到1。对于SVPWM,最大调制比可以到1.1547,所以150V的目标电压用SVPWM完全没问题。PWM周期Ts = 1 / 20000 = 50微秒。如果定时器主频100MHz,那么一个PWM周期对应5000个计数。比较寄存器的值就是占空比乘以5000。角度增量前面算过了,164。每进一次中断,角度加164,大概400次中断转一圈,对应50Hz。死区时间1.5微秒,对应计数150。补偿量就是150 / 5000 = 0.03,也就是占空比修正3%。4.4 调试步骤与波形观测调试分几步走。第一步,不接功率级,只用示波器看MCU输出的三路PWM,确认占空比按正弦规律变化,相位互差120度。第二步,接上功率级和直流电源,用低压(比如30V)测试,看输出电压波形。第三步,加上LC滤波,看滤波后的正弦波。第四步,接上负载,看电流波形。我调试的时候,第一步就发现了问题:三路PWM的相位不对,B相和C相反了。查了半天代码,发现是数组索引写错了。所以第一步一定要仔细看波形,确认相位关系。第二步的时候,输出电压波形上有很大的尖刺,后来发现是死区时间设得太短,上下桥臂有轻微直通。把死区从1微秒加到1.5微秒,尖刺就没了。第三步,滤波后的正弦波有明显的三次谐波,后来换成SVPWM,三次谐波就小多了。第四步,接上感性负载,电流波形基本正弦,THD大概3%左右,满足一般应用要求。5. 常见问题与排查技巧实录5.1 扇区判断错误导致输出异常SVPWM的扇区判断是最容易出错的地方。我一开始用if-else判断角度范围,结果在扇区边界附近老是跳变,导致输出波形上有毛刺。后来改成查表法,把0到360度分成六个扇区,每个扇区60度,用角度的高几位直接查表,问题解决。还有一个坑是角度定义和扇区定义的对应关系。有的资料里角度从0开始对应第一扇区,有的从-30度开始。我建议自己画一遍基本矢量的分布图,把每个扇区的角度范围标清楚,然后再写代码。5.2 过调制导致的波形削顶如果目标电压幅值设得太大,超过了调制比上限,就会出现过调制,输出电压波形削顶,电流波形畸变。我一开始把Vref设成180V,母线电压300V,调制比1.2,超过了SPWM的1.0上限,结果波形削顶严重。解决办法有两个:一是降低Vref,保证调制比不超过上限;二是换成SVPWM,调制比上限提高到1.1547。如果还需要更高的输出电压,就得用过调制算法,但那样波形质量会下降。5.3 电流采样噪声与滤波参数电流采样噪声大是常见问题。除了前面说的采样时机和RC滤波,还可以在软件里加滑动平均滤波。我用的是四点滑动平均,每进一次中断更新一次,滤波后的电流波形明显平滑。但滑动平均会引入相位滞后,对于高动态响应的应用,滞后会影响控制性能。所以滤波参数要根据应用需求来定。如果只是做实验验证,滤波可以重一点;如果是做闭环控制,滤波要轻一点,或者用更复杂的滤波器。5.4 常见问题速查表问题现象可能原因排查方法解决措施输出电压偏低死区时间过长示波器看桥臂波形减小死区或加补偿电流波形有尖刺采样时机不对调整采样时刻到PWM周期中间加RC滤波或软件滤波扇区边界输出跳变扇区判断逻辑错误打印扇区号观察改用查表法波形削顶调制比过高计算调制比降低Vref或换SVPWM角度漂移浮点累加误差长时间运行观察改用定点数开关管发热严重载波频率过高测开关损耗降低载波频率或换器件提示:这张表是我自己调试过程中总结的,不一定覆盖所有情况,但大部分常见问题都能在里面找到线索。遇到新问题的时候,先别急着改代码,用示波器把关键波形看一遍,往往能很快定位。5.5 几个容易被忽略的细节第一个细节是PWM输出的死区插入方式。有的MCU硬件自动插入死区,有的需要软件设置。硬件插入的死区精度高,但灵活性差;软件插入灵活,但占用CPU时间。我用的是硬件插入,在初始化的时候配置好死区寄存器就行。第二个细节是ADC采样的触发源。我用的是PWM模块的周期中断触发ADC,这样采样时刻和PWM周期严格同步。如果用的是软件触发,采样时刻会抖动,影响控制精度。第三个细节是中断优先级。PWM中断的优先级要设得高一些,避免被其他中断打断导致PWM输出异常。我把PWM中断设成最高优先级,其他中断比如串口中断设成低优先级。第四个细节是故障保护。逆变器最怕的是上下桥臂直通,一旦发生,开关管瞬间烧毁。所以硬件上要有过流保护,软件上要有故障检测和快速关断。我在代码里加了过流中断,一旦触发,立刻封锁PWM输出。6. 从实验到产品的几个扩展方向这套东西跑通之后,可以往几个方向扩展。第一个方向是闭环控制,加上电流环和速度环,做成完整的电机驱动器。第二个方向是提高开关频率,用SiC器件把载波频率提到100kHz以上,减小滤波器的体积。第三个方向是优化调制算法,比如用不连续PWM降低开关损耗,或者用预测控制提高动态响应。我自己后续做的是第一个方向,加了电流环和速度环,用编码器做位置反馈,跑了一个小功率的永磁同步电机。调试过程中又遇到了不少新问题,比如电流环带宽不够、速度环振荡等等,但那是另一个话题了。如果你也在做类似的东西,我的建议是先把开环跑通,把波形调好,再考虑闭环。开环都跑不好的话,闭环只会更乱。另外,多动手,多测波形,很多问题看波形比看代码快得多。