简介:本资源是一套基于MATLAB实现的IEEE 33节点与69节点配电网潮流计算完整代码包,面向电力系统专业本科生、研究生及工程技术人员,用于教学实践、算法验证与课程设计。内容涵盖牛顿-拉夫森法等主流潮流求解方法,包含节点数据建模(IEEE33Bus.m、IEEE69Bus.m)、前推回代核心算法(forwardSweep.m)、主程序调度(main.m)及配套PDF说明文档,可直接运行并可视化电压分布、支路功率等关键结果。压缩包共5个文件,其中4个MATLAB源码文件(.m)构成完整计算流程,1个PDF提供模型参数与算法说明,总大小仅341KB,轻量易部署。已有459人学习下载,适合初学者理解潮流计算原理,也便于进阶用户对比算法性能、修改拓扑或接入新能源负荷模型进行拓展研究。
1. IEEE 33节点系统潮流计算:为什么它成了配电网算法验证的「默认测试床」?
你手头刚写完一个改进的牛顿-拉夫逊法、或者调试好了一个基于图神经网络的潮流预测模块,第一件事不是跑实际工程数据——而是先在 IEEE 33 节点系统上跑通。这不是凑数,而是行业里心照不宣的「准入门槛」:它规模适中(33个节点、32条支路)、结构典型(辐射状+少量环网)、参数公开可复现(标准支路阻抗、负荷分布、基准电压12.66kV/100MVA),且对算法鲁棒性足够敏感——稍有数值不稳定,收敛就直接报错;负荷突增5%,电压越限马上暴露。它不像 IEEE 14 那么简单到掩盖问题,也不像 IEEE 118 那样庞大到让新手卡在数据预处理上。本文聚焦的就是这个被反复验证、但细节极易踩坑的「最小可靠验证单元」:Power_Flow_33_69_33节点_33ieee_ieee33潮流计算_loadflow_IEEE33节点_。我们不讲抽象公式,只拆解从零加载原始数据、构建导纳矩阵、设置初值、迭代收敛、结果校验的完整链路——每一步都对应真实代码、可调参数和我亲手踩过的坑。适合正在做配电网状态估计、无功优化、分布式电源接入仿真或毕业设计建模的工程师与研究生。
2. 用 Python + Pandas 从零加载 IEEE 33 节点原始数据:别信“一键导入”,手动解析才是可控起点
IEEE 33 节点系统没有官方统一的数据包格式,常见来源包括 MATPOWER 的case33、MATLAB 自带power_circuits示例、或 IEEE 官方文档附录中的表格。但这些来源的节点编号、支路顺序、单位(标幺值 vs 实际值)、基准值(100MVA 还是 1MVA)常不一致——直接调用封装函数(如pypower.loadcase('case33'))看似省事,实则黑匣子:一旦结果异常,你连初值在哪、导纳矩阵是否对称都查不到。我的做法是:放弃所有“自动加载”,用 Pandas 手动解析原始表格,把每一行数据的意义钉死。
2.1 下载并整理原始拓扑表:以标准 IEEE 33 节点参数表为唯一信源
标准 IEEE 33 节点系统参数见于《IEEE Transactions on Power Systems》1991年某篇经典论文附录,或 MATPOWER v7.0 的case33.m文件。我们取其核心三张表:
- 节点表(Bus Data):含节点编号(1~33)、类型(1=PQ, 2=PV, 3=Slack)、基准电压(kV)、有功负荷(MW)、无功负荷(MVar)
- 支路表(Branch Data):含首端节点、末端节点、电阻 R(Ω)、电抗 X(Ω)、对地电纳 B(S)、最大允许功率(MVA)
- 发电机表(Gen Data):仅节点 1 为平衡机(Slack),其余无发电机(PV 节点在原始 IEEE 33 中不存在,全为 PQ 负荷节点)
提示:网上流传的某些“IEEE 33”版本擅自添加了 PV 节点或修改了负荷比例,会导致潮流结果与文献对比不上。务必核对原始论文附录或 MATPOWER
case33.m中的bus和branch数组。
2.2 用 Pandas 构建结构化数据表:明确单位、基准值、索引逻辑
import pandas as pd import numpy as np # 1. 定义系统基准值(必须与原始文献一致!) BASE_MVA = 100.0 # IEEE 标准基准容量 BASE_KV = 12.66 # 线电压基准(注意:不是相电压) # 2. 手动录入节点数据(节选前5行,完整33行需补全) bus_data = { 'bus_i': [1, 2, 3, 4, 5], 'type': [3, 1, 1, 1, 1], # 3=Slack, 1=PQ 'pd_mw': [0.0, 0.100, 0.090, 0.120, 0.060], # 有功负荷(MW) 'qd_mvar': [0.0, 0.060, 0.040, 0.080, 0.030], # 无功负荷(MVar) 'vm_pu': [1.0, 1.0, 1.0, 1.0, 1.0], # 初值电压幅值(标幺) 'va_deg': [0.0, 0.0, 0.0, 0.0, 0.0] # 初值电压相角(度) } df_bus = pd.DataFrame(bus_data).set_index('bus_i') # 3. 手动录入支路数据(节选前5条,共32条) branch_data = { 'fbus': [1, 2, 3, 4, 5], 'tbus': [2, 3, 4, 5, 6], 'r_ohm': [0.0005, 0.0005, 0.0005, 0.0005, 0.0005], 'x_ohm': [0.0020, 0.0020, 0.0020, 0.0020, 0.0020], 'b_s': [0.0, 0.0, 0.0, 0.0, 0.0] # 原始 IEEE 33 无线路电纳,设为0 } df_branch = pd.DataFrame(branch_data) # 4. 将支路电阻/电抗转换为标幺值(关键!) z_base = (BASE_KV ** 2) / BASE_MVA # Ω df_branch['r_pu'] = df_branch['r_ohm'] / z_base df_branch['x_pu'] = df_branch['x_ohm'] / z_base df_branch['y_pu'] = 1 / (df_branch['r_pu'] + 1j * df_branch['x_pu']) # 支路导纳(复数) print("支路标幺化完成,z_base =", round(z_base, 4), "Ω")逻辑说明与参数说明:
z_base = (V_base²)/S_base是标幺化核心,单位必须严格匹配:BASE_KV是线电压(kV),BASE_MVA是三相总容量(MVA)。若误用相电压(12.66/√3 ≈ 7.31kV),z_base会小3倍,导致导纳矩阵数值爆炸,迭代发散。df_branch['y_pu']计算的是支路自身导纳(非导纳矩阵元素),后续用于构建节点导纳矩阵Ybus。df_bus的type列必须明确:节点1为 Slack(type=3),其余32个为 PQ(type=1)。IEEE 33 原始系统无 PV 节点,强行设为 PV 会导致雅可比矩阵奇异,牛顿法无法收敛。vm_pu初值全设为1.0、va_deg全设为0.0 是最安全的起点;若设为随机值,可能因初值远离解域而迭代不收敛。
3. 构建节点导纳矩阵 Ybus:手写循环比调包更可控,且能定位稀疏性错误
导纳矩阵Ybus是潮流计算的基石,其维度为n×n(n=33),对角元Yii是节点 i 的自导纳(所有连接支路导纳之和),非对角元Yij是节点 i 与 j 之间的互导纳(负的支路导纳)。MATPOWER 或 PYPOWER 的makeYbus()函数内部也是循环构建,但封装后你无法检查:某条支路是否被重复计入?对角元是否漏加?虚部符号是否反了?因此,我坚持用纯 NumPy 循环手写,控制粒度到每一行。
3.1 初始化 Ybus 并逐条支路填充:显式处理对称性与对角元累加
import numpy as np n_bus = len(df_bus) Ybus = np.zeros((n_bus, n_bus), dtype=complex) # 步骤1:遍历每条支路,填充 Ybus 对角元和互导纳 for idx, row in df_branch.iterrows(): f = int(row['fbus']) - 1 # 转为0-based索引 t = int(row['tbus']) - 1 y_ft = row['y_pu'] # f-t 支路导纳(复数) # 对角元:Yii += y_ft, Yjj += y_ft Ybus[f, f] += y_ft Ybus[t, t] += y_ft # 互导纳:Yij = Yji = -y_ft Ybus[f, t] -= y_ft Ybus[t, f] -= y_ft # 步骤2:验证对称性(Ybus 应为对称复数矩阵) is_symmetric = np.allclose(Ybus, Ybus.T, atol=1e-10) print("Ybus 对称性验证:", "通过" if is_symmetric else "失败!检查支路方向") # 步骤3:打印前3行,肉眼核对结构 print("\nYbus 前3行(实部):") print(np.round(Ybus[:3, :3].real, 4)) print("Ybus 前3行(虚部):") print(np.round(Ybus[:3, :3].imag, 4))逻辑说明与参数说明:
f = int(row['fbus']) - 1是关键:Pandas 读入的节点编号是 1~33,但 NumPy 索引是 0~32,漏减1会导致整个矩阵错位,这是新手最高频翻车点。Ybus[f, f] += y_ft和Ybus[t, t] += y_ft必须用+=,因为一个节点可能连接多条支路(如节点1连接支路1-2,节点2连接支路1-2和2-3),对角元是累加关系。Ybus[f, t] -= y_ft和Ybus[t, f] -= y_ft保证了矩阵对称性;若只填上三角,下三角未赋值,则Ybus不对称,雅可比矩阵构造会出错。np.allclose(Ybus, Ybus.T)是必做校验:若失败,说明支路数据方向混乱(如fbus=2, tbus=1但fbus=1, tbus=2也存在),或y_ft计算有误(如电阻/电抗单位错)。- 打印前3行实部/虚部,是为了与 MATPOWER
case33的Ybus(1:3,1:3)对比。标准 IEEE 33 的Ybus[0,0]实部约为 100~200(因支路阻抗小,导纳大),虚部约为 -500~-1000(主导纳为容性),若数值量级差10倍,说明z_base计算错误。
3.2 处理 IEEE 33 的特殊结构:辐射状网络的 Ybus 稀疏性验证
IEEE 33 是典型辐射状配电网,其Ybus矩阵应高度稀疏(约90%为零)。过度稠密意味着支路连接错误(如将环网支路误加多次)或节点编号逻辑混乱。
# 计算稀疏度 nnz = np.count_nonzero(Ybus) sparsity = 1 - nnz / (n_bus * n_bus) print(f"Ybus 稀疏度: {sparsity:.3f} ({nnz} 个非零元)") # 可视化非零元位置(仅示意,生产环境用 plt.spy) import matplotlib.pyplot as plt plt.figure(figsize=(6,6)) plt.spy(Ybus, markersize=1) plt.title('Ybus 非零元分布(IEEE 33)') plt.xlabel('列(节点j)') plt.ylabel('行(节点i)') plt.show()现象与价值:
- 标准 IEEE 33 的
Ybus非零元数应为2*32 + 33 = 97(32条支路贡献64个非零元,33个对角元),稀疏度约1 - 97/1089 ≈ 0.91。若nnz > 150,说明有支路被重复添加或节点编号映射错误。 plt.spy()显示的图案应呈“树状”:节点1(根)连接节点2,节点2连接节点3和节点?,依此类推。若出现密集块状,说明存在未声明的环网或数据表行列错位。
4. 牛顿-拉夫逊法潮流求解:从雅可比矩阵构造到收敛判据,每一步都可打断调试
牛顿-拉夫逊法(NR)是 IEEE 33 潮流计算的黄金标准,因其二次收敛特性在中小规模系统上稳定高效。但它的“黑盒感”最强——一旦不收敛,你不知道是初值问题、雅可比矩阵奇异,还是功率不平衡方程写错了。本节拆解 NR 的每一步,确保你能随时print()中间变量定位问题。
4.1 定义功率不平衡方程 ΔP 和 ΔQ:严格按节点类型区分
def calc_power_mismatch(Ybus, V_pu, df_bus, BASE_MVA): """ 计算节点有功/无功不平衡量 ΔP, ΔQ V_pu: 电压向量 (n_bus,),复数,单位标幺 返回: ΔP (PQ+PV节点), ΔQ (PQ节点),均为实数向量 """ n_bus = len(V_pu) S_calc = V_pu * np.conj(np.dot(Ybus, V_pu)) # 计算各节点注入复功率 P_calc = S_calc.real # 计算有功注入(MW,标幺) Q_calc = S_calc.imag # 计算无功注入(MVar,标幺) # 提取已知负荷(Pd, Qd)和发电机出力(Pg, Qg),IEEE 33 中 Pg/Qg 全为0 Pd = df_bus['pd_mw'].values / BASE_MVA # 负荷有功(标幺) Qd = df_bus['qd_mvar'].values / BASE_MVA # 负荷无功(标幺) # ΔP = Pgen - Pload - Pcalc, ΔQ = Qgen - Qload - Qcalc # IEEE 33 中 Pgen=Qgen=0,故 ΔP = -Pd - Pcalc, ΔQ = -Qd - Qcalc delta_P = -Pd - P_calc delta_Q = -Qd - Q_calc # Slack 节点(type=3)不参与 ΔP/ΔQ 方程,PV 节点(type=2)不参与 ΔQ 方程 # 构建待求解的不平衡向量 pq_nodes = df_bus[df_bus['type'] == 1].index.values - 1 # PQ节点索引(0-based) pv_nodes = df_bus[df_bus['type'] == 2].index.values - 1 # PV节点索引(0-based) slack_node = df_bus[df_bus['type'] == 3].index.values[0] - 1 # Slack节点索引 # ΔP 向量:所有 PQ + PV 节点(不含 Slack) all_gen_nodes = np.concatenate([pv_nodes, pq_nodes]) delta_P_vec = delta_P[all_gen_nodes] # ΔQ 向量:仅 PQ 节点 delta_Q_vec = delta_Q[pq_nodes] return np.concatenate([delta_P_vec, delta_Q_vec]) # 测试:用初值 V_pu = [1+0j]*33 计算初始不平衡 V_init = np.ones(n_bus, dtype=complex) delta_f = calc_power_mismatch(Ybus, V_init, df_bus, BASE_MVA) print("初始 ΔP+ΔQ 维度:", len(delta_f)) print("初始最大不平衡(标幺):", np.max(np.abs(delta_f)))逻辑说明与参数说明:
S_calc = V_pu * np.conj(np.dot(Ybus, V_pu))是核心公式,必须用np.conj()计算共轭,否则功率符号全反。delta_P = -Pd - P_calc中的负号源于定义:潮流方程是P_injected = P_generation - P_load,而 IEEE 33 中P_generation=0,故P_injected = -P_load,不平衡量ΔP = P_specified - P_calculated = (-P_load) - P_calc。pq_nodes和pv_nodes的提取必须严格依据df_bus['type'],不能硬编码索引。IEEE 33 的 Slack 是节点1,若df_bus.index[0]不是1,说明set_index('bus_i')失败。- 初始不平衡量
np.max(np.abs(delta_f))应在0.1~0.3标幺范围内。若大于1.0,说明Ybus或负荷数据单位严重错误(如 MW 未除BASE_MVA)。
4.2 构造雅可比矩阵 J:分块计算,避免矩阵拼接错误
雅可比矩阵J是(2n-1) × (2n-1)维(n=33,故 65×65),分为四块:J11=∂ΔP/∂δ,J12=∂ΔP/∂V,J21=∂ΔQ/∂δ,J22=∂ΔQ/∂V。手动推导易错,但用 NumPy 循环分块计算,可逐行验证。
def build_jacobian(Ybus, V_pu, df_bus, BASE_MVA): """ 构建雅可比矩阵 J 返回: J (n_eq x n_eq) 矩阵,n_eq = len(delta_f) """ n_bus = len(V_pu) # 确定方程数:ΔP 数 = (PQ+PV节点数),ΔQ 数 = PQ节点数 pq_nodes = df_bus[df_bus['type'] == 1].index.values - 1 pv_nodes = df_bus[df_bus['type'] == 2].index.values - 1 slack_node = df_bus[df_bus['type'] == 3].index.values[0] - 1 n_pq = len(pq_nodes) n_pv = len(pv_nodes) n_eq = n_pq + n_pv + n_pq # ΔP for PV+PQ + ΔQ for PQ J = np.zeros((n_eq, n_eq)) # 预计算 V 的实部/虚部,用于偏导数 V_real = V_pu.real V_imag = V_pu.imag V_abs = np.abs(V_pu) V_ang = np.angle(V_pu) # 弧度 # 构建 J11 (∂ΔP/∂δ) 和 J12 (∂ΔP/∂V) —— 对所有 PV+PQ 节点 eq_idx_p = 0 for i in np.concatenate([pv_nodes, pq_nodes]): # J11[i, j] = ∂Pi/∂δj = Vi*Vj*(Gij*sin(δi-δj) - Bij*cos(δi-δj)) for j in range(n_bus): if i == j: # 对角元:∑ Vj*(Gij*sin(δi-δj) - Bij*cos(δi-δj)) sum_val = 0.0 for k in range(n_bus): if k != i: Gik = Ybus[i, k].real Bik = Ybus[i, k].imag sum_val += V_abs[i] * V_abs[k] * (Gik * np.sin(V_ang[i]-V_ang[k]) - Bik * np.cos(V_ang[i]-V_ang[k])) J[eq_idx_p, eq_idx_p] = sum_val else: # 非对角元 Gij = Ybus[i, j].real Bij = Ybus[i, j].imag J[eq_idx_p, j] = V_abs[i] * V_abs[j] * (Gij * np.sin(V_ang[i]-V_ang[j]) - Bij * np.cos(V_ang[i]-V_ang[j])) # J12[i, j] = ∂Pi/∂|Vj| = Vi*(Gij*cos(δi-δj) + Bij*sin(δi-δj)) for j in range(n_bus): if i == j: # 对角元:∑ (Gik*cos(δi-δk) + Bik*sin(δi-δk)) sum_val = 0.0 for k in range(n_bus): if k != i: Gik = Ybus[i, k].real Bik = Ybus[i, k].imag sum_val += V_abs[k] * (Gik * np.cos(V_ang[i]-V_ang[k]) + Bik * np.sin(V_ang[i]-V_ang[k])) J[eq_idx_p, n_bus + j] = sum_val else: Gij = Ybus[i, j].real Bij = Ybus[i, j].imag J[eq_idx_p, n_bus + j] = V_abs[i] * (Gij * np.cos(V_ang[i]-V_ang[j]) + Bij * np.sin(V_ang[i]-V_ang[j])) eq_idx_p += 1 # 构建 J21 (∂ΔQ/∂δ) 和 J22 (∂ΔQ/∂V) —— 仅对 PQ 节点 eq_idx_q = n_pq + n_pv for i in pq_nodes: # J21[i, j] = ∂Qi/∂δj = Vi*Vj*(Gij*cos(δi-δj) + Bij*sin(δi-δj)) for j in range(n_bus): if i == j: sum_val = 0.0 for k in range(n_bus): if k != i: Gik = Ybus[i, k].real Bik = Ybus[i, k].imag sum_val += V_abs[i] * V_abs[k] * (Gik * np.cos(V_ang[i]-V_ang[k]) + Bik * np.sin(V_ang[i]-V_ang[k])) J[eq_idx_q, eq_idx_q] = sum_val else: Gij = Ybus[i, j].real Bij = Ybus[i, j].imag J[eq_idx_q, j] = V_abs[i] * V_abs[j] * (Gij * np.cos(V_ang[i]-V_ang[j]) + Bik * np.sin(V_ang[i]-V_ang[j])) # J22[i, j] = ∂Qi/∂|Vj| = Vi*(Gij*sin(δi-δj) - Bij*cos(δi-δj)) for j in range(n_bus): if i == j: sum_val = 0.0 for k in range(n_bus): if k != i: Gik = Ybus[i, k].real Bik = Ybus[i, k].imag sum_val += V_abs[k] * (Gik * np.sin(V_ang[i]-V_ang[k]) - Bik * np.cos(V_ang[i]-V_ang[k])) J[eq_idx_q, n_bus + j] = sum_val else: Gij = Ybus[i, j].real Bij = Ybus[i, j].imag J[eq_idx_q, n_bus + j] = V_abs[i] * (Gij * np.sin(V_ang[i]-V_ang[j]) - Bik * np.cos(V_ang[i]-V_ang[j])) eq_idx_q += 1 return J # 测试雅可比矩阵维度 J_test = build_jacobian(Ybus, V_init, df_bus, BASE_MVA) print("雅可比矩阵 J 维度:", J_test.shape) print("J 条件数(log10):", np.log10(np.linalg.cond(J_test)))逻辑说明与参数说明:
J的行/列索引必须与delta_f严格对应:前n_pq+n_pv行是ΔP,后n_pq行是ΔQ;前n_bus列是∂/∂δ,后n_bus列是∂/∂|V|。若错位,np.linalg.solve(J, delta_f)会返回完全错误的修正量。J的条件数np.linalg.cond(J_test)应小于1e6。若大于1e8,说明Ybus奇异(如某节点孤立、支路电阻为0),或初值V_pu导致sin/cos计算溢出。- 对角元计算中
for k in range(n_bus): if k != i:是关键,漏掉此判断会导致自导纳项被重复计入,J不准。
5. 潮流收敛避坑指南:6个真实翻车现场与血泪修复方案
潮流计算不收敛?别急着改算法,90%的问题藏在数据和初值里。以下是我在调试 IEEE 33 潮流时亲手踩过的坑,每个都附带现象、根因和一招修复。
5.1 现象:迭代 10 次后 ΔP/ΔQ 不降反升,最终nan
原因:Ybus中某条支路的r_ohm或x_ohm为 0(如0.0000),导致y_pu = 1/(0+0j)产生inf或nan,污染整个矩阵。
解决:在构建Ybus前,强制过滤支路参数:
df_branch = df_branch[(df_branch['r_ohm'] > 1e-8) & (df_branch['x_ohm'] > 1e-8)]5.2 现象:迭代 2 次后电压幅值突变为1e5或1e-5
原因:BASE_MVA或BASE_KV单位错。例如BASE_KV=12.66误写为BASE_KV=12660(单位 V),导致z_base增大 10⁶ 倍,y_pu缩小 10⁶ 倍,Ybus接近零矩阵,NR 步长失控。
解决:打印z_base并与理论值比对——IEEE 33 的z_base应为1.609Ω(12.66²/100)。若为1609,说明BASE_KV多了 1000 倍。
5.3 现象:np.linalg.solve(J, delta_f)报LinAlgError: Singular matrix
原因:Slack 节点(type=3)未正确排除在delta_f和J之外。若df_bus['type']列有缺失值或类型编码错(如 Slack 写成 1),slack_node识别失败,J包含冗余行/列。
解决:强制校验 Slack 节点存在且唯一:
assert len(df_bus[df_bus['type']==3]) == 1, "Slack 节点必须且仅有一个"5.4 现象:收敛后某节点电压Vm为0.4 pu(远低于 0.9),但文献值为0.92 pu
原因:负荷数据单位错。网上某些版本将pd_mw直接当作标幺值(未除BASE_MVA),导致负荷放大 100 倍,压降过大。
解决:核对原始文献——IEEE 33 总负荷约3.715 MW + j2.3 Mvar,标幺值为0.03715 + j0.023。若你的sum(pd_mw)接近3715,说明没除BASE_MVA。
5.5 现象:delta_f初始值极小(<1e-6),但迭代不收敛
原因:V_init全为1+0j时,S_calc计算中np.conj(np.dot(Ybus, V_pu))因Ybus虚部主导,S_calc.imag本应为负(感性负荷),但若Ybus.imag符号反了(如支路y_pu计算时用了1/(r - 1j*x)),Q_calc为正,delta_Q符号错。
解决:打印Ybus[0,1]的虚部——应为负数(感性支路导纳虚部为负)。若为正,检查y_pu = 1/(r_pu + 1j*x_pu)是否误写为1/(r_pu - 1j*x_pu)。
5.6 现象:收敛结果与 MATPOWERrunpf('case33')差异 > 0.001 pu
原因:MATPOWER 默认使用Newton-Raphson但启用了fast decoupled预处理,或其case33的baseMVA为1而非100。
解决:用 MATPOWER 导出Ybus和bus数据,与你的Ybus和df_bus逐元素比对。重点看Ybus[0,0].imag:标准值应为-520.0左右(标幺),若你的为-5.2,说明BASE_MVA用了1。
6. 验证与进阶:用 3 种独立方法交叉校验结果,并实现快速重载负荷场景
潮流结果可信吗?不能只看“收敛”二字。真正的验证是跨工具、跨方法、跨场景的交叉比对。同时,工程中常需批量测试不同负荷水平(如峰荷、谷荷、故障后),手动改df_bus太慢。本节给出可落地的验证框架和自动化技巧。
6.1 三层交叉验证法:让结果自己说话
| 验证方法 | 操作步骤 | 通过标准 |
|---|---|---|
| MATPOWER 对比 | 运行mpc = loadcase('case33'); results = runpf(mpc);提取results.bus(:,8) | 电压幅值误差 < 1e-4 pu(33节点全部) |
| 直流潮流(DC) | 忽略无功、设X>>R,用P = B' * δ解δ,再算V = 1 + X*δ(近似) | 电压排序一致(节点33最低,节点1最高) |
| 功率守恒校验 | 计算sum(P_injected)和sum(P_load),差值应 < 1e-6 MW | abs(sum(P_inj) + sum(Pd)) < 1e-6 |
# 功率守恒校验(最简但最有效) S_calc = V_final * np.conj(np.dot(Ybus, V_final)) P_inj = S_calc.real * BASE_MVA # 转回 MW P_load = df_bus['pd_mw'].values power_balance_error = abs(sum(P_inj) + sum(P_load)) print(f"功率守恒误差: {power_balance_error:.2e} MW") # 应 < 1e-66.2 快速重载负荷场景:用 Pandasloc实现秒级参数切换
工程中常需测试 1.2 倍峰荷、0.8 倍谷荷、或某条馈线切除后的状态。手动改 33 行数据太慢,用df_bus.loc索引批量操作:
# 定义场景字典 scenarios = { 'peak': {'scale': 1.2, 'cut_lines': []}, 'valley': {'scale': 0.8, 'cut_lines': []}, 'fault_12': {'scale': 1.0, 'cut_lines': [11]} # 切除支路12 <p> <a href="https://download.csdn.net/download/weixin_42676678/26286467" style="color:#ec7500;font-size:14px;"> 本文还有配套的精品资源,点击获取 </a> <img alt="menu-r.4af5f7ec.gif" src="https://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif" style="width:16px;margin-left:4px;vertical-align:text-bottom;cursor:text;"> </p>