基于纳什博弈的多微网电热双层共享策略MATLAB建模与复现解析
看到这个标题我第一反应是亲切。做电气或者综合能源方向的研究生这几年但凡碰过多微网共享储能电热联合调度这些关键词基本都绕不开纳什博弈这个坑。网上相关的源码和论文确实不少但真正能让人看得懂、跑得通、改得动的MATLAB代码其实不多。要么是论文写得云山雾罩公式推了一大堆代码里却对不上号要么是代码下载下来一跑就报错注释少得可怜根本不知道哪一步对应论文里的哪个模型。这篇博文我就结合自己的复现经验把《基于纳什博弈的多微网主体电热双层共享策略研究》这类工作从模型到代码完整拆一遍。我会尽量把论文里的黑话翻译成能跑起来的代码逻辑讲清楚纳什博弈在双层共享模型里到底扮演什么角色、电热耦合在MATLAB里怎么建模、求解流程怎么搭以及我在复现过程中踩过哪些坑。无论你是刚开始接触这个方向的新手还是已经被博弈论和双层优化折磨了一阵子的老手这篇文章都应该能给你一些实在的参考。1. 先把场景讲透多微网为什么需要电热双层共享很多人在复现之前就卡在了第一步想不明白这套模型到底在优化什么。这不怪大家因为纳什博弈双层共享电热耦合这几个词叠在一起信息密度确实大。我们先把它拆开来看。1.1 这个模型到底在优化什么先说多微网。多微网一般指的是一个配电网辖区内存在若干个地理位置相邻、但产权或管理主体不同的微网。每个微网内部可能有分布式光伏、风电、燃气轮机、CHP热电联产、电锅炉、热泵、储能电池、蓄热罐以及各自的电负荷和热负荷。如果每个微网各管各的会出现什么问题很典型的一个场景是A微网中午光伏大发电用不完只能弃光或者低价卖给配电网B微网这时候正好缺电却要按市场价从网上高价买电。如果A和B之间有一条联络线A把多余的电卖给B双方都比各自单独运行时更划算。热网侧的逻辑也一样C微网燃气轮机烧出来的余热自己用不完D微网的热负荷不够与其让C浪费热量、D再启动电锅炉制热不如让C把热送过去。这就是共享的价值。但这里有个关键问题A和C凭什么愿意把能量共享给别人如果调度中心强制分配那叫集中式优化不是主体自愿的行为。现实中的微网运营商大概率不愿意把自己的运行数据、成本信息全部交给一个中心。这时候就需要博弈论出场——大家基于对自己最有利的目标在共享互动中自发地达成一个均衡状态。1.2 双层到底指的是哪两层标题里电热双层共享中的双层在不同论文里有不同的指向。在我复现的这类模型里通常包含两层含义物理层级上的电-热双网电功率通过联络线传输热功率通过热力管道传输。两者不是独立的因为CHP、热泵、电锅炉这些设备天生就横跨两个网络。这是物理层面的双层。决策层级上的共享运营商-各微网双层上层是一个共享运营商或调度机构制定共享电价/热价下层是各个微网主体根据上层给出的价格独立求解自己的经济调度问题。上层追求共享收益最大化下层追求自身运行成本最小化。这是决策层面的双层。更要紧的是这两个双层还耦合在一起电价和热价的设定会直接影响各微网的电热购售策略而各微网的策略汇总之后又反过来影响上层最优价格。最终要找到一个让所有主体都不想单方面改变策略的状态这就是纳什均衡。1.3 用纳什博弈建模的合理性在哪里从中心化指令到去中心化博弈这个转变不是数学上的炫技而是对现实机制的还原。第一保护隐私。各微网不需要把内部设备参数、负荷细节全部上报。只需要根据共享价格给出自己期望的购售电量/热量即可。第二尊重自治性。每个微网是一个独立利益主体它有权为实现自身利益最大化而调整策略。只要最后大家形成纳什均衡就不存在一个主体能够通过单方面改变策略来获得更大收益这个结果具有稳定性。第三贴合电力市场机制。现代电力市场本身就倾向于用价格信号引导资源流动而不是靠调度命令。纳什博弈框架天然适合描述多个理性主体在价格机制下的互动行为。提示如果你之前主要接触的是确定性优化或单层经济调度建议先想清楚上面三个点再往下看代码。因为这套模型的所有代码逻辑本质上都是在为多主体价格互动均衡求解服务。思路没转过来代码看半天也是云里雾里。2. 从公式到代码纳什博弈双层模型的求解机制模型最棘手的地方在于求解。很多论文给出了漂亮的公式推导但一说到数值求解就含糊其辞。复现者最需要搞清楚的正是从数学表达式到MATLAB代码逻辑的这条桥。2.1 外层主问题与内层子问题的角色划分把双层模型拆开可以分成清晰的上下层结构。**上层共享运营商/系统层**的决策变量是共享电价λ_e和共享热价λ_h目标是最大化整个共享机制带来的收益或者最小化系统整体综合成本。它需要满足的约束一般包括共享功率不超过联络线/热网容量、价格在合理区间内等。**下层各微网主体**的决策变量是各个微网内部的设备出力、储能充放功率、与外部共享的电量/热量等目标是最大化自身收益或最小化自身运行费用。两个层级之间的联系是这样的上层发布一组共享价格各微网根据价格分别求解自己的优化问题得到购售电/热响应量上层统计所有微网的响应计算系统目标函数如果目标不再改善或价格收敛则停止否则更新价格回到第1步。这种迭代求解模式在代码里实现起来非常直观外层套一个循环内层循环里依次调用各微网的优化子程序。2.2 求解双层纳什博弈的两种主流落地方式根据复现经验目前MATLAB环境下最常见的求解路径有两条它们对应的代码结构差别很大。方式一原对偶迭代 / KKT条件转化把下层各微网的问题写成KKT条件再作为约束代入上层的优化问题中。这样双层就变成了单层问题。这种方式数学上严谨但在代码实现上是最痛苦的。因为KKT条件里包含互补松弛条件会引入大量0-1变量比如不同时段的充电/放电状态、购电/售电状态。一旦微网数量变多混合整数非线性规划MINLP的规模会迅速膨胀Yalmip建模会非常庞大求解速度也很感人。方式二分布式迭代 / 最佳响应Best Response上层每次给定价格下层各微网独立求解并返回需求上层根据需求更新价格反复迭代直至收敛。这种方式不需要把KKT写出来代码实现简单、可扩展性强也是目前大部分复现代码采用的做法。我复现时用的也是这种思路。两种方式的对比我放在下表中求解方式数学严密性编程复杂度计算耗时适用范畴KKT转化严格很高变量爆炸随着维度增加急剧变慢小规模、学术展示最佳响应迭代依赖收敛判据较低模块化清晰相对可控中大规模、工程模拟提示如果你的目标是在毕业设计或者小论文里复现并改进这个模型建议首选方式二。不是因为它更简单就Low而是因为它的模块化结构方便你替换算法、增加约束、调整参数更有利于你做出自己的创新点。2.3 收敛判据别让你的循环永远跑下去既然选了迭代方式就必须回答一个问题什么时候算达到纳什均衡了数学上纳什均衡要求没有任何一个微网能通过单方面改变策略获得更大收益。但在数值实现里这个严格条件很难直接验证。实际操作中一般用相邻两次迭代中共享定价或各微网购售功率的变化量来判断价格变化判据||λ^(k1) - λ^(k)|| / ||λ^(k)|| ε策略变化判据||P^(k1) - P^(k)|| / ||P^(k)|| ε目标函数变化判据|F^(k1) - F^(k)| / |F^(k)| ε我在代码里通常同时判断价格和策略两个变化量只有都小于预设阈值比如1e-4才认为达到均衡。这样会比单判价格更稳妥能有效避免价格收敛了但各微网还在振荡调整的伪收敛情况。3. 电热耦合环节的建模细节与代码实现很多复现代码被超距加热的是电热耦合设备的建模。因为纯电或纯热系统大家熟一旦电和热耦合在一起可行域的形状就变得不规则了约束写起来也容易出错。3.1 CHP机组热电耦合可行域的处理CHP是电热耦合的核心设备。它烧天然气发电余热回收供采暖。但它的电出力和热出力不是独立的——不同的CHP型号有各自的热电出力可行域。比如背压式CHP热出力大概是电出力的一个固定倍数可行域是一条线段抽凝式CHP的可行域则是一个凸多边形。在MATLAB里建模最常见的做法是用顶点表示的凸包约束% Yalmip中定义CHP可行域的示例方式 % 假设CHP可行域有n个顶点每个顶点是 [电出力热出力] V [0, 0; ... 200, 0; ... 150, 250; ... 0, 180]; % 顶点坐标 % % 引入权重变量 w满足 w0, sum(w)1 w sdpvar(size(V,1), 1); P_chp_e V(:,1) * w; % 电出力 H_chp_h V(:,2) * w; % 热出力 Constraints [Constraints, w 0, sum(w) 1];这样写的好处是无论可行域是三角形、四边形还是更复杂的多边形只要顶点坐标给对Yalmip会自动把它转成线性约束。而且由于权重变量w都是连续变量不会引入整数变量求解效率会高很多。3.2 热网模型从供回水温度到热功率平衡热力系统的建模如果完全按照水力-热力动态微分方程来做复杂度会失控在双层共享策略研究里几乎没有必要。绝大多数复现论文采用的都是热功率平衡模型每个节点的热负荷、热源出力、共享热功率之间满足守恒关系。蓄热罐可以看作带SOC状态的热储能类似电池储能的逻辑只是量纲是kWth或者MWhth。在某篇复现的代码里热网侧大致是这样建模的% 蓄热罐模型 HS_soc(k1) HS_soc(k) H_chg(k) * eta_chg - H_dis(k) / eta_dis; % 蓄热罐SOC上下限 0 HS_soc(k) HS_cap; % 同一时刻不能同时充放 H_chg(k) M * z_chg(k); H_dis(k) M * z_dis(k); z_chg(k) z_dis(k) 1;如果论文里用到的是多节点热网还要考虑管道传输延时。但复现时如果发现论文的逻辑是基于单节点热网模型做的那完全可以直接用热功率平衡来简化处理不必强行加延时约束否则求解难度会直线上升而且结果大概率对不上原文。3.3 新能源与负荷不确定性的处理颗粒度很多论文会引入风光出力的不确定性引入场景生成和场景缩减。复现这一步要特别注意颗粒度问题如果原论文用的是确定性预测值那代码里直接用典型日/小时级数据即可不需要蒙特卡洛模拟。如果原论文用了场景法那你需要先生成风电光伏出力场景再做场景缩减同步回代消除法是最常用的把缩减后的场景集带入优化模型。如果为了对比鲁棒优化和随机优化那才需要引入不确定集或机会约束。我的建议是第一次复现先跑通确定性版本理解整个博弈流程之后再考虑扩展不确定性建模。千万不要一上来就做最复杂的版本否则代码跑不出来时你根本不知道是模型错了还是参数错了。4. 双层共享策略在MATLAB中的主循环流程这一节是核心中的核心。我用伪代码加MATLAB片段的方式把整个求解流程走一遍。完整的代码结构大致由四部分组成参数初始化模块、上层主循环模块、下层微网子问题模块、结果统计与绘图模块。4.1 参数初始化与基础数据准备这一步的目标是让整个工程能跑起来。我在复现中的做法是先建立一个脚本专门用来初始化参数% 系统基础参数 num_mg 3; % 微网数量 T 24; % 调度周期 dt 1; % 时间步长(小时) % 设备参数 P_chp_max 200; % CHP最大电出力 (MW) P_pv ...; % 光伏预测出力 (N_mg x T) P_wt ...; % 风电预测出力 (N_mg x T) P_load ...; % 电负荷 (N_mg x T) H_load ...; % 热负荷 (N_mg x T) % 博弈参数 lambda_e ones(1,T) * 0.4; % 共享电价初始值 (元/kWh) lambda_h ones(1,T) * 0.3; % 共享热价初始值 (元/kWh) step_size 0.01; % 价格更新步长 tol 1e-4; % 收敛判据 max_iter 50; % 最大迭代次数需要提醒的是价格初值不能设置得太离谱。如果共享电价初始值远远偏离微网内部发电成本迭代过程中很容易出现价格飞到负值或者振荡发散的情况。我的经验是先对各个微网做一次不共享的独立经济调度得到冷启动价格再以此作为共享价格的初值收敛速度会快很多。4.2 主循环价格更新与子问题求解主循环是整个代码的核心骨架。我给出一个简化但完整的框架for iter 1:max_iter % ---------- 下层各微网对当前价格做出响应 ---------- for i 1:num_mg [P_share_i(i,:), H_share_i(i,:), cost_i(i)] solve_microgrid(i, lambda_e, lambda_h, system_param); % P_share_i 0 表示微网向共享平台售电 0 表示购电 end % ---------- 上层统计共享功率并检查约束 ---------- P_total_share sum(P_share_i, 1); % 共享总功率近似为0 H_total_share sum(H_share_i, 1); % 共享总热量 % ---------- 更新共享价格 ---------- lambda_e_new lambda_e step_size * (P_total_share .* 0.1); lambda_h_new lambda_h step_size * (H_total_share .* 0.05); % 检查共享功率是否在允许范围内若超出则收紧价格更新 % ... % ---------- 收敛判断 ---------- if norm(lambda_e_new - lambda_e, inf) tol norm(lambda_h_new - lambda_h, inf) tol disp([迭代第, num2str(iter), 次收敛]); break; end lambda_e lambda_e_new; lambda_h lambda_h_new; end注意价格更新公式我这里随便写了一个示意式不代表论文里的真实逻辑。很多论文用的是步长乘以供需偏差的梯度上升法或者用二分法来逼近均衡价格。实际复现时要仔细看原文公式把更新式替换成你手中那篇论文的形式。4.3 下层微网子问题的建模核心每个微网的下层问题相对独立核心是完整的机组组合或经济调度问题。这里给出关键变量的Yalmip建模示例function [P_share, H_share, C_net] solve_microgrid(i, lambda_e, lambda_h, param) % 提取当前微网的设备参数 % ... % 定义决策变量 P_chp sdpvar(1, T); % CHP电出力 H_chp sdpvar(1, T); % CHP热出力 P_es_chg sdpvar(1, T); % 电储能充电功率 P_es_dis sdpvar(1, T); % 电储能放电功率 SOC_es sdpvar(1, T1); % 电储能荷电状态 P_buy sdpvar(1, T); % 向共享平台购电 P_sell sdpvar(1, T); % 向共享平台售电 Constraints []; % 功率平衡约束 for k 1:T Constraints [Constraints, ... P_pv(i,k) P_wt(i,k) P_chp(k) P_es_dis(k) P_buy(k) ... P_load(i,k) P_es_chg(k) P_sell(k)]; end % 储能约束 % ... (SOC递推、充放功率上下限、充放互斥) % CHP电热耦合约束 % ... (凸包可行域或简单线性约束) % 目标函数购电成本 售电收益 购热成本 燃气成本 设备运维成本 Objective sum(lambda_e .* P_buy) - sum(lambda_e .* P_sell) ... sum(lambda_h .* H_buy) - sum(lambda_h .* H_sell) ... sum(gas_cost(i) .* P_chp) ... sum(om_cost_es .* (P_es_chg P_es_dis)); % 求解 ops sdpsettings(solver, gurobi, verbose, 0); optimize(Constraints, Objective, ops); % 输出结果 P_share value(P_buy) - value(P_sell); H_share value(H_buy) - value(H_sell); C_net value(Objective); end这段代码的核心是目标函数里通过共享价格λ_e、λ_h让各微网在自利动机下自发产生共享行为。你不需要在代码里强制微网i必须卖给微网j多少电价格信号会自然引导出这个量——这正是纳什博弈的妙处。4.4 热功率共享和电功率共享在代码里的区别共享热功率和共享电功率在代码上的区别主要是约束形式。电功率共享要考虑联络线功率限幅不能超过线路容量因为整个多微网系统在空间上是连通的所以还需要满足正常情况下系统内共享电量代数和为零不计网络损耗时也就是要有平衡约束Constraints [Constraints, sum(P_share_i, 1) 0];热功率共享则需要考虑热网管道的容量限制和热损系数。热损通常用传输效率η_h来表示微网i输出1单位热接受侧只能收到η_h单位这个效率在代码里体现为接收端的有效热功率为源端功率乘以η_h。复现时注意不要漏掉这个效率系数不然热功率平衡对不上。% 热功率共享模型简化为无损 for k 1:T Constraints [Constraints, sum(H_share_i(:,k), 1) 0]; Constraints [Constraints, H_share_i(i,k) H_pipe_max(i)]; end热网的时间尺度和惯性比电网大得多严格建模需要引入管道蓄热和延时微分方程。但在博弈共享框架下大多数复现论文为了可解性都采用稳态热功率模型。复现的时候没必要追求热网模型的过度精细重点应该放在博弈机制是否生效上。5. 跑程序时最值得注意的几个坑这部分是我自己踩坑总结出来的经验可能比任何一段代码都值钱。纳什博弈双层模型的复现难点往往不在建模本身而在于模型能跑但跑不对。5.1 价格更新步长与收敛振荡问题迭代次数跑不满没关系最怕的是价格在某个区域反复振荡上下跳动就是不收敛。最常见的原因是步长太大。步长太大时上层价格更新会过冲——这周把价格调太高微网全体大量向平台售电导致供过于求下一轮价格又压太低微网全体购电又供不应求。如此往复形成阻尼振荡。处理办法不是简单把步长调小。我建议做动态步长迭代早期用大步长快速逼近最优解区域后期检测到振荡或增量变化方向交替时自动缩减步长。另外对价格更新量做一个平滑处理如加权移动平均也能显著改善收敛性。5.2 共享电量平衡约束总对不上前面提到各微网共享电量代数和应为零。但在迭代过程中上层更新价格和下层响应的顺序如果不一致可能会导致某一步的共享电量平衡不满足进而影响收敛性。一种稳妥的做法是在下层求解时不硬性加入系统共享功率代数和为零这个全局约束而是让每个微网根据当前价格自由响应等所有微网算完之后在上层统计总净功率再根据总净功率的正负来修正共享价格。这样全局平衡约束是隐含在价格更新逻辑中的而不是强加在每个微网的局部优化里。5.3 MILP求解效率慢到怀疑人生模型里只要出现充放互斥购售互斥启停状态这类逻辑变量就会引入0-1变量导致问题变成MILP。微网一多、调度时段一长比如24时段求解时间会急剧上升。几个实用建议能用连续变量表达的约束就不要用0-1变量。比如储能同一时刻充放互斥的约束实际中如果充放价格合理模型不会出现同时充放的情况可以不加互斥约束。如果非加不可用Yalmip的implies或big-M即可但M的取值要尽量紧不要无脑取1e6松弛度太大会严重拖慢求解器。求解器配置上Gurobi或Cplex求解MILP的效率远超默认求解器能装Gurobi就装Gurobi。Yalmip默认如果用lpsolve或者内置求解器遇到MILP基本只能干等。5.4 别把数值收敛当真收敛迭代循环跑完了误差也小于阈值了就说明达到纳什均衡了吗未必。我遇到过一种情况价格收敛了但把它代入各微网再求解一次每个微网的目标函数值和前一次有细微差异。这说明迭代中还残留了对偶间隙只是刚好满足外层的收敛判据。稳妥的做法是收敛循环结束后再做一次均衡验证。固定其他微网的策略只改变某个微网的策略看它是否能通过单方面调整获得更大收益。如果每个微网都不能显著改善自己的目标函数才能说达到了真正的纳什均衡。这一步在复现论文时要写进代码里否则审稿人问起来你没法回答。6. 结果的解读与SCI复现的正确打开方式代码跑通只是第一步。复现的目标不是原样抄一遍而是通过复现理解模型然后做出自己的东西。下面聊聊我复现这类SCI文章时的经验。6.1 如何验证代码结果是否可靠拿到运行结果之后首先要判断它对不对。我一般按下面顺序检查约束可行性检查所有关键约束的最大违反量而不是看目标函数。如果某个约束违反量不为0直接判断模型设置有误。收敛曲线画出共享价格随迭代次数变化的曲线正常情况是初始波动→逐渐收敛→最终平稳。如果曲线呈周期性振荡说明参数有问题。对比数值把纳什博弈均衡下的系统总成本和完全不共享以及集中式最优调度做对比。理论上集中式最优成本应小于等于博弈均衡成本博弈均衡成本应小于等于不共享成本。这个不等式关系如果被破坏说明求解过程有问题。单边偏差检验如5.4节所述逐一检验各微网是否存在单方面改善策略的空间。6.2 复现论文结果后还能做什么扩展我觉得复现的最高价值在于给你一个可信的基准模型然后在这个基础上去做增量创新。从这套纳什博弈电热双层共享模型出发下面几个方向都比较容易出成果加入碳交易机制把碳配额和碳价引入各微网的目标函数观察碳约束如何改变共享电热价格与均衡状态。考虑源荷不确定性把确定性博弈拓展为分布鲁棒博弈或机会约束博弈让每个微网在应对不确定性时保有一定的鲁棒性。引入储能运营商或共享储能在原来的多微网主体之上再引入一个独立的储能服务商博弈结构就会从水平博弈变成垂直水平的混合博弈模型更复杂也更有卖点。改进求解算法用分布式ADMM或者共识算法替代传统的价格迭代法强调隐私保护和通信效率工程价值更突出。6.3 给新手的实用建议结合我自己的复现经验最后给刚入坑的同学几条建议第一先跑通再优化。不要一开始就在代码里加入各种创新模块。先把最基础的双层共享模型跑通确认结果合理再逐步加东西。第二不要迷信SCI复现的标题。很多网上的代码版本之间差很多有的是早期会议版有的是期刊最终版还有的基本是作者自己调试过程中的半成品。多对比几个版本以论文公式和逻辑为准。第三手边准备一个数据记录表。把每次运行的参数、目标值、迭代次数、收敛情况记录下来。博弈模型对初值敏感同一个模型换个初值结果可能就不同。没有记录你就不知道什么参数组合是稳定的。个人经验体会做这类多主体博弈优化的复现最大的体会就是论文里简简单单一句通过迭代求得纳什均衡落到代码上可能是一大堆调参和试错。价格初值怎么设、步长怎么选、收敛阈值定多少这些问题论文不会写只能靠自己在调试中摸索。我建议大家在拿到任何一套复现代码后先不要急于跑全场景而是先用小规模数据把所有模块跑通把每个子问题单独验证正确之后再拼接成完整的主循环。这样一旦出问题你至少能定位到具体是哪个模块出了问题而不是对着整个大程序无从下手。如果你现在也被某个SCI复现的代码卡住了不妨把模型规模缩小到2个微网、6个时段把每个时段的价格和功率曲线都画出来仔细观察迭代过程中发生了什么。很多时候问题不在求解器而在于你对模型机制的理解还差一层窗户纸。希望这篇文章能帮你捅破那层窗户纸。