前言:在上期内容火电机组经济调度建模及求解——基础篇中,我们介绍了基础的火电机组经济调度模型,本期内容我们将利用动态规划解决考虑爬坡约束的火电机组经济调度问题,在此问题中我们将涉及爬坡率的概念:
电厂灵活性被认为是管理电力负荷变化和提供电网支持服务的重要工具。衡量这种灵活性的一个指标是爬坡率,即发电厂燃气轮机发电增加或减少产出的速率。(来源:Google)
当负荷变化时,发电机组需要以一定的斜率从一个出力值变为另外一个出力值。由于火电机组存在机械/热力方面的约束,每分钟的出力不能超过规定的最大变化率限值。当电力系统中负荷出现一个小的增量时,为实现最优的经济调度(发电成本最低),需要在满足爬坡率约束的前提下,降低部分机组的发电量的同时增加其他发电机的出力。因此该问题可以视为一个在时间上前后关联的多阶段决策问题,并可以利用动态规划的思想实现问题求解。(来源:《电力系统发电、运行和控制》)
本期推文内容介绍
- 爬坡约束的建模以及编程实现、排污成本的计算
- model.addRange()的用法介绍
- 动态规划中两个连续时间点的约束表述——用于爬坡约束的描述
- x.sum()对变量求和
- 得到最优解后,利用最优解计算其他目标值——getValue()的用法介绍
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
在此基础上加入爬坡约束,以避免因为负荷扰动,出现火电机组违反爬坡率的情况:
P
g
,
t
−
P
g
,
t
−
1
≤
R
U
g
P
g
,
t
−
1
−
P
g
,
t
≤
R
D
g
\begin{aligned} & P_{g, t}-P_{g, t-1} \leq \mathrm{RU}_{g} \\ & P_{g, t-1}-P_{g, t} \leq \mathrm{RD}_{g} \end{aligned}
Pg,t−Pg,t−1≤RUgPg,t−1−Pg,t≤RDg
式中,
P
g
,
t
P_{g, t}
Pg,t、
P
g
,
t
−
1
P_{g, t-1}
Pg,t−1分别为 t 时刻与 t-1 时刻的发电功率,
R
U
g
\mathrm{RU}_{g}
RUg、
R
U
g
\mathrm{RU}_{g}
RUg分别表示火电机组单位时间内增加或减少的出力,即:爬坡率上限。由于火电机组发电需要考虑排污费用,在得到最优调度结果以后,需要计算总的排污成本:
E
M
=
∑
g
,
t
d
g
P
g
,
t
2
+
e
g
P
g
,
t
+
f
g
\begin{aligned} \mathrm{EM}=& \sum_{g, t} d_{g} P_{g, t}^{2}+e_{g} P_{g, t}+f_{g} \end{aligned}
EM=g,t∑dgPg,t2+egPg,t+fg
Part 2 Python+Gurobi 代码实现
import gurobipy as gp
from gurobipy import GRB
'参数设定'
a_g = [0.12, 0.17, 0.15, 0.19] # 发电二次项系数
b_g = [14.8, 16.57, 15.55, 16.21] # 发电一次项系数
c_g = [89, 83, 100, 70] # 发电常数项
d_g = [1.2, 2.3, 1.1, 1.1] # 排污二次项系数
e_g = [-5, -4.24, -2.15, -3.99] # 排污一次项系数
f_g = [3, 6.09, 5.69, 6.2] # 排污常数项
P_g_min = [28, 20, 30, 20] # 发电量最小值
P_g_max = [200, 290, 190, 260] # 发电量最大值
RU_g = [40, 30, 30, 50] # 爬坡率——UP
RD_g = [40, 30, 30, 50] # 爬坡率——Down
L_t = [510, 530, 516, 510, 515, 544, 646, 686,
741, 734, 748, 760, 754, 700, 686, 720,
714, 761, 727, 714, 618, 584, 578, 544] # 24小时的负载
'定义模型及名称'
model = gp.Model('Cost-Based-DED')
'变量'
P_g = model.addVars(4, 24, vtype=GRB.CONTINUOUS, name='P_g')
# # 边界约束描述——方法1
# model.addConstrs((P_g[i, t]>=P_g_min[i] for i in range(4) for t in range(23)), name="Con_Pg_min")
# model.addConstrs((P_g[i, t]<=P_g_max[i] for i in range(4) for t in range(23)), name="Con_Pg_max")
# 边界约束描述——方法2
for i in range(4):
for t in range(24):
model.addRange(P_g[i, t], P_g_min[i], P_g_max[i], name="Con_Pg")
# 爬坡约束描述——方法1
# model.addConstrs((P_g[i, t] - P_g[i, t-1] <= RU_g[i] for i in range(4) for t in range(1, 24)), name="Ramp_UP1")
# model.addConstrs((P_g[i, t-1] - P_g[i, t] <= RD_g[i] for i in range(4) for t in range(1, 24)), name="Ramp_Down1")
# 爬坡约束描述——方法2
model.addConstrs((P_g[i, t+1] - P_g[i, t] <= RU_g[i] for i in range(4) for t in range(23)), name="Ramp_UP2")
model.addConstrs((P_g[i, t] - P_g[i, t+1] <= RD_g[i] for i in range(4) for t in range(23)), name="Ramp_Down2")
# # 发电负载功率平衡的描述——方法1
# model.addConstrs(P_g.sum('*', t) >= L_t[t] for t in range(24), name="Banlance1")
# 发电负载功率平衡的描述——方法2
model.addConstrs((gp.quicksum(P_g[i, t] for i in range(4)) >= L_t[t] for t in range(24)), name="Banlance2")
'目标函数'
T_C = gp.quicksum(a_g[i] * P_g[i, t] * P_g[i, t] + b_g[i] * P_g[i, t] + c_g[i] for i in range(4) for t in range(24))
model.setObjective(T_C, GRB.MINIMIZE)
'优化求解'
model.optimize()
# 计算排污成本——方法1
E_M1 = gp.quicksum(d_g[i] * P_g[i, t].x * P_g[i, t].x + e_g[i] * P_g[i, t].x + f_g[i] for i in range(4) for t in range(24))
# 计算排污成本——方法2
E_M2 = (gp.quicksum(d_g[i] * P_g[i, t] * P_g[i, t] + e_g[i] * P_g[i, t] + f_g[i] for i in range(4) for t in range(24))).getValue()
'输出结果'
print('The total emissions1 are:', E_M1)
print('The total emissions2 are:', E_M2)
print('The total operating costs are TC:'+str(model.ObjVal))
Part 3 编程技巧汇总
以下为本次编程中出现的多种方法集合,具体操作请看程序表达和Gurobi手册
- Tips 1: model.addRange() 定义变量边界的使用方法;
- Tips 2: 当模型中存在 t+1 或者 t-1时,for 循环的表示,尤其是range()的范围 ;
- Tips 3: x.sum() 表述变量求和的使用方法;
- Tips 4: EM是总排放成本,其结果是根据变量的最优解进行计算的,不属于本次优化模型的目标函数或者约束;
- Tips 5: EM的两种计算方法或者说通过变量最优解得到其他函数值的方法——注意 getValue()的使用方法;
Part 4 创作人员名单

参考文献
- A. Soroudi, Power System Optimization Modeling in GAMS.
往期内容回顾
11. 基于Distflow的最优潮流模型(OPF)–模型推导篇
10.火电机组经济调度建模及求解——基础篇
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——零基础学优化建模