☰
输配电网互补优化中的不确定性建模:场景法MATLAB实现与调参避坑
2026/10/13 18:43:44 网站建设 项目流程

简介:针对高比例可再生能源接入带来的不确定性,这套代码实现了一种考虑输配电网协调的互补优化方法,聚焦日前市场与实时市场下TSO与DSO之间共享灵活资源的协调机制。面向电力系统优化、配电网运行以及电力市场方向的研究人员与工程师,尤其适合研究主从博弈和双层优化的读者。代码完整覆盖原文核心模型,以锥规划约束DSO系统安全,利用多段Benders分解技术进行求解,并提供日前市场出清、实时调度、场景生成、PCC优化、结果对比等模块,包含6节点、3TSO-9DSO、24TSO-3DSO等多种算例数据,从数据读取、算例构建到绘图分析均有对应脚本支撑,并附带运行说明。压缩包共50个文件,其中41个Matlab源文件为主体,另有README说明、PDF附录、Shell脚本与许可证文件,整体仅697KB,轻量易部署。已有893人学习或下载,适合复现实验、验证算法性能,也可作为电力市场双层优化编程的参考实现。

1. 输配电网互补优化和不确定性:为什么先看场景而不是拍脑袋

做输配电网互补优化时,最常被问的一句是:预测不完美怎么办。风功率和光伏出力是波动的,负荷预测也有偏差,如果优化模型里不把不确定性放进去,算出来的调度方案在真实运行里大概率翻车。这篇文章讲的是如何在 MATLAB 代码里落地“考虑不确定性的输配电网互补优化”——用场景法把随机性写进目标函数和约束,让方案既有经济性,又有抗风险能力。

这套思路解决的是两类人的需求:一类是做园区、配电网或微电网调度研究的从业者,需要给领导或评审看到“不确定性下仍可行的优化结果”;另一类是刚接触随机优化的电气方向同学,想知道怎么看懂别人的 MATLAB 代码、怎么把模型改成自己的算例。我默认你已经会基础的 MATLAB 和线性规划,但没系统接触过场景法或鲁棒优化。

下面直接进入建模和代码。我会用一个小型输配电网模型贯穿全文:输电网侧有几台火电,配电网侧有风电、光伏、储能和可调负荷,输配之间通过联络线双向交换功率。你不用照抄我的网络参数,关键是理解场景生成、约束组织和调参的套路。

2. 建模思路:场景法下的输配电网互补优化模型

2.1 不确定性建模:场景法、鲁棒盒与分布鲁棒,为什么我选场景法

不确定性建模有三条主流路线。第一条是场景法,也叫随机规划:把风电、光伏、负荷的不确定性离散成若干典型场景,每个场景给一个概率,优化目标变成“期望成本最小”。第二条是鲁棒盒:只知道不确定量的上下界,要求在边界范围内所有情况都可行,解出来偏保守。第三条是分布鲁棒:知道不确定量的均值、方差或矩信息,在“最坏的分布”下做优化,数学形式复杂,但比纯鲁棒更经济。

我一般先选场景法,原因很实际。输配电网互补问题的决策变量多,配电网侧还有储能和可调负荷,模型中往往混着整数变量。场景法是离散场景,约束和目标是线性的,能直接交给成熟求解器;鲁棒盒虽然也能线性化,但会同时放大输配两侧的备用需求,算出来的成本和弃风率经常比真实情况高出太多;分布鲁棒在 MATLAB 里建模更绕,入门的代价不值。

场景法的核心是把“不确定性”转化为“概率加权”。每个场景代表一种可能的日前实现,第一段决策,比如火电出力和储能基点,必须在看到场景前确定;第二段决策,比如储能实时调整、弃风、切负荷,可以在场景确定后跟着变。两段结构非常贴合输配电网实际:日前计划先定,日内滚动再修正。这个结构也是等效于把每个场景的节点功率平衡约束分别写出来,而不是拍一个总平衡。

