
做柔性直流和模块化多电平方向仿真的人应该都遇到过这种尴尬论文里的MMC控制效果很漂亮一上手复现就掉进Simulink的深坑。这篇复现笔记讲的就是基于混合有限集模型预测控制FCS-MPC的模块化多电平换流器MMC整流电路仿真——简单说用模型预测控制去管MMC的交流电流和直流电压而不是传统的PI载波移相那一套。标题里的“SCI二区IEEE复现”指的是IEEE电力电子方向二区期刊里常见的那类控制策略我在Simulink里把它完整跑通了这里把核心思路、参数计算、建模过程和踩坑记录一起整理出来。这套方案能帮你解决什么问题第一FCS-MPC天然适合处理MMC这种多变量、多约束的系统电流响应快还能把“电容电压均衡”直接写进控制目标第二纯FCS-MPC在MMC上有个致命问题是计算量爆炸——所有开关状态穷举根本算不动混合方案把可行状态从全排列压缩成“子模块投入数量”的有限集合工程量瞬间降下来。这篇内容适合两类人一是研究生课题需要复现IEEE论文又不知道从哪下手二是已经在做电力电子仿真但被排序算法、桥臂环流和Simulink离散步长折磨得够呛的工程师。1. 方案整体设计与思路拆解1.1 为什么MMC需要MPC而不是传统调制MMC的基本结构大家都熟三相六桥臂每个桥臂一串半桥子模块加一个桥臂电感。整流模式下交流侧通过桥臂电感给子模块电容充电直流侧输出稳定的直流电压。传统做法一般是PI外环控制直流电压内环用载波移相SPWM或者最近电平逼近NLM去控制桥臂电压。这套方法成熟可靠但问题也很明显调制参数多环流抑制要单独加控制器而且PI参数在不同工况下的鲁棒性一般。FCS-MPC的思路完全不一样。它不搞调制器而是直接把换流器当成一个有限开关状态集合的系统。每个控制周期枚举所有可能的开关状态用系统模型预测未来一个采样周期的电流或电压算一个代价函数取代价最小的那组开关状态直接输出。好处是概念清晰、响应快、多目标约束可以做进代价函数里尤其适合强耦合、非线性的对象。MMC正是这样的对象——桥臂电流、环流、子模块电容电压、直流电压彼此耦合用MPC天然合适。但把FCS-MPC直接套到MMC上会撞墙。假设一个桥臂有N个子模块单个半桥子模块有两种状态整个上桥臂的开关组合就有2的N次方。三相交错、上下桥臂再组合状态数直接变成2的6N次方。我做N4的模型时全遍历的候选状态已经到2的24次方量级Simulink里一个控制周期根本跑不完。N11甚至更高的时候要么牺牲控制频率要么上昂贵的实时仿真器普通实验室的MATLAB平台直接卡死。这就是“混合”两个字的来历。混合有限集模型预测控制本质上是把MPC和传统调制/均压策略做一个分工MPC不直接枚举所有子模块的开关组合而是先输出桥臂需要投入的子模块数量具体投入哪几个子模块交给传统的电容电压排序均衡算法去决定。计算量直接从指数级降到线性级同时保留了MPC快速响应的优点。1.2 “混合有限集”到底在混合什么我一开始也对这个说法有误解以为是论文造新词。真把模型搭起来才明白这里的混合至少包含两层意思。第一层是控制目标的混合。MMC整流要同时管三件事交流电流波形要正弦、直流电压要稳定、子模块电容电压要均衡。传统PI框架里这三件事要拆成多个环路再加均压算法而FCS-MPC可以把它们统一到一个代价函数里通过权重系数调节侧重点。第二层是算法结构的混合MPC负责动态性能好的电流控制排序算法负责静态均衡的电压控制两者各自干自己最擅长的事。具体到候选集合的设计约束条件很关键。正常运行中上下桥臂投入的子模块总数必须恒等于N否则直流侧电压会波动。因此上桥臂投入数N_up一旦确定下桥臂投入数就固定为N - N_up。这样候选集合就不是所有开关排列而是N_up从0到N这N1个取值。N4的时候候选集合只有5个N11也只有12个计算量完全可控。这就是“有限集”的真正含义有限集合不是所有开关状态组合而是所有满足物理约束的投入数量组合。这个设计还有一个额外的好处它天然避免了纯FCS-MPC里常见的“开关状态跳变过大”问题。因为排序算法在同一个数量等级内切换具体子模块而MPC只改变投入数量桥臂电压的变化被量化到单个子模块电压级别输出波形更平滑谐波也更小。2. 核心模型与控制器设计细节2.1 MMC整流电路的等效模型与预测方程要复现论文第一步不是急着在Simulink里搭桥臂而是先列数学模型。以单相为例上桥臂电压记为v_up下桥臂电压记为v_lower它们分别由各自投入的子模块数和子模块平均电容电压决定v_up n_up × v_c_upv_lower n_lower × v_c_lower。整流器交流侧输出电压实际上是上下桥臂电压的差的一半。电网相电压e_g与交流侧电压的关系为e_g L_eq × (di/dt) v_conv其中L_eq是网侧电感L_g和桥臂电感L_arm的等效组合整流模式下通常取L_g L_arm/2。v_conv用上桥臂和下桥臂电压表示为(v_lower - v_up)/2。为了做预测控制要把上面的连续方程离散化。最常用的是一阶前向欧拉控制周期为T_s采样时刻k的电流预测值写为i_pred(k1) i(k) (T_s / L_eq) × [v_conv(k) - e_g(k)]这里v_conv(k)由候选的投入数量和当前电容电压实测值计算得到。每个控制周期内系统会枚举N1个候选的n_up值n_lower随之确定分别计算预测电流然后用代价函数选择最优的投入数量。这里有个容易忽略的细节v_conv的计算用的是实测电容电压而不是额定值因为MPC本质上是基于当前状态的预测电容电压波动是影响预测精度的直接因素不能省略。实际搭建三相模型时我会把三相电流变换到dq坐标系下控制。这样外环直流电压PI输出的就是d轴电流参考值q轴电流参考值设为0单位功率因数无功电流和功率因数控制就都清楚了。MPC还是在abc三相独立预测但代价函数放在dq坐标系里计算这样有功和无功分开看调参直觉更清晰。2.2 代价函数、权重系数与候选集的生成代价函数是整个控制器的心脏。我的实现里采用最典型的电流跟踪型代价函数g (i_d_ref - i_d_pred)² (i_q_ref - i_q_pred)²i_d_ref由直流电压外环PI给出i_q_ref一般设0。MPC枚举候选集合里每一个n_up预测出对应的i_d_pred和i_q_pred找到g最小的那组这就是当前周期的最优投入数量。有人会问不是说均压也进代价函数吗我实测下来如果已经把均压分离给排序算法代价函数里再加电容电压均衡项收益很小反而要调它的权重系数麻烦。IEEE论文里有的加、有的不加属于不同流派。不加时排序算法会保证电压在一个合理的波动范围内加了则更容易把电压偏差控制得更紧但权重系数如果给大了电流波形会变差因为两个目标的优先级发生了冲突。权重系数怎么调我的经验是先只保留电流项把电流波形调到能稳定跟踪再以很小的步长引入均压项。归一化也很重要——电流误差是安培量级电压误差是伏特量级如果直接相加电压项会被数值淹没必须除一个合适的基值。比如用额定相电流峰值做电流误差的归一化基值用子模块额定电压做电压误差的归一化基值这样两个目标在同一个量纲下λ可以从1附近开始调。候选集的生成有一个反向约束要注意如果上桥臂选n_up下桥臂就是N - n_up但排序算法最终投入的具体子模块电压之和并不严格等于n_up × V_c_nom因为电容电压在波动。因此我建议预测时不用理想值而是直接用当前周期实测的上下桥臂各自已投入子模块电压总和来计算v_conv。这样模型误差小很多电流谐波能明显下降。2.3 控制频率、采样与计算量的平衡FCS-MPC的控制频率直接决定了等效开关频率和电流质量。控制频率越高跟踪越快谐波越小但计算量也成倍增加。我在N4、控制频率20kHz时Simulink模型在普通台式机上能跑到实时左右把控制频率降到10kHz时波形谐波明显变差但还能接受。这里有个工程经验与其一味提高控制频率不如先保证MPC的采样和执行真正同步。Simulink里如果用了变步长求解器控制周期的间隔可能不一致MPC每次执行时模型状态和假设条件不完全匹配波形会出现随机毛刺。所以控制器的Trigger必须用固定步长离散求解器采样信号用零阶保持器锁存。控制频率和开关频率不同——MPC在一个控制周期内切换一次投入数量组合等效开关频率通常只有控制频率的1/4到1/3因为连续多个周期可能保持同一个候选状态。计算量方面MATLAB Function块里做枚举排序N4时有5个候选每个候选做一次预测和代价计算运算很少。真正的瓶颈在排序算法每周期对每个桥臂的电容电压排序N越大越耗时。我后面在第三章里具体讲怎么把排序和MPC解耦这里先记下结论——排序算法必须从MPC主循环里拆出去才能兼顾仿真速度和后续C代码生成部署。3. Simulink仿真搭建全过程3.1 主电路部分搭建我的模型基于Simulink Simscape Electrical Specialized Power Systems库搭建电源用Three-Phase Source线电压380V、50Hz网侧电感L_g取2mH。MMC部分是重点三相六桥臂每个桥臂4个半桥子模块串联加一个5mH桥臂电感。半桥子模块内部结构不复杂两个IGBT带反并联二极管中间一个直流电容输出端引出。搭建时有一个关键细节子模块的IGBT开关信号来自控制侧但Simscape里的IGBT需要数字信号驱动而测量得到的电容电压又是连续信号。信号跨域容易出代数环。我的做法是给控制侧所有输入输出都接上Zero-Order Hold并且在MATLAB Function块内部全程用double类型变量避免Simulink自动把信号类型推断成boolean导致编译报错。直流侧接一个负载电阻功率大约5kW量级。子模块电容的参数需要按桥臂能量波动公式估算。单桥臂能量波动峰值约8焦耳4个子模块共享电容电压额定200V允许电压波动10%即20V那么C ΔE/(N × V_c × ΔV_c) 8/(4×200×20) 0.5mF。为了留裕量实际模型里取1mF。算出来之后我还专门验证过电容电压波动范围大约在192V到206V之间和估算比较吻合。3.2 MPC控制器与排序均衡的实现控制器部分我分成了三个子系统外环直流电压PI、内环FCS-MPC、排序均衡。外环PI的输入是直流母线电压参考值800V和实测值输出是d轴电流参考。PI参数我沿用传统整定方法然后根据仿真响应微调。d轴电流参考要加限幅防止启动瞬间电流冲击过大——我一开始没加限幅第一次仿真直接从交流侧吸了上百安培的冲击电流波形难看不说还差点把虚拟的IGBT都“烧”了。内环MPC用MATLAB Function块输入是三相电流、三相电网电压、直流电压和上下桥臂投入子模块电压总和输出是每个桥臂需要投入的子模块数量。核心代码结构大概是function [n_up, n_down] mpc_selector(...) % 输入全部由零阶保持器锁存 % 枚举 n_up 0 : N % 对每个候选计算 v_conv预测电流计算代价函数 % 找到代价最小的 n_upn_down N - n_up % 输出给排序模块这里要注意MATLAB Function块里不建议直接访问工作区参数必须通过参数对话框传进去否则代码生成和复用都会出问题。我吃过的亏是参数被自动转成常量后改参数还要重新编译整个模型排查问题慢了半拍。排序均衡子系统的逻辑更直接每个桥臂接收本桥臂所有子模块电容电压实测值、桥臂电流方向判断充电还是放电和需要投入的子模块数量。如果桥臂电流方向是充电就投入电压最低的N个模块放电则投入电压最高的N个模块。我用的是经典的sort算法把电容电压排序取对应位置。这个逻辑单独放在一个Triggered Subsystem里由固定频率的脉冲触发和MPC周期分开互不阻塞。3.3 参数汇总与求解器配置模型里用到的典型参数汇总如下参数数值备注电网相电压峰值311V线电压380V50Hz网侧电感L_g2mH用于交流侧滤波桥臂电感L_arm5mH限制环流和故障电流子模块数N4桥臂串联半桥子模块数量子模块电容C1mF按能量波动估算电容电压参考200V直流母线800V除以N直流电压参考800V外环PI给定负载电阻128Ω对应约5kW功率MMC控制频率20kHz等效开关频率约5kHz外环PI频率2kHz比内环慢10倍排序触发频率20kHz与MPC同步求解器设置是最容易被忽略的环节。我的配置是定步长、离散求解器、ode4步长1e-6秒。为什么不直接用和MPC一样的20kHz因为IGBT的开关动作、Simscape的电力电子模型对求解步长有要求步长太大容易产生数值振荡。控制频率20kHz是控制器的执行频率仿真步长1e-6是数值积分步长两者各有职责不要为了省时间强行把仿真步长拉到50us——我试过波形会变得毛糙代价是花更多时间排查“假故障”。仿真时长我一般设0.4秒前0.1秒是启动动态后面看稳态效果。4. 常见问题与排障实录4.1 仿真不收敛、电压电流发散怎么查这类问题十有八九出在初始化。MMC的子模块电容电压如果默认从0开始启动瞬间等价于一个极大的充电电流涌进电容MPC再厉害也扛不住。我的做法是用一个预充电逻辑前0.02秒不启动MPC而是让所有子模块通过一个旁路电阻充电到额定电压附近或者更简单一点直接给MATLAB Function的持久变量和控制器的初始状态赋值让电容电压从200V附近开始。第二个高频原因是代数环。MPC的输入里如果包含了自己的输出或由输出反推的中间变量Simulink会在每个步长里反复迭代轻则报错重则计算结果震荡。排查方法很简单用信号探查工具看变量是否有迭代延迟或者把输出逻辑拆开输出直接给零阶保持器再接输入人为断开代数环。我最早搭框架时就是没注意这一点报了几个“Algebraic loop detected”警告仿真速度慢了三倍去掉之后立刻恢复正常。发散还有一个隐蔽源头外环PI限幅太宽。直流电压误差在启动瞬间很大PI输出直接顶到上限MPC为了追这个大电流参考会把投入数量推到极端接着桥臂电压失衡。所以我建议给外环输出限幅的同时给MPC的候选集合外加一个“每周期最多改变一个投入数”的限速逻辑。这个限速不只是限制冲击也能显著降低开关频率一箭双雕。4.2 波形畸变、谐波与环流问题如果电流波形看起来正弦但毛刺多先检查采样信号是不是有噪声。解决办法是在测试点加截断滤波器或者在MATLAB Function入口加一个滑动平均滤波。但要留个心眼滤波器带来的延迟会直接影响MPC预测精度所以滤波窗口越短越好我一般只做3点滑动平均。谐波偏大且主要集中在低频段优先怀疑L_g和L_arm太小。电感取小了电流纹波就大取大了MPC的响应速度会变慢。调整时看电流纹波和动态响应的平衡不要盲目增大电感。整流模式里桥臂环流是一个绕不开的话题。环流是二倍频分量在上下桥臂之间流动不经过交流侧所以从交流电流波形上不一定看得出来。因为混合方案中MPC控制的是交流电流并没有主动控制环流桥臂电感对环流有限流作用但不彻底。N4时环流对电容电压的影响还能接受想要更好效果代价函数里可以加入“桥臂电流与期望环流的误差项”或者参考经典做法加一个二倍频负序环流抑制器。我在代价函数里加过环流项效果很明显但权重又多了一个要调的λ最终取舍看课题目标。Bus Selector没有可选信号的问题我遇到过好多次。这是因为Simulink对总线信号的缓存刷新不及时。解决办法是在Simulink模型窗口按CtrlD刷新或者把BUS对象定义成simulink.Bus对象并在模型初始化时加载。如果是仿真过程中动态修改了总线结构必须重新编译一次模型否则信号列表不会更新。4.3 MATLAB Function、持久变量和外环整定坑MATLAB Function块里用persistent变量存上一周期的状态时有个很烦的坑模型重启时持久变量不会自动清零导致第二次运行从一开始就带着上一次的残迹。解决办法是在函数里用一个reset信号作为初始化触发仿真开始前手动执行一次模型初始化或者用clear命令清掉持久变量。我后来为了省事写了一个初始化标志位从Constant块接到函数输入仿真开始前置1第一个控制周期内清零从此不再有“闹鬼现象”。外环PI的整定我多说一句。第一次做时我按直流电机控制的经验把PI带宽设得较高结果直流电压在800V附近高频抖动MPC跟着电流参考来回切换开关频率暴涨。后来把PI带宽降到内环的1/5到1/10电压纹波和开关频率都正常了。这个先内环后外环、外环慢于内环的原则在MPC系统里同样成立甚至比传统调制系统更敏感。如果觉得模型和论文结果还是对不上我最后的排查手段是把MPC模块临时换成纯NLM调制跑一遍。如果NLM模式下波形正常说明主电路和参数没问题问题一定在控制器如果NLM也不正常先回头查主电路。这个对比排查法帮我区分了至少三次“控制器bug”和“主电路参数错”的场合。最后再分享一个小技巧把排序算法和MPC主循环分离之后如果后续想往实验方向走这两个模块都能用Simulink的C代码生成直接转成嵌入式代码FPGA或DSP上都好移植。我自己在完成仿真复现之后下一步就在用这个框架跑组串型拓扑的扩展验证把混合有限集的思想迁移到更复杂的拓扑上改动量比预期小不少这也是这套方案最值得借鉴的地方。