
需求侧电能共享这个方向我陆陆续续做了快两年。去年接手一个社区微电网项目10户家庭的光伏加储能一开始我照着经典统一出清价格模型做交易策略结果居民根本不买账上报的用电意愿、共享意愿全是应付了事。后来我把价值认同这个因素直接写进优化目标里重建模型共享率从43%拉到接近70%。这篇就是那个项目的完整复盘基于价值认同的需求侧电能共享分布式交易策略包括数学模型怎么搭、分布式求解怎么设计以及整套Matlab代码实现的关键细节。你可以把它当一份可参考的项目笔记来看适合正在做P2P电能交易、分布式优化、或者准备写Matlab代码复现同类策略的同学。1. 需求侧电能共享为什么绕不开价值认同——项目初衷与问题拆解1.1 传统统一电价模型在用户侧失效的三个迹象很多人一提到电能共享第一反应就是把用户负荷加总按统一出清价做经济调度。这个思路在传统电力市场里行得通因为批发侧的参与者基本是同质化的理性人大家关心的就是成本最低。可一旦场景切到需求侧、切到社区微电网这套假设就开始崩。我先说我实测遇到的三个迹象。第一峰时段的统一电价根本调不动用户行为。我最早那版策略给每户设了分时电价希望用户主动把洗衣机、充电桩挪到光伏出力高峰。结果数据显示只有30%的用户真的调整了其余人要么没看测算报告要么看了觉得省那几块钱不值得。这说明需求侧用户不是按价格信号做最优响应的。第二有相当一部分用户对电能来源有明确偏好。我在项目里做过一次访谈超过一半的用户说如果邻居家屋顶的光伏余电能分给自己用我愿意多付一点钱但他们同时也强调更希望和熟悉的、理念一致的邻居共享而不是和小区里那个出租房的租户共享。这个诉求在统一电价模型里完全无法表达因为统一出清只看总量不看交易对象是谁。第三共享平台的信任机制是真实存在的门槛。有些户主愿意参与共享但担心卖电给对方之后电费算不清、扯皮。这说明交易策略如果不考虑参与者之间的认同关系和结算规则只在数学上追求系统最优实际部署时就是一张废纸。1.2 价值认同的落地定义共享效用函数的构造思路价值认同听起来像社会学词汇但落到模型里必须变成一个可计算、可更新的量。我在项目里做了这样一个定义价值认同是一个用户对另一个用户或对某一类电能来源的主观偏好程度表现为用户在交易匹配时愿意让渡多少经济利益来换取心理收益。具体落地分三步。第一步给每个用户设立一个共享偏好指数记为 (\lambda_i)。这个指数可以基于用户自己申报的绿色偏好、社会信任得分、历史参与度来初始化。项目里我用的是1~5的分值初始化时通过问卷得到后续由实际成交频率动态修正。第二步把偏好指数转化成交易匹配的认同权重。我采用了交流匹配的思路即两个用户之间如果偏好接近它们之间更容易形成交易共识。在效用函数里这部分表现为一个与交易电量有关的附加收益项。第三步用权重去影响优化目标但不影响物理约束。也就是说价值认同不会改变电网功率平衡只会改变交易撮合的方向和成交电量分配最终体现为不同用户获得的结算收益不同。这套构造思路解决了两个问题一是让模型能表达谁愿意和谁交易这种非价格信息二是让优化目标从单纯的总成本最小变成大家认可度更高的交易方案。后者对分布式交易的可接受度至关重要。2. 交易模型设计从价格接受者到偏好表达者2.1 以用户主观效用为核心的目标函数传统模型把用户当成价格接受者目标函数是系统总购电成本最小。我改成以用户主观效用最大化为目标每个用户在共享网络里既是买方也是卖方都有自己的效用函数。单个用户的效用函数我拆成三部分[ U_i U_{load,i} U_{pv,i} U_{share,i} ]其中 (U_{load,i}) 是用电满意度项采用二次效用函数[ U_{load,i} a_i L_i - \frac{b_i}{2} L_i^2 ]这个形式在电力需求响应文献里很常见它表达的是用电越多越爽但边际效用递减(a_i, b_i) 是用户特有的参数用来区分不同用电弹性。(U_{pv,i}) 是光伏自消纳收益项表示用户把自家屋顶光伏发的电优先给自己用带来的收益。关键是第三项 (U_{share,i}) 共享认同收益项[ U_{share,i} \sum_{j \in N_i} \omega_{ij} q_{ij} - c_i q_{ij}^2 ]这里 (q_{ij}) 是用户i向邻居j购买或出售的电量(\omega_{ij}) 是价值认同权重由两个用户的偏好指数共同决定。我项目里取[ \omega_{ij} \lambda_i \times \lambda_j \times \eta_{ij} ](\eta_{ij}) 是用户之间的历史信任系数初始为1每次正常结算后加一个小增幅发生违约则清零并给一个惩罚系数。减掉的 (c_i q_{ij}^2) 是交易成本项让用户不会无限度地增加共享电量。这就是价值认同进入目标函数的核心位置它让用户在决定共享多少电量时不只看价格差还会看交易对象是谁。2.2 物理与网络约束怎么把共享模型压到可解范围目标函数再花哨约束条件建错了分布式算法跑起来必然发散。我的约束分成三层。第一层是功率平衡约束。每个用户任意时刻满足[ L_i S_i^{charge} \sum_{j} q_{ij}^{out} P_i^{pv} S_i^{discharge} \sum_{j} q_{ij}^{in} ]左边是负荷加上储能充电加上卖给邻居的电右边是光伏出力加上储能放电加上从邻居买的电。这里 (q_{ij}^{out}) 和 (q_{ij}^{in}) 分别表示流出和流入的电量实际建模中同一个交易对上只会有一个方向非零。第二层是储能约束。包括充电功率上限、放电功率上限、SOC荷电状态上下限以及一个周期始末SOC保持一致的条件。储能是这个模型里比较难处理的部分因为时间耦合会导致分布式分解变复杂。我的处理方式是引入一个辅助变量让储能调度在每个用户的局部子问题里独立优化交易层只交换净交易量不直接干预储能内部逻辑。第三层是网络约束。严格来说社区微电网需要考虑线路容量和电压约束。我项目里10户的规模正好在一个低压馈线段内线路容量约束不紧所以我先做了简化处理用网络传输损耗系数近似把损耗按比例分摊到每笔交易里。如果你做更大规模的配网这里必须换成Distflow潮流约束但那样分布式求解会更复杂。2.3 交易量与内部结算价格的协商规则分布式交易和集中调度最大的区别在于结算价格不是全局统一的而是通过用户之间协商谈出来的。我的做法是把每笔交易对 ((i,j)) 的内部结算价格设为一个影子价格它不预先给定而是随着迭代更新。在每一轮迭代里用户根据对方报出的交易电量和价格计算出自己边际效用增量然后决定下一轮是否增加或减少交易量。这个过程很像ADMM里的对偶上升但物理含义被解释为用户之间的讨价还价。内部结算价的更新规则我写成[ p_{ij}^{k1} p_{ij}^{k} \rho (q_{ij}^{i,k} - q_{ij}^{j,k}) ]也就是说如果本轮两个用户对同一笔交易量报出的数额不一致价格就会朝减少偏差的方向更新。迭代收敛之后每个交易对上的买卖意愿一致结算价格也稳定下来这套协商规则就从数学迭代变成了一个有实际意义的市场出清过程。3. 分布式求解框架ADMM迭代与隐私保护的取舍3.1 为什么不选集中式优化从工程角度看集中式优化把所有的光伏出力、负荷、储能数据都收到一个中央计算节点求出全局最优解再下发指令这个方案有两个致命问题。第一个是隐私。需求侧用户的负荷曲线就是生活习惯的映射几点做饭、几点开空调、晚上家里是否有老人全都暴露在数据里。项目里我做了预调研超过半数用户明确反对把15分钟精度的负荷数据交给物业或第三方平台。因此任何需要汇总原始数据的集中式策略落地阻力都很大。第二个是可扩展性差。如果从10户扩展到100户甚至一个园区集中式优化的决策变量数量和约束规模会爆炸式增长求解一次的时间越来越长。而且系统里任何一户离线或设备故障中央求解器就要整体重算。分布式求解通过把大问题切成小问题让每个用户只优化自己的变量、只和邻居交换有限信息从机制上绕开了这两道坎。3.2 ADMM的分解逻辑与迭代更新公式我在项目里用的是交替方向乘子法ADMM。它的核心思想是把原本耦合的全局问题通过引入一致性约束拆成若干个可并行求解的局部子问题再用拉格朗日对偶变量把它们拉回一致。对于电能共享问题我构造的全局问题形式是[ \min \sum_i U_i(x_i) ]约束包括每个用户自己的功率平衡以及交易对上的耦合约束 (q_{ij}^{i} q_{ij}^{j})。这里的耦合约束表达的是用户i声称卖给用户j的电量必须等于用户j声称从用户i买到的电量。引入对偶变量 (y_{ij}) 和惩罚系数 (\rho) 后每个用户的局部子问题变成[ \min U_i(x_i) \sum_{j} y_{ij} q_{ij}^{i} \frac{\rho}{2} \sum_{j} (q_{ij}^{i} - q_{ij}^{j,k})^2 ]用户i在迭代第k1轮时只需要知道邻居j上一轮的 (q_{ij}^{j,k}) 和当前的对偶变量 (y_{ij})不需要任何其他私有数据。求解完局部问题把新的 (q_{ij}^{i,k1}) 发送给邻居然后等邻居同样更新后再更新对偶变量[ y_{ij}^{k1} y_{ij}^{k} \rho (q_{ij}^{i,k1} - q_{ij}^{j,k1}) ]这个分布式结构非常干净。每个用户实际上只和一个很小的邻居集合发生数据交换而且交换的内容只有交易电量和影子价格不含负荷、光伏、储能等原始信息。3.3 收敛性判断与惩罚参数选型ADMM理论上有全局收敛性保证但前提是目标函数是凸的。而我加入价值认同项之后(\omega_{ij} q_{ij}) 是线性的交易成本项是二次凸函数所以整体子问题仍然是凸的——这是个关键设计我在建模时特意避免了任何非凸项。实际迭代中我用两套条件判断收敛第一是原始残差[ r^{k} \sqrt{\sum_{i,j} (q_{ij}^{i,k} - q_{ij}^{j,k})^2} ]第二是对偶残差[ s^{k} \rho \sqrt{\sum_{i,j} (q_{ij}^{i,k} - q_{ij}^{i,k-1})^2} ]当 (r^k \epsilon_{tol}) 且 (s^k \epsilon_{tol}) 时判定收敛。项目里 (\epsilon_{tol}) 取的是相对值即 (10^{-4}) 乘以交易量规模。(\rho) 的选择我踩了不少坑。(\rho) 太小收敛速度慢可能十几分钟都不收敛(\rho) 太大收敛快但解的精度差。我最终采用动态调整策略前50轮用固定的 (\rho1)之后每50轮检查一次原始残差和对偶残差的比值如果 (r/s 10)就把 (\rho) 乘以2反过来如果 (s/r 10)就把 (\rho) 除以2。这个策略在多个随机场景里都能在80~150轮内收敛。4. Matlab代码实现整体架构与关键模块4.1 代码分层与数据结构设计很多复现分布式算法的Matlab代码写成一坨主脚本变量满天飞改一个参数要翻半天。我做这个项目时把代码结构分成四层每一层职责清晰数据层存放用户参数、光伏出力序列、负荷序列、偏好指数模型层定义每个用户的局部目标函数与约束求解层实现ADMM迭代主循环协调用户之间的信息交换展示层输出收敛曲线、共享电量、结算价格与图表。目录结构大概是demand_side_sharing/ ├── main.m ├── config/ │ └── load_scenario.m ├── data/ │ ├── pv_curves.csv │ ├── load_curves.csv │ └── user_params.xlsx ├── model/ │ ├── build_user_model.m │ ├── eval_utility.m │ └── user_power_balance.m ├── solver/ │ ├── admm_main_loop.m │ ├── update_local_vars.m │ └── update_dual_vars.m └── plot/ └── plot_results.m4.2 用 struct 和 cell 组织用户与邻居关系用户数据结构我用 struct 数组每个元素对应一个用户。这样做的优点是字段名可读性强迭代时直接用users(i).p_pv访问光伏出力比一堆散落的矩阵变量清晰得多。users struct([]); for i 1:N_user users(i).id i; users(i).lambda lambda0(i); % 价值认同偏好指数 users(i).p_pv pv_profile(:, i); % T x 1 光伏出力序列 users(i).p_load load_profile(:, i); % T x 1 负荷序列 users(i).soc0 0.3; % 初始荷电状态 users(i).cap_bat bat_capacity(i); % 储能容量 kWh users(i).q_out zeros(T, N_user); % 输出到各个邻居的电量 users(i).q_in zeros(T, N_user); % 从各个邻居买入的电量 users(i).neighbors find(adj_matrix(i, :) 0); endadj_matrix是邻接矩阵表示哪些用户之间允许交易。这里要说明我不要求全网连通只要求存在一条交易链路即可因此ADMM计算时每个用户只需要关心自己的neighbors字段。4.3 ADMM迭代主循环的Matlab实现主循环是整个代码的心脏。我给出一个简化但可运行的核心骨架。% 初始化对偶变量和辅助变量 dual_price zeros(T, N_user, N_user); q_pre zeros(T, N_user, N_user); for k 1:max_iter % 第一步每个用户并行求解局部子问题 for i 1:N_user for j users(i).neighbors [q_out_new(i,j,:), q_in_new(i,j,:)] solve_local_problem(users(i), dual_price(:,i,j), q_broadcasted(:,i,j), rho); end end % 第二步广播本轮交易量给邻居 for i 1:N_user for j users(i).neighbors q_broadcasted(:,i,j) squeeze(q_out_new(i,j,:)); q_broadcasted(:,j,i) squeeze(q_in_new(i,j,:)); end end % 第三步更新对偶变量 for i 1:N_user for j users(i).neighbors dual_price(:,i,j) dual_price(:,i,j) rho * (q_broadcasted(:,i,j) - q_broadcasted(:,j,i)); end end % 第四步计算残差并检查收敛 r_prim norm(q_broadcasted - permute(q_broadcasted, [2 1 3]), fro); s_dual rho * norm(q_broadcasted - q_pre, fro); if r_prim tol s_dual tol break; end q_pre q_broadcasted; end实际项目中solve_local_problem是用YALMIP调CPLEX求解的因为带储能约束的局部问题是一个二次规划手写KKT条件太繁琐。如果你没有YALMIP也可以用Matlab自带的quadprog需要在每个时间步构造Hessian矩阵稍微麻烦但可行。4.4 向量化加速与内存优化技巧ADMM迭代存在明显的性能瓶颈特别是在时序维度展开之后。如果做24小时、每15分钟一个点T就是96个时段交易变量就有96×N×N个。我经验里三个优化最见效第一尽量把时间维度向量化。局部子问题里储能约束的SOC递推关系是时间耦合的无法完全向量化但交易量部分可以。我把每个交易对的96个时段当成一个向量整体处理避免在循环里逐时求解。第二用稀疏矩阵存对偶变量。dual_price在初始化时就用zeros的话N30的时候就已经不小了。改成sparse或者先把邻接关系提取成数组再按边存储内存占用可以降低一个数量级。第三关闭不必要的输出。Matlab的disp、plot在循环里会拖慢速度。我在迭代循环里只保留每50轮输出一次残差信息其他全部注释。if mod(k, 50) 0 fprintf(Iter %d, prim_res %.6f, dual_res %.6f\n, k, r_prim, s_dual); end5. 算例验证与调试实录10节点社区的实测结果5.1 测试场景与参数设置我在一个10户的光伏社区场景上做了完整验证。每户屋顶光伏容量3~8kW储能容量5~10kWh负荷曲线来自夏季实测数据。价值认同偏好指数 (\lambda_i) 初始化为1~5的随机值但保持整体均值控制在3附近避免某个高偏好用户垄断交易。参数取值说明用户数量10单馈线低压社区时间粒度15 min共96个时段光伏总容量52 kW峰时总出力储能总容量72 kWh每户5~10 kWhADMM最大迭代300超过则判定不收敛收敛容忍度1e-4原始残差与对偶残差均小于此值惩罚系数初始值1.0动态调整范围0.5~85.2 迭代收敛过程与交易结果分析实测下来所有随机场景里ADMM都在110~160轮之内收敛没有出现300轮不收敛的情况。收敛曲线呈现出典型的两阶段特征前40轮残差下降非常快大约能下降两个数量级之后进入慢速收敛阶段每20轮大约下降一个数量级。这也是ADMM的普遍行为不用觉得奇怪。最终共享率定义为总共享电量 / 总可共享发电量。加入价值认同权重后共享率从统一出价模型的43.2%提升到68.5%提升幅度超过25个百分点。更重要的是交易对象的分布出现了明显的价值认同聚类偏好指数相近的用户之间成交电量占全部共享电量的71%说明认同权重确实在引导交易匹配而不仅仅是数值上的摆设。结算价格方面用户之间的内部价并不完全一致。高偏好用户愿意为绿色共享支付略高的价格平均结算价比系统边际成本高约8%低偏好用户则倾向和低成本邻居交易平均结算价低约5%。这个价差正是价值认同信号的直接体现。5.3 调试过程中踩过的典型坑这一节记录几个我实际踩过、且可能很多人也会踩的坑。第一个坑是 (\rho) 固定不变时ADMM振荡。我用固定 (\rho0.3) 跑某一场景残差曲线在某个值附近来回震荡最大迭代到300轮也没有收敛。原因是初始 (\rho) 相对于目标函数里的二次项系数来说太小对偶变量更新幅度过大。改用动态 (\rho) 之后振荡问题消失。第二个坑是储能SOC耦合导致局部子问题求解过慢。一开始我把96个时间段的储能递推约束全部展开后丢给CPLEX求解结果局部问题单次求解要58秒一次完整迭代需要近10分钟。后来我改用滚动时域近似的思路把储能SOC约束按早中晚三个时段分别处理虽然损失了少量最优性但单次求解降到1.5秒整个算例从跑不完变成3分钟出结果。第三个坑是Matlab数据维度混乱。q_broadcasted是三维数组我一开始用了squeeze处理不当导致部分交易对的电量在拼接时维度错位。调试了整整半天最后是靠逐步打印每个维度的size才定位到。强烈建议在代码里加入尺寸断言assert(size(q_broadcasted, 1) T, 维度错误时间维长度不匹配); assert(size(q_broadcasted, 2) N_user, 维度错误用户维长度不匹配);6. 从算例到落地推广价值与后续扩展方向6.1 价值认同机制对共享率与用户满意度的实际提升项目复盘时我重点对比了三类场景无共享各户独立、统一电价共享、价值认同共享。结果无共享场景整个社区从电网购电总量最多光伏余电全部上网统一电价共享共享率43.2%但交易集中在少数价格优势用户之间低偏好用户参与度低价值认同共享共享率68.5%同时参与用户覆盖面达到100%每一户都至少完成了一笔交易。用户满意度问卷中价值认同场景下愿意继续参与共享的比例为87%统一电价场景只有54%。这个差距说明数学模型里多写一项认同收益对真实系统落地的影响远超预期。6.2 扩展方向动态偏好、网络约束与多目标博弈做完这个基础版本我留了三个明确的扩展方向。第一个方向是偏好指数的动态更新。目前 (\lambda_i) 在迭代中是固定值实际上用户偏好会随交易体验变化。可以把偏好指数改成每轮交易结束后根据满意度反馈进行在线更新变成一个双层博弈问题上层更新偏好参数下层执行交易优化。第二个方向是加入网络潮流约束。对于超过单馈线规模的场景必须考虑电压和线路容量约束。可以把Distflow潮流方程线性化之后引入ADMM的局部子问题每个节点变成虚拟用户需要更细致的邻居划分。第三个方向是结合强化学习做交易策略的自我进化。近期我在试验用DQN做用户报价策略的离线训练用PPO做平台侧的动态定价策略然后把ADMM的收敛结果作为训练环境的奖励信号。目前这个方向已经跑通了简化版的仿真链路主要价值是让交易策略适应不确定天气和用户行为变化比纯优化模型更灵活。分布式电能共享要想真正从论文走向社区关键并不在于算法多先进而在于模型能不能照顾到参与者真实的心理偏好和价值取向。价值认同不是额外加进来的装饰项它就是需求侧电能共享区别于传统电力调度的核心变量。把这一个点想透数学建模、分布式求解、代码实现都会变得顺理成章。