配套的做法是从历史数据里提取典型日曲线。如果没有历史数据,就用正态分布在预测值周围抽样,先跑通模型,再换真实数据。后面第 3 章的代码就是这么组织的。

2.2 目标函数与约束:从功率平衡到电压越限

目标函数在 MATLAB 代码里通常写成三块之和:第一块是日前机组成本,第二块是场景下的调整成本,第三块是惩罚项,比如弃风弃光和切负荷。这里有一个容易踩坑的点:切负荷的惩罚权重必须比机组发电成本高一个量级以上,否则求解器会倾向用切负荷来“省钱”,这在物理上不可接受。

约束也分两个层次。输电网侧,我一般用直流潮流近似,忽略无功和网损,节点功率平衡用注入功率等于流出功率表示,线路潮流限制在容量以内,机组出力上下限和爬坡约束单独写。配电网侧,辐射状网络用 Distflow 方程做线性化处理,或者直接按有功平衡加电压幅值边界处理,重点看研究目标是精确潮流还是经济调度。如果只做互补优化和不确定性分析,不需要完整交流潮流,否则求解规模会迅速失控。

联络线是输配电网互补优化的关键约束。联络线功率是两个系统之间的耦合变量,容量有限,而且输电网和配电网各自的安全校核要求不同。建模时把联络线功率当成可调度变量,可以双向流动,在目标函数里加上传输损耗成本或网损惩罚,能让优化结果更符合实际。储能约束要特别注意时间耦合:荷电状态是上一时段状态加充电减放电,如果写成逐场景独立,储能就可以跨场景“凭空搬运能量”,结果完全失真。

场景概率的处理方式也影响目标函数。最简单的是等概率,每个场景权重取 1/S。如果场景由聚类生成,权重应该设为每个簇的样本占比。很多人在这一步偷懒,全部用等概率,结果期望成本被少数小概率场景带偏,这是这类代码最常见的隐藏错误之一。

2.3 求解架构:集中式还是分布式

输配电网互补优化的求解架构主要分两类。集中式做法是把输电网和配电网的所有变量放进同一个优化模型,一次性求解。好处是全局最优,缺点是模型规模大,而且输配分属不同运营主体时,谁也不愿意把机组报价、网络参数全交出去。分布式做法用 ADMM 或类似方法把问题拆成输电网子问题和配电网子问题,通过迭代交换联络线功率价格和数量达成一致。

从 MATLAB 代码角度,我建议先做集中式,把模型跑对,再考虑拆分。集中式实现简单,调试方便,尤其适合论文仿真和方案论证。分布式适合真实系统落地,但子问题协调参数很敏感,后面避坑章节会专门讲 ADMM 的震荡问题。如果你最终目标是做分布式,也建议先用集中式结果做基准,否则很难判断分布式迭代误差到底是多少。

3. 用 MATLAB 实现最小可运行版本:场景生成、建模与求解

3.1 场景生成:用历史数据或正态分布构造典型场景

场景生成是整段代码的地基。如果地基歪了,后面优化做得再漂亮,结果也是空中楼阁。先给出最简单也是最常见的生成方式:对预测值加正态噪声。代码里固定随机种子,是为了让同一个算例在别人机器上能复现同样的结果。

% 场景生成:场景数 S,时段数 T % mu_load, mu_wind, mu_pv 是预测曲线,长度 1 x T % sig_load, sig_wind, sig_pv 是标准差,长度 1 x T function scen = gen_scenarios(S, T, mu_load, sig_load, mu_wind, sig_wind, mu_pv, sig_pv) rng(42); % 固定随机种子,方便复现 scen.load = zeros(S, T); scen.wind = zeros(S, T); scen.pv = zeros(S, T); for s = 1:S scen.load(s,:) = max(0, mu_load + sig_load .* randn(1, T)); scen.wind(s,:) = max(0, mu_wind + sig_wind .* randn(1, T)); scen.pv(s,:) = max(0, mu_pv + sig_pv .* randn(1, T)); % 光伏只在白天出力,按光照有效时段折减 daylight = zeros(1, T); daylight(7:18) = 1; scen.pv(s,:) = scen.pv(s,:) .* daylight; end end

