先说结论:这个项目核心就三件事,建模、调度、分钱。综合能源系统现在不是什么新鲜概念,但真正落地时最头疼的不是设备选型,也不是潮流计算,而是“多个利益主体怎么合作、合作之后怎么分钱”。单独运行的园区、楼宇、社区各自追求自身成本最小化,结果就是整个系统的设备利用率上不去,可再生消纳也受限。但如果把几个主体捏在一起搞联合调度,总成本确实能降下来,新的问题马上又来了——省下来的钱怎么分?分得不公平,联盟明天就散伙。合作博弈就是干这个的。
这个项目其实是一套完整的Matlab实现方案:用合作博弈理论搭建综合能源系统多个主体之间的利益分配框架,把优化调度和收益分配串成一条线。调度层负责算出联盟总成本最低的运行方案,博弈层负责把联合运行产生的增量收益合理地摊到每个主体头上,最终输出一套“既让系统整体最优、又让每个主体都愿意留在联盟里”的运行策略。适合想深入研究园区级综合能源系统、多主体协同优化、或者正在写相关方向论文的同学,也适合已经在做能源系统优化、想把博弈论真正用起来的工程师。整体代码框架清晰,参数可调,拿到手改改数据就能跑出自己的场景。
1. 项目整体设计与思路拆解
先说清楚这个项目为什么要用“合作博弈”这个工具,它到底解决了什么问题。
综合能源系统里,不同主体之间的能量耦合非常强。A园区有富余的余热,B楼宇刚好缺热;C社区光伏大发的时候用不完,D工厂正好需要电力。这些供需关系是天然存在的,但各个主体独立调度时,A园区只会考虑自己的热需求,多余的热就排掉;C社区的光伏电只能低价上网。如果让它们组成一个联盟统一调度,A园区的余热正好补上B楼宇的缺口,C社区的多余光伏电直接卖给D工厂,大家都能获益。
这个收益是真实存在的,但它不是自动产生的,需要两件事同时成立:
- 调度层面:联盟需要有一个统一优化的运行方案,告诉每个主体“你什么时候该开CHP机组、什么时候该买电、什么时候该放电”,从物理层面把互补的潜力挖出来。
- 分配层面:优化完成后产生的总成本比各主体单独运行成本之和要低,这个差值(也就是联盟的收益)需要公平分给每个成员,否则谁都不傻,分少了下次就单干。
项目里的合作博弈模型就是用来解决第二个问题的。它是怎么设计的,可以分三层看:
第一层是物理系统层。每个主体内部都有一套冷热电联供系统,核心设备包括燃气轮机或内燃机(CHP)、燃气锅炉、电锅炉、吸收式制冷机、储能设备(蓄电和蓄热)等。这些设备的能量输入输出特性、效率曲线、运行约束,是这个项目模型里最基础的部分,也是调度优化的可行域来源。
第二层是调度优化层。针对任意一个联盟(可以是单个体、也可以是多个主体组合),构建一个以联盟总运行成本最小为目标的优化模型。决策变量包括各设备的出力、储能充放功率、与外网购售电功率等,约束包含功率平衡、设备出力上下限、储能容量限制等。求解这个优化问题,能得到该联盟的最小运行成本。
第三层是利益分配层。对所有非空子联盟分别求解上述优化问题,得到每个子联盟的运行成本后,就能算出合作博弈的特征函数——联盟的总收益增量。然后利用分配方法(比如Shapley值、核仁)把这个总增量收益分配给各个主体。这一步是项目的核心创新点所在。
整个逻辑链条是一个“先优化求解、后博弈分配”的串联流程。最开始做这个项目时我差点走弯路,想把调度和博弈放到一个双层优化框架里同时求解。后来发现完全没必要,因为合作博弈的分配环节本质上是一个“后处理”过程,调度是米,分配是分饭,先把饭做出来再谈怎么分,分开处理反而更清晰、更容易调试。
2. 核心建模原理与关键参数解析
这块是项目技术含量最集中的地方,也是网上资料讲得最含糊的部分。整个模型的数学表述看起来头大,但拆开就几块。
2.1 单主体设备模型怎么搭
每个能源站内部的设备建模是基础,这里简要展开几个核心设备的模型表达:
CHP机组是系统的核心。它的输入是天然气,输出是电和热。数学模型的关键在于电出力P和热出力H之间存在耦合关系,通常用热电比来刻画:
H_CHP = k * P_CHP其中k是热电比。这个参数在实际工程中由机组类型决定,比如常见的燃气轮机电热比在1.0到1.5之间。更精确的模型还会加上效率随负荷率变化的曲线,但项目主体用线性化处理就够了,效果已经不错。
燃气锅炉模型简单,就是天然气输入转化成热输出,效率一般在0.85到0.95之间。储能设备的模型核心是SOC状态转移:
SOC(t+1) = SOC(t) + P_charge * eta_ch - P_discharge / eta_dis - SOC_loss这个公式非常关键,需要重点解释。SOC的上下限通常设0.1和0.9,不能充满也不能放空,原因有两方面:一是蓄电池过充过放会极大加速寿命衰减;二是在优化模型里,SOC边界设置过宽会导致求解器在目标函数的引导下总是把储能塞到极限,实际根本跑不出来。充电效率eta_ch和放电效率eta_dis都取0.9到0.95,差异来自于变流器损耗和内阻损耗。
外网购电模型要区分“从电网买电”和“向电网卖电”两个变量,不能用一个自由变量表示。原因很简单,同一个节点同时买电和卖电在数学上可行,但物理上不可能,实际上还会导致求解结果出现“边买边卖”这种荒唐方案。所以必须拆成两个非负变量,让求解器去自己选择。
2.2 调度优化模型的目标函数
联盟S的调度目标函数是具有代表性的,所有成本项加总的形式。举一个典型目标函数:
min C_total = sum(C_gas + C_elec_buy + C_om + C_curtail - R_elec_sell)拆开看:
- C_gas是燃气成本,等于天然气耗量乘以气价,CHP和燃气锅炉都会消耗天然气。
- C_elec_buy是购电成本,按分时电价计算。这里需要注意,购电的价格是有峰谷平段的,晚上10点之后的低谷电和白天高峰电可能相差3倍以上,这会极大影响储能充放策略。
- C_om是运维成本,通常按设备出力的比例折算,燃气轮机每发一度电的运维成本大概取值0.02到0.05元/kWh。
- R_elec_sell是售电收入,这实际上是在减少总成本。但要注意,上网电价远低于购电价,所以一般不会出现故意多发电再卖给电网的情况。
约束条件集中在这几块:
- 电功率平衡:CHP出力加光伏加放电功率加购电,等于电负荷加充电功率加售电。
- 热功率平衡:CHP产热加燃气锅炉产热加蓄热放热,等于热负荷加蓄热充热。
- 设备出力上下限:每台设备的出力在最小技术出力和最大出力之间,最小技术出力这个值特别重要,很多燃气轮机最小出力是额定容量的30%到50%,这个约束会直接影响夜间低负荷时的调度方案。
- 爬坡约束:CHP在相邻两个时段的出力变化不能超过机组的爬坡速率,通常每分钟1%到3%额定容量,折算成1小时就是0.6到1.8倍额定容量之间。很多初学者会漏掉这个约束,结果优化出来的方案看着很好,现场根本执行不了。
- 储能SOC约束:如上文所述,包括SOC上下限、充放功率上限、以及充电和放电不能同时进行的逻辑约束。
2.3 合作博弈模型设计
合作博弈部分,先定义“特征函数”。对有N个主体的综合能源系统,任意子集S(子联盟)都会有一个特征值v(S),表达该联盟通过协调调度能够获得的总收益(定义为各成员单独运行成本之和减去联盟统一运行成本)。
需要特别澄清一个点:在计算v(S)时,联盟内部的成员是合作调度的,但联盟与联盟外的成员是独立运行的。所以v({i})等于主体i单独运行时的成本节约量(通常设为0或相对值),v({i,j})等于主体i和j组成联盟共同优化时的成本节约量,以此类推。总共需要求解2的N次方减1个不同联盟的调度优化模型,这正是项目计算量大的根源。
然后,用Shapley值来分配联合收益。Shapley值的公式在这里可以写出来:
phi_i = sum_{S not containing i} [ ( |S|! * (N-|S|-1)! ) / N! ] * ( v(S ∪ {i}) - v(S) )直观理解就是:主体i加入任意一个联盟S时带来的边际贡献,对所有可能的联盟顺序求加权平均。权重是小数量的联盟更可能先形成所以权重更大。
Shapley值是唯一满足对称性、虚拟性、可加性等公理的分配方案,理论性质很好。缺点也很现实:对N个参与者需要计算N!种排列,实践中的N较大的时候必须采用近似方法(比如蒙特卡洛采样)。对于N=3到5的典型园区场景,精确计算完全没有问题。
另外一个可选的分配方法是核仁,它基于超出的概念,通过不断缩小分配集合让最小分配尽量均匀。核仁的计算需要反复求解线性规划问题,实现难度更高,但它的好处是分配结果一定满足所有子联盟的“个体理性”,不容易被任何小团体推翻。
3. Matlab实现要点与关键代码逻辑
接下来是项目中实操性最强的部分——这一套方法到底怎么用Matlab落地。这个项目整体是基于Matlab + YALMIP + 求解器(Gurobi或CPLEX)的架构,这个组合在能源系统优化领域非常常用。
3.1 数据结构怎么设计
写代码之前先想清楚数据怎么组织,否则后面会越改越乱。推荐用结构体数组(struct array)来存每个主体的设备参数。每个主体是一个结构体,字段包括:
agents(i).P_CHP_max % CHP最大电出力 agents(i).k_HP % 热电比 agents(i).eta_boiler % 锅炉效率 agents(i).P_PV % 光伏预测曲线 agents(i).Load_e % 电负荷曲线 agents(i).Load_h % 热负荷曲线 agents(i).SOC_max % 储能最大SOC agents(i).SOC_min % 储能最小SOC把参数全部堆在一个结构体数组里,好处是可以只用一层循环遍历所有主体,而且构建某个联盟的模型时自然把对应结构体索引传进去就行,不用搞一堆并行数组。
另一个关键设计是联盟枚举。N个主体时,用二进制位掩码来枚举所有非空子集,这是成熟的枚举方法。对于N=4,子集编号1到15,二进制为0001到1111,哪一位是1就代表哪个主体在联盟中。用这一招可以写一个循环解决所有联盟的调度问题。
3.2 调度模型怎么构建
这是项目核心中的核心。用YALMIP语言构建联盟S的调度模型,最典型的核心片段如下:
function [cost, detail] = solve_agent(agent, price, H) % 输入:agent结构体、电价/气价、时段数 % 定义变量 P_chp = sdpvar(1, H, 'full'); % CHP电出力 H_chp = sdpvar(1, H, 'full'); % CHP热出力 P_boiler = sdpvar(1, H, 'full'); % 锅炉热出力 P_buy = sdpvar(1, H, 'full'); % 购电功率 P_sell = sdpvar(1, H, 'full'); % 售电功率 SOC = sdpvar(1, H+1, 'full'); % 储能SOC P_ch = sdpvar(1, H, 'full'); % 充电功率 P_dis = sdpvar(1, H, 'full'); % 放电功率 % 约束 Constraints = []; for t = 1:H % 电平衡 Constraints = [Constraints, P_chp(t) + P_dis(t) + P_buy(t) ... == agent.Load_e(t) + P_ch(t) + P_sell(t)]; % 热平衡 Constraints = [Constraints, H_chp(t) + P_boiler(t) ... == agent.Load_h(t)]; % CHP热电耦合 Constraints = [Constraints, H_chp(t) == agent.k_HP * P_chp(t)]; % 爬坡约束 if t > 1 Constraints = [Constraints, ... -agent.ramp <= P_chp(t) - P_chp(t-1) <= agent.ramp]; end % 储能SOC递推 Constraints = [Constraints, SOC(t+1) == SOC(t) ... + P_ch(t) * agent.eta_ch - P_dis(t) / agent.eta_dis]; % 充放互斥和上下限 Constraints = [Constraints, P_ch(t) <= agent.P_ch_max * u_ch(t)]; Constraints = [Constraints, P_dis(t) <= agent.P_dis_max * u_dis(t)]; Constraints = [Constraints, u_ch(t) + u_dis(t) <= 1]; end % 目标函数 Cost = sum(price.gas * (P_chp * agent.CHP_fuel_rate + P_boiler / agent.eta_boiler) ... + price.buy .* P_buy - price.sell .* P_sell ... + agent.c_om * P_chp); % 求解 optimize(Constraints, Cost); cost = value(Cost); end这段代码虽然做了大幅简化,但把核心逻辑都体现出来了。有几个细节值得专门说明:
充放互斥约束必须用二进制变量u_ch和u_dis实现。有些资料上推荐用线性不等式P_ch <= M*(1-u_dis)这样的技巧,但实操中直接用binvar加上u_ch+u_dis<=1更稳,因为M的取值如果选得不好会影响求解器数值稳定性。充放互斥在数学上不是严格必需的,因为如果同时充电和放电,两者相抵后对外效果为零,但白白浪费效率损失。理论上求解器会自动避免这种情况,因为同时充放会增加成本(充电耗电、放电收益),除非目标函数里没有惩罚充放动作的项。但是把互斥约束显式加上可以让模型更严谨,也更容易向导师或同行解释。
SOC的维度设为H+1。这意味着要处理初始状态和末状态。通常设SOC(1)=0.5(初始50%),末状态SOC(H+1)要不要约束,取决于场景。如果做日前调度(24小时),一般会加SOC(H+1)=SOC(1)这个约束,因为储能不可能只用一个周期。如果做滚动优化,末状态可以自由优化。这一点最好提前想清楚,改起来很麻烦。
3.3 特征函数和Shapley值计算
计算每个联盟的成本后,特征函数和Shapley值的计算就很直接了。算法流程是:
% 1. 枚举所有子联盟 N = length(agents); cost_ind = zeros(1, N); % 单个主体成本 cost_coal = zeros(1, 2^N-1); % 所有联盟成本 % 2. 先算单主体成本(单独运行) for i = 1:N cost_ind(i) = solve_agent(agents(i), price, H); end % 3. 算联盟成本 for mask = 1:2^N-1 % 提取联盟中主体索引 idx = find(bitget(mask, 1:N)); coalition_agents = agents(idx); cost_coal(mask) = solve_coalition(coalition_agents, price, H); end % 4. 计算特征函数(收益增量) baseline = sum(cost_ind); v = baseline - cost_coal; % v(mask) 是联盟可以带来的收益 % 5. Shapley值 phi = zeros(1, N); for i = 1:N for mask = 0:2^N-1 if bitget(mask, i) == 0 S_size = sum(bitget(mask, 1:N)); w = factorial(S_size) * factorial(N - S_size - 1) / factorial(N); v_S = coalition_value(mask); % v(S) v_S_i = coalition_value(mask + 2^(i-1)); % v(S∪{i}) phi(i) = phi(i) + w * (v_S_i - v_S); end end end写好之后跑一个三主体的案例验证,会发现这个模块的计算量很可观。每个联盟都要完整求解一个调度模型,联盟数量是2^N-1,每个模型可能包含几百个变量和约束。N=5时已经需要算31个调度模型,好在每个模型规模不大,Gurobi几秒钟就能解完一个,总共也就几分钟。
3.4 求解器的选择与配置
这里有个很实际的问题需要重点说明:用YALMIP还是直接用MATLAB自带优化工具箱?直接用linprog当然可以处理线性规划问题,但代价是手写矩阵约束,模型一复杂就非常痛苦。YALMIP相当于一个建模层,让你用符号变量的方式描述优化问题,后面接什么求解器都行,换求解器只改一行代码。
求解器配置如下:
options = sdpsettings('solver', 'gurobi', 'verbose', 0); optimize(Constraints, Cost, options);实测下来,这个项目场景中Gurobi的表现是最好的,CPLEX次之。Gurobi的www.license需要申请学术license,很多高校都有授权。如果学生拿不到正式license,可以先用测试license,限制是模型规模不能太大。其实这个项目的模型规模不大,测试license完全可以跑下来。
4. 调度方案与利益分配的联动设计
这一部分讲清楚“先算成本、再分钱”的全流程,以及分配结果如何闭环保真。
4.1 单主体运行与联盟运行的对比逻辑
项目设计了一个很实用的对比框架。首先是基准情形:每个主体完全独立运行,各自优化各自的调度,得到单主体运行成本之和,这是联盟合作的“谈判破裂点”。然后是联盟情形:所有设备资源放在一起统一调度,得到联合运行成本。两者的差值,就是合作创造的价值。
举一个典型场景:某园区配了CHP机组、光伏和蓄电设备,白天光伏大发加CHP满发,电用不完就低价卖给电网;隔壁数据中心晚上负荷很高,但自己没装任何分布式电源,全靠从电网买高价电。如果二者联合调度,园区的多余电低价直供数据中心,数据中心省了高价购电费,园区减少了低价卖电损失,联合运行成本比独立运行低百分之八到十五。双方合理分配这部分收益,各取所需。
这部分在Matlab里实现时,输出结果需要包含几个关键数组:
- 每个单主体的成本费用明细,包括购电、燃气、运维、售电收入。
- 联盟总调度方案,包括每个小时各设备的出力。
- 每个主体的收益分配结果(phi值)。
有了这三个数组,就可以画出两份核心图表:一份是调度最优功率平衡图(各设备24小时出力曲线和负荷曲线叠加图),另一份是成本分配占比图(每个主体从合作收益中分到多少)。这两张图是论文和汇报时的标配。
4.2 分配机制如何验证合理性
Shapley值算出来之后,不是直接拿去用就完事了,还要做合理性验证。这个验证有几个关键指标:
个体理性:每个主体分到的收益要大于等于它不合作时的收益。换算成成本是phi_i >= 0。如果某个主体分配结果是负的,这意味着它加入联盟反而亏了,它一定会选择退出。这个约束在Shapley值下天然满足,因为Shapley值分配是预算平衡的,但如果是用其他近似方法,就需要专门检查。
集体理性(帕累托最优):各主体分配收益之和等于联盟总收益。Shapley值天然满足,核仁也满足。
联盟稳定性(核心条件):对任意子联盟S,sum(phi_i for i in S) >= v(S)。意思是任何一个小团体通过单干能得到的收益不能超过它在联盟里的分配总和,否则它没有理由陪着联盟玩。Shapley值不保证一定满足核条件,这时需要用到核仁。所以项目最终会输出一个核条件检验表,标注哪个分配机制违反了哪个约束。
这里还有一个小细节值得注意:特征函数v(S)是基于成本差算的收益,但收益也可以用相对百分比来表示。比如联盟总收益是10万元,A分4.2万、B分3.1万、C分2.7万,换算成百分比就是42%、31%、27%。展示时用绝对金额更高效,换算成百分比反而丢失了规模信息,文献里两种都有。
4.3 分配结果如何反馈到调度策略
这个项目做得深的一点是:分配结果不是终点,它还会影响实际调度执行。
分配完成后,可以用Shapley值算出一个内部结算电价(或热价),让每个主体按照这个内部价格与联盟内的其他主体交易。比如,Shapley值算出来,A主体在联盟中分摊了5%的总购电成本,那内部电价就可以按比例分摊来定。内部价格作为信号,各个主体会在下一轮调度时自发调整自己的用能行为。
从实操角度,实现方式是在Matlab里做两轮优化:第一轮算联盟最优调度,得到成本和收益;第二轮用市场均衡价格替代内部结算价(解决报价问题),每个主体根据内部价格独立做自己的决策,验证最终结果是否收敛到联盟最优方案附近。这一整套流程下来,项目就不只是“划算不划算”的理论分析,而是一个闭环的可执行方案。
5. 仿真结果分析方法与案例展示
写完代码必须跑出结果才说明事情闭环了。这一部分分享项目中几个经典的仿真场景设置和结果分析方法。
5.1 经典案例设置
用三主体系统做标准测试案例特别合适。三个主体分别为:
- 主体A:工业厂区,配备CHP机组(1MW电、1.5MW热)、燃气锅炉、蓄电系统。白天电负荷很高,夜间低。热负荷全天比较平稳。
- 主体B:商业楼宇,配备光伏和电储能,但无燃气设备。电负荷集中在白天,热负荷需求很低。
- 主体C:居民社区,配备燃气锅炉,无CHP。晚上电热负荷高峰,白天低。
三个主体的负荷和产能特征有很强的互补性。A白天电力富余、余热多,B白天电负荷高但自己光伏可能不够,C夜间热负荷高但没有高效热源。任何一个主体单干都要花冤枉钱,组合在一起则互相补缺。
参数设置上,电价采用峰平谷三段式,峰时电价1.1元/kWh、平时0.68元/kWh、谷时0.32元/kWh;气价2.5元/立方米;天然气低位热值按照每立方米可产9.5kWh热来折算。这些参数选择都会影响最终的调度结果和分配比例,写论文时一定要说明参数的依据,不能全凭感觉拍脑袋。
5.2 两个核心输出图表
项目跑完需要展示以下核心结果:
成本对比柱状图:三根柱子分别代表“各自独立运行总成本”“三体联盟运行总成本”“Shapley分配后各主体分摊成本”。从图上可以直观看到联盟总成本确实低了一大截,而每个主体分摊的成本也比独立运行少。这张图就是整个项目的“灵魂图”。
调度功率平衡曲线:画联盟最优调度下,每个小时的电源出力(CHP、光伏、放电、购电)与负荷的堆叠面积图。这张图能让你检查调度方案是否合理。比如,如果夜间CHP还在满发,而同一时段却还在大量购电,这就说明模型有问题——要么约束写错了,要么目标函数出了问题。
5.3 敏感性分析怎么做
项目做完基础案例后,强烈建议补一个敏感性分析,这是论文加分项,也是理解系统特性的关键。
做法很简单:固定其他参数不变,把气价从2元/立方米扫到4元/立方米(步长0.2),分别重新求解整个调度和分配流程,记录下来每个主体分配收益的变化。最终你会发现很有意思的现象:
- 气价低时,CHP是绝对主力,谁的CHP容量大谁的话语权就强,分到的收益更多。
- 气价高时,CHP的优势缩小,光伏和储能的边际贡献比重上升,分配结果会向新能源侧倾斜。
- 电价峰谷比拉大后,储能的价值显著提升,分配结果重新向储能资源倾斜。
这个敏感性分析结果本质上说明了很重要的一点:合作博弈的分配结果反映了“稀缺资源”的价值变化,谁的资源在当前价格体系下对联盟贡献更大,谁就分得多。分析这个逻辑不但能帮助理解模型,还能在实际业务谈判中解释为什么某个主体应该多拿。
6. 常见问题与实战排查技巧
最后这部分内容最实在——把项目开发过程中踩过的坑集中整理一遍。这些问题在网上资料里很难找到,但做项目时基本都会碰到。
问题一:求解器报“Infeasible problem”(模型不可行)。
这是最常遇到也最让人头大的错误。常见原因和排查顺序:
- 功率平衡约束写反了。最简单的方法是先检查电平衡等式左右两侧的单位是否一致。把某个时刻的值手工代进去算一下,看看是不是负荷和出力的数量级对不上。
- SOC递推约束导致末值超出边界。比如SOC初始0.5,而负荷结构导致储能一直放电,末状态就被压到0以下了。解决办法是把SOC初值上调(0.6或0.7),或者放宽末状态约束。
- 爬坡约束过于严格。最小技术出力加爬坡约束,可能直接导致CHP在某个调度时刻没有可行解。可以先去掉爬坡约束跑一次,把可行域摸清楚,再逐步加回约束。
问题二:决策变量值出现“边买电边卖电”。
出现这个问题,大概率是把购电和售电建模成了同一个自由变量。也就是说,你让P_grid是一个自由变量,没有拆成P_buy和P_sell。这时候求解器如果发现买电和卖电同时出现在目标函数里可以“对冲套利”,就会出现这种情况。解决办法前面已经说了,拆成两个非负变量,另外还得加上P_buy * P_sell = 0的逻辑(但这是非线性约束)。不过在实践中这不是必需的:只要购电价远高于售电价,目标函数天然会让其中一个为零。
问题三:Shapley值算出来分配结果不满足个体理性。
这个问题的根源在于特征函数v(S)的定义方式。如果定义的是“联盟成本”,那分配也应该用“成本分摊”的语义;如果定义的是“收益”,那就要从总收益中分配。一旦混淆,算出来就会有的主体分不到任何好处甚至还要倒贴。碰到这个情况,先回头检查baseline和联盟成本是不是同一个口径。
问题四:YALMIP建模时用binvar导致求解速度极慢。
充放互斥用二进制变量,这是常规做法,但二进制变量会把线性规划变成混合整数规划,求解复杂度直线上升。如果发现模型太慢,有两个办法:
- 不显式加充放互斥约束,让目标函数自然地避免同时充放。
- 如果模型的N较大,把储能SOC分成多个分段线性段处理。
实测下来,对于24个调度时段、3到5个主体、每主体若干台设备的模型,Gurobi在默认参数下求解时间通常在几十秒到几分钟之间,属于完全可接受的范围。
问题五:不同联盟的调度结果迭代不收敛。
这个现象主要出现在加入内部价格反馈闭环时。内部价格变了,各主体的策略就变了,新策略又反过来影响联盟总调度方案,可能导致震荡。解决方法不是调参数,而是改变闭环设计:避免直接在调度层和分配层之间直接迭代,而是对所有主体同步更新内部价格,或者对内部价格做平滑处理,也就是新价格等于旧价格加比较小的步长乘以偏差,能有效抑制震荡。
7. 学习路径与扩展方向建议
整个项目跑通之后,下一步还可以做很多扩展,这也是写论文或做工程项目时最自然地延伸方向。
7.1 参与主体规模扩充
当前代码处理3到5个主体是没问题的,但如果扩展到十几个主体,Shapley值的精确计算就会遇到困难的组合爆炸问题。这时需要用近似方法,比较成熟的方案是蒙特卡洛采样估计Shapley值、或者用“截断采样的Shapley值近似算法”。这两种方法在游戏影响力分析(机器学习方向)里已经是成熟工具,可以直接借鉴思路移植到能源系统。
7.2 引入不确定性优化
目前所有负荷曲线和光伏预测都是确定性的。现实中光伏预测误差很大,负荷也有波动。把鲁棒优化或者随机规划引入调度层,然后在利益分配层把不确定性带来的成本增量也纳入博弈模型,团队合作时如何分配“风险收益”会变成一个有意思且前沿的方向。
7.3 动态合作博弈
现在做的是单时段静态博弈,即把一天24小时作为一个整体来合作,每天重新计算一次分配。但如果跨天、跨季节合作,比如光伏多发的夏天和热负荷高的冬天,把多个时段的收益捆绑在一起分配,就得到了动态合作博弈。这会极大提升模型的实际使用价值,也会显著增加论文的差异化亮点。
7.4 代码工程化改造
当前Matlab代码是单机仿真为主,很多调度优化的瓶颈在于巨大的计算量——每次改一个参数都要重新枚举联盟、求解所有模型。实际上可以很自然地做一个并行化改造:3到5个机制求解的任务分配到工作站的多核处理器上同时跑,2^N个联盟模型天然是相互独立的,不需要任何通信。Matlab里可以直接用parfor把联盟求解循环改成并行,实测5核并行比单核快四倍左右。
8. 个人实操经验与几点体会
项目写到最后一章,聊聊实操中比较深刻的几个体力感受。先做一个三主体案例,调试MODEL数小时之后,你会对整个系统理解的深度完全不一样——所有参数对结果的影响、所有约束条件的物理意义、每个变量在平衡方程里的来龙去脉,都会有一个异常清晰的认识。如果有条件,强烈建议先把三主体的完整流程手写推导一遍再开始写代码,这会节省你后面调错的更多时间。
第二点体会是关于模型粒度选择的。能源系统优化模型特别容易陷入“越精确越好”的陷阱——把设备效率做成非线性曲线、把电价做成时间序列动态模型、把管路延迟也建模进来。但调度和分钱这个层面,线性模型已经足够好了。非线性模型不仅求解慢,而且数值稳定性差,收益分配结果对参数非常敏感。所以做项目的原则是:能用线性表达就用线性,能简化就简化,先跑通再逐步加复杂度。
第三点体会是,合作博弈分配结果是否“合理”,本质上是个价值判断问题。Shapley值给出了理论最优分配,但实际谈判中可能更看重的是各方的“底线收益”和“谈判筹码”。项目的价值在于提供了一个科学的参考基准——每个人都知道公平分配大致是什么水平,才有进一步谈判的空间。这个思路,在做实际园区能源项目时比直接抛出一个Shapley值更有说服力,也更受项目方认可。
这套代码和思路后续还可以扩展什么方向,如果大家感兴趣,我可以把扩展部分的实现细节单独写一篇。整个项目从头到尾串下来后发现,合作博弈作为综合能源系统多主体协同调度的分配框架,不光是论文里的一个数学模型,它本质上提供了让不同能源主体从“零和博弈”走向“正和博弈”的机制设计思路。在双碳目标下,分布式能源和多主体协同的大趋势里,这套方法会有越来越多的应用空间。