做微电网或综合能源方向的课题大概率会遇到这样一个场景手上有好几个微网的负荷、光伏、热负荷和储能数据每个微网都有自己的运营方彼此不能互相指挥但物理上却硬生生连在同一条联络线或供热管道上。谁该多出力、谁该支援谁、电和热怎么分摊算账越来越难。我复现《基于纳什博弈的多微网主体电热双层共享策略研究》时就是为了解决这个问题——借助纳什博弈把多个利益不一的微网主体放进同一个框架里博弈最后用Matlab把整套双层共享策略从论文符号翻译成可以运行的代码。这篇博文把完整的建模思路、代码实现路径和踩坑记录写下来适合两类人想快速复现论文算法做对比实验的研究生以及面对一堆公式不知道如何落地的实战派从业者。1. 多微网电热共享到底在共享什么1.1 单微网调度早已不够用先把背景故事说清楚。微网是什么简单讲就是一块区域内把分布式光伏、风电、燃气轮机、储能、电锅炉、热泵以及本地负荷打包在一起的自洽供电系统。它既能并网运行也能独立孤岛运行。单独一个微网做调度时事情其实很单纯在一个调度周期内用最便宜的方式满足本地电负荷和热负荷。之前我做单微网能量管理系统时这本质上就是一个确定性优化问题光伏出力、负荷曲线给定燃气轮机怎么开、储能什么时候充放电把每天运行成本优化一遍就算完事。但实际工程里一个园区、一个区域往往不止一个微网。相邻微网之间有联络线有的还共用热力管道。这时候单微网调度就不够用了——白天光伏大发而本地负荷低的微网看着自家的电白白弃掉另一个微网晚上负荷高企却要从外部高价买电。如果各自为政系统整体利用率低成本也高如果直接拉通统一调度从物理层面看是最优的从组织层面又行不通。原因在于每个微网都有自己的运营商没有人愿意无条件服从全局调度。这种“物理上互联、管理上自治”的格局正是后面所有复杂模型的根源。多微网共享调度要做的就是在承认各主体自治的前提下通过交易和策略实现比单干更好的结果。1.2 电和热是两套节奏完全不同的交易“电热双层共享”这六个字里最容易忽略的是电和热的本质差别。我自己复现早期就犯过想当然的错误以为把电功率换成热功率模型推导照葫芦画瓢就行结果算出来的调度方案完全不合理。电和热虽然都是能量物理属性差异却非常大建议所有复现的人先把这张差异表建在心里。属性电力共享热力共享时间尺度秒级到分钟级平衡实时性极强小时级响应热惯性大短时可不严格平衡传输介质联络线上的有功功率损耗按线路电阻计算热水或蒸汽存在延时与散热损耗沿程温度下降主要约束联络线容量、功率平衡、机组爬坡热网传输容量、节点温度上下限、蓄热罐容量与充放速率核心设备燃气轮机、光伏、储能电池热电联产、电锅炉、热泵、蓄热罐计量结算有功电能表计量按kWh结算按热量kJ/GJ结算计量相对复杂电的物理特性是“瞬间平衡”发多少用多少波动要靠储能和机组调节去扛热的物理特性是“有惯性”供热管道里的水本身就是储能介质允许运行时段之间有热量盈余和亏欠只要终端温度不越界就行。这也是模型里为什么要把电和热分两层处理的原因电层优化需要精细的功率平衡约束热层优化则要考虑热惯性、散热损耗和温度约束两套逻辑不能用一个方程糊弄过去。1.3 多个“老板”坐在同一张桌上更关键的是每个微网背后都是一个利益主体。A微网有余电凭什么低价卖给B微网C微网的燃气轮机余热可以供热但D微网不想付钱谁强制得了在工程实际里这种多主体利益冲突非常普遍也正是纯物理优化模型难以解决的问题——因为物理优化默认“大家都听调度中心的”。然而真实的多微网系统里只存在合作意向不存在统一命令。因此在复现这篇论文时模型做的最重要的一步就是把每个微网当作一个独立决策者让它以自身运行成本最小为目标去决定共享多少电、共享多少热、接受什么价格。于是问题从“如何一起最优”变成了“如何各自最优且能共存”这个转换一旦想通后面看纳什博弈就顺理成章。2. 纳什博弈为什么能治多主体协调的病2.1 先分清两类问题集中优化和分散博弈很多第一次接触多微网课题的人第一反应是用集中式优化把所有微网的数据汇总到调度中心以全局成本最小为目标一步求出最优解。这种方法从数学上讲最漂亮KKT条件一写求解器一跑就有解。但它有一个致命前提所有微网愿意把内部数据和决策权交给调度中心。我实际参与某多微网模拟项目时各运营方的反馈很明确“我们自己的运行数据可以报但最终运行方案要我们自己定。”集中优化模型做得再准落地时也走不通。于是有了博弈的思路。如果用生活场景打比方集中式优化像一家人坐在一起由家长统一安排每个月怎么花钱目标是全家总支出最小博弈则更像一群朋友AA聚餐每个人各自选自己想吃的菜最后大家会根据别人的选择调整自己的点单最终达到一个“没有谁愿意独自换菜”的状态。多微网电热共享本质上更像聚餐大家共享餐桌电网和热网但谁都不愿意被指挥于是只能用博弈来协调。2.2 纳什均衡的通俗解读与限定条件纳什均衡是博弈论里最核心的概念。它的定义表述很简洁所有参与者都选定了自己的策略后任何一个人单方面改变策略都不能让自己过得更好那么这个策略组合就是纳什均衡。注意它不一定是所有人加起来最好的解也不一定是公平的解它只是稳定的解——谁也没有动机单独偏离。我复现时一度困惑的问题是纳什均衡和帕累托最优到底什么关系后来想明白了。帕累托最优关注整体效率存在一个方案让所有人都比现状更好纳什均衡关注个体稳定性每个人在现有牌局里都不愿意单独换牌。两者不一定重合经典例子是“囚徒困境”纳什均衡是两人都坦白而整体最优是两人都沉默却没人敢先沉默。多微网系统里同样可能出现“整体效益差一点但个体稳定”的均衡结果这正是多主体自治必须付出的代价。论文要做的事情是通过设计共享价格机制和双层结构把纳什均衡尽量推向更接近帕累托最优的结果。在使用纳什均衡之前必须确认存在性。如果策略空间不连续、目标函数非凸均衡可能根本不存在或者不唯一。好在多微网主体模型里目标函数通常写成二次成本函数约束是线性等式和不等式每个主体的可行域是非空紧集目标函数又是严格凸的纯策略纳什均衡的存在性基本有保障。这也是整个Matlab复现能稳健跑通的数学基础——如果模型连均衡都不保证存在代码里看到的只会是一堆不收敛的迭代日志。2.3 双层结构里上层和下层分别管什么标题里的“双层”是整个模型的骨架。我一开始把双层理解成两个优化问题直接串联结果完全不对。认真推导迭代逻辑后才发现这实际上是“一个博弈在上层、多个优化在下层”的嵌套结构。上层处理的是共享策略每个微网主体通过申报自己的共享电力、共享热力功率或者通过协商形成的交易价格和其他主体一起迭代直到收敛到纳什均衡。下层处理的是主体内部的能量管理在上层给定的共享功率或价格下每个微网单独求解自己机组出力、储能充放电、蓄热罐充放热的优化问题得出自身的最优响应。上层每个主体的策略变化会影响下层的优化结果而下层的优化结果又会反过来影响上层的共享策略循环往复直到整个系统达到一个内外一致的稳定状态。用代码来理解就是外层while循环是博弈迭代内层for循环依次求解每个主体的子优化问题。如果论文的数学公式里目标函数有两个优化层级相互嵌套那基本就是这种结构。复现时要特别注意上下层的决策变量维度不同、量级不同迭代时的收敛判据要分别设置不能用同一个绝对容差去卡否则很容易因为某一层残差波动大导致外层始终无法收敛。3. 拆解SCI复现中的数学模型3.1 主体模型运行成本怎么构成把概念理清后可以进入数学表达。先说明每个主体在下层优化问题里到底在最小化什么。一个典型微网主体的运行成本由几块组成燃气轮机的燃料成本通常写成出力的一次或二次函数、从共享网络购电或购热的费用或售电售热收入符号需要注意、储能的运行损耗成本、设备维护费用。目标函数可以简单归纳为主体运行成本 本地发电供热成本 向共享网络购买电热的费用 - 向共享网络出售电热的收益我复现时最常犯的错误是正负号。购电费用要写进目标函数售电收益要从成本里减掉但如果该主体是多卖方它的售电收益对于系统整体来讲其实是另一主体的成本所以博弈的目标函数在不同文献里有不同写法。建议按“自身现金流出最小”来理解这样正负号不容易写错。目标函数一般写成二次凸函数min f_i Σ_t (a_i·P_i^2(t) b_i·P_i(t) c_i) Σ_t (c_e_buy·P_buy(t) - c_e_sell·P_sell(t)) 热力部分对应项其中P_i是主体本地机组的电出力P_buy和P_sell是主体与共享网络的电力交换量。热力部分的成本同理可能包括燃气轮机余热回收成本、电锅炉消耗的电费、蓄热罐维护费用等。需要提醒的是二次项系数a_i非常重要它决定了目标函数的凸性和迭代收敛特性复现时不要为了省事把它改成线性项。3.2 电热耦合设备与共享网络约束主体内部的约束才是复现工作的主要工作量约束可以分为三类设备约束、能量平衡约束、共享网络约束。先看设备约束。燃气轮机有出力上下限和爬坡约束储能电池有容量状态递推方程、充放电功率上限、SOC上下限电锅炉有输出热功率上下限蓄热罐有储热状态递推、充放热速率限制。其中储能和储热罐的时序耦合约束特别容易写错尤其是状态递推方程的时间步索引漏一项或者错一位结果就会出现“能量凭空消失”的离奇现象。电热耦合设备的约束是另一个重点。一台CHP机组发电和产热不是独立的电出力和热出力存在一个热电比范围写成约束就是热出力等于电出力乘以热电比或者热出力落在某个区间内。电锅炉则是把电能转化为热能转化效率通常在0.9以上。这些设备的存在让电层和热层在物理上无法割裂这也是为什么模型要强调“电热双层共享”而不是单纯的电共享或热共享。共享网络约束包括联络线传输功率上限、热力管道传输容量、节点温度约束、共享功率方向限制等。复现时建议把共享功率设成有符号变量正值表示输入负值表示输出。传输容量约束写绝对值约束或者拆成两个线性不等式。热力网络往往还要考虑散热损耗用固定比例系数对传输热量打折扣即可。3.3 从模型到均衡的求解条件有了目标和约束每个主体的子问题就是一个凸二次规划可以用KKT条件描述最优性。整体怎么形成纳什均衡通常的做法是构造一个博弈迭代每个主体在其他主体策略固定时求出自己的最优响应所有主体同步更新策略重复迭代。当所有主体的策略残差都小于容差时认为到达纳什均衡。在写代码之前强烈建议先做一遍严格凸性检查。每个主体的目标函数必须是关于自己决策变量的严格凸函数否则子问题可能有多个最优解最优化响应是一个集合迭代过程就会在两个甚至多个解之间来回抖动永远达不到收敛。论文里往往会保证这一点但复现时如果自己调整了参数比如把成本系数改成线性甚至更简单就很可能会破坏凸性。总之数学上先确认存在性和凸性代码才可能收敛别一上来就埋头写while循环。4. Matlab实现的关键路径与核心代码逻辑4.1 复现前先做的事参数整理与单位统一很多复现失败不是算法问题而是单位问题。论文里电力单位用MW热量单位可能用GJ/h储能容量用MWh时间分辨率是1小时到你自己造数据的时候一个不留神就把热量和电力数值直接相加了模型跑出的结果自然是错的。每次复现新模型第一件事是把所有参数列一张表统一单位固定时间分辨率。下面是我复现这套模型时用过的参数清单仅供参考。参数类别示例参数单位电源光伏、燃气轮机出力上限kW负荷电负荷、热负荷时序kW / kWth储能电池容量、最大充放电功率kWh / kW储热蓄热罐容量、充放热速率上限kWh / kW耦合设备CHP电出力上限、热电比、电锅炉电热效率kW / - / -共享网络联络线容量、热网传输容量、热损失系数kW / kW / -价格购电电价、售电电价、共享电价元/kWh单位统一后在Matlab里把所有已知量放在一个结构体里比如params。我习惯写成params.pv、params.load_e、params.load_h这样清晰的名字后面每个子问题都从params取数避免在公式里硬编码数字。这是看起来琐碎但收益极大的习惯。4.2 主体优化与博弈迭代的代码框架模型主体部分的伪代码大致是这个结构% 初始化各主体的共享策略 strategy zeros(n_agent, T); price initial_price(T); % 初始共享价格 max_iter 200; tol 1e-4; for k 1:max_iter % 下层各主体独立求解自身最优响应 for i 1:n_agent % 固定其他主体策略构建第 i 个主体的约束和目标 x_i solve_agent_problem(i, price, strategy); new_strategy(i, :) x_i.share_e x_i.share_h; end % 上层根据所有主体的响应更新共享价格或策略 residual max(abs(new_strategy - strategy), [], all); strategy alpha * new_strategy (1 - alpha) * strategy; % 阻尼更新 price update_price(strategy, price); % 价格调整 fprintf(iter%d, residual%.6f\n, k, residual); if residual tol break; end end真实代码里还需要在solve_agent_problem内部处理储能约束、热网约束等一般用Matlab优化工具箱的quadprog就能解。根据我的经验求解工具够用就好先跑通小规模算例再考虑引入更复杂的建模层和外部求解器。内层每个主体问题只涉及一个微网的时间序列变量规模不大quadprog的耗时完全可以接受。阻尼更新系数alpha是稳定性的关键。我实测alpha取0.5到0.8之间比较稳alpha等于1时如果初始解离均衡点远容易振荡等于0.2时收敛很慢。迭代判据要分别看策略残差和价格残差最好同时打印出来肉眼观察两个量是在同步下降还是互相拉扯。4.3 三个必须做的正确性验证代码跑通不等于模型正确。论文复现最容易出现“算得出结果但结果是错的”。我通常做三组验证见下表。验证场景做法预期现象单主体退化把所有微网数据合并成一个主体博弈结果与集中式优化结果一致或误差在可接受范围无互济场景把联络线容量设为0、热网解列各主体的调度结果应等于各自独立运行的本地优化结果极端负荷场景随机生成100组负荷曲线跑敏感性分析均衡解落在合理范围不出现功率越限或能量凭空消失第一组验证尤其重要。如果多主体博弈代码在最简单的单主体情况下都不能和常规优化对齐说明求解逻辑一定有bug如果两组对齐了至少说明代码的底层正确性有保障。第二组验证用来检查共享模块有没有引入不必要的耦合第三组用来检查鲁棒性。这三组验证做完我才会拿代码去复现论文里的图表不然方向错了后边全是白费。有一个小细节值得提在单主体退化验证时共享价格的初值并不会影响最终解因为此时所有物理量都在同一个主体内部价格只是内部记账如果这个场景下价格还影响解说明目标函数正负号或约束耦合写错了。5. 复现途中踩过的坑与排除过程5.1 迭代不收敛罚参数不是越大越好第一次跑博弈迭代时我的收敛曲线像心电图残差在第一轮下降后就开始来回跳。检查了约束和初值都没发现问题后来逐行分析外层循环才发现我在共享功率更新时引入了罚项想让各主体的共享策略被“钉”在目标值附近。罚参数取得很大本意是想让策略不敢跑偏结果适得其反罚项过大主体每一步都过度反应策略在下一次迭代时冲过头形成持续振荡。这就像弹簧两端挂重物刚挂上去时弹性系数太大稍微动一下就来回弹。解决办法是把罚参数调小并配合阻尼更新。我的经验是先用无罚项的版本跑通确认迭代本身能收敛再加罚项加罚项后参数从一个较小值开始往上调观察收敛速度和稳态残差找到一个让迭代既快又不振荡的区间。这个“先裸跑再加约束”的思路对几乎所有分布式算法调试都适用。5.2 热力约束的非凸性质如何绕开热电联产设备和热网约束带进来之后模型不再天然是凸的。典型麻烦来自两类约束热网管道中的流量乘以温度形成的双线性项以及某些CHP机组的热电比可变区间在x-y平面上并非凸集。如果直接把这类约束写进优化问题quadprog会直接报错被迫回退到穷举或启发式算法收敛质量难以保证。论文里通常有化简前提比如假设热水流量恒定、只控制供回水温度或把热网模型简化为带损耗系数的热量传输。复现时建议严格遵照论文的简化假设不要另起炉灶追求更精细的热网模型。那些模型当然更准确但会破坏原有的凸性导致根本复现不出论文的数值结论。真正需要精细热网模型时得换技术路线比如分解成两个交替迭代的子问题每轮固定一侧变量。5.3 初值选择的经验法则与敏感性分析初值对博弈迭代的影响比想象中大得多。同一个模型初值不同最终可能跑到不同的均衡点遇到非严格凸的目标函数时这种情况尤其常见。我第一次复现时直接在随机初始策略下跑结果和论文里给出的均衡差异很大一度怀疑代码写错。后来做敏感性分析才知道问题出在多均衡上不同初值落入了不同的均衡点。大多数论文会明确或暗示地给出均衡唯一性条件但复现时参数一改动条件可能被破坏。我的建议是先固定一组符合论文参数的初值跑出稳定结果然后把初值在可行域内随机扰动几百次统计均衡策略分布的离散程度。如果结果很集中说明均衡稳定如果结果很分散就要检查是否是目标函数凸性出了问题或者模型存在多均衡。实际工程里也可以用“前一天的最优解作为今天迭代初值”这种思路让算法在时间序列上有连续性比每次从零开始随机初值有效得多。还有一个经验是要把热层和电层的迭代初值分开设置。由于电层响应快、热层响应慢合并设置会让热层拖慢电层收敛单独给热层一个相对保守的初值再让电层先跑几轮整体收敛速度会明显提升。这个细节论文里不会写只有自己跑迭代才会发现。最后谈一点复现这套模型后的实际感触。论文里的双层博弈模型看着公式复杂落到代码上其实可以拆成很多个小而清晰的部分数据结构、参数表、每个主体的quadprog、外层迭代循环、结果可视化。我复现之前习惯先把论文公式抄一遍再写代码后来发现更高效的做法是先拿数据试算一个小例子哪怕只用两个微网两个时段的简化版本把模型的手算结果和代码输出对上再扩展到全规模。这样能最快找出正负号、索引和单位的问题。如果你也在复现类似的多主体博弈论文建议从最小可运行样例出发逐步加约束、加主体、加时段每一步都有验证点最后再和论文图表对比。这个过程虽然慢但每次报错都会有收获等全套代码跑通你对模型的理解深度远超过只看论文的层次。还想再提醒一句多微网博弈的初始条件、罚参数、迭代容差这些“工程味”很重的细节往往是复现出与论文一致结果的关键。论文里的框架是地图这些细节才是导航。
阅读完成 · 觉得有帮助?