
晚上七点半微网里的风电出力开始往下掉负荷却往上蹿。我当时用的还是那套经典的确定性日前调度24小时计划排得满满当当结果一遇到这种预测偏差只能临时手动切燃气轮机、拉储能折腾下来成本超预算15%还差点甩掉一片负荷。后来我把调度框架换成两阶段鲁棒微网优化调度配合关键场景辨别算法去刻画不确定性才把这类风险真正压住。这篇东西我不打算写成教材就把我在Matlab里从建模、求解到调通的全过程连同踩过的坑一次性说清楚。文章面向正在研究微电网优化调度、两阶段鲁棒优化或者拿Matlab做论文仿真但被CCG迭代卡到怀疑人生的同学也适合想弄清楚鲁棒优化到底怎么落地的工程师。1. 为什么微网调度要搞两阶段还要鲁棒从一次晚间负荷突变聊起的问题1.1 确定性调度的短板预测误差下为什么总在救火先看传统做法。我们把微网里的风电、光伏、负荷都当成已知参数建一个混合整数线性规划MILP求解让总运行成本最小的出力计划。这个模型本身没毛病而且在预测完全准确的时候结果也确实漂亮。问题在于真实世界里风电出力是波动的负荷预测总有偏差光伏更是每分钟都可能被云层遮住。一旦实际值和预测值对不上日前排好的计划就变成了纸面方案。我举一个实际案例。某天晚间19点到22点天气预报的风速比实际偏高40%光伏在18点半后已经归零负荷却因为突然降温比预测高出8%。按照确定性模型最优方案是让燃气轮机在低谷时段多发电、储能低谷充电高峰放电。但实际运行时燃气轮机爬坡速率跟不上负荷突增储能又在高峰段被计划排满最后只能紧急调用柴油机补电——单小时成本翻了快三倍。这不是模型算法错而是模型本身假设了一个不会出错的世界。业内处理不确定性的主流路线有两条随机优化stochastic programming和鲁棒优化robust optimization。随机优化要给不确定性变量配概率分布然后搞场景树场景一多计算量爆炸而且微网里风电、光伏、负荷的联合分布你根本拿不到准确数据。鲁棒优化的思路更蛮横我不赌概率我把所有可能的不确定性范围圈起来在这个范围里找出最坏的情况然后保证这个最坏情况下系统也能安全运行且成本可控。这就是两阶段鲁棒微网优化调度的核心动机。1.2 两阶段决策的真实含义日前计划与实时调整的分工两阶段不是玄学它对应的是微网运行中真实存在的两个决策层次。第一阶段这里统一叫主问题决策发生在日前做的是那些定了就很难改的决定哪些燃气轮机明天开机、哪些停机储能的充放电状态怎么安排与上级电网的购电协议要不要签。这些决策的特点是带二进制变量要么0要么1一旦定了之后日内一般不轻易翻转。第二阶段子问题决策发生在日内实时做的是在开机状态和储能状态都锁死的前提下各台机组实际发多少电、储能实际充放多少功率、从电网买多少电。这一层的变量是连续的类似经济调度的出力分配。这样的分层其实很符合微网的实际操作习惯日前做机组组合日内做经济调度。两阶段鲁棒模型把不确定性放进了第二阶段——假设第一阶段决策已经做出不确定性在第二阶段显现系统做最坏情况下的最低成本调整。我们优化的目标是让第一阶段成本 第二阶段最坏场景下的最低运行成本之和最小这就是典型的min-max-min结构。1.3 鲁棒优化和随机优化的差别不需要精确概率分布接着上面说的随机优化的结果是一个期望成本它隐含假设你知道每个场景的概率。鲁棒优化不需要这个假设它只需要一个不确定集——就是不确定性变量可能的取值范围。比如风电出力的预测值是50kW允许偏差±10%那不确定集就是一个盒式区间。你在这个区间里找最坏情况然后保证它发生系统也不出事。代价是鲁棒优化通常比随机优化保守毕竟它只盯着最坏场景。但如果不确定集构造合理比如加一个预算约束Γ限制最坏情况不会在所有时段同时发生保守程度会被大幅压缩。这个预算约束我用下来是对工程实用性影响最大的参数之一后面会专门讲怎么调。2. 两阶段鲁棒优化的数学骨架min-max-min结构、不确定集与对偶转换2.1 目标函数和约束怎么拆成主问题子问题两阶段鲁棒的标准形式我用代码块把它表达出来因为纯文本写公式容易糊目标函数 min_x ( c^T * x max_{u ∈ U} min_{y ∈ Ω(x, u)} d^T * y ) 第一阶段约束 A * x ≥ b x ∈ {0,1}^p × R^n 第二阶段约束对给定x和u Ω(x, u) { y | B * y ≥ h - C * x - D * u, y ≥ 0 }这里x代表第一阶段决策u是不确定性向量y是第二阶段连续决策。整个问题的难点在于中间那个max-min对于每个x你得先找到让y最优目标值最大的那个u最恶劣场景再算这个场景下y的最小成本。这在计算上不是一个可以直接丢给求解器的问题得拆。最常用的拆法是列约束生成算法CCGColumn-and-Constraint Generation。CCG的套路是先不管u只针对一个初始场景u1求解第一阶段问题得到一组x把x代入第二阶段求解max-min子问题找到最恶劣场景u*如果这个u对应的目标值还没达到收敛条件就把关于u的约束和变量加到主问题里重新求解x。如此反复迭代直到上界和下界之差小于容忍度。2.2 不确定集的选择盒式、椭球式与预算约束不确定集决定了鲁棒优化的防守范围。我常用的有三种。最基础的是盒式不确定集形式是u ∈ [u_mean - Δu, u_mean Δu]每个时刻的偏差独立最大偏差Δu根据历史预测误差统计得到。优点是建模简单缺点是太保守——如果风电和负荷在24个时段都取到最坏偏差那运行成本会高得离谱工程上根本接受不了。改进方案是加预算约束Γ。还是盒式集合但限制偏差的总量不超过一个阈值。比如Γ 4含义是整个调度周期内至多4个时段的不确定性同时取到边界值。这样既保留了对极端情况的防护又不会让所有时段一起背锅。Γ的值一般取调度时段数的15%到30%我系统测试下来Γ取524时段系统时成本比Γ取24要低不少且失负荷概率仍然很低。椭球不确定集更平滑但会引入二阶锥约束求解负担变大。我的经验是工程调度用盒式预算约束性价比最高除非你的微网里储能占比很大、需要精细刻画相关性才值得上椭球。2.3 子问题里max-min怎么通过强对偶变成可求解的单层问题第二部分子问题是个双层优化内层对y求min外层对u求max。YALMIP不能直接处理这种嵌套结构所以得把它转化成单层问题。核心工具是线性规划的强对偶定理或者更通用的KKT条件。因为内层对y的线性规划是凸的满足强对偶条件我可以把内层的min_y问题替换成它的对偶问题max_λ于是max-min变成max_{u∈U} max_{λ ≥ 0} λ^T * (h - C*x - D*u)把两个max合并就变成一个在(u, λ)上联合求max的线性问题可以直接丢给Gurobi或CPLEX求解。这里有三个关键点第一这要求第二阶段问题里y的系数矩阵不包含二进制变量否则强对偶不成立。如果模型里第二阶段也有启停变量或者储能状态变量你得先用大M法或者把它提升到第一阶段加以线性化否则对偶间隙会直接弄崩收敛精度。这点我在第5章会重点展开。第二对偶变量λ本身是无约束的但要保证对偶问题有界需要加上内层原始问题约束对应的对偶可行域约束写代码时别忘了把对偶变量符号约束对应好。第三子问题求出的最优u*就是当前x下的最恶劣场景它的目标函数值加上第一阶段成本构成原始问题的上界UB。主问题每次迭代求解得到的x和对应目标值因为约束少于原始问题给出的则是下界LB。迭代就是不断缩小UB-LB的间隙。3. 关键场景辨别算法它不是在挑场景而是在给CCG做瘦身3.1 CCG列约束生成的标准流程我先描述一下CCG的标准循环大家都熟悉初始化把不确定变量u固定到某个初始场景比如预测平均值求解主问题MP得到x和LB的候选值。把x代入子问题SP求解max-min得到最恶劣场景u和SP的目标值。此时UB c^Tx SP目标值。若UB - LB ε停止否则把u*对应的第二阶段变量及其约束加入MP回到第1步。逻辑上很简单。它最大的优势是每次迭代加入的是整段约束变量比经典的Benders分解只加一条割线要紧得多所以收敛次数通常远少于Benders。我用下来大多数24时段系统CCG在5到15次迭代内能收敛而Benders往往需要几十上百次迭代。3.2 为什么切割会越加越多、主问题越解越慢CCG有个很实际的问题每轮子问题都会产出一个最恶劣场景这些场景会被全部加进主问题主问题的规模会随迭代次数线性膨胀。你听上去每次只多一个场景好像无所谓但主问题是含有二进制变量和几百条约束的MILP每多一个场景就是几十个变量和几十条约束。迭代到第八轮、第十轮的时候MP的求解时间会从几秒变成几分钟整个算法在算力上就僵住了。更麻烦的是很多场景其实长得差不多。比如风电出力最恶劣的情况可能连续几轮迭代解出的u*都是第7时段和第13时段取上界只是其他时段的微调不同。这些场景对约束的贡献高度重叠把它们全部加进MP等于把大量冗余约束堆进模型白花钱。关键场景辨别算法要解决的就是这个问题。它的思路很直接在把子问题解出的场景加入MP之前先做一次筛选体检只放那些对解有实质影响的新鲜场景进去。3.3 关键场景辨别的判据设计与场景库管理我用的判据分为三个层面第一层是场景重复度。维护一个场景库S里面存着所有已经加入MP的场景。每轮SP解出新的u*先计算它与场景库里每个场景的归一化欧氏距离dist ||u* - s_i|| / ||s_i||如果最小距离小于一个阈值ε_s我通常取0.05就认为这个场景和库里的某个场景在结构上几乎相同直接丢弃不更新MP。这能杜绝大量换汤不换药的重复切割。第二层是目标值增益。即使场景不重复也要看它对这个x到底狠不狠。计算该场景下SP的目标值也就是如果加入该场景会给MP带来的约束强度与当前LB之间的相对提升幅度。如果提升幅度小于0.5%说明这个场景虽然新但对优化方向没有实质影响可以延迟或者丢弃。第三层是紧约束检测。这一步更精细SP求解完会给出对偶乘子乘子里数值较大的那部分意味着当前x在该场景下卡得很紧。如果一个场景对应的最大对偶乘子都很小说明即使这个场景发生第一阶段决策也毫不费力那它就不构成有效约束。用这个指标可以进一步过滤。我最后实现的流程是SP解出u* → 重复度检查 → 目标增益检查 → 紧约束检查 → 决定是否加入MP和场景库。三重门槛全过才更新MP。实测在24时段微网算例中标准CGG需要12轮、往MP加了12个场景加了辨别后只加了5个场景就收敛MP单轮求解时间从峰值17秒降到6秒总计算时间大概缩短了40%。3.4 算法收敛与计算时间对比一个简单算例的直观感受简单看一组来自我算例测试的对比数据微网含1台燃气轮机、1套储能、风电场、负荷24时段Gurobi 9.5作为求解器策略迭代次数加入MP的场景数总求解时间最终UB最终LB标准CCG1212约210秒12640.512639.8关键场景辨别CCG75约95秒12640.212639.6两条路线最终目标值几乎一样说明辨别算法没有牺牲精度但把计算时间砍掉了一半多。对小规模系统你体感不强一旦微网节点数上百、或者把时序运行耦合约束加进来这个差距会被放大到小时级别。4. Matlab代码实现的关键环节YALMIP建模、MP/SP迭代与场景库动态更新4.1 工作环境与求解器配置我的环境是Matlab R2022b YALMIP Gurobi。YALMIP负责把优化问题建模成高层的数学表达式Gurobi负责实际求解MILP和LP。如果你手头没有GurobiCPLEX也行甚至Mosek都能跑大部分步骤不过子问题SP里那个大M法线性化部分Mosek处理起来会比Gurobi略慢我测过不算大问题。安装之后先跑一下自检yalmiptest;确保Gurobi和YALMIP之间通信正常。一个容易踩的坑是Gurobi版本和YALMIP不兼容表现是solve函数报Output too long或者Unknown solver。我建议Gurobi 9.x配合YALMIP R20200516以上的版本别用太旧的YALMIP。4.2 主问题MP的建模与切割追加方式主问题MP本质上是一个带离散变量的大MILP。建模代码如下省略具体参数赋值思路是结构性的% —— 主问题MP建模 —— x_s binvar(n_gen, T); % 机组开停状态 p_g sdpvar(n_gen, T); % 各机组出力 p_es sdpvar(2, T); % 储能充放功率 cost_second sdpvar(1); % 第二阶段成本变量 % 目标第一阶段成本 第二阶段成本变量 objective sum(sum(cost_start * max(0, diff(x_s,1,2)))) ... sum(sum(c_gen .* p_g)) sum(p_es(1,:).*c_ch p_es(2,:).*c_dis) cost_second; Constraints []; Constraints [Constraints, % 机组出力上下限 p_g repmat(P_G_MAX,1,T) .* x_s, ... p_g repmat(P_G_MIN,1,T) .* x_s]; % 储能约束 Constraints [Constraints, SOC(:,2:end) SOC(:,1:end-1) p_es(1,:)*eta_ch - p_es(2,:)/eta_dis]; Constraints [Constraints, SOC(:,1) SOC_init, SOC SOC_min, SOC SOC_max];关键的切割追加逻辑在迭代循环里。每次SP解出一个新场景u_k我就往MP里加一组对应这个场景的等式约束、不等式约束和变量p_g_k sdpvar(n_gen, T); % 该场景下的机组出力 p_es_k sdpvar(2, T); % 该场景下的储能功率 p_buy_k sdpvar(1, T); % 该场景下的购电功率 Constraints [Constraints, % 功率平衡负荷 各类电源出力 储能放电 - 充电 购电 p_load - u_k .* p_wind sum(p_g_k,1) p_es_k(2,:) - p_es_k(1,:) p_buy_k, p_g_k repmat(P_G_MAX,1,T) .* x_s, p_g_k repmat(P_G_MIN,1,T) .* x_s, % …… 其余约束类似 ];这里有个坑MP里新加的第二阶段变量p_g_k等必须和已有的x_s等第一阶段变量通过约束关联起来否则它只是被塞进模型对x_s产生不了约束力切割等于白加。4.3 子问题SP的KKT/强对偶转换在Matlab里的落地子问题SP求解是整篇代码里最容易写错的地方。我的做法是先写出内层规划的对偶问题然后用对偶变量作为新的优化变量和u一起做联合求解。如果内层问题是纯LP对偶问题可以手推。比如内层问题给定x和u是min_y d^T y s.t. B y ≥ h - C x - D u , y ≥ 0其对偶是max_λ λ^T (h - C x - D u) s.t. B^T λ ≤ d λ ≥ 0于是SP变成一个在(u, λ)上的联合LPmax_{u, λ} λ^T (h - C x - D u) s.t. B^T λ ≤ d λ ≥ 0 u ∈ U这个形式在Matlab里直接用YALMIP写就行% —— 子问题SP强对偶转换后 —— lambda sdpvar(n_con, 1); % 对偶变量 u_var sdpvar(n_unc, 1); % 不确定变量 % 不确定集盒式预算约束 Constraints_SP [Constraints_SP, u_mean - u_dev u_var u_mean u_dev, sum(abs(u_var - u_mean) ./ u_dev) Gamma]; % 对偶可行域 Constraints_SP [Constraints_SP, B * lambda d, lambda 0]; % 目标max λ^T (h - C*x_fixed - D*u_var) Objective_SP -lambda * (h - C*x_fixed - D*u_var); % 注意YALMIP是求min所以取负号 optimize(Constraints_SP, Objective_SP, sdpsettings(solver,gurobi));如果你不想手推对偶也可以用KKT条件把内层问题作为约束放进SP配合互补松弛的线性化。这个做法不用求对偶表达式但会引入更多变量和非线性项我一般只在内层问题比较复杂、手推对偶容易出错时才用。4.4 收敛判据、初始场景选择与关键代码框架CCG的收敛判据是UB-LB小于容忍度ε。UB是SP目标值加上第一阶段成本LB是MP目标值。迭代主体我用伪代码形式放出来% 初始化 x_current []; UB inf; LB -inf; k 0; quiesce false; while (UB - LB) epsilon ~quiesce k k 1; % 求解MP optimize(MP_Constraints, MP_Objective, MP_options); LB value(MP_Objective); x_current value([x_g, x_es]); % 取出第一阶段决策 % 求解SP optimize(SP_Constraints, SP_Objective, SP_options); SP_obj -value(SP_Objective); % 还原符号 UB_temp value(objective_first) SP_obj; if UB_temp UB UB UB_temp; end u_star value(u_var); % 最恶劣场景 % —— 关键场景辨别 —— if ~isKeyScene(u_star, scene_set, epsilon_s) || ... (UB_temp - LB) / LB epsilon_gain % 不加入MP继续下一轮 quiesce true; % 或者进入更精细的局部搜索 continue; end % 加入新场景和对应变量约束到MP scene_set [scene_set, u_star]; end初始场景怎么选对收敛速度影响很大。我的经验是用预测均值场景也就是u u_mean先让系统在最乐观的情况下给出一个初始x。这个阶段MP求解很快得到的x比较平滑。之后SP再去找这个x下的最恶劣场景逐轮逼近。比随机初始化收敛稳定得多。还有一个细节SP问题规模不大但有时会因为对偶变量过多而变慢。可以预先在MP里把所有对偶变量的索引整理成一个稀疏矩阵传入Gurobi别让YALMIP动态扩维。5. 我在调试中踩过的坑二进制变量、对偶间隙与伪收敛5.1 子问题里的二进制变量怎么处理大M法与二进制展开这是新手最容易卡死的地方。如果你的微网模型里储能充放电状态、机组启停状态这些二进制决策出现在第二阶段子问题中——比如实时调度还要决定储能是充还是放——那么内层min问题就不是一个LP而是MILP强对偶定理不成立你没法直接转换成单层max-λ形式。我踩过一次很惨的坑直接把MILP子问题扔进CCG用Gurobi的默认解算UB和LB怎么都收敛不到同一个值差了大概2.7%。排查后发现是SP里含二进制变量对偶转换出来的对偶间隙根本绕不过去。解决办法有两种第一种是大M法。把第二阶段里的二进制变量全部线性化掉比如储能充放电的互斥约束p_ch p_dis ≤ M * z_statez_state是0/1变量然后再做对偶转换时把这部分约束换成它的对偶约束。这个大M要选得足够大但不至于破坏数值稳定性M取该机组最大出力或储能最大功率的3到5倍我一般这样定。第二种是二进制展开法。把第二阶段二进制变量从子问题中提出来放到第一阶段去或者在每次迭代求解子问题时把x_fixed当作参数、枚举部分典型组合来生成场景。这种方法在二进制变量少的时候可行变量一多就会让场景数量爆炸。我的最终建议是尽量重新审视模型划分把可能改变系统拓扑结构的离散决策机组启停、储能状态统一放到第一阶段第二阶段只保留连续变量的经济分配。这样两阶段鲁棒模型才干净也最符合微网实际运行逻辑——日前确定运行方式日内只做连续功率调整。5.2 为什么UB-LB卡住不动切割失效的典型原因我调试CCG时遇到过最诡异的现象是迭代三轮之后UB和LB完全卡住两个数字在小数点后两位都不变化了。表面上看是收敛但实际上UB比真实最优高了一大截是典型的伪收敛。后来排查发现问题出在MP里追加的第二阶段变量没有和第一阶段变量形成足够强的耦合约束。具体来说我在第4.2节写的那个功率平衡等式里把u_k参与的地方写错成常量了——风电出力直接用了预测值导致场景变化根本不影响MP约束结构。SP每次返回的u*虽然不同但MP根本不感知这些场景所以LB一直停在同一个值上。这是个非常隐蔽的bug。排查方法很简单看每个场景加入后LB有没有实质变化。如果连续两个不同的极端场景加进去、LB纹丝不动那几乎可以确定切割约束是失效的赶紧检查追加的约束和变量是否正确关联了x_s。另一个常见的原因是场景重复太严重。SP每次返回的u*只在两个数值上变动MP的信息量早就饱和了。这种就要靠关键场景辨别里的重复度检查来提前拦截否则白白多迭代好几轮。5.3 关键场景辨别阈值怎么调太小没效果、太大丢精度阈值ε_s和ε_gain过小辨别算法形同虚设场景还是会大量涌入MP过大又会把真正紧约束的场景过滤掉导致UB-LB虽然收敛快但收敛到的解严重偏离真实最优。我的标定经验是用历史几轮SP的场景轨迹做统计。先跑一轮完整的标准CCG把每轮场景的归一化欧氏距离和目标值增益记录下来。取中位数和分位数作为初始阈值。对我来说ε_s取0.03到0.08之间比较合适ε_gain取0.002到0.01之间0.5%左右。然后对比同一算例在不同阈值下的最终UB挑UB相对变化不超过0.1%的最大阈值。这样既保证精度又保证速度。这里放一个测试小表ε_sε_gain迭代次数场景入库数最终UB相对标准CCG偏差0.010.001121012640.50.00%0.050.0057512640.2-0.002%0.150.024212895.32.02%第三组参数明显丢精度了所以阈值不是越大越好得卡在中间区间。5.4 求解器数值问题YALMIPGurobi的精度参数注意点鲁棒调度模型里经常出现量级差异巨大的系数比如成本系数是几百设备容量是几万千瓦对偶变量可能小到10^-4这种数值差异会让Gurobi内部单纯形法出现数值警告。我建议在sdpsettings里显式设置几个参数opts sdpsettings(solver,gurobi, ... gurobi.MIPGap, 1e-4, ... gurobi.OptimalityTol, 1e-6, ... gurobi.FeasibilityTol, 1e-6, ... gurobi.NumericFocus, 2);更重要的预处理是把成本除以100或1000、功率以MW为单位、成本系数单位统一到元/MW避免出现10^6级别的巨大数值。我遇到过一次MP求解器返回Success但结果明显不对打开Gurobi日志发现模型有数值警告就是因为风电和负荷功率用了W为单位数值太大导致Presolve直接把一堆约束误删了。这种错误极难发现只能靠这个经验提前规避。6. 拿到调度方案之后怎么用蒙特卡洛验证它真的鲁棒6.1 后验评估流程别让鲁棒优化变成纸上盾牌优化求解收敛不等于方案可信。我每次跑完两阶段鲁棒一定会再做一次蒙特卡洛后验评估根据风电和负荷预测误差的历史分布随机生成2000组不确定性场景注意这些场景可以超出你设定的不确定集范围用来测试方案的安全感然后把鲁棒调度方案的第一阶段决策x固定下来逐个场景求解第二阶段经济调度问题。评估指标我常用三个系统失负荷概率LOLP、缺供电量期望值EENS、平均运行成本。鲁棒方案和确定性方案后验对比通常长这样方案平均成本元成本95%分位元LOLPEENSkWh确定性优化方案11280151206.2%32.8两阶段鲁棒Γ511840126400.3%1.5两阶段鲁棒Γ2412970131000.0%0.0这个表很有说服力。确定性方案平均成本低但在极端场景下会付出高额代价甚至失负荷鲁棒方案平均成本高出5%但代价的尾部被压住了。实际工程里尾部风险往往比平均值更致命——一次失负荷事故的惩罚成本可能顶得上几十次正常运行的利润。6.2 蒙特卡洛实现的几个注意点做后验评估的时候我直接把不确定性场景当作参数传入第二阶段问题不经过SP那个max-min结构所以它就是一个标准的LP或QP求解极快。2000个场景并行跑Matlab里用parfor可以轻松在三分钟内完成。这里也有个容易踩的坑第二阶段问题本身可能无解。如果某个极端场景下燃气轮机爬坡不够、储能电量不足系统会直接不可行。在确定性优化和鲁棒优化的主问题里我们一般允许切负荷并设定很高的罚函数成本让模型有最后保底手段。后验评估时保留同样的罚函数才能让每个场景都有解LOLP和EENS才有意义。6.3 我在实际运行中积累的几点体会这套流程跑了快一年我个人最深的感触是两阶段鲁棒优化的价值不在它算得有多快多准而在于它逼着你在建模阶段就把哪些决策是日前定的、哪些是日内调的、不确定性怎么圈这三件事想清楚。这个梳理过程本身比跑通代码更值钱。另外预算约束Γ的取值千万别照搬文献。不同微网的负荷曲线、风电置信度、储能容量差异很大我建议把它当成一个可调参数做敏感性分析画一条Γ vs 成本/失负荷概率曲线再让运行人员根据风险偏好去选。成本端和风险端的平衡只有结合具体场景才有意义。最后再分享一个小技巧CCG迭代过程中把每轮SP求出的最恶劣场景u*存下来做个热力图能非常直观地看出哪些时段对不确定性最敏感。我接手过一套系统迭代里反复出现的就是傍晚骤风时刻和晚间负荷尖峰后来根据这个观察专门在傍晚时段提高了燃气轮机的热备用效果比单纯调大Γ还要好。这个套路大家以后做鲁棒优化分析时可以试试。