假设 Y_bus 是IEEE 6节点的导纳矩阵,已经提前算好了

张开发
2026/4/12 17:54:02 15 分钟阅读

分享文章

假设 Y_bus 是IEEE 6节点的导纳矩阵,已经提前算好了
遗传算法IEEE6潮流程序 适用于电力系统及其自动化专业IEEE 6节点系统这可是电力系统分析界的“Hello World”稍微有点基础的同学闭着眼都能画出它的单线图。通常我们要算它的潮流牛顿-拉夫逊法或者PQ分解法是标配迭代个几次就收敛了又快又准。但今天咱们不走寻常路既然是搞电力系统自动化的偶尔也得整点“暴力美学”——用遗传算法GA来硬解潮流方程。为什么这么干为了好玩当然不是。这其实是一个把非线性方程组求解转化为优化问题的经典案例。潮流方程本质上是 $P{calc} - P{spec} 0$ 和 $Q{calc} - Q{spec} 0$。既然要等于0那我们就让它们的绝对值越小越好这不就变成求最小值的问题了吗咱们直接看代码这里用Python写个最核心的思路不依赖那些花里胡哨的现成库方便看清逻辑。首先是适应度函数。这是遗传算法的灵魂相当于告诉算法“谁长得更像答案谁就是好孩子”。import numpy as np # P_load, Q_load 是节点注入功率负荷为负发电为正 def calculate_power_mismatch(individual, Y_bus, P_spec, Q_spec, pv_indices, slack_index): individual: 这是一个染色体里面存了所有节点的电压幅值(V)和相角(theta) n len(P_spec) V individual[0:n] theta individual[n:2*n] # 复数电压 V_angle V_complex V * np.exp(1j * theta) # 计算注入功率 S V * conj(I) V * conj(Y * V) I_calc np.dot(Y_bus, V_complex) S_calc V_complex * np.conj(I_calc) P_calc S_calc.real Q_calc S_calc.imag # 计算偏差 error 0.0 # PQ节点的P和Q都要匹配 for i in range(n): if i not in pv_indices and i ! slack_index: # PQ节点 error abs(P_calc[i] - P_spec[i]) * 10 # 权重放大一点强迫收敛 error abs(Q_calc[i] - Q_spec[i]) # PV节点的P要匹配Q不管 for i in pv_indices: error abs(P_calc[i] - P_spec[i]) * 10 # 平衡节点不用算它是基准 return error def fitness_function(individual, Y_bus, P_spec, Q_spec, pv_indices, slack_index): mismatch calculate_power_mismatch(individual, Y_bus, P_spec, Q_spec, pv_indices, slack_index) # 偏差越小适应度越高。用倒数加个极小值防止除零 return 1.0 / (mismatch 1e-9)这段代码其实挺直白的。你看那个calculatepowermismatch它根本没做什么矩阵求导或者雅可比矩阵的逆运算就是纯粹的算术运算。这里有个细节值得玩味我们在计算误差的时候给了P偏差一个* 10的权重。为什么要这么干因为在电力系统里有功功率P通常对相角$\theta$更敏感无功Q对电压幅值V更敏感。如果不加权算法可能会为了让Q完美匹配把V调得飞起结果P就崩了。这种调参的手感就像是在调PID控制器的参数全靠经验和对物理过程的理解。遗传算法IEEE6潮流程序 适用于电力系统及其自动化专业接下来是遗传算法的主循环部分也就是所谓的“进化”过程。def genetic_algorithm_flow(Y_bus, P_spec, Q_spec, pv_indices, slack_index, pop_size50, generations100): n len(P_spec) # 初始化种群 # 染色体结构[V0, V1...V5, theta0...theta5] population [] for _ in range(pop_size): # 电压幅值初始化在 0.95 ~ 1.05 之间瞎蒙的 V_init np.random.uniform(0.95, 1.05, n) # 相角初始化在 -pi ~ pi 之间 theta_init np.random.uniform(-np.pi, np.pi, n) # 强制约束平衡节点和PV节点的电压幅值通常是固定的或者有范围的 # 这里为了简化假设PV节点V固定平衡节点V1.0, theta0 # 实际编码中这些固定变量甚至可以不编进染色体里 individual np.concatenate([V_init, theta_init]) population.append(individual) for gen in range(generations): # 1. 评估 scores [fitness_function(ind, Y_bus, P_spec, Q_spec, pv_indices, slack_index) for ind in population] # 简单的轮盘赌选择或者直接取最好的那一半 sorted_pop [x for _, x in sorted(zip(scores, population), reverseTrue)] # 精英保留策略直接把前5个最好的克隆到下一代 new_pop sorted_pop[:5] # 2. 交叉与变异生成剩下的个体 while len(new_pop) pop_size: parent1 sorted_pop[np.random.randint(0, pop_size//2)] parent2 sorted_pop[np.random.randint(0, pop_size//2)] # 交叉实数编码用算术交叉比较稳 alpha np.random.rand() child alpha * parent1 (1 - alpha) * parent2 # 变异给电压和角度加点随机扰动 if np.random.rand() 0.1: # 10%的变异率 # 扰动电压部分 child[0:n] np.random.normal(0, 0.02, n) # 扰动角度部分 child[n:2*n] np.random.normal(0, 0.05, n) new_pop.append(child) population new_pop # 打印一下最好的那个看看收敛没 best_score max(scores) if gen % 10 0: print(fGeneration {gen}: Best Fitness {best_score:.6f}) return sorted_pop[0]这里用的交叉方式是“算术交叉”也就是child ap1 (1-a)p2。对于这种连续变量的优化问题这比二进制编码那种像切香肠一样的切断拼接要高效得多。毕竟电压是个连续的实数你把它切成一串0和1再解码回来精度损失不说还容易产生“海明悬崖”也就是两个二进制数看着很像比如0111和1000实际数值差老远。还有那个变异操作我加了一个高斯噪声np.random.normal。这玩意儿模拟的是自然界中的微小突变。在潮流计算里这相当于在解空间附近做微小的试探。如果当前的解陷入了一个局部最优虽然潮流方程通常是凸的但在加了罚函数或者复杂约束后就不一定了变异能帮它“跳”出来。最后咱们聊聊IEEE 6节点那个著名的导纳矩阵Y-bus。在遗传算法里Y-bus是环境是固定的背景板。# 简化的IEEE 6节点数据构建 def build_ieee6_ybus(): # 节点数 n 6 Y_bus np.zeros((n, n), dtypecomplex) # 这里的数值只是示意具体要查IEEE标准数据 # 比如节点1和节点2之间有线 # y12 1 / (r jx) # Y_bus[0,0] y12 y_shunt/2 # Y_bus[0,1] - y12 # ... # 实际跑的时候得把电阻电抗标幺值填进去 return Y_bus # 运行 Y_bus build_ieee6_ybus() # 假设节点0是平衡节点节点1是PV节点 pv_indices [1] slack_index 0 # 假设P, Q数据 P_spec np.array([0, -0.5, -0.6, -0.7, -0.8, -0.9]) Q_spec np.array([0, -0.1, -0.2, -0.3, -0.4, -0.5]) best_solution genetic_algorithm_flow(Y_bus, P_spec, Q_spec, pv_indices, slack_index)说实话用遗传算法算潮流在工程上其实挺“奢侈”的。牛顿法迭代5次收敛GA可能得跑几百代每一代还要算50个个体的功率偏差计算量大得惊人。但是GA有个巨大的优势它对初值不敏感。牛顿法如果你给个离谱的初值直接就发散了GA不在乎给它一堆乱七八糟的初值它自己慢慢就能摸到门道。而且如果你要做的是最优潮流OPF比如要在算潮流的同时还得让发电成本最低这时候牛顿法就得变成复杂的内点法而GA只需要把适应度函数改成1 / (Cost lambda * Mismatch)就行了架构完全不用动。这才是启发式算法在电力系统里真正的用武之地。写完这一通感觉把非线性的方程组硬生生当成寻优问题来解虽然笨拙但别有一番风味。对于咱们学电力自动化的来说手里多掌握一种“非主流”的武器说不定哪天在处理那些极其恶意的非凸优化问题时就能派上用场。

更多文章