☰
梯级水光互补系统期望最大化调度模型复现与Python实现
2026/10/10 3:44:00 网站建设 项目流程

梯级水光互补系统这个方向,最折磨人的往往不是公式本身,而是把一个写在纸面上的“期望最大化”目标,变成一个真正能跑、能调、能解释的调度模型。这篇复现我前后折腾了两周,踩了不少坑,把核心思路、建模取舍、Python实现细节和验证方法完整梳理一遍,给同样在啃EI论文复现的朋友一份可以直接抄作业的路线图。

先说清楚这个模型在解决什么问题。一条流域上有两座梯级水电站,上游水库调节能力较强,下游电站偏径流式,附近再配一座大型光伏电站,水电光伏打捆后通过一条容量有限的输电通道送出。晴天且光伏大发时,水电如果满发,通道容量不够,只能被迫弃水或弃光;阴天或晚上光伏出力为零,又得靠水电顶上。调度员要在日前决定未来24小时甚至96个时段里,每座水电站发多少电、蓄多少水、弃多少水,光伏能消纳多少。难点在于,明天光伏到底发多少是不确定的,任何基于单一预测值的确定性计划都是在“押宝”。这篇EI论文的核心思路,就是把光伏出力的不确定性用一组概率场景表示,然后让目标函数变成“期望可消纳电量最大化”,本质上是在所有可能的光照情形下,找到一套平均表现最优的调度方案。

这篇文章适合正在复现同类优化调度论文的研究生、做水光互补项目的工程师,以及想让自己的调度模型从“确定性”进阶到“不确定性优化”的人。我会按建模主线的顺序来讲:先拆解目标函数为什么这么构造,再展开梯级水电约束里最容易出错的滞时和线性化问题,接着讲光伏场景集怎么进模型,最后给出完整的Python实现框架和验证手段。

1. 为什么“最大化可消纳电量期望”值得单独复现一遍

1.1 短期调度问题的现实场景

先把问题边界固定下来。这里说的“短期”,指日前计划到日内滚动优化这个时间尺度,一般以15分钟或1小时为一个时段,优化周期24小时或96个时段。控制对象是梯级水电站群和一座光伏电站,它们共享同一条外送通道或同一个负荷区域。

通道容量是硬约束。通道能送多少电,决定了水电和光伏加在一起最多能消纳多少。当来水充裕、光伏又大发时,系统的发电潜力大于通道能力,必然有一部分清洁电量要废弃。调度的艺术,就是在不同时段之间分配有限的“通道资源”:是把水存起来等光伏落下去再发,还是现在就发满把光伏压掉一部分。这本质上是一个跨时段的资源分配问题,而光伏预测又给这个问题加了一层不确定性。

1.2 为什么不是“消纳量最大”,而是“期望最大”

如果光伏出力是已知的,问题就是一个标准的确定性线性规划,目标直接写成总消纳电量最大即可。但光伏预测不可能完全准确,尤其提前24小时看明天的云量,误差可能达到20%以上。此时若只用一个预测均值做优化,晴天实际出力高于预测时,通道可能被低估;阴天实际出力低于预测时,水电计划又可能过于激进,导致弃水。期望最大化则是给每种可能的光照情形一个概率权重,选一个在概率意义上最优的计划。

打个比方,你出门前看天气预报说有60%概率下雨、40%概率晴天,带伞的“期望收益”取决于两种天气下淋雨和拿伞的不便程度加权。光伏调度就是这个逻辑,只是把“淋雨”换成了“弃水弃光”,把“概率”换成了场景权重。

1.3 这篇模型和普通水电调度模型的差别在哪

常规水电短期优化调度,目标通常是发电量最大或蓄能最大,不确定性主要来自入库径流。这篇模型把光伏不确定性作为核心,水电作为调节资源来“补位”,两者通过共享的通道约束耦合在一起。所以复现时必须同时处理好三件事:梯级水电的水力联系、光伏场景的随机性表达、以及水电与光伏之间的竞争关系。缺了任何一块,模型就失去了“互补”的意义。

2. 建模第一步:期望目标与决策变量怎么挂钩

2.1 目标函数的数学形态

假设一共有 T 个时段,I 座梯级水电站,S 个光伏场景,场景 s 的概率为 p_s。模型的目标函数可以写为:

maximize J = Σ_{s=1}^{S} p_s · Σ_{t=1}^{T} [ Σ_{i=1}^{I} P_h(i,t) + P_pv_abs(s,t) ]