这里randn(1,T)生成的是标准正态随机数,再乘标准差加期望,得到近似的预测误差曲线。max(0, ...)是防止负荷、风电和光伏出现负值,物理上不存在负的负荷或负的风电出力。光伏后面乘daylight掩码,是因为光伏在夜间出力必然为零,不能靠正态噪声生出晚上的光伏。

这个生成方式的问题是相邻时段完全独立,没有时间相关性,真实的风电出力往往是持续一小时以上的波动过程。想要更逼真,可以把randn改成 AR(1) 模型,让后一时段误差在上一时段误差基础上衰减:

function x = ar1_scenario(T, mu, sig, rho) % AR(1) 场景生成:mu 是预测均值,sig 是扰动标准差,rho 是自相关系数 x = zeros(1, T); e = randn(1, T) .* sig; x(1) = mu(1) + e(1); for t = 2:T x(t) = mu(t) + rho * (x(t-1) - mu(t-1)) + e(t); if x(t) < 0 x(t) = 0; end end end

rho 一般取 0.7 到 0.95,越接近 1,曲线越平滑。如果样本量够,更严谨的做法是从历史数据里按天抽样,再用 kmeans 做场景缩减,保留有代表性的典型日。场景缩减的细节放到第 4 章参数部分讲,这里先确认:场景生成的输出应该是一个结构体或三维数组,后续求解循环直接读取,不要在优化代码里反复生成随机数,否则结果不可复现。

3.2 用建模工具箱搭优化模型:变量、目标与约束的代码骨架

MATLAB 里做线性规划,可以直接用内置的 linprog,但输配电网互补优化的变量多、约束多,手写系数矩阵非常痛苦。行业里常见做法是借助建模层,把变量声明成符号变量,再把约束和目标按数学习惯写出来。下面代码给出的是变量声明部分的骨架,分第一段决策变量和第二段场景变量。

% 网络参数假设已在外部定义: % ng 台火电机组,n_ess 套储能,n_res 个可再生能源场站,ntie 条联络线 % T = 24 个时段,S 个场景 P_g0 = sdpvar(ng, T, 'full'); % 火电日前出力,第一段变量 P_tie0 = sdpvar(ntie, T, 'full'); % 联络线日前计划,第一段变量 P_ess0 = sdpvar(n_ess, T, 'full'); % 储能日前充放电计划 % 每个场景下的第二段变量用元胞数组存 P_delta = cell(1, S); % 火电调整量 P_ess = cell(1, S); % 储能实际功率调整 curtail = cell(1, S); % 弃风弃光量 shed = cell(1, S); % 切负荷量 for s = 1:S P_delta{s} = sdpvar(ng, T, 'full'); P_ess{s} = sdpvar(n_ess, T, 'full'); curtail{s} = sdpvar(n_res, T, 'full'); shed{s} = sdpvar(ng, T, 'full'); end

'full'表示声明一个稠密矩阵变量。默认的sdpvar(ng, T)也是稠密,写'full'只是显式表达意图。场景变量为什么不用三维数组sdpvar(ng, T, S)?原因在于约束里很多地方要按场景索引,元胞数组在循环里写更直观,也方便后期做场景缩减或并行求解。

目标函数按前面的三块成本组织。第一段成本是火电燃料成本,第二段是场景下的调整成本,第三段是惩罚项。惩罚项里最重要的一点:弃风弃光惩罚必须小于火电可变成本,否则模型会宁可多发火电也不消纳新能源;切负荷惩罚必须远大于其他成本,否则模型会牺牲负荷。

