ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

带补偿与爬坡的电力市场出清二元均衡精确求解方法

带补偿与爬坡的电力市场出清二元均衡精确求解方法 有一种模型看起来只是个普通优化问题可一旦把市场行为作为内生变量写进去问题就立刻跨到了另一个世界。我们今天聊的就是这类问题带补偿、带爬坡上升的电力市场出清最后落到一个二元平衡还要求精确求解。做过现货市场出清或者机组组合的人都知道单纯做调度已经够麻烦再让机组报价、储能充放电、补偿费用和爬坡约束互相咬合模型里就会出现离散变量、互补条件和双线性乘积混在一起的局面。很多团队这时候习惯性丢给启发式算法或者干脆做松弛但结果经常是给了个“看起来能算”却不能保证最优、甚至没法解释的出清方案。这篇文章先拆清楚二元平衡在带补偿的爬坡市场里到底卡在哪再给一整套可以落地的精确求解路线从KKT条件重构、强对偶、大M变换到分支定界和外部逼近。文末配一个两台机组加补偿的微型算例把每一步怎么算、踩了什么坑都写明白。适合刚开始做市场仿真、结算模型或者准备写论文但不知道从哪入手的人读。1. 先理解“二元均衡”到底卡在哪1.1 爬坡上升问题不是只加一条不等式那么简单电力系统里说“上升问题”行业内更多叫爬坡问题。负荷从午前到高峰突然上扬火电机组、储能、需求响应都要在一两个调度时段内把出力提起来。表面上这是一个约束每台机组每个时段出力变化不能超过 ramp 上限。但在市场环境下爬坡不是免费的。机组为了在下一时段能拉高出力要么提前压低本时段出力要么多预留旋转备用这些成本必须体现在出清价格里。所以爬坡问题从来不是“调度可行不可行”的问题而是“价格信号怎么在能量市场里体现”的问题。如果模型里只有一台机组负责爬坡问题很简单直接用拉格朗日乘子把爬坡约束的影子价格算出来就行。但实际市场里多个机组同时竞争、负荷分段上升、补偿机制又给了特定爬坡资源额外支付情况就变成了多个机组的爬坡约束可能存在不同的绑定状态。一台机组的爬坡约束绑定了另一台没绑定这本身就是离散组合。这个组合状态不是先验已知的是要和市场价格同时求出来的——这就是二元均衡的第一个含义。1.2 补偿机制让“二元”变成真正的麻烦很多市场为了激励灵活性资源会额外给爬坡容量一笔补偿。注意这笔补偿不是单纯加在目标函数里就行。补偿一旦进入结算机组报价行为会跟着变出清结果会变影子价格也会变。换句话说你没法先算一个不含补偿的调度再把补偿后补进去。补偿必须作为内生变量进入平衡条件和能量价格一起求解。从数学上看补偿项往往只对正向爬坡有效也就是说不是每台机组每一段都有补偿可能超过某个上升阈值才给也可能只有特定技术类型的机组才有资格拿。这个“分段触发”导致目标函数变成不可微的分段函数。再加上机组最小出力、启停状态这些变量模型里既有连续变量又有 0-1 整数变量连续变量之间还有互补关系。这样的问题称它为难解是客气的不少情况下它连局部收敛都保证不了。1.3 “精确求解”四个字意味着放弃侥幸一说到这类问题很多人第一反应是“那用遗传算法/粒子群/模拟退火”。我不反对启发式算法用于探索性分析但它解决不了市场出清结算这种需要可解释性、唯一性和可追溯性的问题。电力市场结算要求每条约束的乘子能解释价格要求同样的输入得到同样的结果要求补偿费用有明确的会计映射。启发式算法做不到这些。所以“精确求解”在这里指的是把原问题——不管是带补偿费用的市场出清、机组利润最大化下的均衡、还是带爬坡约束的变分不等式——变换成有限个可以用商业 MILP 或 MIQP 求解器证明最优等价的问题。注意精确求解不是说每一步都手工算而是把求解过程收敛到数学上可证明的全局最优而不是碰运气。2. 把补偿、爬坡和均衡写成一组互补条件2.1 基本记号与参与主体为了让后续讨论不悬空先约定一套最小化记号。假设市场里有若干发电机组每台机组在每个调度时段 t 的出力是 q_{i,t}单位报价或边际成本由非线性函数 C_i(q_{i,t}) 描述。为了简化本文先只讨论两台机组和两个时段的小规模问题但所有变换方法都可以推广到更大尺度。除机组外还存在一个补偿变量 r_i表示机组 i 在两个时段之间实际提供的正向爬坡量。补偿费率 theta_i 由市场规则给定可以是每 MW 给多少钱。负荷在每个时段的需求是 D_t无瞬时价格弹性也就是说出清时满足总出力等于总需求即可。2.2 市场运营商的优化问题市场运营商的目标是在满足需求、容量、爬坡约束的前提下让系统总购电成本最小。所谓总购电成本不仅包含燃料成本也包括负荷需要为爬坡补偿支付的费用于是目标函数可以写成$$ \min \sum_{i,t} C_i(q_{i,t}) \sum_i \theta_i r_i $$爬坡补偿 r_i 和出力的关系必须显式建模。最直接的方式是引入辅助变量让 r_i 等于时段 2 出力减去时段 1 出力再限定在这个差值大于等于 0 时才计入补偿。这里有个常见坑如果不加指示变量直接把 max(q_{i,2}-q_{i,1}, 0) 放进目标函数就不可微。尤其当爬坡不一定每次都发生时求解器会在这个点上产生麻烦。后面的精确求解里会处理这个不可微项。爬坡约束本身写为$$ q_{i,2} - q_{i,1} \le R_i $$如果机组下调约束不限制向下的变化但补偿只针对正向上升。容量约束、最小出力约束这些常规项当然也得保留。2.3 市场均衡条件就是数控条件下的最优性条件在市场环境中运营商单方面最小化成本还不算均衡必须让每个主体的边际收益、边际成本和补偿收益同时满足最优性条件。对每个机组 i在给定市场价格 lambda_t 的情况下最优条件是一个带有补偿项的 KKT 条件。这里要注意lambda_t 不是预先给定的它由总需求约束的对偶变量内生决定。所以完整问题是由一组优化问题的 KKT 条件加总平衡条件构成也就是市场均衡条件每个机组在其爬坡、容量约束下的利润最大化条件成立总出力等于总需求补偿费用按规则结算。这组条件里含有互补松弛项互补条件的意思是某一不等式约束要么不起作用松弛变量大于 0乘子等于 0要么起作用约束等式成立乘子可取非负值。这种 0-1 性质不是事先枚举的而是求解的一部分。这些互补条件单独拿出来就是典型的混合整数条件。2.4 二元函数微分的判断还能用在哪儿搜索热词里总出现“二元函数微分判断”很多人以为这是纯数学题。放在这个场景里它就是判断市场均衡是否存在、是否唯一、影子价格是否可靠的核心工具。比如补偿费用使目标函数变成分段可微时我们需要在所有分段交点处检查函数是否可微如果不连续可微就不能直接套用基于梯度的 KKT 条件必须先线性化。更关键的是如果市场结算模型的目标函数不是凸的那么 KKT 条件只是必要条件不一定是全局最优的充分条件。判断凸性通常看二阶条件目标函数的海森矩阵是否半正定。如果因为补偿项的引入出现凹性区域就必须在求解前做凸化或精确线性化处理。很多市场模型算出来的价格出现异常跃变根源就在这里。3. 精确求解线性化、强对偶与分支定界3.1 为什么不能直接把模型丢给非线性求解器如果直接写一个非线性模型给 IPOPT 这类求解器碰到带整数的补偿触发条件会非常难受。IPOPT 要求连续可微碰到 0-1 变量就只能做松弛松弛以后解出来的状态很可能落在 0 和 1 的中间一到整数恢复就全部翻盘。更麻烦的是市场均衡里天然有互补条件这种“要么等于 0要么大于等于 0”的结构需要特殊处理。精确解的基本思路是把不可微项和互补项等价转化为线性约束。转化旧的方法就是用大 M 法加二进制变量。虽然大 M 法听着老套但它依然是目前把均衡问题送进 MILP 求解器最可靠的手段之一。3.2 非线性项与互补条件如何线性化先处理补偿项。假设正向爬坡量 r_i 只在 q_{i,2} - q_{i,1} 0 时产生补偿我们可以设置一个二进制变量 z_i 表示“这台机组提供了正向爬坡”。然后用下面几组约束逼近原意$$ q_{i,2} - q_{i,1} \le R_i $$$$ r_i \le q_{i,2} - q_{i,1} M(1-z_i) $$$$ r_i \le R_i z_i $$$$ r_i \ge 0 $$当 z_i 1 时r_i 最多取到爬坡上限 R_i同时也受 q_{i,2} - q_{i,1} 限制当 z_i 0 时r_i 被强制为 0。其实这里完全可以在最优解处用 R_i 和正向差值的较小值来刻画。要注意如果正向差值本来就低于 R_i补偿只给实际上升量如果实际上升量高于 R_i 那就违反爬坡约束了所以 r_i 一定不超过 R_i。互补条件同样可以用大 M 线性化。假设约束 g(x) ≤ 0 和对偶乘子 lambda ≥ 0 是互补的那就改写为$$ g(x) \le M(1 - z_g) $$$$ \lambda \le M z_g $$这里 z_g 是一个新的二进制变量。当 z_g 1 时g(x) 可以小于等于 0当 z_g 0 时乘子必须为 0。这样就把互补松弛转换成了混合整数线性约束。大 M 的选择很讲究太大容易造成数值病态太小又可能把真正的可行解剪掉后面章节会单独展开。3.3 双层问题改单层强对偶条件怎么用带补偿和爬坡的市场均衡问题常常被写成下层跟随者的双层结构。上层是市场结算下层是机组的报价/调度决策。把下层问题用 KKT 条件替换以后就得到了单层的 MPEC。MPEC 里的目标函数如果带有电价乘子和出力变量的乘积就会出现双线性项比如 lambda_t 乘以 q_{i,t}。这是求解时最麻烦的部分。解决双线性项有两种常用思路。第一种是把下层问题视为凸优化直接用强对偶条件把下层目标函数的值用对偶目标替代从而消掉双线性项。第二种是用 SOS1 约束或者精确交替方向法。多数情况下首选强对偶条件因为它在数学上最干净而且能保留原始变量的物理含义。具体操作是把下层机组决策写成带爬坡约束的二次规划假设二次成本系数是正定的。此时强对偶成立下层的原始目标值等于对偶目标值。再用这个等式代入总目标原本的 lambda 乘以 q 的双线性项就会被消除模型变成 MILP 或 MIQP。注意下层必须是凸问题否则强对偶不成立这个方法的整个根基就不存在。3.4 分支定界与外部逼近即使完成了线性化求解器内部依然要处理大量二进制变量。除了补偿触发变量 z_i还有互补条件转换出来的多种 0-1 变量以及机组启停变量。分支定界就是求解器遍历这些离散状态空间的过程。问题规模一旦变大直接全枚举会爆炸所以主流的 MILP 求解器都会做节点预处理、切割平面和启发式分支。外部逼近在这里也有用武之地。补偿项和爬坡项很多时候是凸的只是不可微。可以用一组外部线性切线不断逼近原函数每次迭代后求解一个 MIP再把得到的解带回原模型校验。如果目标函数值是凹的则改用割平面而不是切线。我对爬坡市场的实际项目里外部逼近常常比单纯的大 M 线性化收敛得快因为初始就能给出较好的上界而不是让求解器从一个松弛很差的节点开始慢慢剪。4. 微型算例两台机组加补偿的市场均衡4.1 算例数据为了让上面的方法不悬空这里给出一个小到能手工验算、但又能体现二元均衡特征的算例。两个时段第 1 时段需求 90 MW第 2 时段需求 100 MW负荷是在上升的。两台机组的二次成本函数如下机组成本参数 a成本参数 b爬坡上限 R容量上限A0.53010 MW100 MWB1.0703 MW20 MW成本函数写成 C_i(q) 0.5 a_i q^2 b_i q。补偿只给 B 机组提供的正向爬坡量补偿单价 theta_B 设为 0.2 元/MW。A 机组不参与补偿。这个数据设计得比较刻意目的是让 B 机组的爬坡约束恰好成为绑定约束暴露出二元选择问题。4.2 手工推一遍 KKT 分支先假设 B 机组爬坡约束绑定A 机组爬坡约束不绑定。设 B 机组第 1 时段出力为 x那么第 2 时段出力就是 x 3因为爬坡上限正好是 3 MW 且约束绑定。然后根据需求平衡第 1 时段A 机组出力 90 - x第 2 时段A 机组出力 100 - (x 3) 97 - x。A 机组爬坡是 (97-x) - (90-x) 7 MW不超过 A 的爬坡上限 10 MW所以假设一致。现在把 KKT 条件写出来。A 机组没有补偿、不绑定爬坡所以它的边际成本等于市场价格第 1 时段价格$$ \lambda_1 30 0.5(90-x) 75 - 0.5x $$第 2 时段价格$$ \lambda_2 30 0.5(97-x) 78.5 - 0.5x $$B 机组绑定爬坡拉格朗日乘子设为 mu_B补偿费率为 theta_B。它的 KKT 条件是$$ \lambda_1 70 x - \theta_B - \mu_B $$$$ \lambda_2 70 (x3) \theta_B \mu_B $$把 A 机组给出的两个价格表达式代入 B 机组的条件得到两个方程。先算第 1 时段$$ 75 - 0.5x 70 x - 0.2 - \mu_B $$化简$$ \mu_B 1.5x - 5.2 $$再看第 2 时段$$ 78.5 - 0.5x 70 x 3 0.2 \mu_B $$化简第二个式子时小心一点70 加 x 加 3 加 0.2 等于 73.2 x所以$$ 78.5 - 0.5x 73.2 x \mu_B $$$$ \mu_B 5.3 - 1.5x $$两个 mu_B 表达式相等得到 1.5x - 5.2 5.3 - 1.5x解出来 x 3.5。那么 B 机组两个时段出力分别是 3.5 MW 和 6.5 MWA 机组出力分别是 86.5 MW 和 93.5 MW。把 x 3.5 代回去得到 mu_B 0.05。乘子是非负的说明这个分支中的互补松弛条件成立。4.3 对照没有补偿时会发生什么如果补偿费率 theta_B 0重复上面推导会得到几乎相同的出力分配B 机组仍然是 3.5 MW 和 6.5 MWA 机组仍然是 86.5 MW 和 93.5 MW。但 B 机组的爬坡影子价格从 0.05 变成了 0.25。这个对比很有意义加了补偿以后爬坡约束的影子价格下降说明补偿本身承担了一部分爬坡成本机组不再完全依赖能量市场价格来回收爬坡支出。对我来说这个微型算例最值得留意的逻辑是B 机组爬坡约束是否绑定一开始是假设的最后通过 mu_B 非负验证了这个假设。如果算出来 mu_B 为负就必须反过头去检查别的分支比如 B 不绑定、A 绑定、或者两者都绑定。这正是二元均衡中枚举分支的核心过程。4.4 当补偿费率过高时出现不可行分支如果直接把 theta_B 从 0.2 改到 0.5按同样的 B 绑定分支推导mu_B 会变成负数。负乘子意味着这台机组在被“惩罚”而不是获得爬坡收益和绑定爬坡约束的物理直觉冲突所以这个分支要剪掉。真实的均衡可能转移到别的分支比如 B 机组受到的补偿激励太强系统希望它爬得更多但爬坡上限锁死了又或者需要引入储能、削减负荷重新达到平衡。从算法角度看这就是为什么精确求解必须做分支枚举而不是简单地把所有条件当成等式直接解。数值上看起来很顺的一组线性方程解出来的乘子不满足符号条件照样不能接受。5. 实操调试大M、数值病态与微分判据5.1 大M参数不能拍脑袋大M法的一大忌讳是“M 给个 1e6 省事”。许多新手觉得 M 越大越安全实际上过大的 M 会让矩阵条件数恶化。在整数规划预求解阶段过大的系数还可能让求解器把本来有区分度的约束当成无效约束。经验做法是对每个约束单独找尽可能紧的M值。比如互补条件里如果某个乘子理论上有物理上界那就用这个上界不要给一个通用的大数。我在实际项目里的习惯是先跑一次没有整数的松弛模型收集各乘子和变量的极值然后根据极值设定 M通常设为最大值的 10 倍。这个 M 既能覆盖待剪枝区间又不会离谱到引发浮点问题。如果是做批量市场场景扫描最好对每个场景动态调整 M场景之间的负荷水平变化很大一套 M 打天下的做法经常会莫名出现分支不可行。5.2 多重均衡怎么判断带补偿的市场模型有时会出现多重均衡。比如两个机组各类参数对称补偿费用又有阶梯触发两个解在数学上都是有效的出清价格却完全不同。此时看单一最优解会误导市场分析。建议先把补偿费率设置成参数做一整个费率扫描观察价格是否发生不连续跳变。如果跳变点附近同时存在多个可行分支解大概率是多重均衡。解决办法有两个方向一是增加规则约束比如按报价排序打破对称性二是在目标函数里加一个极小量的正则项比如最小化所有机组出力的平方和让求解器稳定地选到某个方向。正则项的量必须远小于真实成本量级否则会污染价格信号。5.3 微分解判据与乘子稳定性“二元函数微分判断”在实操中的用处主要体现在检查补偿函数的不可微点。假设补偿费率 theta_i 只在爬坡达到某一阈值 H 时触发比如超过 10 MW 才给钱那么目标函数在 r_i 10 MW 这个点上可能不可微。判断不可微最简单的方式是计算左右导数当 r_i 趋近 10 的左侧和右侧目标函数对 r_i 的导数是否一致。如果不一致就必须把这个阈值点单独用二进制条件拆开而不是指望求解器在不可微点自动找到最优解。这个判断逻辑和数学分析课上的“偏导数存在但不一定可微”是一个道理。具体到模型里哪怕所有变量都是连续的目标函数只要在某个平面处存在折痕那折痕附近的梯度就不再是唯一的。KKT条件必须改用次梯度或者显式引入分段线性化否则解出来的乘子会随求解起点的不同而抖动。对结算系统来讲乘子抖动非常要命价格报表很难解释。5.4 快速检查清单模型累计跑了一堆分支还是报无解或者价格异常建议按这个顺序排查先看爬坡总容量是否大于负荷在两个时段之间的需求差。如果负荷上升 20 MW而所有机组的正向爬坡上限加起来还不到 20 MW模型一定无源之水。检查补偿变量是不是只在正向爬坡时才打开负向爬坡如果被误计入了补偿影子价格会彻底乱掉。检查利润表达式中是否漏了补偿费率的符号。补偿在目标函数里是系统支出在机组利润里是收益写反一个符号整个均衡点都会颠覆。检查乘子是否非负。KKT 乘子符号不对说明当前分支假设错误需要切换到别的绑定组合。检查整数变量变量初始值。求解器给出的“最优”如果是基于一个很差的 MIP start有时候解是局部最优要确认它确实达到了全局最优性差距接近于 0。这些坑我都踩过其中补偿符号写反那一次让我排查了整整两天。事后复盘发现问题不是算法复杂而是模型里一个经济含义的符号表达不够清晰。所以我后来写市场模型时都会在目标函数里把补偿项单独拆成一段用注释写明它是“负荷支付”还是“机组收入”避免自身混淆。从数学工具的层面看带补偿和电力市场上升问题的二元均衡本质上是一组带离散状态选择的最优性条件。只要补偿触发、爬坡绑定、机组最小技术出力这些东西存在整数变量就不可能完全绕开。精确求解的关键不在于发明一个神秘算法而是把不可微、双线性、互补条件老老实实地转化为 MILP/QP 求解器能理解和证明的结构。哪怕只是补好大M、乘子符号和补偿费率的符号这类问题其实比想象中更能稳定落地。如果你正打算做类似的结算模型或市场仿真我的建议非常简单先在一个两时段、两台机组的规模上把分支枚举、大M选取、乘子验证全部跑顺再考虑扩大规模。基础的分支逻辑没理顺之前别急着上复杂求解器。
返回列表