基于ADMM的多微电网分布式优化调度与碳排放约束建模

基于ADMM的多微电网分布式优化调度与碳排放约束建模 1. 项目背景与核心问题1.1 为什么多微电网要往“分布式”走先聊一个很现实的问题单一微电网的容量有限风电、光伏出力又看天吃饭。今天你园区里光伏大发用不完隔壁办公楼的微电网却正缺电两头各交各的钱给配电网其实是很亏的。多微电网互联之后可以通过联络线互相支援消纳本地可再生电力减少向主网购电整体运行成本能降一截。这个结论听起来简单真正做起来麻烦。麻烦核心在于各个微电网往往属于不同业主利益主体不同决策权也是独立的。如果有一个“上帝视角”的调度中心统一指挥把所有微电网的机组、负荷、储能数据全部收集到一起算一个全局最优解再下发指令这在理论上最简单也就是集中式优化。但实际工程里园区A不愿意把自己内部的储能SOC、可调负荷的详细曲线全盘托出给园区B或者第三方调度平台。数据隐私、计算规模、单点故障风险都让集中式方案在落地时阻力很大。所以这些年“分布式优化”成了微电网群调度的研究热点。它的思路是每个微电网保留自己的本地优化模型只和邻居交互少量边界变量比如计划交换功率通过迭代逐步逼近全局最优。分布式锁、分布式事务那套玩法是计算机领域的事电力系统里我们聊的是分布式优化算法——各算各的算完再协调协调完再算直到大家意见统一。1.2 碳排放约束怎么“算”进优化目标碳中和目标提出来以后微电网调度不再是“怎么便宜怎么来”还得考虑“怎么低碳怎么来”。碳排放进入优化问题通常有几种做法第一种最直接把碳配额或碳税折算成成本塞进目标函数里。比如给每个微电网分配一个免费碳配额实际排放超出配额的部分需要到碳市场购买或者按超额量交罚金。这样“碳”就有了价格优化器会自动权衡是花高价多买点绿电来少排放还是认罚、多用自己的火电。第二种是加一个排放上限约束比如整个微电网群的日碳排放量不能超过某个值这相当于硬性约束在优化模型里表现为不等式约束。第三种更精细一点引入碳排放流的概念把每一度电从哪个电源来的、对应多少排放追踪到负荷侧。但这在分布式框架下比较复杂因为碳排放流需要全网信息做分布式处理难度较大很多论文只在集中式模型里做。我们这个项目使用的是“碳交易成本 阶梯碳价”模型第三类碳排放流的展开可以后面再聊。需要说明的是这里所有模型和代码都是Matlab环境下用Yalmip工具箱建模、调用Gurobi或者Cplex求解器计算的。如果你没有商用求解器也可以用开源的SCS或者Matlab自带的linprog顶一下不过大规模问题的求解速度会有差距。2. ADMM为什么是它怎么理解它2.1 集中式与分布式的取舍在正式进入ADMM之前我们把几种方案放在一起比较一下你就能理解为什么这个项目选择ADMM。方案通信架构隐私保护收敛速度实现难度集中式优化全拓扑所有数据上送中控差快单次求解即得最优解低一致性交替方向乘子法邻居间交互边界变量好中等中拉格朗日松弛类算法需要一个协调者较差较慢中完全分布式ADMM仅相邻微电网通信好中等中高集中式优化最大的优势是一次求解没有迭代过程结果漂亮。但它不符合多主体自治的现实格局。拉格朗日松弛法需要上层协调者不断更新拉格朗日乘子本质上还是有一个“中央节点”只是计算量分摊下去了。ADMM属于分解协调算法中比较均衡的一种它的核心是把全局耦合问题拆成多个子问题每个子问题交给一个微电网本地求解然后通过交换耦合变量我们这里就是联络线交换功率更新对偶变量不断迭代直到解收敛。2.2 ADMM的数学原理与迭代逻辑ADMM最早可以追溯到1970年代的Dykstra算法和Split Bregman方法2011年Boyd等人出了那篇经典的综述文章《Distributed Optimization and Statistical Learning via the Alternating Direction Method of Multipliers》算是彻底把它带火了。它的标准形式解决的是这样一类问题[ \begin{aligned} \min \quad f(x) g(z) \ \text{s.t.} \quad Ax Bz c \end{aligned} ]写出增广拉格朗日函数[ L_\rho(x, z, \lambda) f(x) g(z) \lambda^T(Ax Bz - c) \frac{\rho}{2}|Ax Bz - c|_2^2 ]然后交替迭代三个步骤[ x^{k1} \arg\min_x L_\rho(x, z^k, \lambda^k) ][ z^{k1} \arg\min_z L_\rho(x^{k1}, z, \lambda^k) ][ \lambda^{k1} \lambda^k \rho(Ax^{k1} Bz^{k1} - c) ]放到多微电网场景里每个微电网的本地决策变量就是自己的机组出力、储能充放电、可平移负荷、联络线注入功率等。耦合约束是微电网i和微电网j的交换功率数值相等方向相反。这个约束写成 ( P_{ij} Q_{ji} 0 )意思是i节点流出多少功率j节点必然流入多少功率两边对同一笔交易的口径必须一致。ADMM的迭代过程说白了就是每个微电网先基于本地信息和上一次邻居给的交换功率期望值求解自己的优化问题算出一个新的交换功率承诺值然后把这个承诺值告诉邻居接着用两边承诺值的平均值校准对偶变量也就是交易价格或者拉格朗日乘子重复上述过程。这里面最有意思也最容易被忽略的一点是实际上迭代到后期我们并不是要求每个微电网用的 ( P_{ij} ) 完全等于邻居的 ( Q_{ji} )而是让它们之间的偏差在可接受范围内。这个“偏差”由对偶变量 ( \lambda ) 和惩罚参数 ( \rho ) 共同控制。2.3 关键参数怎么选rho和收敛容差ADMM参数选择是最玄学的地方。我最早跑这个项目时( \rho ) 取1结果迭代了400多次不收敛后来调成0.05之后80次内就到收敛精度了。( \rho ) 的作用是控制对耦合约束的惩罚力度( \rho ) 太小变量更新对残差不敏感迭代更新很慢甚至震荡不收敛。( \rho ) 太大会过度惩罚交换功率偏差子问题的解过早“咬死”在某个值附近对偶变量更新失效同样收敛慢。工程上常用的经验是先取一个中等值比如0.1观察原残差和对偶残差的变化曲线。如果原残差下降太慢减小 ( \rho )如果对偶残差迟迟下不来增大 ( \rho )。关于收敛判据通常用原残差和对偶残差两个指标[ r^k |P_{ij}^k Q_{ji}^k| ][ s^k \rho|Q_{ji}^k - Q_{ji}^{k-1}| ]当 ( r^k \leq \epsilon_{abs} \epsilon_{rel}|P_{ij}^k| ) 且 ( s^k ) 也满足类似条件时判定收敛。工程上可以简化直接看交换功率偏差的绝对值是否小于某个阈值比如0.01kW并且连续若干次迭代没有继续改善即可提前终止。3. 模型建立与Matlab代码实现3.1 多微网目标函数与约束条件建模下面进入实操部分。假设我们有一个三微电网互联的系统每个微电网都配有光伏、负荷、储能微电网1额外配一台微型燃气轮机微电网2配了柴油发电机微电网3配了燃料电池。网络拓扑是环状连接MG1–MG2、MG2–MG3、MG3–MG1之间都有联络线。每个微电网的优化目标包含四块本地机组发电成本燃气轮机用二次函数 ( aP^2 bP c ) 表示向上级电网购电成本或售电收益分时电价储能充放电损耗成本为了简单可以用充放电功率的线性惩罚近似碳交易成本超出配额部分按阶梯碳价购买。写成数学形式[ \min \sum_{t1}^{T} \left[ \sum_{g \in G_i} (a_g P_{g,t}^2 b_g P_{g,t} c_g) C_{grid,t}P_{grid,i,t} C_{carbon}(E_{i,t} - E_{cap,i}) \right] ]约束条件包括功率平衡本地机组出力 储能放电 − 储能充电 光伏出力 − 负荷 联络线净注入 0联络线容量约束( |P_{ij,t}| \leq P_{ij}^{max} )机组爬坡约束与出力上下限储能SOC动态方程与SOC上下限碳排放约束/碳交易成本函数这里我用的是线性化的碳交易成本函数。阶梯碳价实际上是一个分段线性函数碳排放量越多边际碳价越高。在Matlab里可以用Yalmip的implies和bound实现分段也可以用二进制变量建模。不过更推荐的做法是直接用外点法或者用binvar构造分段线性成本这样能避免非凸问题。3.2 交换功率一致性与交易耦合处理分布式优化的关键在这一步。三个微电网之间的联络线交换功率在全局模型里是一个变量但分解到各微电网本地之后就变成了“MG1认为MG1→MG2的功率是5kW”和“MG2认为MG1→MG2的功率是-5kW”两个变量。它们必须相等。这个就是ADMM要处理的耦合约束。在代码里我是这样处理的把联络线交换功率拆成两个方向变量MG1里记为tie12_1MG2里记为tie12_2分别代表两方对于同一条联络线功率的本地期望值。每次迭代中先把对方的期望值作为固定参数代入本地优化多一个惩罚项 ( \frac{\rho}{2}|tie12_1 - tie12_2^k \lambda^k/\rho|^2 )然后求解本地问题。求解完之后更新对偶变量。这里注意一个细节联络线功率的符号方向必须约定明确。我在代码里全用“正方向为流出本微电网”的约定。如果两个微电网对正方向的理解不一致哪怕算法再正确迭代结果也是乱的。这个坑我踩过一次当时排查了半天最后发现是符号定义反了。3.3 核心代码片段与求解器配置下面这段是ADMM迭代主循环的示意代码用Matlab Yalmip实现%% 初始化 lambda12 zeros(T,1); lambda23 zeros(T,1); lambda31 zeros(T,1); tie12_old zeros(T,1); tie23_old zeros(T,1); tie31_old zeros(T,1); tie12_ref zeros(T,1); tie23_ref zeros(T,1); tie31_ref zeros(T,1); rho 0.1; max_iter 200; tol 1e-3; for k 1:max_iter % 每个微电网并行求解本地问题实际串行也可以 [result1, tie12_1] solve_MG1(tie12_ref, lambda12, rho); [result2, tie12_2, tie23_2] solve_MG2(tie12_ref, tie23_ref, lambda12, lambda23, rho); [result3, tie23_3, tie31_3] solve_MG3(tie23_ref, tie31_ref, lambda23, lambda31, rho); [~, tie31_1] solve_MG1_consistency(result1, tie31_ref, lambda31, rho); % 交换功率取两边期望值的平均作为下一次迭代的参考值 tie12_new (tie12_1 tie12_2) / 2; tie23_new (tie23_2 tie23_3) / 2; tie31_new (tie31_3 tie31_1) / 2; % 更新对偶变量 lambda12 lambda12 rho * (tie12_1 - tie12_2); lambda23 lambda23 rho * (tie23_2 - tie23_3); lambda31 lambda31 rho * (tie31_3 - tie31_1); % 收敛判断 r_pri norm([tie12_1 - tie12_2; tie23_2 - tie23_3; tie31_3 - tie31_1], inf); if r_pri tol break; end tie12_ref tie12_new; tie23_ref tie23_new; tie31_ref tie31_new; end注意solve_MG1、solve_MG2、solve_MG3内部是用Yalmip建模的优化问题每次迭代都需要重新创建optimproblem并调用求解器。为了性能考虑可以尽量复用约束模板只更新参数值而不是每次从头yalmip(clear)不然求解时间会成倍增加。求解器配置方面我使用的是GurobiYalmip的调用配置如下% 设置求解器为 Gurobi options sdpsettings(solver, gurobi, verbose, 0); options.gurobi.MIPGap 1e-4; % 混合整数问题允许的MIP间隙 options.gurobi.TimeLimit 60; % 单个子问题求解时间上限如果模型里用了二进制变量求解器会用branch and bound速度会明显下降。因此在建模时尽量用连续变量替代二进制变量比如碳成本分段可以用pwf函数Yalmip的piecewise接口或者特殊顺序集来建模这样能保持模型为二次规划求解效率高很多。3.4 本地子问题的目标函数结构具体到每个微电网的子问题需要增加一个与交换功率参考值相关的平方惩罚项。以微电网1为例它的目标函数在基础成本之上增加[ \begin{aligned} \frac{\rho}{2}|tie12_1 - tie12_{ref} \frac{\lambda_{12}}{\rho}|^2 \ \frac{\rho}{2}|tie31_1 - tie31_{ref} \frac{\lambda_{31}}{\rho}|^2 \end{aligned} ]这里的 ( tie12_{ref} ) 是上一次迭代中MG1和MG2对同一条联络线交换功率的期望平均值。这个平方项的作用是把联络线功率“拉”向双方的共识值同时通过 ( \lambda ) 项修正偏差方向。最初我尝试不加这个平方项只是固定邻居给的交换功率然后求解本地问题再把结果传给邻居。这样确实也在迭代但非常容易在两个值之间来回振荡无法收敛。加了增广项之后收敛性明显改善。这就是ADMM里“增广”二字的精髓平方惩罚项起到类似阻尼的作用抑制变量更新的振荡。4. 仿真结果与效果分析4.1 收敛性表现与迭代过程这里展示一个典型算例的结果我手上用的是三微网系统24小时调度周期15分钟一个时段共96个时段数据来自项目自带算例。三微电网的特性差异比较大MG1光伏冗余、几乎没有可调机组MG2负荷高峰在白天、配有柴油机MG3有燃料电池和储能、负荷曲线相对平缓。这个设置能让联络线交互非常频繁。迭代过程的关键数据如下迭代次数原残差kW对偶残差kW最大交换功率偏差kW174.5282.3112.84523.1617.426.03204.853.932.11500.720.660.39800.090.080.05可以看到前20次迭代残差下降非常快后面进入缓慢收敛区间。这也是ADMM的典型特征前期线性收敛后期接近尾部时收敛速度放缓。在工程应用中一般不需要把残差压到特别小只要最大交换功率偏差在0.2kW以内对实际调度来说已经可以接受了。我实际跑了80次迭代单次三个微电网子问题的总求解时间约为0.4秒Gurobi二次规划总耗时约32秒。这个速度在离线算例中完全可以接受如果是在线应用可以通过热启动把上一次迭代的解作为初值进一步减少到10秒以内。4.2 对比运行结果考虑与不考虑碳排放为了验证碳排放约束的有效性我跑了两组对比实验第一组在目标函数中不考虑碳交易成本只优化经济成本第二组加入碳交易成本碳排放配额设为微电网自身历史平均排放的90%碳价设为每吨50元阶梯碳价每超出配额100kg碳价上浮10%。结果如下指标不考虑碳排放考虑碳排放变化幅度总运行成本元654270367.55%总碳排放量kg18731485-20.71%向上级电网购电量kWh843762-9.61%微网间交换电量kWh32641226.38%光伏消纳率%87.394.26.9个百分点这个结果很直观加入碳排放约束之后总运行成本上升了约7.5%但碳排放下降了20.7%光伏消纳率从87.3%提升到94.2%。成本上升的主要原因是需要更多地使用燃料电池替代柴油发电机或者在某些时段放弃低成本煤电而从上级电网购买更贵的清洁电。但换来的是碳排放量显著下降以及本地的分布式光伏得到了更充分的消纳。特别值得一提的是微网间交换电量增加了26.38%。这说明碳排放约束改变了各微电网的调度行为MG1光伏大发时段不再只是满足自家负荷后低价卖给上级电网而是优先通过联络线卖给缺电的MG3相当于在系统层面实现了“绿色电力互济”。这也是多微网协同相比单微网运行的核心价值。4.3 分布式结果与集中式结果的一致性校验分布式算法做出来之后很多人会问到底准不准最直接的验证方式是跑一个全局集中式优化模型把三个微电网合并成一个整体建模所有数据可见直接求全局最优解然后将分布式迭代结果与全局最优解做对比。我实测的结果在收敛到残差0.1kW以内时分布式各微电网的目标函数值之和与集中式目标函数值的差距在2%以内。各联络线的交换功率曲线趋势基本吻合峰值时刻的交换功率误差大约在2-3kW。再补充一个追踪性的结论如果只迭代20次就提前终止目标函数差距在4%左右。在实际工程中这个精度也许已经足够但如果追求严格的“最优解”还是建议按残差收敛来判断迭代终止而不是拍脑袋设一个固定迭代次数。5. 调试实录与常见问题5.1 不收敛或收敛慢的处理思路这是一个值得单独拉出来说的部分。ADMM调试中我遇到过好几种“不收敛”的形态各有各的原因形态一残差在某个值附近反复震荡没有明显下降趋势。这种通常是对偶变量更新步长过大也就是 ( \rho ) 值太大。解决方法是把 ( \rho ) 调小一个量级再看。形态二前几轮下降很快后面突然“定住”不动了。这种情况往往出在某个子问题上比如某个微电网的本地优化出现数值问题或者联络线功率越过了容量上限导致子问题不可行。这时需要检查该微电网的约束设置尤其是联络线功率上限和机组出力上限是否自洽。形态三迭代很稳定但收敛极慢每轮只降一点点。这种情况最常见的原因是目标函数中交换功率项的系数和其他成本项的系数量级差距太大。比如电量成本是元级别碳交易成本是分级别导致ADMM的惩罚项权重相对失衡。解决方法是把所有成本归一到同一量纲或者按单位时间每15分钟折算避免跨时间尺度比较。另外一个非常实用的技巧是自适应调整 ( \rho )当原残差与对偶残差的比值大于某个阈值比如10时增大 ( \rho )比值小于0.1时减小 ( \rho )。这不算什么高深理论但在工程上非常管用能显著加快收敛速度。5.2 数值问题与求解器配置陷阱多微电网模型的数值问题比单微网更需要注意。因为各个微电网的规模不等有些子问题的机组容量是百千瓦级有些是兆瓦级量级差异会带来雅可比矩阵条件数变差影响求解器内部算法。建议在建模时统一单位比如功率全部用kW成本全部用元SOC用0到1的标幺值。这样做不仅让ADMM的惩罚系数更稳定也方便调试时人工检查结果。求解器方面还有一个常见的坑Gurobi默认并行线程数可能吃满CPU所有核心在跑分布式迭代时如果每个子问题都抢占CPU反而会拖慢整体速度。可以用options.gurobi.Threads 2限制为双线程在多微网场景下整体效率更高。如果用的是非商用求解器比如SCS或OSQP需要注意它们对二次规划的处理能力较强但对混合整数二次规划支持不足。一旦模型里混入了二进制变量建议要么改回连续模型要么换Gurobi/Cplex。5.3 扩展思路多时间尺度、碳流追踪与在线部署最后聊聊这个项目的延伸方向。当前实现是单时间尺度的日前调度也就是24小时开环优化。真正落地到微电网群控制系统时还需要日内滚动修正环节——光伏出力预测误差大了要用模型预测控制MPC在15分钟级或分钟级窗口内重新优化。ADMMMPC的组合是当前学术界和工业界都比较认可的方向代码框架上只需在滚动窗口内重复执行现有的ADMM迭代即可。碳排放方面如果要做更精细的“碳流追踪”就要在ADMM迭代结果的基础上把每条联络线的功率来源拆解到具体的发电机组和储能然后再计算对应的碳排放因子。目前已有一些基于图论和矩阵运算的碳排放流计算方法配合ADMM的收敛结果可以在多微网场景下实现近实时的碳排放责任分摊。另外一个值得做的改进是完全去中心化。当前ADMM实现中还需要一个协调者角色来统计各微电网的平均交换功率。如果微电网数量多且通信拓扑不是全连接可以使用基于一致性协议的ADMM变体每个微电网只和邻居通信不需要中央节点鲁棒性更强。扩展的另一个方向是考虑储能寿命损耗。储能充放电的循环次数会直接影响电池衰减如果ADMM目标函数中只考虑电池的电量和功率约束而不计入衰退成本在长周期调度时可能高估储能的利用价值。这个可以通过在储能项中增加放电深度惩罚来实现对模型改动不大但结果会更贴近实际。最后说两句项目代码整体下来我最大的体会是ADMM本身不复杂三个更新公式半小时就能讲完难的是建模时把物理问题表达成合适的数学结构以及调试时对耦合变量符号、参数量级的敏感性。如果你准备复用这套代码建议按照“先跑通集中式模型 → 再改分布式分解 → 逐步加入碳约束”的顺序来做不要一上来就上完整版本。再分享一个小技巧在调试ADMM时把每一次迭代的交换功率曲线画出来做成动态图。肉眼看迭代过程中功率曲线怎么变化比只看残差数值更容易发现问题——如果两条曲线一直在“追尾”但始终不重合多半是符号方向或对偶变量更新公式写错了。这个小习惯帮我在后续几个项目里省下大量排查时间。