开年在某个项目的仿真预研里,我又一次把十机三十九节点这套经典测试系统翻出来跑了一遍。之所以说"又",是因为这套系统在电力系统稳定分析、保护整定、控制器参数调试里出现的频率实在太高了,凡是做机电暂态、次同步振荡或者广域控制算法验证的人,几乎都绕不开它。我最早接触它还是在读研那会儿,当时拿着一份从某篇论文附录里抄来的节点数据,泡在实验室里折腾了整整一周才把潮流调收敛。后来在工程里又用Matlab和Simulink重做了好几版,从单纯潮流计算到完整机电暂态仿真,踩过的坑叠起来能写一本小册子。这篇就把我最近一次用Simulink搭建十机三十九节点动态模型的过程好好拆一遍,从数据组织、模型架构、参数映射到扰动仿真验证,全部按可复现的标准写清楚,希望能帮到正在跟这套系统死磕的朋友。
很多人拿到三十九节点的资料第一反应是去网上找现成的模型文件,但现成模型往往"黑盒"得厉害:要么是已经封装好的子系统,要么是封装后修改参数就报错,根本不利于理解系统结构。我更推荐的做法是先把数据吃透,再自己动手搭一遍,这样后面无论换参数、加控制器还是改扰动场景,心里都有底。
1.1 三十九节点系统的基本结构
十机三十九节点测试系统描述的是一个简化但保留关键特征的大区域电网:39条母线、10台同步发电机(其中一台是等效大电网的聚合等值机)、12台双绕组变压器、34条交流输电线路和19个负荷节点。它的拓扑可以粗略分成三个电压层级:发电机通过升压变压器接入高压输电网络(基准电压通常取345kV),区域之间通过长距离输电线路互联,负荷则分布在各个中高压节点上。
这套系统最大的价值在于它保留了"多机系统"最核心的动态行为特征——机群之间的功角摆动、联络线功率波动、电压支撑强弱差异。如果你只用单机无穷大系统做仿真,很多区域间振荡模态根本激发不出来,而三十九节点系统恰好有足够丰富的机电振荡模态,既能覆盖局部模式,也能体现区域间模式,所以它是验证电力系统稳定器、广域阻尼控制甚至机器学习潮流优化算法的理想试验床。
1.2 数据组织方式:从节点表到动态参数
搭建模型前,必须把数据整理成下面几类,缺一不可:
- 母线数据(Bus Data):母线编号、基准电压、节点类型(PQ/PV/Slack)、初始电压幅值与相角;
- 线路数据(Branch Data):首末端母线编号、线路电阻、电抗、对地电纳、变压器变比;
- 发电机数据(Generator Data):接入母线、有功出力、无功出力、机端电压设定值、有功/无功上下限;
- 动态参数(Machine Dynamic Data):同步发电机d轴/q轴电抗、暂态电抗、次暂态电抗、惯性时间常数、阻尼系数,以及励磁系统与调速器的简化模型参数。
我一般会把这些数据统一整理到三个Excel表或三个结构体数组里:bus、branch、gen。因为后边不管是用Matlab做潮流,还是用到Simulink里做初始化,本质上都是读取和映射这些数据。有一个容易被忽略的点是:**网上能找到的三十九节点数据版本很多,不同版本之间机组编号、负荷数值甚至线路参数都有细微差异,甚至"39节点"这个系统在新英格兰原始数据里的基准频率是60Hz,单位是标幺值,而不少国内资料会直接换算成50Hz版本。**做仿真前必须先确认你的基准频率到底是多少,这个参数会直接影响后面所有的电机参数设置。
!> 注意:如果拿到的是p.u.标幺值数据,一定要明确功率基准是多少。三十九节点标准数据通常以100MVA为功率基准,100MVA也是后面Simulink里同步电机模块常用的额定功率基准,两者对齐能省很多换算麻烦。
2. Matlab脚本还是Simulink模型:先在架构上做对选择
不少初学者一上来就问"Simulink怎么搭三十九节点",但实际上在动手拖模块之前,先要决定整体技术路线:**你究竟要做潮流计算、静态安全分析,还是要做机电暂态动态仿真?**这两者的实现路径是完全不同的。
2.1 两条路线的分工
Matlab脚本(m文件)走的是矩阵计算路线:把导纳矩阵拼出来,用Newton-Raphson或者P-Q分解法解潮流方程,优点是轻量、可控性强、适合批量计算和优化算法嵌套,缺点是它本质上只能做稳态分析,动态仿真需要自行积分微分方程,工作量很大。
Simulink走的是物理模型路线:同步发电机、变压器、输电线路、负荷都有现成模块,Simscape Electrical库里的元件按物理端口连起来,配合Powergui(电力图形用户界面)做潮流初始化和仿真求解,优势是天然适合机电暂态、电磁暂态仿真,可以直观地观察电压、电流、功率、转速波形。
在我的实际经验里,**最终稳定可靠的做法是:先用Matlab脚本把潮流算通、算对,再把潮流结果作为初值喂给Simulink模型做动态仿真。**两者不是二选一,而是串联配合。Simulink里的Powergui也能自动做潮流初始化(Load Flow),但它需要所有发电机、负荷参数都正确填写,一旦有一台发电机有功出力跟潮流数据对不上,初始化就会失败。所以我会先在脚本层把潮流校核清楚,再用这个结果去验证Simulink的初始化。
2.2 脚本侧:拼导纳矩阵的脚手架
用Matlab做潮流计算,核心工作是构建节点导纳矩阵Y。做法不复杂:遍历所有线路数据,把每条线路的串联阻抗转成导纳,加上对地电纳的一半,再把变压器支路的非标准变比折算进去,最后把各支路贡献累加到Y矩阵的对应位置。
% 构建导纳矩阵 Ybus function Ybus = buildYbus(bus, branch) nBus = size(bus, 1); Ybus = zeros(nBus, nBus); for k = 1:size(branch, 1) fb = branch(k, 1); % 首端母线 tb = branch(k, 2); % 末端母线 r = branch(k, 3); x = branch(k, 4); b = branch(k, 5); tap = branch(k, 6); % 变压器变比,非变压器为1 z = r + 1j*x; y = 1/z; ysh = 1j*b/2; if tap == 1 % 普通线路 Ybus(fb, fb) = Ybus(fb, fb) + y + ysh; Ybus(tb, tb) = Ybus(tb, tb) + y + ysh; Ybus(fb, tb) = Ybus(fb, tb) - y; Ybus(tb, fb) = Ybus(tb, fb) - y; else % 变压器支路:考虑非标准变比 Ybus(fb, fb) = Ybus(fb, fb) + y / (tap^2); Ybus(tb, tb) = Ybus(tb, tb) + y; Ybus(fb, tb) = Ybus(fb, tb) - y / tap; Ybus(tb, fb) = Ybus(tb, fb) - y / tap; end end end拼好Ybus后,用自带的loadflow或者自己写Newton-Raphson迭代都可以。对三十九节点这类规模,迭代十几轮就能收敛到10的负十次方精度。如果潮流不收敛,优先检查三类问题:一是负荷数据是否单位搞混(MW和Mvar写反了),二是PV节点的无功出力是否越限,三是平衡机的有功取值是否明显偏离系统总发用平衡。
2.3 Simulink侧:选对元件库版本
Simulink里搭建电力系统模型,用的是Simscape > Electrical > Specialized Power Systems库(老版本叫Power System Blockset)。重点模块包括:
- Synchronous Machine pu Fundamental(同步电机标幺值模型,分标幺和有名值两种,推荐标幺值模式,参数好填);
- Three-Phase Transformer(三相双绕组变压器);
- Three-Phase PI Section Line / Distributed Parameters Line(线路模型);
- Three-Phase Parallel RLC Load(三相负荷);
- Three-Phase Fault(三相短路故障模块,扰动注入用);
- Powergui(整个仿真模型的"大脑",用于选择仿真类型、潮流初始化、FFT分析)。
注意:旧版Specialized Power Systems库支持powerlib命令快速打开元件库,新版可能在库浏览器里藏得比较深。建议直接在Simulink库浏览器里搜模块名,比一层层点进去快得多。
!> 避坑:同步电机模块有个特性,端口顺序是总线侧(B、Q、D三组)、励磁输入(fd+、fd-)、机械输入(Pm)。不少新手把Simulink的物理端口跟普通信号端口搞混,导致励磁和机械转矩信号接不进去。这类问题查起来相当耗时间,一定要先看清帮助文档里的模块端口图。
3. 在Simulink里搭建十机三十九节点:步骤、参数与连线顺序
接下来就是硬核的搭建环节。我建议的顺序是:先搭好全部39条母线,再依次接入发电机-变压器支路、线路和负荷。每搭一块就标记清楚,避免后面连错线。
3.1 母线节点:用"Bus Bar"模块还是直接连线?
Simulink里没有专门的"母线模块",物理上传输线、变压器、负荷和发电机会直接在节点处相连。为了模型清晰,推荐在每个节点处放一个三条短线的连接点(即用Simulink的直线直接用结点连接),或者使用Three-Phase Bus模块(在Specialized Power Systems库里可以找到,老版本有,新版本可能要用连接线加标签代替)。
我的习惯是:每个母线用一个Subsystem子系统包起来,子系统内部保留3个三相电气端口,这样可以在子系统里面加测量模块(电压、频率测量),外部连线一目了然。对三十九节点这种规模,如果全部平铺在一个窗口,连线会乱成蜘蛛网,根本没法维护。按照区域划分成几个子系统(比如按发电机所在区域或地理分布),把互联线路在子系统间连接,整体结构会清晰很多。
3.2 同步发电机参数映射
同步电机模块的标幺值参数分几组:额定参数(额定功率、额定电压、额定频率)、绕组参数(定子电阻、漏抗)、d/q轴电抗(同步电抗、暂态电抗、次暂态电抗),以及时间常数(开路时间常数)和惯性参数(惯性时间常数H、阻尼系数)。
标准数据里给的是节点导纳形式和经典模型参数,而Simulink模块要的是电机内部方程里的x_d、x'_d、x''_d、T'_d0、T''_d0等。这两者需要做一个映射:如果你拿到的数据只给了经典二阶模型(即只有x'_d和H),那就只能选"经典模型"的简化方式,把暂态电抗填入x'_d,x''_d和x_d用默认值或与x'_d保持一致。如果你拿到的是完整六阶/四阶模型数据,就逐项对应填入。
**最关键的一个参数是惯性时间常数H。**标准数据里H单位是秒(s)还是MW·s/MVA?大多数公开数据给的是秒,Simulink模块H的填写单位也是秒,直接填就行。但注意某些版本的Simulink同步电机模块要求的是"惯量常数H(s)",而内部计算用的是2H,别重复乘2。
3.3 变压器、线路与负荷建模
变压器模块需要填额定容量、频率、一二次侧额定电压、漏抗(标幺值,通常给0.01-0.08之间)、空载损耗和铜损。在三十九节点里,发电机接入的升压变压器变比很重要,它决定了发电机机端电压与345kV网络电压之间的匹配关系。举个简单的例子:如果发电机机端额定电压是20kV,网络基准电压是345kV,变压器就设成20kV/345kV,漏抗标幺值直接用p.u.给定,不需要换算。
线路模块的选择我推荐Distributed Parameters Line(分布参数线路),因为它的模型在宽频范围内更准确,而且参数填入方式更直观(单位长度电阻、电感、电容、线路长度)。如果使用PI型集中参数模型,则需要在工频下算等效的集总参数。对于30km以下的短线路,两种模型差别不大;但对于三十九节点里几百公里的长线,分布参数模型的波形更贴近真实。**需要强调的一点:标幺值线路数据要先换算成实际单位才能填进线路模块。**比如线路阻抗0.01 + j0.05(p.u.,基准100MVA,345kV),对应实际阻抗是 0.01×345²/100 = 1.19Ω,电抗5.95Ω,再除以线路长度得到单位长度阻抗。这个换算很多新手会漏掉,导致仿真出来的电压、功率完全不对。
负荷建模统一用Three-Phase Parallel RLC Load,填入额定线电压、频率以及有功、无功(单位kW/kvar或MW/Mvar都行,注意Simulink默认用kW),负荷类型默认恒阻抗。实际上标准潮流数据里负荷是按恒功率给定的,严格来说恒功率负荷在Simulink的RLC Load模块里并不完全等价,因为RLC模块本质是恒阻抗。如果想仿真更贴合实际,可以用受控电流源做恒功率负荷,但那会显著增加仿真收敛难度。作为起步,我建议先用恒阻抗负荷跑通动态响应,确认所有结果合理后再考虑负荷模型细节。
3.4 Powergui的潮流初始化
全部模块搭完后,双击Powergui,进入Tools > Compute Load Flow,按顺序填写每台发电机的有功、无功/机端电压,负荷的有功无功,求解器会自动计算初始稳态。这里有两个高频报错场景:
- 初始化失败:报"Power flow did not converge"。几乎都是因为发电机参数、变压器变比、负荷量级三者之间不自洽。排查路径是:先用Matlab脚本算一遍潮流,看各节点电压幅值和相角是否在合理范围(0.9-1.1 p.u.),然后检查Simulink里各个发电机的P和V设置是否跟潮流数据一致。
- 初始化"成功"但初始波形突变:说明Powergui算出来的初值跟模型实际状态不一致,最常见原因是负荷模块的接线方向反了(负荷功率从节点流出接成了流入),或者变压器绕组联结方式错误(Y-D接法和相位偏移会影响潮流分布)。
3.5 完整连线清单参考
下面给出一套自查清单,照着逐项检查能省很多调试时间:
| 检查项 | 常见错误 | 排查方法 |
|---|---|---|
| 发电机机端电压基准 | 20kV侧跟345kV网络混用基准 | 升压变压器变比必须显式设置 |
| 线路单位长度换算 | 直接用p.u.填分布参数 | 先换算成Ω/km再填 |
| 变压器绕阻联结 | Y-Y或Y-D相位偏移搞错 | 核对标准数据里的相移约定 |
| 负荷方向 | 功率方向接反导致潮流不收敛 | 检查负荷模块电流方向箭头 |
| 同步电机机械输入 | PI控制器接错端口 | 确认Pm端口输入的是机械功率标幺值 |
| 励磁电压VF | 初始值不为1导致电压建立异常 | 先用常数1试跑,再加励磁调节器 |
4. 仿真验证:潮流校核、扰动注入与波形解读
模型搭建完成后,最关键的环节是验证仿真结果是否正确。没有验证的仿真模型等于没有校准的仪器,数据再漂亮也不能信。
4.1 第一件事:核对潮流结果
Powergui潮流计算完成后,把仿真跑起来,等波形稳定后,用Scope或者To Workspace模块采集各节点电压幅值和线路功率,跟标准潮流数据逐点对比。两者误差应该在1%以内。如果误差超过5%,说明某个模块参数映射有问题,逐一排查。
经常出现的情况是:发电机节点的电压匹配良好,但负荷节点电压整体偏低。这种情况十有八九是线路参数换算错误——电阻或电抗算大了一倍,导致全网电压降落偏大。可以用一个简单方法快速验证:把一条短线路的参数手动算一遍,看跟软件内部计算值是否一致。
4.2 扰动注入:短路与负荷突变的做法
动态仿真最常用的扰动方式有两种:
三相短路故障用Three-Phase Fault模块,可以设置在指定母线,设置故障起始时间(比如5s)、持续时间(如0.1s)和接地阻抗。故障点可选线路中间某点,也可以直接选在母线上。故障清除后,系统应该经历一段功角摆动,然后经过几秒到十几秒回到稳态。这个"回到稳态"的过程就是机电暂态的核心观察对象。
负荷阶跃更简单:把某个负荷模块的有功输入从一个常数改成阶跃信号即可。比如在t=5s时让某节点负荷增加200MW,观察系统频率、联络线功率和发电机功角的动态过渡。
需要提醒的是,Simulink里Simscape电力系统的刚性很强,仿真步长设置不当会直接导致数值发散。建议:
- 求解器选
ode23tb或ode15s,这类刚性求解器对电力电子和电机模型更友好; - 最大步长设置不超过1ms(如果你要观察次同步频段,则需要更小步长);
- 精度相对容差默认1e-3通常够用,如果波形毛刺多可以收紧到1e-4。
4.3 该看哪些波形
搭建好模型后,优先观察下面几类信号,它们是判断仿真正确与否的直接依据:
- 发电机功角(Rotor Angle):故障后几台发电机之间会出现相对摆动。如果功角持续增大或振荡愈发剧烈,说明系统不稳定。正常情况是经过几个周期衰减后趋于平稳。
- 发电机转速(Speed Deviation):正常情况下转速偏差在干扰后数十秒内回零;如果存在持续振荡,就要考虑是不是缺少阻尼(很多系统初始参数就是欠阻尼的,这恰恰是你要研究的问题)。
- 节点电压:故障期间电压跌落,故障切除后恢复,观察恢复过程是否平滑。电压振荡发散说明模型参数异常。
- 线路有功功率:扰动后联络线功率的波动幅度和频率,能反映区域间振荡模式。
看波形时特别提醒一句:三十九节点系统在只有经典二阶发电机模型、没有励磁系统PSS的情况下,天然就是弱阻尼甚至负阻尼的,故障后出现持续振荡并不一定是你模型错了,可能恰恰说明系统确实缺阻尼。判断模型正确与否的关键,是看振荡频率和模态是否跟理论值接近,而不是只看是否收敛到稳态。
4.4 我踩过的高频坑
4.4.1 发电机模块"参数填错了但潮流还行"
同步电机的某些动态参数(比如x''_d、T''_d0)对潮流结果几乎没有影响,因为潮流只涉及稳态方程。所以可能出现"潮流完全正确、动态波形却离谱"的情况。比如次暂态电抗填错,短路瞬间的电流冲击幅值就会偏差很大。动态参数错误需要专门的手段验证,最常见的就是拿单机无穷大系统的短路特性做标定。
4.4.2 线路充电功率引起的稳态电压偏高
三十九节点系统有很多长线路,分布电容较大。如果跳过潮流初始化直接让模型自己从零过渡到稳态,可能出现某些空载节点电压长时间缓慢爬升的现象。这是线路电容的充电效应,不是错误。可以通过在仿真前用Powergui的Load Flow给一个合理初值来加速稳态建立。
4.4.3 单位问题
这个问题看起来基础,但实际出现的频率最高。三相额定功率和单相额定功率混淆、线电压和相电压混淆、Mvar和MVA混用……我见过不少跑到一半发现振荡幅值差了100倍的案例,最后都是单位问题。建议在模型里建立一份参数清单,每个关键量注明单位和数值来源,排查速度会快很多。
5. 可复现的完整操作流程:从零跑通十机三十九节点仿真
讲了这么多,最后给一份我自己用着比较顺手的完整流程,按顺序执行基本可以跑通一套标准配置。如果你完全没接触过这套系统,建议照着一动不动地执行一遍,再根据研究目标做裁剪。
5.1 准备工作与数据文件组织
在Matlab当前目录下建一个项目文件夹,里面至少包含:
bus_data.m:母线数据,以矩阵或表格形式保存;branch_data.m:支路数据;gen_data.m:发电机数据;machine_dyn.m:动态参数;buildYbus.m:导纳矩阵构建脚本;run_pf.m:潮流计算脚本;sim_39bus.slx:Simulink模型。
数据文件全部放在同一目录下,通过脚本读取,不要手动在Simulink里逐个填数字,否则可维护性极差。
5.2 潮流计算与数据校核
在run_pf.m里调用buildYbus构建导纳矩阵,然后调用Matlab的loadflow(需要Power System Toolbox或自写Newton-Raphson)解潮流。校验判据:
- 每台发电机的无功出力在上下限范围内;
- 所有节点电压幅值在0.9~1.1 p.u.之间;
- 平衡机组有功与全网负荷+损耗大致平衡。
满足以上条件,说明数据本身是自洽的,可以进入Simulink搭建。
5.3 Simulink模型的搭建顺序
- 放置10台同步电机,以编号命名(比如G1~G10),填入动态参数。其中母线39对应的等值机通常选容量最大的那台;
- 放置12台变压器,连接发电机组与升压母线;
- 放置34条线路,根据线路表连接母线;
- 放置19个负荷,填入有功无功;
- 放置Powergui,设置在"稳态潮流+暂态仿真"模式下。
每连完一条线路,可以先用Scope看一次三个单相电压波形,确认该母线电压建立正常。如果某条线连接错误,波形会有明显的相位或幅值异常,这时候定位比全部连完再排查要容易得多。
5.4 动态仿真的标准实验
一套标准的动态仿真实验包括三个算例:
算例A:稳态运行100s。不加扰动,确认所有波形平稳,无漂移、无数值噪声。
算例B:t=5s母线三相短路0.1s。观察各发电机功角摆动、电压跌落与恢复。摆频通常在0.5~1.5Hz范围内,具体取决于系统惯性时间常数和电气距离。
算例C:t=5s负荷阶跃增加。观察频率最低点(频率跌落幅度)和恢复时间,此时可以评估调速器的作用。
如果你要做多工况批量仿真,建议写一个run_sim_batch.m脚本,用sim命令循环运行不同故障参数组合,把结果用To Workspace输出到MATLAB工作区,再统一绘图。大批量仿真时的Simulink模型加载时间很长,建议用Simulink.SimulationInput批量配置参数,可以显著提升效率。
% 批量仿真参数示例:不同故障起止时间 simIn(1) = Simulink.SimulationInput('sim_39bus'); simIn(1) = simIn(1).setBlockParameter([gcb '/Three-Phase Fault'], 'FaultTime', '5'); simIn(1) = simIn(1).setBlockParameter([gcb '/Three-Phase Fault'], 'ClearanceTime', '5.1'); simOut = sim(simIn);5.5 扩展方向:给模型加励磁系统与PSS
跑通最基础的二阶经典模型后,很多人马上会遇到一个问题:模型太简陋,算出来的结果跟论文里对不上。因为真实系统里发电机都带励磁调节器和调速器,这些闭环控制会显著改变动态特性。Simulink的同步电机模块自带励磁端口,可以外接标准的IEEE励磁模型,比如常用的直流励磁机模型(对应Simscape里的励磁系统模板),或者自己用传递函数搭一个一阶惯性环节近似。
这里我的建议是从简到繁梯度推进:先不加励磁,跑通二阶模型;然后加一个简单的AVR(自动电压调节器),用比例积分环节模拟机端电压闭环;最后再升级成包含PSS(电力系统稳定器)的完整励磁系统。每加一级,对比一次动态波形变化,这样才能搞清楚每个环节对稳定性的贡献。很多人一上来就接全套IEEE励磁模型,结果参数太多根本调不过来,最后波形乱成一团也不知道是哪个环节的问题。
这套模型我前后搭过三版,每一版都有不同的教训。第一版是纯脚本做动态仿真,程序写了一千多行,性能差还容易发散;第二版在Simulink里平铺模型,接线连到怀疑人生;第三版也就是今天分享的这套——子系统化、参数文件化、先脚本后Simulink——才算是真正稳定可复现的结构。如果你现在正好卡在潮流不收敛或者初始化失败,不妨先退回去重新核对一遍单位换算和变压器变比,这两个地方是绝大多数问题的根源。把这套十机三十九节点模型吃透了,后面无论是研究新能源并网、储能调频还是广域控制,都有了一个扎实的起步平台。