ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

微电网容量配置双层优化建模与遗传算法求解实战

微电网容量配置双层优化建模与遗传算法求解实战 干这行的人都有一个共同的感受综合能源系统规划里最磨人的不是设备选型也不是潮流计算而是“到底配多少光伏、配多少储能、配多大的柴油机”这种容量配置问题。拍脑袋定容量运行起来不是浪费就是缺电想认真算又要同时面对投资成本、运行调度、分时电价、不确定性这一堆互相牵扯的因素。最近我在做微电网多电源容量配置时把双层优化建模重新撸了一遍才发现这东西看着抽象一旦把上层决策和下层运行的关系想清楚代码落地反而比单层模型更自然。这篇东西就把我踩过的坑、试通的思路、能直接跑的代码骨架全部摊开讲。这篇文章适合正在做微电网规划、综合能源系统设计、或者被“容量配置”这种投资决策问题折磨的研究生和工程师。你不需要提前精通优化理论我会把双层优化的核心逻辑、为什么上下层要这么拆、Yalmip怎么搭、遗传算法怎么和下层调度耦合这些事讲透。看完你至少能动手改出一版自己的容量配置程序。1. 项目背景与双层模型思路拆解1.1 微电网容量配置为什么必须用双层优化先说说单层模型为什么不够用。常见的单层做法是把投资成本和运行成本揉成一个目标函数比如总成本等于设备等年值投资加上典型日运行费用约束里面同时写设备容量上下限、储能SOC、功率平衡一次求解直接得到容量方案。听起来没问题但实际操作时你会发现一个致命缺陷容量和运行是强耦合的而且运行策略本身不是一次求解能确定的。比如你配了2MWh储能不同调度策略下储能的年运行成本、购电费用、弃光率差异巨大单层模型里如果预先固定了运行方式等于默认调度员是个傻子永远按固定规则走容量结果必然失真。如果你用复杂的运行约束去逼近真实调度模型规模又爆炸求解器直接卡死。双层优化天然适合这种“投资决策在前、运行调度在后”的层级结构。上层决定装多少风机、光伏、储能、柴油机算出投资成本把容量参数传给下层。下层拿到这些设备参数后在满足负荷和电网交互约束的前提下以日运行成本最小为目标算出最优调度策略再把运行成本反馈给上层。两层之间反复迭代直到上层找到一组容量配置使得“投资成本运行成本”的总账最优。这就像你先定一个预算买设备再在运营中精打细算看怎么用设备最省钱如果设备买少了下层的运行成本会很难看上层自然会在迭代中被淘汰。1.2 总体方案上层投资决策、下层运行调度我的整体设计并不复杂上层用遗传算法做离散容量寻优下层用Yalmip调Cplex/Gurobi做线性规划调度。为什么会这样分工因为容量配置本质是整数规划问题台数、功率等级都是离散的而连续变量的运行调度很适合成熟的线性规划求解器。用商用求解器直接解混合整数双层问题很容易撞上非凸、非线性这座墙而启发式算法在工程界的稳定性和灵活度反而更高。上层的每个个体就是一组“设备装机方案”比如光伏500kW、风机300kW、储能600kW/1200kWh、柴油机200kW。这个方案传给下层后下层会基于典型日数据负荷曲线、光伏出力曲线、分时电价求出一个最优运行计划再把最小运行成本返回给上层。上层把投资成本和下层反馈的运行成本相加作为这个个体的适应度值。经过多代进化最终收敛出一组年综合成本最低的容量配置。这套框架最大的好处是解耦你不用把复杂的运行策略强行塞进一个庞大的优化模型里下层的运行模型可以做得非常精细哪怕加上机组启停、SOC约束、购售电策略都不会拖垮上层寻优。2. 数学建模与约束设计2.1 上层模型等年值投资成本与设备选型上层的目标函数不是简单把设备价格乘以容量而是要把投资成本折算成等年值才能和运行成本放在同一个时间尺度上比较。这里用到了资金回收系数CRF。如果项目生命周期是20年折现率取6%那么CRF r(1r)^n / ((1r)^n - 1) ≈ 0.0872。也就是说你现在花100万买设备平摊到每年大约是8.72万。这个系数很多人第一次算会错我建议直接用Excel的PMT函数验证一遍。等年值投资成本可以写成C_inv CRF × (C_pv × N_pv × P_pv_unit C_wt × N_wt × P_wt_unit C_bat_p × E_bat C_bat_e × P_bat C_diesel × P_diesel)其中N_pv、N_wt是光伏和风机的安装组数P_pv_unit是单组光伏的额定功率E_bat是储能容量P_bat是储能功率P_diesel是柴油机容量。注意储能一般按容量kWh和功率kW分开计价因为电池电芯和PCS逆变器是两个成本体系。在做设备选型时我还加了建设面积约束、最大装机比例约束比如“光伏装机不能超过屋顶可用面积的极限”这类现实条件这些是实际项目中甲方最关心的硬约束。2.2 下层模型分时电价下的运行调度优化下层运行调度的目标函数是典型日运行成本最小包含向电网购电费用、柴油机燃料费用减去售电收益。分时电价是让这个模型变得有意思的关键。我用的典型日数据里峰时段电价1.2元/kWh平时段0.7元/kWh谷时段0.35元/kWh。下层模型会自动在谷时段充电、峰时段放电体现“低买高卖”的套利逻辑。目标函数写出来C_op Σ_t ( price_buy(t) × P_buy(t) - price_sell(t) × P_sell(t) fuel_cost × P_diesel(t) )注意P_buy和P_sell不能同时为正不然模型会利用买卖价差无限套利。这个问题在Yalmip里通过加一个互斥约束或者设置合理的price_sell小于price_buy来解决。如果售电价和购电价一样就必须显式加P_buy(t) × P_sell(t) 0这种非凸约束不太好处理。我的做法是直接把售电价设为购电价的80%既符合实际又天然避开了同时买卖的问题。下层约束包括功率平衡光伏风电柴油机储能放电购电 负荷储能充电售电、储能SOC递推方程、SOC上下限、充放电功率限制、柴油机出力上下限和爬坡约束。SOC递推要特别注意效率充电时 SOC(t1) SOC(t) η_ch × P_ch(t) / E_bat放电时 SOC(t1) SOC(t) - P_dis(t) / (η_dis × E_bat)。如果不把充放电效率写对储能的套利收益会被高估配置出来的储能容量会偏大。我实际测试过效率从90%改成95%最优储能容量能差出15%左右。2.3 双层耦合机制传递变量与可行性判定上下层交换的数据包括设备容量上层传下层、日运行成本下层传上层。但仅传递这些还不够还需要检查下层模型是否可行。比如上层配了一个很小的柴油机但极端天气下光伏不出力、储能又放完电导致某些时段无法满足负荷下层模型就无解。这种情况下不能简单给个无穷大惩罚值我习惯返回一个很大的适应度值比如1e8同时记录这个个体是“不可行方案”在遗传算法里直接淘汰。还有一种做法是给下层模型加虚拟电源以极高成本提供缺电功率这样即使设备容量不足下层也能解出来但运行成本会异常高上层自然会避开这些方案。这种方法比直接删掉个体更优雅因为它提供了梯度信息引导种群往容量足够的方向进化。下层返回的运行成本是单典型日的如果只算一天会以偏概全。工程上更稳妥的是选几个典型日——比如夏季大负荷日、冬季小负荷日、过渡季节日——分别求解再按每个典型日出现的天数加权汇总成年运行成本。我用的是三个典型日权重分别取0.3、0.4、0.3。这样虽然计算量翻了三倍但配置结果在全年运行中不会出现大的偏差。3. 求解策略与代码实现手把手3.1 遗传算法为什么适合外层、线性规划为什么适合内层先聊一下求解器选型的逻辑。双层优化经典解法之一是KKT条件转换把下层问题用KKT条件替换变成单层带互补松弛约束的问题。这个方法理论上很漂亮但对下层模型的要求很苛刻必须凸、必须可导、互补约束处理不好数值上很容易翻车。我的下层模型里有储能SOC递推、柴油机爬坡这些整数或非平滑项KKT转换后模型复杂度不减反增实际调试成本很高。所以我的选择是上层用遗传算法GA做离散寻优下层用Yalmip调Cplex做线性规划求解。GA的每一代可能要调用下层求解器几十次但每个下层LP问题求解速度快毫秒级整体算下来五六分钟能收敛工程上完全能接受。3.2 整体代码逻辑架构代码整体分四层主程序遗传算法、个体容量解析函数、下层运行优化函数、数据输入模块。主程序负责生成种群、计算适应度、选择交叉变异容量解析函数把一个个体的染色体解码成具体的设备容量下层运行优化函数接收设备容量和典型日数据调用Yalmip建模并求解数据输入模块统一管理典型日负荷曲线、光伏归一化出力、分时电价和成本参数。这样拆的好处是你想换下层的调度模型只需要改“下层运行优化函数”上层完全不用动想换成别的启发式算法主程序替换起来也很方便。我用MATLABYalmip是因为这个组合在学术和工程圈最通用调试环境也友好。Python的同行可以用Pygmo或者Geatpy做外层内层用PuLP或者Pyomo调Cbc逻辑完全一样。这里给出来的是MATLAB版本注释写得很细方便你改成自己的数据。3.3 可运行的MATLAB代码骨架下面这套代码是简化但仍完整可跑的版本。我在关键位置加了注释你把它保存成几个m文件就能跑通。首先是主程序跑遗传算法%% 遗传算法主程序 clear; clc; rng(42); addpath(./data); % 数据目录 % 加载典型日数据 load(typical_days.mat); % 包含 load_curve, pv_curve, wt_curve, price_buy, price_sell, day_weight % 遗传算法参数 pop_size 20; max_gen 30; crossover_prob 0.85; mutation_prob 0.1; % 决策变量编码 [N_pv, N_wt, E_bat, P_bat, P_diesel] % N_pv范围0~10N_wt范围0~6E_bat范围0~2000kWhP_bat范围0~500kWP_diesel范围0~400kW lb [0, 0, 0, 0, 0]; ub [10, 6, 2000, 500, 400]; % 初始化种群 pop zeros(pop_size, 5); for i 1:pop_size pop(i,1) randi([lb(1), ub(1)]); pop(i,2) randi([lb(2), ub(2)]); pop(i,3) lb(3) rand * (ub(3) - lb(3)); pop(i,4) lb(4) rand * (ub(4) - lb(4)); pop(i,5) lb(5) rand * (ub(5) - lb(5)); end best_fitness zeros(max_gen, 1); for gen 1:max_gen fitness zeros(pop_size, 1); for i 1:pop_size % 关键一步调用下层运行优化取得总成本 [total_cost, op_cost] evaluate_individual(pop(i,:)); fitness(i) total_cost; end % 记录最优 [best_fitness(gen), best_idx] min(fitness); fprintf(第%d代最优总成本: %.2f 元\n, gen, best_fitness(gen)); % 选择锦标赛选择 new_pop zeros(size(pop)); for i 1:pop_size idx1 randi(pop_size); idx2 randi(pop_size); if fitness(idx1) fitness(idx2) new_pop(i,:) pop(idx1,:); else new_pop(i,:) pop(idx2,:); end end % 交叉单点交叉 for i 1:2:pop_size-1 if rand crossover_prob cp randi(4); % 交叉点 tmp new_pop(i, cp1:end); new_pop(i, cp1:end) new_pop(i1, cp1:end); new_pop(i1, cp1:end) tmp; end end % 变异随机重置 for i 1:pop_size for j 1:5 if rand mutation_prob if j 2 new_pop(i,j) randi([lb(j), ub(j)]); else new_pop(i,j) lb(j) rand * (ub(j) - lb(j)); end end end end % 强制边界 new_pop max(new_pop, repmat(lb, pop_size, 1)); new_pop min(new_pop, repmat(ub, pop_size, 1)); pop new_pop; end % 输出最优解 [best_cost, best_idx] min(best_fitness); fprintf(最优容量配置: 光伏组数%d, 风机台数%d, 储能容量%.1fkWh, 储能功率%.1fkW, 柴油机%.1fkW\n, ... pop(best_idx,1), pop(best_idx,2), pop(best_idx,3), pop(best_idx,4), pop(best_idx,5)); fprintf(最低年综合成本: %.2f 元\n, best_cost);然后是适应度评估函数就是容量解析和调用下层function [total_cost, op_cost] evaluate_individual(x) % 解码个体 N_pv round(x(1)); N_wt round(x(2)); E_bat x(3); P_bat x(4); P_diesel x(5); % 设备单位容量参数 P_pv_unit 100; % kW, 每组光伏容量 P_wt_unit 100; % kW, 每台风机容量 c_pv 5000; % 元/kW c_wt 8000; % 元/kW c_bat_e 1500; % 元/kWh c_bat_p 1000; % 元/kW c_diesel 2000; % 元/kW CRF 0.0872; % 等年值折算系数 % 上层投资成本等年值 inv_cost CRF * (c_pv * N_pv * P_pv_unit ... c_wt * N_wt * P_wt_unit ... c_bat_e * E_bat ... c_bat_p * P_bat ... c_diesel * P_diesel); % 调用下层运行优化 op_cost run_lower_level(N_pv * P_pv_unit, N_wt * P_wt_unit, ... E_bat, P_bat, P_diesel); total_cost inv_cost op_cost; end下层运行优化是核心我用Yalmip建模function op_cost run_lower_level(P_pv_total, P_wt_total, E_bat, P_bat, P_diesel) % 加载典型日数据 load(typical_days.mat); % Yalmip建模变量 n_day length(day_weight); op_cost_total 0; for d 1:n_day T length(load_curve{d}); % 决策变量 P_buy sdpvar(1, T); P_sell sdpvar(1, T); P_ch sdpvar(1, T); P_dis sdpvar(1, T); P_diesel_out sdpvar(1, T); SOC sdpvar(1, T1); % 约束条件 Constraints []; % 功率平衡 for t 1:T Constraints [Constraints, ... P_pv_total * pv_curve{d}(t) P_wt_total * wt_curve{d}(t) ... P_dis(t) P_diesel_out(t) P_buy(t) ... load_curve{d}(t) P_ch(t) P_sell(t)]; end % 购售电互斥通过价格机制避免同时买卖这里加最大功率约束 Constraints [Constraints, 0 P_buy 500, 0 P_sell 500]; % 储能约束 Constraints [Constraints, SOC(1) 0.5 * E_bat]; % 初始SOC eta_ch 0.95; eta_dis 0.95; for t 1:T Constraints [Constraints, ... SOC(t1) SOC(t) eta_ch * P_ch(t) - P_dis(t) / eta_dis, ... 0.1 * E_bat SOC(t1) 0.9 * E_bat, ... 0 P_ch(t) P_bat, ... 0 P_dis(t) P_bat, ... 0 P_diesel_out(t) P_diesel]; end % 柴油机燃料成本系数 fuel_cost 1.2; % 元/kWh % 目标函数购电费用 燃料费用 - 售电收益 Objective sum(price_buy{d} .* P_buy) sum(fuel_cost * P_diesel_out) - sum(price_sell{d} .* P_sell); % 求解 ops sdpsettings(solver, cplex, verbose, 0); optimize(Constraints, Objective, ops); op_cost_total op_cost_total day_weight(d) * value(Objective); end op_cost op_cost_total * 365; % 折合成年运行成本 end注意最后一个函数里我用day_weight(d) * value(Objective)然后乘以365这个逻辑要小心如果day_weight已经代表了每个典型日占全年天数的比例比如0.3/0.4/0.3那么三个典型日加权求和后直接乘以365就是年运行成本。如果你的典型日权重是“每年出现30天”这种绝对天数那就直接加权求和不用再乘365。我在这上面栽过一次跟头算出来的年成本高得离谱查了两天才发现是权重口径搞混了。3.4 数据准备与典型日生成下层模型的数据准备是整个工程里最容易被低估的部分。负荷曲线、光伏归一化出力、分时电价这些数据如果拍脑袋乱填算出来的配置方案没有任何参考价值。我用的典型日生成方法是拿项目地实测的全年8760小时数据按“聚类”的思路挑出三个最具有代表性的日子——夏大负荷日、冬大负荷日、春秋平均日。每个典型日包含24小时的负荷功率、光伏归一化出力实际出力/额定容量、风电归一化出力、分时购电价和售电价。这里有一个很重要的细节光伏归一化曲线应该是“单位千瓦出力”也就是你装1kW光伏每个时刻实际能发多少电。这个值跟地理位置、天气、倾角都有关系不能随便拿发电小时数去反推。同样风电的归一化曲线也要小心风机有切入风速、切出风速不是风速达标就满发。我用的是PVsyst和WAsP导出的数据如果你手头没有专业软件至少要用气象NASA数据加转换效率估算一下别从论文里抄一组曲线就完事。我实测下来光伏曲线偏差10%容量配置结果能差20%以上。分时电价的设置要结合当地电网的峰谷时段。我用的分时电价是峰时段10:00-15:00、18:00-21:00电价1.2元/kWh平时段7:00-10:00、15:00-18:00、21:00-23:00电价0.7元/kWh谷时段23:00-次日7:00电价0.35元/kWh。售电价统一按购电价的80%计算。这个设定一旦变了储能的最优容量会立刻跟着变——如果峰谷价差小于储能的充放电损耗成本储能就完全没有配置价值。这个盈亏平衡点你可以在跑模型之前先估算一下假设充放电效率95%电池每度电循环一次损耗约0.1元加上PCS损耗如果峰谷价差低于0.3元/kWh储能套利基本不赚钱。4. 实验场景设计微网与外部电网的调控策略4.1 微网与外部电网互动逻辑很多初学者跑微电网容量配置时把并网点功率当成完全自由的变量想买多少买多少。实际项目里电网对微网的联络线功率是有约束的常见的有两种一种是最大交换功率限制比如不能超过变压器容量另一种是功率波动限制比如每15分钟功率变化不能超过多少kW。这些约束在容量配置阶段如果不考虑等设备装完了再发现联络线不够用就很被动了。我在下层模型里加了一个联络线功率上限比如P_line_max 300kW也就是从电网买电或者向电网卖电的功率都不能超过300kW。这个约束对容量配置的影响很大如果联络线功率限制很紧微电网就必须自己配更大的储能或者柴油机来应对负荷高峰总成本会明显上升。你可以把P_line_max设成300、500、1000分别跑一遍看看容量配置结果怎么变这个敏感性分析对实际项目非常有价值也是和甲方谈方案时最有说服力的材料。电网互动还有一层意思是“怎么卖电”。我见过很多模型允许微网向电网卖电但设了很高的售电价导致模型倾向于“使劲装光伏发了电全卖掉”这种结果偏离实际。真实情况下分布式光伏上网电价通常低于目录电价部分地区甚至没有余电上网资格。所以我在模型里把售电价设为购电价的80%且允许向电网卖电。如果你想模拟“自发自用、余电上网”的保守模式把售电价设成0.35元/kWh左右再跑一遍你会发现最优的光伏装机量会降很多。这个参数的敏感性就是商业模式的敏感性。4.2 储能调度策略与分时电价套利分析下层模型跑完之后你可以把储能调度曲线画出来分析。正常情况下谷时段23:00-7:00储能会以最大功率充电SOC从10%一直充到90%左右上午平时段和中午光伏大发时段储能基本不动作因为光伏直接供给负荷就够了下午峰时段18:00-21:00储能开始放电支撑晚高峰负荷直到SOC掉到10%左右。这个行为模式验证了模型在正确实现“低充高放”逻辑。如果你发现储能SOC曲线反着走比如峰时段充电、谷时段放电那一定是电价数据或者目标函数符号搞错了。还有一个细节很多模型会给储能加“日始日终SOC相等”的约束也就是一天下来储能电量回到初始值这是为了避免模型把前一天的能量“偷”到当天用造成日运行成本虚低。我建议加上这个约束尤其在做多典型日加权时。但是注意加了日始日终SOC相等后如果光伏大发日储能被迫在光伏多的时段充电、在晚上全放完可能造成日内无法完成整体循环。我的处理方式是让SOC初始值在0.2到0.8之间可调让优化器自己决定。储能功率和容量也不是随便分开配的。储能容量E_bat决定它能存多少电功率P_bat决定它能以多快速度充放。如果E/P比选得太小就像一个“大水管小水池”一小时就充满了剩下时间闲着如果E/P比太大就是“小水管大水池”每天根本用不完。实际项目中电化学储能的E/P比一般选2~4小时我的模型跑出来的最优配置如果偏离这个范围我会检查是不是价格参数或调度约束出了问题。4.3 柴油机在容量配置中的定位柴油机虽然不环保但在离网型微电网里往往是兜底电源。在并网型微电网里柴油机的作用就变成了“极端工况备胎”——当电网故障或者光伏风电全无出力时柴油机保证重要负荷不断电。我的模型里如果允许柴油机正常参与调度因为它的燃料成本1.2元/kWh高于谷时购电成本优化器会在大部分时间让它停机只在峰时段电价高于燃料成本时启动。这个结果符合预期。你可以加上“最小开机时间”“最小停机时间”约束让柴油机更接近实际工况但这会让下层模型从纯LP变成混合整数规划求解时间会翻好几倍。容量配置阶段我建议先用简化的连续出力模型等确定了大致容量再在详细调度阶段加机组组合约束精算。这里有一个容易忽略的点柴油机的容量配置和它的年利用小时数密切相关。如果模型算出来柴油机年运行时间特别短比如只有50小时那这200kW的柴油机投资几乎就是纯沉没成本。这时候你要么考虑减少柴油机容量要么考虑换成租赁移动电源车的方案。这种“设备买了没用”的信息正是双层模型能提供给决策者的独特价值——它不仅仅给出一个数字还能告诉你每个设备到底在什么场景下被用到。5. 参数校准、常见问题与避坑经验5.1 收敛性差、结果不稳定怎么办跑遗传算法最烦的就是每次结果不一样或者很多代后成本还在大幅波动。我遇到过的原因主要有三个。第一个是种群太小多样性不足算法陷入局部最优。我的经验是种群规模至少20以上迭代次数至少30代以上如果你发现最优个体连续5代没有变化可以适当增加变异概率。第二个是上下层迭代时下层模型的求解容差太大。Cplex这类求解器的默认容差是1e-6但我跑大规模问题时它会自动放宽。你可以在sdpsettings里显式设置cplex.optimalitytarget, 1e-9或者调低容差。第三个是投资成本和运行成本的数量级差异太大导致适应度函数里投资成本主导运行成本成了“噪声”。解决办法是对两个成本做归一化或者调整遗传算子的选择压力。还有一个我自己经常用的技巧把上一代最优个体直接保留到下一代精英保留策略。我给的代码里没有做这一步实际使用建议加上不然最优解很可能在交叉变异中被破坏掉。一个简单的做法是每代记录最优个体下一代强制放回种群替代最差个体。这能显著加快收敛。5.2 下层模型无解时的处理容量配置中下层模型无解是非常常见的情况尤其是初始种群随机生成时大概率会出现“光伏储能柴油机完全撑不住负荷”的个体。我的处理方式前面提过可以在下层模型加一个“虚拟电厂”变量单位购电成本设置成正常购电价的10倍甚至50倍。这样做的好处是下层模型永远不会无解但一旦调用了虚拟电源运行成本会飞涨上层适应度函数自然淘汰这个个体。还有一种更工程化的做法在下层模型求解前先做可行性预判比如算一下“最坏情况下无光伏、无风电、储能SOC最低时柴油机和联络线最大出力能不够满足负荷”。如果不够直接返回一个惩罚值不进入Yalmip求解流程。这样能省下大量无效求解时间种群越大优势越明显。我在写高校项目时常用这种方法特别是学生用的电脑性能一般对求解次数的控制很关键。5.3 代码调试与结果校核的几个土办法很多初学者跑通代码后面对一堆输出数字不知道对不对。我分享几个土办法虽然简单但救命。第一把储能容量设成0跑一次纯购电方案算出来的成本应该等于“所有时段负荷乘以购电价”的全年累计这个值可以手算验证。第二把光伏容量设成0但保留储能跑出来的结果应该比纯购电方案成本更高或持平如果变低了说明模型里储能能凭空造电一定有bug。第三把分时电价全设成同一个值储能的套利价值消失最优储能容量应该会显著变小甚至趋近于0如果没有说明储能约束写拧了。另外Yalmip的check(Constraints)函数是你的好朋友。每次求解完用check检查每个约束的残差如果某个约束残差大于1e-5说明这个约束在数值上没满足可能是量纲问题或者求解器精度问题。我刚做这个项目时吃过亏储能SOC约束单位用的是MWh功率平衡约束用的是kW导致能量和功率直接相加残差巨大结果永远不对劲。统一单位是建模的基本功但在代码里特别容易犯。5.4 代码扩展方向从双层到多时间尺度这套双层框架最让我满意的地方是它的扩展性。容量配置确定之后你往往还要做“日前调度日内滚动”的多时间尺度能量管理。这时上层模型可以变成日前机组组合下层模型可以变成基于模型预测控制的日内滚动优化。热搜里经常看到的“基于模型预测控制的微电网多时间尺度能量管理”本质上就是在容量配置之后把下层的静态调度换成带反馈校正的动态优化。代码层面你只需要改run_lower_level这个函数上层完全不用动。如果你想加入不确定性分析比如光照、负荷预测误差可以在下层模型里改成随机规划或者鲁棒优化。Yalmip对这两种问题都有比较好的支持鲁棒优化还可以用鲁棒对等转换写成线性规划。但我要提醒一句不确定性模型会让计算量成倍增长在容量配置阶段先跑确定性模型确定大致方案后再针对候选方案做不确定性验证这样性价比最高。写在最后的一点个人体会这套代码前前后后我改了好几版最大的体会是双层优化能不能在工程中真正发挥作用关键不在算法多高级而在上下层模型的分工是否符合真实的决策流程。上层管“买什么设备”下层管“设备怎么用”这是每个项目投资方和运营方都要面对的关系模型只是把这种关系数学化了。你如果还在纠结理论推导和求解器选型我的建议是先把手头的单层模型改成双层框架哪怕初始用的都是最简单的遗传算法和线性规划跑通之后再逐步加约束、换算法。另一个建议就是多跑敏感性分析——容量配置的结果对电价、负荷曲线、设备单价特别敏感把几个关键参数的敏感性曲线做出来比单次优化结果更能说服人。这些曲线也是你以后写报告、做答辩、向甲方汇报时最有分量的材料。
返回列表