三相PWM整流器在能量回馈、有源前端、电动汽车V2G这些场景里越来越常见,说白了它就是一块能"反过来发电"的整流器,把交流侧单位功率因数可控地变成直流母线电压。我最早接这个方向,是因为一台要求频繁加减载、母线电压波动要小于5%的回馈装置,当时用传统双闭环PI一版方案做下来,稳态能压住,一遇负载突变就露馅,这才开始认真看有限集模型预测电流控制这条路。这篇文章把我从数学离散、Simulink建模到调参踩坑的完整过程写出来,适合正在做三相PWM整流器仿真、想把FCS-MPC跑通并弄清楚内部细节的人参考,也适合想从PI切换MPC但不知道第一步怎么下手的朋友。先说结论:这套方案在Simulink里完全能复现,动态确实比PI快半个身位,但坑比想象中多,尤其是离散模型、一拍延迟和权重因子这三件事,处理不好就是满屏毛刺。
1. 从PI双闭环的软肋说起:FCS-MPC到底解决了什么问题
1.1 三相PWM整流器的应用场景与核心痛点
先捋清楚三相PWM整流器到底用在哪儿。最常见的三类场景:一是电机回馈系统,比如电梯、提升机、离心机,原来靠制动电阻把能量烧掉,现在用PWM整流器把直流侧能量反馈回电网,省电;二是UPS和电能质量治理设备的前级,要求输入电流正弦、功率因数接近1,同时直流母线电压稳定;三是新能源并网和储能变流器,本质也是一个双向AC/DC拓扑。它的核心能力就是四象限运行:既能整流把交流变成直流,也能逆变把直流回馈到交流,而且输入电流是可控的正弦波,不是传统不控整流的尖峰电流。
这个拓扑一点都不复杂,但控制上有硬要求:母线电压要稳、电流波形要干净、动态响应要快。母线电压不稳会把后级逆变器的调制都带偏,电流波形谐波大了过不了并网标准,动态响应慢一点就可能触发过压或者欠压保护。所以控制策略一直是这个方向的研究重点。
1.2 双闭环PI控制哪里不够用
传统方案是电压外环加电流内环,外环PI输出d轴电流给定,内环PI控制dq轴电流,再经过调制器(SVPWM或SPWM)输出开关信号。PI参数好好调一调,稳态性能和动态性能在很多场合是够用的,这也是为什么工业现场直到今天还是PI占大多数。
但PI方案有几个先天问题。第一,PI控制的带宽受限于调制和采样,动态响应不可能无限快,负载突变时直流母线电压会有明显跌落,恢复时间靠PI积分慢慢扛。第二,dq解耦是需要精确知道自己耦不耦合的,电感参数如果和实际偏差大,d轴、q轴电流会互相串扰,动态过程会变慢甚至震荡。第三,PI内环本质上是线性控制器处理非线性被控对象,在整流器这种变结构强耦合系统里,遇到大扰动时表现往往不理想。
我实际测到的情况是:PI稳态THD能做到不错,比如5%以内,但负载从半载切到满载时,直流母线要掉20V以上,恢复时间在100ms左右。某些回馈工况,电流畸变更明显。这些就是我转向模型预测控制的直接原因。
1.3 "有限集"到底是什么意思
模型预测控制MPC的通用思路是:根据被控对象模型,预测未来几步的行为,选一个能让代价函数最小的控制量输出。对于三相PWM整流器,控制量是开关管的开关状态,这个状态不是连续的,二电平三相桥臂一共就8种组合,所以叫"有限集"。FCS-MPC就是在这8个离散的开关状态里穷举,哪个状态对应的预测电流最接近参考电流,下一拍就输出哪个状态。
这个思路最大的好处是直观、无需调制器。PI需要经过调制器才能生成PWM,MPC直接把代价函数最小的开关状态给到桥臂,本质上是一个在线优化问题。另一个好处是约束处理很自然,比如你希望限制电流不超过某个值,只要在代价函数里加一个惩罚项就行。当然,代价函数怎么写、权重因子怎么调,是后面所有麻烦的来源。不过先理解核心思想:预测每一种可能的结果,然后选最好的那一个,就这么简单。
2. 先把离散数学和开关状态算清楚,后面才不返工
2.1 三相PWM整流器的基本拓扑与开关函数
建模是仿真第一步。三相PWM整流器主电路拓扑如下:三相交流电源经滤波电感L和等效电阻R连接到三相桥臂——桥臂上半部分和下半部分各一只IGBT,直流侧是支撑电容和负载。每相桥臂有且仅有两种状态,定义开关函数S=1表示上管导通、下管关断,S=0表示上管关断、下管导通。
三相桥臂的组合就是二进制的000到111,共8种状态,对应8个电压矢量。其中000和111比较特殊,交流侧被短路,电流通过续流二极管续流,输出电压矢量为零,叫零矢量。剩下6个是有效矢量,把三相电压空间分成了六个扇区。
这里有个关键方向约定:我采用本书最常用的整流器电压方程,等下建模时所有开关状态对应的电压方向都以这个为准,否则仿真结果全反,电流会发散。
2.2 αβ坐标系下的连续数学模型
为了让三相系统在控制算法里好算,先用等幅值Clarke变换把三相abc量转换到两相静止αβ坐标系。三相电压方程在αβ坐标系下可以写成:
L * (di_α/dt) = e_α - v_α - R * i_α L * (di_β/dt) = e_β - v_β - R * i_β
其中e_α/e_β是电网电压在αβ轴上的分量,v_α/v_β是整流器交流侧电压(由开关状态和直流母线电压共同决定),i_α/i_β是网侧电流。
每个开关状态对应的整流器交流侧相电压,按三桥臂的中点对直流负母线计算:
v_a = Vdc / 3 * (2S_a - S_b - S_c) v_b = Vdc / 3 * (-S_a + 2S_b - S_c) v_c = Vdc / 3 * (-S_a - S_b + 2*S_c)
再做Clarke变换得到v_α、v_β。做仿真之前,把这8组值自己用Excel算一遍,对照表如下,后面看波形、排查问题都会非常方便:
| 开关状态(Sa,Sb,Sc) | v_α | v_β |
|---|---|---|
| 000 | 0 | 0 |
| 100 | 2/3*Vdc | 0 |
| 110 | 1/3*Vdc | sqrt(3)/3*Vdc |
| 010 | -1/3*Vdc | sqrt(3)/3*Vdc |
| 011 | -2/3*Vdc | 0 |
| 001 | -1/3*Vdc | -sqrt(3)/3*Vdc |
| 101 | 1/3*Vdc | -sqrt(3)/3*Vdc |
| 111 | 0 | 0 |
这张表我会一直贴在模型旁边,无论是查波形反了,还是看某个扇区切换异常,拿它核对绝对不会错。
2.3 离散化公式与电流预测
FCS-MPC要在数字控制器里运行,必须把连续微分方程离散化。最常用的是前向欧拉法,采样周期为Ts,则:
i(k+1) ≈ (1 - R*Ts/L) * i(k) + (Ts/L) * (e(k) - v(k))
这就是核心预测公式。式子很直观:当前拍测得电流i(k)、电网电压e(k)和直流母线电压Vdc(k),代入8种开关状态对应的v(k),就能算出8种可能的i(k+1)。再把参考电流i_ref(k+1)和每一个预测值做差,求代价值:
g = (i_α_ref - i_α_pred)² + (i_β_ref - i_β_pred)²
取g最小的那一组开关状态作为下一周期的输出。注意参考电流这里的下标是αβ分量,实际控制中一般通过电压外环得到d轴电流参考、q轴电流参考给0,然后根据电网相位角做逆Park变换得到αβ参考值,再进入代价函数。
离散化这一步最容易犯的错是忘记单位、把电感值写成mH而不是H,导致预测电流数值大得离谱,代价函数永远选零矢量,电流直接失控。我建议在MATLAB Function里先加一个断言,让初始检查别溢出。
3. Simulink分模块搭建,每个模块都别想当然
3.1 主电路:三相电源、L滤波器、整流桥和负载
我用的环境是MATLAB R2021b + Simscape Electrical,整套模型从主电路到控制算法大概两三小时能搭完。主电路模块选型如下:
- 三相电源:Three-Phase Source,设为星形Y接,相电压有效值220V,频率50Hz,默认内阻可以设很小(比如0.001Ω)。
- 滤波电感:Three-Phase Series RLC Branch,选成RL串联,电阻0.1Ω,电感5mH。因为实际电感总有内阻,纯L会让仿真起步阶段有轻微直流偏置。
- 整流桥:Universal Bridge,Power Electronic device选IGBT/Diode,桥臂数3,Gate inputs选single pulses(这一个设置很重要,后面写门信号就只需要输出三路上管信号)。
- 直流侧:并联一个电容C=2200μF,再并联一个可调电阻做负载。电容容量和电压纹波、动态特性直接相关,后面讲参数时会细说。
主电路接线要注意共地问题。Simscape Electrical里,电感左边接三相电源,右边接桥臂交流输入端,直流负母线要连接到三相电源的中性点吗?这取决于电源和负载接地设置。我的习惯是电源輸出侧用浮地,不做额外接地,Universal Bridge内部自带虚拟参考,仿真模型才能正常求解。如果你发现仿真特别慢或者提示代数环,大概率是接地和电气参考点设置有问题。
3.2 测量、坐标变换和外环PI
控制部分先从测量说起。需要采集的信号有:三相电网电压、三相电流、直流母线电压。优先用Three-Phase V-I Measurement模块,一次把电压电流都测量出来,输出是Simulink信号,后面好接控制算法,比单独一个一个Voltage Measurement接Simulink转Simscape接口要省事得多。
坐标变换分两步。第一步,把测到的三相电压、电流用Clarke变换转到αβ:直接写一个小的MATLAB Function,公式是:
alpha = (2/3)(a - 0.5b - 0.5c) beta = (sqrt(3)/3)(b - c)
第二步,用PLL获取电网相位θ,然后做Park变换得到dq电流:
d = alphacos(θ) + betasin(θ) q = -alphasin(θ) + betacos(θ)
外环电压PI:直流母线电压给定Vdc_ref减去测量电压Vdc,PI输出作为d轴电流参考i_d_ref。由于单位功率因数要求,q轴电流参考i_q_ref设0。PI参数用工程整定法从带宽估:先按Kp取L电流环带宽的对应值,Ki取Kp的五分之一到十分之一作为基础,再根据阶跃响应微调。我这里用过一组典型值:Kp=1.2,Ki=60,积分限幅±20,输出限幅±30。
电压外环输出的是电流参考,经过逆Park变换得到i_α_ref和i_β_ref,才送入MPC核心模块。
3.3 MPC核心:MATLAB Function逐状态遍历
核心算法用MATLAB Function实现,输入为当前αβ电流、αβ电网电压、直流母线电压、αβ参考电流,输出为三路上管门信号。下面是我一直在用的基础版本代码:
function [ga, gb, gc] = fcs_mpc(ia, ib, ea, eb, vdc, iaref, ibref, Ts, L, R) % 8种开关状态,S=1表示上管导通,下管互补 sw = [0 0 0; 1 0 0; 1 1 0; 0 1 0; 0 1 1; 0 0 1; 1 0 1; 1 1 1]; g_opt = 1e10; ga = 0; gb = 0; gc = 0; A = 1 - R*Ts/L; B = Ts/L; for k = 1:8 sa = sw(k,1); sb = sw(k,2); sc = sw(k,3); va = vdc/3*(2*sa - sb - sc); vb = vdc/3*(-sa + 2*sb - sc); vc = vdc/3*(-sa - sb + 2*sc); valpha = 2/3*(va - 0.5*vb - 0.5*vc); vbeta = (sqrt(3)/3)*(vb - vc); ipa = A*ia + B*(ea - valpha); ipb = A*ib + B*(eb - vbeta); g = (iaref - ipa)^2 + (ibref - ipb)^2; if g < g_opt g_opt = g; ga = sa; gb = sb; gc = sc; end end end这段代码的核心就是三步:算电压矢量、预测电流、选最小代价。注意MATLAB Function输出默认是double型,而Universal Bridge的门信号希望是逻辑或double都可以,直接接就行。如果你在Simulink把MATLAB Function改为离散采样时间,别忘了把Ts也设成和主控制周期一致,防止出现“模块输出变化次数过多导致求解器闪变”。
3.4 采样时间、求解器和仿真参数怎么设置
仿真参数这一块看似不起眼,其实会影响整个模型是否可信。控制采样时间Ts我取50μs,即20kHz控制频率,这个频率对FCS-MPC来说属于比较常规的选择。Ts太大,比如200μs以上,预测精度变差,电流纹波会明显变大;Ts太小,比如10μs,MATLAB Function每步遍历8个状态虽然不算重,但和主电路电磁暂态的求解器耦合起来,仿真会慢得让人失去耐心。
求解器推荐用离散或固定步长。主电路是连续系统,Simscape Electrical需要连续求解,但控制算法是离散的,这时用固定步长ode3或者ode4,步长设为2μs,比控制周期小一个数量级,保证主电路状态在每个控制周期内有足够的插值点。如果你用变步长求解器,控制算法和主电路模块之间的采样不匹配会引起抖动,尤其是MATLAB Function这种自己定义离散更新率的模块,我建议直接固定步长,经验值:仿真步长2μs,控制周期Ts=50μs。
最后加一个单位延迟Unit Delay模块在MPC输出后面,模拟数字控制器的一拍延迟,这个后面第5章会专门讲为什么它很重要。
4. 仿真结果怎么判读:稳态、动态和权重因子
4.1 稳态波形达到什么算"合格"
模型跑通后,第一步先看稳态。把负载设成额定功率,比如10kW,直流母线电压给定650V,等波形稳定到2s以后,观察几个关键指标:
输入三相电流是否正弦,有没有明显畸变;电流幅值是否和功率匹配,10kW对应交流侧线电流大约15A;直流母线电压是否稳在650V附近,纹波峰峰值控制在10V以内已经算很好;网侧电压和电流是否同相位,功率因数接近1。
我第一次跑出来的电流波形,看着像那么回事,但仔细看有比较明显的高频锯齿,这就是FCS-MPC的基本特征——开关频率不固定,谐波散布在较宽频带。做FFT分析时会看到谐波不像SVPWM那样集中在载波频率附近,而是比较分散,这是MPC天然的特点,不是bug。如果你看到的是20kHz以上的连续噪声频谱,反而是正常的。要检查电流有没有直流偏置,看αβ电流瞬态值是否围绕零轴来回穿过,如果有缓慢漂移,基本可以断定离散模型里R或者e的符号反了。
4.2 动态响应:负载突变是试金石
动态性能才是FCS-MPC的主场。仿真1s时把负载电阻从20Ω跳到10Ω,观察直流母线电压波形:PI控制的典型表现是母线先掉下去再慢慢爬回来,掉落的深度由电容容量和环路速度决定,恢复时间通常在80~150ms;而MPC内环动态更快,母线电压跌落幅度更小,恢复时间通常可以压到50ms以内。
这里有个容易误判的点:动态响应快慢不完全取决于MPC内环,还取决于外环PI。如果外环PI调得很软,内环再快也没用,母线电压恢复照样慢。FCS-MPC真正改善的是电流内环的跟随速度,当电网电压突然波动、负载突加突卸时,电流能够在几个控制周期内跟上参考变化。所以在对动态性能敏感的场合,电压外环的带宽也值得同时拉高。
4.3 代价函数里权重因子的影响
如果只控制电流,代价函数里不需要权重因子,g就是两个电流差的平方和,没有参数可调,这是FCS-MPC最吸引人的地方。但很多实际应用里还希望控制直流母线电压,就会把电压误差写进代价函数:
g = (i_α_ref - i_α_pred)² + (i_β_ref - i_β_pred)² + λ_v * (Vdc_ref - Vdc_pred)²
这时λ_v需要手工调。这个参数没有任何通解公式,基本靠仿真试。λ_v太大的话,系统优先压电压误差,电流波形会变差甚至震荡;λ_v太小,电压误差权重上不来,母线稳压效果差。
我的经验是从0开始逐步增大,每次看三个量:电流THD、母线电压稳态误差、负载突变时的电压跌落深度。找到一个三者的平衡点。比如在一组参数下,λ_v=0.01时电压纹波有点大,λ_v=0.1时电流THD从3%涨到7%,最后取0.05。这个方法很土但是有效。如果你希望完全不去调权重,就老老实实保留外环电压PI,内环只做电流MPC,省心很多。
5. 调试过程中真正让我头疼的四个问题
5.1 采样时间不统一导致预测失败
这是最容易犯的第一坑。Simulink中MATLAB Function的采样时间、Unit Delay的采样时间、Universal Bridge的Gate输入采样时间,三者必须严格一致。我之前有一次把MATLAB Function设置成继承采样时间,Unit Delay设置成离散50μs,结果整个控制链路里各自为政,预测公式里用的Ts和模块实际执行周期不一致,电流波形出来像神经信号一样乱跳,还不好排查。
排查办法:在Simulink的Sample Time Display功能里,把所有模块的采样时间标出来,肉眼找颜色不一致的地方。MATLAB Function建议固定设置为离散采样时间50μs,Unit Delay也设置为50μs,Gate信号也要和它一致。这样逻辑才在同一个节拍上。
5.2 一拍延迟补偿:不是可选,是必选
前面提到我在MPC输出后加了一个Unit Delay。为什么要这样?因为真实数字控制器在接收到电流采样值后,要完成遍历寻优、代价计算、输出门信号,这个过程至少要花掉将近一个控制周期。也就是说,这一拍算出来的最优状态,其实是应该给下一拍用的,不是这一拍立刻就能用上。如果不加延迟补偿,仿真里MPC输出立刻作用于下一瞬间,你会在仿真里看到比实机好得多的结果,这不真实,尤其当你后面要移植到DSP时,性能会突然变差,让人摸不着头脑。
正确做法有两步。第一步,在MPC输出后加Unit Delay,模拟一拍延迟。第二步,需要修改预测算法来补偿这个延迟,做法是在当前时刻k先用上一拍选中的开关状态(或者说需要多一个输入:上一拍的开关状态)去预测i(k+1),然后用i(k+1)作为起始点,再对8种状态预测i(k+2),代价函数比较的是i(k+2)和参考电流。这样当前拍算出的最优状态,下一拍正好用上,理论上把一拍延迟抵消了。如果不做第二步只看第一步,动态响应会变得很差。实际模型里很多人偷懒,只加Unit Delay不补偿,也是错的。
给一个简化的延迟补偿代码片段思路:
% 已知上一次输出的开关状态 sa_p, sb_p, sc_p % 第一步:用上一拍的电压矢量预测 k+1 电流 [i_alpha_k1, i_beta_k1] = predict_current(ia, ib, ea, eb, vdc, sa_p, sb_p, sc_p, Ts, L, R); % 第二步:在 k+1 基础上遍历8个状态,预测 k+2 电流 % 用 k+1 电流作为当前值,对8种状态算代价,选择最优输出这样改完,虽然多算了一次预测,但换来的是仿真行为和实机更接近。我用这个版本跑出来的结果,和后面在快速控制原型上实测的波形趋势是一致的。
5.3 MATLAB Function运行慢和代数环问题
FCS-MPC的MATLAB Function本身计算量不大,但要小心代数环。没有延迟时,MPC输出直接连回Universal Bridge,而Universal Bridge工作在主电路电气回路里,如果再加个什么反馈直接引到输入,很容易形成比较隐蔽的代数环。Simulink求解代数环会迭代,仿真慢得离谱。
解决办法:所有从主电路反馈到控制算法的信号,过一遍采样保持器或者Unit Delay,切断代数环。我在电流测量和电压测量后面各加了一个Zero-Order Hold,采样时间Ts=50μs,这样控制信号全部由离散采样值驱动。加了之后仿真速度提升了不止一倍,而且波形更干净。
5.4 电感参数不匹配时模型还扛不扛得住
FCS-MPC是模型依赖控制,预测公式里用了电感L和电阻R。如果仿真模型里的电感是5mH,而算法里写的电感也是5mH,性能自然好。事实是实机参数会因为温度、磁饱和而漂移,电感可能从5mH变成4.2mH,电阻也会变。仿真阶段就要做参数鲁棒性验证。
我的做法是设计一组扫描:算法内部保持L=5mH不变,把主电路的电感参数在4mH、5mH、6mH之间切换,看电流THD和稳态误差怎么变化。实测下来,电感误差在±20%以内,系统仍然稳定,只是THD会有1~2个百分点的变化;如果误差超过30%,电流容易在过零附近振荡,因为预测模型和实际对象偏差太大,控制器会在相邻的几个开关状态间反复切换。这个结论对后续硬件选型和参数辨识都有指导意义,建议所有做FCS-MPC的仿真模型都顺手扫一遍这个参数灵敏度。
6. 一组可直接复现的参数表,以及往硬件走之前的几个提醒
6.1 完整参数速查
为了方便你复现整个模型,我把上面全部参数汇总在一张表里:
| 项目 | 参数 | 值 |
|---|---|---|
| 电网线电压有效值 | U_ll | 380V / 50Hz |
| 滤波电感 | L | 5mH |
| 电感等效电阻 | R | 0.1Ω |
| 直流母线电容 | C | 2200μF |
| 直流母线电压给定 | Vdc_ref | 650V |
| 额定功率 | P | 10kW |
| 负载电阻 | R_load | 20Ω(额定);10Ω(过载) |
| 控制周期 | Ts | 50μs |
| 固定仿真步长 | T_sim | 2μs |
| 外环电压PI | Kp / Ki | 1.2 / 60 |
| 门信号 | Ga,Gb,Gc | 单脉冲上管,下管互补 |
这套参数在多数中功率模型里都能稳定跑起来,如果你改功率等级,按标幺化思想缩放就行:电感感抗一般取系统额定阻抗的5%~8%,电容支撑时间取1~2ms。
6.2 从Simulink到快速控制原型和DSP的几点建议
如果后面打算做硬件在环或者直接移植到DSP,有几件事最好在仿真阶段就养成习惯。第一,MATLAB Function采用C语言兼容的子集,避免persistent变量在代码生成时出现意外,尽量显式传入状态量。第二,代价函数尽量用整数或定点数表达参数,DSP上浮点计算不是不行,而是做并行多步预测时开销大,定点和查表能省不少周期。第三,PLL不要省略,不要因为仿真中三相电源角度可以精确知道就偷懒。并网场景下电网有谐波、频率偏移,不锁相直接控制,功率因数和动态都会打折扣。
还有一个容易被忽略的点:仿真里Universal Bridge和实际IGBT驱动板的延迟不同,硬件驱动有死区时间,而且死区会影响电流过零点附近的质量。仿真如果完全不建模死区,会导致预测值比实际电流响应更快,实机移植后面板要重新调。我建议在仿真中给门信号加一个死区模块,虽然MPC实时计算复杂一点,但结果更可信。
6.3 还能往哪个方向改进
FCS-MPC做完一版能跑,后续有两条路值得走。一条是多步预测,就是从预测一步扩展到两步三步,代价函数需要展开的候选状态从8个变成64个甚至更多,动态性能和控制性能都有增益,但计算量爆炸式增长,适合配合代码生成和并行计算用。另一条是无权重因子方法,如果一定要把直流电压、开关频率、共模电压等目标都塞进代价函数,与其盲目调λ,不如用枚举排序或者模糊逻辑自动分配权重,这几年论文里很多,实测也确实能减少调参工作量。
还有一个更工程化的方向是模型参数在线辨识。既然FCS-MPC依赖L和R,那就做在线最小二乘或者卡尔曼滤波估计,实时修正预测模型里的参数,电感漂移的问题就能从根源上缓解。这些方向在Simulink里都能继续扩展,组件和信号链路不用重搭。
我个人的体会是,FCS-MPC不是一个高不可攀的算法,它的上限更多取决于你对被控对象离散模型的理解深度,而不是算法本身有多玄。仿真阶段把每一步数学基础打扎实,后面的硬件实验会顺很多。先跑通这一版,再在它的基础上做改进,是比较务实的路线。