资讯动态

基于Matlab+Yalmip的CCHP冷热电三联供系统优化调度与P2P交易定价实战

发布时间:2026/9/9 11:53:09 来源:尧图企业网站定制
综合能源系统优化调度这套东西我这两年跟了不少项目踩过的坑比吃过的盐还多。最近用Matlab把CCHP冷热电三联供系统的优化调度模型完整跑通了一遍又顺手把P2P交易和能源定价模块接了进去整体框架算是能复用了。这个项目看着不难但实际做起来牵扯的设备建模、约束条件、求解器调参、交易机制设计每一项都能让人折腾好几个晚上。这篇文章我不打算写纯理论推演而是把从建模到求解的完整链路、关键节点的取舍逻辑、以及那些常规文档里不会写的坑全部梳理出来给正在做综合能源调度、微电网P2P交易研究或者单纯需要一套能跑通的Matlab基线模型的朋友当个参考。文章会围绕CCHP系统的优化调度主线和P2P交易定价机制两条线展开前半部分讲建模思路和数学原理后半部分给能直接复用的代码框架和调试经验。1. 项目定位与整体设计思路1.1 CCHP系统到底在调度什么CCHPCombined Cooling, Heating and Power冷热电三联供系统核心逻辑就一句话把燃气轮机或燃气内燃机发电后产生的余热收集起来再通过余热锅炉、吸收式制冷机等设备转化为热能和冷能实现能源的梯级利用。传统电网供电是单纯的电能输入而CCHP系统通过“发电—余热回收—制冷/制热”一条链把一次能源的利用效率从35%~45%提升到80%以上这个数据在实际项目中确实能看到。优化调度的本质是在满足用户电、冷、热负荷需求的前提下决定每台设备在什么时刻出力多少、储能设备何时充放、是否从电网购电或售电、是否参与P2P交易使得整个系统在某一个时间段内的运行成本最低或综合效益最高。说白一点就是给系统装上“大脑”让它在“用燃气轮机发电”和“直接从电网买电”之间做选择在“用吸收式制冷机”和“用电制冷机”之间做选择。这些选择每15分钟或每小时要做一次所以实际仿真中通常把一天划分为24个时段也可以细化为96个时段形成一个多时段的优化决策问题。单看设备出力并不复杂难点在于设备和设备之间是耦合的。燃气轮机发多少电直接决定了余热回收量有多少余热多了吸收式制冷机就有足够的驱动热源燃气锅炉就可以少烧气。这种强耦合关系必须用数学约束来描述而且设备之间存在启停状态、爬坡速率、储能SOC上下限等非线性特性处理起来就比较头疼。1.2 为什么用Matlab而不是Python或GAMS我在早期项目里用过GAMS建模也试过Python的PuLP和Pyomo最终主力方案还是固定在Matlab上核心原因有三个。第一Yalmip让模型搭建的效率极高。Yalmip是一个Matlab下的建模工具箱它允许你用接近自然数学语言的方式定义决策变量、约束条件和目标函数然后用统一接口调用CPLEX、Gurobi、MOSEK等求解器。定义变量就是sdpvar写约束就是一行不等式非常直观。第二Matlab的数据处理生态对读取负荷曲线、电价曲线、设备参数这种表格型数据非常友好。我们的项目里大量数据来自Excel或CSV文件readtable、xlsread配合timeseries处理起来顺手。这一点在快速搭建原型、反复对比多场景结果时特别重要。第三Matlab的调试体验。优化问题一旦求不出可行解最容易出问题的是约束条件写错。Matlab可以随时在工作区查看变量的维度、数值配合断点检查比在黑框框里运行脚本要直观得多。当然Python在机器学习辅助优化、大规模并行计算方面有优势但就“快速搭建一个能跑、能改、能出结果的调度模型”这件事MatlabYalmip目前仍然是最高效的组合。注意如果你的模型要部署到生产环境或者要处理上万节点规模的问题建议最终迁移到Python或GAMS。Matlab更适合做研究验证和方案对比这也是学术论文中Matlab代码出现频率极高的原因。1.3 系统架构与模块划分项目的主程序并不是一个巨大的脚本而是拆成了四个层次分明的模块。第一层是数据输入模块负责读取设备参数额定功率、效率、爬坡率、负荷预测曲线、分时电价、燃气价格以及P2P交易的对手方报价信息。第二层是建模与求解模块这是核心负责定义决策变量、目标函数和约束条件并调用CPLEX求解。第三层是结果分析模块把求解得到的设备出力、储能SOC、购售电功率、P2P交易电量后处理成可视化的曲线和表格。第四层是多场景循环模块用于进行方案对比比如“有P2P交易和无P2P交易”的成本差异或者“不同碳价水平下”的系统运行策略变化。这种模块划分的好处是换一组数据不用改模型换一个交易场景不用改设备约束逻辑解耦之后调试成本大幅度下降。我第一次做的时候把所有代码写在一个脚本里结果改一个参数要全局搜索非常痛苦。后来重构之后整个项目的可维护性提升了不止一个档次。2. 设备建模与能量平衡约束2.1 五大核心设备的数学模型CCHP系统的能源站里常见的设备配置是一台燃气轮机、一台余热锅炉、一台吸收式制冷机、一台电制冷机和一台燃气锅炉外加上储能装置。每台设备的数学模型是优化调度问题的“砖块”需要先敲定。燃气轮机的建模关键是电效率和热电比。燃气轮机在发电的同时产生高温烟气余热通过余热锅炉回收用于供热。模型里可以用固定效率乘以输入燃气功率得到发电功率也可以用与负载率相关的效率曲线。我使用的模型是分段线性化% 燃气轮机模型P_gt表示发电功率Q_rec表示余热回收功率 % eta_gt为发电效率eta_rec为余热回收效率LHV为天然气低位热值 P_gt eta_gt * V_gas * LHV; % 发电功率 Q_rec eta_rec * (1 - eta_gt) * V_gas * LHV; % 余热回收功率其中V_gas是天然气消耗量单位m³/h。这种简化模型虽然没考虑变工况下效率的变化但对于日前调度来说精度足够。余热锅炉负责把燃气轮机的烟气余热转化为蒸汽或热水热能模型中表现为一个热交换效率系数。吸收式制冷机利用热水或蒸汽驱动制冷循环它的COP制冷性能系数一般在0.7~1.3之间低于电制冷机的COP通常3~5所以从能源效率角度电制冷机往往更“划算”但吸收式制冷机使用的是“免费”的余热综合考虑后者在综合能源系统中依然有重要地位。燃气锅炉是热力的补充来源当余热回收量不足时它启动补燃。每台设备需要设置出力上下限约束和爬坡约束。比如燃气轮机最小出力通常是额定出力的30%到50%而爬坡速率决定了相邻时段出力的变化上限。不设置爬坡约束求解器可能在某个时段让设备出力突跳这在物理上不可行。2.2 能量平衡约束的搭建能量平衡是优化模型里绝对不能出错的硬约束。它实际上表达的是在任何时段系统供给与负荷需求必须相等。电功率平衡约束可以写成P_gt P_pv P_grid_buy P_p2p_buy P_dis P_load P_ec P_grid_sell P_p2p_sell P_ch其中P_grid_buy和P_grid_sell是电网购电和售电功率P_p2p_buy和P_p2p_sell是P2P市场交易量P_ec是电制冷机耗电P_ch和P_dis是储电装置充放电功率。热功率平衡约束是燃气轮机余热回收热量Q_rec加上燃气锅炉产热Q_boiler等于热负荷Q_heat_load加上吸收式制冷机消耗的热能加上储热充放热还要考虑可能的热能弃置。冷功率平衡约束则是吸收式制冷机供冷量加上电制冷机供冷量等于冷负荷需求。这里有三个容易出错的地方。第一个是储能充放电不能同时进行。数学上需要引入二进制变量让P_ch和P_dis不能同时大于0写成P_ch M * alpha_ch、P_dis M * alpha_dis、alpha_ch alpha_dis 1的形式M是一个足够大的数。第二个是P2P买卖的方向区分。P2P交易中一个用户在同一时段不能既是买方又是卖方否则会在结算时出现自我对敲的情况。这个约束也需要二进制变量来限制。第三个是电网购售电的方向互斥。在某些地区政策下同一个计量点不允许同时买入和卖出电量这个约束视具体问题而定但一定要确认清楚。2.3 储电储热环节的处理储能装置在CCHP系统中的角色是“时间搬移器”——把低谷时段的电能或热能搬到高峰时段使用。储电模型的核心是SOC荷电状态的递推方程SOC(t1) SOC(t) eta_ch * P_ch(t) - P_dis(t) / eta_dis - sigma * SOC(t)其中eta_ch和eta_dis分别是充放电效率sigma是自放电率。SOC需要设置上下限比如0.2到0.9末端时段还要设置SOC回落到初始值以保证调度方案的周期性可重复。这个末端约束经常是新手容易忽略的不加上它会得到“最后几个时段把储能放光”的极端策略。储热的模型与储电类似但要注意热损失率通常比电储能高自放电参数需要单独标定。3. 优化目标与P2P交易定价机制3.1 目标函数设计单目标与多目标的取舍优化调度问题最基础的目标函数是“系统总运行成本最小化”其中成本主要由四部分构成购气成本、电网购电成本、P2P购电成本再减去售电和P2P售电的收入。用Yalmip表达目标函数时可以这样写objective sum(c_gas * V_gas) sum(price_grid_buy .* P_grid_buy ... - price_grid_sell .* P_grid_sell) sum(price_p2p_buy .* P_p2p_buy ... - price_p2p_sell .* P_p2p_sell) ... % 设备启停成本 sum(switch_cost_gt .* z_start_gt);这是单目标问题求解速度最快。现在很多研究还会加入碳排放目标形成多目标优化。常见做法是把碳排放在目标函数里加上一个碳价系数转化为碳排放成本从而仍然保持单目标的形式。我之前做过一个方案用权重法把运行成本和碳排放量两个目标加权为单一目标通过变化权重系数得到帕累托前沿。这个方法在Matlab里实现很简单只是需要循环求解多次。多目标优化的另一种思路是用gamultiobj遗传算法求解非凸问题但对于混合整数线性规划模型Cplex配合加权法通常比遗传算法更可靠、更快。我的习惯是能线性化的绝对不用非线性求解器能用凸优化的不用启发式算法。3.2 P2P交易交互与定价逻辑P2P能源交易是综合能源系统研究的热点它的核心思想是让能源产消者Prosumer直接进行点对点交易跳过传统中间商的加价环节实现“用户卖电给用户”。在系统调度的视角里P2P交易多了一个“参与者之间的互动”维度。P2P交易要回答两个问题交易多少交易量、以什么价格成交结算价。我在项目中实现了两种定价机制。第一种是集中式的供给侧定价本质上是“价格跟随供需关系”设定一个内部P2P价格这个价格介于发电方成本价和购电方电网电价之间双方都有动力参与。每个时段的价格可以设定为P2P_price alpha * seller_cost (1 - alpha) * grid_price其中alpha是谈判系数通常取0.5代表公平折中。第二种是双层博弈定价上层是交易平台制定P2P电价策略下层是各个用户根据价格优化自身的调度策略。这种机制会用KKT条件或迭代求解法来处理实现起来复杂一些但更贴近真实的竞价过程。实际仿真中我发现集中式定价虽然简单但已经能反映P2P交易的效益本质——即让光伏充足的家庭把多余电量卖给出力受限的邻居而不是低价卖给电网再高价买回来。注意P2P交易在学术模型中往往是“净额结算”的假设即所有用户的P2P购买量和出售量在整个系统内是平衡的即sum(P_p2p_buy) sum(P_p2p_sell)。这个约束是实现市场出清的关键必须显式地写进模型。3.3 交易模块与调度模块的耦合方式在Matlab代码架构中P2P交易模块可以和设备调度模块放在同一个优化问题中求解也可以分层迭代求解。同层求解的方式是把所有用户的设备约束和交易约束写进同一个混合整数线性规划问题一次性求出全局最优解。这种方式理论上最优但如果用户数量较多比如几十个节点问题规模会迅速膨胀求解时间指数上升。当节点数超过20以上时我建议改用交替方向乘子法ADMM进行分布式求解。ADMM的思路是每个用户各自求解自己的调度子问题然后通过一个协调变量不断迭代修正P2P交易量直至收敛。这种方式保护了各用户的隐私因为它不需要共享所有设备参数符合市场化交易的真实属性。我在Matlab里实现过一个简化的ADMM框架主循环就三层% ADMM主循环伪代码 for iter 1:max_iter for n 1:N [x_n(iter), obj_n] solve_subproblem(n, lambda_hat); end % 更新拉格朗日乘子和全局变量 z_hat mean(x_n(iter)); lambda_hat lambda_hat rho * (x_n(iter) - z_hat); % 检查原始残差和对偶残差是否收敛 if norm(x_n(iter) - z_hat) eps norm(z_hat - z_hat_prev) eps break; end end实际跑下来ADMM大约20到50次迭代就能收敛到较高的精度但参数的选取惩罚因子rho的值非常影响收敛速度。rho过小导致震荡过大导致收敛慢需要根据问题的规模做几次试验。4. 实操过程与代码实现要点4.1 完整建模框架从数据读取到结果输出为了给读者一个可以落到代码上的整体框架我把项目的完整执行流梳理成如下步骤。第一步数据准备。我这里以三个能源产消者为例每个产消者包含分布式光伏、储能、电负荷和热负荷其中一个产消者带有燃气轮机CCHP系统。数据包括分时电价取自典型峰谷平三段式电价、天然气价格、设备参数和负荷曲线。所有数据存到一个结构体params中。第二步变量定义。使用Yalmip的sdpvar定义连续变量用binvar定义二进制变量如设备启停、充放互斥。需要注意变量的维度一般为N产消者数×T时段数。第三步约束编写。用Constraints []累积约束这就是Yalmip的优雅之处。第四步求解。调用Cplex求解器配置求解时间限制和MIP间隙容忍度。第五步后处理。提取结果画出设备出力曲线、P2P交易量柱状图和SOC曲线。4.2 核心代码段主问题求解我写一个精简但完整可跑的脚本框架展示主问题求解的核心逻辑。这个框架省去了很多细节但结构是完整的。%% 综合能源系统CCHP优化调度主程序框架 clear; clc; yalmip; % 1. 读取数据这里直接手写示例数据实际项目用readtable从Excel读取 T 24; % 调度时段数小时 N 3; % 产消者数量 % 基础参数 Price_elect [repmat(0.5, 1, 6), repmat(0.9, 1, 10), repmat(1.4, 1, 5), repmat(0.9, 1, 3)]; % 分时购电价 元/kWh Price_gas 2.8; % 天然气价 元/m3 P_load 50 20 * sin((1:T)/24 * 2 * pi) randn(1, T) * 2; % 电负荷示例 Q_load 30 10 * cos((1:T)/24 * 2 * pi) randn(1, T) * 2; % 热负荷示例 % 2. 定义决策变量 P_gt sdpvar(1, T); % 燃气轮机发电功率 kW V_gas sdpvar(1, T); % 天然气消耗量 m3 P_grid_buy sdpvar(1, T); % 电网购电功率 kW P_grid_sell sdpvar(1, T); % 电网售电功率 kW P_p2p sdpvar(N, N, T); % 产消者间P2P交易电量 kW SOC sdpvar(1, T1); % 储能SOC包含初始时刻 P_ch sdpvar(1, T); % 储电充电功率 kW P_dis sdpvar(1, T); % 储电放电功率 kW alpha_ch binvar(1, T); % 充电状态标识 alpha_dis binvar(1, T); % 放电状态标识 % 3. 约束条件 Constraints []; % 电功率平衡约束这里简化为单个CCHP系统P2P交易作为净输入 % P_gt P_grid_buy P_p2p_net_in P_dis - P_ch P_load for t 1:T Constraints [Constraints, P_gt(t) P_grid_buy(t) P_dis(t) ... sum(P_p2p(:, t, t)) - P_ch(t) - P_grid_sell(t) P_load(t)]; end % 燃气轮机约束 eta_gt 0.35; LHV 9.7; % kWh/m3 Constraints [Constraints, P_gt eta_gt * V_gas * LHV]; Constraints [Constraints, 50 P_gt 200]; % 出力上下限 % 储能SOC递推约束 eta_ch 0.95; eta_dis 0.95; C_bat 300; % 储能容量 kWh SOC_init 0.5; Constraints [Constraints, SOC(1) SOC_init * C_bat]; for t 1:T Constraints [Constraints, SOC(t1) SOC(t) eta_ch * P_ch(t) - P_dis(t)/eta_dis]; end Constraints [Constraints, 0.2 * C_bat SOC 0.9 * C_bat]; Constraints [Constraints, SOC(T1) SOC_init * C_bat]; % 末端状态回归 % 储能充放互斥约束 M 300; Constraints [Constraints, P_ch M * alpha_ch, P_dis M * alpha_dis]; Constraints [Constraints, alpha_ch alpha_dis 1]; % P2P交易量的对称性约束所有参与者之间 % 简化每个时段P2P交易净量平衡 for t 1:T for n 1:N Constraints [Constraints, sum(P_p2p(n, :, t)) sum(squeeze(P_p2p(:, n, t)))]; end end % 4. 目标函数 Cost sum(Price_gas .* V_gas) sum(Price_elect .* P_grid_buy) ... - sum(Price_elect * 0.8 .* P_grid_sell); % 售电价取购电价的80% objective Cost; % 5. 求解 options sdpsettings(solver, cplex, verbose, 2, showprogress, 1, mip.tolerances.mipgap, 0.001); optimize(Constraints, objective, options);这段代码是骨架直接复制到Matlab里还需要补上变量完整定义和P2P的细节但核心逻辑已经完整。4.3 求解器的选择与性能设置Cplex并不是MathWorks自带的需要单独安装并配置addpath。我在Windows上使用的是Cplex 12.10版本通过Cplex的Matlab接口文件和Yalmip对接。如果不想用商业求解器Gurobi也是不错的选择学术免费性能甚至在某些问题上比Cplex更好。完全开源的替代方案是SCIP或Cbc但求解速度明显慢于商业求解器。求解性能的调优有一个经验原则尽量少用二进制变量。每增加一个二进制变量混合整数规划问题的搜索空间指数膨胀。所以建模时要想尽办法把非凸约束转化为线性约束避免不必要的整型变量。比如充放互斥约束如果可以不显式建模通过合理的成本设置让求解器“自动”选择正确方向就能省去一个二进制变量。另一个经验是设置合理的MIP Gap容忍度。如果求解时间过长可以先把mip.gap设置到0.011%快速得到近似最优解再根据需求逐渐收紧。很多工程的场景下1%的最优性差距对结果影响不大但求解时间可能缩短数倍。4.4 结果可视化与敏感性分析结果可视化我通常画三张图第一张是24小时的功率平衡图叠加显示负荷、燃气轮机出力、电网购电、P2P交易曲线第二张是储能SOC变化图第三张是P2P交易量的热力图横轴是时间纵轴是交易对颜色代表交易量大小。这些图用Matlab的plot、bar和heatmap函数就能实现。敏感性分析方面我最常做的是改变碳价系数和天然气价对比系统运行策略的变化。结果通常是天然气价越高燃气轮机发电量减少电网购电量比例提升碳价越高燃气轮机的低碳优势被放大但前提是天然气相对煤电更清洁这个结论在不同电网排放因子下会有差异需要具体数据集来验证。5. 常见问题与排查技巧实录5.1 求解器报“Infeasible”怎么办“模型不可行”是优化问题调试中最头疼的情况。几百行约束到底哪一条导致矛盾我的排查思路是固定化排查法。第一步把所有整数约束放宽松比如把二进制变量的上下限给成连续域看是否有连续可行解。如果没有说明是连续约束冲突问题可能出在能量平衡等式上。第二步分模块测试先单独求解只含电功率平衡和设备约束的子问题再加储能约束最后加入P2P交易约束每加一组约束就求解一次可以快速定位是哪一组约束导致不可行。Yalmip提供了一个比较实用的排查工具即在求解之前检查约束矩阵的线性相关性虽然不能直接指出矛盾但能帮助发现重复定义或维数不对的约束。5.2 P2P交易量一直为0怎么排查P2P交易在模型里没有交易量通常有三个原因。第一价格信号设置不合理。如果P2P购电价高于电网购电价那购电方没有理由通过P2P市场购买所以P2P价格必须介于卖方的成本价和买方的电网电价之间。第二P2P交易的线路约束或对称性约束写错了。比如两个产消者之间的交易量约束P_p2p(n1, n2, t) P_p2p(n2, n1, t)这个约束在有些情况下会限制净交易量的表达需要区分“交易量”和“净交换量”这两个概念。我用的模型是定义有向交易量x_ij表示i卖给j的电量然后有sum_j x_ij等于总售电sum_i x_ij等于总购电。第三目标函数里缺少P2P交易的收益项。如果P2P交易只存在于约束中但目标函数完全不反映它的收益或成本那求解器自然会把它置零因为没有驱动力让它去交易。5.3 求解时间过长一个真实案例我遇到过一个情况同样的模型规模在3个产消者24个时段时Cplex只需要两三秒扩展到10个产消者后一个多小时还算不出来。分析下来最大的问题是P2P交易量定义成了一个N×N×T的完整矩阵10个产消者就意味着每个时段有90个交易变量再加上对称约束和互斥约束二进制变量爆炸性增加。那次我改用了一个技巧把P2P交易量建模为节点净注入功率不再逐对定义交易量。也就是说用P_net_in(n, t)表示第n个产消者在t时段的净购入功率正值是净购入负值是净售出然后只需要一个全局平衡约束sum(n, P_net_in) 0就行。这样P2P变量的数量从N×N×T直接降到N×T模型规模大幅缩减Cplex在几十秒内就能给出最优解。代价是失去了交易对的粒度信息没法画“谁卖给谁”的网络图。如果确实需要交易网络结构再在后续阶段用潮流分配算法将净功率分解到各条交易线路这个过程叫“交易后分配”可以单独处理。5.4 敏感数值导致的数值稳定性问题Matlab求解过程中如果多个单位混用比如功率用kW、能量用kWh、价格用元/kWh但燃气用m³、热值用kWh/m³数值范围会跨越3到5个数量级Cplex内部的数值稳定性会变差甚至出现错误的判定。我的经验是统一采用SI单位制功率用kW能量用kWh热值统一换算成kWh/m³价格统一用元/kWh这样目标函数中的各项数量级比较接近求解更稳定。另外为了避免“大M法”中M的取值过大导致数值问题M应尽量取紧。比如储能充放电功率上限是200kW那么M就可以取250而不是随意写一个10000。过大的M不仅坏数值还会产生松弛余量导致约束形同虚设。6. 写在最后的几个实操心得如果你是自己搭这个系统建议第一版先不要追求P2P和定价机制的复杂度先把单CCHP系统的优化调度跑通、结果合理再往里面加P2P模块。这个顺序能帮你把模型调试的难度拆解开而不是一次性面对几百行约束报错却不知道问题出在哪。第二个建议是重视数据的时间粒度和一致性。24时段的数据和96时段的数据对储能SOC、爬坡约束的刻画深度完全不同。如果设备的爬坡速率是kW/15分钟但模型里用的时段是1小时爬坡约束要记得乘以时段系数这个换算错误我遇见过不止一次。第三个建议是P2P定价参数要多做敏感性分析。alpha从0.3到0.7交易成本和收益的变化往往不是线性的。你可能会发现P2P总交易量在某个价格附近突然跳变这是参与者从“不交易”到“交易”的阈值效应。理解这个拐点比纠结精确的价格数字更有价值。CCHP优化调度和P2P交易这个方向模型可以做得非常深但核心始终是那几个设备约束和能量平衡。把地基打牢了才能在屋顶上盖出漂亮的阁楼。希望这份梳理能帮你少走一些弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价