% 成本系数:c_g 火电边际成本,c_delta 调整成本,c_cur 弃风弃光惩罚,c_shed 切负荷惩罚 Objective = sum(sum(c_g .* P_g0)) ... + sum(sum(c_tie .* abs(P_tie0))); for s = 1:S Objective = Objective + (1/S) * ( ... sum(sum(c_delta .* abs(P_delta{s}))) + ... sum(sum(c_cur .* curtail{s})) + ... sum(sum(c_shed .* shed{s})) ... ); end

注意目标函数里用了abs,这是因为调整量和储能功率可能有正有负。如果变量本身约束在非负区间,就不需要用 abs。很多代码翻车就翻在这里:约束里写了非负,目标里又套 abs,导致模型多了一堆辅助变量,求解速度明显变慢。

约束部分的核心是场景功率平衡。输电网侧,每个场景的火电出力加联络线受电,必须等于输电网负荷;配电网侧,联络线注入加分布式电源出力,必须等于配电网负荷加储能充电减去放电,再考虑切负荷。

Constraints = []; % 第一段约束:火电出力上下限、爬坡 Constraints = [Constraints, P_gmin <= P_g0 <= P_gmax]; Constraints = [Constraints, - ramp_down <= P_g0(:,2:end) - P_g0(:,1:end-1) <= ramp_up]; % 场景约束 for s = 1:S % 输电网功率平衡 Constraints = [Constraints, ... sum(P_g0 + P_delta{s}, 1) - sum(P_tie0, 1) >= 0]; % 配电网功率平衡:注入 + 新能源 = 负荷 - 切负荷 + 充电 - 放电 Constraints = [Constraints, ... sum(P_tie0, 1) + sum(scen.wind(s,:)) + sum(scen.pv(s,:)) ... - sum(curtail{s}, 1) == ... sum(scen.load(s,:), 1) - sum(shed{s}, 1) + sum(P_ess{s}, 1)]; % 储能容量约束 Constraints = [Constraints, -P_ess_max <= P_ess{s} <= P_ess_max]; end

这段代码省掉了 SOC 时变约束和网络潮流约束,是为了让骨架清晰。真正常见的错误在于配电网功率平衡式的符号:储能充电时功率为正还是为负,每个代码作者的约定不同。我习惯把储能功率定义成正表示放电、负表示充电,这样配电网平衡等式右边是负荷减去储能放电量,逻辑不容易乱。如果你沿用别人的代码,第一步先看 P_ess 的符号约定,再看平衡等式,不要直接改参数。

3.3 求解与结果落盘:从目标值到各断面功率

求解代码很短,但调试信息非常关键。optimize返回的 problem 字段是 0 时表示求解成功,非零值要查具体含义。第一次跑通时,建议打开verbose=2,让求解器输出迭代过程,能直接看到问题规模、约束数量和求解耗时。

ops = sdpsettings('solver', 'your_solver', 'verbose', 2); % your_solver 替换成你机器上实际安装的求解器名称 % 常见可选值:'gurobi'、'cplex'、'linprog' 或某个商业求解器 sol = optimize(Constraints, Objective, ops); if sol.problem ~= 0 % 常见 problem 值:1 表示不可行,2 表示求解器内部错误,3 表示达到迭代上限 fprintf('求解失败:%s\n', sol.info); return; end % 结果提取 result.P_g0 = value(P_g0); result.P_tie0 = value(P_tie0); result.cost = value(Objective); for s = 1:S result.P_ess{s} = value(P_ess{s}); result.curtail{s} = value(curtail{s}); result.shed{s} = value(shed{s}); end

value()把符号变量转换成数值。有些变量虽然在目标里用到,但如果不提取,内存里只保留求解器内部结果,后面画图还要重新算。我习惯把所有变量的 value 统一存进一个 struct,再交给后续脚本画曲线。这个习惯能省掉很多重复求解的时间,尤其是场景数多时,一次优化可能跑几分钟,再从头算一次很亏。

