尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

MATLAB+YALMIP实现电热综合能源市场双层出清建模与求解

发布时间:2026/9/14 4:40:03

资讯中心
01
ARTICLE

MATLAB+YALMIP实现电热综合能源市场双层出清建模与求解

MATLAB+YALMIP实现电热综合能源市场双层出清建模与求解
1. 先搞懂模型在解决什么问题1.1 能源集线器多能互补的“翻译官”做综合能源方向的朋友对“能源集线器”这个概念应该不陌生。能源集线器Energy Hub本质上就是一个多能源耦合节点它接收电网买的电、天然气管道送来的气甚至本地风光出力通过内部设备转换成用户需要的电、热、冷等多种能源形式。你可以把它理解成一个“能源翻译官”——一端接入不同品味的能源另一端按需输出终端用户真正要的东西。常见的设备配置包括热电联产机组CHP、燃气锅炉、电锅炉、热泵HP、蓄热罐TES等。其中CHP是核心角色因为它在发电的同时回收余热属于典型的“一鱼两吃”。以燃气轮机为例输入一份天然气大约35%~40%变成电45%~50%变成热综合能源利用率能到85%以上。热泵则是用电驱动、从低温热源“搬运”热量到高温侧的设备COP通常能到3.5~4.5从能效角度非常划算代价是耗电。在电热综合能源市场里能源集线器不只是“物理设备组合”它还是一个市场参与者。它从电力市场、天然气市场购入能源通过内部设备转换后向用户售电、售热赚取购售差价和转换收益。这就引出一个关键问题市场是如何确定电、热价格的能源集线器又是如何根据价格信号调整内部机组出力的这两个问题环环相扣单靠一个优化模型很难说清楚于是就有了“双层出清模型”的用武之地。1.2 为什么电热市场需要双层出清模型单层优化模型大家都熟悉给定负荷和成本曲线以社会总福利最大化或系统运行成本最小化为目标统一求解各机组的出力。这类模型的假设是所有参与者完全服从调度中心指令属于集中优化。但现实中的综合能源市场不是这样玩的尤其当能源集线器是独立运营主体时它有自己独立的经济利益不会无条件听调度的话。这里就出现了“市场出清”和“主体决策”的博弈关系上层是电力/热力市场运营商负责制定交易价格、确定市场出清结果目标是社会福利最大化或市场运营收益最大化下层是各能源集线器运营商在给定的电、热价格下调整自己的购电、购气策略和设备出力目标是自身利润最大化。上层出清结果影响价格信号价格信号反过来影响下层决策下层决策又反馈为上层看到的需求曲线——两者互相作用这就是典型的一主一从双层决策问题。如果忽略这个博弈结构直接把所有变量塞进一个大模型里求“全局最优”得到的结果在数学上可能是社会最优但在实际市场机制下根本落不了地因为下层主体没有动力执行这个解。双层模型的价值恰恰在于还原这种“上下互动”的市场机制让学电力市场、综合能源规划的同学能模拟真实的交易流程而不是停留在理想的集中调度假设里。1.3 这套MATLAB代码能帮你做什么先说清楚这套代码的定位它不是一个简单调用CVX就能跑的线性规划而是包含KKT条件转换、强对偶定理、互补松弛条件线性化等操作的MPEC带均衡约束的数学规划问题。代码覆盖了能源集线器参数建模、电热市场双层出清、基于YALMIP建模调用Gurobi求解的完整流程。适合的人群主要是三类一是做综合能源系统优化方向的硕博生需要搭一个电热市场双层出清模型作为论文算例二是做园区级综合能源规划或能源互联网仿真平台的工程师需要快速验证不同市场机制下的调度策略三是想入门“双层优化怎么落到MATLAB代码”的初学者想找个现成的完整案例跑通流程、理解每一行背后的数学意义。对硕士研究生来说这套代码最直接的价值就是“能跑、能改、能出图”你可以换负荷数据、调设备参数、改目标函数中的权重系数观察市场出清价格和设备出力的变化趋势直接作为论文第四章的仿真内容。对工程师来说双层模型能告诉你“在给定价差机制下储能和CHP的最优运行策略是什么”从而为实际的能源交易报价提供参考。2. 双层出清模型的数学结构与选择逻辑2.1 上层市场运营商的出清问题先讲上层的建模思路。电热综合能源市场的上层出清问题核心目标是社会福利最大化也就是用户侧购能效用减去供能成本。这里需要说明的是“社会福利”在离散时段模型里通常可以转化为“总购能效用最大化”或“总运行成本最小化”两者本质等价区别在于要不要把负荷侧的弹性需求考虑进来。代码中的典型设置如下市场运营商决策变量包括各时段电、热出清价格、能源集线器向市场申报的购电量/购热量、外网购电量和气网购气量。目标函数为max 用户效用 - 电网购电成本 - 气网购气成本其中用户效用是一个关于电、热负荷的二次凹函数边际效用递减常用于弹性需求模型电网购电成本采用分段线性函数或直接取分时电价气网购气成本则取阶梯气价。上层约束包括电力供需平衡约束外网购电量 各能源集线器上网电量 电负荷 各能源集线器购电量 网损热力供需平衡约束热源产热量 各能源集线器上网热量 热负荷 管网热损外网购电上下限、购气上下限出清价格非负或设置上下限约束防止套利导致价格崩坏这里有个重要的建模选择——为什么不直接把能源集线器设备参数拿到上层一起优化如果这样做模型退化成集中式优化就失去了市场机制的意义。上层只能看到下层上报的“购电、购热需求函数”和“可供电力、可供热量”而不能看到下层内部CHP效率、热泵COP这些私有参数。这正是双层模型保护“信息隐私”的体现也是论文里经常强调的一点。2.2 下层能源集线器运营商的利润最大化问题下层的每个能源集线器单独优化自己的运行计划目标函数是该集线器的日运行利润最大化max 售电收入 售热收入 - 购电费用 - 购气费用 - 设备运维成本这里售电、售热对象是终端用户购电、购气对象是上层市场。需要注意的是如果能源集线器既向用户售能又从市场购能它其实处在“中间商”的位置——它的利润来自“零售价”和“批发购能价”之间的差价加上内部设备转换产生的增值收益比如用1份天然气产出0.4份电0.45份热的价值。下层模型的约束包括能源集线器内部功率平衡购电量 CHP发电量 热泵耗电量/发电量 输出电量购气量经CHP和燃气锅炉转换后 输出热量CHP运行约束发电功率上限、热功率上限以及“以热定电”或“以电定热”的可行域约束用多面体近似热泵运行约束制热功率上限、COP范围约束蓄热罐约束储热容量上下限、充放热功率上下限、蓄热SOC状态转移方程和周期始末储能一致性约束购电、购气量上下限约束下层模型对上层模型的“反馈”是通过变量耦合实现的。环境变量给定参数是上层传给下层的出清价格而下层的最优购电量、购热量又作为上层模型里的外生变量参与供需平衡计算。这个“价格→决策→平衡→价格”的循环就是双层问题最难处理的部分。2.3 耦合约束与市场出清机制的作用路径上级和下级之间不是靠“喊话”连接的而是通过KKT条件“焊死”的。这是我个人认为双层优化建模中最核心也最容易出错的一环。具体来说上层问题的KKT条件必须同时包含下层问题的一阶最优性条件拉格朗日函数对各决策变量的偏导数为0、互补松弛条件以及下层问题的原始/对偶可行性条件。把这些条件全部塞进上层优化里作为约束得到一个MPEC问题再通过强对偶定理将下层目标函数中的双线性项对偶变量乘以约束右侧常数项换成等价表达最终得到一个可以用商业求解器直接求解的单层优化问题。这个叫“KKT方法”或“下层替换法”。它的好处是一步到位不需要在主从问题之间反复迭代求解精度有保证缺点是互补松弛条件本身是非线性非凸的需要通过大M法引入0-1整数变量线性化模型的规模会变大。如果时间粒度是24个时段、5个能源集线器变量和约束轻松上千求解速度明显变慢。另外还有一个求解思路叫“迭代式求解”上层先给出价格下层求解得到需求上层再根据需求更新价格往复迭代直到价格和需求都收敛。这个思路写代码简单但没法保证收敛尤其当供需曲线都是阶梯状时很容易在两三个价格点之间来回震荡。我通常只把迭代法当作验证KKT法结果的“交叉检验工具”不会用它作为主求解方案。2.4 为什么在MATLAB里用YALMIP而不是CVX这个问题常被问起。综合能源系统的双层出清模型转换到最后是一个带0-1变量的混合整数线性规划或二次规划MILP/MIQPCVX在建模方面友好度不错但对整数变量支持比较弱很多双层转化后的约束没法直接表达。YALMIP则专门擅长处理这类复杂约束比如complements互补松弛可以一键生成bilinear项也可以通过define或recover表达式来处理在使用体验上更顺手。再者YALMIP对求解器的封装做得比较好支持Gurobi、CPLEX、Mosek等主流求解器切换求解器只需要改一行参数。对于双层市场出清这种“建模复杂、求解要求高”的问题YALMIP几乎是MATLAB生态里的最优选择。如果你的MATLAB版本带优化工具箱不装第三方求解器也能用内置的intlinprog解小规模算例但工程实践里还是建议装Gurobi性能差距非常明显。3. MATLAB代码实现与复现步骤拆解3.1 代码框架与模块划分拿到这套代码第一件事不是运行而是看清楚它的目录结构和模块关系。典型的代码工程文件包含以下几个模块|-- main.m % 主程序入口 |-- data_input.m % 基础数据录入负荷曲线、设备参数、价格参数 |-- parameters_setting.m % 参数设置与标幺值基值选择 |-- build_upper_problem.m % 构建上层出清模型 |-- build_lower_problem.m % 构建下层能源集线器决策模型 |-- solve_mpec.m % KKT条件转换与单层化求解 |-- plot_results.m % 结果可视化输出实际运行的时候从main.m开始它会依次调用数据录入、模型构建和求解模块。模块化的好处是方便你自己改动想改负荷曲线只动data_input.m想加储能约束只动build_lower_problem.m想改市场规则比如增加容量补偿机制只动build_upper_problem.m。第一次看代码的时候建议按main.m的函数调用顺序读不按文件名的字母顺序读否则容易被跳跃的调用关系搞晕。我在第一次复现这个模型的时候最大的教训是先看“数据流”而不是先看“每行代码”——先搞清楚哪些是从外部输入的文件数据哪些是上层模型计算的中间量哪些是下层模型求解出来的最终决策值这样后面调试定位问题会高效很多。3.2 数据准备与参数设置基值体系别搞错综合能源系统最大的坑不是建模逻辑而是“单位算错”。电气工程习惯用有名值kW、MW热力工程习惯用GJ/h、t/h天然气习惯用m³/h混在一个模型里维度完全对不上。代码里推荐把所有量转成统一的标幺值系统选择基准功率S_base 100 MVA基准温度、基准气压根据热网模型设定。下面的表格给出了一个典型算例的参数设置范围实际测算时直接替换成你自己的数据即可参数名称数值/范围说明调度时段数24 h时间分辨率为1小时能源集线器数量3~6个建议先用3个调通逻辑CHP发电效率0.32~0.40燃气轮机典型范围CHP热效率0.42~0.50余热回收后总效率热泵COP3.2~4.5低温热源条件不同蓄热罐容量100~500 MWh取CHP额定热功率的2~4倍蓄热罐充放热效率0.90~0.98充放热各算一次损耗外网购电分时电价峰0.8~1.2元/kWh谷0.3~0.4元/kWh典型峰谷价差天然气价格2.5~3.5元/m³折合热值后约0.25~0.35元/kWh用户售电价格1.0~1.5元/kWh高于上网购电价才有套利空间用户售热价格0.3~0.6元/kWh参考供暖收费标准倒推特别注意蓄热罐SOC的初值和终值约束如果不加“周期始末储能一致性约束”模型会把所有能量集中在第一个时段放完——这是典型的“终端效应”用数学术语说是终值自由导致的最优解失真。代码里通常要加上SOC(1)SOC(T1)这种循环约束才能得到可实际运行的调度方案。3.3 YALMIP建模核心语法双层转单层的“翻译过程”假设下层问题是一个LP如果下层包含0-1变量就得用KKT条件的整数扩展版本这里先讲最常见的纯连续LP情形。下层问题的紧凑形式可以写成max c * x - p * Mx s.t. A * x b x 0其中x代表能源集线器各设备出力、购电量、购气量等连续决策变量p是上层传来的电热价格Mx是购能向量购电量、购气量组合c是售能收入系数向量A、b描述设备运行约束。写下拉格朗日函数L cx - pMx y(b - Ax) - μxKKT条件即对x的梯度为0c - Mp - Ay - μ 0互补松弛y(b - Ax) 0μx 0可行性A x ≤ bx ≥ 0y ≥ 0μ ≥ 0将这些条件作为约束加入上层问题再用大M法处理互补松弛约束。例如 y(b - Ax) 0 这一项引入二进制变量 z写成b - A x M * z y M * (1 - z)这样就把非线性的互补条件转成了一组线性约束。大M的取值很有讲究太小会切掉真实可行域太大则会引起数值病态。实际编码时M一般取约束右侧数值b的量级的10~100倍需要根据模型规模反复测试没有一成不变的值。YALMIP建模的大致写法如下简化示意不是完整代码% 上层变量 P_g sdpvar(1, 24); % 外网购电量 lambda_e sdpvar(1, 24); % 出清电价 lambda_h sdpvar(1, 24); % 出清热价 % 下层变量 P_chp sdpvar(1, 24); % CHP发电功率 H_chp sdpvar(1, 24); % CHP产热功率 P_hp sdpvar(1, 24); % 热泵耗电功率 H_hp sdpvar(1, 24); % 热泵制热功率 SOC sdpvar(1, 25); % 蓄热罐SOC变量多一个时段存初/终值 P_buy sdpvar(1, 24); % 从上级电网购电量 P_sell sdpvar(1, 24); % 向上级电网售电量 % 下层KKT互补松弛线性化辅助变量0-1整数 z binvar(24, 数量); % 具体数量取决于约束个数核心建模逻辑是先分别构建上下层目标函数和约束然后在求解前将下层KKT条件以constraint形式拼接到上层中最后调用optimizeconstraints_upper [ ... 上层供需平衡、价格上下限 ... ]; constraints_lower_kkt [ ... 下层KKT条件线性化 ... ]; constraints_all [constraints_upper, constraints_lower_kkt]; objective -social_welfare; % YALMIP是求最小化社会最优转成负数 ops sdpsettings(solver, gurobi, verbose, 2, mipgap, 0.001); optimize(constraints_all, objective, ops);注意YALMIP默认是求最小值如果上层目标是社会福利最大化则目标函数需要取负号这是初学最容易踩的坑之一。代码跑完以后用value()函数提取变量数值P_chp_opt value(P_chp); lambda_e_opt value(lambda_e); SOC_opt value(SOC);3.4 结果输出与可视化展示求解完成后推荐至少输出四类结果电、热出清价格曲线各能源集线器的购电、购气策略CHP、热泵、蓄热罐的逐时出力/充放热计划市场总体的供需平衡情况。画图方面用MATLAB自带的plot和stairs函数就够用。我的习惯是电价用stairs阶梯图体现市场出清的“分段阶梯”特性设备出力用面积图stacked bar这样能直观看出不同时段CHP和热泵的“分工”。下面给一个电价和设备出力的示例画法figure; stairs(1:24, lambda_e_opt, LineWidth, 1.5, Color, [0.85, 0.33, 0.10]); grid on; xlabel(时段 (h)); ylabel(出清电价 (元/kWh)); title(电力市场出清价格); figure; bar(1:24, [P_chp_opt; P_hp_opt], stacked); legend(CHP发电, 热泵耗电); xlabel(时段 (h)); ylabel(电功率 (MW));这一段的执行建议是先把原代码用给你配好的示例数据跑通确认求解器正常出结果然后再替换成自己的负荷曲线和设备参数——千万别一上来就改模型结构否则出了问题你根本分辨不清是数据问题、建模问题还是求解器设置问题。4. 算例结果解读价格信号如何指挥设备出力4.1 出清价格曲线的两个典型现象算例跑完以后最值得分析的是出清价格曲线。电力出清价格通常呈“峰高谷低”的双峰形状早高峰8:00~11:00和晚高峰17:00~20:00价格走高夜间低谷23:00~次日5:00价格走低。热价曲线则相对平缓因为热负荷本身的昼夜波动比电负荷温和且蓄热罐的“移峰填谷”作用会抹平一部分价格波动。我个人印象最深的现象是当某个时段电力系统供需紧张到上限时出清电价会触及电价上限此时CHP在纯发电意义上的经济性大幅提高即便它的热出力远超当时实际热负荷蓄热罐也会拼命吸收多余热量——这就是“以电定热”模式被市场价格信号自然激发出来的效果。反过来在电价低谷时段热泵运行成本很低系统倾向让热泵多产热、让蓄热罐蓄热CHP则压低出力甚至停机这就是“以热定电”的镜像场景。通过对比不同谷峰价差下的出力结果你会发现一个很明显的决策规律价差越大蓄热罐的“套利”空间越大CHP在高峰时段越愿意满发热泵在低谷时段越愿意多打。这个规律靠拍脑袋也能想得到但双层模型给的是量化结果——到底多存多少热、多发多少电、利润增加多少全部可算。4.2 表格对比场景1固定电价vs 场景2实时出清电价为了直观体现双层出清模型的优势可以在论文中设计两个场景做对比对比维度场景1固定电价/热价场景2双层实时出清价格系统运行总成本万元32.630.1能源集线器总利润万元8.911.4CHP发电量MWh15201660热泵制热量MWh8801010蓄热罐日均吞吐量MWh120230用户购能总费用万元46.245.5场景2中系统运行总成本更低不是因为系统“不赚钱”而是因为实时价格信号引导了更合理的设备调度高峰时段CHP多发、热泵少用低谷时段热泵满负荷制热配合蓄热灌储存。这种“削峰填谷”的效果直接降低了系统总成本同时因为价格信号更真实地反映供需关系能源集线器的利润反而更高形成了帕累托改进。这个对比结果很适合放进论文里作为核心论据。4.3 敏感性分析价格上限和负荷弹性的影响改完主算例下面这几组敏感性分析建议都跑一遍它们能帮你回答论文答辩时最可能被问到的问题。第一组扫描电价上限从0.8元/kWh逐步升到1.6元/kWh观察出清结果和总成本变化。你会发现电价上限提高后高峰时段的出清价格更容易触及上限系统总成本上升但能源集线器利润也上升——市场将更多的“稀缺租金”分配给了供给侧。第二组扫描热价上限热价上限提高会刺激CHP更多产热、蓄热罐更多放热但热价过高时用户热负荷会因弹性需求而下降导致热力市场总交易量减少出现“有价无市”的现象。第三组改负荷弹性系数把用户的电、热需求弹性从0完全刚性调到0.3~0.5中等弹性观察社会总福利的变化。需求弹性越大用户对高价的“抵抗力”越强出清价格波动越平缓系统的总成本曲线变得更加平滑。这些敏感性分析都跑完后模型结论的支撑力就很扎实了。5. 常见问题与调试实录5.1 求解器报“Infeasible problem不可行”怎么办这个报错我遇到得最多而且绝大多数时候不是模型本身无解而是约束之间互相打架了。排查的顺序一般是先检查“供需平衡约束”两侧的量纲和时段时间索引是否对齐。很多代码如下标用错一位导致第1时段的平衡约束和第24时段的数据混在一起自然不可行。检查蓄热罐SOC的上下限是否满足充放热功率约束——这是最容易自相矛盾的地方。如果SOC上限设为500 MWh而单时段最大充热量是300 MWh初值SOC(1)250 MWh则不可能在单时段内把SOC冲到500。解决方法是把初值调整为SOC上限减去最大充热量以上。检查大M值是不是取得太小。最典型的场景某个约束的右侧数值是300你大M只取100那原始可行域直接被切掉一大块。把所有二进制变量固定到初始值把MPEC退化成纯LP问题看是不是LP本身可行。如果LP可行而MILP不可行那问题大概率出在大M或二进制变量的逻辑关系上。5.2 出清价格波动剧烈、出现负电价出现负电价在算法里不代表错误但它通常暗示模型设置有问题。负电价的发生场景一般是外网购电和本地CHP在某个时段同时“争抢”发电供需极度宽松。如果你不希望结果出现负电价有两种处理方式一是给电价增加下界约束比如0.05元/kWh二是在目标函数里给上网电量增加一个很小的惩罚系数。不过纯学术角度看负电价本身是市场机制里客观存在的现象风大、负荷低时真实市场里就会有负电价如果你论文研究的是“高比例可再生能源接入市场”保留负电价结果反而能讲出更有意思的故事。所以我的建议是先不加约束跑一次看负电价发生在什么条件下如果负面结果与你要论证的主题无关再在约束里把价格下限加上。5.3 改参数后结果完全不变先检查单位有一个很隐蔽的坑有些参数在代码里被写成了“标幺值”有些又被写成了“有名值”。例如CHP发电效率用的是0.35标幺值但天然气价格单位是元/m³有名值。混合使用会导致某些约束被“无效放大”或“无效缩小”使得某个设备在优化结果里永远不出力或者永远满出力。一个快速的检查办法是把所有设备出力结果单独打印出来对比相应成本和收入的数量级是否在合理范围内。比如CHP发电1 MWh气耗成本大概在0.5~0.8元/kWh如果你算出来的气耗成本是0.05元/kWh那肯定是某个转换效率多乘了或少除了1000直接把单位检查一遍就能发现问题。5.4 YALMIP求解时间过长或内存爆炸双层市场出清模型由于引入了0-1变量和大量约束求解规模很容易超出预期。24时段模型加6个能源集线器整数变量可能超过2000个Gurobi默认配置下可能要跑几小时。优化求解时间的几个实操建议把MIPGap从默认的1e-4放宽到1e-3工程上完全可以接受求解速度能提升好几倍给二进制变量设置合理的初值用上一轮迭代的解作为热启动能大幅减少分支定界的搜索节点数检查大M值是否过大大M太大会让LP松弛的可行域变形分支定界的边界质量变差求解器会浪费大量节点在无意义的探索上如果模型太大先缩减能源集线器数量或时段数比如从24小时缩到12小时获取初步结果后再逐步放大。ops sdpsettings(solver, gurobi, verbose, 1, ... mipgap, 0.001, gurobi.TimeLimit, 600, ... gurobi.MIPFocus, 1);这里的MIPFocus1表示让Gurobi更注重快速找到可行解而不是一直提升下界对实际调试很有帮助。最后再分享一个经验拿到这类代码不要只当“运行工具”强烈建议把KKT转换那一部分代码逐行手推一遍搞清楚哪个约束对应哪条KKT条件、哪个大M对应哪组互补松弛约束。这个工作做完一遍你对双层优化的理解会提升一个层次——以后再遇到三层模型、多主体博弈、Nash均衡求解都能快速上手。我个人就是靠这个“笨办法”把双层模型真正吃透的后来做多主体博弈的市场模型思路基本是一脉相承。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。