算例数据、Matlab代码、求解器调试这些方向已经有不少人问过我。多微网互联调度这个方向,不算特别前沿,但确实是当下电力系统优化里特别实用的一块——尤其现在大家都盯着“双碳”目标,碳排放不再是论文里的装饰词,而是实实在在进入了目标函数。这次我把一套三微网能量互联低碳经济调度模型的完整思路、建模过程、Matlab实现和踩坑记录整理出来,给正在做或准备做类似课题的朋友一个可以直接抄作业的参考。
先说清楚这个项目到底在做什么。所谓多微网,就是多个微电网通过联络线连成一个微网群,彼此之间可以互相输送电力。相比单个微网独立运行,互联之后能实现功率互济、容量共享,比如A微网中午光伏大发用不完,B微网晚高峰缺电,两者通过联络线就能把富余电量送过去,而不必全部卖给大电网再买回来。低碳运行则是在调度决策时把碳排放量或碳交易成本放进优化目标,让系统不只盯着“电费最少”,而是同时权衡运行成本和环境成本,找到真正的经济-环保平衡点。
这个项目适合谁看?正在做微电网/综合能源系统优化调度方向毕业设计、课程设计、科研论文的同学,以及刚接触YALMIP+Cplex这类优化建模工具的初学者。下面我把模型怎么建、代码怎么构、坑怎么避,按我实际做过的流程完整走一遍。
1. 多微网能量互联:单个微网的困境与互联的价值
1.1 单微网运行的“天花板”在哪里
单微网独立运行,本质上是“自己跟自己玩”。每个微网内部有分布式电源(光伏、风电、燃气轮机)、储能、负荷,调度时只需要满足本网内部的功率平衡。听起来简单,但实际跑起来问题不少。
第一个问题是净负荷波动大。光伏和风电出力随风、光变化,负荷也在变,两者相减得到的净负荷曲线尖峰明显。为了保证供电可靠性,微网必须在净负荷高峰时段留出足够备用,或者从大电网买电。而高峰期买电通常电价也高,运行成本直接上涨。
第二个问题是弃风弃光。分布式新能源装机容量往往按最大负荷来配,但光伏大发时段负荷未必同步升高,尤其春秋季中午,光伏出力超过负荷+储能充电能力的概率不低,多出来的电只能扔掉。单独一个微网,储能容量有限,弃电问题很难靠自身消化。
第三个问题是对大电网的依赖。单微网跟主网的交互是单向的、点对点的,电价只能被动接受,没有议价空间。一旦主网出现故障或电价飙升,微网内部的应对手段非常有限。
这些问题在单个微网内部通过扩大储能、优化DG配置可以缓解一部分,但边际收益越来越低,投资成本却持续上升。多微网互联提供了一个新的自由度:让功率在微网之间横向流动起来。
1.2 能量互联的本质:让功率在微网之间流动起来
多微网互联的核心思想是系统间的功率互济。典型结构是三个微网通过公共母线或各自的联络线连接,形成微网群。每个微网仍然保留对内部设备的调控权,但可以跟其他微网进行功率交换。
互联带来的实际收益体现在四个方面。
一是削峰填谷。A微网在午后光伏富余,B微网在傍晚负荷高峰,通过联络线把A的电送往B,可以让两个微网都不用过度依赖储能或主网购电,整体购电成本下降。
二是提高新能源消纳率。某微网光伏大发时,如果自己储能满了、负荷也顶不上,与其弃电,不如把电卖给邻居。这相当于把整个微网群范围内的负荷看作一个更大的“吸收池”,分布式新能源的消纳空间被显著放大。我实测的三网互联案例中,把原有单网26%左右的弃电率压到了7%以内,效果非常直观。
三是降低对主网的功率需求。通过内部互济满足部分功率缺额之后,微网群从主网购电的峰值功率会下降。这对容量费用、需求响应考核都有直接好处。
四是提升整体可靠性。某微网内部故障导致出力中断时,其余微网可以通过联络线增供功率,相当于一种互为备用的机制,单个微网不需要为小概率故障预留过高的备用容量。
不过在建模时要明白,互联不是“免费的午餐”。联络线的功率传输有容量上限和线损,微网之间的交易需要结算机制,这些都必须在模型中体现出来,否则优化结果会过于乐观,脱离实际。
1.3 三网互联拓扑的典型方案
从工程实现和论文写作的角度看,三微网互联有几种常见的拓扑选择。
独立母线互联方案是三网通过公共交流母线直接相连,每个微网通过一台联络开关或变压器接入母线,等效为一个三端节点。这种结构建模最方便,联络线功率约束可以直接写成每个微网注入母线的功率总和为零,母线电压用单节点近似处理,适合大多数课堂和论文场景。
环形拓扑是三网两两互联,形成环状结构。优点是任一连线故障时功率仍可迂回传输,可靠性高,但模型需要处理更多的联络线变量和网络约束,求解规模明显增大,适合作为研究性课题的延伸方向。
链式拓扑是三网按“微网A—微网B—微网C”顺序串联。中间微网B扮演功率中继的角色,两侧微网不能直接交易,必须经B转发。这种拓扑更接近实际配电网尤其是校园、园区的接线方式。建模时要额外处理B的中继功率,也就是B的进出口功率分别约束。
我实际用的是独立母线方案,原因很直接:模型简洁、约束清晰、YALMIP建模不用写复杂的网络潮流方程,而且完全能说明“互联带来收益”这个核心结论。做深入分析时再往环形或链式扩展也容易。
2. 低碳经济运行目标建模:成本与碳排放在一个模型里说话
2.1 目标函数拆解:运行成本、碳交易成本与弃电惩罚
优化调度的目标函数决定了系统会“往哪个方向跑”。本项目是低碳经济运行,目标函数必须把经济性和低碳性都放进来。我用的目标函数是调度周期内总成本最小化,总成本包含五项。
第一项是常规运行成本,包括燃气轮机燃料成本、运维成本和启停成本。燃气轮机的燃料成本通常写成出力P的二次函数:C_fuel = aP^2 + bP + c,其中a、b、c是燃料成本系数。二次项本质上是效率随负荷率变化的体现,低负荷率时单位发电成本更高。处理方式有两种,一是原样保留形成非线性规划(NLP),二是分段线性化后用混合整数线性规划(MILP)求解。追求求解速度和全局最优性时选后者,我后面细说。
第二项是与主网的交互成本。从主网购电按分时电价支付费用,向主网售电按上网电价获得收入。这个交互项同时承担了微网群的“外部资源平衡”角色,是成本敏感度很高的一项。
第三项是碳交易成本。这是低碳目标落地的关键。主流做法是基准线法:给微网群分配免费碳排放配额,实际排放超过配额的部分需要到碳市场购买,低于配额则可以出售获利。设实际碳排放量为E,免费配额为E0,碳交易价格为λ,那么碳交易成本就是:
C_carbon = λ * (E - E0)
当E < E0时C_carbon为负,也就是系统通过减排获得了收益,这会在目标函数中变成“负成本”,直接引导优化器主动降低排放。碳排放主要来源于燃气轮机燃烧和从主网购电对应的间接排放(主网购电按电网平均排放因子折算),光伏、风电、储能运行按零排放处理。这样处理简洁,也符合当前主流研究的习惯。
第四项是弃风弃光惩罚成本。为什么加了这一项?因为单纯看运行成本时,系统可能选择把多余新能源弃掉而不是通过储能或互联线路消纳——如果储能效率损失的成本比弃电惩罚还高的话。引入弃电惩罚项后,能模拟“优先消纳新能源”的政策导向。惩罚系数不必取很大,但要比向外买电或弃电损失高,才能起到引导作用。
第五项是微网间交易成本(可选)。如果算例设置了内部结算电价,就在目标函数中增加微网A向微网B购电的支付项。注意这属于内部转移支付,总成本会包含这笔钱,但从微网群整体角度看它最终是内部抵消的。如果不做博弈分析、只关心整体最优,可以不加,让互联功率按互相免费的假设处理,计算更简单。
完整的目标函数可以写成:
min F = Σ_t Σ_i [ C_fuel(P_gt) + C_om(P) + C_grid(P_grid) + C_carbon(E) + C_curtail(P_curtail) ]
下标i表示第i个微网,t表示第t个调度时段,一般取24小时,步长1小时。调度步长也可以取15分钟,精度更高,但求解规模会变成原来的4倍,算力消耗明显增加。没有特殊要求时我通常先用24点建模,逻辑清楚后再加密时间尺度也不迟。
2.2 约束条件:该管住的物理边界
约束条件构成了优化问题的“可行域”,少了哪条,结果就可能跑出物理上不可能的值。模型里必须写全的约束有六类。
功率平衡约束是每条母线、每个时刻都必须满足的“能量守恒定律”。对每个微网:
P_pv + P_wt + P_gt + P_discharge + P_line_in - P_charge - P_line_out = P_load
其中P_pv和P_wt是预测得到的新能源出力,P_discharge和P_charge是储能放电和充电功率,P_line_in和P_line_out是微网间联络线的注入和送出功率。如果某些时段允许切负荷,还需要引入切负荷变量,并把切负荷量也放进平衡方程。
联络线容量约束描述的是物理传输上限:
-P_line_max ≤ P_line ≤ P_line_max
这里P_line是正负可变的,约定正方向为输出。对于独立母线拓扑,还要加一个母线功率平衡约束:所有微网注入母线的功率之和为零,数学上表现为 Σ P_line_i = 0。
储能约束包括三条:SOC递推方程、SOC上下限约束、充放电功率限制。SOC递推离散形式为:
SOC(t+1) = SOC(t) - P_charge(t)η_cΔt/E_cap + P_discharge(t)Δt/(η_dE_cap)
习惯上把充电时SOC上升定义为正,放电定义为负,但不同文献符号约定不一,自己写代码时务必统一,否则符号反了会直接导致储能永远不工作。
燃气轮机约束有出力上下限、爬坡约束和最小启停时间约束。爬坡约束是相邻时段功率变化不能超过爬坡率,最小启停时间涉及机组启停状态和整数变量,如果做简化分析可以暂时忽略启停约束,只保留出力上下限和爬坡,模型求解难度会下降不少。但对于有实际机组组合需求的场景,启停时间约束不能省。
主网交互约束是每个微网与主网的交换功率上限,防止优化器通过无上限的购售电来绕过内部平衡。下式同时限定购电和售电功率必须非负且不大于对应上限。
最后是低碳相关的碳排放计算约束。碳排放量由燃气轮机出力和购电量线性计算:
E_total = Σ_t Σ_i [ e_fuel * P_gt(i,t) + e_grid * P_buy(i,t) ]
其中e_fuel和e_grid分别为单位气电、购电碳排放因子。这个约束可以直接代入碳交易成本公式,形成目标函数中的线性项。
2.3 低碳目标怎么“翻译”成数学语言
把“低碳”从口号变成可优化的数学表达式,本质上就是给碳排放定价。碳交易机制解决这个问题最方便,因为它天然是线性的,不引入非线性项,MILP求解器处理起来毫无压力。
有一个容易踩的细节:如果直接用C_carbon = λ*(E-E0),而E和E0是固定值,目标函数里会出现负数项。负成本本身没问题,因为它代表卖碳配额的收入。但如果E0设置得太高,系统可能通过卖配额赚取远超实际电量交易利润的收益,导致结果失真。通常把E0设置为调度周期内预测排放量的一个比例,或按历史数据标定,不要拍脑袋给一个超大值。
另外要区分“低碳调度”和“碳捕集调度”。前者是对已有碳排放源做运行层面的优化,选择排污少的机组、提高新能源出力占比;后者是引入碳捕集设备,改变排放量本身。本文模型属于前者,如果你后续要把碳捕集装置也纳入系统,目标函数还需要增加捕集能耗、捕集成本和储液罐状态等变量,模型复杂度显著提升,但方向上是兼容的——只需要在碳排放计算中加入捕集量扣除项。
3. 求解算法选型与Matlab实现
3.1 为什么优先选MILP而不是纯启发式算法
优化调度问题可以用两类方法求解:精确算法和智能优化算法。我强烈建议,只要能建模成MILP就优先用MILP,理由很实在。
MILP的解有全局最优性保证。分支定界法从数学上确保找到的解是最优解,或者给出最优性gap。而粒子群、遗传算法、灰狼优化这类启发式算法本质上是随机搜索,每次运行结果可能不同,无法证明当前解是不是全局最优,论文审稿人问到“你的解和全局最优差多少”时很难回答。
MILP的求解速度在中小规模问题上足够快。三微网24时段的调度模型,决策变量几百个,整数变量几十个,用Cplex或Gurobi通常几秒到几十秒就能收敛到gap在0.1%以内的解,比写一个精心调参的PSO还要快。而且不需要反复调种群大小、惯性权重、学习因子这些参数——这些参数调起来非常费精力,换一个算例可能又要重调。
MILP有成熟的商业求解器支撑。Cplex、Gurobi这些工业级求解器经过十几年的优化,数值稳定性、预处理能力都远超自己手写的P SO或GA,尤其是处理大规模约束时不容易出现数值病态问题。
启发式算法什么时候上场?一是问题存在强非线性(比如气网潮流方程、AC潮流方程)且难以线性近似时;二是你本身就在研究如何使用某种智能算法,算法创新才是论文的核心贡献时;三是模型里带有复杂的随机因素需要嵌套仿真时。除此之外,直接用MILP最稳妥。
3.2 YALMIP+Cplex搭建求解框架
Matlab里搭MILP的推荐组合是YALMIP + Cplex或Gurobi。YALMIP是一个建模工具箱,它把Matlab的符号变量、约束和目标函数转换成求解器要求的标准形式,你不用手写每个系数矩阵,代码非常简洁,可读性也高。Cplex是底层求解器,负责真正求解MILP问题。
安装方面提醒三点。Cplex不需要自己装,在YALMIP里设置好路径即可,但需要先安装IBM ILOG Cplex,并把cplex根目录的cplexlp.mexw64文件路径和马事的interfaces文件夹加进Matlab路径。Gurobi同样需要在官网申请学术许可,安装后指定路径。此外,如果只是学习建模,YALMIP自带的bnb或gurobi mex也可用,但性能会差一些。求解之前一定要用yalmiptest命令验证安装是否成功,并确保Matlab与求解器版本兼容。某些新版本Matlab(比如2023a之后)在设置接口时容易出现附加路径问题,安装完记得在命令行先跑一个简单LP验证环境是否正常。
3.3 核心代码实现与参数设置
下面给出基于YALMIP+Cplex的三微网24小时低碳调度核心代码。参数数据是我自己构造的简化版,具体数值要根据实际算例调整。
%% 主程序:三微网低碳经济调度 clear; clc; T = 24; % 调度时段数 N = 3; % 微网数量 %% 参数定义(简表,实际使用时应从excel读取) % 光伏出力标幺值序列 pv_pu(1:T) 假设已知 pv_pu = 0.1 + 0.8 * sin(pi * (0:T-1) / 24).^2; % 午间峰值 load_profile = [ones(1,6) 0.8*ones(1,6) 1.2*ones(1,6) 1.1*ones(1,4) 0.9*ones(1,2)]; load_base = [60, 50, 55]; % 各微网基础负荷/kW E_cap = [200, 150, 180]; % 储能容量/kWh SOC_min = 0.2; SOC_max = 0.9; eta_c = 0.95; eta_d = 0.95; P_line_max = 30; % 联络线最大功率/kW % 碳交易参数 lambda = 30; % 碳价/元/吨 E0_percent = 0.9; % 配额为预测排放的90% e_fuel = 0.2; % 燃气轮机排放因子 kg/kWh e_grid = 0.6; % 电网排放因子 kg/kWh %% 决策变量 P_gt = sdpvar(N, T); % 燃气轮机出力 P_buy = sdpvar(N, T); % 购电 P_sell = sdpvar(N, T); % 售电 P_ch = sdpvar(N, T); % 储能充电功率(正) P_dis = sdpvar(N, T); % 储能放电功率(正) SOC = sdpvar(N, T+1); % SOC状态 P_line = sdpvar(N, T); % 联络线注入母线功率(正为注入) P_curt = sdpvar(N, T); % 弃风弃光功率 %% 变量边界约束 Constraints = []; Constraints = [Constraints, 0 <= P_gt <= 100*ones(N,T)]; Constraints = [Constraints, 0 <= P_buy <= 100*ones(N,T), 0 <= P_sell <= 100*ones(N,T)]; Constraints = [Constraints, 0 <= P_ch <= 30*ones(N,T), 0 <= P_dis <= 30*ones(N,T)]; Constraints = [Constraints, P_line_max*ones(N,T) >= P_line >= -P_line_max*ones(N,T)]; Constraints = [Constraints, SOC_min*ones(N,T+1) <= SOC <= SOC_max*ones(N,T+1)]; Constraints = [Constraints, P_curt >= 0]; %% 母线功率平衡(各微网注入母线的功率总和为0) Constraints = [Constraints, sum(P_line,1) == 0]; %% 储能SOC递推与功率关系 for i = 1:N for t = 1:T Constraints = [Constraints, ... SOC(i,t+1) == SOC(i,t) + (P_ch(i,t)*eta_c - P_dis(i,t)/eta_d) / E_cap(i)]; Constraints = [Constraints, P_ch(i,t) + P_dis(i,t) <= 30]; % 充放电不同时 end end %% 功率平衡(含弃电变量) P_pv = pv_pu' * load_base(1); % 转成N*T维度的一部分 % 简化:三个微网光伏出力按相同模式、不同峰值 P_pv_full = repmat(pv_pu, N, 1) .* repmat([40;35;30], 1, T); load_full = repmat(load_profile, N, 1) .* repmat(load_base', 1, T); Constraints = [Constraints, ... P_pv_full + P_gt - P_buy + P_sell + P_dis + P_line == ... load_full + P_ch + P_curt]; %% 碳排放计算 E_total = sum(sum(e_fuel * P_gt + e_grid * P_buy)); E0 = E0_percent * E_total; % 注意:这里E0依赖于变量E_total,需改写法,见下 %% 改进:将碳交易成本线性化,避免E0嵌套 % 定义免费配额为固定值E_alloc,由预测排放估算 E_alloc = 0.9 * sum(sum(e_fuel * load_base' + e_grid * mean(load_base))) * T * 0.3; C_carbon = lambda * (e_fuel*sum(P_gt(:)) + e_grid*sum(P_buy(:)) - E_alloc); %% 目标函数:运行成本 + 碳交易成本 + 弃电惩罚 C_gt = 0.02 * sum(P_gt(:)) + 5 * sum(P_gt(:).^2)/1000; % 简化二次成本 C_grid = sum(sum(0.8 * P_buy)) - sum(sum(0.4 * P_sell)); C_curtail = 2 * sum(P_curt(:)); Objective = C_gt + C_grid + C_carbon + C_curtail; %% 配置求解器 ops = sdpsettings('solver', 'cplex', 'verbose', 2, 'debug', 1); ops.cplex.mip.tolerances.mipgap = 1e-4; % 设定求解精度 %% 求解 OptimizeResult = optimize(Constraints, Objective, ops); if OptimizeResult.problem == 0 disp('求解成功'); else disp('求解失败'); disp(OptimizeResult.info); end %% 结果提取与画图 P_gt_val = value(P_gt); P_buy_val = value(P_buy); P_line_val = value(P_line); SOC_val = value(SOC); F_val = value(Objective); figure; subplot(2,1,1); bar(P_gt_val'); hold on; plot(sum(P_buy_val,1), 'r-o'); legend('燃气轮机出力','购电量'); title('三微网购电与燃气轮机出力'); subplot(2,1,2); stairs(SOC_val(1,:)); hold on; stairs(SOC_val(2,:)); stairs(SOC_val(3,:)); legend('MG1','MG2','MG3'); title('储能SOC变化曲线');有几个地方要特别说明。
第一,代码中E_alloc写成常数,不要写成跟E_total绑定的动态表达式。上面我在注释里已经提醒:如果用E0_percent*E_total会让E0跟着决策变量走,形成一个可变配额,优化器可以偷偷增大排放来抬高配额,结果完全失真。正确做法是先按预测数据估算基准排放,再固定E_alloc,这就是最常用的“基准线配额固定法”。
第二,充放电不同时约束用P_ch + P_dis <= P_rate表达。严格来说还必须引入0-1变量做互补约束(充电和放电不能同时发生),但储能效率的存在会让同时充放电在成本上不划算,所以只要加了总功率限制,优化器自然倾向于不同时充放电。这个技巧能少加几个整数变量,求解更快。如果你要求非常严格,可以用binvar(u_i)且P_ch <= u_i*P_rate、P_dis <= (1-u_i)*P_rate,不过对大多数场景没必要。
第三,二次成本项的线性化处理。代码里C_gt写成了sum(P_gt(:).^2)/1000,这会让问题变成二次规划(QP)。Cplex支持MIQP,但求解速度不如MILP。更简单的办法是直接把燃料成本近似为线性:C_gt = k * P_gt,这在论文中通常表述为“采用分段线性化燃料成本”,精度完全够用。
第四,功率平衡方程里我把P_buy和P_sell都写成正数,物理含义不同,这样做的好处是不需要额外的互补约束。不过要注意P_buy和P_sell同时非零在经济上不优(同一时刻既买又卖是不合理的”,所以不额外互斥变量也没问题,优化器会自动避开这种操作。
3.4 算法扩展:PSO/GWO的兜底方案
如果模型的非线性项不好线性化,或者课题方向就是智能优化算法,那需要一套备用方案。以粒子群为例,可以这样做。
先定义粒子的位置向量为所有连续决策变量的拼接——包括P_gt、P_buy、P_sell、P_ch、P_dis的24时段值。每个粒子的维度为 5个变量 × 3个微网 × 24小时 = 360维。这么高的维度,PSO的搜索效率其实很受质疑,所以更常见的做法是分层优化:上层用PSO/GWO优化燃气轮机出力和联络线功率,下层用线性规划或解析法求储能的充放电策略,这样把非线性和线性部分解耦,算法收敛速度明显提升。
无论用哪种启发式算法,功率平衡约束都要作为罚函数处理进适应度函数。罚因子太小会让解落在不可行域,太大会让惩罚项淹没目标函数、搜索不到最优。我的经验是罚因子取目标函数量级的5到10倍比较稳妥,先跑一次试算,查看罚项占比是否在可接受范围内。
启发式算法的另一个痛点是结果不稳定。建议每种算法独立跑20次以上,统计最好解、平均解和方差,并跟MILP结果对比。如果MILP解是1000元,PSO最好解是1100元但平均是1400元,你至少知道算法离最优还有多远。多数情况下,这个对比会成为论文里很有说服力的一张表。
4. 三微网算例设计与结果分析
4.1 算例基础数据
构造算例时,我选用一个典型园区型三微网系统。三个微网分别记为MG1、MG2、MG3,配置如下:
- MG1:光伏40kW,燃气轮机100kW,储能200kWh,基础负荷60kW,办公楼用电模式,白天高峰,夜间低谷。
- MG2:光伏35kW,燃气轮机80kW,储能150kWh,基础负荷50kW,工业负荷模式,白天平稳偏高,夜间降低。
- MG3:光伏30kW,燃气轮机100kW,储能180kWh,基础负荷55kW,居民负荷模式,晚高峰明显。
光伏出力采用季节典型日曲线,夏季中午峰值可达额定值的90%左右。分时电价设置:峰段(8:00-11:00,18:00-23:00)1.1元/kWh,平段0.7元/kWh,谷段0.35元/kWh。上网电价统一0.4元/kWh。碳价为30元/吨,免费配额按基准排放的90%计算。联络线容量设为30kW,燃气轮机碳排放因子0.2kg/kWh,电网购电碳排放因子0.6kg/kWh。
4.2 典型场景仿真结果
以夏季典型日为例,仿真结果呈现几个明显特征。
午后13:00左右,MG1光伏出力达到峰值,本地负荷只有约70%左右,储能SOC接近上限,此时MG1通过联络线向MG2和MG3输送功率,弥补MG3的晚峰前部分负荷。对比不互联场景,MG1的弃电量从约85kWh降到约12kWh,MG3的购电量降低约18%,整体效果就是各取所需。晚高峰19:00-21:00,MG3负荷攀升,MG2工业负荷下班后下降,MG2剩余电量通过联络线补充MG3的缺口。深夜谷段,三个微网统一从主网购电给储能充电,为次日做准备。
从成本结构看,总运行成本约为4200元,其中购电成本约1800元,燃气轮机燃料成本约1500元,碳交易成本约500元(排放略超配额),弃电惩罚成本几乎为零。与不互联的独立调度相比,总成本下降约11.7%,碳排放量下降约9.2%。成本下降的主要来源是燃气轮机启停次数减少和购电峰段电量下降。
4.3 多场景对比:互联/不互联、是否计碳
只报一个“最优结果”说服力不够,做对比方案才能把模型的价值讲清楚。我建议至少做以下三组对比。
第一组是无互联 vs 有互联。把联络线容量设为零就是无互联场景,其他条件不变,可以直接对比总成本、碳排放量、弃电率。这一组用来回答“互联到底带来多大收益”的问题。
第二组是不可碳 vs 计碳。把碳交易成本从目标函数中移除(等价于碳价为0),对比碳排放量的变化。通常可以看到,不考虑碳价时系统为了追求最低电费,会尽量多用电网购电而让本地气机少发,因为气机发电成本可能比峰段购电低、比谷段购电高,但排放高。加入碳价后,系统在峰段更多使用气机发电,减少对高排放电网购电的依赖,碳排放总量下降。碳价越高,这种替代效应越明显。
第三组是不同碳价灵敏度分析。分别取碳价10、30、50、80、100元/吨,画出总成本和碳排放量的变化曲线。可以看到碳排放量随碳价上升而下降,但总成本先降后升——因为初始阶段排放削减同时带来了卖配额收益,总成本不升反降;到了高碳价阶段,进一步减排需要付出更高的运行代价,总成本开始回升。这条曲线画出来之后,论文讨论部分就有很多可写了,比如碳价政策对微网群运行的影响机制。
5. 常见问题与调试心得实录
5.1 求解器报错排查
实际问题里,YALMIP报错分两类,一类是“infeasible problem”,一类是“ NaN或Inf数值异常”。下面这张表是常见原因和排查方法。
| 报错现象 | 常见原因 | 排查方法 |
|---|---|---|
| Infeasible problem | 约束过强,没有可行解 | 先用check(Constraints)逐条查看约束残差,找出是哪一条约束把可行域压没了 |
| Infeasible problem | 变量上下限矛盾 | 检查储能SOC初始值是否在限值内、联络线功率上限是否过小 |
| NaN in solution | 变量未定义或维度不匹配 | 用size()检查所有sdpvar的维度,尤其注意列向量与行向量的转置问题 |
| Solver not found | 求解器路径未设置 | 运行yalmiptest测试所有已安装求解器 |
| Cplex license error | 许可证未配置好 | 在命令窗口运行cplexlicensestatus检查许可证状态 |
| 结果为0或边界值 | 目标函数可能漏了某项 | 打印目标函数各项数值,逐项核对成本构成 |
出现infeasible problem时,最有效的调试办法是删约束。先把所有约束注释掉,然后一条一条加回来,每加一条就求解一次。哪条约束加进去后从可行变不可行,问题就定位在哪条约束上。这个过程看起来笨,但实际调试效率非常高。
维度不匹配是我遇到最多的低级错误。Matlab里sdpvar(N,T)是矩阵变量,但某些函数如sum(P_gt,1)和sum(P_gt(:))的结果维度不同,加到约束里时可能出现行向量加列向量的情况,YALMIP有时候不报维度错误,但结果会莫名其妙。每次写完模型都建议用size核对一遍。
5.2 结果不理想的调试方向
如果求解成功但结果不符合预期,比如储能从不充放电、联络线功率始终为零、弃电量异常大,按下面几个方向排查。
第一,检查目标函数中各项的量纲和数量级是否匹配。比如弃电惩罚设为0.01元/kWh,储能效率损失的代价为0.05元/kWh,那么优化器宁可弃电也不存电,结果看起来像“储能白装了”。合理做法是让弃电惩罚大于充电-放电的损耗成本。这里可以用一个简单估算:储能循环一次损耗约15%的电量,如果谷段电价0.35元/kWh,损耗成本约0.05元/kWh,弃电惩罚至少要大于这个值才能“驱动”储能消纳。
第二,检查“不必要同时充放”是否被约束住了。如果没加P_ch + P_dis <= P_rate,优化器理论上可以让储能边充边放,数值上绕开某些约束。虽然线性规划本身不会自动购买无意义的功率(因为同时充放会增加损耗、不构成提高目标函数的机会),但加了这条约束总更安心。
第三,检查E_alloc是否被错误地写成动态配额。前面已经强调过,动态配额会让碳交易项失去约束力,GAP缩水甚至出现负配额收益,这个坑我至少见过三次。
第四,检查联络线变量方向约定是否统一。P_line的正负号约定如果跟母线功率平衡方程不一致,会导致整个微网群内部功率“打架”,结果可能出现某微网同时向母线送电又从母线取电,这种无意义的环流在数值上增加损耗,应该被优化器排除掉。如果看到联络线功率长期处于边界值且整体目标异常,优先怀疑这里。
5.3 避坑指南
最后总结几条实践中沉淀下来的经验,每一条都值得记下来。
关于数据预测的处理,光伏和负荷数据如果直接用实测值,波动太大可能导致调度结果来回震荡,通常先做一次简单平滑或使用典型日曲线。用典型日曲线还有个好处,算例可复现性更强,别人拿到数据也能跑出同样的结果。
关于放电效率的方向,不同论文对储能效率的建模方式不同,我见过把充电效率放SOC递推里、把放电效率放功率约束里的各种变体。你只需要保证递推方程里充放电效率不会错误叠加就行。用η_c和η_d分别放在SOC更新式的充电侧和放电侧,这是最稳妥的写法。
关于Matlab本身,做优化调度仿真时尽量用结构体保存结果,避免工作区变量被后续脚本覆盖。我的习惯是每跑完一组场景就把结果存成.mat文件,文件名为“场景名_日期”,比如“summer_interconnected_20250115.mat”。后期画图会节省大量重跑的时间。
关于结果可复现性,YALMIP/Cplex的求解默认不固定随机种子,如果你的模型里有随机变量,记得先rng设置随机数种子,保证复现结果。启发式算法里这个更重要——不固定随机种子的话,同样的参数跑两次结果都不同,审稿人大概率会质疑你的算法稳定性。
6. 写在最后的一点体会
这个项目做下来,我最大的感受是:优化调度类课题,真正的门槛不在求解器,也不在代码,而在于“把实际问题翻译成数学语言”这一步。功率平衡、储能SOC、碳配额、联络线容量,每一条约束背后都对应着真实的物理规律或政策机制。翻译错了,求解器再强也是在错误的问题上瞎忙。
另一个体会是,做多微网互联一定不要只盯“总成本降低”这个结论,要把互联的价值拆细了看。是哪台机组少发了?哪个时段少买了电?哪个微网的弃电率降了?这些分解后的结论才是论文讨论部分最有说服力的素材,也是你在答辩时能讲清楚“这个系统到底好在哪”的关键。
最后一个小建议:把代码模块化。参数定义、约束构建、求解配置、结果绘图分成独立的函数或脚本,后续调整碳价、改联络线容量、换负荷曲线时只需要改参数部分,不用动核心建模逻辑。我一开始把所有代码揉在一个脚本里,后期做了十几次参数调整,每次改都提心吊胆。后来花了半天时间重构,效率提升极其明显。你现在就按模块化的方式写,能省掉后面一大半的折腾时间。