☰
三矢量MPC替代单矢量:PMSM电流纹波与固定开关频率的工程实战
2026/10/24 2:53:38 网站建设 项目流程

三个月前,我在测试台前对着相电流波形上密密麻麻的毛刺皱眉头。当时跑的是传统单矢量模型预测电流控制(FCS-MPC),动态响应确实快,可电流纹波实在扎眼,而且开关频率不固定,给滤波器和EMC设计添了不少堵。后来我把思路从“一个周期只选一个矢量”挪到“一个周期用三个矢量”上,也就是标题里说的相邻有效矢量加零矢量,这版方案实测下来电流质量明显变好,开关频率也稳定了。这篇文章就把这段时间踩过的坑、推导的过程、代码里的关键细节,以及调试时最容易翻车的地方,一次性说透。

这套东西适合正在做电机驱动算法的人,尤其是搞永磁同步电机、伺服驱动、新能源汽车电机控制的朋友。如果你是学生或者刚接触模型预测控制,也不用慌,我尽量把每一步背后的“为什么”都写出来,哪怕暂时不写代码,也能把整套逻辑捋顺。至于已经跑过单矢量MPC的人,这篇对你属于直接升级包。

1. 为什么单矢量MPC不够用:三矢量的设计动机

1.1 单矢量MPC的痛点

先说说单矢量MPC为什么让人又爱又恨。它的逻辑很简单:采样电流,用电机模型外推下一步电流,然后把逆变器所有可能的开关状态(三相两电平逆变器总共8个,其中6个有效矢量、2个零矢量)逐个代入代价函数,选一个能让电流误差最小的矢量,作用整个采样周期。

好处是直观,动态响应快,不需要调制器,代价函数里还能塞各种约束。但问题也很突出:一个采样周期内只作用一个矢量,相当于用“离散的电压点”去逼近连续参考电压,精度天然不足。你会发现电流纹波偏大,而且不同工况下最优矢量可能连续几个周期都不变,也可能每个周期都在跳,开关频率完全不受控,忽高忽低。单矢量MPC在低开关频率下尤其难受——纹波大、噪声怪、死区效应也被放大,这是我在测试中发现最劝退的地方。

有人说那把采样频率拉高不就行了?可以,但代价是处理器算力直线上升,而且开关损耗也压不住。于是业界和学术界就想到一个折中方案:一个周期内不只用一个矢量,而是用两个有效矢量加一个零矢量,通过分配作用时间,等效合成一个任意方向的平均电压矢量。这就是“三矢量MPC”的起点。

1.2 相邻有效矢量加零矢量的组合思路

这里有个关键选择:为什么偏偏选“相邻”的两个有效矢量?因为电压空间矢量平面被六个有效矢量分成了六个60度扇区,每个扇区里的任意参考电压矢量,都能由该扇区两侧的两个相邻有效矢量线性合成。

选择相邻矢量,本质上和SVPWM的扇区逻辑是一致的。相邻矢量之间的切换,每次只改变一相桥臂的开关状态,开关损耗小,电流轨迹也更平滑。如果选非相邻矢量(比如V1和V4),虽然也能合成某些电压,但每次切换可能要同时动两相甚至三相,开关动作次数和损耗都会上去,在一个控制周期内塞三个矢量的时候,这种损耗差异会被进一步放大。

零矢量在这里起的是“填空”作用。两个有效矢量的幅值方向是固定的,靠它们的组合只能合成扇区内一条弧线上的电压,想要调节幅值,就得加入零矢量(000或111)来占掉一部分时间。零矢量本身对电流变化没有净贡献,所以插入零矢量的比例直接决定了合成电压的幅值大小。这样,三矢量组合的等效电压可以在0到直流母线电压可控范围内连续可调,方向也能覆盖整个扇区。

相比更花哨的“在线枚举所有两矢量、三矢量组合”的MPC方案,这里说的“传统三矢量”其实是更工程化的做法:先用无差拍原理求出期望参考电压矢量,再用伏秒平衡公式直接算出三个矢量的作用时间,不需要滚动枚举,计算量小,时序也好控制。

2. 核心推导:从预测模型到作用时间的来龙去脉

2.1 d-q轴电流预测模型与无差拍期望电压

整套算法的起点是永磁同步电机在旋转坐标系下的电流方程:

[ u_d = R_s i_d + L_d \frac{di_d}{dt} - \omega_e L_q i_q ]

[ u_q = R_s i_q + L_q \frac{di_q}{dt} + \omega_e L_d i_d + \omega_e \psi_f ]

其中Rs是定子电阻,Ld和Lq分别是d/q轴电感,ωe是电角速度,ψf是永磁磁链。

用前向欧拉离散化,采样周期为Ts,可以得到:

