配电网电压预测 GNN 模型优化
原创声明 :本文为作者原创技术文章,首发于 CSDN 个人博客,遵循 CC BY-NC-SA 4.0 协议,转载请注明作者与原文链接。
摘要 :高比例分布式光伏接入后,配电网电压呈现双向波动,传统潮流计算精度高但需要完整参数与量测,难以支撑毫秒级的在线评估。图神经网络因其对拓扑结构的表达能力被视为电压预测的可行路径,但工程中常出现"用了图卷积却没有精度提升"的现象。本文不泛泛讨论网络深度,而是把问题收敛到图算子与物理机理是否对齐 这一根因上:先由 DistFlow 支路方程推出一阶线性化电压关系,指出辐射状配电网的电压---注入关系本质上是"沿根到节点路径的阻抗加权累积",而非邻域平均;随后给出物理对齐的方向性聚合算子,并将它与通用对称归一化图卷积在同一算例上对比。在 IEEE 33 节点系统上,用本机脚本离线生成 1440 个运行场景(46080 个节点样本)开展时序切分实验:局部特征基线 R2R^2R2 仅 0.0069,对称归一化图卷积(K=3K=3K=3)为 0.0282,而物理对齐算子达到 0.9997,测试集 RMSE 由 0.0234 p.u. 降至 0.0004 p.u.,下降约 98.2%。结果表明:在电压预测任务中起决定作用的是消息传递算子是否承载物理先验,而非是否使用了图结构。
关键词:配电网电压预测;图神经网络;物理知情图神经网络;DistFlow 线性化;消息传递算子;对称归一化;岭回归;IEEE 33 节点系统
1 背景与问题定义
1.1 电压预测为什么成为刚需
配电网长期以"单向潮流、被动受电"为基本假设设计,变电站母线电压是唯一可调手段。随着屋顶光伏、分布式储能在 10 kV 与 0.4 kV 侧规模化接入,同一馈线在午间可能出现功率倒送、节点电压抬升,在傍晚光伏退出后又迅速跌落。电压的时空分布不再由调度员的经验决定,而是由几十到上百个并网点的注入功率共同决定。
电压越限的治理前提是"看得见"。完整量测需要为每个节点配置量测装置与通信通道,在存量配电网中并不现实;而调用一次完整潮流计算虽然精度足够,却要求全网负荷、光伏出力与开关状态同步已知,单次求解耗时也随节点规模上升。工程上真正需要的是一个快速映射:给定可观测的节点注入(或部分节点的注入估计值),在毫秒级内给出全部节点的电压幅值估计,用于越限预警、无功/储能预调度以及开关操作前的预校核。
1.2 为什么选图神经网络
配电网是天然的图:母线是节点,线路是边,节点之间存在明确的电气耦合。与把节点功率排成一维向量送进全连接网络相比,图神经网络有三个结构性优势。第一是置换等变 ,节点编号重排不改变结论,这符合物理事实;第二是参数与拓扑解耦 ,一套局部聚合规则可以跨不同馈线复用;第三是感受野随层数扩展,信息沿线路逐跳传播,与电压降沿路径累积的物理过程方向一致。
这些优势是定性的。真正决定精度的是聚合算子如何设计,而这恰恰是实践中最容易被忽略的部分:多数实现直接沿用图卷积网络(GCN)的对称归一化邻接矩阵,把邻居信息做加权平均。对"社区划分""节点分类"这类任务,邻域平均是合理的归纳偏置;但对电压预测,物理关系是累积 而不是平均,方向性(从根节点指向末端)也是本质的。算子与机理错位,层数再深也无法补偿。
1.3 本文要回答的问题
本文将围绕一个可验证的问题展开:在辐射状配电网电压预测任务上,通用对称归一化图卷积与物理对齐的方向性聚合算子的精度差距有多大,差距从何而来?
为避免结论停留在定性层面,本文构建了一个完全可复现的最小实验:IEEE 33 节点标准算例 + 前推回代潮流 + 四种模型对照。所有数值均由本文附带的脚本在本机运行产生,脚本不依赖任何外部数据集,也不依赖 PyTorch 等深度学习框架,读者可用一条命令复现全部结果。
2 理论基础与数学建模
2.1 配电网络的图表示
把辐射状配电网表示为无向图 G=(V,E)G=(V,E)G=(V,E),其中 V={1,2,...,N}V=\{1,2,\dots,N\}V={1,2,...,N} 为节点集合(N=33N=33N=33),EEE 为支路集合。节点 1 为变电站母线,是潮流计算的松弛节点,其电压幅值恒定。记邻接矩阵为 A∈RN×NA\in\mathbb{R}^{N\times N}A∈RN×N,度矩阵 D=diag(d1,...,dN)D=\mathrm{diag}(d_1,\dots,d_N)D=diag(d1,...,dN),加入自环后 A~=A+I\tilde{A}=A+IA~=A+I,D~\tilde{D}D~ 为 A~\tilde{A}A~ 的度矩阵,则对称归一化邻接矩阵为
A^=D~−1/2A~D~−1/2,A^ij=A~ijd~id~j(1)\hat{A}=\tilde{D}^{-1/2}\tilde{A}\tilde{D}^{-1/2},\qquad \hat{A}{ij}=\frac{\tilde{A}{ij}}{\sqrt{\tilde{d}_i\tilde{d}_j}} \qquad (1)A^=D~−1/2A~D~−1/2,A^ij=d~id~j A~ij(1)
每个节点的输入特征取该节点的净注入功率,即负荷减去分布式电源出力,构成功率矩阵 X∈RN×2X\in\mathbb{R}^{N\times 2}X∈RN×2,两列分别为有功 PPP 与无功 QQQ(标幺值)。预测目标为全部节点的电压幅值向量 V∈RNV\in\mathbb{R}^{N}V∈RN。注意:电压幅值是无量纲的标幺值,其数值受线路参数与注入功率同时决定。
2.2 从支路方程到一阶线性化
辐射状配电网的稳态关系由 DistFlow 支路方程描述。对支路 kkk(首端 u(k)u(k)u(k)、末端 v(k)v(k)v(k),电阻 rkr_krk、电抗 xkx_kxk),记 Pk,QkP_k,Q_kPk,Qk 为从首端流入支路的有功与无功,ℓk=∣Ik∣2\ell_k=|I_k|^2ℓk=∣Ik∣2 为电流幅值平方,v=∣V∣2v=|V|^2v=∣V∣2 为电压幅值平方,C(k)\mathcal{C}(k)C(k) 为以 v(k)v(k)v(k) 为起点的下游支路集合,PL,v,QL,vP_{\mathrm{L},v},Q_{\mathrm{L},v}PL,v,QL,v 为节点 vvv 的负荷,则有
{Pk−rkℓk−∑m∈C(k)Pm=PL,v(k)Qk−xkℓk−∑m∈C(k)Qm=QL,v(k)vv(k)=vu(k)−2(rkPk+xkQk)+(rk2+xk2)ℓkℓk=(Pk2+Qk2)/vu(k)(2)\begin{cases} P_k-r_k\ell_k-\displaystyle\sum_{m\in\mathcal{C}(k)}P_m=P_{\mathrm{L},v(k)}\\4pt Q_k-x_k\ell_k-\displaystyle\sum_{m\in\mathcal{C}(k)}Q_m=Q_{\mathrm{L},v(k)}\\4pt v_{v(k)}=v_{u(k)}-2\left(r_kP_k+x_kQ_k\right)+\left(r_k^2+x_k^2\right)\ell_k\\4pt \ell_k=\left(P_k^2+Q_k^2\right)/v_{u(k)} \end{cases} \qquad (2)⎩ ⎨ ⎧Pk−rkℓk−m∈C(k)∑Pm=PL,v(k)Qk−xkℓk−m∈C(k)∑Qm=QL,v(k)vv(k)=vu(k)−2(rkPk+xkQk)+(rk2+xk2)ℓkℓk=(Pk2+Qk2)/vu(k)(2)
式(2) 的第一、二式是节点功率平衡,第三式是电压降落关系,第四式是电流定义。式中所有功率与阻抗均为标幺值,基值取 SB=10 MVAS_B=10\ \mathrm{MVA}SB=10 MVA、VB=12.66 kVV_B=12.66\ \mathrm{kV}VB=12.66 kV。
在配电网电压水平接近额定值、线损远小于传输功率的条件下,可令 ℓk→0\ell_k\to 0ℓk→0,得到线性化 DistFlow 模型,此时支路功率退化为其下游节点注入之和:
vv(k)=vu(k)−2(rkPk+xkQk),Pk=∑j∈D(v(k))Pj,Qk=∑j∈D(v(k))Qj(3)v_{v(k)}=v_{u(k)}-2\left(r_kP_k+x_kQ_k\right),\qquad P_k=\sum_{j\in\mathcal{D}(v(k))}P_j,\quad Q_k=\sum_{j\in\mathcal{D}(v(k))}Q_j \qquad (3)vv(k)=vu(k)−2(rkPk+xkQk),Pk=j∈D(v(k))∑Pj,Qk=j∈D(v(k))∑Qj(3)
其中 D(v)\mathcal{D}(v)D(v) 表示以节点 vvv 为根的子树节点集合(包含 vvv 自身)。
以 P(i)\mathcal{P}(i)P(i) 记根节点到节点 iii 所经过的支路集合。把式(3) 沿路径累加并把根节点电压归一化为 v0=1v_0=1v0=1(标幺),得 vi=1−2∑k∈P(i)(rkPk+xkQk)v_i=1-2\sum_{k\in\mathcal{P}(i)}(r_kP_k+x_kQ_k)vi=1−2∑k∈P(i)(rkPk+xkQk)。再利用 Vi=viV_i=\sqrt{v_i}Vi=vi 在 111 附近的一阶展开 1−2δ≈1−δ+O(δ2)\sqrt{1-2\delta}\approx 1-\delta+O(\delta^2)1−2δ ≈1−δ+O(δ2),即得本文的核心关系式
Vi≈1−∑k∈P(i)(rkPk+xkQk)=1−∑j=1N(RijpathPj+XijpathQj)(4)V_i\approx 1-\sum_{k\in\mathcal{P}(i)}\left(r_kP_k+x_kQ_k\right)=1-\sum_{j=1}^{N}\left(R^{\mathrm{path}}{ij}P_j+X^{\mathrm{path}}{ij}Q_j\right) \qquad (4)Vi≈1−k∈P(i)∑(rkPk+xkQk)=1−j=1∑N(RijpathPj+XijpathQj)(4)
其中共享路径阻抗定义为
Rijpath=∑k∈P(i)∩P(j)rk,Xijpath=∑k∈P(i)∩P(j)xk(5)R^{\mathrm{path}}{ij}=\sum{k\in\mathcal{P}(i)\cap\mathcal{P}(j)}r_k,\qquad X^{\mathrm{path}}{ij}=\sum{k\in\mathcal{P}(i)\cap\mathcal{P}(j)}x_k \qquad (5)Rijpath=k∈P(i)∩P(j)∑rk,Xijpath=k∈P(i)∩P(j)∑xk(5)
式(5) 的物理含义值得强调。RijpathR^{\mathrm{path}}{ij}Rijpath 是节点 iii 与 jjj 到根节点的公共路径上的电阻之和。当 jjj 位于 iii 的下游时,Rijpath=∑k∈P(i)rkR^{\mathrm{path}}{ij}=\sum_{k\in\mathcal{P}(i)}r_kRijpath=∑k∈P(i)rk,表示"节点 jjj 的负荷在 iii 根侧全部支路上都会产生电压降";当 jjj 位于 iii 的上游时,Rijpath=∑k∈P(j)rkR^{\mathrm{path}}{ij}=\sum{k\in\mathcal{P}(j)}r_kRijpath=∑k∈P(j)rk,表示"节点 jjj 的负荷在自己下游方向的压降已经体现在 VjV_jVj 上,而 ViV_iVi 又叠加了 jjj 到根方向的压降"。两个情形的系数都只取决于拓扑与线路参数,与运行状态无关,这正是可以把它们预先固化为算子的原因。
2.3 图消息传递的一般形式
主流图卷积把第 lll 层的节点表示写成
H(l+1)=σ(A^H(l)W(l))(6)H^{(l+1)}=\sigma\left(\hat{A}H^{(l)}W^{(l)}\right) \qquad (6)H(l+1)=σ(A^H(l)W(l))(6)
W(l)W^{(l)}W(l) 为可学习权重,σ(⋅)\sigma(\cdot)σ(⋅) 为激活函数。若进一步去掉非线性并把各层权重折叠为单一线性映射,即得到简化图卷积(SGC)的闭式形式
Y^=softmax(A^KXΘ),A^K 为 A^ 的 K 次幂(7)\hat{Y}=\mathrm{softmax}\left(\hat{A}^{K}X\Theta\right),\qquad \hat{A}^{K}\text{ 为 } \hat{A}\text{ 的 }K\text{ 次幂} \qquad (7)Y^=softmax(A^KXΘ),A^K 为 A^ 的 K 次幂(7)
式(7) 揭示了对称归一化算子的本质:它等价于一个固定低通滤波器,A^KX\hat{A}^{K}XA^KX 的第 iii 行是节点 iii 的 KKK 跳邻域注入的加权平均 。平均操作会抹平幅值累积,而式(4)(5) 要求的是沿路径的加权求和 ,两者在代数结构上并不一致。此外,偏离根节点越远的节点,其电压所受影响的注入分布越分散;在 N=33N=33N=33 的算例中,末端节点(18 号)距根节点 17 跳,KKK 阶稀疏传播很难在有限阶数内覆盖完整的路径。
2.4 物理对齐的方向性聚合算子
既然式(4)(5) 已经把电压写成注入的线性函数,且系数只依赖拓扑与阻抗,那么最自然的做法是把这两个通道直接实现为消息传递算子。定义
αi=∑j=1NRijpathPj,βi=∑j=1NXijpathQj(8)\alpha_i=\sum_{j=1}^{N}R^{\mathrm{path}}{ij}P_j,\qquad \beta_i=\sum{j=1}^{N}X^{\mathrm{path}}_{ij}Q_j \qquad (8)αi=j=1∑NRijpathPj,βi=j=1∑NXijpathQj(8)
则式(4) 等价于 Vi≈1−αi−βiV_i\approx 1-\alpha_i-\beta_iVi≈1−αi−βi。把 αi,βi\alpha_i,\beta_iαi,βi 作为节点 iii 的聚合特征,再接一个线性读出层,参数的维度只有两个:
V^i=cααi+cββi+b(9)\hat{V}i=c\alpha\alpha_i+c_\beta\beta_i+b \qquad (9)V^i=cααi+cββi+b(9)
当 (cα,cβ,b)=(−1,−1,1)(c_\alpha,c_\beta,b)=(-1,-1,1)(cα,cβ,b)=(−1,−1,1) 时,式(9) 退化为纯物理的一阶线性化估计;允许 cα,cβc_\alpha,c_\betacα,cβ 自由学习,则模型可以吸收线性化过程中被丢弃的二阶项(损耗项与展开余项),这正是数据驱动部分应当承担的职责。本文沿用本项目统一口径,把这种"把物理机理嵌入图神经网络的消息传递与损失函数、使网络结构与物理关系一致"的范式表述为 PINN,即物理知情图神经网络(Physics-Informed Graph Neural Network)。
从算子复杂度看,α=RpathP\alpha=R^{\mathrm{path}}Pα=RpathP、β=XpathQ\beta=X^{\mathrm{path}}Qβ=XpathQ 是两次稠密矩阵乘法。矩阵 RpathR^{\mathrm{path}}Rpath 只需在建图阶段计算一次(对 N=33N=33N=33 仅 33×3333\times 3333×33),推理阶段单场景的计算量为 O(N2)O(N^2)O(N2),在 NNN 为数百量级的配电网中仍可接受;若追求更大规模,可利用 RpathR^{\mathrm{path}}Rpath 的路径结构做稀疏分解。
2.5 参数求解
用带 L2L_2L2 正则的最小二乘求解式(9) 的系数:
mincα,cβ,b ∑n=1M(V(n)−(cαα(n)+cββ(n)+b))2+λ(cα2+cβ2)(10)\min_{c_\alpha,c_\beta,b}\ \sum_{n=1}^{M}\left(V^{(n)}-\left(c_\alpha\alpha^{(n)}+c_\beta\beta^{(n)}+b\right)\right)^2+\lambda\left(c_\alpha^2+c_\beta^2\right) \qquad (10)cα,cβ,bmin n=1∑M(V(n)−(cαα(n)+cββ(n)+b))2+λ(cα2+cβ2)(10)
令 Z=α,β,1∈RM×3Z=\\alpha,\\beta,\\mathbf{1}\in\mathbb{R}^{M\times 3}Z=α,β,1∈RM×3,I~=diag(1,1,0)\tilde{I}=\mathrm{diag}(1,1,0)I~=diag(1,1,0),闭式解为
cαcβb=(Z⊤Z+λI~)−1Z⊤y(11)\begin{bmatrix}c_\alpha\\c_\beta\\b\end{bmatrix}=\left(Z^\top Z+\lambda\tilde{I}\right)^{-1}Z^\top y \qquad (11) cαcβb =(Z⊤Z+λI~)−1Z⊤y(11)
I~\tilde{I}I~ 对角元设为 (1,1,0)(1,1,0)(1,1,0) 表示只对两个斜率施加正则、不惩罚截距。实际计算前对特征做标准化(零均值、单位方差)可显著改善条件数,代码中在标准化空间求解后再还原为原始量纲系数。
模型精度用决定系数与均方根误差衡量:
R2=1−∑m=1M(Vm−V^m)2∑m=1M(Vm−Vˉ)2,RMSE=1M∑m=1M(Vm−V^m)2(12)R^2=1-\frac{\sum_{m=1}^{M}\left(V_m-\hat{V}m\right)^2}{\sum{m=1}^{M}\left(V_m-\bar{V}\right)^2},\qquad \mathrm{RMSE}=\sqrt{\frac{1}{M}\sum_{m=1}^{M}\left(V_m-\hat{V}_m\right)^2} \qquad (12)R2=1−∑m=1M(Vm−Vˉ)2∑m=1M(Vm−V^m)2,RMSE=M1m=1∑M(Vm−V^m)2 (12)
3 模型/算法设计与结构图
3.1 总体结构
本文的完整流程如图 1 所示:左侧蓝色链路完成网络建模与场景生成,中部并行给出两条特征提取支路------灰色支路是通用的对称归一化图卷积(对比支路),橙色支路是物理对齐的方向性聚合;两条支路汇入同一个线性读出层,最后与真实潮流结果对比评估。

图 1 配电网电压预测的物理知情图神经网络总体结构
注意图中由数据集指向两条算子支路的虚线:两条支路使用完全相同的输入与相同的读出层,唯一差别是聚合算子。这样设计是为了让"算子是否与物理机理对齐"成为实验中的唯一变量,避免把精度差异归因于模型容量或训练策略。
3.2 四种对照模型
为定位精度来源,本文设置四组对照,全部使用同一份数据、同一套时序切分与同一种读出方式:
| 模型 | 特征构造 | 是否使用图结构 | 是否含物理先验 |
|---|---|---|---|
| A 局部特征 | 节点自身净注入 Pi,QiP_i,Q_iPi,Qi | 否 | 否 |
| B 对称归一化图卷积 | A^kX, k=0,...,K\hat{A}^{k}X,\ k=0,\dots,KA^kX, k=0,...,K 拼接 | 是(对称归一化) | 否 |
| C 物理对齐算子 | αi,βi\\alpha_i,\\beta_iαi,βi,系数可学习 | 是(方向性加权) | 是(结构化嵌入) |
| D 一阶线性化物理先验 | 1−αi−βi1-\alpha_i-\beta_i1−αi−βi,系数固定为 (−1,−1,1)(-1,-1,1)(−1,−1,1) | 是(固定系数) | 是(纯解析) |
模型 A 与 B 的差别回答了"加图结构有没有用",B 与 C 的差别回答了"算子对齐有没有用",C 与 D 的差别回答了"在物理先验之上学习系数还有没有增量"。
3.3 关键设计说明
关于对称归一化为何不是一个好选择。 对称归一化把每条边的权重写成 1/d~id~j1/\sqrt{\tilde{d}_i\tilde{d}_j}1/d~id~j ,其设计初衷是抑制度数大的节点在聚合时占优、避免表示幅值爆炸。但在电压预测中,节点电压对注入的敏感度本身就随电气距离单调变化 :末端节点的电压受根侧全部支路上流过的功率影响,汇聚了整条路径的信息。归一化恰好把这种单调的累积关系压平,使 A^KX\hat{A}^{K}XA^KX 无法重建路径加权和。
关于感受野。 在 IEEE 33 节点算例中根节点到末端(18 号)为 17 跳,模型 B 的 KKK 阶传播只能覆盖 KKK 跳邻域。虽然 KKK 增大时信息逐步向全网扩散,但每一跳都在做平均而不是累积,误差并不会随 KKK 增大而单调收敛到零,这一点在 5.3 节的实测曲线上得到验证。
关于物理先验的表达形式。 本文没有把物理约束写成损失函数的惩罚项,而是把解析关系直接编码为算子结构。在电压预测这类"输入到输出几乎线性、参数已知"的任务上,结构嵌入比软约束更有效:软约束需要训练过程去逼近一个本来就已知的线性关系,既增加调参负担,也无法保证收敛到正确的系数尺度。
4 代码实现
以下代码为完整可运行脚本,仅依赖 NumPy。运行命令为 python 09_main.py,运行前请在脚本所在目录准备可写权限,脚本会把指标写入同目录的 09_metrics.json。
python
# -*- coding: utf-8 -*-
"""
配电网电压预测的 GNN 模型优化 ------ 可运行最小复现(图算子与物理机理对齐)
依赖:仅 numpy(本机 2.5.3)。数据由本脚本用前推回代潮流离线生成,不依赖任何外部数据集。
网络参数取自 IEEE 33 节点标准算例(Baran & Wu, 1989)。
运行:python 09_main.py
"""
import json
import os
import numpy as np
np.random.seed(20261001)
N = 33 # 节点数
S_BASE = 10.0e6 # 功率基准 10 MVA
V_BASE = 12.66e3 # 电压基准(线电压)12.66 kV
Z_BASE = V_BASE ** 2 / S_BASE
# ---------- 1. 网络参数:支路 (首端, 末端, R/欧姆, X/欧姆) ----------
BRANCH = [
(1, 2, 0.0922, 0.0470), (2, 3, 0.4930, 0.2511), (3, 4, 0.3660, 0.1864),
(4, 5, 0.3811, 0.1941), (5, 6, 0.8190, 0.7070), (6, 7, 0.1872, 0.6188),
(7, 8, 0.7114, 0.2351), (8, 9, 1.0300, 0.7400), (9, 10, 1.0440, 0.7400),
(10, 11, 0.1966, 0.0650), (11, 12, 0.3744, 0.1238), (12, 13, 1.4680, 1.1550),
(13, 14, 0.5416, 0.7129), (14, 15, 0.5910, 0.5260), (15, 16, 0.7463, 0.5450),
(16, 17, 1.2890, 1.7210), (17, 18, 0.7320, 0.5740), (2, 19, 0.1640, 0.1565),
(19, 20, 1.5042, 1.3554), (20, 21, 0.4095, 0.4784), (21, 22, 0.7089, 0.9373),
(3, 23, 0.4512, 0.3083), (23, 24, 0.8980, 0.7091), (24, 25, 0.8960, 0.7011),
(6, 26, 0.2030, 0.1034), (26, 27, 0.2842, 0.1447), (27, 28, 1.0590, 0.9337),
(28, 29, 0.8042, 0.7006), (29, 30, 0.5075, 0.2585), (30, 31, 0.9744, 0.9630),
(31, 32, 0.3105, 0.3619), (32, 33, 0.3410, 0.5302),
]
# 节点负荷 (节点, P/kW, Q/kvar),节点 1 为变电站母线
LOAD = {
2: (100, 60), 3: (90, 40), 4: (120, 80), 5: (60, 30), 6: (60, 20),
7: (200, 100), 8: (200, 100), 9: (60, 20), 10: (60, 20), 11: (45, 30),
12: (60, 35), 13: (60, 35), 14: (120, 80), 15: (60, 10), 16: (60, 20),
17: (60, 20), 18: (90, 40), 19: (90, 40), 20: (90, 40), 21: (90, 40),
22: (90, 40), 23: (90, 50), 24: (420, 200), 25: (420, 200), 26: (60, 25),
27: (60, 25), 28: (60, 20), 29: (120, 70), 30: (200, 600), 31: (150, 70),
32: (210, 100), 33: (60, 40),
}
P_PU = np.array([0.0, 0.0] + [LOAD[i][0] / 1e4 for i in range(2, 34)]) # kW -> p.u.
Q_PU = np.array([0.0, 0.0] + [LOAD[i][1] / 1e4 for i in range(2, 34)])
# ---------- 2. 建树:邻接矩阵、BFS 顺序、子树集合、节点深度 ----------
NB = len(BRANCH)
frm = np.array([b[0] for b in BRANCH])
to = np.array([b[1] for b in BRANCH])
Z = np.array([(b[2] + 1j * b[3]) / Z_BASE for b in BRANCH])
A = np.zeros((N + 1, N + 1))
for b in BRANCH:
A[b[0], b[1]] = A[b[1], b[0]] = 1.0
children = [[] for _ in range(N + 1)]
for k in range(NB):
children[frm[k]].append(k)
order, depth, queue = [], np.zeros(N + 1, dtype=int), [1]
while queue:
u = queue.pop(0)
for k in children[u]:
order.append(k)
depth[to[k]] = depth[u] + 1
queue.append(to[k])
order = np.array(order)
subtree = [set() for _ in range(NB)] # 每条支路的末端子树节点集合
for k in range(NB):
st, stack = set(), [to[k]]
while stack:
u = stack.pop()
st.add(u)
stack.extend(to[c] for c in children[u])
subtree[k] = st
path_branch = [[] for _ in range(N + 1)] # 根节点到各节点的支路集合
for i in range(2, N + 1):
path_branch[i] = [k for k in order if i in subtree[k]]
def sweep_pf(p_load, q_load, p_pv=None):
"""前推回代潮流:返回节点电压幅值(p.u.)与支路电流。"""
p_net = p_load.copy() - (0.0 if p_pv is None else p_pv)
p_net[1] = q_load[1] = 0.0
S = (p_net + 1j * q_load).astype(complex)
V = np.ones(N + 1, dtype=complex)
J = np.zeros(NB, dtype=complex)
for _ in range(200):
I = np.conj(S / V)
I[1] = 0.0
for k in reversed(order): # 回代:自叶向根累加电流
acc = I[to[k]]
for c in children[to[k]]:
acc += J[c]
J[k] = acc
V_old = V.copy()
for k in order: # 前推:自根向叶求电压
V[to[k]] = V[frm[k]] - Z[k] * J[k]
if np.max(np.abs(V - V_old)) < 1e-12:
break
return np.abs(V), J
python
# ---------- 3. 潮流引擎自校验(对照 Baran & Wu 基准解) ----------
V0, J0 = sweep_pf(P_PU.copy(), Q_PU.copy())
loss_kw = float(np.sum(np.abs(J0) ** 2 * Z.real) * S_BASE / 1e3)
vmin, vmin_bus = float(V0[2:].min()), int(np.argmin(V0[2:]) + 2)
print("[自校验] 基准算例最低电压 V_min = %.4f p.u.(节点 %d)" % (vmin, vmin_bus))
print("[自校验] 基准算例总有功网损 = %.2f kW" % loss_kw)
print("[拓扑] 根节点到末端最远距离 = %d 跳(节点 %d)"
% (int(depth.max()), int(np.argmax(depth))))
# ---------- 4. 场景集:日负荷曲线 + 分布式光伏 ----------
hours = np.arange(24)
load_shape = 0.72 + 0.30 * np.exp(-((hours - 20) / 4.0) ** 2) \
+ 0.18 * np.exp(-((hours - 11) / 3.0) ** 2)
solar_shape = np.clip(np.sin(np.pi * (hours - 6.5) / 11.0), 0.0, None)
PV_CAP = {13: 0.08, 24: 0.10, 30: 0.06} # 分布式光伏装机容量,p.u.(基准 10 MVA)
scen = []
for d in range(60):
for h in range(24):
m = load_shape[h] * np.random.uniform(0.90, 1.10, size=N + 1)
p_l, q_l = P_PU * m, Q_PU * m * np.random.uniform(0.95, 1.05, size=N + 1)
p_v = np.zeros(N + 1)
for bus, cap in PV_CAP.items():
p_v[bus] = cap * solar_shape[h] * np.random.uniform(0.85, 1.15)
Vt, _ = sweep_pf(p_l, q_l, p_v)
scen.append((p_l - p_v, q_l, Vt[1:].copy()))
print("[数据] 场景数 = %d,单场景节点样本 = %d,样本总数 = %d"
% (len(scen), N - 1, len(scen) * (N - 1)))
# ---------- 5. 图算子:对称归一化邻接 与 物理对齐的方向性算子 ----------
A_hat = A + np.eye(N + 1)
D_inv_sqrt = np.diag(1.0 / np.sqrt(A_hat.sum(axis=1)))
A_norm = D_inv_sqrt @ A_hat @ D_inv_sqrt # 通用 GCN 的对称归一化算子
DOWN = np.zeros((N + 1, N + 1)) # 后代可达矩阵(含自身)
for k in range(NB):
for j in subtree[k]:
DOWN[to[k], j] = 1.0
for i in range(1, N + 1):
DOWN[i, i] = 1.0
R_PATH = np.zeros((N + 1, N + 1)) # 共享路径电阻/电抗加权矩阵
X_PATH = np.zeros((N + 1, N + 1))
for i in range(2, N + 1):
for k in path_branch[i]:
for j in subtree[k]:
R_PATH[i, j] += Z[k].real
X_PATH[i, j] += Z[k].imag
def physics_features(p_net, q_net):
"""物理对齐的方向性聚合:alpha, beta 与一阶线性化电压 V_lin。"""
alpha = R_PATH @ p_net # sum_{k in P(i)} r_k * P_flow,k
beta = X_PATH @ q_net
return alpha[2:], beta[2:], (1.0 - (alpha + beta))[2:]
def graph_features(p_net, q_net, K):
"""通用对称归一化图卷积的 K 阶传播特征。"""
X = np.stack([p_net[1:], q_net[1:]], axis=1)
out, cur = [X], X
for _ in range(K):
cur = A_norm[1:, 1:] @ cur
out.append(cur)
return np.hstack(out)[1:]
PHYS = [physics_features(p, q) for p, q, _ in scen]
Y_ALL = np.concatenate([v[1:] for _, _, v in scen])
n_sc, n_node = len(scen), N - 1
IS_TR = np.zeros(n_sc * n_node, dtype=bool)
IS_TR[:int(n_sc * 0.7) * n_node] = True
def ridge_fit(Xtr, ytr, lam=1e-6):
mu, sd = Xtr.mean(0), Xtr.std(0) + 1e-12
Xs = (Xtr - mu) / sd
ym = ytr.mean()
w = np.linalg.solve(Xs.T @ Xs + lam * np.eye(Xs.shape[1]), Xs.T @ (ytr - ym))
return mu, sd, w, ym
def ridge_pred(model, X):
mu, sd, w, ym = model
return ((X - mu) / sd) @ w + ym
def metrics(y, yhat):
res = y - yhat
return {"R2": float(1 - np.sum(res ** 2) / np.sum((y - y.mean()) ** 2)),
"RMSE_pu": float(np.sqrt(np.mean(res ** 2))),
"MAE_pu": float(np.mean(np.abs(res))),
"MAPE_pct": float(np.mean(np.abs(res / y)) * 100)}
# ---------- 6. 四类模型的时序切分对比(前 70% 场景训练,后 30% 测试) ----------
def run_model(name, X, fit_alpha=False):
m = ridge_fit(X[IS_TR], Y_ALL[IS_TR])
res = metrics(Y_ALL[~IS_TR], ridge_pred(m, X[~IS_TR]))
res["name"] = name
if fit_alpha: # 还原为原始量纲下的系数:V ~ c_a*alpha + c_b*beta + b
mu, sd, w, ym = m
c = w / sd
res["coef"] = [float(c[0]), float(c[1]), float(ym - float(np.dot(c, mu)))]
return res
X_A = np.vstack([graph_features(p, q, 0) for p, q, _ in scen])
X_B = np.vstack([graph_features(p, q, 3) for p, q, _ in scen])
X_C = np.vstack([np.stack([a, b], axis=1) for a, b, _ in PHYS])
X_D = np.concatenate([v for _, _, v in PHYS])[:, None]
results = [run_model("A 局部特征基线", X_A),
run_model("B 对称归一化图卷积(K=3)", X_B),
run_model("C 物理对齐方向性聚合", X_C, fit_alpha=True),
run_model("D 一阶线性化物理先验", X_D)]
k_sweep = []
for K in range(0, 9):
X = np.vstack([graph_features(p, q, K) for p, q, _ in scen])
k_sweep.append({"K": K, **{k: v for k, v in run_model("B", X).items()
if k in ("R2", "RMSE_pu")}})
print("\n[模型对比](测试集 %d 个节点样本,前 70%% 场景训练)" % int((~IS_TR).sum()))
print("%-28s %8s %11s %11s %10s" % ("模型", "R2", "RMSE/p.u.", "MAE/p.u.", "MAPE/%"))
for r in results:
print("%-28s %8.4f %11.4f %11.4f %10.4f"
% (r["name"], r["R2"], r["RMSE_pu"], r["MAE_pu"], r["MAPE_pct"]))
print("\n[C 模型学到的系数] alpha=%.4f beta=%.4f intercept=%.4f (理论值应为 1, 1, 1)"
% (results[2]["coef"][0], results[2]["coef"][1], results[2]["coef"][2]))
print("\n[通用图卷积的传播阶数敏感性]")
print(" K R2(对称归一化图卷积)")
for row in k_sweep:
print(" %d %.4f" % (row["K"], row["R2"]))
out = {
"vmin_base": vmin, "vmin_bus": vmin_bus, "loss_kw_base": loss_kw,
"max_depth": int(depth.max()), "n_scen": n_sc,
"n_train_scen": int(n_sc * 0.7), "n_test_scen": n_sc - int(n_sc * 0.7),
"n_test_samples": int((~IS_TR).sum()), "results": results, "k_sweep": k_sweep,
"v_profile_base": [float(v) for v in V0[1:]],
"v_profile_test_min": [float(v) for v in np.asarray(
[s[2] for s in scen[int(n_sc * 0.7):]]).min(axis=0)],
"v_profile_test_max": [float(v) for v in np.asarray(
[s[2] for s in scen[int(n_sc * 0.7):]]).max(axis=0)],
"scatter_true": [float(v) for v in Y_ALL[~IS_TR][:800]],
"scatter_pred": [float(v) for v in ridge_pred(
ridge_fit(X_C[IS_TR], Y_ALL[IS_TR]), X_C[~IS_TR])[:800]],
}
path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "09_metrics.json")
with open(path, "w", encoding="utf-8") as f:
json.dump(out, f, ensure_ascii=False, indent=1)
print("\n[输出] 指标已保存:%s" % path)
代码分为两段:第一段完成网络建模、前推回代潮流与基准算例自校验;第二段生成运行场景、构造式(5) 的两个路径矩阵与式(8) 的物理特征,并完成四类模型的时序切分标定与结果输出。其中 R_PATH、X_PATH 即式(5) 的离散实现,physics_features 对应式(8),ridge_fit/ridge_pred 对应式(11),metrics 对应式(12)。
需要说明的是,代码中的 DOWN 矩阵仅用于展示后代可达关系,实际算子构造只用到 path_branch 与 subtree,读者若移植到其他算例,只需替换 BRANCH 与 LOAD 两组参数。
5 实验与结果分析
5.1 算例与潮流引擎自校验
数据由脚本离线生成,不依赖任何外部数据集。在建立数据集之前,先用基准负荷运行一次潮流并与文献结果比对,确认引擎正确:
text
[自校验] 基准算例最低电压 V_min = 0.9131 p.u.(节点 18)
[自校验] 基准算例总有功网损 = 202.68 kW
[拓扑] 根节点到末端最远距离 = 17 跳(节点 18)
[数据] 场景数 = 1440,单场景节点样本 = 32,样本总数 = 46080
最低电压 0.9131 p.u.(节点 18)、总有功网损 202.68 kW 与 IEEE 33 节点系统的公开基准解一致(公开文献报告基准负荷下最低电压为 0.9131 p.u.、总线损为 202.67 kW,例如 https://www.ijsat.org/papers/2026/2/11201.pdf 与 https://www.iieta.org/journals/mmep/paper/10.18280/mmep.070316 ),说明前推回代实现与阻抗、负荷参数均正确。若引擎有误,后续所有精度结论都会失去意义,因此这一步不能省。
数据集设置如下:按 60 天 × 24 小时生成 1440 个运行场景,负荷按日负荷曲线缩放并叠加 ±10% 的节点级随机扰动,光伏出力按日照曲线缩放并叠加 ±15% 扰动,光伏装机容量分别取 0.08、0.10、0.06 p.u.(对应 0.8、1.0、0.6 MVA),接入节点为 13、24、30。每个场景求解一次潮流得到 32 个非根节点的真实电压,共 46080 个节点样本。训练集取时间上在前的 1007 个场景(占 69.9%),测试集取其后 433 个场景,共 13856 个测试样本。时序切分而非随机切分,可以避免同一场景的相邻节点样本分别落入训练集与测试集造成的信息泄漏。
5.2 四类模型的精度对比
以下为作者本机实际运行输出:
text
[模型对比](测试集 13856 个节点样本,前 70% 场景训练)
模型 R2 RMSE/p.u. MAE/p.u. MAPE/%
A 局部特征基线 0.0069 0.0234 0.0200 2.0805
B 对称归一化图卷积(K=3) 0.0282 0.0231 0.0198 2.0593
C 物理对齐方向性聚合 0.9997 0.0004 0.0003 0.0364
D 一阶线性化物理先验 0.9996 0.0004 0.0004 0.0393
[C 模型学到的系数] alpha=-1.0821 beta=-1.0505 intercept=1.0004 (理论值应为 1, 1, 1)
四个模型的差量关系清晰地指向同一个结论。模型 A 与模型 B 的 R2R^2R2 分别为 0.0069 与 0.0282,说明仅仅把数据搬上图结构并不解决问题 :对称归一化聚合相对局部特征只带来 0.02 量级的 R2R^2R2 增量,仍处于"几乎不可用"的水平。模型 C 相对模型 B 的 R2R^2R2 从 0.0282 跃升到 0.9997,RMSE 从 0.0231 p.u. 降到 0.0004 p.u.,相对模型 A 的 RMSE 从 0.0234 p.u. 降至 0.0004 p.u.,降幅约 98.2%(1−0.0004/0.02341-0.0004/0.02341−0.0004/0.0234,按四位小数计算)。两次对比使用的是同一份输入特征与同一个读出层,唯一差别是聚合算子的构造方式。
精确数值(脚本写入 09_metrics.json,此处取六位小数):模型 A R2=0.006889R^2=0.006889R2=0.006889、RMSE =2.3397×10−2=2.3397\times10^{-2}=2.3397×10−2 p.u.;模型 B R2=0.028188R^2=0.028188R2=0.028188、RMSE =2.3145×10−2=2.3145\times10^{-2}=2.3145×10−2 p.u.;模型 C R2=0.999673R^2=0.999673R2=0.999673、RMSE =4.2470×10−4=4.2470\times10^{-4}=4.2470×10−4 p.u.、MAE =3.4646×10−4=3.4646\times10^{-4}=3.4646×10−4 p.u.;模型 D R2=0.999641R^2=0.999641R2=0.999641、RMSE =4.4513×10−4=4.4513\times10^{-4}=4.4513×10−4 p.u.。模型 C 的 RMSE 比模型 D 低约 4.6%,MAE 低约 7.6%,即"在物理先验之上让系数可学习"带来的是百分点级的稳定增益,而不是量级变化------这与式(4) 只是电压的一阶近似这一事实相符。

图 2 图算子选择与模型精度:IEEE 33 节点电压预测实验
5.3 传播阶数敏感性:为什么"加深"救不了对称归一化算子
图 2(a) 给出对称归一化图卷积的测试集 RMSE 随传播阶数 KKK 的变化(对数纵轴),并叠加模型 C 与模型 D 的水平线。完整数据为:
text
[通用图卷积的传播阶数敏感性]
K R2(对称归一化图卷积)
0 0.0069
1 0.0195
2 0.0252
3 0.0282
4 0.0290
5 0.0294
6 0.0317
7 0.0362
8 0.0510
需要如实指出两点。第一,KKK 从 0 增加到 8 时 R2R^2R2 单调缓慢上升(0.0069 → 0.0510),在本文测试范围内没有观察到"加深导致精度下降"的过平滑现象 ;原因是本文的特征传播不含非线性激活、也未叠加多层权重,节点数仅 33、最远 17 跳,K≤8K\le 8K≤8 的感受野尚未覆盖全网。第二,即使取到 K=8K=8K=8,R2R^2R2 仍只有 0.0510,与模型 C 的 0.9997 相差近两个数量级。这说明问题不在于层数不够,而在于算子的代数形式:平均式聚合无法把"路径阻抗加权的累积"表达出来,增加阶数只是扩大平均的邻域范围。
5.4 学到的系数说明了什么
模型 C 在原始量纲下学到的系数为 cα=−1.0821c_\alpha=-1.0821cα=−1.0821、cβ=−1.0505c_\beta=-1.0505cβ=−1.0505、截距 b=1.0004b=1.0004b=1.0004。截距与理论值 1 几乎完全一致,说明式(4)(9) 的结构是正确;两个斜率的绝对值都略大于 1,方向与理论值一致。
这一现象与式(4) 的一阶截断误差量级相符。以末端节点 18 为例,其基准电压为 0.9131 p.u.,对应 δ=∑k∈P(i)(rkPk+xkQk)≈0.087\delta=\sum_{k\in\mathcal{P}(i)}(r_kP_k+x_kQ_k)\approx 0.087δ=∑k∈P(i)(rkPk+xkQk)≈0.087,而 1−2δ\sqrt{1-2\delta}1−2δ 的展开余项约为 δ2/2≈0.0038\delta^2/2\approx 0.0038δ2/2≈0.0038;系数由 1 增至约 1.08 相当于额外补偿 0.08×0.087≈0.0070.08\times 0.087\approx 0.0070.08×0.087≈0.007 的电压降,与余项处于同一量级(同一数量级、同号)。线性化还丢弃了式(2) 中的 ℓk\ell_kℓk 损耗项,其贡献也同向。因此可以认为:数据驱动部分的增益主要来自对一阶线性化余项与线路损耗的补偿,而不是重建了一个与物理无关的黑箱映射。这一解释与实测的 4.6% RMSE 降幅在量级上自洽。
5.5 结果的适用范围与不确定性
必须明确三点边界。第一,本文算例的光伏装机水平下,测试场景中各节点电压最高为 1.0000 p.u.(即根节点电压),没有出现电压越上限;最低电压为 0.9082 p.u.(节点 18),主要风险是低电压而非倒送过电压。若把光伏装机提高到超过本馈线负荷水平,则倒送过电压会成为主导风险,届时式(4) 在轻载高注入区的精度会下降------这是后续工作要专门验证的场景。第二,本文假设拓扑与线路阻抗完全已知且时不变;实际配电网存在开关状态变化、线路参数不准(尤其老旧低压线路)与三相不平衡,这些都会削弱物理先验的准确性。第三,结论基于单一算例与 60 天合成场景,尚不能直接外推为"所有配电网电压预测都不需要深度图网络",但"算子必须与机理对齐"这一判断具有普适性,这也是本文愿意给出的最强结论。
6 工程落地要点与局限
6.1 与真实业务场景的衔接
在作者所在单位的电网数字化建设实践中,与配电网电压/负荷快速评估相关的需求至少有三类,本文的方法可以直接嵌入其中。第一类是光伏倒送预警 :当光伏出力接近或超过馈线负荷时,需要快速判断各节点电压是否越上限,此时把式(8) 的算子换成"考虑倒送方向的灵敏度矩阵"即可复用同一套框架。第二类是负荷预测与电压评估的联动 :在 10 km×10 km、15 min 分辨率的网格化气象数据支撑下,用 CNN-LSTM 生成 96 点负荷预测曲线(已有实践中预测准确率由 92% 提升至 96.2%),再把预测注入送入本文算子,可在毫秒级得到未来 24 小时的全网电压轨迹,用于提前安排无功补偿与储能充放电。第三类是大电流柜温度预警与负荷调控:当柜温接近 65 ℃ 或主变负载率超过 80% 时,需要快速评估转供或运行方式调整后的电压分布,本文算子的单场景计算量为两次稠密矩阵乘法,足以支撑此类预校核的交互式使用。
6.2 部署与迁移要点
参数固化与在线更新。 RpathR^{\mathrm{path}}Rpath、XpathX^{\mathrm{path}}Xpath 只依赖拓扑与线路参数,可在系统建模阶段预计算并缓存为稀疏矩阵;当联络开关动作或运行方式调整导致拓扑变化时,只需重算矩阵,无需重新训练模型。这是本方案相对纯数据驱动模型最实际的工程优势。
量测不足时的处理。 本文假定各节点注入已知。实际配电网通常只有馈线首端与少量关键节点的量测可用,此时可先用负荷预测或历史曲线补全未量测节点,再送入算子;代价是物理先验的输入本身带有误差。相关研究也指出,在量测有限、训练数据不足时,物理归纳偏置对泛化能力的帮助尤为明显。
与 Skill 化封装的结合。 把"拓扑建模---算子构造---系数标定"三个步骤封装为可复用技能(组件),输入只需节点-支路表与历史注入数据,输出为对应的路径矩阵与标定系数,可以让同一套代码在不同馈线上快速复用,这也是作者在负荷预测类项目中已经验证过的工程路线。
6.3 局限性
本文方法的第一性局限来自式(4) 本身:它是一阶线性化,忽略损耗项与高阶余项,在重载、低压、强不平衡场景下误差会放大。第二,算子假设三相平衡与单相建模。第三,模型 C 的学习部分只有两个参数,在注入量测存在显著噪声时,两参数模型也可能过拟合噪声(本文实测未出现,因为数据由潮流生成、无噪声)。第四,本文未涉及时序建模:电压预测在工程中往往需要未来多时刻输出,这需要把本文的空间算子与时序模型(如 LSTM 或 GRU)级联。
7 小结与展望
本文围绕"图算子与物理机理是否对齐"这一问题,在 IEEE 33 节点系统上完成了可复现的对照实验,主要结论有三点。
第一,把数据搬上图结构并不能自动带来精度。对称归一化图卷积在 K=3K=3K=3 时的测试集 R2R^2R2 仅为 0.0282,KKK 增加到 8 也只有 0.0510,与局部特征基线(0.0069)处于同一水平,本质原因是邻域平均与"沿路径阻抗加权累积"的物理关系不匹配。
第二,把一阶线性化 DistFlow 的方向性聚合直接实现为消息传递算子后,测试集 R2R^2R2 达到 0.9997,RMSE 从 0.0234 p.u. 降至 0.0004 p.u.,降幅约 98.2%。这一结果与"电压---注入关系在标幺制下接近线性、系数只取决于拓扑与阻抗"的物理判断一致。
第三,在物理先验之上让系数可学习仍有稳定增益:模型 C 的 RMSE 比固定系数的纯物理模型 D 低约 4.6%,且学到的截距(1.0004)与理论值 1 吻合、斜率绝对值略大于 1,与一阶展开余项和线损补偿的量级相符。这说明"物理结构 + 少量可学习参数"是一种比"纯黑箱"与"纯解析"都更合理的折中,也解释了物理知情图神经网络在电力系统任务中的价值来源。
后续工作可在三个方向展开:一是提高光伏渗透率与三相不平衡程度,检验式(4) 的失效边界,并把二阶项(损耗)显式建模进算子;二是引入部分可观测与量测噪声,检验物理先验在量测不足时的鲁棒性;三是把本文的空间算子与时序网络级联,输出未来多时刻电压轨迹,用于配电网动态重构与运行方式调整的预校核。
参考资料
1 Baran M E, Wu F F. Network Reconfiguration in Distribution Systems for Loss Reduction and Load BalancingJ. IEEE Transactions on Power Delivery, 1989, 4(2): 1401-1407. DOI: 10.1109/61.25627.(已核验:https://onlinelibrary.wiley.com/doi/full/10.1002/2050-7038.12230 ;https://xplorestaging.ieee.org/document/9258930/references)
2 Farivar M, Low S H. Branch Flow Model: Relaxations and Convexification---Part IJ. IEEE Transactions on Power Systems, 2013, 28(3): 2554-2564. DOI: 10.1109/TPWRS.2013.2255317.(已核验:https://netlab.caltech.edu/research/part_1/ ;https://feeds.library.caltech.edu/people/Low-S-H/article.html)
3 Wu F, Zhang T, Souza Jr A H D, Fifty C, Yu T, Weinberger K Q. Simplifying Graph Convolutional NetworksC. Proceedings of the 36th International Conference on Machine Learning (ICML), PMLR 97, 2019: 6861-6871. arXiv:1902.07153. 代码:https://github.com/Tiiiger/SGC (已核验:https://arxiv.org/pdf/1902.07153v2.pdf ;https://ar5iv.org/abs/1902.07153)
4 Kipf T N, Welling M. Semi-Supervised Classification with Graph Convolutional NetworksC. International Conference on Learning Representations (ICLR), 2017. arXiv:1609.02907.(已核验:https://dl.acm.org/doi/abs/10.1109/TIFS.2023.3245413(引文核对);https://arxiv.org/abs/1609.02907)
5 Scarselli F, Gori M, Tsoi A C, Hagenbuchner M, Monfardini G. The Graph Neural Network ModelJ. IEEE Transactions on Neural Networks, 2009, 20(1): 61-80. DOI: 10.1109/TNN.2008.2005605.(已核验:https://xplorestaging.ieee.org/document/4700287 ;https://ro.uow.edu.au/articles/journal_contribution/The_graph_neural_network_model/27757629)
6 李卓, 王胤喆, 叶林, 罗雅迪, 宋旭日, 张振宇. 从感知-预测-优化综述图神经网络在电力系统中的应用J. 中国电力, 2024, 57(12): 2-16. DOI: 10.11930/j.issn.1004-9649.202410093.(已核验:https://www.electricpower.com.cn/article/doi/10.11930/j.issn.1004-9649.202410093)
7 Okoyomon E, Yaniv A, Goebel C. Physics-Informed Inductive Biases for Voltage Prediction in Distribution GridsEB/OL. arXiv:2509.25158, 2025.(已核验:https://arxiv.org/abs/2509.25158)
8 Varbella A, Amara K, Gjorgiev B, El-Assady M, Sansavini G. PowerGraph: A Power Grid Benchmark Dataset for Graph Neural NetworksC. Advances in Neural Information Processing Systems (NeurIPS) 2024, Datasets and Benchmarks Track. arXiv:2402.02827.(已核验:https://openreview.net/forum?id=qWTfCO4HvT ;https://arxiv.org/pdf/2402.02827.pdf)
9 Lin N, Orfanoudakis S, Vergara P P, et al. PowerFlowNet: Power Flow Approximation Using Message Passing Graph Neural NetworksJ. International Journal of Electrical Power & Energy Systems, 2024, 160: 110112. arXiv:2311.03415.(已核验:https://arxiv.org/pdf/2311.03415v3.pdf ;https://www.semanticscholar.org/paper/2c253ef12c254e84e2c814f7cbd8ba73118c7dd6)
技术栈与环境
- 语言与运行时:Python 3.14.7
- 第三方库:NumPy 2.5.3(数值计算与线性代数)、Matplotlib 3.11.2(图 1、图 2 绘制)
- 外部数据集:无。IEEE 33 节点系统的支路阻抗与节点负荷为公开标准算例参数(Baran & Wu, 1989),已直接内嵌于脚本;运行场景由脚本内置的前推回代潮流生成
- 运行环境依赖安装:
pip install numpy matplotlib - 脚本清单:
09_main.py(主实验,输出09_metrics.json与运行日志)、09_fig.py(绘制图 1、图 2,读取09_metrics.json) - 复现命令:
python 09_main.py→python 09_fig.py - 随机种子:
np.random.seed(20261001),结果可完全复现