ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

多能源系统集群协同优化与联合需求侧响应的Matlab复现指南

多能源系统集群协同优化与联合需求侧响应的Matlab复现指南 拿到一篇EI论文的标题第一反应往往不是太好了终于可以复现了而是这模型到底怎么在Matlab里跑起来。我最近刚好做完了这篇《考虑区域多能源系统集群协同优化的联合需求侧响应模型》的完整复现从读公式到建模、从求解器调试到结果验证都走了一遍。这篇博文就把整个复现过程的思路、关键代码片段和踩过的坑一次性讲清楚给正在复现同类论文的朋友做一个可直接参考的工程指南。这篇论文做的事情可以概括成一句话把一个大区域拆成若干个多能源集群每个集群内部有电、气、热三种能源的耦合设备集群之间通过联络线交换功率同时用户在电价信号和激励信号下联合调整自身的多种用能行为最终让整个区域的经济运行成本最小。听起来不算复杂真正上手复现才会发现这里面既有建模层面的弯弯绕绕也有求解层面的性能问题还有论文里很多参数模糊带过的历史遗留问题。本文会覆盖从模型拆解到Matlab实现的完整链路适合电气、能源方向的在校研究生也适合做综合能源系统、虚拟电厂和需求侧响应相关工程项目的从业者参考。1. 这篇EI论文复现的究竟是什么问题背景与解决思路1.1 区域多能源系统的现实痛点单点优化已经不够用了很多接触过综合能源系统Integrated Energy System的朋友一上来就习惯把区域当成一个大节点来做优化。比如简单地把电网、气网、热网各自建一个模型然后通过CHP机组、电锅炉这类耦合设备把它们串在一起。这样建模当然能跑但忽略了现实里一个很重要的属性一个区域往往是由多个相对独立的集群组成的每个集群有自己的一套设备、负荷和调度机构它们之间只有有限的联络通道。举个例子一个城市里可能有A工业园区、B商业区、C居民区三个集群。A园区本身有燃气轮机和余热锅炉B商业区有电制冷和蓄热罐C居民区则以电负荷和热负荷为主。如果把它们揉在同一个优化模型里所有变量全局可调计算结果理论上是最优的但实际中根本执行不下去——因为不同集群的运营主体不同谁也不会把内部的设备参数和负荷数据完整地交给一个中央机构。集群协同优化的本质就是在保留各集群部分独立决策能力的前提下通过联络线的功率交换和有限的信息交互达到接近全局最优的运行效果。这里用的方法通常是分布式优化ADMM交替方向乘子法是这类问题最常用的求解框架。1.2 集群协同联合需求侧响应要解决的核心矛盾再看需求侧响应这一块。传统的需求侧响应大多只盯着电力负荷——分时电价来了用户把洗衣时间挪到谷段把空调温度调高两度仅此而已。但在多能源系统里用户的用能行为是跨越多个能源品种的。比如同一个用户既用电热水器也开燃气壁挂炉电价高了可以多烧气气价贵了可以多用点电这个替代关系如果不去建模需求侧响应就少了一大块调节空间。这篇论文提出的联合需求侧响应本质是把电力、天然气、热力三种负荷放在同一个响应框架里同时协调。用户在价格信号和激励信号的引导下除了常规的削减用电转移用电还能在电、气、热之间做能源替代决策。这样做的好处是系统调节空间更大了灵活性明显增强同时用户侧的用能成本也因为响应行为而下降。联合需求侧响应的建模比单一电力DR要复杂得多因为引入了负荷之间的耦合弹性。比如电价上升时用户不仅会减少电耗还可能增加气耗用来替代电加热这就是交叉弹性的概念。如果只建自弹性的模型等于砍掉了用户最优响应的一大半空间。这一类问题对模型的精细度要求很高也正是复现时最容易出问题的地方。1.3 复现目标与预期成果我把复现的目标定得很明确搭建一个完整的日前24小时优化调度模型在Matlab中用YALMIP建模、调用商业求解器求解同时实现ADMM分布式求解框架用于集群协同优化并对比无需求响应和有联合需求响应两种场景下的总成本和设备出力情况。最终需要输出的成果包括各个集群的CHP机组出力曲线、燃气锅炉和电锅炉出力曲线、储能的充放电曲线、各集群之间的联络线交换功率曲线、负荷响应前后的对比曲线以及价格型和激励型需求响应的具体执行结果。有了这些输出就能从多个维度验证复现结果是否与论文逻辑一致。2. 模型数学框架拆解目标函数、约束与能量耦合关系2.1 能量枢纽建模电-气-热三种能源的耦合矩阵复现这种论文第一个绕不开的概念就是能量枢纽Energy Hub。它的核心思想是把多种能源的输入和输出之间的关系用一个耦合矩阵刻画出来。拿最简单的电-气-热枢纽来说输入是电网购电 (P_{grid}) 和天然气购气 (F_{gas})输出是电负荷 (L_e) 和热负荷 (L_h)中间经过的设备包括CHP机组电-热联产、燃气锅炉气-热转换、电锅炉电-热转换和储能装置。耦合矩阵可以写成 [ \begin{bmatrix} L_e \ L_h \end{bmatrix}\eta_{hub} \begin{bmatrix} P_{grid} \ F_{gas} \end{bmatrix} ]这里的 (\eta_{hub}) 是一个2×2的效率矩阵但实际上因为CHP同时产出电和热矩阵里会有耦合项。以CHP为例输入燃气 (F_{chp})输出的电功率为 (P_{chp} \eta_{e}^{chp} F_{chp})热功率为 (H_{chp} \eta_{h}^{chp} F_{chp})这两个效率往往不是固定的而是取决于运行工况。在Matlab里实现时我建议把能量枢纽建模为带等式约束的输入-输出关系而不是真的写成一个紧凑矩阵。原因是实际建模中每个设备都有自己的出力上下限和爬坡约束紧凑矩阵表达这些会非常别扭。代码结构大致长这样% CHP机组模型 F_chp sdpvar(T,1); % 燃气输入 (MW) P_chp sdpvar(T,1); % 电出力 (MW) H_chp sdpvar(T,1); % 热出力 (MW) constraints [constraints, P_chp eta_e_chp * F_chp]; constraints [constraints, H_chp eta_h_chp * F_chp]; constraints [constraints, P_chp_min P_chp P_chp_max];这里有一个论文里不会细说但实际建模必须处理的问题电效率和热效率怎么取值。有的论文用固定效率有的用线性化的变效率模型有的用可行域方法feasible operation region。固定效率虽然简单但在某些工况下会失真变效率模型需要引入二进制变量做分段线性化问题就变成了MILP。我当时为了保持复现的简洁性先用固定效率跑通了整体流程再在扩展版本里加入了分段线性化做对比。如果你的算例对精度要求不高固定效率完全够用后文我会再提到。2.2 联合需求侧响应的两类典型建模手法需求侧响应在论文里通常分为两路价格型需求响应Price-based DR和激励型需求响应Incentive-based DR联合需求侧响应则把这两路扩展到多种能源负荷上。价格型DR的核心是价格弹性矩阵。用户负荷的变化率与能源价格变化率之间的响应关系可以写成 [ \frac{\Delta L_i}{L_i^0} \sum_j e_{ij} \cdot \frac{\Delta \pi_j}{\pi_j^0} ]这里的 (e_{ij}) 是弹性系数当 (ij) 时叫自弹性通常为负值当 (i \neq j) 时叫交叉弹性可能为正表示替代关系。在电-气-热联合的模型里你至少需要一个3×3的弹性矩阵电负荷对电价、电气价、热价的响应气负荷对三种价格的响应热负荷对三种价格的响应。注意如果热负荷是集中供热没有直接面向终端用户的热价那热负荷的弹性就要通过供热企业的报价或激励策略来体现。实现时价格型DR不应该直接当作约束处理而是作为对原始负荷曲线的修正环节在优化之前先算出响应后的负荷曲线然后把这个响应后的曲线作为系统的固定负荷输入。这个做法在逻辑上是说得通的价格型DR是用户自发的经济行为发生在调度之前而激励型DR则是在调度中由调度员决策是否需要调用属于可调的灵活性资源。激励型DR建模相对直白通常把负荷分为两类可转移负荷和可削减负荷。可转移负荷的特点是总用电量在时间窗内不变典型例子是电动汽车充电、洗衣机可削减负荷的特点是某一时段内的用能可以削减但要支付补偿费用典型例子是空调温控负荷、部分工业负荷。代码里通常这样表达可转移负荷% 可转移负荷一天总耗电量守恒但各时段可以移动 L_shift zeros(T,1); % 实际调度中的转移量增量用 delta 表示 delta sdpvar(T,1); constraints [constraints, sum(delta) 0]; % 总转移量守恒 constraints [constraints, -L_shift_max delta L_shift_max]; % 每时段最大转移限额 L_dr L_base delta; % 响应后的实际负荷综合两类DR之后联合需求侧响应最终要回答的问题是在价格信号已经修正了用户自发行为之后调度侧还能通过哪些激励手段进一步调节用户的电、气、热负荷从而最小化系统总运行成本。2.3 目标函数与约束体系的完整梳理把整个优化模型串起来目标函数是最小化区域总运行成本 [ \min \sum_{t1}^{T} \left[ C_{grid}(t) C_{gas}(t) C_{om}(t) C_{dr}(t) \right] ]各部分的含义和实现要点如下购电成本(C_{grid}(t))从上级电网买电的费用等于分时电价乘以购电量购气成本(C_{gas}(t))从上级气网买气的费用等于气价乘以购气量设备运维成本(C_{om}(t))所有设备的单位出力运行维护费用之和需求响应补偿成本(C_{dr}(t))对用户削减或转移负荷的补偿支出通常是一个随响应量增加而递增的函数用二次函数或分段线性函数近似。约束条件这块以下几条是必须覆盖的功率平衡约束每个集群内部各个节点的电、气、热功率需要满足平衡关系即发电购电联络线净输入等于负荷设备消耗设备出力约束CHP、燃气锅炉、电锅炉、储能设备都有各自的出力范围储能还有SOC上下限和充放电功率限制爬坡约束CHP机组这类设备的爬坡率有限制短期内不能大幅调节出力联络线容量约束集群之间的交换功率有上限这也是集群协同优化的物理边界DR容量约束可转移负荷的每时段最大转移量、可削减负荷的最大削减比例等能源替代约束联合需求侧响应中电负荷和气负荷之间的替换关系要满足替代弹性或最大替换量约束。这些约束在YALMIP里写起来并不复杂难的是把约束之间的耦合关系搞清楚。我踩过的一个典型坑是把联络线交换功率的正负方向搞反了。在集群协同模型里(P_{ex}(t) 0) 代表从别的集群接收功率(P_{ex}(t) 0) 代表送出功率一旦方向定义错误平衡约束的解就会离谱而且还不好查出来。这里建议在代码里把方向定义写成注释并且用一个很小的测试用例验证一下。3. Matlab代码实现的关键模块从数据准备到求解器调用3.1 算例数据组织方案复现论文最怕的就是没有原始数据。我设计的算例是一个包含3个集群的区域系统每个集群通过联络线连接调度周期为24小时时间步长为1小时。数据组织方式上我强烈建议用结构体把设备参数、负荷曲线、价格曲线、拓扑连接关系全部归置清楚不要散落在脚本各处。后面调试和扩展的时候这种组织方式能节省大量时间。我使用的数据文件大概长这样%% 基础参数定义 param.T 24; % 调度周期 param.baseMVA 100; % 基准容量 % 集群数量与连接关系 param.clusterNum 3; param.line [1 2; 2 3]; % 联络线集群1-2集群2-3 param.lineCap [80; 60]; % 联络线容量 (MW) % 分时电价 (元/MWh) param.price_e [0.42 0.42 0.42 0.38 0.38 0.38 ... ]; % 24个时段的电价序列 % 天然气价格 (元/MWh) param.price_g 0.25 * ones(1, 24); % 各集群负荷数据 (MW) load_data.e [100 95 90 ...]; % 电负荷曲线 load_data.h [80 85 90 ...]; % 热负荷曲线 load_data.g [50 48 45 ...]; % 气负荷曲线这里多说一句关于负荷曲线的获取。论文正文里通常只会放一张看起来非常整齐的典型日负荷曲线图但不会给你原始数据。我的处理方法是先把图中的曲线数字化可以用在线工具或者直接目视估点生成一组粗糙的数据点然后做平滑处理加上3%~5%的随机波动作为多个场景的输入。这样虽然不能保证和原始论文完全一致但足以验证模型逻辑是否正确。如果你的最终目的是对比论文结果可以在图中曲线的基础上做更精细的数据提取。3.2 YALMIP建模实践决策变量、约束与目标函数YALMIP是Matlab里最常用的优化建模工具箱把模型搭好后可以直接连接Gurobi、CPLEX等商业求解器。对于多能源系统这种混合整数线性规划MILP问题YALMIP支持非常好。核心建模代码结构如下%% 决策变量定义 % 各集群的购电、购气变量 P_grid sdpvar(T, clusterNum); F_gas sdpvar(T, clusterNum); % 设备出力变量 P_chp sdpvar(T, clusterNum); % CHP电出力 H_chp sdpvar(T, clusterNum); % CHP热出力 H_gb sdpvar(T, clusterNum); % 燃气锅炉热出力 H_eb sdpvar(T, clusterNum); % 电锅炉热出力 % 储能相关变量 SOC sdpvar(T1, clusterNum); % SOC状态注意T1 P_ch sdpvar(T, clusterNum); % 充电功率 P_dis sdpvar(T, clusterNum); % 放电功率 % 需求响应变量 delta_e sdpvar(T, clusterNum); % 电负荷转移量 delta_h sdpvar(T, clusterNum); % 热负荷转移量 cut_e sdpvar(T, clusterNum); % 电负荷削减量 cut_h sdpvar(T, clusterNum); % 热负荷削减量 % 联络线交换功率 P_ex sdpvar(size(param.line, 1), T); % 每条联络线每个时段的交换功率变量定义是建模的骨架后续所有约束和目标函数都是围绕这些变量展开的。这里有一个经验sdpvar变量一定要有清晰的名字和注释不要用x1、x2这样的命名否则一个月后回来看代码你根本不知道 x17 代表什么。约束的搭建要按模块组织每个模块用一个cell数组accumulate起来最后一次性传给optimize。这样好处是出错时能够快速定位是哪个模块的问题。%% 约束搭建 constraints []; % 各集群功率平衡 for k 1:clusterNum % 电功率平衡CHP出力 购电 储能放电 - 充电 - 电锅炉耗电 联络线净输入 电负荷 % 气功率平衡购气 CHP耗气 燃气锅炉耗气 气负荷 % 热功率平衡CHP热出力 燃气锅炉热出力 电锅炉热出力 热负荷 end % 设备出力上下限、爬坡约束 for k 1:clusterNum constraints [constraints, P_chp_min(k) P_chp(:,k) P_chp_max(k)]; % 爬坡约束用 diff(P_chp) 限制相邻时段的出力变化量 end % 储能约束 for k 1:clusterNum constraints [constraints, SOC(:,k) SOC0(k) cumsum((P_ch(:,k)*eta_ch - P_dis(:,k)/eta_dis))]; constraints [constraints, SOC_min SOC(:,k) SOC_max]; end % DR约束 for k 1:clusterNum constraints [constraints, sum(delta_e(:,k)) 0]; % 电量守恒 constraints [constraints, -delta_e_max(:,k) delta_e(:,k) delta_e_max(:,k)]; constraints [constraints, 0 cut_e(:,k) cut_e_max(:,k)]; end %% 目标函数 objective 0; for k 1:clusterNum objective objective sum(price_e .* P_grid(:,k)); objective objective sum(price_g .* F_gas(:,k)); objective objective sum(om_cost_chp .* P_chp(:,k)); % 需求响应补偿成本二次函数近似线性化 objective objective sum(c_dr_e .* cut_e(:,k) c_shift_e .* abs(delta_e(:,k))); end3.3 求解器选型与MILP求解实操YALMIP本身不求解优化问题它只负责把模型翻译成求解器需要的标准形式。对于MILP问题免费可用的求解器像sedumi、SDPT3只能解凸连续问题遇到0-1变量就不行了。实际项目里必须用Gurobi或CPLEX这类商业求解器。我自己的经验是直接上Gurobi原因有三第一求解速度快在一些大规模MILP问题上比CPLEX快30%以上第二学术许可证申请方便个人和非商业用途免费第三与YALMIP的集成非常顺滑几乎零配置。如果你的环境里暂时没有商业求解器也可以用YALMIP自带的bnb分支定界求解器先跑通小规模算例但说实话性能差距很大到大规模算例时会让人怀疑人生。求解代码很简单%% 求解配置 ops sdpsettings(solver, gurobi, verbose, 2); ops.gurobi.MIPGap 0.01; % 设置MIP最优性间隙1% ops.gurobi.TimeLimit 300; %% 求解 result optimize(constraints, objective, ops); %% 结果提取 if result.problem 0 P_chp_opt value(P_chp); SOC_opt value(SOC); % ...其他结果提取 else disp(求解失败请检查约束是否可行); disp(result.info); end这里有个实操细节必须提醒MIPGap的取值直接影响求解质量和时间。设成0会死等最优解设成0.1又可能得到偏差较大的结果。工程上1%的MIPGap通常已经足够。另外一定要设置TimeLimit防止模型出现问题的时候求解器无限跑下去。如果遇到求解失败第一反应不是改求解器设置而是去检查约束的可行性。最常见的坑是SOC的初始值、功率平衡约束的符号、联络线交换功率的维度定义不一致。建议用check(constraints)函数检查约束是否满足YALMIP会直接告诉你哪条约束越界了。4. 集群分解的分布式求解ADMM算法在Matlab中的落地4.1 耦合变量识别与问题分解中心化模型把三个集群的所有变量一起求解这在算例规模大时会非常吃力更重要的是不符合集群独立运营的现实。分布式求解的思路是把全局问题分解成每个集群的局部子问题通过迭代交换信息逼近全局最优解。分解的关键在于识别哪些变量是集群之间的耦合变量。在这个模型里耦合变量只有一个联络线上的交换功率 (P_{ex})。集群1的平衡方程里需要用到联络线1-2的传输功率集群2同样需要用到它但两个集群各自拥有一份这个变量的副本需要让这两份副本在迭代中趋于一致。用数学语言来说就是引入辅助变量 (z) 表示联络线的实际交换功率然后要求每个集群的本地副本 (P_{ex}^{(local)}) 等于全局变量 (z)这个等式约束就是一致性约束。ADMM通过拉格朗日乘子 (\lambda) 和惩罚项 (\frac{\rho}{2}|P_{ex}^{(local)} - z|^2) 来松弛这个一致性约束。4.2 ADMM迭代主循环的代码结构ADMM的每个迭代包含三个更新步骤x-update各集群并行求解局部优化问题、z-update协调者更新全局变量、lambda-update更新对偶变量。Matlab代码结构如下%% ADMM初始化 lambda zeros(size(param.line, 1), T); % 对偶变量 z zeros(size(param.line, 1), T); % 全局联络线功率变量 rho 0.5; % 惩罚系数 maxIter 100; tolResidual 1e-4; for iter 1:maxIter % x-update各集群并行求解Matlab中可用parfor for k 1:clusterNum % 构建集群k的本地优化问题 [P_ex_local{k}, result_k] solveClusterLocal(k, lambda, z, rho, data); % 把本地联络线变量映射到全局索引 end % z-update更新全局变量 for l 1:size(param.line, 1) % 收集所有与联络线l相关的集群本地变量 z(l,:) mean([P_ex_local{line_from(l)}, P_ex_local{line_to(l)}], 1); end % lambda-update更新对偶变量 for l 1:size(param.line, 1) lambda(l,:) lambda(l,:) rho * (P_ex_local{line_from(l)} - z(l,:)); end % 收敛判断 r_prim norm(P_ex_local{1} - z, fro); if r_prim tolResidual break; end end这里有一个关键实现技巧每个集群的本地子问题在构造时目标函数里需要附加拉格朗日项和惩罚项而不是只优化本地成本。具体来说集群k的本地目标函数变为[ f_k(x_k) \sum_{l \in N_k} \left[ \lambda_l \cdot P_{ex}^{(k,l)} \frac{\rho}{2} \left( P_{ex}^{(k,l)} - z_l \right)^2 \right] ]在YALMIP中这个附加项可以直接作为目标函数的一部分写进去。注意 (\lambda) 是已知常数上一迭代更新得到的值不参与优化变量。4.3 收敛判据与调参经验ADMM的收敛判据通常看原始残差primal residual和对偶残差dual residual。原始残差是本地副本和全局变量的偏差对偶残差是相邻两次迭代全局变量的变化量。两个残差都小于容忍度时迭代终止。调参方面最重要的参数是惩罚系数 (\rho)。我的实测经验是(\rho) 太小对偶变量更新太慢迭代要到上百次才收敛(\rho) 太大变量更新会震荡甚至出现远离可行域的情况。一般从 (\rho0.1) 开始尝试观察前10次迭代的残差曲线如果残差下降缓慢就增大 (\rho)如果残差震荡就减小。我曾经为了图省事直接用了 (\rho10)结果迭代20次后联络线功率还在正负之间来回跳白白浪费了两个小时排查。另一个容易忽略的地方是每个集群的本地子问题约束是否可行。如果某个集群本地约束本身无解ADMM无论如何都不会收敛。在做分布式求解之前先用中心化模型验证一遍所有约束是可行的这是最基本的前置条件。ADMM和中心化模型求解的结果对比很直观两者总成本的差距通常在2%以内但ADMM的迭代时间会显著变长。如果你的模型对实时性有要求可以用更少的迭代次数换取可接受的精度比如前50次迭代就能达到3%的偏差这个精度在很多调度场景里已经可以接受了。5. 复现EI论文的避坑清单与结果验证5.1 复现过程中最容易翻车的五个环节五个月的复现过程下来我把最容易翻车的环节总结成了五条每一条都是实际踩过的坑。第一是论文参数表格缺失。很多EI论文会给出设备容量的表格但未必会给出边际成本曲线的具体分段点、储能的初始SOC、爬坡率的具体数值。这些缺失的参数怎么处理我的经验是从该设备类型的工程标准和参考文献中找合理典型值并在复现文档中明确标注此参数为补充假设。第二是负荷曲线数据提取误差。论文里给的负荷曲线图通常只是示意图图上读到的数据点往往误差很大。我的建议是用多组不同的估计数据测试看优化结果是否稳定——如果模型结果对输入数据的波动很敏感说明你的模型可能存在病态条件。第三是变量方向约定冲突。前面提到的联络线正负号问题、储能充放电的正负号定义、DR削减量和转移量是否带正负号这些都是极其隐蔽的bug来源。解决方案只有一个在代码里对所有有方向约定的变量写清楚注释并且做一个单集群单时段的最小化测试用例验证方向是否正确。第四是目标函数中DR补偿项的处理。可转移负荷的补偿成本涉及绝对值项在MILP中需要引入辅助变量做线性化。代码里如果直接用abs(delta)YALMIP虽然能自动处理但会产生额外的二进制变量影响求解速度。建议在模型构建时自己改写为辅助变量形式这样能显著减少求解时间。第五是求解器的数值稳定性。当模型中同时存在量级悬殊的参数比如电价格是百元级而SOC是0到1的小数时求解器可能出现数值问题。可以在YALMIP里用ops.gurobi.NumericFocus 1开启数值聚焦或者把变量做归一化处理。5.2 复现结果验证看哪些指标、画哪些图复现完成的最终价值在于你能从结果中讲清楚一个故事。我建议从三个维度来验证复现是否成功。第一个维度是经济性指标。核心指标是总成本以及各成本项占比。对比无需求响应和有联合需求响应两种场景你应该能看到DR后总成本显著下降购电成本下降通常最明显因为用户把高峰负荷转移到了谷段。如果DR后总成本不降反升说明DR模型的补偿定价设置过高或者弹性系数方向不对。第二个维度是设备利用率指标。重点看CHP机组的出力曲线是否与热负荷和电负荷的变化趋势匹配储能设备是否在电价低谷充电、高峰放电燃气锅炉是否只在热负荷峰值时段启动。如果这些宏观行为与预期不符大概率是你的目标函数里某几项成本的权重出了问题。第三个维度是分布式求解质量指标。ADMM收敛后的总成本与中心化求解的总成本偏差应该在2%以内各集群的联络线交换功率应该满足容量约束且方向合理。把这些数值整理成一张对比表格放到报告里会非常有说服力。通过对比不同场景下的优化结果得到的设备运行曲线和负荷响应前后对比曲线可以进一步生成图表来展示协同效果。边际电价变化曲线和各集群的功率交换曲线是最直观的佐证建议单独整理成图。5.3 从复现到扩展后续还能加什么复现跑通只是一个开始在做完这个基础模型后有很多值得继续扩展的方向。我个人认为比较有价值的有三个一是加入可再生能源出力的不确定性把确定性日前调度扩展为多场景随机规划或者鲁棒优化二是引入碳交易机制在目标函数中加入碳排放配额成本和碳交易收益这样可以考察联合需求侧响应在低碳运行中的作用三是把需求侧响应模型继续细化比如加入电动汽车的时空转移特性、温控负荷的热力学模型、以及更精细的交叉弹性矩阵标定方法。在Matlab扩展实现上多场景随机规划其实就是把决策变量增加一个场景维度目标函数加上各场景的概率权重碳交易机制的建模稍微复杂一些需要引入排放因子和碳价的乘积项本质上还是对目标函数和约束做加法。这些扩展在现有代码框架里只需要改动目标函数和部分约束模块整体结构不用推倒重来这就是当初把代码按模块化组织的好处。复现这篇EI论文的过程让我最大的体会是单纯的代码复现并不难难的是你心里清楚每一步为什么这么建模、计算背后不需要的计算代价在哪。Matlab做这类多能流优化问题的生态确实很成熟YALMIP加Gurobi的组合是目前最省心的选择。这段时间实操下来还有一个个人很想分享的技巧每个模块跑通后立刻做单元验证。我一度图快把所有设备模型一次性写完了才开始调试结果根本分不清是CHP模型写错了还是储能约束写错了。后来改成每加一个设备就构造一个最小测试用例去验证Debug时间至少缩短了三倍。如果你也在做类似的能源系统复现项目建议从一开始就建立这个习惯。
返回列表