求解器选择上,如果只有 MATLAB 自带的 linprog,那模型必须全是线性约束和线性目标。储能 SOC 这类带时间递推的约束如果写成线性不等式也可以,但引入了连续变量耦合,linprog 也能处理。只是当模型规模超过几千个约束时,linprog 会明显变慢,这时应该换商业求解器。商业求解器怎么配环境,一句话说不清,网上有很多资料,重点是装好后在命令行里敲yalmiptest确认能识别,别等到 optimize 报错再排查。

4. 三个必调参数:场景数、惩罚系数与收敛精度

4.1 场景数怎么定:太多求解慢,太少校核失真

场景数是这类优化第一次跑通后要面对的第一个“玄学”参数。场景太少,比如只有 3 到 5 个,极端出力场景可能完全没覆盖到,优化结果看起来成本很低,但拿到真实数据里一算就露馅。场景太多,比如 1000 个,模型里第二段变量数量是场景数乘时段数乘节点数,求解时间会呈指数级上涨,小算例都容易把内存吃爆。

我一般用两个标准来定。第一是目标值稳定性:从 10、20、50、100 个场景各跑一次,如果目标值变化小于 1%,说明场景数已经够用。第二是极端场景覆盖:检查缩小后的场景集里是否包含风电接近零的高负荷场景,以及光伏大发但负荷低的场景。这两个场景分别对应系统的高峰压力和反送压力,缺一个都会让结果偏乐观。

场景数不够时,优先做场景缩减而不是简单增加。MATLAB 里可以用 kmeans 把 500 个原始样本聚成 20 个代表场景,每个簇的样本占比作为场景概率。这个操作既保留了概率信息,又大幅压低计算规模。注意 kmeans 聚类前要把负荷、风电、光伏拼成一个矩阵,同时对每个维度的量纲做归一化,否则负荷数值大,聚类结果会被负荷主导,风光的不确定性等于没建模。

4.2 惩罚系数与置信水平:成本与风险的平衡旋钮

惩罚系数是模型里最容易被随手一拍、实际影响最大的参数。弃风弃光惩罚设得太低,求解器会主动弃掉可再生能源,因为火电多发的成本更低;设得太高,模型又会为了消纳新能源让储能高频充放,反而增加电池寿命成本。合理的做法是参考当地火电上网电价和绿电溢价,弃风惩罚取火电可变成本的 1.2 到 2 倍,切负荷惩罚取电价的 10 倍以上。

下面这张表是我在仿真里常用的初跑值,具体数值要按你的算例单位调整:

参数常见范围初跑建议调参方向
弃风弃光惩罚0.1~0.5 元/kWh0.2结果弃风过多就调大
切负荷惩罚5~30 元/kWh10出现切负荷就调大
储能循环成本0.05~0.3 元/kWh0.15储能动作过频就调大
联络线传输损耗0.01~0.05 元/kWh0.02反送功率异常就调大

置信水平这个概念主要出现在鲁棒约束里,比如电压越限约束只允许 5% 的概率违反。在场景法里,置信水平体现在“哪些场景进入优化模型”。如果按覆盖率取场景,比如只保留概率权重累计到 95% 的核心场景,那么目标函数就是条件期望而不是全期望,结果会偏保守。到底是取全期望还是条件期望,取决于上级调度对风险的态度。没有定论,但代码里必须有注释写清楚。

4.3 收敛判据与求解器参数:别让迭代在“差不多”处停

线性规划和混合整数线性规划都有明确的收敛间隙,但 MATLAB 里很多人直接调用默认设置,忽略了求解器的可行性和最优性间隙。商业求解器默认的 gap 是 1e-4 到 1e-6,对大多数电网优化足够,但遇到大规模场景时,求解器可能提前终止在一个次优解上。我习惯在 sdpsettings 里显式写:

