做含风电的调度优化,最难的一关不是把目标函数写出来,而是让模型真正扛得住实时运行。我最早跑经济调度时,系统里所有风电、负荷都给死值,求解器几分钟就出结果,看上去一切完美。可一放到带随机波动的真实场景里,方案立刻破功——要么风电预测偏高导致出力缺口,要么负荷预测偏低导致备用被吃穿。后来我把"源荷两侧不确定性"正式建模进调度模型,并且把碳交易成本写进目标函数,整个项目的复杂度上了一个台阶,但结果也终于像样了。
这篇文章围绕"考虑源荷两侧不确定性的含风电电力系统低碳调度"这个题目展开,完整记录我基于Matlab的实现思路:从风电和负荷的不确定性建模,到场景生成与削减,到含碳交易的低碳调度模型,再到Yalmip求解和排坑经验。适合正在做电力系统优化调度方向的研究生、刚接触新能源消纳与低碳调度的工程师,以及想用Matlab快速验证算法思路的读者。全程会给出可直接运行的代码逻辑和调试心得,照着搭一套模型不成问题。
1. 为什么源荷两侧不确定性会成为调度模型的分水岭
1.1 风电接入之前,系统是怎么调度的
传统经济调度的思路很简单:给定负荷预测值,在满足机组出力上下限、爬坡约束和网络约束的前提下,让燃料成本最小。这个范式在负荷相对可控、电源以火电为主的年代基本够用,因为负荷预测误差通常只有百分之几,靠系统预留的固定旋转备用就能消化掉。
风电进来之后,情况变了。风电出力不是"预测值加个小误差"那么简单,它的波动幅度大、间歇性强,短期功率预测误差经常达到10%到20%,极端天气下更高。如果调度模型里把风电当成一个固定出力节点,那等于默认"风电说的数一定靠谱",一旦实时出力达不到,系统功率就不平衡,只能靠火电紧急爬坡或切负荷来补救。
我做第一个含风电模型时踩过这个坑:把风电预测功率直接代入功率平衡,结果某天实际风速偏低,风电出力只有预测值的六成,备用全部耗尽,频率险些越限。从那以后我意识到,调度模型必须把"不确定性"当成一个正式的输入量,而不是事后补救的事。
1.2 双侧不确定性到底是什么意思
"源荷两侧不确定性"里的"源",指的是以风电为代表的电源侧不确定出力;"荷"就是负荷侧的不确定性。电源和负荷两边都有预测误差,如果建模时只考虑一边,另一边用固定预测值,模型就会系统性低估风险。
一个很直观的例子:某日负荷预测偏低了5%,风电预测又偏高了10%,两边叠加起来,净负荷的实际值比预测值高出15%。这个量级已经超过常规备用容量,传统确定性模型直接失守。所以源荷双侧不确定性不是一个可有可无的装饰,而是含风电电力系统调度必须面对的基本现实。
更准确地说,调度关心的不是一个单独的负荷不确定性和一个单独的风电不确定性,而是二者叠加后的"净负荷不确定性"。用公式表达就是:
净负荷预测值 = 负荷预测值 - 风电预测值
实际净负荷 = 实际负荷 - 实际风电出力
净负荷预测误差 = 负荷预测误差 - 风电出力预测误差
注意符号:负荷误差是正的(实际高于预测),风电误差是负向偏差(实际低于预测),它们在功率平衡上是叠加的。这就是为什么双侧不确定性要比单侧更麻烦——它们不是简单抵消,很多时候是互相放大。
1.3 净负荷视角和备用需求的量级
从净负荷视角看调度问题,一切会清晰很多。调度员真正要做的是:安排火电出力计划,使得在各种可能的净负荷场景下,系统都能保持功率平衡。火电出力不能瞬间变化,它需要在"预测净负荷"附近留出足够的上下调节空间。
我一般用两个指标量化不确定性对备用需求的影响:
- P50预测误差:净负荷预测的中位数误差,对应调度基准场景;
- P95预测误差:95%置信水平下的净负荷误差,对应备用需求的保守估计。
实测下来,含风电系统的P95净负荷误差可能是负荷P95误差的2到3倍。如果备用只按负荷误差设,风电一波动就抓瞎。这个量化过程直接决定了后面场景生成和备用约束怎么设置。
2. 场景法:不确定性建模与场景削减的完整链路
2.1 随机规划、鲁棒优化、分布鲁棒,我为什么选场景法
处理不确定性主要有三条路:鲁棒优化、随机规划、分布鲁棒优化。它们各有适用场景,我简单说下取舍。
鲁棒优化考虑的是"最坏情况",不需要概率分布,只要给定不确定集合(比如风电出力在某个区间内波动),就能保证所有情况下方案可行。它的优点是稳健,缺点是过于保守——为了一个概率极低的极端场景,牺牲大量经济性。
随机规划(也叫场景法)用一组带概率的场景来代表不确定性分布,目标函数取期望值。它不会为极小概率事件过度牺牲经济性,也更贴近实际运行逻辑。缺点是场景数量对求解速度影响很大,需要做场景削减。
分布鲁棒优化介于两者之间,假设知道分布的矩信息或支撑集,在最坏分布下优化。理论上更精巧,但建模和求解复杂度高,工程落地门槛不低。
我做这个项目选的是场景法。原因有三:第一,Wind和Load预测误差的分布信息相对容易获得,场景法能充分利用概率信息;第二,场景法的物理含义清晰,电力系统工程师容易理解和接受;第三,Matlab里有成熟工具支持场景生成、削减和优化求解,代码实现效率高。
2.2 风电场景生成:功率域直接加误差这个做法有隐患
风电场景生成看起来简单:预测功率加上一个随机误差项就行。但直接这么做会踩一个隐蔽的坑。
风电出力有上下界:0到装机容量。如果用正态误差直接加在功率域上,采样结果很容易超过这些界限,你得做截断处理。截断之后,概率分布的形状就变了,本来该有的尾部风险被强行抹掉。比如一个200MW的风电场,预测出力是120MW,误差标准差30MW,正态采样会出现负出力,截断成0之后,原本"出力很低"的样本全堆在0上,场景集合失真。
我建议换一个思路:在风速域做采样,再通过风机功率曲线转换成出力场景。风速分布一般用Weibull分布描述,采样值天然为正,经过功率曲线转换后,出力自然落在0到额定功率之间,不会出现截断失真的问题。功率曲线的分段函数我贴在下面:
- 风速 v < v_ci(切入风速)或 v > v_co(切出风速),出力为0;
- v_ci ≤ v < v_r(额定风速),出力按线性或非线性插值;
- v_r ≤ v ≤ v_co,出力为额定功率。
Matlab里生成风速场景的核心代码大概长这样:
% 生成Weibull分布的风速场景 n_scenes = 500; k_shape = 2.2; % Weibull形状参数 c_scale = 8.5; % Weibull尺度参数 v_scene = wblrnd(c_scale, k_shape, n_scenes, n_wind); % 通过风机功率曲线转换为出力 P_w_scene = zeros(n_scenes, n_wind); for i = 1:n_wind P_w_scene(:, i) = wind_curve(v_scene(:, i), wind_params(i)); end注意,如果有多台风电场,风速场景之间要带相关性。实际做法是先用Cholesky分解处理相关矩阵,生成相关的标准正态样本,再做变换到Weibull分布。
2.3 负荷场景生成与相关性处理
负荷不确定性比风电好处理一些,预测误差通常认为是正态分布,标准差根据预测模型精度取负荷预测值的1%到3%。
负荷场景直接在功率域加正态误差是可以的,因为负荷没有硬性上下界问题,而且预测误差的分布特性相对稳定。要注意的是,不同节点的负荷误差不能全部独立,同一地区负荷受温度、天气共同影响,会有空间相关性。处理方法同样是相关系数矩阵加Cholesky分解。
当负荷场景和风电场景都要考虑时,还需要考虑负荷预测误差与风电预测误差之间的相关性吗?从物理上说,温度会影响负荷水平,也影响风速,确实存在一定耦合关系。但在工程实现中,这两者通常先独立采样再组合,因为耦合关系的数据很难拿到,而且对最终调度结果的影响量级不大。这个假设在文献里也很常见,实测下来问题不大。
场景组合代码示意:
% 假设已有 wind_scene (n_scenes, n_wind) 和 load_error_scene (n_scenes, n_load) % 组合成净负荷场景 net_load_scene = repmat(P_load_base, n_scenes, 1) - wind_scene * ones(1, n_wind);2.4 场景削减:K-means与同步回代削减的取舍
500个场景直接丢进优化模型,求解规模会非常大,尤其是带0-1整数变量的时候,可能几个小时都算不完。所以必须做场景削减,把500个场景压缩到20到50个,同时保持场景集对原始分布的代表性。
主流的削减方法有两个:同步回代削减(SBR)和K-means聚类。
SBR的思路是反复合并距离最近的两个场景,把被合并场景的概率累加到保留场景上,直到场景数量达到目标。它的优点是保留的场景概率分配严格符合原始分布,缺点是计算复杂度高,而且容易丢掉一些极值特征。
K-means的思路是把所有场景按距离聚成K簇,用聚类中心代表该簇场景,簇内场景总概率作为中心场景的概率。实现简单,计算快,Matlab自带kmeans函数。实测用K-means配合适当的K值,效果很好。
两种方法我都跑过,对比下来:当原始场景数在1000以内时,SBR削减质量略好一点,但差异不大;当原始场景数大或者需要频繁重复削减时,K-means的效率优势很明显。我的做法是先用快速前向选择法粗削到100个,再用K-means聚到30个,速度和精度都兼顾了。
场景削减还有一个很容易被忽略的细节:削减后要检查极端场景有没有丢。我见过削减完的场景集里,最大净负荷点没了,结果备用约束事实上被放松了。所以削减后我总会补做一步校验:
% 校验极端场景是否保留 extreme_scene = [max(net_load_scene); min(net_load_scene)]; [~, idx_keep] = ismembertol(extreme_scene, scene_reduced, 0.01, 'OutputAllIndices', true);如果极端场景没保住,手动把它加进削减后的集合,赋予一个小概率。这样既保证分布代表性,又不至于漏掉风险点。
3. 带碳交易的低碳调度模型构建
3.1 碳交易机制在调度模型中的表达方式
低碳调度的核心是把碳排放成本化。比较常见的有三种表达:碳税、碳排放上限约束、碳交易机制。我项目里用的是碳交易(碳排放权交易),因为它最贴近当前电力行业实际,而且对调度结果的影响更有意思。
碳交易的基本逻辑是:系统或者每个发电主体先拿到一个碳排放配额,配额不够就要到市场上买,配额多了可以卖。这一进一出就构成碳成本或碳收益。
配额分配方式我采用基准线法:根据机组发电量和单位发电量基准碳排放强度的乘积来分配。基准强度定得太严,大多数机组都要买配额;定得太松,碳交易就形同虚设。实际建模中,基准强度可以根据行业平均水平设定,也可以通过参数灵敏度分析来确定。
3.2 目标函数与约束集
含风电电力系统低碳调度的目标函数包含三部分:火电燃料成本、碳交易成本、弃风惩罚成本(可选)。写成数学形式就是:
最小化 F = Σ_i (a_i P_i^2 + b_i P_i + c_i) + C_carbon × (E_actual - E_quota) + ξ × Σ弃风量
其中:
- P_i是火电机组i的出力和对应成本系数;
- C_carbon是碳价,单位元/吨CO2;
- E_actual是系统实际碳排放量,按机组出力乘排放强度累计;
- E_quota是系统获得的碳配额总量;
- ξ是弃风惩罚系数,用来鼓励消纳风电。
注意碳交易项可能是正的也可能是负的:排放超标时为成本,排放低于配额时变成收益。这个正负切换不需要额外处理,数学上直接放进目标函数求最小化就行。
约束条件里,除了传统的功率平衡、机组出力上下限、爬坡约束、最小启停时间约束之外,还要加旋转备用约束和风电出力上限约束。旋转备用约束是我重点强调的:
上行备用:Σ min(P_i,max − P_i, 爬坡上限) ≥ 净负荷P95误差 + 风电预测偏差
下行备用:Σ min(P_i − P_i,min, 爬坡下限) ≥ 净负荷P95误差的反向部分
这个约束直接承担"不确定性"在调度模型中的落地作用,方向一定要写对,很多初学者的代码在这里出错。
模型中碳约束可以设成硬约束(排放不能超过某上限),也可以只通过目标函数成本化调节。工业项目里两种都用,我代码里留了一个开关:
use_emission_limit = 1; % 1为硬约束,0为仅成本化 if use_emission_limit constraints = [constraints, sum(emission_rate .* P_g) <= E_max]; end3.3 不确定性与低碳目标的内在权衡
低碳调度有趣的地方在于,不确定性和低碳目标不是两个并列的模块,它们之间存在内在权衡。
风电是零碳电源,调度模型在碳成本的压力下会更愿意消纳风电,这没问题。但风电不确定性大,要保证系统安全,就得预留更多备用。备用主要靠火电提供,火电多发电就多排放——于是"多消纳风电减排"和"多留备用增排"之间产生了张力。碳价越高,系统越愿意承受备用成本去消纳风电;碳价低,系统可能更倾向让火电稳定出力,宁可少量弃风。
这个权衡在确定性模型里看不到,只有把源荷两侧不确定性建模进去,碳价的调度信号才真正体现出来。这也是"考虑源荷两侧不确定性的含风电电力系统低碳调度"这个题目的核心价值点。
4. Matlab代码实现:从数据输入到求解
4.1 程序模块划分
整个程序我按四个模块组织,每个模块独立成文件,调试和复用都方便:
main.m:主入口,负责调用数据读取、场景生成、模型构建、求解和结果输出;scenario_generate.m:生成风电和负荷场景,输出削减后的场景集合及概率;low_carbon_dispatch.m:构建优化模型,调用求解器求解;report_result.m:解析求解结果,输出各机组出力、碳排放、成本、弃风量等指标。
其中low_carbon_dispatch.m是核心,我把模型构建和求解器调用放这里。在项目早期,我把所有代码堆在一个文件里,改一个参数要翻半天,逻辑还容易错。后来拆分成模块,调试效率明显提升——强烈建议你从一开始就按模块写,别偷懒。
系统数据我直接采用了Matpower格式的IEEE节点数据,在case文件里加了风电场所在节点、预测出力、装机容量等字段。这样可以用现成的节点数据和线路参数,不用自己造数据,出问题也好排查。
4.2 核心建模代码:Yalmip写法
优化建模我推荐直接用Yalmip工具箱配合求解器使用,比手写矩阵约束省事得多。Yalmip的符号变量声明方式很直观,声明变量、写约束、定目标、调求解器,四个步骤非常清晰。
下面是一个核心代码骨架,展示火电出力、风电出力、碳交易成本和备用约束怎么落进Yalmip:
% 决策变量:火电出力,风电调度出力,弃风量 P_g = sdpvar(1, n_gen, 'full'); P_w = sdpvar(1, n_wind, 'full'); curtail_w = sdpvar(1, n_wind, 'full'); % 目标函数:燃料成本 + 碳交易成本 + 弃风惩罚 fuel_cost = sum(a .* P_g.^2 + b .* P_g + c); carbon_cost = C_carbon * (sum(mu .* P_g) - E_quota); curtail_cost = xi * sum(curtail_w); objective = fuel_cost + carbon_cost + curtail_cost; % 约束 constraints = []; % 功率平衡:基准预测场景下的净负荷平衡 constraints = [constraints, sum(P_g) + sum(P_w) == net_load_base]; % 火电出力上下限和爬坡约束 constraints = [constraints, P_g_min <= P_g <= P_g_max]; % 风电调度出力不能超过可用出力,且不能低于0 constraints = [constraints, 0 <= P_w <= P_w_forecast]; constraints = [constraints, 0 <= curtail_w <= P_w_forecast]; % 弃风关系:调度出力 + 弃风 = 可用风电 constraints = [constraints, P_w + curtail_w == P_w_forecast]; % 旋转备用约束(考虑源荷不确定性) constraints = [constraints, sum(min(P_g_max - P_g, ramp_up)) >= reserve_up]; constraints = [constraints, sum(min(P_g - P_g_min, ramp_down)) >= reserve_down]; % 求解 ops = sdpsettings('solver', 'gurobi', 'verbose', 2); result = optimize(constraints, objective, ops);这里要特别说明一下:功率平衡按基准净负荷场景来写,不确定性的影响通过旋转备用约束传导进模型。这是一种简化但工程上很实用的建模方式,求解规模小,速度快,方案也具备足够的运行可靠性。
如果你的审稿人或导师要求更严格的场景约束,可以把功率平衡约束写成对每个削减后场景都成立:
for s = 1:K constraints = [constraints, sum(P_g) + sum(P_w) == net_load_scene(s)]; end但这种写法会让调度方案只针对一组固定的风电出力,本质上是把多场景变成"同时满足多个确定性平衡",对风电消纳的灵活性刻画不够细,需要谨慎使用。我的代码里用一个参数控制用哪种模式,算是个可配置的选项。
4.3 场景削减代码实现
用K-means做场景削减时,有几个操作细节值得注意。
首先是归一化。风电场景和负荷场景的量纲虽然都是MW,但不同节点的数值范围可能差异很大。如果不归一化直接聚类,数值大的变量会主导距离计算。我通常先做z-score标准化,聚类后再把中心场景映射回原始数值。
其次是K值选取。K太小,场景代表性不够;K太大,求解负担重。我实测教训:IEEE 30节点系统配3台风电场,原始500个场景削减到30个,求解时间还在可接受范围;削减到50个,求解时间翻倍不止。建议先做一组K值扫描(比如20、30、50),对比目标函数值和求解时间,找出拐点。
% K-means场景削减 [idx, C, ~] = kmeans(scene_norm, K, 'Distance', 'sqeuclidean', 'Replicates', 5); % 计算每个聚类中心的概率权重 prob = zeros(K, 1); for k = 1:K prob(k) = sum(idx == k) / length(idx); end % 还原场景到原始量纲 scene_reduced = C .* (scene_std + 1e-6) + scene_mean;Replicates参数建议设置为5以上,因为K-means对初始点敏感,多次重复可以避免陷入差局部最优。我一开始没设这个参数,结果不同批次跑出来的削减场景差异很大,后来加了Replicates才稳定下来。
4.4 结果输出与后处理
求解完成后,必须把结果指标提取出来,否则一堆决策变量看不出所以然。我每次会输出以下指标:
- 各火电机组出力、风电实际消纳量;
- 燃料成本、碳交易成本、弃风惩罚成本;
- 系统总碳排放量和碳配额盈余/缺口;
- 弃风率、碳排强度、单位电量成本。
一个小经验:Yalmip求解后,目标函数值可以用value(objective)取到,但碳交易成本是正还是负要单独计算,不要只看总目标。我迭代调试时发现,某个碳价下燃料成本上升但总成本下降,原因是碳交易收益增加了——只看总数根本定位不到这个关系。
5. 实测排坑:求解器、参数与模型调试经验
5.1 求解器选型与MIP参数
模型里如果有机组启停变量或最小启停时间约束,问题就变成混合整数规划(MIP)。我的建议是优先用Gurobi或CPLEX,远超Matlab内置求解器的性能。实测同一个模型,500场景削减到30个,Gurobi用不到一分钟就收敛,内置求解器可能要跑十几分钟甚至卡死。
Yalmip调用Gurobi很简单,装好求解器后在sdpsettings里指定solver参数即可。几个我常用的关键参数:
mipgap:设为0.0001或更小,保证解的质量,但注意求解时间会上升;timeLimit:设一个上限,防止极端案例跑不完;verbose:调试时开2,正式批量跑时关掉。
如果二次成本项让问题变成MIQP,Gurobi也能处理。但设计模型时尽量把目标函数控制在二次以内,不要出现三次或更复杂的非线性,否则求解器要落到MINLP,稳定性会差很多。
5.2 几个踩过的坑
我实际调试中踩过的坑挺多,挑几个最有代表性的分享。
第一个坑是碳价数量级问题。有一次碳价设置不当,导致碳交易成本比燃料成本小了三个数量级,模型完全感受不到碳约束的压力,调度结果和普通经济调度几乎一样。建议拿一个具体工况手动估算一下碳排放量和碳价乘积,确认碳成本占到燃料成本的5%到20%,这个区间碳价信号才有效。
第二个坑是旋转备用方向写反。reserve_up约束里用的是min(P_g_max - P_g, ramp_up),我一开始误写成min(P_g - P_g_min, ramp_up),导致系统以为有大量上备用,实际根本没有。这类错误用单测试算例验证时就能发现:把净负荷台阶跳上去,看备用是否真的够。
第三个坑是场景削减后概率权重没有归一化。K-means聚类后如果某簇为空,prob(k)算出来是0,权重数组加起来不等于1,目标函数的期望成本就会整体偏小,导致模型的风向不对。我后来加了归一化和空簇清理的逻辑。
第四个坑是Matlab版本与Yalmip/Gurobi的兼容性问题。我项目用的是Matlab R2025b配Yalmip最新版和Gurobi 11,跑得很顺。但同一套代码在不同的Matlab版本上出现过求解器License连接失败、Yalmip函数不可用的问题。建议开始前先跑一个sdpvar最小示例验证环境没问题,再进行完整模型调试。
5.3 模型求解变慢时怎么降维
我遇到过最头疼的情况是场景数增加后模型怎么都算不快。把500个场景削减到20个还慢,就得考虑降维手段。
第一个手段是削减场景数,比如从30割到20,代价是代表性下降,但速度可能提升数倍。第二个手段是固定整数变量,先解一个LP松弛看趋势,找到最优开机组合后再把整数变量固定住,只优化连续变量。第三个手段是把二次成本分段线性化,把MIQP转成MILP。线性化后求解器能充分发挥分支定界的效率。
这几种方法我都试过,组合起来使用,单次求解时间从十几分钟降到了两三分钟,效果非常明显。如果你场景数很大、节点数又多,建议优先尝试前两种手段。
6. 算例验证:低碳调度的效果到底从哪看出来
6.1 测试系统与对比实验设计
我用的是含风电接入的IEEE标准算例系统来做验证,风电场接入点选在负荷相对集中、线路传输容量相对宽裕的节点上。为了对比低碳调度的效果,我设计了三组实验:
第一组:确定性常规经济调度,不考虑源荷不确定性,不考虑碳成本,作为基准; 第二组:确定性低碳调度,只加碳交易成本,不建模源荷不确定性; 第三组:随机低碳调度,同时考虑源荷两侧不确定性和碳交易成本,即本文核心模型。
这样对比有一个明显好处:第二组和第三组的差异能单独反映"源荷不确定性建模"带来的影响,而第一组和第二组的差异反映"低碳约束"带来的影响。
6.2 结果解读
以一个典型的测试工况为例(具体数值因系统规模和数据而异,看相对变化趋势即可):
| 方案 | 燃料成本 | 碳排放 | 弃风率 | 总成本(含碳成本) |
|---|---|---|---|---|
| 确定性常规调度 | 基准 | 基准 | 较高 | 基准 |
| 确定性低碳调度 | 略升 | 下降 | 降低 | 略升或持平 |
| 随机低碳调度 | 小升 | 进一步下降 | 更低 | 与第二组互有高低 |
从现象看,第三组方案在碳排放和弃风率上表现最好,燃料成本比基准会上升一点,但这是正常代价——为了应对不确定性预留了更多备用,同时为了降低碳排放调整了机组出力排序。最关键的一点是:第三组方案的可执行性远高于第一组,因为它在生成调度计划时就把净负荷波动考虑进去了,实时运行时不容易出现功率不平衡。
另外我还做了碳价敏感性分析,从碳价0元/吨一路升到200元/吨,观察调度结果如何变化。碳价低时,系统排碳配置基本不受影响;碳价升高到某个临界值,模型的机组出力排序会明显向低碳机组倾斜,风电消纳率也会跨过一个台阶;继续升到很高后,减排增量趋缓,说明碳价信号在某个区间内最有效。这个临界值受系统燃料结构和碳排放强度影响很大,需要针对自己的算例实际算一遍,不能拍脑袋定碳价参数。
6.3 置信水平与碳价敏感性的联动
备用约束里置信水平的选择(比如P80、P90、P95)对结果影响不小。我扫描过一组置信水平,从80%升到99%,备用需求量显著增加,火电出力下限被抬高,导致风电消纳空间变小,碳排放不降反升。这是一个反直觉但很重要的发现:过度追求不确定性覆盖,可能反过来损害低碳目标。所以在实际项目里,置信水平要根据运行可靠性标准和碳减排目标联合校准,不要盲目设高。
碳价和置信水平还会联动:高碳价时系统愿意承担备用成本去消纳风电,此时即便置信水平升高,碳排放增幅也不会太大;低碳价时系统本来就不太愿意为风电预留太多备用,置信水平一升高,低碳效果就被明显侵蚀。二者联合调参,是让模型跑到最优工况的关键。
最后再分享两个小技巧
第一,跑任何不确定性调度模型之前,先跑一遍确定性模型并保证结果合理。这样可以把问题拆分:如果确定性模型结果都有问题,说明是模型约束写错了;如果确定性模型正常但随机模型异常,大概率是场景生成或削减的锅。逐层定位,调试效率会高很多。
第二,把场景生成模块做成可复现的,固定随机种子。源荷不确定性研究里,场景生成自带随机性,如果不固定随机种子,每次跑出来的场景都不同,结果难以对比。我在main.m开头加一行固定随机种子,所有对比实验都在同一组场景下进行,结论才可信。
含风电电力系统的低碳调度,说实话不是一个能一蹴而就的模型。源荷两侧不确定性、碳交易成本、备用约束、场景削减,每一个模块单拎出来都有讲究,组合在一起更是充满权衡。我做完这个项目最大的体会是:调度模型的价值不在于算法多花哨,而在于每个假设是否清晰、每个参数方向是否正确、每类不确定性是否真正进入了决策。把这几点想清楚,Matlab代码反而是最简单的部分。