
前阵子一直在啃一篇基于有限集模型预测控制的MMC整流器方向论文原论文发表在IEEE的电力电子类期刊上。这类工作在学术界讨论得很热但真正落到Simulink里能跑出一套稳定波形中间隔着的坑远比表面上多。这篇博文就围绕我复现过程中整理的模型思路来写控制对象是模块化多电平换流器MMC应用场景是三相整流电路控制算法采用混合结构核心可复现模块全部在MATLAB/Simulink中完成。如果你正在做MMC相关研究或者想把手里的SCI复现需求从“看懂公式”推进到“模型能出图”这篇文章应该能帮你省掉不少时间。我做这个方向已经有好几年了从最早的一堆手写S函数到后来慢慢形成一套比较成熟的建模习惯。复现论文和看论文完全不是一回事论文里一页纸的控制框图真正搭起来涉及子模块封装、离散预测模型、枚举逻辑、均压策略和仿真参数整定任何一个环节出问题波形都很难看。这篇文章会把整个模型拆开逐个环节说明为什么要这样搭以及哪些地方容易踩坑。1. 复现之前先看清系统到底在控什么1.1 从标题里拆出来的技术栈标题信息量很大但核心其实可以拆成三层。第一层是主电路对象MMC模块化多电平换流器这个不用多说现在高压直流输电、中压电机驱动、电能质量治理里都很常见。第二层是控制算法FCS-MPC有限集模型预测控制它的特点是控制器的输出不是连续占空比而是直接给出一组离散开关状态因此非常适合MMC这种本来就只能输出有限等级电压的拓扑。第三层是系统工况整流电路也就是能量从交流侧流向直流侧直流侧接电阻负载或电池负载系统主要控制目标是直流电压稳定、交流电流正弦、功率因数接近1。还有半句话容易被忽略就是“混合”两个字。IEEE论文里“hybrid FCS-MPC”的含义并不统一不同组可能有不同定义。我这次复现采用的是一种工程上最常出现的混合框架上层用PI控制直流电压中层用FCS-MPC的代价函数枚举桥臂需要投入的电平组合底层再通过电容电压排序算法决定具体是哪几个子模块投入。这个架构把“状态空间枚举的有限集”和“排序均压的连续切换决策”混在一起所以叫混合。如果你在别的论文里看到混合指的是MPC和载波调制混合、双矢量MPC或者带虚拟矢量的方案控制细节会有些不同但模型整体搭建思路大同小异我这篇文章里的Simulink结构仍然可以参考。1.2 为什么这个系统要用FCS-MPC先把传统线性控制的思路摆出来。MMC整流器想用经典电压电流双闭环一般需要根据调制环节输出连续调制波再配合载波移相或最近电平逼近去生成门极信号。内环可能还需要加环流抑制器子模块均压往往是单独一个排序算法。控制链路很长PI参数加起来十几个调试并不轻松。FCS-MPC的吸引力在于用一个统一的滚动优化模块去替代多环路结构。它基于系统离散预测模型枚举所有可用的开关状态预测每个状态作用下下一拍的系统变量然后计算代价函数选择代价最小的状态在下一拍输出。它天然能处理多目标电流跟踪、环流抑制、电容电压偏差、开关频率限制都可以直接塞进同一个代价函数里权重项调起来比PI参数直观一些。更重要的是MMC每相桥臂虽然有多个子模块级联但从桥臂端口看能够输出的电平等级也是有限的。这和FCS-MPC的“有限控制集”设定完全对味。整流工况下控制器关心的核心变量有三组交流侧电流、桥臂环流、子模块电容电压。直流母线电压由电容自然形成但需要外环给定电流指令来维持功率平衡。这些变量都耦合在同一个MMC拓扑中预测模型建模时不能只记一个方程后面我会把核心公式逐个列出来。2. 数学模型预测控制器的地基不能糊弄2.1 半桥子模块和桥臂电压表达复现模型时我选择了半桥子模块结构这是MMC最基础也最常用的单元。每个子模块由一个电容和两个IGBT反并联二极管组成等效来看就是一个单刀双掷开关IGBT导通状态决定电容是投入桥臂还是旁路。定义第i个子模块的开关函数 s_i ∈ {0, 1}1表示投入0表示旁路则该子模块端口电压为 s_i * v_c子模块从桥臂电流中吸收或者释放的电流为 s_i * i_arm。每一相有两个桥臂上桥臂、下桥臂分别由N个子模块串联再各串一个桥臂电感。假设某一相上桥臂的子模块端口电压总和为 v_p下桥臂电压总和为 v_n那么这一相能够向交流侧呈现的端口特性可以简化为上下桥臂分压后的中间抽头关系。交流等效方程写出来是v_ac (v_n - v_p) / 2 - (L_arm / 2) * di_ac/dt - (R_arm / 2) * i_ac式子里的v_ac表示MMC交流侧端口电压i_ac是流入交流线路的电流。从这个方程可以看到想让交流电流按指令变化核心是控制 v_n - v_p 的差值也就是上下桥臂投入子模块数量形成的电压差。反过来看上下桥臂电压之和 v_p v_n则直接影响直流侧和桥臂环流这个和值又被单独拎出来做环流抑制。所以上下桥臂的投入子模块数不是一个自由量它同时决定了交流输出电压和内部控制电压这正是MMC控制器设计时最需要理解的地方。我在实际复现时每相桥臂的子模块数取了 N 4。这个数字不大但足够验证FCS-MPC的控制逻辑。如果直接取几十个乃至上百个电平的换流器枚举搜索空间会迅速爆炸在普通PC上根本跑不动实时Simulink仿真。用N4做原理性复现并没有失去控制方法的一般性因为算法逻辑不依赖于具体电平数后面需要放大多电平数量时把枚举表维度换成实际拓扑参数即可。2.2 环流动态和电容电压动态MMC有别于普通两电平变换器的关键问题之一就是桥臂环流。环流定义为同一相上下桥臂电流的平均值i_cir (i_p i_n) / 2环流中主要含直流分量和二倍频负序分量。直流分量事实上会传递自动率二倍频分量则是导致桥臂电流畸变、损耗增大的主要来源。在整流工况下我们希望把二倍频环流抑制到接近0。从直流回路的电压方程来看环流动态满足2 * L_arm * di_cir/dt 2 * R_arm * i_cir Vdc - (v_p v_n)这个方程说明控制 v_p v_n 就可以调整环流。而在经典MMC控制里调制时往往要求 v_p v_n 保持恒定接近Vdc这样环流就没有额外驱动源。但FCS-MPC可以更灵活直接把预测环流放进代价函数枚举时优选出 v_p v_n 合适的那组状态相当于把环流抑制融入滚动优化不需要额外单独调PR控制器的谐振频率。电容电压动态也非常关键直接影响均压项设计。子模块电容的微分方程如下C * dv_c/dt s_i * i_arm这是一个异常直观的方程只有当子模块投入桥臂时电容电压才会被桥臂电流充电或放电子模块被旁路时电容电压保持不变。但它也暗示了均压控制的本质如果一个子模块电容电压偏高系统应当在合适时机让它多放电如果某子模块电压偏低就应当让它多充电。投入哪个子模块、投入多久在底层往往用排序算法决定这也是我前面所说“混合执行架构”的底层环节。2.3 从连续方程到离散预测模型FCS-MPC需要的是离散预测式。我采用前向欧拉法进行离散化控制周期设为Ts。以三相交流电流为例如果不考虑三相之间的交叉耦合可以先把模型写到dq旋转坐标系里。整流器交流侧方程为L_s * di_d/dt e_d - v_d - R_s * i_d omega * L_s * i_q L_s * di_q/dt e_q - v_q - R_s * i_q - omega * L_s * i_d这里的 e_d、e_q 是网侧电压在dq坐标系的分量v_d、v_q是MMC交流端口的基波电压分量。把前向欧拉代入后得到i_d(k1) i_d(k) Ts/L_s * [e_d(k) - v_d(k) - R_s * i_d(k) omega * L_s * i_q(k)]同理可以得到 i_q(k1)。对环流也可以类似离散i_cir(k1) i_cir(k) Ts/(2L_arm) * [Vdc(k) - v_p(k) - v_n(k) - 2R_arm * i_cir(k)]每一个候选开关状态都会产生一组对应的 v_p、v_n也就对应一组预测电流和预测环流。控制器把它们分别和参考值比较折算成代价之后选出最优解。2.4 代价函数设计与权重整定经验代价函数是整个FCS-MPC的心脏。我在模型里使用了如下形式的目标函数g ( (id_ref - id_pred) / Ib )^2( (iq_ref - iq_pred) / Ib )^2lambda_cir * ( (0 - i_cir_pred) / Ib )^2lambda_bal * ( (v_c_max - v_c_min) / Vb )^2lambda_sw * n_switch_change第一项和第二项保证交流电流跟踪指令第三项抑制环流第四项是子模块电容电压的离散度约束第五项可以附加开关次数约束降低开关频率。每一项都做了标幺化处理否则把电流和电压直接平方相加量纲和数量级完全对不上权重系数会调到怀疑人生。权重系数整定的通用策略是分步来。先把 lambda_cir、lambda_bal、lambda_sw全部置0只保留电流跟踪项确认系统能稳定输出正弦电流、直流电压能建立起来。之后逐步增大 lambda_cir观察桥臂电流中二次谐波分量是否下降一般取值在0.05到0.5之间就能看到明显效果。再增大lambda_bal代价最小化会促使控制器选择让电容电压更均匀的状态但代价项太大会影响电流波形不能盲目往大了加。开关次数约束项在离线仿真里我通常先不加因为MMC排序策略本身会带来一定的自然换流如果开关频率过高可以最后用这项目限制。3. Simulink逐模块搭建从拓扑到代码能跑通3.1 主电路模型搭建我不建议一上来就摆几十个IGBT刚复现MMC时最容易犯的错是想在Simulink里把每一个IGBT都建模出来看起来非常接近实际工程但仿真速度会让人崩溃。对于FCS-MPC算法验证我建议第一版主电路采用“受控电压源受控电流源”构成的等效半桥子模块。具体做法是每个半桥子模块封装成两个端口。输入信号是当前拍的门极开关状态 s 和桥臂电流 i_arm内部通过一个受控电压源向桥臂串联路径输出 s * v_c 的电压。同时从桥臂电流取回来用一个受控电流源给电容并联支路注入 s * i_arm 的电流从而实现电容的动态充放电。这样的等效模型在算法层面和实际开关模型完全等价但省去了大量IGBT和二极管的非线性器件求解仿真速度能快出一个数量级以上。我比较推荐先搭“三相交流源 网侧电感 MMC本体 直流负载”的结构。三相交流源用理想电压源线电压有效值取380V50Hz。网侧电感取3mH它起到滤波和能量交换的作用也和整流器输入阻抗有关。MMC每一相配四个半桥子模块桥臂电感取8mH桥臂电阻设0.05Ω。直流侧用50Ω电阻作为负载。单个子模块电容取8mF这在仿真参数里能够保证直流电压跌落幅度满足要求。搭建MMC桥臂时建议把“半桥子模块”封装好然后在桥臂内部用Simulink的For Iterator或者直接四次复制生成四串子模块。使用封装的目的是后续想做高电平数复现时只需要在封装参数里改一下重复次数不用重画一遍拓扑。3.2 外环PI和坐标变换FCS-MPC并不能自己给出交流电流参考值大小。因为整流器最终目标是把交流功率馈到直流侧维持直流电压恒定因此必须有直流电压外环产生d轴电流参考。我在模型里设置直流电压参考Vdc_ref 700V将实际直流电压采样后和参考值做差送入一个带输出限幅和积分抗饱和的PI控制器。PI输出作为 d 轴电流参考值 id_ref。这里有个细节整流器采用电网电压矢量定向q轴参考电流通常直接给0让系统运行在单位功率因数状态。具体的实现是采集三相电网电压和三相交流电流经过Clarke变换得到静止两相坐标系分量再经过Park变换得到dq分量。变换角度来自三相锁相环。我使用的是Simulink自带的PLL如果做纯理想工况直接用固定的50Hz正弦角度也能跑但加上PLL之后模型更接近论文的通用场景。实际仿真时需要注意d轴电流参考的极性要正确。整流工况下能量从交流流向直流电流参考方向和坐标变换定义有关如果参考方向写反直流电压会往下掉而不是建立起来。遇到电压往下掉的情况先检查PLL输出角度和变换矩阵是否匹配再检查PI输出限幅方向我在复现时第一版就踩了这个小坑。3.3 FCS-MPC控制器核心代码逻辑控制器我采用MATLAB Function来实现。这个模块的输入包括三相交流电流、dq变换角度、网侧电压、上下桥臂各子模块电容电压、直流电压、外环过来的电流参考指令。输出为上下桥臂各自需要投入的子模块数量以及最底层具体投哪些子模块的布尔向量。先做枚举层预测。N4时每个桥臂可投入的子模块数有0到4共5种选择上下桥臂组合起来是25种候选状态。对每一相独立枚举计算候选状态下的上下桥臂端口电压预测值再通过离散预测方程得到电流预测值和环流预测值。这样三相总计算量是3×25次预测评估Simulink中如果打开代码加速普通MATLAB环境下也能在几十微秒量级跑完。选择一个在多个IEEE论文里常见的近似枚举时先假定当前周期内所有子模块的电容电压都等于该桥臂电容电压平均值这样由投入个数 n_p 和 n_n 计算出来的桥臂电压就是 n_p * vc_p_avg 和 n_n * vc_n_avg。预测完成后拿到最优的 n_p 和 n_n再去做子模块层面的排序选择。这种分层处理大幅度减小状态搜索空间因为如果直接枚举每个子模块投切状态N4时每相上臂就有16种状态上下臂组合变成256种N再大一点就不可能实时计算了。底层排序逻辑也是我在MATLAB Function中一并实现的。对某一个桥臂来说当桥臂电流方向为正时电容处于充电趋势为了抬高低电压子模块就优先投入电压最低的几个子模块当桥臂电流方向为负时电容处于放电趋势为了压低高电压子模块就优先投入电压最高的几个子模块。注意初始条件设置时我把每个子模块电容电压初值都设到额定值附近也就是175V左右可以避免启动瞬间排序逻辑出现极端投切。伪代码如下for np 0:N for nn 0:N vp_pred np * vc_p_avg; vn_pred nn * vc_n_avg; v_ac_candidate (vn_pred - vp_pred) / 2; id_pred id Ts/Ls * (ed - v_d_candidate - Rs*id w*Ls*iq); iq_pred iq Ts/Ls * (eq - v_q_candidate - Rs*iq - w*Ls*id); i_cir_pred icir Ts/(2*Larm) * (Vdc - vp_pred - vn_pred - 2*Rarm*icir); g calc_cost(id_ref, iq_ref, id_pred, iq_pred, i_cir_pred, ...); if g g_best g_best g; np_best np; nn_best nn; end end end成本计算时注意dq坐标系下的参考值和预测值要处在同一个时刻。由于控制器输出一拍延时的影响比较严谨的做法是用参考值在k1时刻的值和预测值在k1时刻的值比较。做复现时如果嫌参考值预测麻烦也可以直接在当前时刻比较代价函数不大也不会导致系统不稳定。但如果你要把仿真结果写进论文和原文章对比波形建议处理一拍延时补偿逻辑更严谨波形毛刺也更少。3.4 仿真环境配置和步长选择Simulink中电力电子仿真建议使用Powergui模块并设置为离散仿真模式。我的Powergui步长设为1微秒用于捕捉电容电压的快速动态。控制算法执行周期单独用Rate Transition模块控制通常设为100微秒即10kHz控制频率。这两个时间基准不同一定要用Rate Transition把不同速率的信号分隔开否则Simulink很容易产生代数环仿真起来报错一堆。仿真时长我建议先跑0秒到2秒。启动过程观察直流电压从初始值爬升到700V的动态过程然后再看稳态波形。采样数据要保存到工作区便于后面做FFT分析和电流THD计算。我整理了一套比较常用的主电路参数见下表参数数值说明交流线电压有效值380 V50 Hz三相理想电源直流电压参考值700 V外环PI给定每桥臂子模块数 N4五个电平等级子模块电容8 mF电压波动控制在合理范围桥臂电感8 mH限制环流和故障电流桥臂电阻0.05 Ω等效损耗网侧电感3 mH交流滤波直流负载50 Ω额定功率约9.8kW控制频率10 kHzFCS-MPC执行周期电力电子仿真步长1 μsPowergui离散步长这套参数做出来直流电压稳定后电容电压平均值大约是175V正常波动范围应该在正负8%以内最终额定功率下直流侧电压纹波大概在几伏量级。4. 我踩过的坑和排查实录4.1 启动阶段电容电压直接飞掉第一版模型跑起来后电容电压不是从175V附近缓慢建立而是直接发散去到几百上千伏波形很快变乱。排查下来发现是启动瞬间交流侧对电容充电能量过大而控制器还没有建立起有效的均压能力。排序逻辑里充电和放电方向判断没有问题真正问题在于启动时电流参考值给得太大导致电容快速过充。解决办法有两个一个比较省事把所有子模块电容电压初始值直接设成175V让模型从预充电平衡状态开始跑。这样省去了写预充电电路的麻烦适合验证控制算法本身。另一个更贴近真实工程给外环PI输出的电流参考加一个斜坡限幅或者给直流电压参考值设一个从0到700V的斜坡让调制过程自然完成预充电。SCIE论文复现阶段我自己对算法的关注度大于启动特性所以更多使用初始值法但论文图表中如果说明了模型从空载启动推荐用斜坡给定法更可信。4.2 模型仿真慢到像放PPT刚把完整的四子模块开关等效模型搭完跑2秒仿真需要几个小时。当时第一反应是控制算法复杂度太高后来发现问题出在主电路模型。每次执行都要反复调用MATLAB Function内的大循环而MATLAB Function在普通解释模式下每次迭代都有额外开销。优化分成三步第一步把主电路改为前面提到的受控源等效模型仿真步长不变计算量骤降。第二步在MATLAB Function内部把候选状态枚举写成局部循环不调用外部脚本尽量避免使用eval这类低效函数。第三步在仿真参数设置中打开“代码生成”或把MATLAB Function指定为支持C代码生成让Simulink把函数编译成可执行代码后再跑。实测三步做完以后加速效果至少是5倍以上2秒工况能在半小时内跑完后续长时间波形分析才可行。有一点值得强调FCS-MPC计算时间和枚举数量直接相关。如果扩展成每臂N11以上建议不要在MATLAB Function里双层枚举所有上下桥臂组合。可以先用一个简化规则初选出若干个较优的候选子集只在子集内部做代价函数比较这是很多大电平MMC模型预测控制落地时的常见降维思路。4.3 稳态交流电流毛刺大、波形发糊有一段时间波形虽然稳定但交流电流正弦度很差谐波毛刺明显。检查后发现代价函数里的电流项和均压项出现冲突。底层排序策略在某个控制周期内频繁切换子模块导致桥臂端口电压有瞬间尖峰反映到交流电流上就是毛刺。我把排序切换策略做了个限制控制周期内如果某个子模块刚被投入下一拍不因为两个电容电压轻微不平衡就把它切出。判断阈值设在额定电容电压的1%以内。直觉上这会让均压效果变差一点但实际对电容电压波动影响很小反而电流THD显著改善。这个限制在很多论文中也叫开关状态冻结属于降低开关频率的实用技巧。另外一个造成电流毛刺的原因是PLL和Park变换角度存在波动。整流工况下电网电压谐波并不大但如果PLL参数带宽设置过窄角度抖动会加剧dq轴电流参考扰动。调试时可以用虚拟的固定频率角度对比一下波形如果固定角度下波形明显更干净说明PLL参数有问题而不是控制算法问题。4.4 模型仿真的常见问题速查表现象可能原因排查方法直流电压建立不起来d轴电流参考方向反了检查坐标变换方向和PI输出极性电容电压发散子模块初始值与额定值偏差太大预充电或设置电容初值175V仿真速度极慢主电路开关器件模型太重换成受控源等效半桥模型电流毛刺大代价函数权重不匹配先只调电流项再逐步加其他项桥臂环流出现很大二倍频lambda_cir权重太小增大lambda_cir到0.1以上观察MATALB Function报代数环错误控制信号和测量信号交叉加Rate Transition或Memory模块隔开PLL锁定后dq轴分量依然振荡PLL带宽不合适调低PLL带宽或检查滤波子模块电压长时间不均衡排序阈值过小导致频繁切换增加电压平衡判断死区做复现的过程里最容易出现的心态问题是看到波形不对劲马上去调权重系数。实际上多数不稳定根源来自模型对象本身比如主电路参考方向、电容初值、采样同步问题。建议在动控制器之前先把MMC开环调制或者直接用最近电平逼近跑一个基线工况确认主电路模型本身没有问题。这一步很重要因为FCS-MPC控制器一旦接入它天然的强非线性会让问题变得很隐蔽很难判断是预测模型写错了还是权重调坏了。整流侧波形验收的时候除了看直流电压是否稳定在700V交流电流是否正弦外还要看电容电压排序是否像预期那样“动了”。我做过对比试验关掉排序逻辑所有子模块机械地按顺序循环投入电容电压会快速分开一部分越来越高一部分越来越低最后控制器发散。所以拿到模型后可以先测试一下人为把排序逻辑改成固定顺序观察均压失效的波形反向验证当前均压模块在正常工作时确实起了作用。这个习惯帮我发现过不少封装错误和变量传递错位问题。整体复现下来的体会是SCI论文里那一行行漂亮的波形图背后并不是什么神秘算法而是建模细节、离散化精度和调试经验共同堆出来的。MMC整流器本身拓扑不算复杂真正复杂的是多目标在有限控制集下的取舍。把直流电压外环、电流内环、环流抑制和子模块均压分层理顺再将每个层次落到Simulink对应的模块上模型就不容易乱。最后再分享一个小技巧写FCS-MPC控制器的时候不要一开始追求把所有性能指标全部塞进代价函数先把电流跟踪跑通再逐步加项否则任何一环出问题你都找不到突破点。