做综合能源优化这类项目,最难熬的往往不是建模本身,而是模型写完之后求解器给你撂挑子。我自己在做"基于共享储能电站服务的冷热电多微网系统双层优化配置模型"这个课题时,前后花了大概四个月时间,其中一半以上都耗在了非线性问题的处理上。双层优化加上共享储能定价机制,稍不注意就会把模型写成MINLP,求解时间从几分钟直接飙到几十个小时,甚至压根不收敛。这篇文章把我从模型搭建、非线性来源拆解、线性化策略到最终求解的完整过程整理出来,重点讲清楚那些"非线性项"为什么要处理、怎么处理、处理完之后精度和求解速度怎么权衡。内容偏实用,适合正在做综合能源优化、多微网协同或者储能规划方向的研究生和工程师参考。
1. 项目缘起:共享储能与冷热电多微网为什么要放在一起
1.1 冷热电多微网的用能特征与三大痛点
冷热电多微网,说白了就是把若干个同时包含电力、热力、冷负荷的微电网放在一个区域里,每个微网内一般都配有微型燃气轮机、余热锅炉、吸收式制冷机、电制冷机、燃气锅炉这些设备,实现冷热电联供(CCHP)。
这样一个系统的核心优势是能源梯级利用:天然气进燃气轮机发电,排出的高温烟气进余热锅炉回收,冬季直接供暖,夏季推动吸收式制冷机制冷。能量利用率能从传统分供的50%~60%提到70%~85%。但这里有个很现实的问题——单微网规模小,负荷波动大,典型日曲线往往是"上午一个小高峰、傍晚一个大高峰、夜间塌下去"。
我自己在算例里测过,单个微网在夏季典型日,冷负荷峰值能到1200 kW,但夜间低谷只有200 kW出头,峰谷比接近6:1。这种情况下,如果每个微网都自己配一套储能,投资成本高不说,利用率还很低——储能设备一年中有大量时间处于闲置状态,尤其是热储能和冷储能,季节性强得离谱。要命的是,冷热电三种负荷的峰值时刻往往错开,电负荷高峰在傍晚,冷负荷高峰在下午两三点,热负荷高峰在清晨。你按各自峰值去配设备,最后每台设备一年真正满负荷跑的时间还不到三分之一,这就是综合能源系统里典型的"配置冗余、运行低效"困境。
1.2 共享储能电站的商业逻辑与技术优势
共享储能的概念其实是从共享经济延伸过来的:由一个独立的投资运营主体建设一座集中式储能电站,向区域内多个微网用户提供充放电服务,用户按容量或按电量付费,不需要自己采购、运维储能设备。这个模式在行业内这几年讨论很多,真正落地的示范项目也在增加,但大多数公开研究还停留在"自建储能"的思路上,把共享储能作为决策变量的模型并不多见。
这个模式在技术上有几个实打实的好处。第一是容量复用,不同微网的负荷峰值出现时间不完全重合,共享储能电站可以用更小的总容量满足多个微网的调节需求。第二是运行效率,集中式储能电站一般用大容量电化学储能(锂电或液流),充放电效率和循环寿命都比散装小储能更有优势。第三是商业模式灵活,可以设计成"容量费+电量费"两部制,或者按需定制服务套餐,用户侧的固定成本投入大幅降低。
在我建的模型里,共享储能电站是一个独立的利益主体,它和微网之间不是上下级关系,而是服务契约关系。这个设定直接影响了后面双层模型的架构——你不能把储能电站当成某个微网的附属设备来处理,因为它有自己的投资回报诉求,它会通过制定服务价格来引导微网的用能行为。
1.3 双层优化配置要解决什么问题
配置问题问的是"装多少",运行问题问的是"怎么用"。这两个问题在数学上天然耦合——储能容量配置是多少,直接决定了运行调度时的可行域;反过来,调度策略是高效还是低效,又直接影响应该配多大的容量才能满足可靠性要求。
这就是为什么单层模型做不好这件事:如果把运行约束全部塞进配置模型,问题规模会爆炸;如果先固定容量再算运行,又得不到全局最优。双层优化(Bi-level Optimization)把这两层决策分开建模,上层管规划、下层管运行,上下层通过共享变量和运行成本反馈互相迭代、最终收敛到均衡解。这是这类项目的主流技术路线,也是我在这个课题里采用的框架。
2. 双层优化配置模型:上层定容量、下层定运行
2.1 上层规划层的决策变量与目标函数
上层的角色是共享储能电站的投资运营方。决策变量包括:储能电站的额定功率(MW)和额定容量(MWh),以及是否建设、在哪些站点建设这些0-1变量。如果区域内有多个候选站址,还需要加入选址变量,这就让上层问题天然带有整数规划的特征。
上层目标函数是所有投资方视角下的综合经济性指标,一般是年化总成本最小化,包含几块:
- 储能电站的年化投资成本,用等年值法折算。电池本体、PCS变流器、土建和并网设备的投资单价不一样,寿命也不同,得分开算再乘资金回收系数。
- 年运行维护成本,包括固定运维费和随充放电量变化的可变运维费。
- 向电网购电的成本,以及向微网购售电的结算费用。
- 共享储能向微网收取的服务费收入,这一项在上层目标里是负成本(收益)。
举个例子,假设储能单位容量投资成本按1400元/kWh、PCS按800元/kW,寿命取10年,贴现率取8%,那资金回收系数大概是0.149。一座10 MWh/2 MW的储能电站,年化投资成本差不多就是 10×1000×1400×0.149 ≈ 208.6万元,加上PCS部分2×1000×800×0.149 ≈ 23.8万元,光设备折旧就200多万。这个数字直接决定了你不把运行收益做上去,共享储能方案根本算不过账。
2.2 下层运行层的调度模型
下层是每个微网在典型日(或者全年8760小时)的运行调度问题。目标函数是微网的日运行成本最小化,包括:向共享储能购电/售电的费用、从上级电网购电的费用、燃气轮机消耗天然气的成本、以及各设备的启停成本。
约束条件比上层还多,主要是:
- 电、热、冷三种能量的逐时平衡约束;
- 燃气轮机、燃气锅炉、吸收式制冷机、电制冷机等设备的出力上下限和爬坡约束;
- 储能电站的SOC动态方程和充放电功率约束;
- 微网与共享储能之间的功率交换约束。
这类下层问题是一个典型的混合整数线性规划(MILP),如果设备台数和调度时段控制在合理规模,商用求解器直接就能解。这里有一个关键点:下层问题的目标和约束里包含上层传来的参数(储能容量上限、服务价格),所以下层的最优解本质上是上层决策的函数。这个函数关系是我们后续做线性化处理的核心对象。
2.3 上下层耦合机制与求解思路
上下层之间靠什么耦合?两个东西:一是储能电站的额定功率和容量(上层定,下层把它作为约束上限);二是共享储能的服务价格(上层定,下层作为成本系数)。
这就构成一个典型的Leader-Follower(领导者-跟随者)博弈,也就是Stackelberg博弈。上层先决策,下层在给定上层决策下做最优响应,上层再根据下层的响应调整自己的决策,直到没有单方面改变策略的动机。
处理这个双层问题的主流方法有两种。第一种是把下层问题用KKT条件替代,转成单层带互补约束的数学规划问题(MPEC),再用大M法或者SOS1把互补约束线性化,最终得到MILP。第二种是启发式算法,上层用遗传算法或者粒子群,每一次迭代都调用下层求解器。我的做法是第一种为主,因为它能给出理论上有最优性保证的解,而不是启发式算法的"近似最优"。下文会详细展开KKT转化的细节。
3. 非线性问题的根源:模型中那些"不听话"的项
3.1 二进制变量带来的组合性与逻辑非线性
第一个非线性的来源不是函数形式上的非线性,而是组合爆炸。只要是带规划性质的问题,就离不开0-1变量:某个站点建不建储能、某台燃气轮机开不开机、储能处于充电还是放电状态。
0-1变量本身不产生数学意义上的非线性项,但一旦它和连续变量相乘,比如"机组运行状态 × 机组出力",就出现了双线性项,这在数学上属于非凸非线性,求解难度陡增。
最常见的例子就是储能的充放电互斥约束。很多初学者会写成:
P_ch(t) × P_dis(t) = 0
这个约束在物理上是对的——不能同时充放电——但它是非线性的,而且是非凸的。非凸意味着可行域不是一块"凸的连续区域",而是被切成了好几块不连通的碎片,这对求解器来说是非常糟糕的。正确做法是引入0-1变量,写成一堆线性不等式,后面会详细给公式。
3.2 效率-出力特性曲线引入的非线性
CCHP系统里的设备,效率曲线几乎全是非线性的。微型燃气轮机的电效率随负载率变化明显,满负荷时能到32%,半负荷可能掉到25%以下。如果我们把效率当常数处理,误差在部分负荷工况下能超过20%,这在工程上完全不可接受。
典型的热电联产机组模型里,燃料成本通常写成关于出力的二次函数:
C_fuel = a·P² + b·P + c
这个二次函数在目标函数里,如果是Min问题且系数是凸的,还能用二次规划处理。但如果它出现在约束里,或者和其他变量相乘,就麻烦了。类似的还有吸收式制冷机的COP随负荷率变化曲线、储能电池充放电效率随SOC变化曲线,都是非线性。
3.3 共享储能服务定价带来的双线性耦合
这是我这个项目里最特殊的一个非线性来源。共享储能电站的服务价格如果是决策变量(而不是固定输入参数),那么在下层运行模型里,微网支付的服务费 = 结算价格 × 购电量,就出现了"价格 × 数量"的双线性项。
这个双线性项还跨越了上下层:上层定价格,下层出电量。下层的最优电量响应是价格的函数,这个函数本身是非线性的(实际上是分段线性的,因为下层是LP/MILP)。所以价格变量进来之后,整个双层模型的非凸性进一步增强,这是很多同类研究直接把它当作给定参数、不加处理就绕过的原因。但我的观点是,服务价格恰恰是共享储能商业模式里最核心的调控杠杆,把它作为决策变量,模型才能真正回答"共享储能电站应该怎么收费"这个运营方最关心的问题。
3.4 其他隐藏的非线性项
还有一些容易被忽略的坑。比如储能寿命损耗模型,很多研究用吞吐量(累计充放电量)来近似寿命损耗,吞吐量本身是线性可加的,但如果引入充放电深度(DOD)对寿命的影响,就会出现非线性。又比如阶梯电价、需求响应激励这类政策机制,本质上是分段函数,处理得不好也会引入非光滑项。
我在建模阶段做了一个很实用的动作:把模型里所有可能出现非线性乘积的地方列了一张清单,逐项判断"能不能线性化、用什么方法线性化、线性化后会牺牲多少精度"。这张表是整个项目中后期没有反复返工的重要原因。
4. 线性化策略:把非线性问题"掰直"的实用方案
4.1 大M法:处理逻辑约束与0-1变量乘积
大M法是最基础的线性化工具,核心思想是用一个足够大的常数M配合二进制变量,把逻辑关系转换成线性不等式组。
以储能不能同时充放电为例。设u(t) ∈ {0,1}为充电状态标志位,P_ch(t)和P_dis(t)分别是充电和放电功率,P_max是最大功率,那么:
% YALMIP中定义约束 P_ch = sdpvar(24,1); P_dis = sdpvar(24,1); u = binvar(24,1); P_max = 500; % kW Constraints = [P_ch >= 0, P_dis >= 0]; Constraints = [Constraints, P_ch <= P_max*u]; Constraints = [Constraints, P_dis <= P_max*(1-u)];当u=1时,充电功率可以取到P_max,放电功率被强制为0;u=0时恰好相反。这样既满足了互斥约束,又保持线性。
再举二进制×连续变量的通用处理:z = x·y,其中x ∈ {0,1},0 ≤ y ≤ y_upper。引入辅助变量z,满足:
- z ≤ y_upper·x
- z ≥ 0
- z ≤ y
- z ≥ y - y_upper·(1-x)
这个公式组特别常用,我几乎在每个储能项目里都用到。但这里有个重要的实操细节:M的取值非常有讲究。M取得太小,比如小于y的实际最大值,会错误地削减可行域;M取得太大,比如1e9,会导致求解器数值条件恶化,LP松弛质量变差,分支定界效率骤降。我的经验是M取实际物理边界的1.5~2倍就够,没必要追求"大得安全"。
4.2 分段线性化:逼近非线性效率曲线
对于效率曲线、成本曲线这类单变量非线性函数,分段线性化是标准做法。
思路很简单:把函数定义域切成N段,每段用一条直线近似。在数学上,可以用SOS2约束的λ法,或者用增量法(Incremental Method)实现。
以燃气轮机的燃料成本二次函数C_fuel = a·P² + b·P + c为例,设在出力的定义域[P_min, P_max]内选择断点P1, P2, ..., Pn,对应的函数值为C1, C2, ..., Cn。引入非负变量λ1, λ2, ..., λn,要求∑λ = 1,且最多两个相邻的λ非零(这就是SOS2约束),那么:
P = ∑λi·Pi C = ∑λi·Ci
用增量法的话则不用SOS2,效率更高。具体做法是给每个区间引入一个分段变量δk ∈ [0, 1],表示该区间内的占比,配合二进制变量控制区间的连续性。增量法在Gurobi里的表现比λ法好,因为它的LP松弛更紧。
分段线性化的精度取决于段数。我实测过一个案例:燃料成本函数切成5段时,目标函数误差约1.8%;切成10段,误差降到0.4%左右;再往上切,精度提升就不明显了,但求解时间几乎线性增加。所以我在项目中默认取8~10段,这是一个精度和效率都比较平衡的点。
4.3 McCormick松弛:处理双线性项的标准武器
对于"连续变量×连续变量"的双线性项,比如w = x·y,McCormick松弛是目前工业界最常用的方法。它利用x和y的上下界信息,构造w的凸包络。
假设x∈[xL, xU],y∈[yL, yU],McCormick包络由四个不等式构成:
- w ≥ xL·y + x·yL - xL·yL
- w ≥ xU·y + x·yU - xU·yU
- w ≤ xL·y + x·yU - xL·yU
- w ≤ xU·y + x·yL - xU·yL
这四个不等式给出的区域是双线性等式w=xy的凸松弛。松弛的紧密程度完全取决于x和y的上下界有多紧。我踩过的坑是:如果上层给储能容量的取值范围太宽,比如0到100 MWh,下层电价变量0到2元/kWh,McCormick松弛出来的区域非常松,最终得到的最优解和真实最优解差得很远。
解决办法是尽可能收紧变量边界:容量上限要根据区域负荷总量来推算,服务价格的上下限要根据替代方案(比如自建储能的成本、峰谷电价差)来标定。边界越紧,松弛越紧,解的质量越高。
下面这张表是我在项目里整理的不同线性化方法适用场景,对照着选择能省不少试错时间:
| 非线性类型 | 典型场景 | 推荐方法 | 精度损失 | 实现难度 |
|---|---|---|---|---|
| 0-1变量×连续变量 | 机组启停与出力耦合 | 大M法 | 无(精确) | 低 |
| 单变量非线性函数 | 效率曲线、燃料成本曲线 | 分段线性化 | 可控(依赖段数) | 中 |
| 连续×连续双线性项 | 价格×电量、容量×利用率 | McCormick松弛 | 较大(依赖边界紧度) | 中 |
| 互补约束 | 双层模型KKT转化 | 大M法或SOS1 | 无(精确) | 高 |
4.4 下层LP问题的KKT等效转化
处理双层问题的关键一步,是把下层优化问题"嵌入"到上层问题里。如果下层是线性规划(LP),可以用KKT条件精确替换下层问题,得到包含原问题所有变量的单层约束系统。
KKT条件包括三组:
- 稳定性条件(Stationarity):拉格朗日函数对各变量求导为零;
- 原始可行性(Primal feasibility)和对偶可行性(Dual feasibility):原变量和对偶变量满足各自的不等式约束;
- 互补松弛(Complementary slackness):每个不等式约束和对应的对偶变量乘积为零。
其中互补松弛条件是非线性的——对偶变量×松弛变量=0。对于这种乘积项,可以用大M法线性化:引入二进制变量和足够大的M,把乘积为0等价转化为两条线性不等式。也可以用SOS1约束直接表达"两个非负变量中至多一个为正",很多求解器原生支持SOS1,数值稳定性比大M法更好。
这一套下来,原来的双层非线性规划就被转换成了单层MILP,可以扔给Gurobi或CPLEX直接求解。我在YALMIP里用kkt命令快速搭建原型,但在生产版本里是自己手动推导KKT并逐条写成约束的,因为YALMIP自动生成的KKT往往带有过多冗余变量,求解效率会打折扣。
这里需要提醒一个容易踩的坑:用KKT条件替换下层问题时,必须确认下层问题是凸的(线性规划天然满足),否则KKT条件只是必要条件而不是充分条件,替换之后解出来的"均衡"可能根本不是下层的最优响应。如果你实在需要处理非凸的下层问题,就得考虑用启发式算法或者对偶间隙分析,那复杂度会上一个台阶。
5. 求解框架搭建与算例验证:从模型到结果的最后一公里
5.1 建模平台与求解器选择
我的技术栈是MATLAB + YALMIP + Gurobi。选这几个工具的原因是:YALMIP建模快,适合快速验证模型逻辑;Gurobi的MILP求解器在同类软件里目前是性能天花板,尤其是它的Presolve和分支策略,对于这种动辄几万个变量的大模型非常关键。
如果你偏好开源方案,Python + Pyomo + CBC也能做,但在大规模MILP上求解速度差距还是比较明显的。我自己的建议是:初期模型调试可以用开源求解器跑通逻辑,最终数值实验用商用求解器出结果。Python生态里还有一个值得关注的库叫PAO(Pyomo Algebraic Optimization),专门做双层优化,但成熟度还有待观察。
求解器参数设置有几个值得注意的点。MIPGap建议设到0.1%甚至0.05%,我项目里的目标函数是千万级别的年化费用,0.1%的gap对应几千块钱的误差,可以接受。TimeLimit要结合算例规模设置,我在72时段×5微网的算例下,一般给3600秒上限。另外,Gurobi的MIPFocus参数也很关键,如果模型主要是为了搜索可行解,设成1;如果上界已经很好但想证明最优性,设成3。我在项目中后期把MIPFocus设为2(强调最优性),求解器更倾向于对当前最优解做改善而不是漫无目的地探索新区域。
5.2 算例参数设计与场景构建
算例设计的好坏直接决定项目报告的"说服力",但这个环节最容易翻车。我的做法是分三步。
第一步定系统拓扑。我采用了3个冷热电联供微网+1座共享储能电站的典型结构,3个微网的负荷曲线分别设为居民型、商业型和工业型,峰值错开,这样能充分体现共享储能的容量复用价值。居民型负荷晚高峰明显,商业型负荷白天平稳、傍晚骤降,工业型负荷全天波动小而基数大。三者的合成负荷曲线比任何单一微网都平滑得多。
第二步设设备参数。每台微型燃气轮机的额定功率设为500 kW,电效率曲线取典型数据,余热回收率0.65,吸收式制冷机COP取1.2,电制冷机COP取3.5,锂电池储能的充放电效率各取0.95。这里要特别强调的是,设备参数不要只从厂家手册抄,最好用实测数据或者至少是经过同行评议的文献数据,否则审稿人一问数据来源就尴尬了。
第三步是场景设置。为了控制计算量,我选了夏季典型日、冬季典型日、过渡季典型日各1天,每天24个时段,一共72个调度时段,代表全年的运行情况。这样比直接跑8760小时省一个数量级的计算时间,同时能覆盖主要工况。每个典型日的权重分别为0.25、0.25、0.5(全年来看过渡季时间最长),这个权重系数直接乘在运行成本上,可以换算成年化值。
5.3 结果对比与关键指标
我跑了四组对照实验:方案一每个微网自建储能;方案二使用共享储能但服务价格固定;方案三使用共享储能且服务价格为决策变量;方案四是理想情况(不考虑储能容量约束,作为成本下限参考)。
几个重点看的数据:
- 总年化成本:共享储能方案比自建方案低大约18%~25%,这个差异主要来自容量复用和规模效应;
- 储能利用率:共享储能电站的年等效充放电循环次数比各微网自建储能高出一倍以上;
- 求解时间:线性化之后MILP求解时间在200~1500秒之间,同一个问题如果不做线性化直接交给非线性求解器,不仅慢,而且经常找不到可行解。
还有一点想提醒:算例结果一定要做敏感性分析。我测试了共享储能服务价格从0.2元/kWh到0.8元/kWh变化时,各微网的最优容量配置和成本变化。结果发现价格超过0.6元/kWh以后,部分微网会选择减少向共享储能购电、增加自己机组的出力,这说明价格信号对用户行为有很强的引导作用——这个结论对共享储能的运营定价有直接参考价值。
6. 踩坑记录与工程落地体会
6.1 Big-M取值是线性化精度和数值稳定性的命门
整个项目里我在这上面翻过两次车。第一次是M取值太小,导致某些可行解被切掉了,结果看起来"很理想",但实际上是错误的可行域。第二次是另一个参数M取到了1e8,求解器在分支定界时数值混乱,出现了一些诸如"0.0001 > 0"的荒谬矛盾。
我现在养成了一个习惯:每一个M都手动核对数量级,全模型扫描一遍,保证M相对于该约束里的最大可能量级只大一个数量级左右。宁可多花半小时做这一步,也好过求解器跑了两小时给你一个数值噪声导致的次优解。在Gurobi里还可以开启NumericsFocus参数(设为2或3),让求解器在数值困难时自动切换到更稳健的算法路径,但这个只能兜底,不能依赖。
6.2 求解时间与模型规模的博弈
双层优化最大的现实挑战是真难收敛快。KKT转化之后的MILP,变量数量是原问题的好几倍,尤其互补约束需要引入大量二进制变量,分支定界的搜索树会变得很深。
我的经验是三个降规模的技巧。第一,对称性破坏:微网如果结构和参数相似,会存在大量对称解,求解器会在这些等价解之间反复搜索。加一些对称性破坏约束(symmetry breaking constraints),比如按负荷大小给微网排序、要求容量配置随负荷非递减,能显著加速求解。第二,初始解注入:先用一个简化模型(比如把共享储能服务价格固定)跑出一个可行解,作为MILP的MIP start,让求解器在分支定界一开始就有一个好的上界。实测这一步能把求解时间压缩30%~40%。第三,适当合并时段:如果对精度要求不那么苛刻,把24时段合并成12个两小时时段,模型规模直接减半。
6.3 线性化精度与模型保真度的取舍
线性化本质上是"用可解性换保真度"。McCormick松弛给出的是原问题的松弛解,如果松弛太松,最优值会比真实值偏低,你以为省钱省了很多,实际做不到。分段线性化则相反,是给原问题加了近似约束,最优值可能会比真实值略高。
我在项目报告里都是这样处理的:在3个微网的小规模算例上,用非线性求解器(比如SCIP)直接解MINLP问题,拿结果和线性化模型的结果做对比。如果两者的目标函数差距在3%以内,就认为线性化策略是可接受的;如果超过5%,就需要加密分段数或者收紧边界重新求解。这个"线性化前后验证"步骤,在审稿和项目评审时非常加分,它证明你的线性化不是拍脑袋。
6.4 工程落地层面的几点思考
最后聊点模型之外的东西。共享储能电站在真实世界落地,难点远不止数学建模。第一个体之间的信任和结算机制——多微网共享一个储能,谁用了多少电、谁该付多少钱,需要透明可信的计量和结算系统,这是目前很多示范项目卡壳的地方。第二个是调度权归属——共享储能的充放电指令由谁下发?独立运营商、微网聚合商还是电网调度?不同模式对应的模型结构完全不同。
第三个是边界条件——真实工程里储能还要参与一次调频、备用、需求响应等辅助服务,收益来源比模型里的"峰谷套利+容量费"复杂得多。我在这篇模型里没有把这些服务都展开,但它们完全可以作为约束条件或收益项加进来。
我在后续的研究方向里,会把这些机制设计问题和优化模型结合起来做,比如在双层模型里加入收益分配机制、考虑多主体之间的合作博弈,以及把共享储能的服务模式从"按电量结算"扩展到"容量租赁+辅助服务"的多元套餐。模型从论文走向工程,中间的路还很长,但先把非线性这座山翻过去,后面的事会顺很多。如果这篇内容能帮你在建模和求解的路上少走点弯路,那这些坑就算没白踩。