其中 P_h(i,t) 是第 i 座水电站在 t 时段的出力,P_pv_abs(s,t) 是场景 s 下 t 时段光伏被实际消纳的功率。这里有个关键细节值得注意:水电出力不带场景下标,光伏消纳带场景下标。

这个设计不是随意的。水电是日前计划决策,在光伏实际出力还没揭晓之前就要确定下来;而光伏消纳属于“事后调整”,可以在每个场景下根据实际出力决定是否弃光。所以水电决策对所有场景是公共的,光伏消纳则随场景不同而变化。这种“公共决策+场景相关调整”的结构,正好对应实际调度中“日前计划+日内修正”的两阶段逻辑。

2.2 期望与弃电惩罚的等价转换

最大化可消纳电量,等价于最小化期望弃电量,但这个等价关系只有在总发电潜力是外生给定的前提下才成立。光伏场景出力是外生参数,水电来水量也是外生参数,那么系统总可用电量固定,消纳得越多就意味着弃得越少。

工程上我更喜欢在目标函数里把弃电惩罚项显式写出来:

maximize J = Σ_s p_s Σ_t [ Σ_i P_h(i,t) + P_pv_abs(s,t) — C_w · Qspill_coeff(i,s,t) — C_v · P_pv_spill(s,t) ]

这里 Qspill 是弃水流量,P_pv_spill 是弃光功率,C_w、C_v 是惩罚系数。加惩罚项的好处是可以调节“保水”和“保光”的优先级,比如来水丰沛时弃光惩罚加重,枯水期弃水惩罚加重。复现论文时,先看原文目标函数是纯消纳量最大还是带惩罚,再决定用哪种形式。

2.3 决策变量与参数表

建模前先把所有量纲和符号固定下来,可以避免后面写代码时混乱。建议用下表做一张建模速查表:

符号含义单位类型
P_h(i,t)水电站 i 在时段 t 的出力MW决策变量
Q_out(i,t)水电站 i 的发电流量m³/s决策变量
Q_spill(i,t)水电站 i 的弃水流量m³/s决策变量
V(i,t)水电站 i 在时段 t 末的库容m³决策变量
P_pv_abs(s,t)场景 s 下时段 t 的光伏消纳功率MW决策变量
P_pv_fore(s,t)场景 s 下时段 t 的光伏预测出力MW参数
P_avail(t)时段 t 的通道可用容量MW参数
I_in(i,t)水电站 i 的区间入流m³/s参数
τ(i)从上游电站到下游电站的水流滞时时段参数

决策变量里最容易被忽略的是 Q_spill。很多人写水量平衡时只写“来水=发电流量+库容变化”,把弃水漏了,导致系统没有弃水通道,通道约束一紧就无解。这个问题我第5章还会详细讲。

3. 梯级水电四组约束:库容、流量、出力与水流滞时

3.1 水量平衡方程:梯级耦合的核心

每一座水电站的库容变化,由入流、出流和弃水决定。单站水量平衡是:

V(i,t) = V(i,t-1) + [ I_in(i,t) + Q_in_up(i,t) — Q_out(i,t) — Q_spill(i,t) ] · Δt

梯级耦合体现在 Q_in_up 上。对于梯级电站,上游电站的出库流量经过 τ 个时段的滞时之后,才会到达下游电站。数学上写成:

Q_in_up(i,t) = Q_out(i-1, t — τ) + Q_spill(i-1, t — τ)

这个滞时项是最容易写反的地方。我之前第一次建模就把下标写成了 t+τ,结果上游电站还没放水,下游库容就先涨了,调度计划完全失真。滞时的方向一定是“过去的上游出库决定现在的下游入库”。

Δt 的单位也要统一。如果流量单位是 m³/s,库容单位是 m³,一个时段的流量转换成水量要乘以 3600 秒(小时级时段)或 900 秒(15分钟级时段)。转换系数漏掉是最低级的错误,却非常常见。

3.2 库容、发电流量和出力限制

每组物理边界都是约束,缺一个模型就可能算出“超自然”的调度结果:

  • 库容上下限:V_min(i) ≤ V(i,t) ≤ V_max(i),对应水库死水位和正常蓄水位。
  • 发电流量上下限:Q_out_min(i) ≤ Q_out(i,t) ≤ Q_out_max(i),取决于水轮机过流能力。
  • 弃水流量非负:Q_spill(i,t) ≥ 0。
  • 水电出力上下限:P_h_min(i) ≤ P_h(i,t) ≤ P_h_max(i),对应最小技术出力和装机容量。

