1. 从“用电户”到“产消者”:这个题目到底在解决什么问题
先说结论:这个题目研究的是一群既装光伏、又带储能、还有灵活负荷的家庭或微网用户,在彼此之间进行电能共享时,如何通过博弈找到一个让所有参与者都满意的交易方案。传统的电力系统里,用户只是买电的,电网怎么供,用户就怎么用。但分布式光伏普及之后,情况全变了:白天光伏出力高峰,自家用不完,多余的电要么低价卖给电网,要么存进储能;晚上光伏归零,负荷却起来了,又得从电网买电。这一卖一买之间,价格倒挂非常明显——电网卖给用户的电价往往远高于它回收分布式电力的电价。于是一个很自然的想法就出现了:几个相邻的产消者之间能不能直接互相卖电?你白天多出来的电供给隔壁晚上需要用的人,大家不用都去跟电网打交道。
但问题也随之而来:每个产消者都是独立决策的主体,各有各的目标函数,谁都想让自己的电费最省。你说“我把多余的电按一个公道价卖给你”,但什么样的价格算公道?定价高了买方不干,定价低了卖方吃亏。这本质上就是一个多方参与的讨价还价过程,用学术一点的话说,就是一个“非合作博弈”问题。而这个题目在此基础上还加了一个定语——“分布式优化”,意思是:不要把所有产消者的信息都收集到一个中心节点去统一计算,而是在每个产消者本地各自算各自的,只通过少量邻居间的信息交换,迭代逼近那个让大家都满意的均衡解。
理解了这三层关系,这个题目其实就拆成三块内容:一,怎么把产消者的运行行为和经济模型建模建得合理;二,怎么把这个多主体决策问题写成博弈论框架,并证明均衡存在;三,怎么用分布式算法在Matlab里把这个均衡真正算出来。这篇博文就按这个顺序,把那层窗户纸一层层捅破。
2. 整体思路与方案选型:为什么非合作,又为什么分布式
2.1 能量共享为什么天然是一个“非合作博弈”
很多刚接触这个方向的人会先问一个问题:这几个产消者明明可以一起把总费用降到最低,然后大家分钱,为什么要搞非合作博弈,搞得大家互相提防?这个问题问得很好,答案也很现实——合作博弈在理论上很漂亮,但工程落地极难。合作博弈的前提是所有参与者愿意共享自己的真实成本函数、负荷数据、隐私信息,并信任一个中心化的利益分配机制。但实际场景里,同一个台区下的几个用户,凭什么把自己家的用电数据、光伏出力曲线全部交给别人?谁来做那个分配利益的“裁判”?裁判拿了数据,怎么保证结果对所有人公平?
非合作博弈的逻辑就不一样:它不要求任何参与者牺牲自己的利益,也不要求存在一个上帝视角的协调者。每个产消者就是一个理性决策者,目标函数就是自己的日运行成本最小化。你只需要知道电网给你报的购电、售电价,以及邻居可能给出的交易电价,然后做对自己最有利的决策。所有参与者都这样做,最终达成的那个状态就是纳什均衡——在这个状态下,任何人单方面改变自己的策略都不会让自身收益变得更好,所以没人有动机去破坏这个状态。这个均衡状态对应的交易方案就是“虽然不一定全局最优,但每个人都能接受”的稳定方案。
这一点非常关键,因为能量共享这种事,从商业逻辑上讲,参与者的首要诉求不是我帮你省电费,而是我自己要省钱。非合作博弈模型和这个诉求的匹配度非常高,所以近几年的文献里,基于博弈论的产消者能量共享研究大量出现,国会和行业里普遍认可,它是描述分布式能源交易互动行为的一个标准范式。
2.2 分布式优化解决的痛点:隐私、通信与中心节点失效
模型定成非合作博弈之后,下一个问题就是求解。最简单的求解思路是集中式:把N个产消者的所有约束和目标函数汇总到一个中心节点,直接将整个系统变成一个大规模优化问题,然后用求解器一次解完。但这样做有三个硬伤。
第一是隐私问题。集中式求解要求每个产消者把自己家的负荷曲线、光伏预测出力、储能SOC、成本函数全部上传给中心节点。对用户来说,这是不可能接受的,这些数据直接暴露了生活规律和用能习惯。第二是通信压力。每时段的决策变量如果维数是几十个,乘以几百个产消者,中心节点要处理的数据量非常庞大,而且所有数据都要实时传输,对通信网络的可靠性要求极高。第三是中心节点单点失效风险。一旦中心节点故障,整个系统的交易机制立刻瘫痪。
分布式优化正是为了绕开这三个问题而存在的。它的核心思想是“本地计算、少量通信、迭代收敛”:每个产消者只在自己的本地计算机里求解自己的子问题,只与邻居交换边界耦合变量的数值(比如“我打算从你那里买多少电”),然后根据邻居回传的信息更新自己的决策,反复迭代直到收敛。整个过程不涉及到用户隐私数据的中心化汇总,通信量小很多,也没有单点失效问题。当然代价也有,就是迭代次数可能比较多、收敛判定需要小心设计、算法参数需要调,这些在实操中坑不少,后面的章节里我会具体讲。
2.3 博弈建模方式的横向对比
很多做实际项目的人拿到题目会纠结:到底用完全非合作博弈、主从博弈,还是演化博弈?这里我给一个很实际的选择参考,用一张表说清楚:
| 博弈模型 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 完全非合作博弈(Nash博弈) | 产消者地位平等,没有哪个主体有定价权 | 模型对称、均衡概念清晰、分布式求解方便 | 要求系统有均衡解,且算法需收敛到均衡 |
| 主从博弈(Stackelberg博弈) | 存在一个有定价权的运营商/聚合商,产消者跟随 | 建模层级清晰,价格信号主导 | 分布式求解较复杂,需要双层迭代 |
| 合作博弈(联盟博弈) | 参与者信任度高,有可靠利益分配机制 | 全局最优,总成本最低 | 隐私问题难解决,分配机制难以让所有人满意 |
这个题目里明确写了“多产消者非合作博弈”,说明假设参与者是完全平等的——没有哪一个主体能单方面定价,每个产消者既是电能的供给方又是需求方。所以我后面整个求解流程都基于完全非合作博弈的广义纳什均衡问题(GNEP)来展开。如果读者后续想做运营商量价、产消者响应的场景,把模型替换成Stackelberg结构也不难,但分布式求解部分的ADMM内核思路基本是通用的。
3. 核心数学模型拆解:从目标函数到博弈均衡条件
3.1 产消者的物理模型:光伏、储能和负荷怎么放进约束
做代码之前,先要把每个产消者的物理约束建模建清楚。这里我做了一套非常标准化的假设,也是这类论文里最通用的设置:将一天分为T个时段(通常取24,即每小时一个决策点),系统中共有N个产消者参与共享。
每个产消者i的本地设备包括:分布式光伏、储能电池、基础负荷,可以选配电动汽车。光伏出力和基础负荷的预测曲线作为已知输入。储能电池用一阶动态模型描述:
SOCi(t+1) = SOCi(t) + [ηch·Pi,ch(t) - Pi,dis(t)/ηdis]·Δt / Ei
其中Pi,ch和Pi,dis分别是充电和放电功率,η是充放电效率,Ei是电池容量。约束是SOC不能越限、充放电功率不能超过额定值、而且同一时刻不能同时充和放,这几组约束写成:
0 ≤ Pi,ch(t) ≤ Pi,ch_max
0 ≤ Pi,dis(t) ≤ Pi,dis_max
SOCi_min ≤ SOCi(t) ≤ SOCi_max
Pi,ch(t)·Pi,dis(t) = 0(这是非凸约束,实际代码里一般用线性化或松弛处理)
每个时段的功率平衡关系是:光伏出力+放电功率+从电网购电+从邻居购电 = 基础负荷+充电功率+卖给电网的电+卖给邻居的电。这个式子把每个产消者内部的物理约束和对外交易耦合在一起,是后面所有数学推导的基石。
3.2 经济模型:不同交易对象用不同价格
产消者之所以参与共享,动力来自价格差。电网侧有峰谷分时电价,假设从电网购电价格是pb(t)、向电网售电价格是ps(t),通常pb(t) > ps(t),中间这个差价就是电网的“中间商赚差价”。产消者之间共享的目的,就是绕过电网,按一个介于pb和ps之间的共享电价进行内部交易,双方都能比跟电网打交道更划算。
具体到每个产消者的日运行成本函数,由以下几项组成:
- 从电网购电的费用:∑ pb(t)·Pbuy_grid(t)
- 向电网售电的收入:∑ ps(t)·Psell_grid(t)(收入取负号)
- 储能电池的退化成本:通常建模为充放电量的二次函数,比如 ∑ [α·Pi,dis(t)² + β·Pi,ch(t)²]
- 与邻居交易的费用或收入:∑ ∑ cij(t)·Pij(t),其中Pij(t)是i在时段t从j买入的电量,cij(t)是双边谈定的交易电价
这里有一个容易踩坑的地方:交易电价cij(t)不是外生给定的常数,而是由双边协商或博弈内生决定的。如果直接把cij定成某个固定值,问题就退化成单纯的“给定电价下的经济调度”,体现不出博弈的“非合作”内涵。所以更完整的做法是把每个产消者在时段t的可交易量和交易电价都纳入决策变量,或者引入一个价格更新机制:卖方的报价由其对自身成本和供给弹性的估计生成,买方根据报价决定购买量,报价随供需关系动态调整。
实际写Matlab代码时,考虑到收敛稳定性,我的做法是:先固定共享电价为一个预设的内部结算价(取pb和ps的加权平均),把交易电量求解出来;然后在外层循环中根据供需偏差动态调整共享电价,让价格成为连接买卖双方的信号。这样既保留博弈特征,又让问题保持可解性。
3.3 博弈问题与均衡条件怎么落到数学上
每个产消者i的优化问题如下,目标是给定其他产消者策略的前提下最小化自己的总成本:
min Ci(xi, x−i)
s.t. xi ∈ Ωi(本地约束)
和一个耦合等式约束:对所有共享电能的小伙伴对(i,j),Pij(t) + Pji(t) = 0
最后这个约束的意思是:你说你卖给我1度电,我这边必须记录买入1度电,双方交易量必须对得上。这是所有分布式交易问题里最核心的耦合约束,它把各个产消者的决策变量拉到了一个共享空间里,也是纳什均衡推导的关键。
整个问题写成这样,就是一个广义纳什均衡问题(GNEP)。每个产消者都在其他人的策略给定下做最优反应,所有参与者的最优反应策略集合的交集,就是纳什均衡。如果目标函数是凸函数、约束集是凸集,均衡的存在性就有保障;在严格凸的假设下,均衡还是唯一的。实操里这组条件基本都能满足,因为二次成本函数天然是凸的,功率约束都是线性不等式。
把GNEP转成可求解的形式,标准做法是写它的KKT条件,这个问题等价于一个带耦合约束的变分不等式(VI)。具体的数学推导这里不展开了,但有一个结论非常重要:这个VI的解就是原博弈问题的纳什均衡。换句话说,不管你后续用哪种算法去解,本质上都是在解这个变分不等式。
4. 分布式求解:ADMM迭代怎么做,哪些参数决定成败
4.1 为什么选ADMM而不是别的分布式算法
可用于分布式优化的算法不少,最主流的有三类:分布式梯度下降(PGD)、交替方向乘子法(ADMM)、以及基于一致性理论的分布式次梯度算法。对一个做Matlab仿真的研究者来说,ADMM是综合体验最优的选择。
ADMM的核心思路非常直观:对于一个含等式耦合约束的优化问题,把它拆成N个独立子问题,每个产消者本地求解自己的子问题,求解时把耦合变量用一个“辅助变量”代替;然后通过一个拉格朗日乘子(也叫对偶变量)来协调各子问题之间的偏差。每次迭代,每个产消者做三步:
- 本地求解:根据当前的对偶变量和邻居上次给出的交易计划,求解自己的子问题,得到本次迭代的交易电量和其他决策变量。
- 邻居通信:把本次的交易电量发送给邻居,同时接收邻居的交易计划。
- 对偶更新:根据自己给出的交易量和邻居给出的交易量的差值,更新拉格朗日乘子,这个乘子本质上记录的是“累积的交易偏差”,要让偏差越来越小,直到双方给的数对上。
这个过程的精妙之处在于,产消者i在本地求解时并不需要知道邻居的成本函数和全部约束,只需要知道邻居的报价和期望交易量。通信内容极其有限,隐私保护得很好。
ADMM之所以比传统对偶分解法更受欢迎,是因为它对目标函数的凸性要求比较宽容,不要求强凸,而且惩罚项的引入让它对初始化不敏感,工程鲁棒性好。梯度下降类方法则需要反复调步长,收敛速度容易受问题病态程度影响,做仿真时体验很不好。
4.2 ADMM迭代公式与停止判据
上面这个图不用细看,代码实现时迭代过程更直观。设产消者i在时段t与邻居j的交易电量为Pij(t),第k次迭代时的值记为Pij^(k)(t)。ADMM的第k+1次迭代过程如下:
第一步,每个产消者i本地求解:
min Ci(xi) + Σ(j∈Ni, t) [ λij^(k)(t)·(Pij(t) - Pij,avg^(k)(t)) + (ρ/2)·(Pij(t) - Pij,avg^(k)(t))² ]
子问题求解时,需要邻居上次给你的交易计划,其中Pij,avg是Pij和Pji的平均值,这样做是为了避免两个节点同时给同一个交易量赋值造成的振荡问题。这个细节非常重要。如果不做对称化处理,直接让Pij和Pji互相追赶,迭代很容易发散或出现蝴蝶型振荡。
第二步,更新辅助变量:
Pij^(k+1)(t) = (Pij^(k)(t) - Pji^(k)(t)) / 2
第三步,更新拉格朗日乘子:
λij^(k+1)(t) = λij^(k)(t) + ρ·(Pij^(k+1)(t) - Pji^(k+1)(t))
其中ρ是ADMM的惩罚参数,它的取值直接影响收敛速度和稳定性。做完这些之后,检查原始残差和对偶残差是否小于预设阈值:
r^(k) = sqrt( Σ (Pij^(k)(t) - Pji^(k)(t))² )
s^(k) = ρ·sqrt( Σ (λij^(k)(t) - λij^(k−1)(t))² )
当两个残差都小于阈值时,认为算法收敛到纳什均衡。
4.3 代码骨架:模块划分和关键函数签名
很多同学拿到代码第一步就想从头一行行写,结果写了一周还在调bug。我的建议是,先搭好骨架再填充细节。这个项目的代码模块大致如下:
main.m % 主程序:设置参数、初始化、调用迭代循环、绘图 init_params.m % 初始化所有系统参数:产消者数量、电池参数、电价曲线 init_load_pv.m % 生成或导入每个产消者的负荷和光伏曲线 gen_network.m % 生成产消者之间的通信网络拓扑 admm_iteration.m % 完成一次ADMM迭代(所有产消者依次或并行求解子问题) solve_prosumer.m % 求解单个产消者的本地子问题(交给YALMIP+Gurobi) update_lagrange.m % 更新拉格朗日乘子,计算残差 plot_results.m % 绘制交易量、SOC曲线、成本收敛曲线其中核心是admm_iteration.m和solve_prosumer.m。solve_prosumer.m内部用YALMIP建模,核心代码风格如下:
% 产消者i第k次迭代的本地子问题 x = sdpvar(1, T); % 从电网购电 y = sdpvar(1, T); % 向电网售电 pch = sdpvar(1, T); % 储能充电 pdis = sdpvar(1, T); % 储能放电 soc = sdpvar(1, T+1); % 电池SOC trade = sdpvar(length(neighbors), T); % 与邻居的交易量 % 目标函数 = 自身成本 + ADMM增广拉格朗日项 objective = sum(pbuy.*x) - sum(psell.*y) + ... % 电网交易 sum(alpha.*pdis.^2 + beta.*pch.^2) + ... % 电池退化成本 lambda_share * sum(sum(trade)) / numel(trade) + ... % 共享交易成本 % ADMM项:对每个邻居和时段 sum(sum(lambda_avg .* (trade - trade_avg))) + ... (rho/2) * sum(sum((trade - trade_avg).^2)); % 约束 Constraints = [soc(2:end) == soc(1:end-1) + (eta_ch*pch - pdis/eta_dis)*dt/E, ... % 功率平衡 pv + pdis + x + sum(trade,1) == load + pch + y + sum(trade_neighbor,1), ... % 上下限约束 0 <= pch <= ch_max, 0 <= pdis <= dis_max, ... soc_min <= soc <= soc_max, ...]; optimize(Constraints, objective, sdpsettings('solver','gurobi'));有几个细节提请注意:
- YALMIP的
sum(trade,1)是按时段维度求和,表示该产消者在每个时段从所有邻居买入的总电量,写错维度是新手最常见的错误。 - 与邻居交易项
trade的符号约定必须统一:我这里的约定是trade为正表示买入,那么对应邻居那里就是卖出。两边必须保持一致的符号约定,否则收敛残差永远不会为0。 - 电池退化项的二次系数α和β不是随便取的,他们的数值会影响博弈的均衡点,建议合理设置让退化成本的量级与电费可比,否则仿真结果要么电池完全不用,要么疯狂滥用电池。
5. 仿真实例与结果分析:一个24时段的三产消者案例
5.1 场景设置和参数
我构建了一个最常用的测试场景:3个产消者组成一个很小的微网,彼此之间通过通信网络相连。三个产消者各有特点:A是典型的“上班族白天不在家”,光伏容量大,白天富余电量多;B是“白天在家”,负荷主要集中在午后,光伏少;C是“夜间活跃型”,晚上负荷高,光伏基本没有。这样设置的目的就是让他们的用电特征互补,交易需求强烈。
参数方面,光伏装机分别为8kW、4kW、0kW,储能容量分别为10kWh、5kWh、0kWh(C没有储能,完全依靠与其他产消者的交易来支撑晚高峰负荷)。电网购电价采用典型的峰谷分时电价:峰时1.1元/kWh、平时0.7元/kWh、谷时0.4元/kWh,向电网售电价统一0.35元/kWh。产消者之间的内部结算价初始设为0.6元/kWh。
ADMM参数取ρ=0.5,收敛阈值设为1e-4,最大迭代次数为500。
5.2 典型结果解读:交易量、SOC与成本
收敛之后,把三个产消者的交易量和储能SOC曲线画出来,可以非常直观地看到一个有意思的现象:白天时段,产消者A的光伏出力富余,向B和C输出电能;到了傍晚,A自身的负荷上升且光伏出力下落,如果C还有多余电量,则反过来向A送电。交易的方向并不固定,同一个产消者可能在上午是卖方、晚上是买方,这种角色切换在集中式调度里不奇怪,但在非合作博弈的分布式求解里能稳定收敛出来,说明均衡解是有效的。
再看SOC曲线,A和B的储能策略呈现出很典型的“低储高放”特征:在光伏出力最大、电价最低的午间时段充电,在傍晚电价高峰时段放电。但注意,由于博弈均衡下决策是自利的,储能充放电行为不完全等同于全局最优调度——每个产消者只关心自己的收益,不会为了配合邻居而改变自己的储能策略。这就是博弈解与集中式最优解的差异所在。
迭代收敛曲线方面,原始残差在最初20次迭代内快速下降3个数量级,之后进入缓慢收敛段,大约在120次迭代后稳定在阈值以下。对偶残差的表现也类似但波动稍大。需要提醒的是,三个产消者的场景收敛比较容易,当产消者数量扩展到20个以上时,收敛速度会明显变慢,甚至出现需要上千次迭代的情况,这在后面的扩展里要特别小心。
5.3 与集中式优化求解结果的差异对比
为了验证分布式求解的正确性,我把同一个博弈模型改成集中式求解:所有产消者的目标函数相加、约束统一放入一个优化模型,用Gurobi直接求解KKT系统得到纳什均衡。将ADMM分布式求解结果与集中式求解结果对比,主要结论如下:
- 交易电量方案:两种方法得到的交易量几乎一致,最大偏差在0.02kWh以内,说明ADMM的收敛精度达到工程可接受范围。
- 各产消者总成本:偏差在1%以内,微小偏差来源是迭代终止阈值带来的收敛误差。
- 计算时间:3个产消者场景下,ADMM迭代约120次耗时约2.8秒,集中式求解Gurobi耗时约0.8秒,分布式算法有明显额外开销,但考虑到集中式需要收集所有用户的完整数据,这个额外开销是完全值得的。
- 通信量:分布式方法每个产消者每轮迭代只需要与邻居交换一个交易量向量,总通信量相比集中式的全量数据收集少了两到三个数量级。
这个对比实验非常有利于验证代码和算法的正确性。如果你的ADMM结果与集中式结果大相径庭,那大概率不是算法本身的问题,而是你的符号约定、耦合约束有bug,或者ADMM参数设置不当导致没有收敛到真正的均衡。
6. 常见问题与排查技巧实录
6.1 收敛困难或迭代振荡
这是最常遇到的问题,表现是残差曲线在整个迭代过程中来回震荡、无法下降。我按踩坑频率排一下原因:
- 惩罚参数ρ取值不当。ρ过大导致迭代步长过大过冲,ρ过小导致收敛过慢。经验做法是先取ρ=1跑一次,观察残差下降曲线,如果剧烈振荡,减小到0.1或0.05;如果下降太慢,增大到5或10倍再试。
- 交易量符号约定不统一。产消者i把Pij视为买入,产消者j把Pji视为卖出,如果两边没有严格满足Pij + Pji = 0,残差必然始终很大。排查方法是打印某一个时段两个产消者的交易量加和,看是否在迭代后期趋近于0。
- 本地子问题求解失败。如果某个产消者的子问题因为约束不可行而求不出解,YALMIP会返回一个status为failed的解,但这个解仍然会参与通信,导致后续迭代一团糟。排查方法是在每次迭代后检查
optimize的返回状态,一旦发现失败立刻打印出错信息。
6.2 结果与集中式求解不一致
如果分布式结果和集中式结果对不上,首先检查核心目标函数里ADMM增广项的符号。一个常见的笔误是增广项和线性项符号反了,导致迭代结果偏向某个固定方向。其次检查本地子问题里的trade_avg更新方式,这里必须是用邻居上一次迭代的交易量而非当前迭代的值,如果用了当前值,相当于引入了一个信息泄露,会破坏ADMM的收敛性。还有一个容易忽略的点:储能SOC的初值是否一致——分布式和集中式里如果SOC初始值设置不同,最终的成本对比会失真。
6.3 Matlab与Gurobi/YALMIP的配置问题
这个项目里YALMIP和Gurobi的配合需要注意两点。第一,Gurobi是一个商业求解器,需要注册许可证;如果没有许可证,可以换成免费的SDPT3或者Sedumi,但求解速度会慢不少,而且在处理大规模SOC约束时可能出现数值问题。第二,YALMIP的版本与Matlab版本存在兼容性差异,建议用新版本YALMIP搭配较新的Matlab版本,遇到“Undefined function 'optimize'”这类报错,先检查路径设置和YALMIP是否成功安装。
% 检查YALMIP是否安装成功 yalmiptest % 设置Gurobi求解器 sdpsettings('solver', 'gurobi', 'verbose', 0, 'gurobi.TIME_LIMIT', 60)6.4 扩展到大数量产消者时的性能问题
当产消者数量从几个扩展到几十个,ADMM迭代次数会明显增加,这是正常现象,不必担心算法写错了。可以采用两个加速技巧:一是用自适应惩罚参数,在残差下降慢时适当增大ρ;二是采用“过松弛”技术,在更新辅助变量时引入一个松弛因子α(典型取值1.0到1.8),公式是:
Pij^(k+1)(t) = Pij^(k)(t) + α·(Pij,avg^(k)(t) - Pij^(k)(t))
实际测试下来,取α=1.3到1.5时,收敛速度能提升30%到60%,但过松弛过大时会重新引入振荡,需要配合残差曲线观察调整。
7. 如何把代码改造成自己的版本,以及后续扩展方向
7.1 改造建议:从固定场景到完全参数化
拿到任何一套可运行的代码,我的建议是不要直接拿过来跑出图就完事,而是按下面三步去改造,直到这套代码变成了你自己的工具。
第一步,把所有数值写进参数文件。把产消者数量、拓扑结构、光伏容量、储能参数、电价曲线、惩罚参数ρ、收敛阈值等全部参数化,改成一个数据结构参数,这样换一套数据不用动算法逻辑。
第二步,把单时段模型扩展到多时段滚动。目前大家拿到的大多数基础版本都是单日静态优化:输入一天的预测曲线,得到一天的调度方案。实际应用中,光照和负荷预测误差是很大的,更稳健的做法是采用模型预测控制(MPC)的方式:每个时段滚动更新一次预测、求解一次未来24小时的博弈均衡,但只执行当前时段的决策。这样系统对突发天气变化的适应性大幅提升。
第三步,把确定性模型升级为鲁棒或随机优化。光伏出力的随机性是分布式能源系统的核心痛点之一。一个简单有效的升级方案是把光伏预测曲线替换成多个典型场景(比如晴、多云、阴雨三种),每个场景赋予概率,然后目标函数变成期望成本最小化,约束仍然满足所有场景下的物理限制。这种随机规划模型和ADMM的框架结合得很好,只是子问题的规模会增大几倍,收敛时间相应变长。
7.2 可以做的扩展方向
这个题目的框架其实非常灵活,稍微改动就可以延伸出很多有价值的子方向,这里给出三个我认为工程价值最大的:
一是引入电动汽车作为移动储能。电动汽车本身就是一个可移动的储能单元,接入微网后既可能是负荷也可能是电源,它的充放电决策与出行需求强耦合。在博弈模型里,把电动汽车的充电需求和SOC约束加入产消者的约束集,交易场景的复杂度明显提升,但仿真难度也更大,适合作为进阶方向。
二是加入网损和电压约束。目前的前述模型默认交易只涉及有功功率且不考虑网络拓扑损耗,这在台区级小范围场景下可以接受。但如果你面向的是馈线级或中压配电网场景,就必须加入潮流约束,或者至少用线性化的DistFlow模型计算网损,然后按潮流结果修正节点边际电价。这一步会显著增强研究的工程价值。
三是与强化学习结合做智能报价。前面讲到交易电价是博弈的内生变量,通常用固定规则或简单动态调整机制。能不能让每个产消者学一个报价策略,通过学习历史交易数据,自动找到对自己最有利的报价策略?这个方向如果用深度强化学习来做,就是目前学界和工业界都很感兴趣的多智能体能量管理问题。你可以把ADMM求得的均衡价格作为基准,用多智能体强化学习去逼近它,然后对比逼近效果。
7.3 我个人的一点编程经验
最后分享几个我在写这类代码时积累的操作习惯,虽然不是高深的理论,但能帮你少走弯路:
第一,写代码之前先用手算一个最简单的小规模算例。取2个产消者、1个小时段,把光伏、负荷、储能全部设成常数,手算或者用Excel算出期望的交易量和均衡电价,然后用你的代码跑同样的小算例对照。这一步看起来花时间,实际上能帮你排查掉90%的潜在模型错误。
第二,在ADMM迭代循环里加入可视化调试。每迭代10次就画一次当前交易量的散点图,如果看到交易量在两个值之间来回跳,基本可以确定是参数振荡;如果交易量单调缓慢变化,那可能是惩罚参数过小。可视化调试效率远比打印几十行数值高得多。
第三,对代码里的每个符号约定,写注释时标明物理方向。比如trade(i,j,t)>0表示i从j买入。这种注释能极大减少自己改代码时栽跟头的次数,尤其是当你隔了一个月再回头看自己代码的时候。
这个方向的研究这几年发展非常快,从基本的博弈建模到分布式算法求解,再到与深度学习的结合,每一步都有大量值得深挖的空间。核心还是先把尽可能简单的博弈均衡模型跑通、吃透,再逐步添加随机性、网络约束和智能决策的元素。希望这篇文章能成为你入坑这个方向的一块垫脚石,在Matlab里把第一版仿真代码跑起来。