最近刚好在复现一篇SCI二区IEEE上关于模块化多电平换流器MMC整流电路的FCS-MPC控制方案用的是Simulink仿真。整个流程从看论文、搭模型、写控制算法到调试、排坑前前后后折腾了不少时间。这篇博文就围绕这个项目把从零到能跑通MMC整流FCS-MPC仿真的完整思路、核心公式、建模细节和踩过的坑都梳理出来给准备复现同类方向的同学一个可以直接参考的路线。简单说清楚这是什么东西MMC是模块化多电平换流器现在高压直流输电和电力电子变压器里用得非常多拓扑上就是每相上下两个桥臂每个桥臂一串子模块通过子模块电容的投切叠加出多电平波形。FCS-MPC是有限控制集模型预测控制算法直接枚举每个桥臂可能的投入组合用一个代价函数选最优不需要传统的SPWM调制器也不用一堆PI调参。这个组合在论文里很常见因为FCS-MPC的多目标约束能力非常适合MMC这种控制目标多交流电流、环流、电容电压均衡的场合。适合谁看准备复现MMC类IEEE论文、做硕士/博士课题、或者正在用Simulink搭电力电子控制的工程师这篇对你会有实际帮助。1. 先把方案吃透FCS-MPC与MMC之间的“为什么”1.1 MMC整流器要做的其实是三件事很多同学以前做过单相桥式全控整流或者三相桥式全控整流第一次碰MMC会不太适应。传统全控整流是交流侧电感换相、晶闸管自然导通控制点相对少而MMC本质是一种电压源型换流器每一相上桥臂和下桥臂串联多个子模块每个子模块相当于一个带旁路能力的电容源。整流工况下交流侧三相电压源通过桥臂的开关动作给直流侧提供稳定的直流电压和功率。所以MMC整流器表面上只说了“整流”两个字实际控制目标拆开是三件事第一交流侧电流波形可控比如单位功率因数或者指定功率因数第二直流侧电压稳定负载变化时不能大幅波动第三桥臂环流要压下去。环流这个东西是MMC特有的三相桥臂之间会天然流通一个二倍频负序环流分量如果不管它桥臂电流峰值明显变大、损耗上升、电容电压波动也更严重。这篇论文的关键点就是用FCS-MPC一个控制器同时协调这三个目标比传统“PI双闭环载波移相环流抑制器”的结构更紧凑。1.2 FCS-MPC凭什么能直接用于MMCFCS-MPC的核心逻辑很直白拿到当前时刻的测量量基于离散状态方程预测下一拍在不同开关组合下的系统状态然后把每个组合代入代价函数打分分最低的那组就是下一拍采用的开关状态。整个过程不需要调制器这一步也不需要像SPWM那样先把参考波和载波比较。用在MMC上的优势尤其明显。因为MMC一个桥臂可能有一二十个子模块如果完全用调制器还需要额外设计子模块电容电压排序均压策略而MPC的思路是把“到底投入哪几个子模块”当成候选动作本身天然可以叠加电容电压均衡目标。多目标是MPC的老本行交流电流误差、环流误差、开关动作次数全都可以加权写进去不用像PI那样一个环一个环地解耦设计。当然缺点也摆在这计算量按组合数翻采样频率要高代价函数权重系数需要调。科幻一点的想象是“控制器一边枚举几千种开关状态一边还要求仿真跑得快”所以复现时往往在小规模MMC上先验证算法再考虑换步长和大规模。1.3 复现前必须确认的参数与假设论文复现最怕的不是数学难而是参数表不完整。拿到一篇SCI论文里的MMC整流仿真第一件事是找两个东西一个是主电路参数比如交流侧电压幅值/频率、桥臂电感、子模块电容、子模块数量N、直流电压参考值、负载类型另一个是控制参数比如采样周期Ts、权重系数、预测步数。很多论文会把主要参数列成一张Parameter Table但偶尔也会漏掉一两个关键值。我在复现时一般按这个顺序处理先把能确认的填进去确定不了的先给一个合理的典型值。比如子模块电容电压基准值通常直流侧电压除以N就是单个电容电压稳态值桥臂电感一般取0.1pu到0.15pu量级太小环流大太大动态响应慢。遇到真不确定的参数优先看论文的波形幅值去反推比如环流波形纹波大小能帮你判断桥臂电感估算得对不对。还有一点是模型的理想化假设论文里一般都会写“忽略死区开关器件理想电源阻抗忽略”之类仿真也要按这个假设搭否则你复现出来的波形跟论文对不上会怀疑自己是不是改错了。2. 数学模型与控制公式推导2.1 桥臂动态与交流侧方程MMC每相有两个桥臂定义上桥臂电流为i_uj下桥臂电流为i_lj交流输出节点在上下桥臂之间。交流侧电流i_sj是流到交流电网方向的电流它和桥臂电流满足i_sj i_uj - i_lj。令环流为i_cj (i_uj i_lj) / 2这是桥臂内部流动的共模电流分量它不直接参与交流侧能量交换却会把损耗和波动带起来。从电路关系看上下两个桥臂共同分压设输出点对直流中性点的电压为v_jo上桥臂电压为u_uj下桥臂电压为u_lj桥臂电感为L那么L * d(i_uj)/dt Udc/2 - u_uj - v_jo L * d(i_lj)/dt Udc/2 - u_lj v_jo两个式子相加除以2得到环流动态方程L * d(i_cj)/dt Udc/2 - (u_uj u_lj) / 2两个式子相减除以2再乘上2的换算得到交流侧电流动态方程(L/2) * d(i_sj)/dt (u_lj - u_uj) / 2 - v_jo这里关键理解在于u_uj和u_lj的差模分量(u_lj-u_uj)/2决定了交流端口电压是交流电流控制的手段u_uj和u_lj的共模分量(u_uju_lj)/2决定了环流控制的手段。这两条路在数学上解耦得很干净FCS-MPC正好可以统一在一个框架里同时优化。2.2 环流方程与二倍频来源环流为什么存在把时间平均角度看i_cj并不为零它包含一个直流分量Idc/3因为三相总共传送直流功率每一相桥臂需要流过三分之一的直流电流。但如果只考虑直流分量问题就简单了。实际工况下桥臂瞬时功率在波电容电压有波动这个波动会通过桥臂相互作用激励出二倍频负序环流i_2fj。波形上看三相的二倍频环流彼此相差120度合成后不流入直流侧也不流入交流侧纯粹在三个桥臂之间“打转”白白增加损耗。环流抑制的本质就是让环流的参考值变成Idc/3也就是说控制器要主动把二倍频分量压到接近零。传统做法是加PR调节器或者谐振控制器专门在二倍频处补偿而FCS-MPC的方案更直接把环流预测值跟参考值之间的误差写进代价函数选出的开关组合天然会把环流压住。需要注意的是如果仿真模型中测量的是上下桥臂电流之和的一半那参考值必须用Idc/3不能直接设成0否则会把直流分量也压掉直流侧功率传输就出问题。2.3 离散预测模型FCS-MPC需要的是离散化的预测模型。最常用前向欧拉法步长就是控制周期Ts把上面两个微分方程直接变成递推式。交流电流预测i_sj(k1) i_sj(k) (Ts / (L/2 L_s)) * [e_sj(k) - R_eq * i_sj(k) - v_jo(k)]其中e_sj是交流电网相电压L_s是交流侧等效电感如果有R_eq是等效电阻v_jo(k)由当前候选开关组合对应的桥臂差模电压决定。更简洁地说v_jo(k) (u_lj(k) - u_uj(k)) / 2。环流预测i_cj(k1) i_cj(k) (Ts / L) * [Udc/2 - (u_uj(k) u_lj(k)) / 2]有了这两个递推式枚举候选开关组合时就能算出下一拍的交流电流和环流。离散化时要注意一个隐藏前提Ts要远小于系统最小的电磁时间常数否则前向欧拉精度撑不住。一般工程上选5e-5秒到1e-4秒之间具体看桥臂电感和电容参数。电容电压动态通常比电流慢但MPC如果想同时均衡电容电压也需要把电容电压递推式写进去vc_i(k1) vc_i(k) (Ts / C) * i_arm(k) * s_i(k)其中s_i是某个子模块的投入状态i_arm是该桥臂电流这个式子用于预测下一拍电容电压的走向。2.4 代价函数怎么设计代价函数是整个FCS-MPC的灵魂。一个典型结构是g lambda_ac * (i_s_alpha_error^2 i_s_beta_error^2) lambda_cir * (i_c_a_error^2 i_c_b_error^2) lambda_vc * (vc_max - vc_min)^2 lambda_sw * n_switch_actions交流电流误差可以用静止坐标系下的alpha/beta分量来算或者直接用三相误差平方和。环流误差是把三相环流参考设成Idc/3后算误差。电容电压均衡项一般用“本桥臂内子模块电容电压的最大最小差值”来惩罚差值越大分越高这样算法会倾向于选择能让电压更均匀的投入组合。开关动作惩罚项则是统计本次选择跟上一拍开关状态相比有几个管子发生了变化目标是为了降低平均开关频率。这里有一个非常关键的实操细节权重系数不能盲调。论文里一般不给全给也只是一组最终值。我的经验是先做误差归一化把交流电流误差除以电流基准值Ibase环流误差也除以Ibase电容电压差值除以电容电压额定值这样每一项误差都缩放到同一个量纲再调权重就有意义了。初始设置可以lambda_ac取1lambda_cir取0.5lambda_vc取0.1lambda_sw取很小比如0.01然后分别单独调看波形。3. Simulink建模实操从0到能跑3.1 顶层架构和各子系统划分Simulink建这种带MPC的系统最忌把所有东西拖到同一张图上。我搭的时候分四层最外层是仿真配置和工作区初始化第二层是主电路包括三相交流源、MMC主电路、直流负载第三层是测量和信号处理把桥臂电流、子模块电容电压、交流电压电流这些量采样出来整理成控制器需要的向量第四层是控制器核心是一个MATLAB Function把FCS-MPC算法写在里面输出的是每个子模块的触发脉冲。模块划分决定了后续调试的难度。我的习惯是主电路和控制器之间只通过Goto/From或者Bus传递信号不要在图上拉几十根线。这样后期替换控制器比如从MPC切回PI双闭环或者改子模块数量N时不需要重新理线。3.2 子模块和桥臂怎么搭子模块最常见的拓扑是半桥一个电容两个带反并联二极管的IGBT一个输出端口。在Simulink里可以用Simscape Electrical的IGBT/Diode模块搭或者用更简化的开关模型。第一次复现论文我强烈建议先用理想开关模型跑通算法别一上来就上Simscape精细模型因为后者每个开关都带热模型和数值阻尼仿真速度会慢到一个难以接受的程度而且调试时很难分清到底是控制算法问题还是开关模型数值问题。我搭桥臂时会封装一个“Arm”子系统里面是一串子模块数量N串联再串上一个桥臂电感L。电感旁边加一个小电阻数值取桥臂电感寄生电阻的量级作为数值阻尼否则纯电感状态方程容易算不下去。交流侧按论文要求接三相电压源或者经过小电感接电网。整流负载可以接一个纯电阻先验证稳态想更接近论文的“整流电路”场景然后接电阻加直流电容负载加一个动态阶跃负载来测控制器动态响应。直流侧电容要不要另加取决于MMC子模块电容本身能否维持直流电压刚度一般会加一个直流滤波电容。3.3 控制器用MATLAB Function还是模块化框图FCS-MPC里避不开枚举和排序用纯Simulink框图写会非常痛苦。我直接用了MATLAB Function把预测模型、候选组合枚举、代价函数计算全部写在函数内部。这样做有几个好处一是可以写for循环枚举所有候选组合代码结构和论文公式一一对应二是后续改权重、加约束只需要改几行三是如果后面要做代码生成再把这个函数提出来改C代码也方便。输入端上需要接采样时刻的交流三相电流、交流三相电压、直流电压Udc、三个桥臂的环流、子模块电容电压向量、参考值比如直流电压参考或者交流电流参考。注意这里有一个很常见的坑测量得到的连续信号进到MATLAB Function里以后因为函数是按采样周期触发的信号本身最好在外部用Zero-Order Hold锁存一拍避免Simulink在步进过程中反复调用函数导致信号时序混乱。函数内部不要直接写无穷循环或者用可变尺寸的全局变量Simulink的代码生成器对这种写法很不友好。输出端设计成两组一组是每个桥臂应该投入的子模块数量n_pulse0到N另一组是每个子模块具体的触发脉冲。第二组可以由排序均压模块来产生也可以直接在函数内部完成排序后输出完整脉冲向量。3.4 求解器与运行时间设置这是新手最容易翻车的地方。FCS-MPC是离散算法整个系统里控制器的采样Ts和控制周期必须严格跟随。我建议Simulink求解器直接用固定步长离散求解器比如discrete步长设成Ts的整数分之一。如果Ts是5e-5秒仿真步长可以设成5e-6或1e-5这样控制器每5到10步触发一次。别用可变步长否则控制器在Simulink内部被零阶保持的方式跟离散算法预期不一致容易出现“同一拍开关状态被重复计算”“波形毛刺乱跳”之类的问题。还要把仿真时长设置跟实际物理时间对齐。比如要看到2倍频环流的完整波形仿真时长至少得跑到0.2秒到0.4秒太短看不到稳态。如果你用精细开关模型大N0.4秒可能得跑十几分钟这就是为什么我强调第一步先用简化模型。3.5 参数工作区与初始化脚本搭模型前先把所有参数写进一个初始化脚本init_mmc.m不要在Simulink界面上到处改常量。我一般把主电路参数、控制参数、权重系数分成三个结构体比如mmc.N、mmc.C、mmc.L、ctrl.Ts、ctrl.lambda1之类。这样每次调参只需要改脚本不需要开模型。模型里所有参数都用变量名引用的方式比如电容值写mmc.C而非直接填数字。这个习惯还帮你避免另一个问题Simulink工作区里如果残留旧变量名字冲突了很难排查。脚本第一行加clear all最后一个section把运行需要的变量全部打印一遍下次打开模型直接跑一遍脚本就能保证环境干净。另外Subsystem里如果用了Bus信号建议在初始化脚本里定义Bus对象否则下次打开模型经常报“Bus type not defined”。4. FCS-MPC核心算法实现与调试细节4.1 控制集与枚举策略理论上MMC的开关组合数是(2N)的6次方量级子模块数一大根本算不完。所以实际论文里说的“有限控制集”并不会细致到枚举每一个IGBT而是枚举每个桥臂需要投入的子模块数量从0到N一共N1个离散值。三相六个桥臂总组合数就是(N1)的6次方。N等于2时是729个组合还能接受N等于5就是46656个组合每拍枚举就已经很吃力了。所以复现时有两个策略。一是小N验证先设N2或者N3把控制算法跑通看趋势正确后再换大N或者优化枚举二是分层枚举把循环拆成“先选交流差模电压再选环流共模电压”先在一组候选里找能让交流电流误差最小的再在这个基础上加环流代价搜索空间可以压到接近N1的3次方量级。很多论文在算法描述里不会写这么细你自己实现时要知道这个工程化处理。确定每个桥臂投入数量后还有一个“具体投入哪些子模块”的问题这里用排序均压把桥臂内所有子模块电压按大小排列如果本拍桥臂电流是充电方向通常以对电容充电为正就投入电压最低的那n个模块如果放电方向就投入电压最高的那n个模块。排序均压在MATLAB Function里实现很轻松sort函数一行搞定。4.2 权重系数调参经验调权重是FCS-MPC最玄学的环节但也是有套路可循的。先用归一化误差然后从单目标开始只保留交流电流项权重为1其他项全部设0看交流电流波形能不能跟踪参考。这时候环流和电容均衡不管波形能出来说明预测模型和控制集是对的。第二步加入环流项从0.1开始往上加加到环流二倍频分量明显降下去为止注意不要加太大否则交流电流波形会畸变。第三步加入电容电压均衡项这时会看到排序均压带来的效果波形更平滑。最后再加开关惩罚用一个很小的值比如0.01目的是限制不合理的频繁开关。实际调试时我习惯把波形送进Scope后分别观察交流电流THD、环流纹波、单个子模块电容电压波动这三张图。调一次权重系数跑一遍仿真记录趋势而不是一次性把所有项全加上。一个容易忽略的点是交流电流参考值的动态变化会显著影响权重感受测试时要加一次负载阶跃或者参考阶跃看看环流项和电容均衡项是否会把动态拉慢。4.3 两次采样延时补偿MPC的先天问题是一拍延时从采样到计算出开关状态再下发到主电路物理上已经过一个Ts了。如果不做补偿实际用的开关组合比理想情况晚了一拍会导致电流纹波变大、重载时跟踪误差明显。常见做法是两步预测补偿第一拍先用当前测量量预测k1时刻的状态然后枚举候选开关组合时从k2时刻的代价来评估实际执行的是第k1个Ts内算出的最优组合。实现上很简单就是一次循环里连续调两次预测函数。第一次预测用测量值第二次预测用第一次的预测值。这个细节论文里的公式表达可能很简略尤其是实验型论文里就一句“to compensate the computation delay”但复现时不加这一句你会发现自己仿真结果是能跑但就是跟论文波形的毛刺量级对不上。4.4 环流参考值的处理前面说了环流参考不能简单设0但Idc/3这个值怎么拿实操里Idc可以按功率平衡算Pdc Udc * Idc而交流侧输入功率约等于3/2 * E_mode * I_s。用Udc和I_s反推Idc。也可以直接从直流侧负载电流测量值除以3得到。更稳的做法是在控制环里加一个低通滤波后的前馈值因为负载突变时瞬时电流会波动直接用瞬时值除3会让环流控制目标抖。还有一种写法把环流误差里的直流分量先滤掉只抑制二倍频负序分量。实现方法是对i_cj做一次带阻滤波陷波在2f处或者坐标变换到2倍频负序旋转坐标系然后在那个坐标系里把误差控制到0。这个方法麻烦一点但受人喜欢的地方是它不需要精确的Idc/3在一些直流电流测量噪声大的仿真场景下反而更鲁棒。FCS-MPC加这个约束也不难多一个代价项而已。5. 常见问题排查与避坑实录5.1 仿真发散、数值爆炸最典型的症状是电流直接冲到几十倍额定值然后NaN。原因排查顺序先看求解器步长固定步长设得比Ts还大肯定爆再看桥臂电感是否有小电阻纯电感加开关器件在离散求解器里容易产生数值振铃再看直流侧负载是否瞬间短路整流启动时如果直流电容初始电压是0而控制器还没接管会有很大的冲击电流。解决方法是电容电压加初始值负载用电感或电阻缓冲启动时控制器参考值斜坡上升。复现论文时别一上来就全压阶跃启动先斜坡启动等稳态了再突加负载。5.2 输出波形有大量毛刺如果交流电流波形有高频毛刺像锯齿一样大概率是开关切换太频繁。FCS-MPC天然会在每个控制周期可能改变开关组合出现高频抖动尤其在代价函数里没有开关惩罚项时。解决办法加lambda_sw权重或者做“最小开关时间约束”禁止控制器在最近几拍内再次切换同一桥臂的模块。还有一种可能是仿真步长和控制周期不匹配零阶保持插值生成的开关波形带有数值毛刺检查一下Scope里应该看到的是阶梯波而不是密集抖动。5.3 环流抑制效果差二倍频很大环流纹波偏大先检查参考值。确认环流参考是Idc/3而不是0。再看环流权重是否给太低如果lambda_cir只有0.01甚至没加这个代价项那MPC根本不会主动去管环流。另外看预测模型里的共模电压项是否漏了如果只把差模电压写进去控制器对环流是“开环”的当然抑制不住。还有一种隐蔽问题是桥臂电感太小使得环流动态太快超出离散预测模型的有效带宽这种只能靠调大L或者减小Ts解决。5.4 Bus Selector找不到可选信号这个热词在搜索里我印象很深因为我自己也碰到过。Simulink里Bus Selector有时打开后下拉列表是空的根本找不到刚创建的总线信号。原因一般是总线的信号没有被编译器“认识”要么模型还没初始化要么总线信号来自一个非总线类型的信号线要么不同的Bus命名对象不一致。解决办法有三个先CtrlD刷新模型再打开Bus Selector确认源端用的是Bus Creator而不是向量拼接在初始化脚本里定义Simulink.Bus对象并给Bus Creator指定总线类型。如果还是不行干脆把整个信号线删除重连一次一般就能刷出来。5.5 仿真速度慢到无法接受复现SCI论文时大N模型几乎都会遇到这个问题。解决办法不是去升级电脑而是先换小N把算法验证完了再放大。验证算法阶段N2足够波形趋势和代价函数灵敏度都能看出来。如果必须跑大N把子模块开关模型换平均值模型用一个受控电压源代替整个桥臂电压值等于投入数量乘以平均电容电压。这样仿真的精确度稍降但速度最少快一个数量级适合参数扫参。后面有实验再说要不要退回详细模型。5.6 毛刺排查测量信号中的高频分量除了MPC开关动作仿真里的毛刺也可能来自测量环节本身。Simulink里直接从电力电子模型取电压电流时开关动作瞬间会有数值尖峰如果你的测量环节没有滤波或采样保持这尖峰会被MPC放大。所以测量量的处理很重要交流电流用一阶低通或者过采样取平均环流用陷波器提取电容电压用移动平均。我一般会把测量环节放在一个子系统中统一处理让控制器看到的都是干净的反馈量这一步能大幅减少后面排查问题的难度。6. 复现完成的下一步还能怎么用其实把FCS-MPC的MMC整流跑通之后后面能扩展的方向不少。最简单的扩展是把整流工况改成逆变工况参考值方向一改交流侧变成输出功率控制器本身不用动大手术。再进一步可以做故障穿越测试比如交流侧电压突降、直流侧短路看MPC能不能比PI更快地限制过流。FCS-MPC的一大优点就是约束能力可以在代价函数里加入限流约束过流时主动切换控制目标这是调制类控制很难做到的。如果准备发论文可以考虑的点也很多降低计算量的分层枚举策略、代价函数的自适应权重、开关频率和波形质量的帕累托优化、多步预测等等。复现论文只是第一步把别人的结果跑出来你才算有资格开始改自己的东西。最后分享一个小经验复现这类项目千万别急着一次性把MPC算法写到完整模型里。先把没有控制器的MMC主电路搭好加一个简单的PI双闭环或者手动开环确认桥臂电压、电容电压、环流这些波形都有物理意义然后注释掉PI控制器再把MPC函数接着写。我一开始图省事直接写MPC结果模型哪里错了都分不清退回两阶段调试之后反而快得多。这个顺序准备复现的朋友真的可以先记下来。