复制代码时这些都是直线约束,直接用线性库可以搞定。真正需要动脑的是出力与流量、水头之间的非线性关系,见 3.3。

3.3 出力函数与水头处理:先线性后精确

水电站出力公式是 P = η · ρ · g · H · Q,其中 H 是发电水头,由上下游水位差决定,而上下游水位又都跟库容有关。于是 P 与 Q、V 之间存在非线性关系,直接丢给线性求解器会报错。

复现时有两条路。第一条路是固定水头近似:假设调度期内水库水位变化不大,水头 H 近似取额定值,那么 P 与 Q 就是线性关系 P = k · Q。对短期调度来说,如果上游水库容量足够大、日水位变幅较小,这个近似的精度在可接受范围内。建议先跑通固定水头版本,再去升级精确模型。

第二条路是分段线性化。把水头 H 关于库容 V 的函数以及出力 P 关于 H 和 Q 的乘积项做 McCormick 松弛或 SOS2 分段线性逼近,转换成混合整数线性规划。这条路精度高,但模型规模大,求解时间成倍增加。我的建议是:复现初期先做固定水头,等模型和求解器都稳定了,再对照原文看看它是否用了分段线性化,按需加回来。

3.4 梯级约束汇总

把上面四组关系汇总成一张表,建模时逐条对照,不容易漏:

约束类型数学表达线性/非线性
水量平衡V(i,t) = V(i,t-1) + Δt·(入流 + 上游滞后出库 — 出库 — 弃水)线性
库容边界V_min ≤ V ≤ V_max线性
流量边界Q_min ≤ Q_out ≤ Q_max线性
出力边界P_min ≤ P_h ≤ P_max线性
出力-流量关系P_h = ηρgH·Q(固定水头时)线性近似
水流滞时上游出库经 τ 时段后进入下游线性,注意下标

我有一个实操习惯:把水量平衡方程单独拿出来,在代码里做一个“净流入校验函数”,算完一组结果后,用它检查每个时段每个电站的库容变化是否严格等于入流减出流。误差超过 1e-6 就说明约束拼错了,这是最快定位问题的方法。

4. 光伏场景集与弃电惩罚:随机性进入模型的正确姿势

4.1 光伏预测误差怎么变成场景

光伏出力的不确定性,通常用“预测值 + 误差扰动”来描述。常见的做法是假设误差服从正态分布或 Beta 分布,在此基础上用蒙特卡洛抽样或拉丁超立方抽样,生成大量光伏出力样本,再用场景削减算法筛出少量有代表性的场景。

具体操作是:先拿到一条光伏预测出力曲线 P_pv_pred(t),然后对每个时段施加扰动因子 ε(s,t),得到场景出力 P_pv_fore(s,t) = max(0, P_pv_pred(t) + ε(s,t)),或者用乘性扰动 P_pv_fore(s,t) = P_pv_pred(t) · (1 + ε(s,t))。扰动项的方差可以按时段设置,中午光伏大发时绝对误差大,早晚误差小。

场景削减这一步很多人图省事直接跳过,实际上非常关键。原始抽样可能有几百上千个场景,全部放进模型,变量数量爆炸,商用求解器也扛不住。用同步回代消除法或 K-means 聚类把场景缩减到 5 到 10 个,每个场景重新分配概率,就能在精度和计算量之间取得平衡。我实测下来,7 个左右场景基本能逼近几百个场景的期望值结果。

4.2 场景概率在目标函数里的正确位置

场景概率 p_s 必须出现在目标函数的加权项里,而且每个场景的目标贡献都要乘以对应概率,所有 p_s 之和等于 1。这里有个隐蔽的坑:如果每个场景的概率是通过削减算法得到的,有些场景可能只剩 0.03 之类的权重,调试时看着目标函数值“变小了”不要慌,那只是期望化之后量纲变了。

另外,如果只期望光伏消纳部分而忘记期望水电部分,会导致目标函数在概率加权上的不一致。正确做法是先写出完整的 J(s) = Σ_t [ Σ_i P_h(i,t) + P_pv_abs(s,t) ],再整体乘以 p_s 求和。水电出力虽然是公共决策,但在求期望时它同样出现在每个场景里,相当于它的系数是 Σ_s p_s = 1,所以最终水电部分不会被概率稀释。这一点在写代码时很容易无意识弄错。

