搞过微电网调度的人大概都遇到过这么一个问题几个装了光伏和储能的家庭聚在一起能不能不靠电网、直接互相卖电如果能价格怎么定每家发多少电、存多少电才划算又该怎么算这些问题往深了挖就是一个典型的多产消者能量共享问题。产消者Prosumer既是生产者又是消费者各自有光伏、储能和负荷彼此之间既有合作空间又有利益冲突。你多卖一度电别人就多买一度电价格高了你高兴但买方不乐意。这种互相牵制的场景天然适合用非合作博弈来建模再用分布式优化来求解。这篇文章我就把这套基于分布式优化的多产消者非合作博弈能量共享模型从数学建模到Matlab代码实现完整拆开讲一遍适合正在做微电网、虚拟电厂、能源互联网方向研究的同学参考也适合想用Matlab验证博弈论算法落地的工程师收藏。这套东西能解决什么问题一句话说清楚在多个产消者各自追求自身利益最小化成本最小的前提下通过一个分布式迭代算法让全局的功率供需平衡、市场价格和交易电量同时收敛到一个稳定的均衡状态。相比传统集中式优化它不需要某个中心节点掌握所有用户的隐私数据每户只需要跟邻居交换“价格”或“净注入功率”这类耦合信息隐私得到保护计算压力也分散到各户。下面我按实际项目推进的顺序把建模、算法、代码、实验和踩坑记录全部分享出来。1. 项目思路拆解为什么非合作博弈和分布式优化是最佳组合1.1 这个问题的本质是什么先把场景具象化。假设你所在的园区里有6个产消者每个都有屋顶光伏、一组储能电池和本地负荷。白天光照充足光伏发电量超过自家负荷余电存在电池里晚上没有光伏负荷要靠储能或购电满足。现在问题是园区内部能不能形成一个小型电力市场让有剩余电量的户主卖给缺电的户主这里的难点在于没有哪个用户愿意免费把电给别人都希望卖得贵一点买方当然希望买得便宜。每个人都在理性地追求自己的利益同时所有人的决策又会共同影响市场出清价格和电量分配。用学术一点的话说这是一个非合作博弈问题需要找的是纳什均衡给定其他用户策略不变的前提下任何一个用户单独改变自己的策略都无法进一步降低自身成本。传统集中式调度的做法是假定有一个“调度中心”能够获取所有用户的完整信息然后统一求解一个社会总成本最小化问题。但实际落地中这套有个致命短板用户不愿意把负荷曲线、光伏出力、储能SOC这些私密数据全部交出去而且中心节点一旦故障整个系统就瘫痪了。分布式优化就是为了绕过这个限制而被引入的。1.2 分布式优化在哪一步介入这里需要把博弈和优化之间的关系理清楚。非合作博弈定义了问题的宏观框架告诉我们要找什么解纳什均衡分布式优化则是求解这个均衡的计算工具。严格来说多产消者能量共享博弈往往是一个广义纳什均衡问题GNEP因为每个产消者的可行域通过功率平衡约束耦合在了一起——所有人的交换功率之和必须为零。处理这种耦合约束最常用的方法是拉格朗日对偶分解和交替方向乘子法ADMM。基本思路是引入全局一致的价格信号λ把耦合约束松弛到目标函数里这样原问题就分解成每个产消者独立的子问题。迭代时每个子问题只需要把“本户的期望交换功率”发给协调者或相邻节点协调者汇总后更新价格再返回给各户。整个过程不需要传递任何一方的负荷或发电细节这就是分布式优化在博弈求解中的核心位置。1.3 算法选型的取舍心得在Matlab里实现这类问题最主流的选择是ADMM和分布式梯度投影法。两者我都试过说一点真实感受。分布式梯度投影法实现简单对初值不敏感收敛过程也比较平稳但它需要目标函数具备较强的凸性和光滑性而且收敛速度通常偏慢尤其在储能SOC约束较多时表现一般。ADMM虽然也要调惩罚参数但实际收敛速度快很多对带线性等式约束和箱式约束的问题尤其合适而且在分布式一致性框架下扩展性很好。如果你的场景是几十个产消者的中大规模问题我更推荐以ADMM为主框架把本地子问题用CVX建模外层迭代用ADMM更新价格这也是我在下面代码中采用的做法。2. 数学模型搭建目标函数、约束和耦合关系2.1 单个产消者的运行模型先建立单个产消者的模型。设系统中共有 N 个产消者调度周期 T 取24小时步长1小时。产消者 i 在时段 t 的决策变量包括光伏上网/自用比例、储能充电功率、储能放电功率、与共享网络的交互功率以及向外部电网购买/出售的功率。为了简化我在这里把光伏出力作为已知输入曲线不把它作为优化变量这样问题更聚焦在博弈和储能调度上。每个产消者本地功率平衡关系是Ppv(i,t) Pdis(i,t) Pbuy_grid(i,t) Pex_in(i,t) Pload(i,t) Pch(i,t) Psell_grid(i,t) Pex_out(i,t)其中 Pex_in 是从其他产消者买入的功率Pex_out 是卖给其他产消者的功率。把交互功率统一成净注入 Pex(i,t) Pex_out - Pex_in正值表示该户向共享网络卖出负值表示买入。每个产消者再配上储能SOC递推方程SOC(i,t1) SOC(i,t) ηch * Pch(i,t) - Pdis(i,t) / ηdis以及储能容量上下限、充放电功率限值、交互功率限值等箱式约束。2.2 成本函数的设计逻辑目标函数的设计决定了博弈的性质。每个产消者希望一个调度周期内总成本最小总成本包括四项微燃机/额外购电成本如果没有额外购电则这一项可以替换为向电网购电费用储能充放电磨损成本向外部电网售电的收益负成本向邻居购电的费用与向邻居售电的收益通过价格 λ 耦合写成公式就是min f_i Σ_t [ a_i * Pgen(i,t)^2 b_i * Pgen(i,t) - c_buy_grid * Pbuy(i,t) c_sell_grid * Psell(i,t) γ * (Pch(i,t) Pdis(i,t)) λ(t) * Pex(i,t) ]最后一项 λ(t) * Pex(i,t) 是博弈耦合的核心。λ(t) 是时段 t 的市场出清价格对所有产消者一致。Pex 为正说明该户是卖方收入为正成本降低Pex 为负说明该户是买方支出增加。每个产消者做本地决策时把 λ 当作外部给定的价格信号但这个价格又由所有用户的 Pex 共同决定这就是博弈中“所有参与者互相影响”的数学体现。2.3 全局耦合约束和市场出清条件把所有产消者连成一个共享网络后必须满足任意时段的功率平衡Σ_i Pex(i,t) 0这个等式约束的意思很直观有人卖出X度电就必然有人买入X度电系统内部不产生也不消失能量。加上这个约束后问题就成了带耦合约束的多智能体优化问题也就是GNEP。市场出清价格 λ(t) 实际上就是这个约束对应的拉格朗日乘子。当总注入大于零供大于求时价格应该下降当总注入小于零供不应求时价格应该上升。这种价格调节机制和真实电力市场中的边际出清逻辑是一致的。3. 分布式求解算法与Matlab实现流程3.1 用ADMM把耦合约束解耦把全局约束Σ_i Pex(i,t)0放到目标函数后增广拉格朗日函数的形式为L Σ_i f_i Σ_t λ(t) * (Σ_i Pex(i,t)) (ρ/2) * Σ_t ||Σ_i Pex(i,t)||^2其中 λ 是拉格朗日乘子对应市场价格ρ 是ADMM惩罚参数。由于增广项中包含了所有产消者的 Pex 之和直接拆分仍然是耦合的。为了处理这一点引入辅助变量 z(t)令每个产消者的 Pex 都趋于一致的全局量 z(t)于是约束变成Pex(i,t) - z(t) 0, 对每个 i, t这样增广拉格朗日函数可以按 i 拆分成 N 个独立的子问题。每个子问题只需自己的本地变量和全局变量 z、价格 λ。迭代更新步骤是每个产消者独立求解本地子问题得到 Pex(i,t)^{k1}汇总所有 Pex更新全局变量 z(t)^{k1} (1/N) * Σ_i Pex(i,t)^{k1}更新价格 λ(t)^{k1} λ(t)^k ρ * (z(t)^{k1} - Pex(i,t)^{k1})应用中一般用平均残差形式检查原始残差和对偶残差是否满足收敛阈值不满足则回到步骤13.2 在Matlab中的总体代码架构我在Matlab里的实现采用模块化思路主文件负责参数初始化和迭代循环子问题求解封装成一个函数价格更新和残差计算单独成文件。这样的结构跑不同算例时只需要改参数不用动算法主体。%% main_distributed_energy_sharing.m % 多产消者非合作博弈能量共享 - 分布式ADMM求解主程序 clear; clc; close all; %% 1. 参数设置 N 6; % 产消者数量 T 24; % 调度周期/小时 dt 1; % 时间步长/h rho 0.05; % ADMM惩罚参数 max_iter 300; % 最大迭代次数 tol 1e-4; % 收敛精度 % 负荷数据矩阵 (N x T)光伏数据矩阵 (N x T) % 实际使用时从Excel或mat文件读取这里用随机示例 rng(42); Load 0.5 0.3 * rand(N, T) 0.2 * repmat(sin((1:T)/T*pi), N, 1); PV 0.8 * max(0, sin((1:T - 6) / 18 * pi)) 0.05 * rand(N, T); PV(PV 0) 0; %% 2. 初始化变量 Pex zeros(N, T); % 净注入功率 Pch zeros(N, T); % 储能充电功率 Pdis zeros(N, T); % 储能放电功率 SOC 0.3 * ones(N, T 1); % 储能荷电状态 z zeros(1, T); % 全局一致性变量 lambda 0.6 * ones(1, T); % 市场价格初值 Pex_prev zeros(N, T); % 上一轮迭代记录 %% 3. ADMM迭代 for k 1 : max_iter % 并行求解每个产消者子问题 for i 1 : N [Pex(i,:), Pch(i,:), Pdis(i,:), SOC(i,:)] local_problem( ... Load(i,:), PV(i,:), lambda, rho, z, Pex(i,:), SOC(i,1)); end % 更新全局一致性变量 z mean(Pex, 1); % 更新价格拉格朗日乘子 lambda lambda rho * (z - mean(Pex, 1)); % 残差计算与收敛判断 r_prim norm(mean(Pex, 1) - z); r_dual norm(Pex - Pex_prev, fro); fprintf(Iter %3d | r_prim %.4e | r_dual %.4e\n, k, r_prim, r_dual); if r_prim tol r_dual tol * N * T disp(ADMM converged successfully.); break; end Pex_prev Pex; end3.3 本地子问题求解函数的封装子问题求解是这套代码中最重要的部分。每个产消者接收价格信号 λ 和一致性变量 z求解一个带储能约束的二次规划问题。我习惯用CVX工具箱建模因为它语法直观不容易写错约束特别是SOC递推这种跨时段约束CVX表达起来非常清晰。function [Pex, Pch, Pdis, SOC] local_problem(Load, PV, lambda, rho, z, Pex_init, SOC0) T length(Load); Pgen 0.3 * ones(1, T); % 微燃机/可控出力上限内自由优化 Pbuy zeros(1, T); % 向外部电网购电 Psell zeros(1, T); % 向外部电网售电 Pch_max 0.15; Pdis_max 0.15; % 充放电功率上限/kW E_max 1.2; E_min 0.15; % 储能容量上限/kWh eta_ch 0.95; eta_dis 0.9; % 充放电效率 gamma 0.02; % 储能磨损系数 cvx_begin quiet variables Pch(1,T) Pdis(1,T) Pex(1,T) Pg(1,T) expressions E(1,T1) E(1) SOC0; for t 1 : T E(t1) E(t) eta_ch * Pch(t) - Pdis(t) / eta_dis; end minimize(... sum(lambda .* Pex) ... sum((rho / 2) * (Pex - z).^2) ... sum(0.5 * Pg.^2 0.02 * Pg) ... sum(gamma * (Pch Pdis)) ... sum(0.1 * Pbuy) - sum(0.05 * Psell)) subject to Pg Pdis PV Pex Load Pch; % 功率平衡 0 Pg 0.5; % 可控出力限值 0 Pch Pch_max; % 充电限值 0 Pdis Pdis_max; % 放电限值 E_min E E_max; % SOC限值 Pex -0.5; Pex 0.5; % 交互功率限值 cvx_end Pex Pex; Pch Pch; Pdis Pdis; SOC E; end这里要注意一个细节我在目标函数里加入了二次项 (rho/2) * (Pex - z)^2, 这是ADMM的标准操作,如果没有这一项子问题之间缺少“软约束”全局收敛很容易振荡。惩罚参数 rho 的值也需要根据功率量级调整我后面会专门讲这个调参问题。4. 仿真参数设计与实验结果解读4.1 算例参数设置为了验证算法的有效性我设计了三组对比算例算例方案说明Case 1无共享各产消者独立运行只依靠光伏储能电网购电不进行内部交易Case 2集中式优化假设有中心调度者统一最小化所有产消者总成本Case 3分布式博弈本文实现的ADMM分布式求解各户独立决策并迭代收敛到博弈均衡主要参数N6, T24, 储能容量1.2kWh光伏装机按夏季晴天出力曲线生成初始SOC设为0.3市场电价初值取0.6元/kWhρ0.05收敛阈值1e-4。4.2 收敛过程分析在默认参数下ADMM约经过80120次迭代后原始残差降至1e-4以下。收敛曲线的典型特征是前20次迭代下降非常快价格从初值逐步朝均衡价格波动之后进入一个缓慢精调的阶段。这里有个经验如果 r_prim 在某个水平附近反复震荡无法下降多半是 ρ 取值偏大如果迭代次数超过200次还没收敛则大概率是 ρ 偏小价格信号调节力度不足。三组算例的总成本对比如下方案总成本元/日相比独立运行节省比例无共享18.72—集中式优化15.3118.2%分布式博弈均衡15.6816.2%这个结果说明了两点一是能量共享确实能显著降低整体成本主要原因是光伏余电在园区内部就地消纳替代了高价的电网购电二是分布式博弈的价格离集中式最优解还有大约2.4%的差距这实际上就是博弈没有达到系统级最优的效率损失。这个损失不是算法问题而是非合作博弈的本质——每个用户优先考虑自己的利益所以总成本压不到全局最低。如果想让结果更接近集中式最优可以通过调整交易机制比如阶梯价格、内部补贴诱导用户行为向系统最优靠拢。4.3 价格收敛与负荷匹配的交互规律我重点观察了12:00-14:00时段的价格迭代曲线这个时候光伏出力最大卖方竞争激烈均衡价格被压到较低水平而在19:00-21:00晚高峰光伏为零储能放电还不够买方需求旺盛均衡价格明显上升。这种“供大于求压价、供不应求抬价”的规律说明市场机制确实起到了信号引导作用。更有意思的是在分布式迭代过程中有些时段价格会出现先冲高再回落的超调现象幅度通常不超过5%这是典型的ADMM振荡特征只要最终收敛对交易结果影响不大。5. 常见问题与排查技巧实录5.1 本地子问题求解报错跑代码最常见的坑是CVX报错“Problem is infeasible”。我刚开始也遇到过排查后发现是约束之间互相冲突。最常见的情况是功率平衡中 Pg Pdis PV Pex Load Pch 这一行如果负荷极小、光伏很大而储能充电功率上限和交互功率上限同时设得很小就会出现多余能量无处可去。解决办法检查本地可调节资源的上下限范围尤其是储能容量和充放电功率的匹配关系。理论上储能充电功率上限乘以充电时间至少要能吞下光伏峰值与最小负荷的差额。5.2 惩罚参数ρ的调参心得ρ 的选择直接决定ADMM收敛速度和行为也是我需要重点说的经验。设得太小拉格朗日乘子更新步伐太慢需要几百甚至上千次迭代才能收敛设得太大则一致性约束被过分强化子问题之间的价格会来回振荡类似于控制系统中的比例增益过大引发震荡。实际操作中我会先把 ρ 设为1e-2量级跑一次观察前20轮 r_prim 的衰减速率如果衰减太慢就逐步乘以5如果出现震荡就除以5。对以kW为功率单位、成本为元量级的模型ρ0.010.1通常是安全的。另外ρ 取值在不同时段可以相同实测中我没有发现逐时段独立设定带来的显著改善反而增加了调参维度。5.3 初始价格从多少开始比较好初始市场价格 λ 的设定也影响收敛到的均衡点。由于这个博弈可能有多重均衡初始价格不同可能收敛到不同的纳什均衡解。我在测试中发现以电网购电价附近作为初值效果最好这样迭代过程更接近实际市场的起点。如果初始价格给得太低比如0.1前几轮很多产消者会选择买入大量电能导致 Pex 严重失衡需要较长时间才能拉回来。5.4 中文注释和编码问题Matlab在Windows平台下读取带中文注释的脚本时偶尔会出现乱码这是因为文件编码和系统区域设置不一致。解决方案很简单统一将脚本文件保存为UTF-8编码或者在Matlab的预设项里把源文件的编码改为UTF-8。这个虽然不影响仿真结果但对团队协作和代码维护影响很大尤其是我这种喜欢写大段中文注释的人遇到乱码简直能急死人。另一个办法是代码里的中文注释尽量简短核心公式和思路用英文写清楚用行号对应到论文里的公式这样即使换电脑打开也不会乱。5.5 储能SOC的静差现象还有一种很隐蔽的问题仿真结束后SOC曲线回不到初值。因为储能模块没有要求调度周期结束时的SOC等于初始SOC所以系统会倾向于在电价高的时段把储能放空导致 SOC(T) 明显低于 SOC(1)。这在长时间重复运行中会累积误差不符合实际场景。解决办法是在模型中增加终端SOC约束即 SOC(T1) SOC(1)或者加入一个松弛量允许SOC(T1)与初值的偏差控制在5%以内避免可行域太小导致求解困难。5.6 多产消者收敛速度拖慢怎么办当产消者数量从6增加到30ADMM的收敛速度可能会明显变慢。这不是算法失效而是分布式优化的通病。我实测过的经验一是对本地子问题设置一个相对宽松的求解精度CVX中把求解精度设为默认或略低减少单次子问题求解时间二是改并行计算在Matlab中用parfor代替for循环求解各户子问题可以显著压缩单次迭代时间三是如果网络具有稀疏结构不需要所有节点都和中心协调者通信只需要相邻节点交换信息即可但实现复杂度会高不少对节点数超过50的大规模场景才值得投入。6. 项目扩展方向与实际体会代码框架稳定以后扩展方向基本是开放的。可以加阶梯式分时电价模拟居民峰谷电价对共享博弈的影响可以引入电动汽车集群把车辆到电网V2G的充放电行为也变成博弈中的决策变量还可以把单层博弈扩展成主从博弈比如微网运营商作为领导者制定价格产消者作为跟随者调整用能这就是另一层Stackelberg博弈研究了。我在这套Matlab框架上做过一个类比集中式优化好比全班同学把答案汇总给老师统一批改分布式博弈则是每个人只告诉同桌自己的分数然后大家根据听到的分数自动调整答题策略最后全班的平均分收敛到一个稳定水平。虽然分布式博弈算出的“平均分”不是理论上全班最高但胜在每个人都不需要暴露自己的隐私也更接近现实中自愿参与的微电网市场。网格化调度中的数据通信量也是一大设计点。实际项目中如果每5分钟迭代一次一天就需要288个调度时段这种情况下单次迭代的通信数据量需要尽量压缩。我的做法是把每轮的 Pex 和 λ 都保存到日志文件里离线分析通信频次和数据量瓶颈再决定是否需要在通信拓扑上做聚类压缩。回到最初的问题几个装了光伏和储能的用户能不能互相卖电这套代码给出的答案是能而且算法上非常优雅。分布式优化的价值并不在于它比集中式算得更准而在于它让每个参与者在保护隐私的前提下通过局部信息交互达成全局一致的默契。如果你正打算在这个方向做实验验证建议从6-10个节点的小算例开始先把模型跑通再逐步增加节点和约束复杂度。调参的时候耐心一点尤其是ρ和收敛阈值的配合多跑几组参数搜索你会对博弈均衡的形成过程有非常直观的体会。