最近在折腾微电网调度这块接触了不少做新能源、储能和优化算法的同行大家聊得最多的除了“怎么让系统稳定运行”就是“怎么把碳排放和运行成本一起降下来”。我手里正好有一套三微网能量互联的优化调度Matlab代码目标是面向低碳经济运行多微网之间可以互相买卖功率同时引入碳交易成本用一个统一的目标函数去寻优最后输出各微网的调度计划、交互功率和碳排放情况。这篇文章就把整个模型的构建思路、Matlab实现细节、求解器选型、算例调试经验一次性说清楚给正在做相关课题或者毕设的朋友一个可以直接参考的样本。先说明白这套代码适合谁。如果你正在研究多微网、综合能源系统、低碳调度或者用Matlab做优化仿真那这篇内容正好对口。代码本身不算复杂核心是用线性化目标函数加约束借助Yalmip调用求解器求解不需要自己写复杂的优化算法。但如果你想换用粒子群、遗传算法等启发式方法我也会给出对比和注意点。更重要的是我会把建模过程中容易踩的坑比如碳配额怎么设、联络线功率怎么处理、储能SOC怎么防止越限全部拆开讲清楚。1. 问题重构为什么把“低碳”和“经济”放进一个目标1.1 多微网能量互联的价值与痛点单个微网规模小新能源波动大储能有限很容易出现“白天光伏多到用不完晚上又得高价买电”的尴尬局面。三个微网通过联络线连在一起之后A网富余的光伏可以卖给B网B网的储能可以帮C网扛一下晚高峰整体上降低了对外部电网的依赖也提高了新能源消纳率。这个逻辑听起来简单真要落地到优化调度里麻烦就来了谁和谁交易、交易多少、什么价格、储能怎么配合这些决策是相互耦合的。多微网的能量互联本质上是一个多主体优化问题但如果我们站在“统一调度者”的角度可以把它简化成一个集中式优化问题来处理。这套代码采用的就是集中式思路把三个微网的设备模型和交易关系全部纳入一个优化框架一次求解得到全局最优。1.2 碳交易机制如何引入调度模型低碳运行不能光靠口头约束得有一个经济信号把它们“指挥”起来。碳交易就是这样一个信号。常规做法是给每个微网分配一个碳排放配额实际碳排放低于配额就能把剩余额度卖出去赚钱高于配额就得花钱买配额。这样一来碳排放从“道德约束”变成了“成本项”微网在做调度决策时就会自然倾向于多用清洁能源、少用燃气轮机。具体的数学表达是将总碳排放量E_total与配额E_quota的差值乘上碳价λ_carbon加入目标函数。如果E_total E_quota这部分是负成本收益优化器会主动降低碳排放反之则是惩罚成本。这里有个关键点碳价设多少才合理如果太低优化器根本不在乎碳排结果等同于纯经济调度如果太高则会牺牲过多经济性。很多论文里都是直接把碳价设为常数简单有效但实际中建议做一个碳价灵敏度扫描看看调度方案怎么变。1.3 目标函数的构建逻辑这套代码的目标函数可以写成总运行成本购电成本燃料成本储能损耗成本碳交易成本最小化。注意我并没有把“低碳”单独列成一个目标而是把碳排通过碳交易机制折算成经济成本放进同一个目标函数。这样做的好处是单目标优化问题不存在权重调参的烦恼而且经济性和低碳性可以在同一个量纲下直接权衡。很多初学者喜欢写多目标比如“最小化成本和碳排放”然后用NSGA-II去算Pareto前沿也不是不行但实际工程中“碳价”本身就是一种权衡尺度比人为指定权重系数更符合碳市场逻辑。成本项里细说一下。从配网购电的成本是分时电价乘以购电功率售电给配网有售电价格一般低于购电价防止套利燃气轮机的成本可以用二次函数或线性分段表示储能的折旧成本可以折算成充放电功率的线性代价也可以忽略取决于你的研究侧重。碳成本刚才说了是碳排总量和配额的差额乘以碳价。把这几项加起来就是一个完整的低碳经济调度目标。2. 调度模型建模与约束体系2.1 微网内部结构假设与单元建模代码里每个微网都包含光伏PV、微型燃气轮机MT、储能ESS和负荷。光伏出力直接按典型日曲线给定不是预测值也就是我们做的是“确定性优化”。如果你想做不确定性可以考虑场景法或者鲁棒优化那是后话。燃气轮机的模型是输出功率范围在[P_mt_min, P_mt_max]爬坡约束限制相邻时段功率变化。碳排放模型就是燃气轮机的出力乘以排放强度系数再加一个微网购电对应的间接排放电网侧发电的碳排放光伏和储能视为零碳。这里的细节是微网购电的间接排放怎么算我用的方法是从主网购电量乘一个电网平均排放因子这个因子各地不一样代码里设的是0.583 kgCO2/kWh你可以自己改。储能模型采用最常用的一阶动态方程SOC(t1) SOC(t) - P_ch(t)·η_ch·dt P_dis(t)/η_dis·dt。充放电效率通常取0.95左右SOC范围[0.1, 0.9]。注意充放电不能同时进行这可以用互补约束或二进制变量实现。在Yalmip里用binvar定义充放电状态再加两个相邻时段的状态切换限制防止频繁启停这个在工程中很重要。2.2 互联功率交易建模三个微网之间两两存在联络线编号为1-2、1-3、2-3每条联络线有传输功率上限。交易变量P_link(i,j,t)有方向我定义正值表示从微网i流向微网j负值表示反向。为了统一每对微网只需要一个变量不需要正负两个变量加上上下限约束即可。比如-Pmax P_ij Pmax。交易价格怎么定这里有两种做法。一种是设一个内部交易电价比如取两个微网购电价格的加权平均这种模式只在目标函数里增加交易成本项。另一种是不设内部电价假设所有微网属于同一个运营商只考虑从主网购售电成本和设备成本互联功率本身不产生额外费用只需要满足功率平衡即可。我采用的默认方案是后者——因为内部交易只是功率分配总成本已经包含了各微网的实际支出如果再设内部电价就会重复计费。这一点很多新手容易绕晕。2.3 储能与可再生能源处理储能充放电状态用二进制变量建模但要注意Yalmip处理混合整数线性规划MILP时二进制变量的引入会使求解时间明显上升。24小时、3个微网、每个微网24个时段储能只有3×2472个二进制变量CPLEX处理非常轻松。但如果把调度时段扩展到96点或者加入更多二进制变量求解速度会慢很多到时候可以考虑用滚动优化或者松弛方法。光伏处理相对简单直接作为负的负荷接入功率平衡方程。这里有个常见疑问光伏能不能弃光在优化里弃光需要增加一个“光伏实际出力”变量而不是直接使用预测值然后约束实际出力小于等于预测值目标函数可以加入弃光惩罚如果不想主动弃光就把光伏出力固定为预测值这样系统必须消纳。我的代码里做了可弃光设计因为有些情况下为了减少向主网购电弃一点光伏反而能让储能更充裕地应对晚高峰甚至降低总成本。当然弃光本身是浪费所以加入了弃光惩罚系数让优化器非必要时尽量不弃。2.4 约束条件完整清单为了让你复现时不漏项我把这套模型的约束条件完整列出来各微网时段的功率平衡光伏出力 MT出力 储能放电 - 储能充电 外部购电 从其他微网收到的功率 - 向其他微网送出的功率 本网负荷。MT出力上下限约束和爬坡约束。储能SOC递推、SOC上下限、充放电功率限制、充放电互斥约束。联络线功率上下限以及两个方向的功率通过有界变量实现。各微网从主网购电和售电不能同时的约束如果允许同时优化器可能会低买高卖套利但现实中不允许所以用二进制变量或变量关系限制。碳排放计算约束碳排放量 MT发电碳排放 外购电间接碳排放碳交易成本 碳价 × (碳排放量 - 配额)。有读者会问联络线功率需要二进制变量吗不需要因为它是实数变量只要上下限约束就够了功率方向由正负号自然决定不需要表示方向状态。这和储能充放电不同储能充放电涉及效率不同且不能同时进行所以需要二进制。3. Matlab代码实现与求解器选型3.1 求解方案对比YalmipCPLEX还是自己写粒子群这套代码最初我用的是粒子群算法但后来改成了Yalmip调用求解器。原因很简单粒子群这类启发式算法处理24时段、3微网、含二进制变量的混合整数问题需要调很多参数而且收敛结果不稳定每次跑出来的调度方案不一样图表也难看。YalmipCPLEX则直接得到精确最优解代码量少调试方便。如果你的Matlab版本没有CPLEX也可以用Gurobi或者开源的CBC求解器Yalmip都支持。这里强调一下不是所有问题都适合用MILP求解器。你的目标函数如果是非线性比如MT成本二次函数Yalmip也能处理可以转换成二次约束二次规划QCQP或者用分段线性化近似。这套代码里我把燃气轮机成本近似为分段线性函数整体模型就是MILP求解稳定、快。3.2 代码结构设计数据、模型、求解、绘图一份能用的调度实验代码至少要包含四个模块参数数据模块、模型构建模块、求解与结果处理模块、画图模块。我通常这样组织main.m——主脚本负责启动求解和输出关键结果。data_para.m——存放微网数、时段数、负荷曲线、光伏曲线、分时电价、碳价、设备参数、联络线参数等。model.m——Yalmip建模定义变量、约束和目标函数。solve_and_plot.m——调用求解器处理结果绘制功率平衡图、SOC图、碳排放柱状图等。在实际学习时建议把参数集中放在一个结构体里比如para struct(...)这样后续做扫参数实验很方便。不要把所有参数散落在主脚本各处改起来容易出错。模型构建的核心是利用Yalmip铁三角sdpvar定义变量、约束集合赋值、objective定义目标函数。接着调用optimize(Constraints, objective, sdpsettings(solver,cplex))。需要留意一下如果没用Yalmip就得手写矩阵形式的线性规划或整数规划那会很痛苦。我强烈建议用Yalmip它让优化建模像写数学公式一样直接。3.3 关键代码段解读下面展示模型构建里最核心的几段代码摘录自能直接运行的脚本你可以从中看出建模套路。首先定义变量。PPV和PLoad是已知数据不需要定义变量。MT出力、储能充放功率、从主网购售电量、联络线功率都是变量。% 时段和微网数量 T 24; N 3; % 决策变量 P_MT sdpvar(N, T, full); % 燃气轮机出力 P_ch sdpvar(N, T, full); % 储能充电功率 P_dis sdpvar(N, T, full); % 储能放电功率 SOC sdpvar(N, T1, full); % 储能SOC注意多一个初始时刻 P_buy sdpvar(N, T, full); % 从主网购电 P_sell sdpvar(N, T, full); % 向主网售电 P_link sdpvar(3, T, full); % 联络线功率3对应三条线 u_ch binvar(N, T, full); % 充电状态 u_dis binvar(N, T, full); % 放电状态注意“full”参数在Yalmip新版本中已经不需要但加上也无妨。SOC定义N×T1是因为我们需要初始SOC方便迭代。接下来约束条件我挑几个典型的。储能的充放电互斥约束Constraints [Constraints, u_ch u_dis 1]; Constraints [Constraints, 0 P_ch P_ch_max .* u_ch]; Constraints [Constraints, 0 P_dis P_dis_max .* u_dis];这里利用二进制变量把充放电功率钳制为0。如果不用二进制变量完全可以写成 P_ch P_ch_max * u_ch 这种形式Yalmip支持变量相乘最终会线性化吗不行二进制与连续变量乘积是双线性项所以必须用“Big-M”技巧不过Yalmip会自动识别这种约束模式并转换为线性不等式。其实更稳妥的写法是上面的形式Yalmip和求解器都能处理。SOC演化约束Constraints [Constraints, SOC(:, t1) SOC(:, t) P_ch(:, t) * eta_ch * dt - P_dis(:, t) / eta_dis * dt];这里eta_ch和eta_dis分别是充放电效率dt在小时单位下为1。注意充放电功率和SOC单位需要保持一致如果功率是kW时段是1h则能量增减就是kWh。功率平衡约束Constraints [Constraints, P_MT P_PV P_dis - P_ch P_buy - P_sell ... P_link_in - P_link_out P_load];具体实现时P_link_in和P_link_out需要根据三条线的连接关系累加。比如微网1收到的互联功率 P_link(1, t) P_link(3, t)约定线1为1-2线2为1-3线3为2-3微网1送出的互联功率 P_link(1, t) P_link(2, t)。注意这里正负号要根据方向定义来。我在代码里使用了一个简单的“连接矩阵”避免手工写错。目标函数也很直观total_cost sum(sum(P_buy .* repmat(price_buy, N, 1))) ... - sum(sum(P_sell .* repmat(price_sell, N, 1))) ... sum(sum(P_MT)) * mt_cost_coef ... % 简化线性成本 carbon_cost * max(0, total_emission - quota); % 注意max函数会导致非线性这里有个大坑carbon_cost * max(0, total_emission - quota) 是非线性的因为max不可导且不是线性的。Yalmip处理max(0,x)可以通过引入辅助变量m约束 m 0, m total_emission - quota目标函数里用m代替max(0,...)。也就是说碳交易成本需要线性化m sdpvar(1,1); Constraints [Constraints, m 0, m total_emission - total_quota]; total_cost ... carbon_price * m;这样才是标准的MILP。很多初学者直接写max就会导致求解器报错或者使用不支持的模型。这个细节一定要记住。总排放量怎么算它是MT排放和外购电排放之和total_emission sum(sum(P_MT * mt_emission_factor)) sum(sum(P_buy * grid_emission_factor));配额可以设为一个常数比如各微网配额总和也可以按每个微网的历史排放比例分配。代码里用的是总配额因为我们是集中式调度只看整体碳交易成本。4. 算例分析与调参心得4.1 三微网算例参数设定我选了一个典型夏季日做测试。三个微网微网1是工业负荷为主白天负荷高微网2是商业负荷白天和傍晚双高峰微网3是居民负荷晚高峰明显。光伏装机分别为800kW、600kW、400kW。燃气轮机容量均为500kW储能容量均为1000kWh最大充放电功率200kW初始SOC为0.5。分时电价设置为峰、平、谷三段峰时1.05元/kWh平时0.65元/kWh谷时0.35元/kWh。售电价统一为0.45元/kWh。碳配额设为总排放需求的一个比例比如初始设为不约束的宽松值再慢慢调紧。MPTMicrogas Turbine成本系数取0.6元/kWh碳排放强度0.8 kgCO2/kWh电网排放因子0.583 kgCO2/kWh。碳价初始取0.1元/kgCO2也就是100元/吨。4.2 典型日调度结果解读跑完优化后我习惯先看三个微网的功率平衡堆叠图。从结果来看夜间谷时段三个微网都会从主网购电给储能充电同时压低燃气轮机出力。白天光伏大发时微网1和微网2除了满足自身负荷外会把多余功率通过联络线送给微网3因为微网3光伏容量小。傍晚时段微网1燃气轮机会满发同时从主网购电而微网2则优先用储能放电减少高价购电。微网3由于负荷峰值高除了本地电源外还会从微网1和微网2购电。值得注意的是在碳价为0.1元/kg时调度结果其实和纯经济调度差别不大因为碳成本在总成本中占比较小。只有当碳价提高到0.4元/kg以上时燃气轮机的出力才明显下降光伏弃光率也开始降低因为要优先用清洁能源替代火电部分时段甚至会牺牲一点经济性选择更低碳的方案。这个现象说明碳价信号确实能引导低碳调度但需要达到一个阈值。储能SOC曲线呈现“谷充峰放”的典型形态但三个微网的行为略不同。微网1的储能容量利用率最高因为工业负荷平稳微网3居民负荷集中储能往往在晚高峰前放空之后就只能靠购电。这个差异提示我们储能配置不能一刀切在多微网场景下可以通过互联功率“借”储能容量比如微网1的储能傍晚给微网3供电整体削峰效果更好。4.3 灵敏度分析与碳价影响我做了一组碳价扫描从0.05到0.6元/kg步长0.05观察总成本、总碳排放和联络线利用率的变化。结果发现随着碳价升高总碳排放近似线性下降但总成本先增加后趋于平缓因为高碳价迫使某些时段从燃气轮机切换到外购电如果外购电排放因子相对较低。另外联络线的平均功率交换量随碳价升高而增大说明互联通道在低碳调度中扮演了更重要的角色——高碳价下微网更倾向于利用互联功率“搬运”清洁能源而不是本地火电支撑。如果你在写论文这一组灵敏度分析往往是审稿人喜欢的点。我建议你拿到代码后把碳价循环起来跑把结果导出成表格然后画一张“碳价-成本-碳排放”双y轴图这个图非常有说服力。还有一个值得做的实验是把碳配额从宽松调到紧张。宽松配额相当于没有碳约束紧张配额会让总排放必须下降调度结果会发生结构性改变储能充电量增加、联络线功率峰值明显上升、燃气轮机基本处于关停或最小出力状态。这种“配额紧缩”实验能充分体现低碳调度模型的应对能力。4.4 常见报错与排查技巧我在调试过程中踩过不少坑下面列几个最典型的给你提前排掉。报错Solver not applicable or unsupported.这通常是因为模型包含了非线性项比如max函数、绝对值、双线性项。解决办法是像上面那样用辅助变量线性化。检查的方法是在调用optimize之前运行disp(export(Constraints))或者直接看Yalmip报错提示是MILP还是NLP。如果你的目标含有平方项且求解器是CPLEX它会尝试处理为二次约束但如果不支持就会报错。报错Infeasible problem.无解。先检查功率平衡约束是不是写错了符号特别是联络线功率的正负方向。我第一次建模时就是符号搞反导致某些时段所有微网都“缺电”或无解。排查技巧把约束逐条注释掉看哪条导致无解。或者把目标函数设为零常数只找一个可行解来判断约束之间的矛盾。另外SOC的初始值或范围设置不当也可能导致无解比如初始SOC 0.9但第一时段强制放电就很容易冲突。储能充放电同时进行的bug。如果不用二进制变量互斥求解器会在某些峰谷差大的时段安排同时充放电这显然不合理。加上u_ch u_dis 1之后这个现象就消失了。联络线功率越限或方向不一致。三个微网之间有三条联络线很容易在写功率平衡时重复计算。我的建议是设一个连接矩阵link_matrix [0 1 1; 1 0 1; 1 1 0]三个微网全互联然后在计算微网收到的互联功率时直接用矩阵运算。这样即使以后改成4个微网代码也能自动拓展。求解时间过长。如果你加了储能启停约束就是限制一天内储能只能启动K次这个约束是相邻时段状态变化的约束会引入更多二进制变量24时段下求解时间可能从几秒变成几分钟。可以先用不考虑启停次数的版本跑通再加这个约束。如果真需要可以设置sdpsettings(cplex.mip.limits.timelimit, 120)给一个最高时限超时取可行解。Yalmip版本问题。新版Yalmip中sdpvar函数名称不变但提醒级信息很多可以用solvesdp替换一些旧函数其实新版推荐用optimize旧代码可能大量使用solvesdp如果遇到函数缺失统一替换成optimize即可参数格式略有差别但一般不重要。5. 从代码到论文/项目的拓展建议如果你手头已经有这套三微网调度代码但希望在论文中做出新意有几个方向值得尝试。首先是不确定性处理。目前光伏和负荷是确定性曲线实际中会有预测误差。你可以用场景法生成若干典型场景用随机优化或两阶段鲁棒优化把场景集合放进约束里。这个过程可以在Yalmip中实现只是约束数量会线性增加。风电和光伏的预测误差通常假设为高斯分布或Beta分布可以从这个角度完善。其次是多目标扩展。虽然我认为碳交易单目标更贴合现实但论文评审往往期待你提供Pareto前沿。你可以在碳价扫描的基础上绘制碳排放-成本Pareto近似曲线这种曲线其实就是不同碳价下得到的解点连线理论上它们构成Pareto前沿的近似。这个方法非常简单只需要把每次碳价求解的结果记录下来。严格意义上的多目标算法当然也可以跑但结果的稳定性和可解释性反而不如单目标参数扫描。然后是分布式求解。三个微网集中式调度虽然全局最优但现实中各微网通常属于不同运营主体不愿意共享全部数据。你可以把模型改写成分布式优化使用ADMM算法将互联功率作为耦合变量进行迭代求解。这个方向的Matlab代码量会大不少但非常吸引人。如果你时间充足建议先跑通集中式再用ADMM复现同一个算例对比收敛性和最优间隙。我在实际测试中ADMM的参数rho和步长对收敛速度影响很大需要花一点心思调。最后是碳交易机制扩展。目前是统一的碳价你可以考虑阶梯碳价、碳配额拍卖、绿证交易等更细化的机制。比如阶梯碳价是指碳排放超过配额一定比例后超出部分碳价上浮一个台阶。这种机制会导致目标函数分段线性但Yalmip依然能手到擒来只需要多引入几个分段辅助变量。这套代码改到现在我最大的体会是多微网优化调度的核心难点并不在求解算法本身而在于把复杂物理特性和市场规则转成精确的数学模型。碳交易也好、储能约束也好每一个“花哨”的机制最后都要落到一个个不等式中。Matlab配合Yalmip的价值就在于它能让你把注意力集中在“如何建模”而不是“如何写求解器”上。我建议所有做这块研究的朋友先去亲手把三微网模型写一遍别急着换高级算法跑通一个带碳交易和联络线约束的MILP你对整个问题的理解会完全不一样。代码里那些参数碳价、配额、联络线容量、储能容量建议多扫描几组你会发现系统行为经常出乎意料而这也正是调度研究的乐趣所在。