4.3 通道约束与弃电逻辑

通道约束表达为:

Σ_i P_h(i,t) + P_pv_abs(s,t) ≤ P_avail(t)

这个约束对每个场景 s 都要成立。注意 P_h(i,t) 是公共变量,不随场景变化,所以它的可行性必须对所有场景同时保证。如果某个场景下光伏预测出力很高,而水电计划已定的情况下压不掉,那就只能靠弃光来实现约束,也就是让 P_pv_abs(s,t) 小于 P_pv_fore(s,t)。

所以在每个场景下还需要满足:

0 ≤ P_pv_abs(s,t) ≤ P_pv_fore(s,t)

P_pv_abs 与预测上限之间的差值,就是该场景下的弃光功率。是不是需要显式定义弃光变量,取决于你目标函数里要不要给它加惩罚。如果目标函数里只有消纳电量最大化,那 P_pv_abs 会自动尽量取大,弃光变量可加可不加;一旦要调弃光惩罚系数,就必须把弃光变量显式写出来。

5. Python完整求解流程:数据准备、模型构建与求解器调优

5.1 数据准备:没数据怎么复现

EI论文复现第一步卡住的往往是数据。真实电站的径流序列、水库参数、光伏出力数据属于生产数据,通常拿不到。但复现的目的是验证模型逻辑,不是复刻真实电站的精度,所以完全可以用公开的模拟数据或合成数据。

我的做法是:先按典型参数构造一个两库一光的小系统。上游水库总库容 2 亿 m³,死库容 5000 万 m³,发电流量上限 200 m³/s;下游水库库容 5000 万 m³,发电流量上限 250 m³/s;光伏装机 300 MW,通道容量取 400 MW。入库径流用一条带季节趋势的正弦曲线加随机扰动生成;光伏预测出力用一条典型的“中间高早晚低”曲线生成,再按 4.1 节的方法生成场景。

数据准备脚本可以单独放在一个模块里,输出一个字典或 CSV 文件。建议所有参数集中管理,不要散落在模型代码里,否则后面调参数会很痛苦。

5.2 模型构建代码骨架

我用 PuLP 来演示核心建模思路,因为它开源、语法清晰、对教学友好。完整代码框架如下:

import pulp as lp import numpy as np # === 参数设置 === T = 24 # 时段数 I = 2 # 梯级水电站数量 S = 7 # 光伏场景数 dt = 3600 # 秒/时段 p_s = np.array([0.2, 0.15, 0.15, 0.15, 0.15, 0.1, 0.1]) # 场景概率,需和为1 P_avail = np.linspace(350, 400, T) # 通道可用容量 # 水电站参数(示意) Q_out_max = [200, 250] # m3/s Q_out_min = [0, 0] V_max = [2e8, 5e7] # m3 V_min = [5e7, 1e7] V_init = [1.2e8, 3e7] k_head = [8.5, 7.2] # 固定水头下的出力系数 MW/(m3/s) tau = [0, 2] # 水流滞时,下游电站滞后2个时段 I_in = np.random.uniform(80, 120, size=(I, T)) # 区间入流,示意 P_pv_fore = np.random.uniform(0, 250, size=(S, T)) # 光伏场景出力 # === 构建模型 === model = lp.LpProblem("Expected_Max_Absorption", lp.LpMaximize) # 决策变量 P_h = {} Q_out = {} Q_spill = {} V = {} P_pv_abs = {} for i in range(I): for t in range(T): P_h[i, t] = lp.LpVariable(f"P_h_{i}_{t}", lowBound=0) Q_out[i, t] = lp.LpVariable(f"Q_out_{i}_{t}", lowBound=Q_out_min[i], upBound=Q_out_max[i]) Q_spill[i, t] = lp.LpVariable(f"Q_spill_{i}_{t}", lowBound=0) V[i, t] = lp.LpVariable(f"V_{i}_{t}", lowBound=V_min[i], upBound=V_max[i]) for s in range(S): for t in range(T): P_pv_abs[s, t] = lp.LpVariable(f"P_pv_abs_{s}_{t}", lowBound=0, upBound=P_pv_fore[s, t]) # 目标函数:最大化期望可消纳电量 objective = 0 for s in range(S): for t in range(T): scenario_value = sum(P_h[i, t] for i in range(I)) + P_pv_abs[s, t] objective += p_s[s] * scenario_value * dt / 3600 # 换算成电量 MWh model += objective # 约束:水量平衡与梯级耦合 for i in range(I): for t in range(T): inflow = I_in[i, t] if i > 0 and t - tau[i] >= 0: inflow += Q_out[i-1, t - tau[i]] + Q_spill[i-1, t - tau[i]] if t == 0: model += V[i, t] == V_init[i] + (inflow - Q_out[i, t] - Q_spill[i, t]) * dt else: model += V[i, t] == V[i, t-1] + (inflow - Q_out[i, t] - Q_spill[i, t]) * dt # 约束:水电出力与流量关系(固定水头线性化) for i in range(I): for t in range(T): model += P_h[i, t] == k_head[i] * Q_out[i, t] model += P_h[i, t] <= 300 # 装机容量约束 # 约束:通道容量 for s in range(S): for t in range(T): model += sum(P_h[i, t] for i in range(I)) + P_pv_abs[s, t] <= P_avail[t] # 求解 solver = lp.PULP_CBC_CMD(msg=1, timeLimit=60, gapRel=1e-4) model.solve(solver) print("Status:", lp.LpStatus[model.status]) print("Objective (MWh):", lp.value(model.objective))

