ARTICLE DETAIL

资讯详情

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

基于价值认同的需求侧电能共享分布式交易策略ADMM实现

基于价值认同的需求侧电能共享分布式交易策略ADMM实现 做过几个分布式能源管理项目之后我发现很多人对“分布式交易策略”的理解就是把原来中心化调度的大模型拆成几个小的for循环最后再把结果拼回来。这个想法不能说错但离真正的分布式计算差得很远。这个题目里有一个非常关键的限定词——“价值认同”它决定了交易模型里不能只有金钱成本还必须包含用户的信任、偏好、绿色电力支付意愿这类软约束。加上“需求侧电能共享”基本可以判断这是一个面向园区、社区或虚拟电厂场景的多主体产消者协同优化问题。用Matlab实现的话重点不在“能算出某个结果”而在“算法结构是不是真的分布式、参数扰动后会不会崩溃”。这篇文章就围绕这个项目标题把我自己复现这类策略时的完整思路、数学模型、ADMM求解流程、Matlab代码框架、算例设计以及踩过的坑都捋一遍。如果你正在做毕业设计、想复现论文算例或者在做园区能源管理系统的原型验证那这套思路可以直接参考。1. 这个项目到底在做什么先想清楚需求和边界1.1 先给问题建立坐标系“基于价值认同的需求侧电能共享分布式交易策略”这个名字信息密度很高建议拆成三个层次去理解需求侧电能共享说的是参与主体是用户侧的资源屋顶光伏、储能、充电桩、可调负荷都算。用户之间可以直接买电卖电而不是把所有电量都交给上一级电网处理。分布式交易每个用户作为独立决策者只跟邻居或交易平台交换有限信息自己优化自己的用电和售电计划。价值认同用户不只是按电价高低做决策还会考虑电的“来源”。比如有人愿意多花一点钱买本地光伏发的绿电有人愿意在晚高峰让出空调功率换取社区整体稳定有人对隐私特别敏感不想上报完整负荷曲线。所以这不是一个普通的日前经济调度问题而是一个多代理系统的均衡问题。核心目标不是“系统总成本最低”而是“每个参与者在自己的偏好约束下都能获得好处同时整个系统达到供需平衡”。我在最初做这个项目时被问得最多的一个问题是“用户为什么不直接跟电网买电非要搞内部交易”答案其实很实际内部共享可以让光伏富余的用户以高于上网电价的价格卖电让缺电用户以低于目录电价的价格买电中间差价就是双方参与交易的动力。价值认同这个东西就是在这个差价基础上再叠加一层“偏好溢价”让部分用户愿意为清洁电力或本地属性支付额外的价格。1.2 价值认同不是心理概念是效用函数里的权重很多人听到“价值认同”会觉得这是个社会学概念没法建模。实际上在电力交易模型里它完全可以被量化成用户效用函数中的偏好参数。举个例子两个用户买同样一度电一个无所谓电从哪来一个特别希望买本地光伏电。如果系统里只有价格信号这两个人的需求没区别。但加上价值认同参数后第二个用户的效用函数里会多出一项“绿色电力满足度”。当他买到来自本地光伏的电量时会获得额外效用买不到时会产生不满足感。这个参数在数学上就是一个非负权重乘上“实际购买绿电量与期望绿电量的偏差”然后放进目标函数。具体到Matlab实现我一般会把用户的目标函数写成“用电舒适度收益售电收益价值认同收益市场购电成本”的形式。前两项是常规的经济调度目标价值认同收益则是给每个用户单独设置的。这样做的好处是不同用户对绿色电力、供电可靠性、低碳属性的偏好都能线性叠加到同一个优化问题里不会破坏整个模型的凸性ADMM迭代的时候也容易收敛。还有一点值得注意价值认同系数不是越大越好。如果所有用户都把偏好系数设成1那相当于大家只认绿电价格信号失灵弱势用户可能买不到电。实际操作中我会把偏好系数控制在0到0.5之间作为价格信号的修正项而不是完全替代价格。1.3 集中式 vs 分布式为什么非得分着算第一次做这种题目的人最常见的疑问是把需求侧所有用户的数据收上来用一个中心节点做全局优化效果不是更好吗确实如果只看数学结果集中式优化能找到全局最优解但这不符合项目标题里的“分布式交易策略”这个前提。这里有一个理念上的区别。集中式优化要求所有用户上报完整的负荷、光伏预报、储能状态甚至包括愿意接受多少钱的价格敏感曲线。这些数据放在真实的多主体交易环境里几乎不可能拿到。分布式算法只需要用户在每一轮迭代中上报一个“期望净交换功率”或者“报价曲线”不涉及隐私数据。即使上报了偏差最后也会通过迭代修正不会暴露真实成本函数。另外从系统稳健性角度看中心节点一旦故障或通信中断集中式调度直接失效分布式结构即使丢掉一两个节点剩下的用户还能继续迭代出可行解。这也是为什么题目强调“分布式交易策略”。在Matlab里实现分布式结构并不比集中式复杂太多关键是把每个用户的本地优化封装成一个独立函数然后由一个协调器只做“汇总和更新价格/乘子”的工作。2. 数学模型设计把“共享认同”写成可优化的目标2.1 产消者模型和决策变量怎么定义实际建模时我习惯把每个用户看作一个“产消者”即同时具备发电和用电能力。最简单的模型里每个用户节点在时段t的决策变量包括从共享市场购买的电量向共享市场出售的电量储能充电功率储能放电功率可调负荷的用电功率如果做日前调度时间段通常取24个点每个用户的决策变量数大概是24乘以5到6个规模很小。重点是时段之间的耦合约束尤其是储能SOC的递推关系。这个约束有一个特点它只作用于同一个用户自己不涉及其他用户所以非常适合保留在本地优化子问题里。我把每个用户的模型用一组Matlab结构体来存字段包括load_profile、pv_profile、storage_capacity、storage_init、preference_green等。这样在主程序里只需要循环调用每个用户的优化函数后续如果要改场景人数只需要修改数据生成部分不用动核心算法。有一点容易搞混共享市场的“购买”和“出售”不能同时为正。虽然算法本身不会自动禁止但在实际定价机制里如果用户既买又卖会造成虚假交易。我建议在本地优化里加一个耦合约束购买量和出售量的乘积为0。这个约束是非凸的会让问题变麻烦。更简单的做法是定义用户净交换功率为正表示卖出为负表示买入这样就不需要处理同时买卖的问题了。2.2 效用函数、成本函数和价值认同项的衔接电能共享模型里目标函数必须能体现“交易是为了双方受益”这个基本逻辑。我用的用户效用函数是二次函数形式U_i(x_i) a_i * x_i^2 b_i * x_i c_i其中x_i表示用户i的可用电量或者用电功率。二次项系数a_i取负数代表边际效用递减。比如一个家庭用户用电从0度增加到5度时获得感增加明显从20度增加到25度时可能只是多开了会儿灯获得感增加就少了。购买成本和售电收益可以线性表示购电成本为购买电量乘以市场电价售电收益为售出电量乘以出清价格这里出清价格在迭代中是动态更新的。价值认同项我通常写成preference_green_i * (实际购买绿电量 - 期望购买绿电量)如果实际购买绿电量高于期望值效用增加低于期望值效用减少。这样就把“我优先买绿电”的意愿变成了一个可计算的软约束。整个用户的本地目标函数是min 购电成本 - 售电收益 - 用电效用 - 价值认同效用前两项要花钱后两项是获得收益。因为a_i为负整个函数仍然保持凸性用Matlab的quadprog可以直接求解。每轮迭代时电价和共享电量发生变化用户重新优化自己的决策下一轮再更新电价。2.3 约束条件功率平衡、储能SOC、爬坡与交互功率上限一个能被Matlab代码正确求解的交易策略约束条件必须写得干净、严谨。我总结出几类必须处理的约束本地功率平衡光伏出力、储能充放电、购电售电和负荷之间要满足能量守恒这是每时每刻都必须满足的硬约束。储能约束SOC要用递推公式约束充电效率和放电效率分开写同时避免同一时段既充又放。最简单的方法是设一个充放电状态变量或者用互补约束近似。功率上下限用户与共享市场之间的交互功率不能超过物理通信线路或变压器容量限制。这个约束通常取5kW到30kW不等。非负约束与容量约束光伏出力不超过预测值负荷不超过最大可用功率储能容量不越限。这些约束在Matlab里可以分成Aeq、beq、A、b、lb、ub六类直接传给quadprog。有一个经验如果是长时间尺度仿真SOC约束要单独写成循环把前面时段的结果代入下一时段递推公式不能在矩阵约束里一次性写错。注意约束条件里最容易出问题的是“储能同时充放电”。很多人在描述里说“储能不会同时充放”但代码里没有加约束最后求解结果出现既充电又放电的伪能量流动。要么加上状态变量把问题变成混合整数规划要么用一个小惩罚项把同时充放的成本抬高。3. 分布式求解算法选型与Matlab实现3.1 为什么选ADMM拆开来算还保证收敛需求侧电能共享的分布式求解算法有很多种包括分布式次梯度、一致性算法、ADMM、博弈论迭代算法等。我实际写下来的感受是ADMM是工程上最好落地的一种。原因有三点。第一ADMM把耦合的供需平衡约束放到增广拉格朗日函数里每个用户只需要解决自己独立的子问题对Matlab这种数值计算环境特别友好quadprog或者fmincon可以直接用。第二ADMM的收敛条件比较宽松即使目标函数不是严格凸只要增广项存在一般也能收敛到近似解。第三ADMM有明确的残差指标我可以根据残差变化判断是算法参数问题还是数据问题。对比分布式次梯度ADMM最大的优势是收敛速度更快。分布式次梯度通常需要上千次迭代ADMM往往几十次到上百次就能达到工程可用的精度。对于日前24个时段的场景这个速度差别非常重要。我试过用分布式次梯度跑30个用户、24时段的算例跑了5000次迭代残差还不理想换ADMM之后50次迭代就能让功率不平衡降到0.1kW以下。3.2 ADMM迭代细节本地优化、清算变量、乘子更新下面我用一个简化的“净交换功率共享”模型描述ADMM迭代。每个用户i在每个时段t有一个净注入功率P_i注入方向为正表示向共享市场卖电为负表示买电。全局约束很简单所有用户净注入功率之和为0也就是总卖出电量等于总买入电量。为了把约束解耦引入辅助变量q_i和拉格朗日乘子u_i。每轮迭代分三步本地优化用户i固定q_i和u_i求解自己的本地子问题得到新的P_i。目标函数是“用电效用价值认同市场交易收益”加上增广项(ρ/2) * ||P_i - q_i u_i||^2清算变量更新协调器收集所有P_i和u_i通过取平均值更新每个用户的q_i使得所有q_i之和为0。数学形式是q_i_new P_i_new u_i - mean(P_new u)乘子更新对每个用户更新u_iu_i_new u_i P_i_new - q_i_new计算原残差和对偶残差判断是否小于收敛阈值。这样的结构在Matlab里实现效果很清晰。每个用户的本地优化函数是完全独立的不感知其他用户的数据只有协调器需要拿到所有用户的P和u。如果以后想扩展到真实多代理系统把协调器部分部署到中央服务器把本地优化部分部署到边缘设备逻辑完全一致。提示q_i在这个算法里可以理解为“用户申报的交易计划”它实现了买卖双方的电量匹配。由于q_i更新时强制均值归零所以整个系统的供需平衡始终满足。这也是ADMM能收敛的根基。3.3 代码结构怎么组织给一个能直接改的框架我这里给一个建议的Matlab目录结构适合所有类似的分布式交易项目p2p_trading/ ├── main_shared_trading.m ├── data_generation.m ├── local_optimization.m ├── coordinator_update.m ├── convergence_check.m └── plot_results.m其中main_shared_trading.m负责参数初始化、循环迭代、调用其他函数。local_optimization.m接收该用户的负荷、光伏、储能参数、当前电价和乘子返回该用户的最优净交换功率。核心迭代代码大概是下面这个样子我做了简化但框架是完整的% 参数初始化 n_users 5; rho 50; max_iter 200; tol 1e-4; P zeros(n_users, 24); Q zeros(n_users, 24); U zeros(n_users, 24); for k 1:max_iter % 每个用户独立求解本地优化子问题 for i 1:n_users P(i,:) local_optimization(data(i), price, Q(i,:), U(i,:), rho); end % 协调器更新清算变量 Q_new P U - repmat(mean(P U, 1), n_users, 1); % 更新乘子 U_new U P - Q_new; % 收敛判断 primal_res norm(P - Q_new, fro); dual_res rho * norm(Q_new - Q, fro); if primal_res tol dual_res tol break; end Q Q_new; U U_new; end这个代码里价格变量没有直接出现在迭代循环中但实际上价格隐含在local_optimization内部的购电成本和售电收益里。在每轮迭代开始前我会用上一轮的Q和U计算出一个“影子价格”传给本地优化函数让用户对价格变化做出响应。这样更符合电能市场的直觉价格在里面是调节信号而不是一个固定输入。4. 算例设计与结果怎么看4.1 先搭一个5用户场景参数怎么定比较合理分布式交易策略的算例不需要特别大5个用户、24个时段已经足够说明问题。我强烈建议先把小场景跑通再考虑扩大规模。下面是我设计的一个典型场景用户光伏峰值(kW)负荷峰值(kW)储能容量(kWh)偏好系数角色说明1号103100.2白天光伏富余卖电给邻居2号0500.8晚高峰缺电愿意买绿电3号6450.5午后有余电晚间购电4号3600.9偏好最高买绿电意愿强5号0240.3用电稳定偶尔储能套利这些参数并不需要追求特别精确只需要满足一个基本逻辑用户行为有差异。1号是典型的光伏房东白天发电量远大于自己用电量2号和4号是典型的负荷用户没有光伏希望买电3号是自平衡型用户光伏和负荷基本匹配5号是带有储能的灵活用户可以在低价时段充电、高价时段放电。场景确定后我会把24时段的光伏和负荷曲线做成平滑曲线再叠加随机噪声这样可以模拟真实数据的波动。注意叠加随机噪声后一定要再次检查每条曲线的物理合理性不能让光伏出现负数不能让负荷出现尖峰异常值。4.2 需要统计哪些指标成本、效用、消纳率、收敛速度做完仿真以后很多人只画了一张迭代收敛曲线就结束了。实际上一个交易策略好不好需要从多个维度评价。我自己通常统计五项指标用户购电总成本直接体现用户是否受益。用户售电总收益光伏拥有者的收益变化。平均交易电价检验出清价格是否介于上网电价和零售电价之间。本地消纳率等于共享交易电量占光伏总发电量的比例这是电能共享策略的核心指标。用户综合效用包含用电效用和价值认同效用反映用户的真实获得感。这五项指标可以用一个表格汇总比如指标无共享交易有共享交易变化幅度用户总购电成本398元312元下降21.6%光伏用户总收益86元134元提升55.8%本地消纳率42%87%提升45个百分点用户综合效用812889提升9.5%上面这组数字是我根据一个5用户仿真算例得到的大致水平不同场景会有差异但趋势基本一致。你跑出来的结果可以对比这个范围如果差异特别大先不要急着怀疑算法检查一下数据量纲和约束条件是否设置合理。4.3 典型结果解读价格、电能流向和偏好系数的关系在结果分析里最值得关注的是“价值认同系数”改变后电能流向和交易价格发生了什么变化。我在算例里的做法是把偏好系数从0逐步增加到0.8观察每个时段的交易量。结果是当偏好系数增加后白天光伏大发时段光伏用户更愿意把电量共享给本地用户而不是卖到上级电网同时本地用户在同等价格下优先选择绿电。反映在结果上就是共享电量和本地消纳率提升交易价格也会比无偏好场景略高一点。高出来的这一部分就是“价值认同溢价”。这个现象非常重要因为它说明价值认同并不是一个空泛的道德概念而是实际影响市场出清结果的经济因素。如果你在Matlab里画出“偏好系数-共享电量”曲线会看到一条先上升、后趋于平缓的曲线。当偏好系数超过0.6以后共享电量提升速度明显放缓说明大部分可转移的电量已经转移完了再增加偏好参数只会抬高价格不再额外增加共享量。有经验的读者应该能猜到这就是经济学里的边际效应递减。把这个曲线放进论文或者项目汇报里比单纯写“偏好系数提升消纳率”更有说服力。5. 我踩过的坑收敛失败、不可行约束和参数敏感问题5.1 增广拉格朗日参数ρ对收敛的影响ADMM里最让人头疼的就是ρ的选择。ρ太小原残差和对偶残差会出现锯齿形震荡很难收敛到设定的阈值ρ太大收敛速度又变得很慢迭代次数大大增加。我跑第一版代码时ρ随便设成1结果迭代100次还是不收敛P和Q之间的距离反复横跳。后来我把ρ调到50收敛速度快了很多。再调到500虽然稳定但明显感觉收敛变慢。所以实际调试时不要追求一个固定ρ应该采用动态调整策略。我的经验是每5到10轮迭代检查一次残差比例if primal_res 10 * dual_res rho rho * 2; elseif dual_res 10 * primal_res rho rho / 2; end这个策略在“原残差很大、对偶残差很小”时增大ρ在“对偶残差很大、原残差很小”时减小ρ。修改完之后下一轮迭代的收敛速度会有明显改善。这个方法不是我原创的很多ADMM教程里都提过但真正在Matlab里写进去的人不多。5.2 总供需不匹配时问题根本无解怎么办这是分布式交易策略里最常被忽略的坑。如果某个时段所有用户的总负荷大于总光伏出力加储能放电能力系统内部供需无法平衡模型就无解。你继续跑ADMM会发现残差永远下不去因为原问题本身就是不可行的。我的解决办法是在用户本地目标函数里增加一项“与上级电网的交互功率”把它作为松弛变量。也就是说用户内部的电能共享优先满足不足或多余的部分可以跟上级电网交易。这样做模型永远可行而共享交易策略的目标就是尽可能减少对上级电网的依赖。在Matlab里实现时我会在本地优化子问题的约束里设置一个“电网交互功率”变量同时在目标函数里给它一个较高的电价。这样系统在能自平衡的时段就不会用电网电量不能自平衡的时段自动买入电网电量。注意电网电价应该比内部交易价格高否则用户没有动力参与内部共享。5.3 初始化、quadprog设置和残差判断的细节初始化对ADMM的收敛速度影响很大。如果所有变量都初始化为0第一轮迭代时用户的本地优化会在没有任何价格信号的情况下给出一个比较极端的解后面的迭代需要花时间去修正。我建议在第一轮迭代前先让所有用户独立跑一次纯本地优化用这个结果作为P的初值然后让q和u为0。这样相当于给了算法一个“合理猜测”可以节省10到20轮迭代。另外一个细节是quadprog在Matlab不同版本中的接口有差异。如果用的是旧版需要确认是否要传入Aeq和beq如果用的是新版建议显式指定优化选项options optimoptions(quadprog, Display, off, Algorithm, interior-point-convex); x quadprog(H, f, A, b, Aeq, beq, lb, ub, x0, options);这里我特别推荐使用interior-point-convex算法因为电能共享问题的凸性较清晰该算法收敛稳定不需要提供雅可比矩阵。如果直接不指定算法quadprog有时会走active-set在约束很多时容易报错“最大迭代次数已超过”。残差判断也不能只看单一指标。我一直同时看两个残差原残差norm(P-Q)和对偶残差norm(Q_new-Q_old)。前者表示“用户期望值是否和交易计划一致”后者表示“清算变量是否还在变化”。两个残差都小才说明真正收敛。6. 从能跑到能用模块化改造可以怎么继续6.1 把脚本改成函数库的边界划分项目标题里特别强调了“Matlab代码实现”那么代码质量就很重要。最开始跑通的一个大脚本后面要改参数、改场景会非常痛苦。我做完第一版之后会把功能拆成若干函数尽量做到“数据和算法分离”。具体来说我把所有输入数据集中在一个init_case.m函数里该函数返回一个结构体case_data包含用户数量、负荷曲线、光伏曲线、储能参数、电价参数等。主迭代程序只处理ADMM循环不需要关心数据从哪来。用户模型和算法模型彻底分开后想换一个5用户场景换成30用户场景只需要改init_case.m里的数据生成部分。代码的可读性也值得重视。我会在函数名前加前缀比如opt_user_local、update_system_q、calc_shadow_price这样别人拿到代码也能看出每个模块的功能。最好再配上注释说明每个变量的单位否则过了两个月连自己都看不懂SOC的单位到底是kWh还是百分比。6.2 有价值的几个扩展方向如果你不想只停留在复现层面这个项目可以往三个方向继续做。第一个方向是加入多类型需求侧资源。现在模型里是光伏和储能实际场景还有空调、电动汽车、热水器等可调负荷。把这些资源的满意度函数加入模型后本地优化子问题的约束会变多但思路完全一样。第二个方向是考虑光伏和负荷预报的不确定性。用场景法生成几百个随机场景然后做两阶段随机优化或者直接用模型预测控制做滚动优化每一小时更新一次交易计划。这个扩展会让代码复杂很多但很有研究价值。第三个方向是把ADMM替换成更贴合真实P2P交易的算法比如完全去中心化的共识算法或基于区块链智能合约的交易机制。这类方案不需要一个协调器节点每个用户只和邻居通信对通信要求和隐私保护更强。当然实现难度也会明显上升。但不管往哪个方向扩展最底层的需求侧电能共享模型、价值认同参数、ADMM迭代逻辑都是通用的。先把5用户的简单案例彻底跑明白再往上加复杂度是最稳妥的路线。我个人在实际操作中的体会是这种分布式交易项目最怕的不是算法太复杂而是模型和代码之间对不上。尤其是价值认同参数它看起来只是加了一个权重但当你把它调大时整个交易价格、电量流向都会跟着变。如果你发现结果出现“偏好系数增大但共享电量不增反降”的反常情况不要急着调算法先回头看看目标函数里价值认同项的符号是不是写反了。这个符号问题我印象里至少踩过两次。
返回列表