基于纳什博弈的多微网电热双层共享策略MATLAB建模与复现解析
2026/9/23 1:58:12 网站建设 项目流程

看到这个标题,我第一反应是亲切。做电气或者综合能源方向的研究生,这几年但凡碰过"多微网""共享储能""电热联合调度"这些关键词,基本都绕不开纳什博弈这个坑。网上相关的源码和论文确实不少,但真正能让人看得懂、跑得通、改得动的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. 各微网根据价格分别求解自己的优化问题,得到购售电/热响应量;
  3. 上层统计所有微网的响应,计算系统目标函数;
  4. 如果目标不再改善或价格收敛,则停止;否则更新价格,回到第1步。

这种迭代求解模式,在代码里实现起来非常直观:外层套一个循环,内层循环里依次调用各微网的优化子程序。

2.2 求解双层纳什博弈的两种主流落地方式

根据复现经验,目前MATLAB环境下最常见的求解路径有两条,它们对应的代码结构差别很大。

方式一:原对偶迭代 / KKT条件转化

把下层各微网的问题写成KKT条件,再作为约束代入上层的优化问题中。这样双层就变成了单层问题。这种方式数学上严谨,但在代码实现上是最痛苦的。因为KKT条件里包含互补松弛条件,会引入大量0-1变量,比如不同时段的充电/放电状态、购电/售电状态。一旦微网数量变多,混合整数非线性规划(MINLP)的规模会迅速膨胀,Yalmip建模会非常庞大,求解速度也很感人。

方式二:分布式迭代 / 最佳响应(Best Response)

上层每次给定价格,下层各微网独立求解并返回需求;上层根据需求更新价格,反复迭代直至收敛。这种方式不需要把KKT写出来,代码实现简单、可扩展性强,也是目前大部分复现代码采用的做法。我复现时用的也是这种思路。

两种方式的对比我放在下表中:

求解方式数学严密性编程复杂度计算耗时适用范畴
KKT转化严格很高,变量爆炸随着维度增加急剧变慢小规模、学术展示
最佳响应迭代依赖收敛判据较低,模块化清晰相对可控中大规模、工程模拟

提示:如果你的目标是在毕业设计或者小论文里复现并改进这个模型,建议首选"方式二"。不是因为它更简单就"Low",而是因为它的模块化结构方便你替换算法、增加约束、调整参数,更有利于你做出自己的创新点。

2.3 收敛判据:别让你的循环永远跑下去

既然选了迭代方式,就必须回答一个问题:什么时候算达到纳什均衡了?

数学上,纳什均衡要求没有任何一个微网能通过单方面改变策略获得更大收益。但在数值实现里,这个严格条件很难直接验证。实际操作中,一般用相邻两次迭代中共享定价或各微网购售功率的变化量来判断:

  • 价格变化判据:||λ^(k+1) - λ^(k)|| / ||λ^(k)|| < ε
  • 策略变化判据:||P^(k+1) - P^(k)|| / ||P^(k)|| < ε
  • 目标函数变化判据:|F^(k+1) - 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,满足 w>=0, 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(k+1) = 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, T+1); % 电储能荷电状态 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的impliesbig-M即可,但M的取值要尽量紧,不要无脑取1e6,松弛度太大会严重拖慢求解器。
  • 求解器配置上,Gurobi或Cplex求解MILP的效率远超默认求解器,能装Gurobi就装Gurobi。Yalmip默认如果用lpsolve或者内置求解器,遇到MILP基本只能干等。

5.4 别把"数值收敛"当真收敛

迭代循环跑完了,误差也小于阈值了,就说明达到纳什均衡了吗?未必。

我遇到过一种情况:价格收敛了,但把它代入各微网再求解一次,每个微网的目标函数值和前一次有细微差异。这说明迭代中还残留了对偶间隙,只是刚好满足外层的收敛判据。

