ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于非合作博弈的居民负荷分层调度:双层鲸鱼算法与Matlab实现

基于非合作博弈的居民负荷分层调度:双层鲸鱼算法与Matlab实现 做电力系统需求响应和智能用电方向的人应该都清楚居民负荷调度这个方向模型建起来不算难难的是把“多个用户之间的博弈关系”和“电网侧的决策引导”塞进同一个可求解的框架里。最近我完整复现了一个基于非合作博弈的居民负荷分层调度模型外层用双层鲸鱼算法寻优电价的制定策略内层通过博弈迭代把多个用户之间的非合作博弈均衡点解出来。整体跑下来削峰效果比单层集中式调度更明显用户侧的公平感也更好——每个用户都在给定电价下选择了自己电费最小的策略属于典型的“理性人各谋其利”。这篇内容主要讲清楚三件事模型为什么要分层、非合作博弈和双层优化怎么在同一套系统里共存、以及用Matlab实现这套模型时真正容易踩的坑。适合正在做需求响应、虚拟电厂、智慧用能研究的同学参考也适合刚接触双层优化和博弈调度、想找一个能动手复现的算例的人。1. 项目背景与核心思路1.1 为什么居民负荷必须分层调度居民负荷有一个很尴尬的特点单户容量小、数量大、用电行为随机性强。如果电网侧直接对每一台空调、每一台热水器下发控制指令通信负担和计算规模会直接爆炸而且用户的舒适度基本没法保障。所以业内更倾向于“分层管理”电网或售电公司只管到社区变压器或聚合商这一层再由中间层把任务拆解到户。分层调度其实是在解决两个问题一个叫“规模”一个叫“意愿”。“规模”很好理解大量用户直接参与调度在工程上不可行必须通过层级来压缩计算复杂度。“意愿”则更关键——居民用户不是配电柜里的设备他们有主观用电需求不会因为电网想削峰就让自己热着或饿着。分层模型天然适合表达这种“上层定规则、下层自由响应”的关系这也是我在项目中采用分层模型的核心原因。从我实际复现的经验来看分层模型还有一个隐性好处当某层参数需要调试时可以单独隔离测试不需要整个系统一起跑。比如想测试用户在某个时段的响应灵敏度直接改底层用户模型就行上层电价策略可以先不动。这种模块化调试带来的便利在代码开发过程中价值非常大。1.2 非合作博弈到底指的是什么“非合作”听起来好像很消极但在负荷调度里它恰恰是现实。居民用户之间不会提前商量“你今天少用点电明天我少用点”大家只会看电价信号做对自己最有利的选择。多个决策主体各自追求自身利益最大化、不签订合作协议、通过策略互动影响彼此收益的这种结构就是非合作博弈。在博弈框架里每个用户是一个玩家策略是各时段负荷的启停状态或功率大小收益是电费最小化或者包含舒适度惩罚之后的综合效用最大化。当没有任何一个用户愿意单方面改变自己的用电策略时就达到了纳什均衡。这里可以类比一个商圈里几家奶茶店抢生意谁也不会听谁指挥但价格最终会稳定在一个相对合理的区间因为谁先轻举妄动调整价格谁就可能流失顾客。需要注意非合作博弈和“完全不受约束”不是一回事。用户之间虽然不合作但每个人都要受物理设备约束比如可转移负荷的工作时段、空调的设定温度范围、电动汽车的充电时间窗。这些约束属于用户自身的可行域恰恰是博弈均衡点落在哪里的关键因素之一。1.3 双层模型的主从博弈视角有了分层结构和非合作博弈自然就引出了双层优化。上层是电网或售电公司制定分时电价目标是削峰填谷、提高收益或者降低系统运行成本下层是居民用户接收电价信号后调整自身用能计划。上层先做决策下层再响应这种“我定规则你玩游戏”的结构在博弈论里叫Stackelberg主从博弈。双层优化难就难在上层不能直接控制下层只能通过电价信号间接影响用户的用电行为。也就是说每次上层给定一组电价都要先解一遍下层的用户博弈问题拿到所有用户的负荷曲线之后上层才能评价这组电价好不好。下一组电价再试下层用户又变如此反复迭代直到找到“上层最优且下层理性响应”的均衡解。我刚开始以为可以把双层模型直接塞进一个求解器里一次性解出来后来发现不行。原因在于下层是一个博弈问题本身就有复杂的策略交互不是简单的单目标优化问题。必须把内外层拆开用迭代的方式让两层都能表达各自的决策逻辑这也是最终选择双层鲸鱼算法作为外层求解引擎的原因。2. 数学模型拆解2.1 上层模型定价策略与目标函数上层决策变量是分时电价向量记为 (p_t)其中 (t) 表示时段。工程上最常见的是24点调度也就是每小时一个时段如果想做得更精细可以取96个15分钟时段但那样内层博弈的计算量会明显增加。我复现时先用24点确认逻辑正确之后再扩展到96点。上层目标函数主要有三类做法最小化电网峰谷差(\min (\max_t L_t - \min_t L_t))最大化售电公司收益(\max \sum_t p_t \cdot L_t)综合目标削峰权重 收益权重加权求和我自己使用的是“峰谷差最小化 平均电价波动约束”的组合目标这样既能有效削峰也不会把电价抬到用户接受不了的程度。上层约束条件包括电价上限下限比如0.3-1.5元/kWh、相邻时段电价变化幅度限制防止电价剧烈波动刺激用户、以及供需平衡约束。这里有一个很容易被忽略的点上层每次在目标函数中计算节能收益时使用的负荷曲线必须来自下层的博弈均衡解而不是上层自己预测的“理想响应负荷”。如果拿预测值代替真实博弈结果外层算法会被虚假的适应度误导最终算出来的电价策略在实际应用时效果会大打折扣。2.2 下层模型负荷分类与用户收益函数下层模型首先要对居民负荷做分类不同类型负荷的建模方式完全不同固定负荷冰箱、路由器、电视待机等刚性不可调直接当作背景功率。可转移负荷洗衣机、洗碗机、电动汽车充电桩运行时段可以平移但总用电量必须保持不变。可削减负荷空调、电热水器可以降低功率但要牺牲舒适度需要引入舒适度惩罚项。用户的目标函数一般是[ \min C_i \sum_t p_t \cdot L_{i,t} \lambda \cdot \text{舒适度偏离惩罚} ]再加上电动汽车充电时间窗、空调设定温度上下限、家庭总功率上限等约束。用户的决策变量是 (L_{i,t})也就是第 (i) 个用户在时段 (t) 的用电功率。关键在于用户之间的耦合从哪里来。如果只是各自独立优化自己的用电计划那不过是一堆单目标优化问题并行求解根本不构成博弈。我在模型中把用户之间的耦合设置成了“社区总负荷超过变压器容量时按比例分摊惩罚费用”。这样某个用户在低谷时段抢着用电会导致其他用户承担更高的分摊成本于是形成了真正的策略耦合。加了这个机制之后博弈过程才变得有血有肉均衡结果也更有分析价值。2.3 纳什均衡的存在性与求解思路纳什均衡的存在性在理论上需要满足Kakutani不动点定理的条件每个用户的策略空间是非空紧凸集支付函数连续且拟凹。但在实际工程算例中只要约束是线性的、费用函数是凸的基本都能满足。实操时没有必要对每个算例都做严格的数学证明更务实的做法是直接迭代求解然后观察迭代是否收敛、解是否稳定。求解下层博弈的思路主要有两种。第一种是KKT条件法把下层博弈问题转成KKT最优性条件并并入上层再用求解器直接解。这个做法数学上很优美但实现复杂度高尤其当用户类型很多、约束条件杂的时候KKT系统的规模会失控。第二种是迭代法在给定其他用户策略的前提下每个用户用优化器算出自己的最优响应反复迭代直到收敛。我这里采用的是第二种因为代码直观而且方便和WOA结合。迭代法最大的痛点是收敛速度慢、可能出现振荡。我处理振荡的办法是在用户策略更新时加阻尼系数不让用户一下子跳到当前最优解而是按一定比例逐步调整。后面第5章会专门讲这个细节。3. 双层鲸鱼算法的设计与改进3.1 标准WOA核心机制快览鲸鱼优化算法Whale Optimization AlgorithmWOA模拟的是座头鲸的泡泡网捕食策略。标准WOA有三种位置更新机制随机搜索鲸鱼随机找一头其他鲸鱼朝它游动对应全局勘探。包围捕食所有鲸鱼朝当前最优个体收缩包围对应局部开发。螺旋气泡网鲸鱼沿螺旋线向最优个体靠近模拟泡泡网攻击。关键控制参数是 (A 2a \cdot r - a)其中 (a) 从2线性降到0(C 2r)(r) 是[0,1]均匀随机数。当 (|A| \ge 1) 时执行随机搜索当 (|A| 1) 时执行包围捕食同时以50%概率执行螺旋更新。选WOA而不是粒子群或遗传算法主要原因是WOA参数少、实现简单、全局勘探能力够用在电价这类连续优化问题上收敛速度还不错。从我实际对比的情况看标准WOA比标准PSO更稳关键是“螺旋更新”这个操作在电价搜索空间里能产生局部微调的效果不容易把某些时段的电价锁死在边界跳坑的概率会小一些。3.2 双层嵌套求解架构设计我设计的求解架构是“外层WOA 内层博弈迭代”整体逻辑如下外层每个鲸鱼个体表示一组归一化后的24维电价向量映射到实际电价范围后作为当前定价策略。上层计算出这组电价后传入内层博弈模块。内层模块在给定电价下让所有用户进行多轮最优响应迭代直到得到纳什均衡解输出所有用户的负荷曲线。上层拿到负荷曲线后计算峰谷差或收益把结果作为该鲸鱼个体的适应度。外层WOA根据适应度更新全部鲸鱼位置生成新的电价策略重复整个流程直到达到最大迭代次数或适应度连续若干代没有改善。这里需要说明为什么叫“双层鲸鱼算法”。严格来说是“用于求解双层优化模型的鲸鱼算法”而不是“两个鲸鱼算法叠在一起”。但在很多论文里“双层WOA”也有一种写法是外层一张鲸鱼种群负责搜电价内层再用一张小型鲸鱼种群或另一个优化器去求用户的最优响应。我复现时内层直接用循环迭代的博弈求解器因为内层问题有明确的数学结构用循环迭代比再套一个启发式算法更可控。3.3 针对双层嵌套计算量大的三个改进双层嵌套计算量非常大外层每评估一个鲸鱼个体都要跑一遍完整的内层博弈。如果外层种群30个、迭代100次内层每轮博弈又要迭代50次理论上需要评估 (30 \times 100 3000) 次内层求解一次完整仿真可能要跑几个小时甚至更久。我做了三个改进实测效果明显一是外层采用非线性收敛因子衰减即 (a 2(1 - (iter/maxIter)^2))。相比标准WOA的线性衰减这种方式前期收敛因子下降更慢可以让鲸鱼有更多时间做全局勘探后期快速收敛到局部精细搜索。在电价规划问题上前期勘探直接决定了能不能跳出“全天统一电价”这种平庸解。二是内层博弈采用间隔更新策略。每个用户不必每一轮都重新计算最优响应可以每两轮更新一次。这个想法源自异步更新的思想实测在用户数量超过50户时收敛速度能提升一倍左右而均衡点的位置变化非常小。原因是用户策略之间存在惯性频繁同步更新反而容易造成过度反应。三是对适应度函数做缓存机制。如果两个鲸鱼个体代表的电价向量差异很小比如最大分量差小于0.001就直接复用历史适应度不再调内层求解器。这个在种群进化后期尤其有用因为大量个体会聚集在最优解附近缓存命中率很高。做完这三个改进完整算例从原来跑几个小时的量级降到了半小时内出结果对于调试阶段来说完全够用。4. Matlab代码实现与实操4.1 代码文件结构规划整个项目建议按模块拆分不要把所有代码堆在一个文件里main.m主脚本负责读入参数、启动外层循环、调用结果绘图。obj_upper.m上层目标函数输入电价和负荷曲线输出适应度。solve_Nash_game.m内层博弈求解函数项目核心。user_response.m单个用户的最优响应函数。WOA_main.m鲸鱼优化算法主体函数。plot_results.m绘制电价曲线、负荷曲线、收敛曲线。文件拆开的好处很明显后期想换算法比如把WOA换成灰狼算法或差分进化时只需要改外层对应的文件内层完全不用动。而且每个模块可以单独写测试脚本调试阶段省下的时间非常可观。我自己的习惯是每完成一个子函数先写一段测试代码只跑这个子函数确认输出合理后再接进主流程。4.2 典型参数设置与初始化我复现时用的典型参数如下参数项数值用户数量80户调度周期24小时每小时一个时段电价范围0.3-1.5元/kWh可转移负荷数量每户1-2个可转移任务可削减负荷功率空调负荷1-2kW变压器容量约束200kW社区级外层WOA种群30外层最大迭代120次内层博弈最大迭代50次需要特别强调用户数量如果太大内层博弈的迭代复杂度是 (O(N \times T \times iterations))而且不是所有用户都对电价敏感。我建议先跑20户小规模算例确认博弈收敛逻辑正确再扩到100户以上。否则一上来就大规模出了问题都不知道是算法不收敛还是程序写错了。4.3 内层博弈核心代码讲解内层博弈求解函数是代码实现里最关键的部分核心逻辑就是“给定对手策略算自己的最优反应”然后交替更新function [loadProfile, equilibriumFlag] solve_Nash_game(price, userParams) % price: 1xT 分时电价 % loadProfile: NxT 各户各时段总负荷 N userParams.numUsers; T length(price); loadProfile zeros(N, T); optimalResponse loadProfile; for iter 1:userParams.maxInnerIter for i 1:N % 给定其他用户负荷求第i个用户的最优响应 otherLoad sum(loadProfile, 1) - loadProfile(i,:); optimalResponse(i,:) user_response(price, otherLoad, userParams, i); end % 收敛判断前后两次负荷变化小于阈值 if max(abs(optimalResponse(:) - loadProfile(:))) 1e-4 equilibriumFlag 1; break; end % 阻尼更新防止策略振荡 epsilon max(0.5, 1 - iter / userParams.maxInnerIter); loadProfile epsilon * optimalResponse (1 - epsilon) * loadProfile; end equilibriumFlag 0; % 若循环结束仍未达到阈值标记为未收敛 end这里有个很实用的细节阻尼更新那一行不是摆在最优响应更新之前而是在收敛判断之后。意思是一开始先判断用户是否改变策略如果已经稳定就直接退出如果还在振荡就用衰减系数把新策略和旧策略做一个加权平均。我在调试过程中发现不加阻尼时两个用户的负荷时段经常在代际之间互换始终达不到收敛阈值加了阻尼之后立刻稳定下来。4.4 上层目标函数与WOA结合上层目标函数的输入是电价向量和负荷曲线输出是适应度。我的实现里适应度函数定义为峰谷差和电价波动惩罚的加权组合function fitness obj_upper(price, loadProfile) loadTotal sum(loadProfile, 1); % 所有用户总负荷 peakValleyDiff max(loadTotal) - min(loadTotal); priceVolatility max(price) - min(price); fitness peakValleyDiff 0.2 * priceVolatility; end注意在负荷建模时有一个容易漏掉的约束分时电价会影响用户把可转移负荷安排在哪个时段但不会影响总用电需求。也就是说可转移负荷的总量在调度前后必须保持不变否则相当于凭空增加或减少了用户的用电需求算出来的电费完全失真。我在代码里用全局约束检查来保证这一点每个用户的可转移任务总时长乘以额定功率必须等于预设值不满足直接判罚。外层WOA主体代码相对简单就是标准的包围捕食、螺旋更新和随机搜索三种位置更新逻辑结合目标函数计算适应度后迭代更新最优个体。4.5 对调试友好的输出设计我建议在每次外层迭代后打印几行关键信息迭代代数、当前最优适应度、对应的峰谷差、平均电价、电价区间宽度。这样不用中断程序就能看到搜索行为是否健康。另外一个很有效的做法是把外层适应度曲线画出来实时刷新如果曲线出现长时间水平线不动基本可以判断是外层陷入局部最优需要调参数或重新生成初始种群。另外我强烈建议把每轮迭代的决策变量快照保存下来而不是只存最终结果。中间过程的电价演化曲线对分析算法行为非常宝贵写报告或者做答辩的时候展示“从初始均匀电价到最终多峰电价”的演化过程比只放一张最终结果图更有说服力。5. 仿真结果分析与常见问题排查5.1 结果曲线怎么读复现完成后通常需要看四类图外层适应度收敛曲线确认算法没有振荡或早熟。优化前后的总负荷对比看峰谷差是否真的减小。电价与用户负荷的时变关系看高电价时段是否对应负荷低谷。各用户电费分布看是否存在个别用户电费异常高或异常低。我在实际跑的时候发现一个有意思的现象优化后的分时电价并不是简单的“峰时高价、谷时低价”而是会在用户响应后出现一定程度的“价格反弹”。原因是当大量用户看到低价时段后都涌过去用电低价时段的新负荷峰值反而可能超过原来的高峰于是算法在下一次迭代会把该时段价格调回来。最终稳定的电价曲线往往有多个价格小峰反映了用户群体行为的非均匀性。这个现象在刚开始跑的时候容易误判为算法不收敛其实是博弈交互的自然结果。5.2 常见问题速查表问题现象可能原因解决方法外层适应度曲线剧烈振荡内层博弈未收敛即返回负荷曲线调大内层最大迭代次数或收紧收敛阈值结果长期不更新外层陷入局部最优调整收敛因子衰减方式或更换随机种子某用户电费为0或异常低可转移负荷总量约束写错检查任务持续时间约束是否生效峰谷差减小但总负荷增加罚函数权重失衡将总量偏差惩罚系数提高几个数量级博弈循环始终不收敛用户之间策略互相冲突改用阻尼更新策略或缩短用户单步决策步长其中最后一条是很多同行的真实痛点。直接使用最优响应替换策略在数学上是最朴素的“最优反应动态”但在代码层面极容易出现两个用户之间不断互换负荷时段、始终停不下来的情况。我用“新策略等于阻尼系数乘以最优响应加剩余比例乘以原策略”的方式让每个用户不会一下子跨到当前最优解而是逐步靠近实测收敛稳定性明显提升。5.3 代码调试中的独家经验第一先把内层博弈单独测试。给一组固定电价和用户参数单独跑solve_Nash_game函数看内层循环能不能收敛。如果内层都不收敛外层跑多少代都没有意义。我之前吃过这个亏外层跑了几十代以为结果合理其实内层每次返回的都是未收敛的中间态造成外层在同一个“假均衡”附近反复搜索。第二不要一上来就追求大规模。先用10户、24时段的算例把流程跑通结果合理后再扩展。这个建议听起来像废话但项目周期紧张的时候最容易跳过这一步最后修bug的时间多出好几倍。小规模算例的另一个好处是可以手算核验比如只有两户用户时可以用穷举验证博弈均衡点是否和代码输出一致确认建模没写歪。第三控制程序运行时间时优先削减外层迭代次数而不是减少内层博弈迭代。因为内层博弈精度直接影响每次外层评价的质量外层迭代少了只是搜索粗糙一点不会破坏模型逻辑。如果内层为了省时间而降低精度外层会把噪声当成真实的适应度信号导致算法行为变得非常不可预测。第四如果论文里要分析不同算法对比建议保留完全相同的参数设置只换外层算法。我试过在固定随机种子的前提下把WOA换成粒子群和差分进化发现WOA在电价搜索问题上常常能找到峰谷差更小的解而且在迭代后期收敛更干净。个人体会我在复现这个模型过程中最大的收获是把“双层优化”从纸面概念变成了能跑的代码。一开始我以为只要把两个优化器套在一起就能出结果结果跑出来的东西完全不对劲——要么电价冲到上限不动要么用户负荷在几个时段来回跳。后来沉下心把内层博弈单独拎出来调试才发现问题是策略更新没有加阻尼、可转移负荷总量约束没写对。这两个细节比算法本身更能决定模型能不能收敛。如果后面你想往深了做可以考虑三个方向一是把外层从标准WOA换成混合策略比如WOA和差分进化交替搜索提高跳出局部最优的能力二是引入负荷聚合商的中间层把电网-用户两层结构扩展成电网-聚合商-用户的三层Stackelberg结构贴合实际电力市场体系三是在内层博弈中考虑用户的有限理性用演化博弈替代完全理性纳什均衡这样更接近真实居民用户的行为模式。每个方向都是不错的延伸选题我自己已经准备在下一个项目中尝试三层结构了。
返回列表