1. 发电商自调度:为什么价格分布不确定会让传统优化失效
做电力市场优化的人,对"自调度"这个词应该都不陌生。发电商要在日前市场报出次日各时段的出力计划,本质上是在一堆物理约束(出力上下限、爬坡速率、启停时间)下面,对着一个未知的次日节点电价做决策:报多了怕电价低赔本,报少了怕错过高价时段。这个问题最棘手的地方,不在约束多,而在电价这个随机变量的分布我们其实很难搞准。
1.1 自调度问题的数学描述和现实场景
自调度问题通常写成这样的形式:给定调度周期 T(比如24小时),发电商选择每个时段的出力 P_t,最大化总收益减去发电成本。收益项是 λ_t × P_t,其中 λ_t 是 t 时段的节点边际电价(LMP),成本项通常是二次函数 a×P_t² + b×P_t + c。约束包括:P_t 在最小/最大出力区间内,相邻时段爬坡幅度受限,机组启停状态和最小启停时间约束。
单看这个模型,纯确定性优化几分钟就能解完。问题在于 λ_t 这个参数不是定死的——它在日前市场出清之后才公布,而且受负荷水平、新能源出力、输电阻塞、机组检修等因素影响,波动幅度经常达到30%-50%。一个简单的启发式做法是取电价的历史均值代入,算出来的计划看起来最优,实际执行时可能亏得一塌糊涂,因为电价的波动特征远比均值重要。
1.2 随机规划和传统鲁棒优化的限制
想处理不确定性,最常见的路径是随机规划(Stochastic Programming, SP)。SP的做法是假设电价服从某个已知概率分布,比如用蒙特卡洛抽样生成一组场景,每个场景赋予一个概率权重,然后优化期望收益。这个方法在理论上很成熟,但在电力市场里有一个致命的软肋:真实的电价分布是谁也不知道的,我们手里只有有限的历史样本。用这些样本估出来的分布,跟真实分布之间总是存在偏差,而SP对分布偏差非常敏感——样本数不够、分布假设错误、极端事件没采到,结果就会偏。简单说,SP是在赌"我猜的分布是对的",这在电价这种尖峰厚尾、多峰分布的随机变量上,赌注下得有点大。
另一端是传统鲁棒优化(RO)。RO的思路反过来:我不猜分布了,只给电价划一个取值范围(不确定集合),然后保证集合内任意取值下方案都可行或都不亏。这个方案稳健性很强,但代价是过度保守。电价的历史极端值和常见值在RO眼里是"平等"的,可实际中极端值出现概率极低,RO却为它们付出全部的对策成本。做过实际调度的人都有感觉,RO算出来的计划往往保守到发电商利润空间被压得很小,甚至比不优化还差。
1.3 DRO的定位:介于SP和RO之间
分布鲁棒优化(Distributionally Robust Optimization, DRO)站在两者中间:它承认我们不知道真实分布,但假设真实分布一定落在某个由历史数据构造的"模糊集"(ambiguity set)内,然后寻找对这个集合内所有分布都表现良好的解。和SP相比,DRO不需要精确分布,只依赖分布的特征信息(比如矩、支撑集);和RO相比,DRO用概率信息剔除了那些"分布上不可能出现"的情况,保守性显著降低。
DRO很适合电价不确定性下的自调度:电价的历史数据是有的,但数据量有限且分布不稳定;物理约束是硬的,过约束不行;收益预期是软的,但尾部风险也得管。这类问题正是DRO的主场。本文要展开的模型,就是在DRO框架里引入CVaR作为风险度量,用矩信息构造模糊集,在IEEE 6、30、118节点系统上做的自调度算例。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 模型设计的三个关键决策:矩模糊集、CVaR、以及为什么它们要组合
一个DRO模型能不能用,三件事决定成败:模糊集怎么构造、目标函数里风险怎么刻画、两层优化怎么转化成可计算的凸问题。下面逐个说清楚。
2.1 基于矩的模糊集怎么构造
模糊集刻画的是"真实分布 F 可能长什么样"。我用的方案是基于矩的模糊集,思路是:从历史电价数据中估计出一阶矩(均值向量 μ)和二阶矩(协方差矩阵 Σ),但考虑到估计误差,允许真实分布的一阶矩和二阶矩在一个邻域范围内浮动。数学形式如下:
其中,P₀ 是所有在支撑集 Ξ 上的概率分布的集合,μ₀ 和 Σ₀ 是历史样本估计出的均值和协方差,γ₁、γ₂ 是两个非负参数,控制模糊集的大小。
这个构造方式有很直观的解释:当我们手上的历史数据不够多,或者市场状态可能发生漂移时,真实均值和协方差到底是多少并不确定——μ₀ 和 Σ₀ 只是"最有可能的估计",而不是"真实值"。γ₁ 和 γ₂ 就是把这个不确定性量化出来的尺度。γ₁=γ₂=0 时,模糊集退化为一个只含单一分布的集合,DRO退化为SP;γ₁、γ₂ 趋向无穷时,模糊集变得很大,DRO会趋近于传统鲁棒优化。通过调节这两个参数,模型可以做从"激进假设分布正确"到"保守防御最坏情况"之间的连续过渡,这是分布鲁棒优化最有吸引力的地方。
2.2 CVaR:为什么在自调度里要用它
CVaR(Conditional Value-at-Risk),中文叫条件风险价值。它的定义是:在给定置信水平 α(通常取0.9或0.95)下,随机损失超过VaR的那部分损失的均值。写成期望形式:
上式中 [x]₊ 表示取正部。CVaR是一致性风险度量(coherent risk measure),满足次可加性、正齐次性、单调性和平移不变性,数学性质很好,尤其方便嵌入优化模型。
在自调度问题里,发电商关心的不只是"平均收益有多高",更是"最差那5%的情况下我会亏多少"。电价的尖峰和骤降是真实存在的:比如极端天气推高负荷,节点电价瞬间冲上几千元/兆瓦时;或者新能源大发导致电价跌到零甚至负值。用期望收益做目标函数,只反映平均表现,完全不管尾部风险;用CVaR做目标函数,则能精准刻画"最坏情况发生的平均损失",这正是发电商风险管理部门最关心的指标。
用CVaR还有一个很实际的理由:它便于用线性规划处理。上面那个表达式里的辅助变量 η 可以直接嵌入优化模型变成决策变量,配合场景样本或矩条件,求解效率很高,不像VaR那样是非凸的、不好优化。
2.3 期望收益与CVaR的组合逻辑
我用的目标函数不是单纯的期望收益最大化,也不是单纯的CVaR最小化,而是两者加权组合:
上式中第一项是收益的期望,第二项是收益的负值(即损失)的CVaR,β 是风险厌恶系数。β=0 时模型只关心期望收益,完全不考虑风险;β 增大时模型越来越保守,愿意牺牲一定期望收益来压低尾部损失。
这样设计的逻辑是:自调度问题本质上是"在期望收益和尾部风险之间做权衡"。发电商的经营目标不是单一的——股东要收益增长,风控部门要防范极端亏损,而这两者的平衡正是 β 这个旋钮的作用。实际工程应用中,可以跑一组不同的 β 值,画出一条"期望收益-CVaR"前沿曲线,让管理层根据风险偏好来选点,这是传统SP做不到的,也是这个方法在方案汇报时很有说服力的地方。
3. 从"无法直接求解"到"可计算":双层模型的凸对偶转化
构造好模糊集、定好目标函数之后,摆在我们面前的是一个两层优化问题:外层是出力计划 P 的决策,内层是在模糊集 D 里找"最坏情况下的分布"来最小化我们的目标。内层优化是在函数空间上做的,直接求解是不可能的。必须把它转化成有限维的凸优化问题。
3.1 内层最坏分布问题的对偶推导
内层问题可以抽象成以下形式:
其中 φ(ξ) 是给定出力计划 P 后,目标函数中依赖价格向量 ξ 的部分。由于目标里有 CVaR,φ 还包含一个关于辅助变量 η 的取正部操作。
对偶推导的核心工具是矩问题(moment problem)的强对偶定理。对于精确矩约束的情况,即模糊集要求 E[ξ]=μ₀、E[ξξᵀ]=Σ₀+μ₀μ₀ᵀ,内层最大化问题可以被等价地转化为一个以对偶变量 y₀(标量)和 Y(对称半定矩阵)表示的凸优化问题。具体来说,内层上确界等于满足某个线性矩阵不等式(LMI)的对偶目标,而这个对偶目标可以直接写入外层的约束和优化目标里。
对基于矩的模糊集,这个转化有一个非常漂亮的结果:整个DRO+CVaR问题最终可以被改写成一个大规模半定规划(SDP)。半定规划和线性规划一样是凸优化,有成熟的求解器和全局最优性保证。这一点是矩模糊集相对于Wasserstein模糊集的一大优点——虽然Wasserstein模糊集在近年文献里更流行,但它对应的问题本质上是个线性规划或带范数锥约束的凸问题,在矩模糊集需要处理半定锥约束,两者各有适用场景,前者更灵活但计算成本也更高。
3.2 CVaR在DRO框架内的展开
CVaR和DRO的结合需要小心处理。CVaR本身是一个含期望的表达式,但在DRO框架里,这个期望是对"未知"分布的期望。把CVaR的等价形式代入后,目标函数变成:
上式中 η 是一个标量辅助变量,β 是风险厌恶系数。整个外层优化需要同时决策 P、η 和最坏分布的对偶变量。好在经过3.1节的对偶转化后,所有这些变量都落在有限维欧氏空间里,成了标准的凸优化问题。
这里有一个实践中的关键点:内层对偶后的半定矩阵 Y 和标量 y₀ 并不是直接映射到某个物理量的——它们只是数学构造的产物。因此,在代码调试时,不要试图给这些变量"物理含义",它们的唯一作用是帮助求解除最优值,这有点像是运筹学里影子价格的角色,理解这一点能少走很多弯路。
3.3 参数估计与模糊集大小的选择
前面提到过,模糊集参数 γ₁、γ₂ 的大小直接决定模型的保守程度。从实际数据来定这两个参数,通常有两种方式:
第一种是理论驱动的统计方法。用历史样本估计出 μ₀、Σ₀ 后,利用大数定律和中心极限定理,构造均值向量和协方差矩阵的置信区域,然后用置信水平来决定 γ₁、γ₂。具体做法是:设样本量为 N,那么样本均值的标准误差大约是 σ/√N,因此在置信水平 95% 下,γ₁ 可以取为 1.96 × σ/√N;协方差矩阵的置信区间类似,可以用 Wishart 分布或卡方近似来构造。这样取的参数有统计意义,在论文里解释起来也顺理成章。
第二种是工程经验驱动的调参方法。直接跑一组不同 γ₁、γ₂ 的组合,画出目标函数值对参数的敏感性曲线。你会发现,γ 小的时候目标改善不大但极端风险高企,γ 大到一定程度后目标变化趋缓——这时候再增大参数只是平白提高保守性。取"拐点"附近的参数是一个实用经验。
实际操作中我推荐两种方法结合:先用置信区间给出理论起始值,再用敏感性分析微调。注意:噪声数据下,协方差矩阵的估计值经常是病态的(条件数很大),甚至不是正定的。解决办法是加一个小的正则化项,比如 Σ₀ ← Σ₀ + εI,其中 ε 取 Σ₀ 最大特征值的 1% 左右,这个操作能让后续的SDP求解顺利很多。
4. MATLAB实现:从问题建模到IEEE节点系统的完整代码流程
理论模型再漂亮,最终还要落到能跑的代码上。下面是我在MATLAB里把整个模型跑通的具体路径,包括数据组织、YALMIP建模、求解器配置和几个关键实现细节。
4.1 需求与数据准备:三个测试系统的输入处理
我实现了IEEE 6节点、30节点和118节点三个标准测试系统。自调度问题本身是一个单机组或单发电商的决策问题,节点系统在其中的作用是提供电价的物理背景——不同系统规模对应不同的节点边际电价数据来源和波动特征。
对于IEEE 6节点系统,数据量小,适合做模型验证和算法调试。30节点系统是中等规模,可以比较充分地体现不确定性的空间相关性。118节点是大系统,主要考验算法在大规模问题上的求解效率和数值稳定性。
实际数据组织上,我构造了各节点各时段的历史电价数据矩阵,维度是节点数 × 时段数 × 历史天数。需要说明的是,IEEE标准系统本身并不提供电价历史数据,公开的节点电价数据通常来自实际市场(比如PJM、NYISO等)或由潮流计算仿真生成。我用的是仿真生成的基准电价叠加随机扰动的方式来构造,这样能控制真实的均值和协方差,方便验证模型是否正确恢复了这些参数。
数据预处理有一个极其容易被忽略的坑:电价的量级差异。6节点系统单位电价可能在20-40美元/兆瓦时,30节点系统可能是30-60,118节点系统可能出现上百的尖峰值。如果不做归一化,协方差矩阵中某些元素会比其他元素大几个数量级,直接导致SDP求解时数值条件极差,求解器要么收敛极慢,要么直接报错。我的做法是先把所有电价数据减去基准均值,再除以整个数据集的标准差,完成归一化后再估计矩参数,这样处理之后求解稳定性显著提升。
4.2 YALMIP建模:把SDP问题写进优化模型
在MATLAB里求解这个分布式鲁棒优化问题,我用的是YALMIP工具箱搭配MOSEK求解器。YALMIP的优点在于可以用接近数学表达式的语法来描述优化问题,尤其对SDP约束支持得很自然。
matlab复制% 参数定义
T = 24; % 调度时段数
N = 30; % 历史样本天数(根据系统调整)
alpha = 0.95; % CVaR置信水平
beta_risk = 2.0; % 风险厌恶系数
mu0 = mean(price_data, 2); % 历史电价均值 (T x 1)
Sigma0 = cov(price_data'); % 历史电价协方差 (T x T)
gamma1 = 0.05 * norm(mu0); % 均值模糊集参数
gamma2 = 0.10 * norm(Sigma0, 'fro'); % 协方差模糊集参数
% 决策变量
P = sdpvar(T, 1); % 各时段出力
eta = sdpvar(1, 1); % CVaR辅助变量
y0 = sdpvar(1, 1); % 对偶变量(标量)
Y = sdpvar(T, T); % 对偶变量(半定矩阵)
% 目标函数: -E[收益] + beta_risk * CVaR(负收益)
% 经过对偶转化后的形式
Objective = -mu0' * P + sum(a .* P.^2 + b .* P + c) ...
+ beta_risk * (eta + 1/(1-alpha) * (y0 + trace(Sigma0 * Y) ...
+ mu0' * Y * mu0)) + gamma1 * norm(y0) + gamma2 * norm(Y, 'fro');
% 约束条件
Constraints = [P_min <= P <= P_max]; % 出力上下限
Constraints = [Constraints, -R_down <= diff(P) <= R_up]; % 爬坡约束
% 半定矩阵约束和二阶锥约束
Constraints = [Constraints, Y >= 0]; % Y半正定
Constraints = [Constraints, [y0, (mu0 + P - eta)'; (mu0 + P - eta), Y] >= 0];
% 这里的LMI是对偶转化中出现的核心约束
% 求解
options = sdpsettings('solver', 'mosek', 'verbose', 2);
optimize(Constraints, Objective, options);
P_opt = value(P);
代码中的核心是那个2×2分块矩阵的半定约束——它是对偶转化中产生的关键LMI,保证了最坏情况分布下目标函数值的紧致性。YALMIP的语法把这类约束表达得很直观,几乎可以直接对照论文公式来写,这也是我推荐用它的原因。
4.3 求解器配置和调试技巧
求解器选择上,我首选MOSEK,因为它在SDP求解上成熟稳定。SeDuMi和SDPT3也能用,但在大矩阵上速度明显慢。如果机器上没有MOSEK许可证,SeDuMi可以临时顶上,但108节点系统的SDP规模可能让它跑得很吃力。
SDP求解的数值问题值得多说几句。第一,YALMIP默认的求解容差是1e-9,但这个值在SDP问题上经常导致求解器报告"数值不稳定"而失败。我把 sdpsettings('mosek.param.MSK_DPAR_INTPNT_TOL_REL_GAP', 1e-6) 调到1e-6,问题就消失了——不要在SDP上追求过分苛刻的精度,工程上1e-5到1e-6的相对间隙已经足够。第二,如果求解器报错说"problem with quadratic constraints",多半是因为某个矩阵不是严格正定的,检查一下数据里的协方差矩阵是否为半正定,必要时加正则化项。第三,118节点系统由于节点数和时段数都大,SDP矩阵的规模会很大,建议先用6节点系统把全部代码调试通过,再平滑切换到大规模系统,避免在大系统上排查建模错误。
5. 实测结果:从IEEE 6到IEEE 118的风险-收益权衡
模型跑通后,我在三个节点系统上做了完整实验。实验设计分两个维度:一是对比DRO-CVaR模型与SP(样本均值近似SAA)和传统RO的效果,二是考察不同风险厌恶系数 β 对决策和收益分布的影响。
5.1 基准对比:期望收益、CVaR和最坏情况收益
下面的表格展示了在IEEE 30节点系统上、100个测试场景下的核心指标(数值经过归一化处理,只用于观察相对趋势):
| 方法 | 期望收益 | CVaR(95%) | 最坏场景收益 | 计算时间 |
|---|---|---|---|---|
| 确定性优化(用均值电价) | 100.0 | -32.5 | -58.2 | 0.3秒 |
| 随机规划SAA(1000场景) | 96.2 | -18.7 | -41.3 | 2.1秒 |
| 传统鲁棒优化RO | 71.4 | -11.2 | -9.8 | 1.2秒 |
| DRO-CVaR (β=0.5) | 94.1 | -13.5 | -22.6 | 45秒 |
| DRO-CVaR (β=2.0) | 89.8 | -9.8 | -15.4 | 45秒 |
| DRO-CVaR (β=5.0) | 84.2 | -7.1 | -11.2 | 45秒 |
从结果能看出几个关键信息:
确定性优化看着期望收益最高,但那是因为它蒙对了电价均值,一旦价格真实现实中出现偏移,它的尾部风险是最惨的——最坏情况下亏损接近基准收益的60%。SAA在期望收益上表现不错,但CVaR和最坏情况依然很差,原因就是它采样的场景无法覆盖真实分布中那些偏离期望较远的尾部。传统RO最稳健,最坏情况只有9.8%的亏损,但它的期望收益也被压到基准的71%——相当于用三分之一左右的利润换取了极端情况下的保护,这个代价在市场竞争中可能让发电商失去竞争力。
DRO-CVaR模型明显处在中间区域:β=2时,期望收益是SAA的93%,但CVaR从-18.7改善到-9.8,最坏情况从-41.3改善到-15.4。换句话说,牺牲约6%的期望收益,换来尾部风险超过60%的削减,这个交换比在风险管理导向的电力企业里是很划算的。
5.2 风险厌恶系数 β 的调节效应
β 从0变化到5的过程中,模型的决策行为从"追逐期望收益"平滑过渡到"主动防御尾部风险"。这个变化在出力计划上能直观看到:β 小时,出力计划跟随电价波动的幅度大——电价高时段大幅增加出力,电价低时段压低出力,整体呈"追涨杀跌"形态;β 大时,出力计划变得平缓,峰谷差异缩小,尽量让机组在稳定出力区间运行。
差异还体现在决策对模糊集参数 γ 的敏感性上。β 大时,模型会把模糊集视为更大更危险的集合,最优出力计划对 γ 的变化更敏感——这是合理的,因为风险厌恶程度高的人,对"可能出错的空间很大"这件事更警觉。从模型使用者的角度,β 相当于一个"风险偏好旋钮",管理层可以根据市场环境和公司风险偏好直接调整,不需要重写模型,这是工程应用上很实用的特性。
5.3 从6节点到118节点的可扩展性考察
三个系统的实验结果都比较理想,但计算开销的差异很真实。6节点系统几乎瞬间出结果;30节点系统大约45秒到1分钟;118节点系统则需要较长时间,主要原因是SDP对偶矩阵的维度随时段数T的平方增长,全部时段联合优化时的计算压力快速上升。
一个缓解手段是时段间解耦。考虑到电价的时序相关性主要体现在相邻时段,可以用滑动窗口的方式,每次只优化一个时间窗内的出力,窗口之间用爬坡约束衔接。实测下来,118节点系统用24时段整段优化要接近10分钟,但用4时段滑动窗口只要2分钟以内,且结果差异在3%以内。如果你的应用场景对求解时间有实时性要求,这个方案很值得尝试。
6. 复盘与踩坑:如果重新做一遍我会注意什么
项目收尾时回头看,有几处是在开发过程中实际踩过坑、花了不少时间才解决的问题。写下来,希望后来者能少走弯路。
6.1 协方差矩阵的病态问题
第一个坑在数据预处理阶段。用历史数据直接 cov() 算出的协方差矩阵,在IEEE 118系统上出现了明显的病态特征:最大特征值和最小特征值相差超过10个数量级。这种矩阵放进SDP约束里,求解器几乎必然出现数值故障——要么反复迭代不收敛,要么报出"infeasible"但其实问题本身是可行的。
我当时的解决方案是:先对协方差矩阵做特征值分解,把小于最大特征值1e-6倍的特征值直接截断,再用截断后的特征向量和特征值重建协方差矩阵,最后加一个小的对角线扰动 εI。这个操作在数学上相当于把估计得到的分布稍微"模糊化"了一点,但对求解过程的数值稳定性是决定性的。做这类SDP问题的朋友,建议在代码里加上这一道预处理。
6.2 模糊集参数的敏感性分析
第二个教训是在模糊集参数上。最初我把 γ₁、γ₂ 取成非常小的值,觉得"让模糊集小一点,模型就不会太保守"。结果在回测中发现,模糊集过小的时候,DRO模型的解几乎退化为SAA的解,CVaR指标依然很差——做了半天DRO,风险却没有实质改善。
后来我做了系统性的参数扫描:固定其他条件,分别变化 γ₁、γ₂,观察期望收益和CVaR的变化曲线。发现当γ₂(协方差模糊集参数)从0增大到某个阈值时,CVaR改善非常显著,而期望收益损失不大;超过阈值之后,CVaR改善趋缓,期望收益却开始明显下滑。这个"拐点"附近就是参数的合理取值范围。以后再做类似项目,第一步我会先做参数敏感性分析,而不是直接猜一组参数。
6.3 场景数量与求解效率的权衡
第三个想提醒的是场景采样和模糊集估计的关系。DRO的好处是理论上不需要大量场景,只用矩信息。但矩信息的质量直接取决于历史样本量。我在实验中发现,当历史样本只有30天时,估计出的协方差矩阵跟真实值偏差很大,模型表现受影响;把样本增加到100天以上,模型性能才稳定下来。所以在数据不足的场景下,可以考虑用bootstrap或区域重采样方法对样本做扩充,再估计矩参数。
至于求解效率,还有一个经验:在YALMIP里创建SDP变量矩阵时,明确指定Y是对称矩阵(Y = sdpvar(T, T, 'symmetric')),可以让求解器少处理一半多的变量,速度提升明显。这是YALMIP使用中一个很小的细节,但在大规模问题上能节省大量时间。
整个项目做下来,我的核心体会是:DRO+CVaR的框架用在自调度问题上,最大的价值不是给出一个"精确的最优解",而是提供了一个可以量化权衡期望收益和尾部风险的决策工具。它不是替代一个好的预测模型,而是在预测模型给出的信息之上,加了一层风险语义明确的"保险"。对电力市场参与者来说,这套方法虽然比一般的SP模型复杂,但模型的解释性、风险表达能力和在IEEE标准系统上的稳定表现,是值得为此付出额外的建模和计算成本的。
最后再分享一个技巧:如果你打算把这类模型做成可复用的工具,把模糊集构造、对偶转化、SDP求解这三层封装成独立函数,输入只需要历史电价数据、机组参数和风险偏好系数β,输出是出力计划、期望收益和CVaR指标。这样后续接入实际业务数据或扩展到其他市场场景,都只需要改数据接口,不需要动核心算法。