ops = sdpsettings(ops, 'solver', 'your_solver'); ops = sdpsettings(ops, 'gurobi.MIPGap', 1e-4); % 如果是 gurobi 求解器 ops = sdpsettings(ops, 'verbose', 1); ops = sdpsettings(ops, 'debug', 1); % 约束不可行时开调试

如果用的是 linprog,没有 MIPGap 这个概念,那就只能靠检查约束是否全部满足。可以把约束表达式代入value,看最大残差是多少。残差在 1e-5 量级以下通常没问题,超过 1e-3 就要考虑数值问题,比如不同变量的量纲相差太大。

对于 ADMM 这类迭代算法,收敛判据必须是残差双重标准:原始残差和对偶残差都要小于阈值。只看原始残差,会出现功率平衡已满足但成本还没稳定就停掉的假收敛。更要命的是解在迭代后期小幅震荡,这时候可以看近 20 次迭代的目标值方差,如果方差超过目标值的 0.1%,就说明罚参数设置不合理,要回到参数调整而不是死等。

5. 输配电网互补优化的 MATLAB 避坑指南

5.1 现象:求解器报“不可行”或“数值病态”

optimize 返回 problem=1,或者求解器提示 infeasible problem。第一次跑这类代码的人会一脸懵,因为约束看起来都对。

原因分三类。一是量纲不一:功率用 MW,电压用 p.u.,成本用万元,目标函数各项数量级差 10 的幂次,求解器内部容差直接失效。二是储能 SOC 约束写错了方向:把充电当正、放电当负,导致功率平衡式始终差一倍。三是场景数据本身不自洽,比如负荷场景里出现了负值,或者风电出力超过装机容量。

解决方法是先开debug=1让建模层输出不可行约束的索引,再逐条检查变量边界和平衡式。工程上我更建议做一次“约束冒烟测试”:把所有变量的 value 先用可行初值填充,看哪些约束最大残差最大,优先处理残差最大的那几个。单位统一这一步花十分钟,能省后面两天排查时间。

5.2 现象:场景一多内存直接爆掉

场景数从 20 提高到 50,MATLAB 就报内存不足或卡死。

这个问题的根源是变量存储方式。如果场景变量全都用三维sdpvar(ng, T, S),中间计算会把稀疏矩阵转成稠密矩阵,内存消耗远大于实际变量数。而且很多约束是逐场景独立的,完全可以用元胞数组循环累加,不需要一次性构建一个巨大的稀疏模型。

解决方法是检查约束构建时是否把循环体外的临时变量也带进了约束,比如把scen.wind(s,:)写成了scen.wind,等于把整个场景矩阵里的数据全塞进模型。其次是给 MATLAB 打开“使用多线程”和在求解前清理多余变量。最好把场景法代码拆成函数,输入场景不必全部留在工作区,用完就清。如果内存还是不够,就要做场景缩减,而不是硬上全场景。

5.3 现象:结果里弃风量异常大,目标成本反而更高

弃风量占到风电总出力的 30% 以上,但你并没有设置任何弃风限制。

原因大概率是弃风惩罚权重低于火电边际成本。求解器比较两种方案:多弃风多发电,成本更低;少弃风少发电,火电爬坡成本高。只要前者的总成本更低,就会选择大量弃风。另一个常见原因是联络线容量或者配电网承载力设太小,导致新能源送不出去,被迫弃掉。

解决方法是先看目标函数各项成本的数值比例,弃风惩罚必须比火电成本高。再把线路容量按实际参数复核一遍,特别是联络线容量,它决定输配互补的上限。调完之后如果还是弃风,就要在约束里加入最小消纳率,比如要求弃风率不超过 5%,这样不管成本怎么算,结果都不会离谱。

5.4 现象:ADMM 收敛慢且迭代曲线持续震荡

如果你把集中式改成分布式,常见现象是迭代 100 次还不收敛,目标值像锯齿一样上下跳。

