ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Matlab复现MMC的HSS阻抗模型:从推导到代码的避坑指南

Matlab复现MMC的HSS阻抗模型:从推导到代码的避坑指南 1. 为什么我要啃MMC的HSS阻抗模型这块硬骨头做电力电子和柔性直流输电方向的朋友对模块化多电平换流器MMC肯定不会陌生。但凡涉及到MMC并网系统的稳定性分析尤其是高频振荡问题谐波状态空间Harmonic State Space简称HSS阻抗模型就是绕不开的一座山。我最初接触这个模型的时候翻了不少文献公式推导看着都能懂但真正打开Matlab准备敲代码的时候整个人是懵的——文献里那些矩阵怎么组装、截断阶数怎么选、仿真怎么验证几乎没人给你讲清楚。这篇内容就是把我自己从推导到代码落地的完整过程梳理出来。核心关键词就几个Matlab、MMC、HSS阻抗模型、避坑指南。我会把每一步为什么这么做、参数怎么定、代码怎么写、哪里容易翻车全部摊开讲。适合正在做MMC阻抗建模的研究生、电力电子工程师以及任何需要用Matlab复现HSS类模型的从业者。哪怕你之前没接触过HSS只要懂基本的线性化方法和Matlab编程跟着走一遍也能跑通。先说清楚HSS阻抗模型到底解决什么问题。MMC内部有大量开关器件本质是一个非线性、周期性时变系统。传统的dq阻抗模型在基频附近做线性化到了高频段就失效了因为谐波耦合效应太强。HSS的思路是把周期时变系统通过傅里叶级数展开映射到一个无穷维的线性时不变系统里然后截断到有限阶数。这样一来你就能用线性系统那套阻抗分析方法去处理高频稳定性问题了。说白了HSS就是给周期性时变系统做了一次“频域升维”把耦合的谐波成分全部展开成矩阵形式。我选择Matlab而不是其他工具原因很实际矩阵运算方便、控制系统工具箱成熟、画Bode图直接调函数就行。Python当然也能做但涉及到大规模复数矩阵的特征值分析和扫频验证Matlab的生态还是更顺手。下面我从整体设计思路开始一步步往代码里钻。2. 整体方案设计与核心思路拆解2.1 HSS建模的基本框架为什么这样搭HSS建模的核心思想用一句话概括把周期时变系统的状态空间方程通过傅里叶展开转换成谐波域里的常系数线性方程。具体来说一个周期为T的系统其状态变量x(t)可以展开成傅里叶级数每个谐波次数对应一个分量。把这些分量堆成一个列向量原来的时变系数矩阵就变成了一个块Toeplitz矩阵。为什么用Toeplitz结构因为傅里叶展开后时变系数的各次谐波会以卷积的形式作用在状态变量上而卷积在频域就是乘一个Toeplitz矩阵。这个结构非常规整对角块是直流分量上下偏移的对角线对应各次谐波分量。理解这一点后面写代码组装矩阵的时候就不会迷路。整个建模流程我分成四步走第一步写出MMC的时域状态空间方程第二步确定需要保留的谐波次数做傅里叶展开第三步组装HSS矩阵第四步计算阻抗并做扫频验证。这四步里第一步和第二步是理论功底第三步是代码工作量最大的地方第四步是验证环节。很多人卡在第三步因为矩阵维度一上去就容易搞混索引。2.2 谐波截断阶数怎么选才不翻车截断阶数是HSS建模里第一个要拍脑袋定的参数。选少了高频耦合信息丢失阻抗曲线对不上选多了矩阵维度爆炸计算时间成倍增长。我的经验是先看你的关注频段。如果你关心的是2kHz以内的振荡基频50Hz那谐波次数到40次左右就够了。但MMC的高频振荡往往在几百Hz到几kHz这时候建议截断到50次以上。具体怎么算假设基频f050Hz你想分析的频率上限是fmax那截断阶数N大致满足N≥fmax/f0。比如你要看到5kHzN至少取100。但实际中不用这么死板因为高次谐波的幅值衰减很快取到fmax/f0的1.2倍左右通常足够。我一般会做两次仿真一次N30一次N60对比阻抗曲线如果两条曲线在关注频段内重合说明截断够了。还有一个坑截断阶数必须是整数而且HSS矩阵的维度是(2N1)×n其中n是原始状态变量个数。比如你有6个状态变量N50那HSS矩阵就是606×606。这个维度下做特征值分析还好但如果再往上加到N200矩阵就变成2406×2406Matlab算一次特征值可能要等好几分钟。所以截断阶数的选择是精度和效率的平衡。2.3 为什么不用dq阻抗模型替代有人会问dq阻抗模型也能分析稳定性为什么非要上HSS这个问题我当初也纠结过。简单说dq模型只保留了基频附近的动态它假设系统在dq坐标系下是时不变的。但MMC的桥臂电感和子模块电容导致系统存在大量的谐波耦合尤其是在高频段dq模型的阻抗曲线和实际扫频结果偏差很大。我做过对比在1kHz以下dq模型和HSS模型的阻抗曲线基本重合到了2kHz以上dq模型开始出现明显偏差相位误差能到几十度。这个偏差在稳定性分析里是致命的因为相位裕度可能就差这么几十度。所以如果你的应用场景涉及高频振荡HSS是必须的。如果只关心基频附近的低频动态dq模型确实够用而且计算量小很多。3. 核心细节解析与实操要点3.1 MMC时域状态空间方程的建立MMC的时域模型我采用的是单相等效电路。每个桥臂有N个子模块但为了简化我把每个桥臂等效成一个受控电压源加上桥臂电感。状态变量选桥臂电流和子模块电容电压的等效值。具体来说上桥臂电流i_p、下桥臂电流i_n、上桥臂等效电容电压v_cp、下桥臂等效电容电压v_cn这四个是核心状态变量。为什么选这四个因为MMC的动态主要由桥臂电感和子模块电容决定桥臂电流反映了能量流动电容电压反映了子模块的储能状态。其他的变量比如环流可以通过这两个电流组合得到。这样状态变量个数n4HSS矩阵维度就是(2N1)×4。如果N50矩阵就是404×404计算量可控。时域方程怎么写上桥臂的KVL方程v_dc/2 - v_p - L_arm * di_p/dt - R_arm * i_p 0其中v_p是上桥臂等效输出电压等于子模块电容电压乘以开关函数。下桥臂类似。电容电压的动态方程C_sm * dv_cp/dt i_p * s_p其中s_p是上桥臂的开关函数。开关函数是周期性的用傅里叶展开后就是各次谐波分量。这里有个细节开关函数怎么建模理想情况下开关函数是方波傅里叶展开后只有奇次谐波。但实际中考虑死区和调制方式会有偶次谐波。我建议先用理想方波做验证跑通了再考虑非理想因素。理想方波的傅里叶系数是基波幅值为1三次谐波为1/3五次为1/5以此类推。这些系数在组装HSS矩阵时会用到。3.2 傅里叶展开与Toeplitz矩阵组装傅里叶展开这一步理论推导看着复杂但代码实现其实很直接。假设时域系数矩阵A(t)是周期的展开成A(t)Σ A_k * e^(jkω0t)其中A_k是第k次谐波的系数矩阵。在HSS域里A(t)对应的矩阵是一个块Toeplitz矩阵第(i,j)块是A_{i-j}。具体到代码我一般先定义一个函数输入是谐波次数N和时域系数矩阵的傅里叶系数输出是HSS矩阵。这个函数的核心就是一个双重循环外层遍历行块内层遍历列块根据索引差去取对应的傅里叶系数。如果索引差超出了预先计算的谐波范围就填零。这里最容易翻车的地方是索引对应关系。Matlab的数组索引从1开始而谐波次数是从-N到N所以第i个谐波对应的数组索引是iN1。我当初就是在这里搞混了导致矩阵组装出来完全不对阻抗曲线像噪声一样。后来我写了一个小测试用一个已知的简单周期函数比如cos(ω0t)手动算它的HSS矩阵然后和代码输出对比确认索引无误后才继续。另一个坑是复数共轭。实际系统的时域系数是实数所以傅里叶系数满足A_{-k}conj(A_k)。组装矩阵的时候如果你只计算了正次谐波负次谐波要用共轭补上。我建议一开始就把正负次谐波都算出来虽然计算量翻倍但不容易出错。等代码跑通了再优化成只算一半。3.3 阻抗计算的实现细节HSS矩阵组装完成后计算阻抗就是解一个线性方程组。具体来说在HSS域里系统的输入输出关系是Y H * U其中H是HSS域的传递函数矩阵。阻抗Z U / I在HSS域里就是传递函数矩阵的逆。但注意我们通常关心的是从某个端口看进去的阻抗所以需要指定输入端口和输出端口。对于MMC的交流侧阻抗输入是交流侧电压的某个谐波分量输出是交流侧电流的对应谐波分量。在HSS矩阵里这对应的是特定行列的元素。我一般会先算出整个HSS域的导纳矩阵然后取对应谐波次数的对角元素作为该频率下的阻抗。这里有个细节频率扫描的时候每个频率点都需要重新组装HSS矩阵因为矩阵里的ω0是固定的但你要分析的频率是变化的。实际上HSS方法的美妙之处在于你只需要组装一次矩阵然后通过改变输出端口的谐波次数就能得到不同频率下的阻抗。比如你想看第h次谐波的阻抗就直接取HSS矩阵里对应第h次谐波的那个元素。但这里有个前提HSS矩阵是在基频ω0下展开的所以它给出的阻抗是离散的频率点即ω0的整数倍。如果你想要非整数倍的频率点比如75Hz那就需要做频率平移或者插值。我通常的做法是先算出一系列整数倍频率的阻抗然后用插值得到连续曲线。对于稳定性分析整数倍频率点通常就够了因为振荡频率往往接近基频的整数倍。4. 实操过程与核心环节实现4.1 Matlab环境准备与基础参数设定开始写代码之前先把Matlab环境理清楚。我用的版本是R2022b但R2020a以上的版本应该都能跑。需要用到的基本工具箱就是Matlab本身和Control System Toolbox后者主要用来画Bode图和做系统分析。如果你没有这个工具箱用基本的plot也能画只是麻烦一点。基础参数设定这块我建议全部放在一个脚本的开头方便后续修改。核心参数包括基频f050Hz直流电压Vdc±200kV桥臂电感Larm50mH桥臂电阻Rarm0.5Ω子模块电容Csm10mF子模块个数Nsm200。这些参数是我做的一个典型MMC系统你可以根据实际系统替换。代码里我习惯用结构体来管理参数比如para.f050para.Vdc200e3这样后面调用的时候一目了然。谐波截断阶数N50这个先定下来后面可以调整。状态变量个数n4所以HSS矩阵维度是(2*501)*4404。这个维度下Matlab组装矩阵大概几秒钟特征值分析也就十几秒完全可以接受。注意参数单位一定要统一。我当初把电感写成50mH结果代码里忘了乘1e-3导致阻抗曲线差了三个数量级排查了半天才发现是单位问题。建议所有参数都用国际单位制电感用H电容用F电压用V。4.2 时域系数矩阵的傅里叶系数计算时域系数矩阵的傅里叶系数是组装HSS矩阵的原材料。对于MMC时域系数矩阵主要来自开关函数和电路参数。开关函数的傅里叶系数是已知的对于理想方波第k次谐波的系数是2/(kπ)k为奇数偶次为0。但实际中由于调制波的影响开关函数的谐波成分会更复杂。我采用的方法是先写出开关函数的时域表达式然后用Matlab的fft函数做数值傅里叶分析。具体来说在一个基频周期内采样1024个点做fft然后取前N次谐波的系数。这样做的好处是不用推导解析表达式直接数值计算适合各种复杂的调制方式。代码实现上我定义一个函数get_fourier_coeffs(signal, N, f0, fs)输入是时域信号、谐波次数、基频和采样率输出是各次谐波的傅里叶系数。这个函数的核心就是fft和索引提取。注意fft的结果需要除以采样点数做归一化而且正负频率的系数要对应好。这里有个坑fft的频谱是双边谱索引0对应直流1到N对应正频率N1到2N对应负频率。提取的时候正频率系数取索引2到N1负频率系数取索引end-N1到end。我当初就是索引搞错了导致正负频率系数对调矩阵组装出来完全不对。4.3 HSS矩阵的组装代码实现HSS矩阵的组装是整个流程的核心。我写了一个函数build_hss_matrix(A_coeffs, N, n)输入是傅里叶系数、截断阶数和状态变量个数输出是HSS矩阵。这个函数的逻辑是先初始化一个(2N1)*n维的零矩阵然后双重循环遍历行块和列块根据索引差去取对应的傅里叶系数。具体代码逻辑是这样的外层循环i从1到2N1内层循环j从1到2N1索引差ki-j。如果k在-N到N之间就把A_coeffs的第kN1个系数矩阵填到第(i,j)块否则填零。这里A_coeffs是一个三维数组第三维是谐波次数前两维是n×n的系数矩阵。组装完成后HSS矩阵是一个大的稀疏矩阵。我一般会用sparse函数转成稀疏存储这样后续做特征值分析会快很多。对于404×404的矩阵稀疏存储能省不少内存。但注意如果你的矩阵不是特别稀疏转稀疏反而可能更慢这个要实测。实操心得组装完矩阵后先检查几个关键位置。比如对角块应该是直流分量也就是A_coeffs的第N1个系数。如果对角块不对那肯定是索引错了。我一般会打印对角块和几个偏移块的数值和手动计算的结果对比确认无误后再继续。4.4 阻抗曲线计算与扫频验证阻抗曲线的计算我分成两步先算HSS域的导纳矩阵再提取对应谐波的阻抗。导纳矩阵的计算就是HSS矩阵的逆但注意HSS矩阵可能奇异所以用pinv或者加一个小正则化项。我一般用Y inv(H 1e-10*eye(size(H)))加一个很小的对角项避免奇异。提取阻抗的时候对于第h次谐波取Y的第(hN1)行第(hN1)列的元素然后取倒数就是阻抗。这里h的范围是-N到N对应频率h*f0。比如h1对应50Hzh2对应100Hz以此类推。注意负频率对应的是共轭实际物理意义不大我们通常只看正频率。扫频验证是最后一步也是最能暴露问题的一步。我用两种方法验证一是用Matlab的Simulink搭一个时域仿真模型注入小信号扰动测量阻抗二是用解析法对于简单的RLC电路手动计算阻抗和HSS结果对比。两种方法交叉验证确保代码正确。时域仿真验证的时候注意扰动幅值要小一般取稳态值的1%到5%否则非线性效应会污染结果。我一般用1%的扰动然后做fft提取对应频率的响应。如果HSS结果和时域仿真结果在关注频段内吻合那基本就对了。5. 常见问题与排查技巧实录5.1 阻抗曲线异常排查速查表问题现象可能原因排查方法解决方案阻抗曲线全是噪声矩阵组装索引错误检查对角块是否为直流分量重新核对索引映射关系低频段吻合高频段偏差大截断阶数不够增大N重新计算N取到fmax/f0的1.5倍阻抗幅值差几个数量级参数单位不统一检查所有参数的单位统一用国际单位制相位曲线跳变复数共轭处理错误检查负频率系数确保A_{-k}conj(A_k)矩阵奇异报错HSS矩阵不满秩检查状态变量是否冗余加正则化项或减少状态变量计算时间过长矩阵维度太大检查N和n的乘积优化截断阶数或稀疏存储这个表是我踩坑踩出来的每一条都对应我实际遇到过的问题。比如第一条我当初组装完矩阵阻抗曲线像随机数一样后来发现是索引差算错了把ki-j写成了kij。改过来之后曲线就正常了。5.2 截断阶数选择的实操经验截断阶数N的选择我总结了一个实操方法先取一个较大的N比如100算出阻抗曲线作为基准。然后逐步减小N比如80、60、40、30每次对比曲线。当两条相邻曲线的最大偏差小于1%时就取较小的那个N。这样既能保证精度又能节省计算时间。我实测下来对于MMC的高频振荡分析N50通常够用。但如果你的系统有很强的谐振峰比如在3kHz附近有个尖峰那N可能要取到80以上才能准确捕捉。因为谐振峰对应的是高次谐波的耦合截断不够的话峰值会被削平。还有一个技巧如果你只关心某个特定频率附近的阻抗比如2.5kHz那可以只保留该频率附近的谐波其他谐波截断。这叫“局部HSS”能大幅降低矩阵维度。但实现起来复杂一些需要对频率做平移。我一般先用全局HSS跑通再考虑局部优化。5.3 时域仿真验证的避坑要点时域仿真验证是最后一道关卡但也是最容易出问题的地方。我踩过的坑包括扰动幅值太大导致非线性失真、仿真步长太大导致高频信息丢失、fft采样窗口不是整数个周期导致频谱泄漏。扰动幅值我建议取稳态值的1%最大不超过5%。仿真步长要小于最高关注频率对应周期的1/20。比如你关注5kHz周期是0.2ms步长要小于10μs。fft采样窗口要取整数个基频周期否则加窗函数但加窗会引入幅值误差所以最好还是取整数周期。还有一个坑时域仿真里MMC的开关频率和采样频率要匹配。如果开关频率是1kHz采样频率至少10kHz否则开关动作捕捉不到。我一般用20kHz的采样率这样5kHz以内的谐波都能准确提取。注意时域仿真验证的时候先不加扰动跑一遍稳态确认系统稳定。然后再加扰动做小信号分析。如果稳态都不稳那说明参数有问题先调参数再验证。6. 代码优化与扩展方向6.1 稀疏矩阵与并行计算加速当N取到100以上时HSS矩阵维度超过800稠密矩阵的逆运算会非常慢。这时候用稀疏矩阵能大幅加速。Matlab的sparse函数可以把矩阵转成稀疏存储然后inv对稀疏矩阵有优化。我实测下来N100时稀疏矩阵的逆运算比稠密矩阵快3到5倍。另一个加速方法是并行计算。如果你有多个频率点要算可以用parfor并行循环。但注意HSS矩阵的组装是串行的只有阻抗提取可以并行。我一般把矩阵组装好然后parfor遍历谐波次数提取阻抗。这样能利用多核CPU速度提升明显。还有一个技巧预分配内存。Matlab里数组动态增长很慢所以组装矩阵之前先zeros预分配。我当初没预分配N50时组装矩阵花了半分钟预分配之后只要几秒钟。6.2 从单相到三相的扩展我上面讲的是单相等效模型实际MMC是三相对称的。扩展到三相的方法有两种一是直接建立三相模型状态变量翻三倍二是利用对称性把三相解耦成正序、负序、零序三个单相模型。我推荐第二种因为计算量小而且物理意义清晰。正序、负序、零序的HSS矩阵结构相同只是参数略有差异。正序和负序的阻抗在对称系统中是相同的零序不同。所以你可以只算正序和零序负序直接取正序的共轭。这样计算量减少三分之一。扩展到三相后阻抗矩阵变成3×3的矩阵对角线是各序阻抗非对角线是序间耦合。对于对称系统非对角线为零。如果系统不对称比如桥臂参数不一致那非对角线就不为零这时候需要做特征值分析。6.3 与其他阻抗建模方法的对比HSS阻抗模型不是唯一的选项。除了dq阻抗模型还有谐波线性化方法、描述函数法等。我简单对比一下dq模型计算量最小但只适用于低频谐波线性化方法精度高但推导复杂描述函数法适合分析极限环但不直接给出阻抗。HSS的优势在于精度高、适用频段宽、代码实现相对直接。缺点是矩阵维度大、计算量大。所以选择哪种方法取决于你的应用场景。如果只关心基频附近的稳定性dq模型足够如果涉及高频振荡HSS是首选。我个人的经验是先用dq模型快速评估如果发现高频段有异常再上HSS做精细分析。这样既能保证效率又能保证精度。7. 我在实际操作中的几点体会这套HSS阻抗模型的代码我从头到尾写了三遍。第一遍完全照搬文献结果跑不通第二遍自己推导了一遍发现文献里有些细节没讲清楚第三遍才把代码理顺跑通了验证。最大的体会是理论推导和代码实现之间有一条鸿沟这条鸿沟只能靠反复调试来填。另一个体会是不要怕矩阵维度大。我一开始看到404×404的矩阵就发怵觉得肯定算不动。实际上Matlab处理这种规模的矩阵毫无压力几秒钟就出结果。真正花时间的是调试索引和验证结果而不是计算本身。最后分享一个小技巧写代码的时候每完成一个模块就单独测试。比如傅里叶系数计算完先画个频谱图看看对不对HSS矩阵组装完先检查对角块阻抗算完先和解析解对比。这样一步步验证比最后一起调试要高效得多。我当初就是图省事全部写完才跑结果一个索引错误导致所有结果都不对排查了一整天才找到问题。
返回列表