这段代码是一个可以跑通的最小骨架,把目标函数、水量平衡、梯级滞时、通道约束全部包含了。注意目标函数里我按 dt/3600 把功率换算成了电量,因为可消纳“电量”的单位是 MWh,不是 MW。

5.3 求解器选型:从小规模演示到工程级

PuLP 默认自带的 CBC 求解器,处理上百万变量的模型不太行,但对复现这类小规模问题足够。如果你的场景数多、分段线性化后引入了整数变量,建议换成 Gurobi 或 CPLEX 这类商用求解器。在 Python 里只需要把 solver 换成对应接口,模型定义部分基本不用动。

求解性能的瓶颈主要来自场景数。S 个场景会把通道约束和光伏消纳约束复制 S 倍,变量数量差不多也乘以 S。我实测过一个 96 时段、2 座水电站、20 个场景的模型,CBC 要跑几分钟;缩减到 7 个场景后,几十秒内就能收敛。因此性能优化的第一手段永远是场景削减,其次是设置合理的求解时间上限和 MIP gap,而不是盲目加机器。

5.4 结果导出与可视化

算完之后一定要把关键结果落盘,方便后续分析。我的习惯是把每个时段的 P_h、P_pv_abs、弃光量、库容轨迹、弃水量整理成 DataFrame,再导出 CSV。可视化用 Matplotlib 画三张图:第一张是水电光伏消纳堆叠图,看互补关系;第二张是库容轨迹图,看调度有没有违反边界;第三张是弃电功率曲线,看弃电集中在什么时段。

这三张图能快速暴露建模问题。比如如果你发现弃电集中发生在光伏大发时段,而水电出力仍然很高,那就是目标函数里弃光惩罚权重太低,水电不肯让路;如果库容曲线在某几个时段贴着上限走,说明通道约束太紧或水电出力上界设小了。

6. 复现中的关键坑与验证方法:从结果反推建模漏洞

6.1 坑一:水流滞时方向写反

这个我在 3.1 提过一次,但值得单独强调。很多初版模型的写法是“下游电站 t 时段的入库等于上游电站 t+τ 时段的出库”,这等于让下游提前预支了未来才到的水,水量平衡从根上就错了。检查方法很简单:把上游出库序列设成一个脉冲,看下游库容响应是不是在 τ 个时段之后才开始变化。如果立即变化,滞时写反了。

6.2 坑二:目标函数里的期望被重复计算

还有一种隐蔽的逻辑错误,是把场景概率同时乘到了公共决策和场景决策上,导致目标函数量纲混乱。比如有人写 objective += p_s * sum(P_h) 之后再写 objective += p_s * sum(P_pv_abs),看起来没问题,但 P_h 部分是公共变量,它本来就会被所有场景计算一次,等价系数是 Σp_s = 1,现在额外乘了 p_s,相当于把水电电量按概率打折了。检查方法是把 S 设为 1、p_s 设为 1,目标值应该等于确定性模型的总消纳电量。如果不等于,说明加权写错了。

6.3 坑三:固定水头近似在部分时段严重失真