原因是罚参数 rho 固定不变,子问题各自走过的步长不匹配。输电网子问题的目标函数值比配电网子问题大几个量级时,固定 rho 会让输电网侧响应过快、配电网侧响应过慢,两边怎么都达不成一致。另一个原因是子问题不是严格凸,迭代到某个区域后出现多个等优解,对偶变量来回切换。

解决方法是采用残差平衡的自适应规则:当原始残差大于 10 倍对偶残差时,把 rho 调大;相反则调小。同时对每个子问题的目标函数加一个小量级正则项,比如二次罚项rho/2 * norm(x - x_prev)^2,让子问题变成严格凸。这个技巧在工程里非常常见,改起来也就十行代码,但对收敛速度影响巨大。

5.5 现象:结果对随机种子敏感,换 rng 值方案大变

换一个随机种子,弃风率从 5% 变成 20%,目标成本变化超过 5%。

根本原因是场景数太少,极端场景没有被覆盖。在正态分布抽样下,万一随机种子生成的那组场景里恰好没有“大风小负荷”组合,系统就不需要为它做备用;换一组场景又出现了,结果当然天差地别。

解决方法是做敏感性分析而不是只跑一组随机数。我会固定 20 到 50 个场景,分别换 5 个随机种子,统计目标值的均值和方差。如果方差过大,先做场景缩减,把历史数据的极端工况显式加进去。另一个做法是手动在场景集里注入“极端场景”,比如风电出力为零且负荷峰值为 1.2 倍的场景,概率不用高,但保证优化器见过这种情况,结果稳定性会好很多。

6. 进阶验证:把不确定性优化结果拿到蒙特卡洛里复盘

场景法再怎么说,也只是对真实不确定性的近似。判断一个 MATLAB 代码模型到底靠不靠谱,我习惯做蒙特卡洛复盘。做法是保持日前计划不变,生成几千条与场景生成分布相同的“真实出力曲线”,逐条做实时校核,统计失负荷和弃风量。

function [avg_cost, max_shed, avg_curtail] = validate_plan(plan, mu, sig, MC) % plan 是场景法算出的日前计划 % mu/sig 是“真实”预测误差参数,MC 是抽样次数 avg_cost = 0; max_shed = 0; avg_curtail = 0; for i = 1:MC w = max(0, mu.wind + sig.wind .* randn(1,24)); l = max(0, mu.load + sig.load .* randn(1,24)); % 实时校核:固定火电出力,储能和联络线按场景进行调整 [cost_i, shed_i, cur_i] = realtime_check(plan, w, l); avg_cost = avg_cost + cost_i / MC; max_shed = max(max_shed, shed_i); avg_curtail = avg_curtail + cur_i / MC; end fprintf('平均成本 %.2f,最大切负荷 %.2f,平均弃风率 %.2f\n', ... avg_cost, max_shed, avg_curtail); end

用同一组随机种子对比三个方案:确定性优化、场景法优化、鲁棒优化。如果场景法的平均成本比确定性只高 3%,但最大切负荷小了一半,这个代价就值得;如果两个指标同时变差,说明场景生成或约束建模有错误,而不是算法问题。很多代码跑完直接看目标值,从不做这步复盘,结果论文里的“鲁棒性”只是自说自话。

我自己的习惯是先把场景法代码跑通,用 10 个场景对拍确定性结果,确认方向和量级合理,再放大到 50 个场景做正式实验。这个顺序看着慢,实际最省时间。蒙特卡洛复盘如果发现场景法比确定性还差,基本能断定是场景生成分布和校核分布不一致,优先改场景生成,而不是调优化模型的参数。输配电网互补优化的难点从来不是哪个公式难,而是不确定性的分布、决策变量的耦合、成本权重的比例,这三样只要有一样是悬空的,结果就一定翻车。希望这篇文章能帮你把这些坑都绕开,也让你的 MATLAB 代码跑出真正经得起复盘的结果。

本文还有配套的精品资源,点击获取

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

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

立即咨询