├── README.md └── distflow-opf.py /README.md: -------------------------------------------------------------------------------- 1 | # DistFlow-opf 2 | optimal power flow based on DistFlow 3 | Case: IEEE39 bus 4 | Constrains: 5 | ![image](https://user-images.githubusercontent.com/51228607/231430803-045b60b6-f8f2-4457-bc21-a2b6e814c5e1.png) 6 | 7 | Objective: 8 | 9 | a*Pg_i^2+b*Pg_i+c 10 | 11 | Results: 12 | 13 | Voltage 14 | 15 | ![image](https://user-images.githubusercontent.com/51228607/231431057-5a4904cb-6fe6-4d93-ad81-7c835cf376b0.png) 16 | 17 | Generator 18 | 19 | ![image](https://user-images.githubusercontent.com/51228607/231431253-9d54c877-0c61-4da5-91a6-26a68bced2b1.png) 20 | 21 | -------------------------------------------------------------------------------- /distflow-opf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sun Apr 9 19:18:55 2023 4 | 5 | @author: wyx 6 | """ 7 | #%% 读取数据 8 | import pandas as pd 9 | import numpy as np 10 | from gurobipy import * 11 | from pypower.api import case39 12 | # 定义常数 13 | baseMVA = 100 14 | basekV = 500 15 | baseI = baseMVA*1000/basekV 16 | I_max = 1000*1000/baseI**2 17 | V_max = 1.06*1.06 # 节点电压上限 18 | V_min = 0.94*0.94 # 节点电压下限 19 | c = [0.01, 0.3, 0.2] # 发电成本 20 | # 节点数据 21 | Data = case39() # 读取IEEE39节点数据 22 | node = Data['bus'] # 读取节点数据 23 | bus_num = node[:,0].astype('int') # 节点编号 24 | P_i = {i+1:node[:,2][i]/baseMVA for i in bus_num-1} # 节点有功功率 25 | Q_i = {i+1:node[:,3][i]/baseMVA for i in bus_num-1} # 节点有功功率 26 | G_Data = Data['gen'] # 读取发电机节点数据 27 | gen_num = G_Data[:,0].astype('int') # 发电机节点编号 28 | genP_max = dict(zip(gen_num,G_Data[:,8])) # 发电机电压上限 29 | genQ_max = dict(zip(gen_num,G_Data[:,3])) # 发电机电压下限 30 | commen_num = list(set(bus_num.tolist())-set(gen_num.tolist())) # 非发电机节点 31 | # 支路数据 32 | branch = Data['branch'] # 读取支路数据 33 | f = branch[:, 0].astype('int') # 支路起始节点 34 | t = branch[:, 1].astype('int') # 支路末端节点 35 | ij = list(zip(f,t)) # 线路集合 36 | r = branch[:,2]/(basekV**2/baseMVA) # 电阻有名值化为标幺值 37 | x = branch[:,3]/(basekV**2/baseMVA) # 电抗有名值化为标幺值 38 | r_ij = dict(zip(ij,r)) # 将电阻与支路对应 39 | x_ij = dict(zip(ij,x)) # 将电抗与支路对应 40 | upStream = {Node:branch[branch[:,1]==Node][:,0].astype('int') for Node in bus_num} # 所有节点的上游节点 41 | downStream = {Node:branch[branch[:,0]==Node][:,1].astype('int') for Node in bus_num} # 所有节点的下游节点 42 | 43 | #%% 建立模型 44 | model = Model('DistFlow') 45 | GP_i = model.addVars(gen_num,lb=-GRB.INFINITY,name='GP_i') # 发电机有功出力 46 | GQ_i = model.addVars(gen_num,lb=-GRB.INFINITY,name='GQ_i') # 发电机无功出力 47 | P_ij = model.addVars(ij, lb=-GRB.INFINITY,name='P_ij') # 线路无功潮流 48 | Q_ij = model.addVars(ij, lb=-GRB.INFINITY,name='Q_ij') # 线路有功潮流 49 | l_ij = model.addVars(ij, lb=-GRB.INFINITY,ub=I_max,name='l_ij') # 线路电流 50 | v_i = model.addVars(bus_num, lb=V_min,ub=V_max,name='v_i') # 节点电压 51 | 52 | #%% 功率平衡约束 53 | # 非发电机节点功率平衡 54 | model.addConstrs((0==P_i[i]+quicksum(P_ij[i,j] 55 | for j in downStream[i])-quicksum(P_ij[k,i]-r_ij[k,i]*l_ij[k,i] for k in upStream[i]) 56 | for i in commen_num),name='NodePBalance') 57 | model.addConstrs((0==Q_i[i]+quicksum(Q_ij[i,j] 58 | for j in downStream[i])-quicksum(Q_ij[k,i]-x_ij[k,i]*l_ij[k,i] for k in upStream[i]) 59 | for i in commen_num),name='NodeQBalance') 60 | 61 | # 发电机节点功率平衡 62 | model.addConstrs((0==-GP_i[i]+P_i[i]+quicksum(P_ij[i,j] 63 | for j in downStream[i])-quicksum(P_ij[k,i]-r_ij[k,i]*l_ij[k,i] for k in upStream[i]) 64 | for i in gen_num),name='NodeGPBalance') 65 | model.addConstrs((0==-GQ_i[i]+Q_i[i]+quicksum(Q_ij[i,j] 66 | for j in downStream[i])-quicksum(Q_ij[k,i]-x_ij[k,i]*l_ij[k,i] for k in upStream[i]) 67 | for i in gen_num),name='NodeGQBalance') 68 | 69 | model.addConstrs((GP_i[i]<=genP_max[i] for i in gen_num),name='Pmax') # 发电机有功出力上限 70 | model.addConstrs((GP_i[i]>=0 for i in gen_num),name='Pmin') # 发电机有功出力下限 71 | model.addConstrs((GP_i[i]<=genQ_max[i] for i in gen_num),name='Qmax') # 发电机无功出力上限 72 | model.addConstrs((GP_i[i]>=-genQ_max[i] for i in gen_num),name='Qmin') # 发电机无功出力下限 73 | 74 | model.addConstrs((v_i[j]==v_i[i]-2*(r_ij[i,j]*P_ij[i,j]+x_ij[i,j]*Q_ij[i,j])+(r_ij[i,j]**2 75 | +x_ij[i,j]**2)*l_ij[i,j] for (i,j) in ij),name='voltage') 76 | model.addConstrs((v_i[i]>=V_min for i in bus_num),name='voltageMin') 77 | model.addConstrs((v_i[i]<=V_max for i in bus_num),name='voltageMax') 78 | model.addConstr((v_i[31]==1),name='slackNode') 79 | model.addConstrs((l_ij[i,j]<=I_max for i,j in ij),name='Lijconstrs') 80 | 81 | model.addConstrs((l_ij[i,j]*v_i[i]>=(P_ij[i,j]**2+Q_ij[i,j]**2) for i,j in ij),name='SOC') 82 | # #%% 模型求解 83 | # 定义目标函数 84 | obj = quicksum(c[0]*GP_i[i]**2+c[1]*GP_i[i]+c[2] for i in gen_num) 85 | model.setObjective(obj,GRB.MINIMIZE) 86 | model.optimize() 87 | #%% 输出结果 88 | P,v, i,f = {},{},{},{} 89 | P = [P_ij[i].x for i in ij] 90 | v = [v_i[i].x for i in bus_num] 91 | i = [GP_i[i].x for i in gen_num] 92 | f = [GQ_i[i].x for i in gen_num] 93 | dP = pd.DataFrame(P) 94 | dV =pd.DataFrame(v) 95 | di= pd.DataFrame(i) 96 | df= pd.DataFrame(f) 97 | --------------------------------------------------------------------------------