
做这个课题的原始动机其实来自一个很朴素的困惑当几十个屋顶光伏用户在同一片配电网里互相买电卖电每一笔电费单上除了电量费到底应该为电网付多少钱怎么付才公平多产消者点对点能源交易听起来是纯粹的市场行为可一旦加上过网费用分摊这个约束事情立刻从单纯的供需匹配升级成一个需要分布式优化的系统性课题。我在MATLAB里折腾了几个版本的模型从两节点的玩具网络一路做到带光伏和储能的上百个节点的算例最大的感受是这个问题的难点不在算法库调用而在于把用户隐私电网公平市场效率三个目标塞进同一个目标函数还要保证能收敛到有意义的解。这篇文章主要写给正在研究配电网P2P交易、分布式优化算法的研究生以及想评估分布式能源落地机制的工程师。读完你会得到一个可以在MATLAB里直接改着用的ADMM求解框架以及一套把过网费用动态分摊嵌入迭代过程的完整方案。下面按我的踩坑顺序来。1. 项目背景与研究动机1.1 多产消者点对点交易为何值得做产消者这个词在能源圈已经不算新鲜屋顶光伏、家用储能、电动汽车充放电让普通用户第一次从被动的负荷变成同时能发能用的节点。我见过最典型的场景是一栋办公楼装了几百千瓦光伏周末没人上班光伏出力全部倒送同一台区里的几家小商户周末正好满负荷运转。如果没有点对点交易办公楼只能拿一个可怜的上网电价小商户则要按零售电价买电两者的价差被配电公司拿走买卖双方都没有议价能力。P2P交易的价值恰恰是把这部分被中间环节吃掉的价差重新分配。它不需要高深的区块链技术也不需要复杂的电力市场牌照本质就是在满足网络约束的前提下让买卖双方直接商量价格。文献和试点里最常见的目标函数是最大化所有产消者的社会福利也就是让总效用减去总成本最划算。但这里必须小心一个陷阱如果不考虑电能流经公共网络的代价优化结果会把交易量推向完全脱离物理现实的极端——原本为了消纳光伏而设计的交易反而会造成大量的网络潮流积压。我在实际建模仿真中发现很多初次接触这个课题的人会急着上分布式算法却忽略了最上游的物理约束。回头看你为什么要进行P2P交易是为了减少弃光、提升自消纳、降低网损最后才是用户收益。如果优化出来的交易计划让某条线路过载那这个计划再经济也是废纸。所以模型里必须有潮流约束或至少线路容量约束这正是后文要重点展开的部分。1.2 过网费用分摊为什么是个坎过网费在现实账单里通常是一笔按时段或按容量的固定费用目的是覆盖电网的固定成本、线损和辅助服务。P2P交易出现后问题变得微妙两个用户之间签了一笔电能量合同但传输路径上所有线路容量、损耗成本都没有体现在合同里。如果这笔钱不付电网运营者的固定成本回收不足如果要求每笔交易都付一大笔过网费P2P的经济性又荡然无存。所以分摊比一刀切定价更合适——总费用是确定的关键是怎么在各产消者的交易电量之间公平地摊。直觉上最简单的分摊是按交易电量比例摊但实测下来公平性很差两个隔着远距离的用户交易电量和两个紧挨着的用户相同时前者占用的线路资源明显更多按电量摊就等于让相邻用户补贴远程用户。按交易距离加权会合理一些但距离在环形网络或含有分布式电源的配电台区里并不是一个清晰的概念。更本质的做法是回到潮流本身看每笔交易对线路上实际潮流的边际贡献。这就引出了Shapley值一类博弈论工具但Shapley值在产消者数量超过十几个时计算量会指数增长必须做近似。所以过网费用分摊在数学上和优化模型是嵌套关系一方面分摊结果依赖交易量另一方面交易量又受分摊费率影响。正是因为这种耦合关系才需要设计迭代框架而非一次性求解。后面第四章我会专门讲这个耦合怎么处理。1.3 为什么非用分布式优化不可模型建出来第一时间想到的解法往往是集中式求解把所有产消者的成本函数、光伏出力、用电意愿收集到一个中心节点用求解器一次把全局最优解算出来。我一开始就是这么干的直到面对三个现实问题才转向分布式。第一个是隐私。产消者不愿意把自己的完整用电曲线、储能荷电状态、成本参数都交给别人这在商业化运营场景里是红线。第二个是可扩展性。集中式问题规模随产消者数量非线性增长几十个节点还行几百个节点带储能与多时段的混合整数问题常规求解器会非常吃力。第三个是市场机制的自治性。P2P的核心理念是去中心撮合每个用户应该拥有独立决策权而不是被动接受中央调度给出的交易计划。分布式优化的思路是把大问题分解成若干个只和单个产消者相关的子问题子问题之间通过交换少量边界信息来达成一致。应用最广泛的算法是交替方向乘子法ADMM它把全局一致的目标拆成一个带惩罚项的局部问题序列。表1是我自己做的集中式和ADMM分布式在几个维度上的对比供参考。维度集中式ADMM分布式隐私暴露所有参数汇总到中心只交换交易量和价格信息可扩展性几十节点以下尚可可到上百节点全局最优性精确全局最优收敛后近似全局最优对通信的依赖单向收集多轮双向迭代实现复杂程度简单需要调步长和残差在实际算例里ADMM收敛后的目标值通常与集中式解差距在1%以内对于市场结算场景完全可以接受。下面进入模型建立。2. 模型建立产消者、网络与成本函数的数学表达2.1 个体产消者的成本与效用函数先定义基础要素。设配电网有N个节点每个节点对应一个产消者集合记为{1,2,...,N}。调度周期划分为T个时段比如一天24小时或更细的15分钟间隔。每个产消者i在时段t内有本地负荷d(i,t)、光伏出力p(i,t)^pv、储能充放电功率p(i,t)^ch和p(i,t)^dis。储能荷电状态E(i,t)按如下递推关系变化E(i,t1) E(i,t) eta_ch * p(i,t)^ch - p(i,t)^dis / eta_dis其中eta_ch和eta_dis是充放电效率。储能的约束包括容量上下限、充放电功率上限以及不能同时充放电这些在子问题里都会以线性不等式出现。产消者的目标函数由三部分组成本地用能的效用函数、购电成本/售电收益、以及过网费分摊。为了获得凸的光滑目标常用二次效用函数来表示用户对电能消费的满意程度比如对净负荷用电量L(i,t)使用函数U_i(L) alpha_i * L - 0.5 * beta_i * L^2其中alpha_i和beta_i是偏好参数。对光伏和储能生产者成本函数可以写成C_i(g) a_i * g^2 b_i * g其中g是实际出力。把这些东西组合起来单个产消者的局部目标函数就是min sum_t [ C_i(p(i,t)) - U_i(L(i,t)) 过网费分摊项 ]这里p(i,t)是节点i与配电网交换的总功率或者等价地是交易矩阵汇总后的净注入。注意这样定义的局部目标里还包含与其他产消者的耦合项交易变量耦合正是需要通过ADMM拆开的。2.2 P2P交易约束与网络拓扑点对点交易用矩阵T(i,j,t)表示t时段内节点i从节点j购买的电量默认非负且T(i,j,t)与T(j,i,t)不能同时为正。如果定义净交易量x(i,j,t) T(i,j,t) - T(j,i,t)那么满足反对称关系x(i,j,t) -x(j,i,t)。任意节点i的功率平衡可以写成sum_j x(i,j,t) p(i,t) L(i,t)左侧是与邻居交易和与上级电网的交换右侧是本地净负荷。如果配电网是辐射状线路潮流可以用DistFlow方程描述。DistFlow的核心是支路末端的有功功率等于下游所有节点的有功注入代数和支路电压降由有功功率、无功功率和电阻电抗决定。在P2P仿真里如果重点研究费用分摊和交易量可以忽略无功只保留P_line(l,t) sum_{节点k在下游} p(k,t)再叠加线路容量约束|P_line| 容量上限。这一步务必加上否则过网费分摊的成本映射就失去了物理依据。网络拓扑还决定了过网费分摊的分母。比如某条线路被多个用户的交易量共同占用用户对这条线路的占用权重怎么算我在模型里采用交易路径分解对每一对交易对(i,j)按照它在原有网络路径中的功率分配因子把交易量分配到各条线路上。这样每条线路的流量可以分解为各交易对的贡献之和分摊就有了清晰的对象。2.3 过网费用分摊模型过网费分摊的目标是把电网运营者的一笔总额C_grid可包含折旧、运维、线损等固定项按谁占用、占用多少分配到每个产消者。最简单的机制是固定费率法每个产消者按净购电量支付过网费费率由总额除以总购电量得到。这种办法实现简单但对自消纳率低、交易路径长的用户明显不公平。我在课题里对比了三种分摊方案方案一固定费率分摊。把总过网费按各节点净购电量比例分摊每度电费率相同。优点是简单缺点是忽略空间差异。方案二距离加权分摊。每一对交易的电量乘以该交易对在网络中的电气距离加权线长或阻抗再归一化分摊。优点是比方案一公平但电气距离在含分布式电源的配网里计算麻烦且对环网不友好。方案三潮流边际分摊。先求解得到交易矩阵再计算每对交易在各线路上的潮流贡献按贡献比例把线路成本分摊到交易对最后归集到节点。方案三的物理意义最清晰也是我在最终模型里采用的。它的数学形式是给每个交易对(x(i,j,t))分配一个动态费率lambda(i,j,t)该费率依赖所有线路的影子价格和功率分配因子。到这里过网费分摊项就可以写进目标函数了sum_t sum_{i,j} lambda(i,j,t) * |x(i,j,t)| / 2绝对值是因为交易对的总过网费对买卖双方都产生影响除以2避免重复计算。lambda越大说明这条交易路径占用的网络资源越多优化就会倾向于减少远程交易代之以本地交易或储能调节。这正是我们想要的价格信号。3. 分布式求解ADMM在MATLAB中的落地实现3.1 为什么选ADMMADMM不是唯一的分布式优化工具还有梯度投影、对偶分解等方法。我选ADMM主要因为三点第一它在凸问题上保证收敛到全局最优这对目标函数里二次项较多的场景很友好第二允许每个产消者保留独立的子问题子问题甚至可以交给不同的求解器解耦合只通过乘数迭代体现第三工程上对参数rho的选择没那么敏感不像对偶分解那样容易出现振荡。当然ADMM也有代价它需要多轮迭代每轮每个节点都要参与计算和通信而且子问题必须求到足够精度否则整体收敛会变慢。在我测过的算例里如果子问题用求解器求解精度设到1e-6ADMM主循环通常50到200步可以收敛如果子问题精度放宽到1e-3主循环次数会明显增加甚至出现平台期。这个权衡在写代码时要注意。3.2 问题重构与对偶变量更新把模型转换成ADMM形式的关键是把交易矩阵从局部变量提升为全局一致性变量。具体做法是定义局部交易变量x(i,j,t)在每个节点i侧都能自主决策但要求任意交易对的双方最终对本笔交易电量达成一致。引入辅助变量z(j,i,t)表示节点j视角下接受的交易量于是加约束x(i,j,t) z(j,i,t) 0。这样局部问题只和自身的成本函数、本地潮流约束相关全局一致性约束通过拉格朗日乘子松弛。带惩罚项的增广拉格朗日函数可以写成L sum_i f_i(x_i) sum_{(i,j)} [ y(i,j) * (x(i,j) - z(i,j)) (rho/2) * (x(i,j) - z(i,j))^2 ]其中y(i,j)是拉格朗日乘子rho是惩罚参数。ADMM迭代分三步第一步所有节点并行求解各自的局部子问题把y和z固定为上一轮值子问题i: min f_i(x_i) sum_j [ y(i,j)x(i,j) (rho/2)(x(i,j)-z(i,j))^2 ]第二步更新一致性变量z。对每一对交易对取两个局部变量与乘子的平均并利用反对称关系强制z(i,j) -z(j,i)z(i,j) ( x(i,j) - x(j,i) ) / 2值得注意的是这一步可以直接通过反对称平均完成不需要复杂的协调器这也是ADMM在P2P场景下特别方便的原因之一。第三步更新拉格朗日乘子y(i,j) y(i,j) rho * ( x(i,j) - z(i,j) )停止准则用原始残差r_prim ||x_i - z||和对偶残差r_dual rho * ||z - z_old||两者都小于容忍度时判收敛。这个准则要同时看只看原始残差容易漏掉对偶不收敛的情况。3.3 MATLAB代码框架与关键函数下面给一个我在MATLAB里常用的ADMM主循环框架去掉了一大堆业务细节保留最核心的结构。变量说明X是N×N×T的交易矩阵Z是辅助变量Y是对偶变量local_solve函数返回每个产消者的局部解。function [X, Z, Y, hist] admm_p2p_solver(N, params) % 初始化 X zeros(N,N,params.T); Z zeros(N,N,params.T); Y zeros(N,N,params.T); rho params.rho; % 惩罚参数 tol params.tol; % 容忍度 maxIter params.maxIter; for k 1:maxIter Z_old Z; % 第一步并行求解局部子问题 % 对每个产消者i考虑与其相连的交易变量 parfor i 1:N X(i,:,:) local_solve(i, Z, Y, rho, params); % local_solve 内部解 min f_i y*x (rho/2)*||x-z||^2 end % 第二步更新一致性变量反对称平均 Z 0.5 * (X - permute(X, [2 1 3])); % 如果希望得到i从j购买电量的非负表示可在后处理里转换 % 第三步更新对偶变量 Y Y rho * (X - Z); % 残差与收敛判断 r_prim norm(X(:) - Z(:), 2); r_dual rho * norm(Z(:) - Z_old(:), 2); hist.r_prim(k) r_prim; hist.r_dual(k) r_dual; if max(r_prim, r_dual) tol break; end end end关键点在local_solve它返回的不是某个数值而是节点i所有相关联交易变量的完整向量。在我的实现里local_solve内部用quadprog求解目标函数是二次成本项加ADMM增广项约束是节点功率平衡、储能递推和线路容量。如果目标函数里包含过网费项过网费费率lambda会在每一步传入local_solve形成动态费率下的局部优化。有一个容易被忽略的细节交易矩阵的索引方向。很多刚上手的人会把X(i,j,t)定义成节点i卖给节点j的功率结果对称性处理一团乱。建议统一成节点i从节点j买入的功率这样反对称约束自然成立后处理也直观。4. 过网费用分摊的算法融合与迭代耦合4.1 从优化结果到分摊结果的映射ADMM收敛后得到的是每个时段每个交易对的成交量。要得到过网费分摊需要把这些交易量映射到线路潮流上。对辐射状配网功率分配因子其实可以预先计算每条线路的潮流由下游所有节点的净注入代数相加。因此不需要重新做潮流计算只需要按拓扑遍历即可算出P_line(l,t)。有了线路潮流就可以算每条线路的边际成本或影子价格。如果过网费总额是固定的那么把C_grid按线路潮流比例分配到各线路再把线路成本按功率分配因子分摊到交易对公式如下cost_of_pair(i,j,t) sum_l ( C_grid_l * |contribution(i,j,t,l)| / sum_{(a,b)} |contribution(a,b,t,l)| )其中contribution(i,j,t,l)表示交易对(i,j)在t时段对线路l潮流的贡献可用功率分配因子乘以交易量近似得到。把所有线路的贡献加总就是该交易对应承担的过网费。这个映射做完以后如果把lambda(i,j,t)固定下来ADMM的下一轮才算是考虑过网费的完整优化。于是有两种做法。4.2 两层迭代分摊费率的固定点更新第一种做法很直接把分摊模块放在ADMM主循环之外。先运行一次不含过网费的ADMM得到初始交易矩阵计算过网费分摊得到动态费率把这些费率代入目标函数重新运行ADMM反复进行直到费率变化小于阈值。这就是一个固定点迭代。固定点迭代的收敛性并非自动成立费率对交易量过于敏感时可能振荡。我在实验里遇到过费率在两个值之间来回跳的情况原因是某条线路在两个产消者之间只差一点就能越限导致线路影子价格剧烈波动。解决办法有两个一是对费率更新做阻尼每次只更新20%到50%二是对线路潮流做松弛处理让影子价格随潮流连续变化而不是硬性阶梯。第二种做法是把边际成本直接以影子价格形式嵌入ADMM的局部目标函数做成单层耦合。这在凸优化框架下更优雅但要求子问题能够接受任意凸的过网费函数否则还是要回退到外层迭代。从工程稳定性看我个人建议先实现两层迭代等跑通跑稳了再去考虑单层耦合的改进。4.3 仿真对比采用与不采用分摊的差异我在一个50节点、24时段的模拟台区上做过对比实验。场景是每节点带光伏、随机负荷和一部分储能。比较三种方案结果如表2。指标方案A忽略过网费方案B固定费率0.02元/kWh方案C潮流动态分摊系统社会福利元/天123401189012020平均用户收益元/户/天78.265.472.8线路网损kWh/天312286271远距离交易占比高中低价格信号清晰度无弱强方案A忽略过网费时社会福利最高但这只是假象有大量远程交易在占用线路资源网损也最高电网运营者几乎收不回固定成本。方案B用统一费率压制了总交易量社会福利下降最多用户收益被无差别分摊拖累。方案C把费率集中在真正占用网络的远程和高损耗交易对上社会福利介于两者之间但网损最低且用户收益下降幅度比固定费率方案小得多——因为它惩罚的是该惩罚的人。这个对比想说明一个核心理念过网费分摊不是简单的成本回收而是通过价格信号引导交易行为。动态分摊方案把网络稀缺性显式写进了每个产消者的目标函数用户会自发减少无谓的远程交易更多转向本地消纳、储能调节和时段平移整体网络效率自然提上来。5. 参数设置、收敛调参与常见问题排查5.1 关键参数与收敛性调参参数rho是ADMM里最敏感的一个。rho太小约束惩罚弱两个节点对同一笔交易的预期电量长期不一致原始残差迟迟压不下去rho太大一致性约束被加强但目标函数项相对被淹没对偶残差可能振荡。我在实践中通常先取rho0.1然后观察残差曲线如果原始残差下降很慢甚至有平台期就把rho调大2到5倍如果对偶残差大幅波动就把rho调小一半。其他参数也影响收敛。子问题求解精度建议设为1e-6至少不能低于1e-4。初始点不用太讲究交易量都置零就能跑起来但如果想让收敛更快可以用一次直流潮流结果作为初始交易量。迭代次数上限我习惯设500步理论上足够若超过还没收敛问题多半在阶梯电价或二进制变量上而不是ADMM本身。还有一个实操技巧把不同量纲的变量归一化。交易电量动辄几百kWh储能SOC是0到1如果混进同一个残差计算规范化的残差会失真。我在计算残差时没有简单用2范数而是除以各自变量范围的均值再求无穷范数。这个改动看似不起眼却避免了残差下降但解并不可用的假收敛。5.2 常见问题和解决实录我在调试时踩过不少坑整理成速查表供参考。问题现象可能原因解决办法原始残差不下降rho太小增大rho或者检查子问题求解精度对偶残差振荡rho太大减小rho或对费率更新加阻尼交易矩阵不对称索引方向定义混乱强制X(i,j)-X(j,i)并在每一步更新后做反对称投影过网费分摊出现负值线路影子价格映射错误检查功率分配因子矩阵确认贡献符号子问题求解时间过长二次规划精度过高降低求解精度到1e-5或换active-set算法某时段交易量异常大光伏尖峰导致储能满给储能SOC加软约束或增加可售上限最常见的坑其实是倒数第三个功率分配因子的符号。我用一个开源配电网算例测试时第一次计算出来的分摊结果里有一半节点的过网费是负的查了很久才发现是下游节点集合的遍历方向写反了潮流贡献的正负号整体取反。这个错误在集中式方案里不会被发现因为总过网费不变但分摊到各节点后就全乱套了。所以验证过网费分摊结果时一定要先检查两个基本量所有节点的分摊费用之和等于总额C_grid负的分摊只允许在注入网络并减少流动这种特殊情况下出现。5.3 实操心得与避坑做这个课题最想分享的经验是千万不要一上来就搭几十节点、多时段的大模型。我的流程是先造一个三节点的微型网络手动验证ADMM每步数值确认残差和交易矩阵都符合预期再加储能再加多时段最后扩展到完整台区。这样每一步的bug都能定位在一个很小的范围内否则等几百个变量混在一起排查一个符号错误可能需要好几天。第二个心得是可视化残差曲线。ADMM调试时把r_prim和r_dual画在同一张对数坐标图里观察它是单调下降还是振荡。如果出现日常下降、隔轮跳变的锯齿形基本可以确定是某个时段约束在边界上弹跳需要平滑费用函数或调整rho。这个经验救了我很多次。第三个心得是过网费分摊不能孤零零地算。很多研究把分摊从优化里剥离开先算交易再贴一张费用表看起来简单但价格信号打折了。我坚持把分摊费率反馈进下一轮ADMM得到的交易计划在网损和收益分配上都更符合直觉。哪怕用两层迭代也比完全不反馈强得多。最后再说一个小技巧输出结果时把交易矩阵按买入视角打印成热力图一眼就能看出网络有没有出现跨区倒卖的畸形交易。正常的P2P交易应该集中在相邻节点和高光伏匹配的节点之间如果热力图稀疏、没有明显的对角集中带说明价格信号还没起作用需要进一步调整过网费参数或检查约束条件。