稳妥的做法是:收敛循环结束后,再做一次均衡验证。固定其他微网的策略,只改变某个微网的策略,看它是否能通过单方面调整获得更大收益。如果每个微网都不能显著改善自己的目标函数,才能说达到了真正的纳什均衡。这一步在复现论文时要写进代码里,否则审稿人问起来你没法回答。

6. 结果的解读与SCI复现的正确"打开方式"

代码跑通只是第一步。复现的目标不是原样抄一遍,而是通过复现理解模型,然后做出自己的东西。下面聊聊我复现这类SCI文章时的经验。

6.1 如何验证代码结果是否可靠

拿到运行结果之后,首先要判断它"对不对"。我一般按下面顺序检查:

  1. 约束可行性:检查所有关键约束的最大违反量,而不是看目标函数。如果某个约束违反量不为0,直接判断模型设置有误。
  2. 收敛曲线:画出共享价格随迭代次数变化的曲线,正常情况是"初始波动→逐渐收敛→最终平稳"。如果曲线呈周期性振荡,说明参数有问题。
  3. 对比数值:把纳什博弈均衡下的系统总成本,和"完全不共享"以及"集中式最优调度"做对比。理论上,集中式最优成本应小于等于博弈均衡成本,博弈均衡成本应小于等于不共享成本。这个不等式关系如果被破坏,说明求解过程有问题。
  4. 单边偏差检验:如5.4节所述,逐一检验各微网是否存在单方面改善策略的空间。

6.2 复现论文结果后还能做什么扩展

我觉得复现的最高价值在于给你一个"可信的基准模型",然后在这个基础上去做增量创新。从这套纳什博弈电热双层共享模型出发,下面几个方向都比较容易出成果:

  • 加入碳交易机制:把碳配额和碳价引入各微网的目标函数,观察碳约束如何改变共享电热价格与均衡状态。
  • 考虑源荷不确定性:把确定性博弈拓展为分布鲁棒博弈或机会约束博弈,让每个微网在应对不确定性时保有一定的鲁棒性。
  • 引入储能运营商或共享储能:在原来的多微网主体之上,再引入一个独立的储能服务商,博弈结构就会从水平博弈变成垂直+水平的混合博弈,模型更复杂也更有卖点。
  • 改进求解算法:用分布式ADMM或者共识算法替代传统的价格迭代法,强调隐私保护和通信效率,工程价值更突出。

6.3 给新手的实用建议

结合我自己的复现经验,最后给刚入坑的同学几条建议:

第一,先跑通再优化。不要一开始就在代码里加入各种创新模块。先把最基础的双层共享模型跑通,确认结果合理,再逐步加东西。

第二,不要迷信"SCI复现"的标题。很多网上的代码版本之间差很多,有的是早期会议版,有的是期刊最终版,还有的基本是作者自己调试过程中的半成品。多对比几个版本,以论文公式和逻辑为准。

第三,手边准备一个数据记录表。把每次运行的参数、目标值、迭代次数、收敛情况记录下来。博弈模型对初值敏感,同一个模型换个初值结果可能就不同。没有记录你就不知道什么参数组合是稳定的。

个人经验体会

做这类多主体博弈优化的复现,最大的体会就是:论文里简简单单一句"通过迭代求得纳什均衡",落到代码上可能是一大堆调参和试错。价格初值怎么设、步长怎么选、收敛阈值定多少,这些问题论文不会写,只能靠自己在调试中摸索。我建议大家在拿到任何一套复现代码后,先不要急于跑全场景,而是先用小规模数据把所有模块跑通,把每个子问题单独验证正确之后,再拼接成完整的主循环。这样一旦出问题,你至少能定位到具体是哪个模块出了问题,而不是对着整个大程序无从下手。

如果你现在也被某个"SCI复现"的代码卡住了,不妨把模型规模缩小到2个微网、6个时段,把每个时段的价格和功率曲线都画出来,仔细观察迭代过程中发生了什么。很多时候,问题不在求解器,而在于你对模型机制的理解还差一层窗户纸。希望这篇文章能帮你捅破那层窗户纸。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询