前言:在火电机组经济调度建模及求解——基础篇中,我们介绍了固定负荷情况下,基础的火电机组经济调度模型。然而,有些时候我们需要进行一些灵敏度分析。以"负荷"为例,在实际的火电机组经济调度中,负荷会随着用户需求的改变发生变化,从而会对机组的出力产生影响。因此,当负荷发生改变时,需要对经济调度过程中火电机组的出力变化进行分析。
本期推文内容介绍
- 负荷灵敏度分析介绍与编程实现
- pd.Dataframe的用法
Part 1 考虑负荷灵敏度分析的火电机组经济调度模型
基础的火电机组经济调度模型为:
min
P
g
,
t
T
C
=
∑
g
,
t
a
g
P
g
,
t
2
+
b
g
P
g
,
t
+
c
g
P
g
min
≤
P
g
,
t
≤
P
g
max
∑
g
P
g
,
t
≥
L
t
\begin{aligned} \min _{P_{g, t}} \mathrm{TC}=& \sum_{g, t} a_{g} P_{g, t}^{2}+b_{g} P_{g, t}+c_{g} \\ & P_{g}^{\min } \leq P_{g, t} \leq P_{g}^{\max } \\ & \sum_{g} P_{g, t} \geq L_{t} \end{aligned}
Pg,tminTC=g,t∑agPg,t2+bgPg,t+cgPgmin≤Pg,t≤Pgmaxg∑Pg,t≥Lt
以上火电机组的基础模型在推文火电机组经济调度建模及求解——基础篇中做过详细的介绍,这里不在赘述。在之前内容中,将负荷视为一个确定的标量,实际上该经济调度问题对位于区间[281,998]内的任意负荷值都是以可求解的。该区间的上下边界值根据所给出的火电机组出力最小值、最大值之和分别求得。火电机组出力范围参数值请看Part2程序。为了更好反应负荷变化情况,我们在负荷区间
∑
i
=
1
N
L
o
a
d
m
i
n
(
i
)
=
281
∼
∑
i
=
1
N
L
o
a
d
m
a
x
(
i
)
=
998
\begin{aligned} \sum_{i=1}^{N}Load_{min}(i)=281 \sim \sum_{i=1}^{N}Load_{max}(i)=998 \end{aligned}
i=1∑NLoadmin(i)=281∼i=1∑NLoadmax(i)=998
内取11个值,并计算相应的火电机组出力情况。其负荷表达式为:
l
o
a
d
T
o
t
a
l
=
∑
i
=
1
N
L
o
a
d
m
i
n
(
i
)
+
k
K
(
∑
i
=
1
N
L
o
a
d
m
a
x
(
i
)
−
∑
i
=
1
N
L
o
a
d
m
i
n
(
i
)
)
,
k
∈
[
1
,
K
]
\begin{aligned} load_{Total}=\sum_{i=1}^{N}Load_{min}(i)+\frac{k}{K}(\sum_{i=1}^{N}Load_{max}(i)-\sum_{i=1}^{N}Load_{min}(i)),k \in [1,K] \end{aligned}
loadTotal=i=1∑NLoadmin(i)+Kk(i=1∑NLoadmax(i)−i=1∑NLoadmin(i)),k∈[1,K]
利用上述负载值分别计算相应的最优经济调度结果,其表达式可以用代码表示为:
load_demand = sum(output_min[i] for i in range(units))+(c/(counter-1))*(sum((output_max[i]-output_min[i] for i in range(units))))
当然,读者也可以选取属于负荷区间[281,998]内的任意值进行灵敏度分析,即: K K K可以取任意值。
Part 2 Python+Gurobi 代码实现
import gurobipy as gp
from gurobipy import GRB
import pandas as pd
# In[] data input
load_demand = 400 ##(Mw)
units = 5 # the total number of thermal units
counter = 11
# In[] minimum and maximum generating limits of each unit
output_min = [28,90,68,76,19] ## P_i^th,min (MW)
output_max = [206,284,189,266,53] ## P_i^th,max (MW)
# In[] the cost coef a b c of these thermal units
coef_A = [3,4.05,4.05,3.99,3.88] ## a_i^th ($/MW^2)
coef_B = [20,18.07,15.55,19.21,26.18] ## b_i^th ($/MW)
coef_C = [100,98.87,104.26,107.21,95.31] ## c_i^th ($)
##Difining the model
m = gp.Model("thermal_unit_dispatch_example ")
##Defining the decision variables
thermal_output = m.addVars(units, vtype = GRB.CONTINUOUS, name='thermal_output')
## Constranits of the operating
m.addConstrs((thermal_output[i]>=output_min[i]
for i in range(units)),name='Operating_Limits_min')
m.addConstrs((thermal_output[i]<=output_max[i]
for i in range(units)),name='Operating_Limits_max')
## Constranits of the load demanding(In this way, the load is a certain value)
# m.addConstr(gp.quicksum(thermal_output[i] for i in range(units))>=load_demand ,name='demand_load')
## seting the objective function
total_cost = gp.quicksum(coef_A[i]*thermal_output[i]*thermal_output[i]+coef_B[i]*thermal_output[i]+coef_C[i]
for i in range(units))
# In[] Sometimes we need different dispatch patterns, if the load value changed
##### we need to analyze the sensitivity of load value
optimize_cost=[]
load=[]
rows = ['C'+str(c+1) for c in range(counter)] #define rows of the table
dispatch_plan = pd.DataFrame(columns=['g'+str(u+1) for u in range(units)],index=rows,data=0.0)
for c in range(counter):
load_demand = sum(output_min[i] for i in range(units))+(c/(counter-1))*(sum((output_max[i]-output_min[i] for i in range(units))))
load.append(load_demand)
m.addConstr(gp.quicksum(thermal_output[i] for i in range(units))>=load_demand ,name='demand_load')
m.setObjective(total_cost,GRB.MINIMIZE) #get the minimize total_cost
m.optimize()
for u in range(units):
dispatch_plan.loc['C'+str(c+1),'g'+str(u+1)]=float(thermal_output[u].x)
optimize_cost.append(m.objVal)
dispatch_plan['load(MW)']=load
dispatch_plan['cost($/h)']=optimize_cost
# In[] showing the solution for load sencisitity analysis
print(dispatch_plan.round(2))
优化结果如下:
- Tips 1: 通过一个简单的例子介绍pd.DataFrame的用法:
import pandas as pd
#pd.DataFrame( data, index, columns, dtype)
'''
data:输入的数据,可以是 ndarray,series,list,dict,标量以及一个 DataFrame.
index:行标签
columns:列标签
dtype:数据类型
'''
data=[[100,80,90],[90,100,80]]
table = pd.DataFrame(data,index=['张三','李四'],columns=['语文','数学','英语'])
结果展示如下:
Part 7 创作人员名单
作者| Thor、李同学
代码| Thor
审核| Thor、李同学
参考文献
- A. Soroudi, Power System Optimization Modeling in GAMS
往期内容回顾
13. 拉格朗日乘子法与KKT条件
12. 经济调度问题的建模及求解——考虑爬坡约束
11. 火电机组经济调度建模及求解——基础篇
10. 基于Distflow的最优潮流模型(OPF)–模型推导篇
9. 火电机组经济调度建模及求解——基础篇
8. Python|Gurobi——零基础学优化建模-终章
7. Python|Gurobi——零基础学优化建模-压轴篇:多目标优化
6. Python|Gurobi——零基础学优化建模-分段模型线性化(PWL)
5. Python|Gurobi——零基础学优化建模-QCP
4. Python|Gurobi——零基础学优化建模-NLP
3. Python|Gurobi——零基础学优化建模-MIP
2. Python|Gurobi——零基础学优化建模-LP
1. Python|Gurobi——零基础学优化建模