[ i_d(k+1) = i_d(k) + \frac{T_s}{L_d}\left[u_d(k) - R_s i_d(k) + \omega_e L_q i_q(k)\right] ]

[ i_q(k+1) = i_q(k) + \frac{T_s}{L_q}\left[u_q(k) - R_s i_q(k) - \omega_e L_d i_d(k) - \omega_e \psi_f\right] ]

到这里,我们就有了“预测模型”。所谓无差拍,就是反着用这个模型:我们希望下一个采样周期电流正好等于参考值,也就是令 [ i_d(k+1)=i_d^, i_q(k+1)=i_q^],解出当前应该施加的电压:

[ u_d^* = \frac{L_d}{T_s}(i_d^* - i_d) + R_s i_d - \omega_e L_q i_q ]

[ u_q^* = \frac{L_q}{T_s}(i_q^* - i_q) + R_s i_q + \omega_e L_d i_d + \omega_e \psi_f ]

这个u_d^*和u_q^*就是无差拍电压,是当前控制周期最理想的电压矢量。因为有电流反馈和参数项,它其实已经把反电动势和交叉耦合都考虑进去了。

然后通过反Park变换,把旋转坐标系下电压转到静止的α-β坐标系:

[ v_\alpha^* = u_d^* \cos\theta - u_q^* \sin\theta ]

[ v_\beta^* = u_d^* \sin\theta + u_q^* \cos\theta ]

θ是转子电角度。到这里,我们拿到了目标电压矢量v*。

2.2 伏秒平衡:两个有效矢量加零矢量怎样合成参考电压

接下来要解决的问题是:在一个开关周期Ts内,怎样分配两个相邻有效矢量和零矢量的作用时间,让它们的平均效果等于v*。

假设当前v*落在第I扇区,也就是0°到60°之间。这两个相邻有效矢量取V1(100)和V2(110),它们在α-β坐标系下的分量分别是:

[ V_1: \left(\frac{2}{3}V_{dc}, 0\right) ]

[ V_2: \left(\frac{1}{3}V_{dc}, \frac{\sqrt{3}}{3}V_{dc}\right) ]

零矢量V0的幅值为0。设t1、t2、t0分别是三个矢量的作用时间,满足:

[ t_1 + t_2 + t_0 = T_s ]

伏秒平衡就是让合成后的伏秒积相等:

[ v_\alpha^* T_s = \frac{2}{3}V_{dc} t_1 + \frac{1}{3}V_{dc} t_2 ]

[ v_\beta^* T_s = \frac{\sqrt{3}}{3}V_{dc} t_2 ]

由第二个方程直接得到:

[ t_2 = \frac{\sqrt{3} v_\beta^* T_s}{V_{dc}} ]

代入第一个方程整理得到:

[ t_1 = \frac{(3v_\alpha^* - \sqrt{3}v_\beta^*) T_s}{2V_{dc}} ]

然后:

[ t_0 = T_s - t_1 - t_2 ]

这三个公式就是第I扇区的解析解。整个过程没有迭代,没有搜索,纯粹是解一个二元一次方程组,MCU里面几个时钟周期就算完了。实际工程中我会先检查t1和t2是否为负,如果为负说明v*其实不在当前扇区,属于扇区判断误差或数值饱和,需要钳位修正。

提示:这套推导里,把零矢量看成(0,0)代入伏秒平衡,本质上是线性的叠加。因为Ts很短,电流在一个周期内近似匀速变化,所以这种“平均电压”近似是成立的。

2.3 扇区判定与坐标旋转复用公式

其他五个扇区没必要重新推导公式。更聪明的做法是:先把v*旋转到第I扇区,然后用同一套公式计算t1和t2,再把结果映射回对应扇区的两个有效矢量。

具体来说,如果v*的角度落在第n个扇区,扇区起始角是:

[ \theta_{sector} = n \times \frac{\pi}{3} ]

把v*反向旋转θ_sector,得到旋转后的vα'_rotate和vβ'_rotate:

[ v_{\alpha_rot} = v_\alpha^* \cos(-\theta_{sector}) - v_\beta^* \sin(-\theta_{sector}) ]

[ v_{\beta_rot} = v_\alpha^* \sin(-\theta_{sector}) + v_\beta^* \cos(-\theta_{sector}) ]

然后把vα_rot和vβ_rot代入前面第I扇区的公式,算出t1和t2。这样就只需要准备一套公式,六个扇区通用。

扇区本身可以用角度直接算:

theta_src = atan2f(v_beta_star, v_alpha_star); if (theta_src < 0.0f) theta_src += 2.0f * PI; sector = (int)(theta_src / (PI / 3.0f)); // 0~5

