做 MMC 仿真的人,十有八九都会卡在同一个坎上:模型搭起来很快,跑起来全是问题——波形发散、电容电压乱跳、桥臂电流畸形、仿真速度慢得离谱。我最近刚好把 N=22 的模块化多电平换流器(MMC)在 Matlab/Simulink 里完整搭了一遍,调制策略用的最近电平逼近(NLM),从参数计算、模型搭建到调参排错走了一整轮,这里把能直接复用的经验整理出来。这个配置很典型,N=22 在学术研究和工程预研里都很常见,既保留了多电平的波形质量优势,又不会像 N=200 那样把仿真器拖垮。这篇文章适合正在做课程设计、毕业论文,或者刚接触柔直/变频方向、准备用 Simulink 验证控制算法的同学参考,我尽量把每一步为什么这么做讲清楚。
1. 方案选型:为什么是 N=22,为什么用最近电平逼近
1.1 NLM 与载波移相法的取舍
MMC 的调制策略主流有两大类:载波移相正弦脉宽调制(CPS-SPWM)和最近电平逼近调制(NLM)。很多人一上来就纠结选哪个,我的建议很直接:子模块数量 N 比较小(比如 N≤10)时,CPS-SPWM 的优势明显,因为能保住较高的等效开关频率,波形谐波好;但 N 到了 22 这个量级,再用 CPS-SPWM 就有点自找麻烦了。
为什么?CPS-SPWM 每个子模块都需要一路三角载波,N=22 意味着每个桥臂 22 路载波,三相六个桥臂就是 132 路载波,相位要精确错开,调制波要逐一比较,模型里光载波生成和比较器就是一大片,仿真步长稍大一点波形就失真。更关键的是,CPS-SPWM 下每个子模块开关管都在高频动作,仿真计算量非常大,而且实际工程中这么高的开关损耗也不划算。
NLM 的逻辑非常朴素:参考电压是多少,就投入最接近的那个电平数对应的子模块数量。每个桥臂需要投入的子模块个数 n 可以写为:
n = round(u_ref / u_c)
其中 u_ref 是当前时刻的参考电压,u_c 是单个子模块电容电压的实时平均值或额定值。NLM 不需要三角载波,不需要复杂比较器,核心就是一个取整函数加一个限幅,实现成本极低。在 N=22 时,输出相电压可以形成 23 个电平的阶梯波,谐波含量已经相当可观,完全够用。
所以我的结论是:N 一旦超过 10,优先考虑 NLM;N 到 22 这个量级,NLM 基本是唯一合理选择。这也是现实中模块化多电平换流器工程普遍采用 NLM 的原因。
1.2 子模块数量 N 对仿真的实际影响
N 的取值直接决定了系统设计的好几个关键指标。首先,单个子模块电容电压额定值由直流母线电压和 N 共同决定:
u_c = U_dc / N
如果直流母线电压是 20kV,N=22,那么每个子模块电容电压额定值大约是 909V。N 越大,单个模块电压应力越低,对功率器件耐压要求越宽松,但子模块数量增加会带来控制复杂度和成本上升。N=22 是一个性价比很高的折中。
从仿真角度看,N=22 的模型规模是三相六桥臂,每个桥臂 22 个子模块,总共 132 个半桥子模块。如果你用最详细的 IGBT 器件级模型去搭,每个子模块里俩 IGBT、俩二极管、一个电容,再带上开关动作的数值求解,仿真会慢到怀疑人生。所以我后面会讲一套工程上常用的等效建模方法:把开关动作抽象成理想的受控源,把电容电压用积分器等效,只保留控制层面的动态特性。这样既保留 MMC 的外特性,又能让仿真跑得动。
2. 调制与均压:NLM 的原理、参数含义与工程实现
2.1 最近电平逼近的数学本质
最近电平逼近这个名字听起来高大上,实际上就是一个“四舍五入”的问题。MMC 每个桥臂有一串子模块,每个子模块要么旁路(输出 0),要么投入(输出电容电压 u_c)。桥臂能输出的电压是离散的,只能取 0、u_c、2u_c、3u_c……也就是 N×u_c 这些台阶。而控制系统给出的参考电压是一个连续变化的正弦量,我们需要在每个控制周期里找一个离参考值最近的台阶,这就是最近电平逼近。
用公式表达:
n_ref = round(u_ref / u_c_avg)
n_on = max(0, min(N, n_ref))
其中 u_c_avg 是当前桥臂所有子模块电容电压的平均值。这里有一个细节很多人会忽略:u_c_avg 究竟用实时平均值还是额定值?我建议用实时平均值。因为电容电压在运行中会有波动,如果一直用额定值做除法,参考值靠近峰值时可能会出现投入子模块数计算偏差,导致输出电压台阶不平整。用实时平均值做归一化,等效于把电容电压波动的影响从调制环节中隔离出去,波形更干净。
还有一个细节是取整方式。Simulink 里直接调用 round 函数即可,但要注意 round 在 Simulink 的 MATLAB Function 块里是四舍五入,不是向上取整也不是向下取整。最近电平逼近的关键就在这个“最近”上,不建议用 floor 或 ceil,否则输出电压会系统性偏低或偏高,产生恒定偏差,在闭环控制里会变成稳态误差。
2.2 排序均压算法的 Simulink 实现技巧
NLM 本身很简单,真正决定 MMC 能不能稳定运行的是子模块电容电压均衡。因为每个子模块的电容参数不可能完全一致,充放电时间也不一样,如果不加均压控制,各电容电压会逐渐发散,有的模块电压飙升,有的模块电压跌落,最后损坏器件。
经典的排序均压算法思路是:每个控制周期,对所有子模块电容电压排序,根据当前桥臂电流的方向决定怎么投入。
- 如果桥臂电流为正值,说明电流在给电容充电,那就优先投入电容电压最低的 n 个子模块,让低电压模块多充电;
- 如果桥臂电流为负值,说明电流在给电容放电,那就优先投入电容电压最高的 n 个子模块,让高电压模块多放电。
用这样的规则,电容电压会被拉向平均值。这个算法写出来非常简单,排序用 sort 函数即可:
function [pulses, order] = sorting_balancing(u_c_vec, n_on, i_arm) % u_c_vec: 当前桥臂N个子模块电容电压向量 % n_on: 需要投入的子模块个数 % i_arm: 桥臂电流,正为充电方向 % pulses: 输出投切信号,1表示投入,0表示旁路 N = length(u_c_vec); [~, idx] = sort(u_c_vec); % 默认升序排列 pulses = zeros(N, 1); if i_arm >= 0 % 充电:投入电压最低的n_on个 pulses(idx(1:n_on)) = 1; else % 放电:投入电压最高的n_on个 pulses(idx(N-n_on+1:N)) = 1; end end这段代码在 Simulink 里放进 MATLAB Function 块就能跑。但有几个性能坑要提醒:
第一,如果每个仿真步长都执行一次全局排序,仿真速度会明显变慢。N=22 时每个桥臂才 22 个数,排序开销还不算大,但如果你以后扩展到 N=100 以上,就必须优化。常见做法是加一个触发条件,只有在参考电压变化超过一个电平或者每隔固定步数才执行排序。我在 N=22 的模型里用了 PID 采样时间控制排序频率,仿真速度快了将近一倍,电容电压波动并没有明显恶化。
第二,排序均压会导致子模块开关频率偏高,因为每次排序后投入组合都可能在变。为了降低开关频率,可以在排序时加入滞环:电压差小于一定阈值时保持原来的投切状态不变。这个技巧在做损耗分析时非常有用。
第三,MATLAB Function 块内的代码要注意变量初始化。很多人第一次跑就报“Output argument 'pulses' not assigned”的错误,就是因为 if/else 分支没有覆盖所有情况,或者排序索引越界。建议在代码开头先把 pulses 全部置 0,再根据条件修改。
3. 从零搭一个 N=22 的 MMC 仿真:参数计算与建模步骤
3.1 主电路参数计算(含算例)
在动手搭模型之前,先把参数算清楚。我以一个 10kV/5MVA 的交流系统为例,直流母线电压 U_dc 取 20kV,子模块数 N=22。所有计算逻辑可以复用到你自己的工况,只要替换电压和容量即可。
第一步,子模块电容电压额定值:
u_c = U_dc / N = 20000 / 22 ≈ 909 V
第二步,桥臂额定电流。MMC 的桥臂电流由两部分构成:一部分是交流输出电流的一半,另一部分是直流电流的三分之一。交流线电流有效值:
I_line = S / (√3 × U_ac) = 5e6 / (1.732 × 10e3) ≈ 288.7 A
交流电流峰值约 408A,桥臂电流里交流分量大约是峰值的一半,也就是 204A 左右。直流电流:
I_dc = P / U_dc = 5e6 / 20000 = 250 A
桥臂电流里直流分量是 I_dc / 3 ≈ 83A。两者叠加,桥臂电流额定值大概在 230A 上下,再加一点环流裕量,可以取 250A 作为设计值。
第三步,子模块电容取值。工程上常用时间常数法:
C = 2 × H × I_arm / u_c
其中 H 是时间常数,一般取 30ms 到 40ms。取 H=35ms 的话:
C = 2 × 0.035 × 250 / 909 ≈ 0.0193 F ≈ 19.3 mF
这个电容值可以在仿真里先跑一版,观察电容电压波动幅度。如果波动超过额定值的 ±10%,就需要增大电容;如果波动很小,说明电容有余量,可以适当减小以降低成本。
第四步,桥臂电抗。桥臂电抗的作用是限制环流和故障电流,经验取值在 0.1 到 0.2 p.u. 之间。按 0.15 p.u. 计算:
L = 0.15 × U_dc² / (2 × ω × S) = 0.15 × 400e6 / (2 × 314.16 × 5e6) ≈ 19 mH
这四个参数算完,主电路基本就定了。这里特别提醒,参数计算不是一锤子买卖,仿真里观察到的波形会反过来要求你调整电容和电感,先按公式算出一个基准,再微调,这是正常流程。
3.2 系统级建模:三相结构、信号路由与调制模块
Simulink 模型的整体结构我建议分成四层:主电路层、控制层、调制层、观测层。主电路层包括直流源、六个桥臂(每相上桥臂和下桥臂)、每桥臂的 22 个子模块等效电路、桥臂电感和交流负载。控制层负责生成三相参考电压,最简单的开环控制就是直接给三相正弦参考,闭环的话就加电压/电流环。调制层把参考电压换算成每个桥臂的投入子模块数,再结合排序均压生成 132 路投切信号。观测层接 Scope 或 Data Inspector 看波形。
子模块等效电路是仿真提速的关键。不要用 Simscape 里的 IGBT 器件去一个个搭,正确做法是:每个子模块建模成一个受控电压源(输出侧)和一个受控电流源(电容侧),投切信号直接控制这两个受控源的增益。
- 电容侧:电容电流 i_c = i_arm × S_invest,S_invest 是投切状态(1 投入,0 旁路),电容电压通过积分器积分得到;
- 输出侧:子模块输出电压 u_sm = u_c × S_invest。
这样每个子模块在数学模型里只占一个积分器和两个乘法器,132 个子模块算下来计算量也很小。我在实际测试里,同样的参数和工况,详细器件模型的仿真速度大约是等效模型的 1/20 到 1/30。做控制算法验证、参数优化、故障分析,等效模型完全够用,没必要用器件级模型折磨自己。
桥臂之间的信号路由也要注意。每个桥臂输出的投切信号是 22 维向量,电容电压也是 22 维向量,这些信号在 Simulink 里建议直接用 Mux 或 Bus 组织成向量,不要一根线一根线地连。排序均压模块放在每个桥臂内部,输入是电容电压向量、投入子模块个数、桥臂电流,输出是投切向量。这样封装好之后,六个桥臂的子系统结构完全一致,复制粘贴就能搭出三相,改参数也只需要改桥臂内部的常量。
3.3 启动策略:预充电与解锁过程
很多人搭完模型直接给方波或正弦参考一跑,结果波形惨不忍睹,电容电压直接崩掉。原因很可能是没有做预充电。MMC 启动时,所有子模块电容电压都是零,如果直接解锁投入,冲击电流会非常大,电容电压根本稳不住。
标准的启动流程分两步。第一步是不解锁控制,让所有子模块处于旁路状态,通过直流电源经限流电阻给电容充电,直到电容电压接近额定值。这个过程在仿真里可以用一个 Simulink Signal Builder 或 Step 模块控制接触器完成:先串入限流电阻充电,电容电压到达额定值后切除限流电阻。第二步再解锁调制和均压控制,参考电压从零开始缓慢增大,给定一个斜坡而不是阶跃,让系统平滑过渡到稳态。
我在实际仿真中发现,N=22 时预充电时间大约需要 0.1 到 0.2 秒(取决于电容大小和限流电阻),如果跳过预充电直接跑,初始阶段桥臂电流会出现几十倍额定值的尖峰,虽然仿真不至于崩,但后面的动态过程会失真。
4. 仿真提速与常见问题排查
4.1 仿真速度慢的优化手段
N=22、132 个子模块的模型,如果不做优化,仿真推进会非常糟心。我总结了三层提速手段,按性价比排序。
第一层,求解器设置。默认的变步长连续求解器在开关动作频繁时会不断缩小步长,非常慢。如果控制算法是离散的,建议把整个模型改成离散定步长,步长取 20 微秒到 50 微秒。20 微秒对应 50kHz 采样率,对于 50Hz 基波、NLM 调制(等效开关频率本来就不高)来说绰绰有余。改成离散定步长之后,仿真速度可以提升好几倍。
第二层,等效模型。前面提到的受控源等效子模块已经是底线了,不要用器件级模型。
第三层,降低排序频率。排序均压算法不一定要每个步长都跑,可以每 10 个步长排序一次。N=22 时排序本身不慢,但这种习惯对以后扩展到更大 N 有好处。
还有一个容易忽略的点:Scope 模块不要放太多。Scope 本身不影响仿真主流程,但如果开了大量数据记录,尤其是把所有 132 路投切信号都送到 Scope 里,内存和显示开销会让仿真明显变卡。我的做法是只观测关键的聚合量:三相输出电压、桥臂电流、某个桥臂的电容电压向量、投入子模块个数,需要看详细投切状态时再临时加 Scope。
4.2 波形分析与电容电压波动问题定位
模型跑起来之后,第一件事是看三个波形:输出相电压、桥臂电流、电容电压。
输出相电压应该是 23 电平的阶梯正弦波。如果看到电平数不对,先检查投入子模块个数有没有被限幅在 0 到 N 之间,很多时候是 round 之后没做限幅,或者 u_c_avg 传错了信号维度。如果电平做了但波形不对称,检查上桥臂和下桥臂的参考电压是不是互补关系,MMC 每相上桥臂和下桥臂的参考电压相位应该差 180 度,且两者之和等于直流母线电压。
电容电压波形应该是围绕额定值的小幅脉动,脉动频率是二倍基波频率(100Hz),波动幅度在额定值的 5% 到 10% 之间属于正常。如果电压发散或整体漂移,优先检查排序均压算法的方向对不对:充电时投入低压模块,放电时投入高压模块,如果方向反了,电容电压会越拉越偏。我调试时在排序模块里加了一个变量输出当前投入模块的电压平均值,一眼就能看出均压逻辑是否在起作用。
电容电压波动幅度过大的原因通常有三个:电容值太小、桥臂电流过大、缺少环流抑制。前两个通过参数调整解决,第三个需要单独说说。
4.3 二倍频环流的来源与抑制
MMC 运行中,上桥臂和下桥臂的瞬时电压之和并不严格等于直流母线电压,差值会在三相桥臂之间形成环流,频率主要是二倍频(100Hz)。环流本身不体现在交流侧,但它会增加桥臂电流有效值,加剧电容电压波动,还可能让桥臂电抗饱和。
如果仿真里发现桥臂电流波形里有明显的 100Hz 正弦分量,且三相之间相互流通,这就是环流。抑制方法有两类。一是被动抑制,增大桥臂电抗,简单有效但会拖慢动态响应。二是主动抑制,在控制系统里加一个二倍频负序环流抑制器,常用的方案是 dq 坐标系下的 PI 控制器或静止坐标系下的 PR 控制器。检测三相环流,在二倍频 dq 旋转坐标系下做控制,输出补偿电压叠加到参考波上。
对于 N=22 的仿真验证,我建议先加大桥臂电抗把环流压住,把整个系统跑稳定了,再决定要不要加主动环流抑制。一开始就上复杂的环流抑制环,出了问题很难分清是调制的问题还是环流控制的问题。
4.4 谐波评估与 THD 改善
NLM 的输出波形是阶梯波,谐波特性跟电平数直接相关。N=22 时输出 23 电平,THD 一般在 3% 到 5% 之间,具体取决于调制比和电容电压波动。想看谐波成分,在 Simulink 里可以直接用 Powergui 的 FFT Analysis,或者把波形数据导到 MATLAB 工作区用 fft 函数分析。
FFT 分析时会发现一个规律:NLM 的谐波主要集中在中低频段,不像 PWM 那样有明确的高次载波边带。电平数越大,最低次谐波的次数越高,幅值越小。如果 N=22 的 THD 不满足要求,最直接的办法是增大 N,但在仿真里如果 N 已经被限定,那就只能通过控制手段改善:一是在调制波里注入合适的三次谐波(零序分量),提高调制比利用率;二是优化电容电压波动幅度,因为电容电压波动会直接耦合到输出电压里,形成低频谐波。
另外提醒一句,FFT 分析时要注意加窗和采样点数,直接取一个周期做 FFT 会有频谱泄漏。我习惯的做法是取 10 个周期的数据,用汉宁窗,再把结果换算到基波有效值归一化,这样算出来的 THD 比较准。很多人仿真波形看着挺好,一算 THD 数值偏大,往往就是分析窗口和窗函数设置的问题。
5. 从一次真实调试经历谈几个容易踩的坑
最后分享一次印象比较深的调试经历。模型搭好之后第一次跑,输出电压阶梯波出来了,但电容电压以肉眼可见的速度往下掉,掉到额定值的一半左右才稳住,而且桥臂电流波形严重畸变。排查了很久,最后发现是限幅条件写错了:我把投入子模块个数的上限写成了 N-1,导致每个桥臂永远少投入一个模块,直流电压无法完全建立。
这个错误很隐蔽,因为在开环状态下交流输出波形看起来没问题,只有看直流侧电压和电容电压平均值时才能发现。从那以后,我每次跑仿真都会先看几个关键的平均值指标:直流母线电压、各桥臂电容电压平均值、调制波和实际输出电压的偏差。这四个量能快速判断模型是“大体正确”还是“看似正确但暗藏问题”。
还有一次,模型一启动就报“Matrix dimension must agree”错误,查了半天发现是电容电压向量的维度在某个信号路由处被截断成了 21 维,因为有个 Mux 模块少接了一路信号。这个问题的教训是:N=22 的模型里,所有跟子模块相关的向量信号维度必须是 22,建议在调试阶段把关键信号的维度用 Display 模块显示出来,一眼就能看出哪里断了。
N=22 的 MMC 仿真模型,在我个人看来是整个模块化多电平技术里性价比最高的一个试验台。它比 N=5、N=11 那种低电平模型更贴近工程实际,谐波和均压特性都有代表性,又不像 N=100 以上那样对仿真资源有苛刻要求。跑通这个模型之后,往高压大容量方向扩展、换成全桥子模块、加环流抑制、做故障穿越,都是在同一套框架上做增量修改。希望这篇经验整理能帮你少走几步弯路。