固定水头版本在库容变化剧烈时会有明显偏差。上游水库如果从高水位降到低水位,实际出力比线性模型算出的要低,可能导致结果过于乐观。验证方法是把固定水头模型的 P_h 反代回真实水头公式,算一个“实际出力”,然后对比模型出力。两者偏差超过 5% 时,就得考虑升级成水位-库容曲线分段线性化。

6.4 模型验证:不能只跑出一组好看的数字就完事

复现论文时,我习惯按下面这个清单做验证:

  • 约束残差检查:水量平衡每天的累计误差应接近 0,通道约束所有场景下应严格满足。
  • 与确定性模型对比:把光伏场景数设为 1 且取期望预测值,跑一个确定性版本,比较它的目标值和期望模型的目标值。期望模型的目标值理论上不高于“完美预测”的确定性上界,也不低于最保守模型的取值。
  • 灵敏度测试:把光伏预测误差方差调大,期望可消纳电量应当下降或不变,如果反而上升,说明模型在“利用”不确定性套利,通常是有问题的。
  • 边界测试:通道容量无穷大时,目标值应等于总可用电量;通道容量为 0 时,目标值应为 0。两个极端场景能快速检验模型的物理一致性。
验证项目操作方式预期结果
水量平衡残差逐时段计算入流减出流减库容变化接近 0
确定性对照单场景预测均值模型 vs 期望模型期望模型值介于保守与完美预测之间
边界测试通道容量取 0 和无穷大目标值为 0 和可用电量上界
滞时测试上游脉冲出库,观察下游响应响应滞后 τ 个时段

6.5 常见问题排查表

现象可能原因排查思路
模型无解通道容量过紧且无弃电变量检查 Q_spill 和 P_pv_abs 是否配了上界
目标值异常大电量换算系数错误核对 dt/3600 是否漏乘或重复乘
库容长期贴着下界水电出力下限设置过高调低 P_h_min 或检查出力系数
光伏消纳总是等于预测值通道约束没生效或场景概率异常打印各场景下通道松弛量
求解时间过长场景数过多或整数变量过多场景削减,调整 SOS2 分段数

7. 代码模块复盘与可以继续深挖的方向

7.1 模块划分的经验

我的复现代码一般拆成四个模块:data.py 负责参数与场景生成,model.py 负责定义变量和约束,solve.py 负责调用求解器和保存结果,analyze.py 负责指标计算和绘图。这样划分的好处是,想换一组数据或换一个求解器时,不需要动模型定义;想改目标函数时,也不需要碰数据生成。

写模型文件时,建议把目标函数、水量平衡、通道约束分别封装成函数。后期扩展成滚动优化时,只需要在主循环里反复调用这些函数,每次滚动更新初值,不必复制粘贴整个模型。

7.2 扩展方向一:两阶段随机规划加非预期约束

本文骨架里水电决策对所有场景是公共的,本质是“日前计划固定”。如果想更精细地模拟日内滚动修正,可以引入两阶段随机规划:第一阶段决定水电出力,第二阶段根据光伏场景调整弃光量和弃水量,并通过非预期约束保证第一阶段决策不依赖具体场景。这个方向与当前骨架的差异主要在场景树的构建上,值得深入。

7.3 扩展方向二:鲁棒优化替代期望优化

期望最大化关心的是平均表现,不保证极端场景下的可消纳电量。如果实际调度更关注“最坏情况下的底线”,可以把光伏出力集合改成盒式不确定集或椭球不确定集,目标改成最大化最坏场景下的可消纳电量。鲁棒模型会牺牲一定的平均消纳量,换来对极端天气的抵抗能力。两种模型跑一次对比,你会对“风险偏好”在调度模型里的体现有非常直观的感受。

7.4 扩展方向三:考虑碳约束或市场电价

如果系统运行在电力市场环境下,目标函数可以选择把“期望消纳电量”替换成“期望收益”,并叠加碳价或绿证收益。梯级水电的蓄水决策会从“物理上能消纳多少”变成“经济上值不值得在这个时段发”,模型的性质就完全不一样了。这个方向对已经有电力市场背景的读者会更有吸引力。

复现这篇模型的过程中我最深的体会是,不确定性优化模型的难点从来不在求解器,而在“哪些决策先定、哪些决策后定”这个问题上。结构设对,模型才有物理意义;结构设错,再精致的算法也只是花哨的错误。希望这份路线图能帮你少走我之前走过的弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询