也可以用SVPWM里常用的三值符号判断法,但角度法直观,够用。扇区和有效矢量组合的对应关系在下一节给表。

3. 动手实现:三矢量MPC的代码落地与波形调试

3.1 主循环结构和开关表

把一个控制周期的执行逻辑拆开,大概是这几步:

  1. 采样三相电流、转子位置、母线电压
  2. Clarke变换得到iα、iβ,Park变换得到id、iq
  3. 查表或用MTPA计算id*、iq*
  4. 用无差拍公式计算ud*、uq*
  5. 反Park得到vα*、vβ*
  6. 判定扇区,坐标旋转,套公式算出t1、t2、t0
  7. 根据扇区映射到实际开关组合,生成七段式PWM比较值
  8. 装载PWM寄存器,等待下一个周期中断

其中第4步我用的是上一节给出的公式,包含反电动势补偿项。有的人会把电流采样放在PWM计数的谷底或者峰值,这个根据你的硬件习惯来,不重要,重要的是采样时刻和控制周期严格对齐,否则模型预测会引入一拍延迟误差。

扇区和开关组合的映射表,建议直接写死:

扇区有效矢量1有效矢量2三相开关序列(按七段式)
I100110000-100-110-111-110-100-000
II010110000-010-110-111-110-010-000
III010011000-010-011-111-011-010-000
IV001011000-001-011-111-011-001-000
V001101000-001-101-111-101-001-000
VI100101000-100-101-111-101-100-000

这里“100”表示A相上桥臂导通,B、C相下桥臂导通,以此类推。注意实际工程中通常会在序列两端插入同一组有效矢量或零矢量来保证对称性,最常用的是七段式,也就是两边用零矢量000,中间用零矢量111,这样每个周期首尾状态相同,PWM载波对称性最好,谐波能量也更集中。

3.2 七段式对称PWM与作用时间分配

七段式的具体时间分配可以这样拆:设整个周期开头和结尾的零矢量各占t0/4,中间的零矢量占t0/2,两个有效矢量各占一半。也就是说:

  • 第一段:000,时间t0/4
  • 第二段:有效矢量1,时间t1/2
  • 第三段:有效矢量2,时间t2/2
  • 第四段:111,时间t0/2
  • 第五段:有效矢量2,时间t2/2
  • 第六段:有效矢量1,时间t1/2
  • 第七段:000,时间t0/4

加一起验证:t0/4 + t1/2 + t2/2 + t0/2 + t2/2 + t1/2 + t0/4 = t0 + t1 + t2 = Ts,没问题。

这段逻辑用代码实现时,最方便的办法是转换成三个桥臂的占空比。因为每个扇区里的开关序列虽然不同,但某个桥臂在两个有效矢量之间的状态变化是确定的,你可以直接根据扇区查表得到A、B、C三相的PWM比较值,然后写道比较寄存器里。我习惯维护一个CMP数组:

