简介:pandapower 1.2.0 是面向电力系统科研与工程应用的官方 Python 库压缩包,可帮助用户高效完成电网建模、潮流计算、故障分析与最优潮流等任务,适合具备 Python 基础、需要离线使用完整工具链的研究人员、工程师和高年级学生。包内共 163 个文件,127 个 py 模块构成核心实现,22 个 pickle 格式算例数据可直接用于测试与复现,另有配置、说明文档和许可证文件,压缩后约 1.93MB,部署非常轻量。内容包含典型 IEEE 节点测试系统以及大规模输电网络模型,覆盖从教学算例到接近真实电网的多种规模,读者可借助自带数据快速验证算法,或基于开放接口构建自定义拓扑与运行场景。目前已有 573 人浏览学习,作为官方发布版本,可满足课程实验、论文复现和工程预研等需求,同时减少自行整理数据与处理依赖的时间成本,是入门及进阶电力系统仿真的实用资料。
1. pandapower 装好不一定会用,先搞懂它解决什么问题
如果你只是pip install pandapower然后用net = pp.create_empty_network()建了一条线,跑完runpp()就以为会了,那这篇值得往下看。pandapower 是基于 pandas、NumPy 的电力系统分析工具,它把电网建模变成填表,把潮流计算、最优潮流、短路计算变成一行函数调用。它的价值不在“能算潮流”,而在于“数据和结果都是 pandas DataFrame”,你可以像处理普通表格一样处理电网数据,批量改参数、批量跑场景、对照结果做差异分析。对于配电网规划、微电网调度、教学科研和新能源并网分析,这是目前开源库里综合体验最顺的一条路。这篇会从安装 zip 包讲起,一路到潮流计算参数调整、不收敛排查和批量仿真,中间每个步骤的代码都能直接拷走改改就跑。
2. 从 pandapower-1.2.0.zip 到可复现的安装流程
2.1 为什么 1.2.0 需要明确 Python 版本
pandapower 1.2.0 是 2025 年 4 月发布的版本,引入了 generator 的功率因子定义、load/static_generator 的 scaling 简化标记,以及针对有功-频率控制的扩展。它不是最新版,但在不少生产环境和教材里仍然被引用,原因是它的 API 行为相对固定,对新用户来说社区资料更好找。安装前先确认 Python 版本:pandapower 1.2.0 官方支持 Python 3.9 到 3.12,低于 3.9 会遇到语法兼容问题,高于 3.12 则可能因为依赖包没有对应 wheel 而失败。我一般会先检查当前环境的 Python 版本再装,避免把基础环境搞乱。
2.2 离线 zip 包安装的两种方式
有时候机器不能直接访问公共包索引,只能拿着 pandapower-1.2.0.zip 手动安装。常见做法是用 pip 直接指向本地文件,但在那之前必须先装好它的依赖。pandapower 1.2.0 的核心依赖包括 pandas(要求 >=1.4,不建议用 2.2 以下版本)、numpy、scipy、networkx、deepdiff。可以先建一个干净的虚拟环境,避免污染全局解释器。下面是我惯用的方式,Windows 和 Linux 通用。
python -m venv pp_env # Windows pp_env\Scripts\activate # Linux / macOS source pp_env/bin/activate # 先装依赖 pip install "numpy>=1.23" "scipy>=1.8" "pandas>=1.4" "networkx>=2.6" "deepdiff>=6.0" # 再装本地 zip 包 pip install ./pandapower-1.2.0.zip这段命令的逻辑是先创建独立虚拟环境,然后把 pandapower 的五个核心依赖装好,最后用pip install ./pandapower-1.2.0.zip安装本地包。./前缀是为了明确告诉 pip 这是一个本地路径,而不是 PyPI 上的包名。有人会直接把 zip 包解压后运行python setup.py install,这个做法在新版 Python 里容易踩坑,因为 setuptools 对 project metadata 的处理方式变了,推荐优先用 pip。
另一种方式是先解压 zip,再把pandapower文件夹直接复制到site-packages下。这种方式不推荐,因为依赖关系不会自动解析,卸载时也容易残留文件。非要这么做的话,至少先记录下当前环境的pip freeze结果,方便回滚。
2.3 验证安装:导入与版本检测
装完后不要急着建网络,先跑一组最基础的验证代码,确认核心模块能导入、版本正确、依赖没有缺失。
import pandapower as pp print(pp.__version__) # 创建最小测试网络 net = pp.create_empty_network() bus1 = pp.create_bus(net, vn_kv=20.0, name="bus1") bus2 = pp.create_bus(net, vn_kv=0.4, name="bus2") pp.create_transformer(net, hv_bus=bus1, lv_bus=bus2, std_type="0.4 MVA 20/0.4 kV") pp.create_line(net, from_bus=bus2, to_bus=bus2, length_km=0.1, std_type="NAYY 4x50 SE") pp.create_load(net, bus=bus2, p_mw=0.1, q_mvar=0.05) pp.runpp(net) print(net.res_bus)这段代码的意思是:用create_empty_network建空网络,依次创建高压母线、低压母线、变压器、线路和负荷,然后调用runpp做潮流计算,最后打印结果表。如果看到版本号、没有报错,并且res_bus表里有 vm_pu 数据,说明安装成功。如果这里就报了ModuleNotFoundError: No module named 'pandapower',八成是当前解释器和安装神器 misalign 了。此时在 VSCode 里检查右下角解释器路径,确认它指向pp_env下的 python,而不是全局解释器。
pip show pandapower这条命令会显示 pandapower 的安装路径,可以用来和which python的输出做交叉验证。如果两个路径不在同一个 site-packages 目录下,解释器选错了,直接切换解释器重新跑。
出现AttributeError: module 'pandapower' has no attribute 'runpp'这类错误时,原因是安装的版本不对或者安装文件损坏。重新下载 zip 包,检查文件 hash 是否和官方 release 一致,再来一遍安装流程。
3. 用 pandapower 搭建电网模型:bus、line、load 的参数该填什么
3.1 数据模型:从 pandas 表格到电力网络
pandapower 的核心概念是“表格即模型”。net.bus、net.line、net.load、net.trafo 这些都是 DataFrame,每一行对应电网里的一个设备,每一列对应设备的参数。这种设计的直接好处是:你想批量修改同类型设备参数时,不用写循环,直接对 DataFrame 做列计算就行。
理解这个模型对后续使用很重要。pandapower 本身不保存一个独立的“图结构”,网架拓扑是从这些 DataFrame 的 from_bus / to_bus 列中推导出来的。所以哪怕只填错一个 bus 索引,拓扑就会错,潮流结果自然不对。下面这个图可以帮你建立基本印象:
| 元素类型 | 核心 DataFrame | 关键列 | 作用 |
|---|---|---|---|
| 母线 | net.bus | vn_kv, name, type | 电压等级基准,拓扑锚点 |
| 线路 | net.line | from_bus, to_bus, length_km, std_type | 输电/配电连接 |
| 变压器 | net.trafo | hv_bus, lv_bus, std_type | 电压变换 |
| 负荷 | net.load | bus, p_mw, q_mvar | 有功/无功消耗 |
| 发电机 | net.gen | bus, p_mw, vm_pu | 有功注入,电压控制 |
母线是拓扑锚点,线路和变压器两端必须挂在已存在的 bus 索引上。负荷和发电机也必须挂在某个 bus 上。所有设备的索引都是自动生成的,插入顺序从 0 开始递增。这意味着如果你删除了某个 bus,它后面的索引不会自动紧凑,新建设备时要注意避免索引冲突。
3.2 最小放射状配电网实例
下面以一个 20kV 馈线带两个 0.4kV 台区为例,搭一个最小但完整的配电网模型。放射状配电网是最常见的结构,也是学习 pandapower 最好的起点。
import pandapower as pp net = pp.create_empty_network() # 上级变电站母线 for vn_kv in [20.0, 0.4]: pp.create_bus(net, vn_kv=vn_kv) # 20kV 馈线 pp.create_line(net, from_bus=0, to_bus=1, length_km=1.2, std_type="NA2XS2Y 1x240 RM/25 12/20 kV", name="Feeder") pp.create_load(net, bus=1, p_mw=1.5, q_mvar=0.3, name="load_1") # 变压器 20/0.4 kV,容量 630 kVA pp.create_transformer_from_parameters( net, hv_bus=1, lv_bus=2, sn_mva=0.63, vn_hv_kv=20.0, vn_lv_kv=0.4, vkr_percent=0.4, vk_percent=4.0, pfe_kw=1.2, i0_percent=0.2 ) # 0.4 kV 低压线路 pp.create_line_from_parameters( net, from_bus=2, to_bus=3, length_km=0.05, r_ohm_per_km=0.642, x_ohm_per_km=0.083, c_nf_per_km=210.0, max_i_ka=0.142, name="LV_Line" ) pp.create_load(net, bus=3, p_mw=0.08, q_mvar=0.02, name="load_2") pp.runpp(net) print(net.res_line[["from_bus", "to_bus", "loading_percent", "i_ka"]]) print(net.res_load[["bus", "p_mw", "q_mvar", "vm_pu"]])这里用create_line配合 std_type 引用标准型号,用create_transformer_from_parameters和create_line_from_parameters直接填写电气参数。两者的区别是:std_type 是 pandapower 内置的标准类型库,填了型号会自动带出电阻电抗参数,适合快速搭建;from_parameters 则完全手填,适合找不到标准型号的场景。这里的 bus 索引是从 0 开始的,母线 0 是 20kV 上级母线,母线 1 是中压馈线末端,母线 2 是 0.4kV 低压侧,母线 3 是低压负荷节点。
3.3 参数陷阱:电压单位、容量、线路参数
新手最常犯的错误是把潮流计算用的单位搞混。pandapower 里电压用 kV,功率用 MW / MVAr,容量用 MVA,长度用 km。但很多人习惯用 W、V、A 去填参数,导致结果数量级完全不对。另一种常见错误是把阻抗的单位写成欧姆而不是欧姆每公里,create_line_from_parameters里 r_ohm_per_km 和 x_ohm_per_km 都是每公里的值,如果直接填了总阻抗,长线路后会明显偏高。
检查网络完整性有现成方法:
pp.check_net(net)这个方法会检查孤立节点、未连接的设备、缺失的参数值等常见问题。如果检查通过但结果仍然不像话,可以用net.bus和net.line的 DataFrame 看索引和参数是否和预期一致。另一个容易忽略的地方是 net.load 的 scaling 列,这个列默认是 1.0,如果你之前批量改过,可能会造成实际负载和填的 p_mw 不一致。
4. 潮流计算 runpp 的参数调优与不收敛处理
4.1 算法选型:NR、IW、FDBX 的适用边界
runpp默认使用全牛顿-拉夫逊算法(NR),这是最通用、收敛性最好的选择。但对于某些病态网络,NR 可能迭代多次仍然不收敛,这时可以切换到其他算法。pandapower 提供的算法主要有:
- NR(Newton-Raphson):默认,精度高,适用于大多数电网
- IW(Implicit Z-bus Gauss):对配电网络收敛较慢,但对恒功率负载较多的低压网络可能更稳
- FDBX(Fast Decoupled):速度最快,适合辐射状网络,但对重负载线路精度稍差
实际使用中,我会先跑一次 NR,不收敛时再看结果调整。选算法不是一个“哪个更好用”的问题,而是要匹配你的网络结构。下面的代码展示了如何在 runpp 时切换算法,并开启详细输出:
# 默认算法 pp.runpp(net, algorithm="nr", tol_v=1e-6, tol_i=1e-6, max_iteration=20) # 切换到 IW pp.runpp(net, algorithm="iw", tol_v=1e-6, max_iteration=50) # 切换到 FDBX pp.runpp(net, algorithm="fdbx", tol_v=1e-6, max_iteration=30)tol_v是电压收敛容差,tol_i是电流收敛容差,max_iteration是最大迭代次数。容差设置得太严(如 1e-9)会导致不必要的迭代次数增加,设置得太松(如 1e-3)则结果误差偏大。我一般取 1e-6 作为初始设置,跑不收敛时再放宽到 1e-5。max_iteration也不是越大越好,NR 超过 20 次还不收敛基本说明网络有问题。
4.2 容差、分布式负载、电压限制怎么设置
runpp还有几个不太起眼但实际很常用的参数。distributed_slack在微网或孤岛电网中特别重要,默认 False 表示只有参考节点承担不平衡功率,设置为 True 后,所有带 gen 的母线都会按比例分摊功率缺额。init参数控制初值选择,支持 "auto"、 "flat" 和 "dc" 三种,默认 "auto" 会先用直流潮流做初始化,交流潮流迭代次数会减少。trafo_model控制变压器模型,t 是 T 型等效电路,pi 是 π 型等效电路,后者在配电网仿真中更常见。
pp.runpp( net, algorithm="nr", tol_v=1e-6, tol_i=1e-6, max_iteration=20, distributed_slack=True, init="dc", trafo_model="t", trafo_loading="current", enforce_v_decimal=True, )enforce_v_decimal会强制把电压运行点作为离散变量处理,适合做电压调节器仿真。trafo_loading控制变压器负载率按电流还是按功率计算,配电网里建议用 "current",因为低压侧功率因数和电压偏差会影响视在功率,而电流负载率更能反映真实热稳定裕度。
4.3 不收敛第一动作:别急着调参数,先查网络
遇到loadflow not converged报错时,我的排查顺序是固定的:
第一步看 bus 索引是否连续。用net.bus.index和net.line[["from_bus","to_bus"]]做差集,找出引用了不存在的 bus 编号的设备。
第二步看孤岛。使用pp.topology.simple_calc_graph(net)检查网络是否被分割成多个不相连的子图。如果 feeder 断开,潮流根本不可能收敛,因为公式矩阵奇异。
第三步检查负荷量级。把net.load[["bus","p_mw","q_mvar"]]按 bus 分组求和,和变压器容量对比。如果某个变压器满载超过 150%,大概率是潮流发散的原因。
load_group = net.load.groupby("bus")[["p_mw", "q_mvar"]].sum() print(load_group) trafo_sn = net.trafo["sn_mva"].sum() print("总负荷 vs 总变压器容量:", load_group["p_mw"].sum(), trafo_sn)如果以上都正常,再回到 runpp 的参数上来。把容差放宽到 1e-4,把 init 改成 "flat",把算法换成 IW,逐项排除因素。遇到配电网线路过长导致的低压问题,不要只靠调参数,要看电压结果。
5. 不止于潮流:优化、故障与批量仿真的扩展路径
5.1 最优潮流 runopp 的边界约束参数
在传统配电网分析中,潮流计算只是“已知负载求状态”。做规划或调度时,还需要求解“在满足电压和线路容量约束下,如何调整发电机出力让运行成本最小”,这就要用到最优潮流(OPF)。pandapower 的runopp提供了这个能力,但它依赖pandapower.opf模块,需要额外安装pandapower自带的 OPF 引擎,或者对接pypower。这里直接看代码:
import pandapower as pp from pandapower.control import ContinuousTapControl net = pp.create_empty_network() b0 = pp.create_bus(net, vn_kv=110.0) b1 = pp.create_bus(net, vn_kv=110.0) b2 = pp.create_bus(net, vn_kv=110.0) pp.create_ext_grid(net, bus=b0, vm_pu=1.0) pp.create_line(net, b0, b1, length_km=10.0, std_type="149-AL1/24-ST1A 110.0") pp.create_line(net, b1, b2, length_km=10.0, std_type="149-AL1/24-ST1A 110.0") # 在 b1 和 b2 上挂发电机,带成本 g1 = pp.create_gen(net, b1, p_mw=20.0, vm_pu=1.0, min_p_mw=0.0, max_p_mw=50.0) g2 = pp.create_gen(net, b2, p_mw=30.0, vm_pu=1.0, min_p_mw=0.0, max_p_mw=50.0) pp.create_poly_cost(net, g1, "gen", cp1_eur_per_mw2=0.02, cp0_eur=0.0) pp.create_poly_cost(net, g2, "gen", cp1_eur_per_mw2=0.05, cp0_eur=0.0) pp.create_load(net, b2, p_mw=40.0, q_mvar=5.0) pp.runopp(net, delta=1e-12) print(net.res_cost) print(net.res_gen[["p_mw", "q_mvar", "va_degree", "vm_pu"]])create_poly_cost指定发电机的成本函数,cp1_eur_per_mw2是二次项系数,cp0_eur是固定成本。runopp会求解一个以总发电成本最小为目标、满足潮流方程和电压/线路容量约束的最优问题。结果res_gen里的 p_mw 不是初始值,而是优化后的出力。如果两处发电机成本不同,优化结果一定是让成本低的发电机多出力。
5.2 批量场景:参数扫描与 pandas 联动
实际工作中经常要做参数扫描:比如负荷从 50% 涨到 150%,看电压如何变化。pandapower 的数据模型决定了这种扫描写起来很舒服,不需要反复建模型,改一个列就行。
import pandas as pd load_p = [0.5, 0.75, 1.0, 1.25, 1.5] rows = [] for i, scale in enumerate(load_p): # 重新设置 load scaling 列 net.load["scaling"] = scale pp.runpp(net) min_vm_pu = net.res_bus["vm_pu"].min() max_loading = pd.concat( [net.res_line["loading_percent"], net.res_trafo["loading_percent"]] ).max() rows.append({"case": i, "scaling": scale, "min_vm_pu": round(min_vm_pu, 4), "max_loading_percent": round(max_loading, 2)}) df_result = pd.DataFrame(rows) print(df_result)这个循环里,每次只修改net.load["scaling"]的值,不用重新建网。每轮跑完runpp后,把最小电压和最大负载率记下来。这样一张表就能看出哪个负荷水平下电压越限或线路过载。跑完后用 matplotlib 画一条电压随负荷变化的曲线,能直接贴进报告。pandapower.plotting也内置了类似 simple_plot 的功能,可以直接显示网络拓扑和结果。
5.3 提取结果:res_bus 和 res_line 里的关键列
结果数据都在res_*前缀的表里,但不同版本对某些列名做了调整,建议先把表格的列检查一遍再使用:
print(net.res_bus.columns.tolist()) print(net.res_line.columns.tolist()) print(net.res_trafo.columns.tolist())输出结果里最常用的列有:
| DataFrame | 关键列 | 含义 |
|---|---|---|
| res_bus | vm_pu, va_degree | 电压幅值标幺值、相角(度) |
| res_line | loading_percent, i_ka | 线路负载率、电流(kA) |
| res_trafo | loading_percent, vm_hv_pu, vm_lv_pu | 变压器负载率、高压侧/低压侧电压标幺值 |
| res_load | p_mw, q_mvar | 实际有功、无功消耗(scaling 已生效) |
res_load显示的 p_mw 是考虑了 scaling 之后的值,不是原始填表值。如果你填了 scaling=1.2,结果表里会显示放大的功率。反过来说,验证网络建模是否正确时,也应该用 res_load 而不是 net.load。这也解释了为什么很多人在对比结果时发现对不上账,因为他们拿原始负荷值跟结果表比,忘了 scaling 这个变量。
6. 验证结果不靠感觉:三条实用技巧
第一,检查有功功率平衡。电网运行必须满足供给等于需求加上网损。手动计算:所有 gen 出力之和减去所有 load 消耗之和,结果应该等于全网的电阻损耗。电阻损耗可以从 net.res_line 的 pl_mw 列加总得到。如果一个带负荷的台区供电的所有线路损耗接近 0 或者负数,说明网络模型有问题,多半是线型选错导致 r_ohm_per_km 为 0。
total_p_gen = net.res_gen["p_mw"].sum() + net.res_ext_grid["p_mw"].sum() total_p_load = net.res_load["p_mw"].sum() + net.res_sgen["p_mw"].sum() total_pl_loss = net.res_line["pl_mw"].sum() + net.res_trafo["pl_mw"].sum() print("发电机总出力:", total_p_gen) print("负荷总消耗:", total_p_load) print("网损:", total_pl_loss) print("差值:", total_p_gen - total_p_load - total_pl_loss)这个差值应该在 1e-6 量级,如果差太多就回头查设备参数,不要继续做下一步。
第二,孤立节点检测。上面用的pp.topology.simple_calc_graph可以检查拓扑连通性。在较大网络中,一个不显眼的 bus 索引错误可以导致潮流结果偏离实际。把孤立节点找出来比肉眼盯 index 高效得多:
import pandapower.topology as top even = top.calc_connected_components(net, bus_pq="bus") print("组件数量:", len(even))如果组件数量大于 1,说明有孤岛。配电网规划中除非是刻意设计的孤岛微网,否则必须把每个 island 都通过变压器或线路连接起来,否则潮流计算结果的物理意义就不成立。
第三,把结果导出到 excel 形成审计痕迹。在工程场景里,结果不只要“算得对”,还要“说得清”。pandapower 可以直接把结果写成 DataFrame,再交给 pandas 导出:
with pd.ExcelWriter("powerflow_result.xlsx") as writer: net.res_bus.to_excel(writer, sheet_name="bus") net.res_line.to_excel(writer, sheet_name="line") net.res_trafo.to_excel(writer, sheet_name="trafo") net.res_load.to_excel(writer, sheet_name="load")导出后的文件可以直接拿去和同事核对,也能和旧版结果做 diff。如果你的计算场景需要频繁做这类对比,还可以直接保存整个 net 对象:
pp.to_json(net, "net_result.json")把 net 保存成 json 的好处是,下次打开就能看到当时的模型和结果,不必重新搭一次网络。这也特别适合在 Jupyter 里做研究时保留中间过程。
本文还有配套的精品资源,点击获取