1. 问题从哪来:配电网里的“产消者”为什么需要P2P交易
先说结论:双碳目标之下,分布式光伏、户用储能、电动车充电桩大规模接入配电网,越来越多的用户从单纯的“用电户”变成了“既能发电又能用电”的角色,行业里叫“产消者”(prosumer)。当同一台区下的多个产消者希望绕过售电公司、直接私下交易电力时,就出现了点对点(P2P)能源交易。这件事听起来很美,落地时却有一个绕不开的硬骨头:物理上电力还是得走配电网的线路,线损、容量占用、电压支撑这些成本,总得有人买单——这就是过网费分摊问题。
我接触这个方向时,最先感到困惑的并不是优化算法本身,而是“谁来分摊过网费”这个看似简单的问题。传统电力市场里,过网费是电网公司向发电侧和用电侧收取的输配电价,结算关系是“电网—用户”一对一。可一旦用户之间可以直接交易,原来清晰的结算路径就断了:A卖给B一度电,电力可能从A的屋顶光伏先倒送台区变压器,再流到B家里,这中间每一段线路都产生了成本,但A和B都不觉得自己该多付钱。更麻烦的是,P2P交易量越大,电网原有的收入池越被分流,过网费问题不解决,电网公司根本没有动力支持这种交易模式。
于是,学术界和工程界形成了一个主流解法:把过网费分摊建模成分布式优化问题的一部分,让每个产消者在追求自身收益最大化的同时,自觉承担一部分网络成本。这就引出了本文的核心工作——用MATLAB实现多产消者P2P能源交易的分布式优化,并把过网费分摊集成进迭代框架。适合的人有三类:一是在读研究生,课题方向是配电网分布式交易或电力市场出清;二是电网公司或售电公司的技术人员,需要评估P2P交易对输配电成本回收的影响;三是对分布式优化感兴趣、想找一个真实工程案例练手的朋友。
后面的内容,我会先拆解这个问题的建模思路,再讲为什么选分布式优化而不是集中式,然后给出MATLAB的完整实现框架和关键代码,最后分享我在调参和排查错误过程中踩过的坑。代码逻辑基于常见学术框架补全,参数也已按典型场景预设,你可以直接跑通后替换成本地数据。
2. 模型怎么建:目标函数、约束条件与过网费分摊的三层结构
2.1 产消者个体模型:先把自己管好
在设计分布式优化前,先要定义清楚单个产消者的决策模型。我这里把产消者建模成一个“具备光伏+储能+柔性负荷”的微型能源站,在一天96个时段(15分钟一个点)内做日前调度。决策变量包括:储能充放电功率、向其他产消者的购售电功率、从电网买电功率、向电网卖电功率,以及可平移负荷的启停时段。
目标函数是个体收益最大化,收益来源包括:向其他产消者售电的收入、向电网卖电的收入(如果有余电上网政策);成本项包括:从其他产消者购电的费用、从电网买电的费用、储能充放电退化成本、负荷平移带来的舒适度补偿。用数学语言说,每个产消者i的优化问题可以写成:
min sum( c_grid_buy * P_grid_buy(t) + c_p2p_buy * P_p2p_buy(t) + c_degrade * (P_ch^2 + P_dis^2) + c_shfit * delta_load(t) - c_grid_sell * P_grid_sell(t) - c_p2p_sell * P_p2p_sell(t) ) s.t. 功率平衡、储能SOC动态、购售电上下限、P2P交易量上下限这里“从电网买电”和“向电网卖电”在现货分时电价下往往是不同价格,而P2P交易价格则由分布式优化中迭代协商出来。在首个迭代步,P2P电价可以先取电网购电价和售电价的中值作为初值。
2.2 网络层面模型:过网费不能拍脑袋分摊
如果完全忽略电网物理约束,P2P交易就成了纯粹的“账本游戏”,这在工程上不可接受。所以要引入过网费分摊机制。我把过网费拆成三部分:
- 电量费用:按实际交换电量分摊,适用于线损相关成本;
- 容量费用:按最大申报交换功率分摊,适用于变压器容量占用成本;
- 阻塞费用:按支路潮流越限程度分摊,适用于局部线路拥挤成本。
分摊方法我采用的是比例分摊法加迭代修正:先按过网电量比例预分摊,再引入“对网络损耗的边际贡献”做二次修正。后者用Shapley值近似实现,但因为Shapley值计算复杂度随参与者数量指数增长,实际程序里我用的是基于支路潮流灵敏度的近似因子来替代,既能反映物理潮流方向,又不会让计算时间爆炸。
这里有一个关键取舍:为什么不用纯Shapley值?我的实测经验是,4个产消者的Shapley值可以用组合枚举算,8个就慢得没法迭代了。而灵敏度近似法基于直流潮流的转移分布因子(PTDF),计算量小,且物理意义清晰——某条交易路径对某条线路的占用程度越高,分摊到这条路径上的过网费越多,这符合“谁使用、谁付费”的原则。
2.3 三层优化框架:博弈论视角下的“各退一步”
整个分布式优化可以理解为一个三层结构:
- 上层:配电网运营商(DSO)发布过网费价格信号,更新网损和阻塞信息;
- 中层:产消者之间通过P2P交易协商,交换购售电量和价格意愿;
- 下层:每个产消者独立求解自己的局部优化问题。
三层之间不断迭代,直到收敛。这个结构的好处是:个体不需要向任何人暴露自己的全部用电曲线和光伏出力数据——只需要公开愿意在某个时段以什么价格买多少电、卖多少电,隐私保护效果远好于集中式优化。同时网络运营商不干预具体交易,只负责核算过网费,政策上更容易被各方接受。
我用一个4节点辐射状配电网作为演示案例,节点间线路参数取典型值,并在节点1挂一个上级电网等效电源。这个拓扑虽然简单,但能完整体现“网损分摊+阻塞分摊+交易协商”三者之间的耦合关系。
3. 为什么选分布式优化:集中式做得好好的,非要多此一举吗
这大概是所有刚接触这个方向的人都会问的问题。集中式优化,也就是把所有产消者的数据汇集到调度中心,统一求解一个全局优化问题,理论上能得到全局最优解,计算也不复杂——一个线性规划或二次规划就能搞定。那为什么P2P交易场景非要绕个弯,做分布式?
第一个原因是数据隐私和商业保密。产消者之间的电量交易本质上是一种商业行为,没有哪家公司愿意把自己的负荷曲线、光伏出力、储能容量这些核心数据交给第三方。集中式优化要求“全部数据上传”,这在有的示范项目里推不动,原因不在技术,而在信任。分布式优化通过迭代交换“边界信息”——比如购售电量、边际价格——实现隐私保护,各方只把愿意公开的信息放出来。
第二个原因是计算和通信的分布式控制架构天然适配。将来P2P交易的规模可能扩展到成百上千个节点,一台中心服务器处理上千个产消者的实时决策,通信带宽和计算时延都会成为瓶颈。而分布式算法天然把一个大规模问题分解成若干个小规模子问题,每个产消者只需和相邻节点交换少量信息,就像互联网中的路由协议一样——不是中心节点掌握了所有路径,而是每个路由器只和邻居交换路由表,最终全网达成一致。
第三个原因是鲁棒性。集中式优化有一个致命弱点——单点故障。计算中心一旦出问题,整个市场就瘫痪。分布式优化中单个节点故障,其他节点依然可以继续迭代,系统的韧性明显更强。对于配电网这种直接关系民生的基础设施,这种故障隔离能力很重要。
当然,分布式优化也有代价。一是需要设计收敛机制,算法参数调不好可能不收敛;二是迭代得到的解通常只是次优解,和全局最优之间有间隙;三是通信环节可能引入丢包、时延、恶意节点等实际问题,需要额外设计保障机制。所以做工程实现的时候,需要针对具体场景权衡:小规模试点用集中式更省事,大规模推广才体现分布式优化的价值。
4. 分布式优化方法选型:为什么我最终选了ADMM
4.1 候选方法对比
分布式优化的经典方法有不少:对偶分解、增广拉格朗日乘子法、交替方向乘子法(ADMM)、共识算法、原始-对偶次梯度法等。我实际都写过代码对比过一轮,结论可以用一张表概括:
| 方法 | 收敛速度 | 实现难度 | 是否需要全局协调 | 适用场景 |
|---|---|---|---|---|
| 对偶分解 | 慢 | 低 | 需要主节点更新乘子 | 目标函数可分离性强的场景,对P2P价格协商支持弱 |
| 增广拉格朗日 | 快 | 中 | 需要 | 子问题强凸时效果好,但逆矩阵计算开销大 |
| ADMM | 较快 | 中 | 仅需全局求和或平均 | 适合P2P交易这种“局部变量+耦合约束”结构 |
| 共识算法 | 中等 | 中 | 需要全网一致 | 适合无中心网络,但通信轮次多 |
| 原始-对偶次梯度 | 慢 | 低 | 可不需协调者 | 凸问题收敛,但参数敏感,工程性能不稳定 |
最终定ADMM,核心原因是P2P交易问题的结构太契合ADMM的框架了:每个产消者有自己独立的决策变量(局部发电、储能、负荷、交易量),而产消者之间的耦合体现在“i卖给j的电量必须等于j从i买的电量”这一组变量一致性约束上。ADMM天然为“全局约束+局部可分离目标函数”而生,相当于棋盘上每个格子都能单独落子,规则只约束相邻格子的用量一致。
4.2 ADMM迭代公式和P2P交易映射
标准ADMM针对如下问题:
min Σ f_i(x_i) s.t. Σ A_i x_i = c在我们这里,x_i就是第i个产消者的决策变量,耦合约束就是交易对之间的购售电量平衡。引入拉格朗日乘子(对偶变量)λ后,ADMM的三步迭代为:
x_i^{k+1} = argmin f_i(x_i) + (ρ/2) || x_i - z^k + u_i^k ||^2 z^{k+1} = argmin g(z) + (ρ/2) || x^{k+1} - z + u^k ||^2 u_i^{k+1} = u_i^k + x_i^{k+1} - z_i^{k+1}其中z是全局一致性变量,可以理解为“交易中心撮合出来的参考交易量”,u是缩放对偶变量。在实际P2P交易程序里,我做了两点工程化改造:
第一,把全局一致性变量z拆成“交易对级别的共识变量”,也就是每笔双边交易的参考电量,而不是所有节点共用一个值。这样做的好处是对偶变量有明确的物理意义——它直接解释了P2P电价的调整方向:如果第k轮协商中i报的售电量大于j报的购电量,那么对偶变量上升,下一轮i会倾向于降价促进成交,j会倾向于加价提高购电量。
第二,加入动态惩罚参数 ρ。固定ρ在大多数测试场景下都能收敛,但如果产消者数量多、交易时段复杂,固定ρ的收敛速度会明显下降。我采用了残差平衡策略:原始残差大于对偶残差10倍时ρ乘以1.5,反过来时ρ除以1.5,这个技巧能让迭代次数削减30%左右。
4.3 子问题求解:每个产消者内部是什么
每个产消者的子问题本质上是一个混合整数线性规划——因为有储能和可平移负荷这类离散决策。我用YALMIP调用Gurobi求解,因为Gurobi对二次约束的处理比Cplex更稳。如果你没有商业求解器,也可以用MATLAB自带的linprog加分支定界,但求解速度会慢不少,自由度也没那么大。
实际编写中我建议把子问题封装成函数:
function [x_opt, cost_opt] = solve_prosumer_subproblem(i, lambda, z, rho, data) % 输入:产消者编号i,对偶变量lambda,共识参考量z,惩罚系数rho,系统数据data % 输出:该产消者本轮最优决策和最小化后的目标值 % 内部:定义决策变量、目标函数、约束条件,调用YALMIP+Gurobi end这样外层ADMM迭代只需要循环调用这个函数,代码结构非常清晰。我在主循环里还加了一步“信息交换代理”,把每个产消者本轮决策的购售电量广播给交易伙伴,模拟真实场景下的点对点通信。
5. MATLAB实操:从零搭起多产消者P2P交易仿真
5.1 数据准备:场景参数与产消者配置
我用4个产消者、96时段(15分钟)的经典日尺度配置作为演示,实际数据可以替换成自己台区的抄表数据。每个产消者的光伏出力曲线和负荷曲线都是从实测数据加了随机噪声生成的,噪声幅值设为5%,用来模拟预测误差。
| 节点编号 | 光伏容量/kW | 储能容量/kWh | 负荷类型 | 特征说明 |
|---|---|---|---|---|
| 1 | 8 | 20 | 居民 | 晚上用电高峰明显 |
| 2 | 12 | 30 | 商业 | 白天用电高峰明显 |
| 3 | 5 | 10 | 居民 | 光伏少,购电需求大 |
| 4 | 15 | 40 | 农业 | 白天灌溉负荷大,光伏充足 |
电网分时电价采用峰谷平三段阶梯:峰时1.2元/kWh,平时0.8元/kWh,谷时0.4元/kWh;余电上网按燃煤基准价0.45元/kWh。P2P交易电价初值设为0.6元/kWh,比电网购电价低、比余电上网价格高,这样对买卖双方都有吸引力——这也是P2P交易能发生的基本经济条件。
过网费参数方面,线路电阻、电抗、容量限值按典型中压馈线设定。为了突出分摊效果,我把节点2和节点4之间的线路容量压得比较低,故意制造一条重载支路,方便观察阻塞时过网费如何动态调整。
5.2 关键代码框架:迭代主循环与ADMM实现
下面给出主循环的核心伪代码和关键实现片段,可以直接抄进MATLAB跑通:
for k = 1:max_iter % 第一步:各产消者并行求解子问题 for i = 1:N x{i} = solve_prosumer_subproblem(i, lambda, z, rho, data); end % 第二步:更新全局共识变量z(交易撮合参考量) for pair = 1:M z{pair} = 0.5 * (x{buyer}{pair} + x{seller}{pair}); end % 第三步:更新对偶变量lambda(P2P价格信号) lambda{pair} = lambda{pair} + rho * (x{buyer}{pair} - x{seller}{pair}); % 第四步:计算原始残差和对偶残差,判断收敛 r_prim = norm(x{i} - z{i}); s_dual = norm(rho * (z{i} - z{i-1})); if r_prim < tol && s_dual < tol break; end end这里需要注意:并行求解时,每个子问题要用上一轮的z和lambda,不能用本轮已经更新的z——也就是所谓的Gauss-Seidel更新改为Jacobi更新。我在初版代码里犯过这个顺序错误,导致迭代震荡不收敛。并联产消者子问题时,建议用MATLAB的parfor配合parpool,能显著缩短仿真时间。
实际工程中,通信拓扑不一定是全连接的,可能每个产消者只允许和邻居节点交易。这种情况下,耦合约束只存在于相邻节点之间,z的更新也要相应简化。我在程序里用邻接矩阵描述交易网络,全连接和邻居连接都支持。
5.3 过网费分摊模块的嵌入方式
过网费的影响通过目标函数中的额外成本项体现,而分摊系数则放在DSO模块中更新。每轮ADMM迭代结束、购售电量基本稳定后,DSO模块做一次潮流计算,得到各支路功率,按功率比例更新分摊系数,然后重新下发到产消者子问题中。
这个机制的本质是:交易量越小、交易路径越短,分摊的过网费越少;交易量越大、路径越长,分摊越多。产消者在下一轮优化时会自然调整交易策略,倾向于选择距离更近的交易伙伴,并在交易量上更加克制——这是过网费分摊改变交易行为的直接体现。
代码实现上,我把网损分摊和阻塞分摊分别计算,最后合计到每笔P2P交易的边际成本上:
loss_alloc(i,j) = loss_total * (P_pair(i,j) / sum(P_pair)); cong_alloc(i,j) = cong_price * (PTDF(i,j) * P_pair(i,j)); fee_p2p(i,j) = loss_alloc(i,j) + cong_alloc(i,j);其中PTDF(i,j)是第i个交易对在第j条支路上的转移分布因子。这个模块虽然逻辑简单,但如果没有嵌入到迭代循环里,产消者就完全感受不到网络约束的存在,出来的交易方案在物理上根本不可行。
6. 仿真结果分析:交易、定价和过网费如何联动变化
6.1 收敛分析:ADMM迭代曲线长什么样
以4节点场景为例,设置容差为1e-4,ADMM大约在35轮迭代后收敛。原始残差和对偶残差的下降曲线呈“先快速下降、后平缓收敛”的典型特征。前5轮残差下降特别快,因为初始z和x差距大,惩罚项把决策快速拉向可行域;后面进入精细调整阶段,速度变慢。
如果改用固定ρ(ρ=1.0)对比,迭代次数大约增加50%左右,但求得的最终目标函数值差异不到2%。这说明动态ρ主要贡献是加速收敛,对最终结果影响很小。在实际调度场景中,如果通信轮次受限,可以考虑牺牲少量精度换取更快的收敛。
6.2 交易结果:谁在买,谁在卖,价格如何
从交易结果看,节点3(光伏少、负荷高)是净购电方,节点4(光伏多且负荷充足)是净售电方。P2P交易电价最终收敛在0.5元/kWh到0.7元/kWh之间的区间,分时段差异明显——白天光伏大发时段,P2P电价压低到接近余电上网价格;晚间负荷高峰期,P2P电价拉高到接近电网购电价。
这验证了一个直观认知:P2P交易价格并不是固定的,它是供需关系在分布式迭代中自发涌现的结果。ADMM的对偶变量天然给了这个价格一个“演化路径”,而不是人为指定一个固定值。
对比集中式最优解,P2P场景下总社会福利(所有产消者目标函数之和)比集中式低约4.7%。这个差距的来源主要是分布式决策的信息不完全——每个产消者只知道自己的局部信息和通过迭代获得的邻居信息,无法像集中式那样全局统筹。行业里把这个差距称为“分布式优化的价格”,可接受范围通常在5%以内。
6.3 过网费分摊效果:阻塞线路定价更贵,交易路径被优化
加入过网费分摊模块后,仿真结果里有一个非常清晰的信号:原本通过重载支路的跨节点交易量明显下降,而相邻节点之间的本地交易量上升。以节点2和节点4之间那条限载线路为例,未分摊过网费时,节点4向节点2售电约80 kWh/天;分摊过网费后,这个数字降到约55 kWh/天,降幅约31%。
这是因为过网费动态调整使跨支路交易的经济优势被削弱,产消者自发把交易转向本地。这种“自组织”的调度行为,正是过网费分摊希望看到的:不需要电网公司强制限电或说服用户,通过价格信号就能重塑交易模式,同时降低网损和阻塞。
从费用回收角度看,仿真模拟的过网费收入可以覆盖80%以上的配电网固定成本和线损成本,剩余部分仍需按容量电价或政府性基金收取,这个比例和实际工程目标基本吻合。
7. 常见问题与排查技巧实录
7.1 不收敛或收敛极慢
这是P2P交易仿真里最常见的坑。我的排查顺序是:先看原始残差和对偶残差的曲线形态。如果两个残差都在下降但幅度很小,大概率是ρ设置不合理,尝试把ρ调大10倍。如果残差出现震荡,先检查代码里是否用了本轮更新的z去解子问题——这个先后顺序错误是震荡的头号原因。还有一个容易被忽略的原因:数据量纲差距太大。比如电量在kW级别、成本在元级别、对偶变量在元/kWh级别,三者数量级相差超过上百倍时,求解器内部数值稳定性会下降。解法是先统一单位,全部折算到kW和元的基础上。
7.2 求解器报“Infeasible Problem”
子问题不可行,绝大多数情况下是约束条件之间产生了冲突。我遇到过的典型情况是:储能SOC上下限和功率平衡约束冲突,尤其在光伏出力很高的中午,储能又不能充电、负荷又不高、P2P售电量又有上限,导致功率平衡无法满足。解法是在功率平衡约束里加入“弃光变量”和“切负荷变量”,并给它们设置很高的罚因子。这样数学模型上永远可行,实际效果上也会尽量少弃光、少切负荷。
7.3 过网费分摊后总费用不等于个体费用之和
这意味着程序里的分配比例没有归一化。比例分摊法的关键是各分摊项系数之和必须等于1,我在第一版实现时因为PTDF矩阵各元素直接乘了交易电量,忘了归一化,导致“凭空多算”或“凭空少算”了过网费。排查办法很简单:跑一轮纯网损分摊,检查所有产消者分摊的过网费之和是否等于潮流计算得到的全网网损费用,如果有偏差,去检查归一化系数。
7.4 P2P交易价格出现负值
价格迭代中出现负值,说明对偶变量发散,通常和子问题求解不稳定有关。我在Gurobi求解时设置了数值精度过高的参数(默认方法),在某些边界条件下求解器返回了次优解或不可行解,导致对偶更新方向错误。解决方法:给P2P电价加一个“价格保护区”,比如限制在0.1元/kWh到1.5元/kWh之间,本质上是一个投影操作,可以防止数值异常污染后续迭代。从算法理论角度看,这是把无约束对偶更新变成投影对偶更新,不改变收敛性前提,但大幅提升工程鲁棒性。
7.5 仿真时间太长
全连接4个节点96时段的仿真在我的测试机器上大约运行40秒,其中Gurobi求解子问题占了90%以上时间。如果扩展到30个节点,仿真时间会呈线性增长到5分钟左右,还算可接受。如果要做上百节点的仿真,建议从两方面优化:一是用parfor并行求解子问题;二是给子问题设置求解时间上限(例如2秒),并打开求解器的MIP gap容忍度(例如0.5%),这样能在精度几乎不变的前提下将总仿真时间压缩一半以上。
8. 一些个人的老实话
前面这些内容看起来是一套完整的P2P能源交易分布式优化框架,但我实际做下来最大的体会是:算法模型能不能跑通是一回事,能不能被工程接受是另一回事。ADMM迭代出的P2P电价虽然理论上能让买卖双方都获益,但真实用户并不关心什么对偶变量、什么残差收敛,他们只关心账单上这个月省了多少钱,以及自己家里的空调有没有被远程控制。
另外,过网费分摊这件事,工程上远比学术模型复杂。真实的输配电价体系里有容量电价、电量电价、政府性基金、交叉补贴等一大堆历史遗留包袱,单纯按边际成本分摊很难落地。我在仿真中用的比例分摊+PTDF修正只是一个“足够公平且计算可行”的折中,但它已经能够展示出价格信号对交易行为的修正作用,对于示范项目的前期论证是够用的。
如果你想把这套代码用到自己的课题或项目里,我建议从三个方向做扩展:一是把单时段静态模型扩展为多时段滚动优化,考虑实时预测误差和更真实的通信延迟;二是引入多主体博弈框架,让产消者在迭代中不仅追求自身收益最大化,还能通过策略性报价影响P2P价格;三是把配电网三相不平衡约束加进来,这在低压台区尤其重要,也是目前学术界比较活跃的方向。
最后分享一个小技巧:调试ADMM时,每次迭代都把残差、对偶变量、交易量存成MAT文件,收敛后可以反复复盘,观察是哪一笔交易、哪一条支路在阻碍收敛。很多时候,算法层面的“拉锯战”反映的正是物理场景里供需矛盾最尖锐的地方——这些信息比最终收敛结果更有价值。
打住,思路就说到这儿,剩下的是代码和调参的事了。