float cmp_a, cmp_b, cmp_c; switch (sector) { case 0: // 扇区I cmp_a = t0/4 + t1/2 + t2/2; // A相一直为高,中间从100到110再到111 cmp_b = t0/4 + t1/2; // B相只在第二个有效矢量段变高 cmp_c = t0/4; // C相在整个有效矢量期间保持低 break; // 其他扇区同理,查表即可 }

具体每个扇区的cmp表达式很容易推导,按住七段式的开关序列逐段累计就行了。这里不展开全部六段,但工程上一定要自己画一遍时序图,别硬背公式,画一次你就再也不会搞混。

3.3 参数标定与边界限幅

写代码时最容易忽略的是作用时间的限幅。t1、t2、t0理论上都是非负且加起来等于Ts,但实际运行时由于参数误差、电流采样噪声、电压饱和,很可能出现下面两种情况:

  • t1 + t2 > Ts,也就是两个有效矢量的时间之和已经超过了整个周期,说明参考电压矢量超出了逆变器能输出的线性范围,进入了过调制区。这时候按比例缩放两个有效矢量:t1' = t1Ts/(t1+t2),t2' = t2Ts/(t1+t2),t0设为0。

  • t1或t2为负,通常说明扇区判断边界刚好卡在误差附近,或者无差拍电压计算值存在震荡。我的处理方法是将负值钳到0,另一个时间补上,但这不是长久之计,要从扇区判断的平滑性和给定值的斜坡上找原因。

母线电压Vdc不能一直用常数,尤其电池供电或电网波动明显的场合。我都是每个周期实时采样Vdc,再用一阶滤波压掉噪声。否则电压一变,伏秒平衡就失真,电流控制会抖。

注意:作用时间公式里用的Vdc是母线电压的线性平均值,如果死区时间比较长,还要做死区补偿。否则轻载工况下电流波形会出现明显的平顶失真,我在这里吃过亏。

4. 实验对比与常见问题排查

4.1 实验波形与性能对比

我在一台某公司的电机测试台架上做了对比实验,电机参数大概是某款额定310V的永磁同步电机,电感标称值Ld=0.8mH、Lq=1.2mH,极对数4,额定转速3000rpm。采样频率设10kHz,母线电压约310V。

第一轮跑单矢量MPC,相电流毛刺明显,用功率分析仪看THD大概在9%左右。跑三矢量MPC之后,同工况下电流THD降到5%以内,而且因为每个周期都固定完成一次完整的矢量组合,开关频率稳定在载波频率附近,电流噪声从那种杂乱的“噼啪”声变成均匀的“嗡嗡”声,这在实际产品上是很重要的体验差异。

动态性能上,三矢量MPC不会比单矢量MPC慢太多。因为每个控制周期都在实时计算电压参考,本质上还是模型预测的响应节奏,从转矩阶跃到电流建立,大概一个控制周期内就能响应。代价是多花了一点时间做坐标变换和伏秒平衡计算,在现在的MCU上这是几十纳秒的差别,根本不构成压力。

除了电流谐波,我还比较了两种算法在零速低速区的表现。单矢量MPC在低速时零矢量选多了电流纹波会加大,三矢量MPC因为有固定周期内的矢量合成,波形更规整。这也是我最终决定换掉老方案的原因。

4.2 高频噪声、过流、扇区切换抖动等典型问题

调试过程中我遇到最坑的一个问题:扇区边界处的电流抖动。现象是转速在某个区间来回晃时,电流波形偶尔跳变一下,幅度不大但明显能听出来。后来定位到是角度触发扇区切换时,v落在了扇区边界附近,t1或t2在0附近来回跳,导致开关序列频繁切换。解决办法是在扇区判断前加一点迟滞:如果当前扇区与上一周期扇区相邻,且v角度离边界太近,就沿用上一周期的扇区,这个迟滞窗口我取1到2度,效果立竿见影。

还有一次是电感参数标错导致的高频啸叫。当时用万用表粗测相电感,忽略了不同转速下磁路饱和的影响,实际运行中大电流工况下Lq掉得厉害,无差拍公式算出来的电压偏高,电流开始震荡。后来我把Ld和Lq改成按id和iq的幅值查表修正,问题才消停。如果你不想维护查表,至少要在调试软件里留一手按实测辨识参数更新的功能。

启动过流是另一个容易踩的雷。三矢量MPC在零速启动时,如果当时参考电流给得比较莽,无差拍算出的电压会很大,作用时间限幅又没做好,就容易顶到过流保护。我习惯在速度环输出端加一个斜坡限幅器,让dq轴参考电流按速率上升,而不只是靠电流环的斜坡。再配合作用时间钳位,启动过程就稳了。

4.3 排查速查表

现象可能原因排查和解决方向
电流纹波偏大采样频率低或Lq参数偏离实际提高采样频率;标定电感参数或用在线辨识
高频啸叫/振荡无差拍增益过高,模型参数不匹配降低Ts或增加代价函数权重,检查电感值
扇区边界毛刺角度判断抖动,v*落在扇区边界扇区判定加迟滞,或滤波v*角度
过流报警启动给定太猛,作用时间超限未钳位斜坡限制参考电流,严格做t1/t2钳位
零速电流波浪形零矢量占比过大,死区影响突出加死区补偿,或改用对称零矢量分配
噪声频谱杂乱开关频率不稳定确认是否跑成三矢量固定频率;检查中断优先级

5. 写在最后的一点体会

这套传统三矢量MPC,本质上是用SVPWM的调制思路去补FCS-MPC的短板。它保留了预测控制的动态敏捷,又通过伏秒平衡拿到了调制稳定器和固定开关频率的优势。实现难度并不高,核心就在那几个公式和一张扇区表,真正的坑都在参数标定、边界处理和时序对齐上。

如果你正准备从单矢量MPC往三矢量MPC迁移,我的建议是别急着一步到位。先在仿真环境里跑通无差拍加伏秒平衡的流程,再搬到板子上,先把电流环闭环起来,确认作用时间输出正常,再逐步加扇区迟滞和限幅保护。调试时多花点时间观察t1、t2、t0这三个值,它们的比例关系和波形特征能告诉你很多东西。

最后分享一个小技巧:调试三矢量MPC时,别只看相电流波形,把t1、t2、t0和v在α-β坐标系里的轨迹一起录下来。有一次我就是看到v在扇区边界附近画出了一个“打结”的轨迹,才定位到角度抖动的问题。这三个时间值和参考电压轨迹,比电流波形更能暴露算法内部的隐患。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询