
最近在给几个学生引导综合能源系统优化调度方向的项目发现大家上手时最大的困惑不是某个数学公式看不懂而是面对“冷热电联产”“微网”“优化调度”这一堆词的时候不知道从哪下手。我自己最早接触这个方向是在一个园区级冷热电联产项目上当时要用 Matlab 搭一套调度程序让燃气轮机、余热锅炉、溴化锂吸收式制冷机配合起来在满足园区冷热负荷的前提下把运行成本压到最低。那时候没有太多现成参考资料基本是靠啃论文和反复调参一步步趟过来的。这篇文章我打算把综合能源系统优化调度这个方向的建模思路、Matlab 程序实现步骤、还有微网优化调度入门的学习路线从头到尾梳理一遍。面向的是刚接触这个方向的研究生、做项目需要快速落地的工程师。我会把我实际做项目时踩过的坑、总结的经验都放进去包括目标函数怎么设计、约束条件怎么处理、求解器怎么选、结果不收敛怎么办等等希望你看完能少走一些弯路。1. 综合能源系统优化调度到底在解决什么问题1.1 冷热电联产系统的能量流与耦合关系先把系统内部的能量关系捋清楚。一个典型的冷热电联产CCHP系统核心设备是燃气轮机或者燃气内燃机烧天然气发电电能优先供给用户电负荷不够就从电网买电多了可以卖给电网。关键在于燃气轮机发电会产生大量高温烟气这部分余热不回收就是纯粹的浪费回收之后可以通过余热锅炉产生蒸汽或者热水直接供给热负荷也可以驱动溴化锂吸收式制冷机制出冷冻水供给冷负荷。这就是冷热电联产中“联”字的含义一条天然气输入变成电、热、冷三条输出。但耦合远不止“联产”这么简单。夏季冷负荷大、热负荷小吸收式制冷机需要大量余热来驱动这时候为了满足制冷需求燃气轮机就得使劲发电结果发出来的电可能用不完。冬季反过来热负荷大但吸收式制冷需求低余热又可能不够用。这就是综合能源系统里常说的“热电比矛盾”。所以调度问题的核心不是把每个设备单独调好而是找到整个系统在不同季节、不同时段下的全局最优运行点。比如夏季某个时段燃气轮机发 300 千瓦电、回收 400 千瓦余热其中 300 千瓦余热送去制冷、100 千瓦供给生活热水同时从电网买 50 千瓦电补足负荷缺口——这个组合是否最优取决于电价、气价、设备效率、负荷水平等多个因素。优化调度做的就是这件事。1.2 为什么不能用传统电力调度思路很多初学者上来就套电力系统经济调度的框架目标函数是发电成本约束是功率平衡和机组出力上下限。放到综合能源系统里这个框架存在几个根本性的问题。第一个问题是能量种类。电力调度只看有功功率但综合能源系统里电、热、冷三种能量各有各的平衡方程而且换热站、供热管网存在热惯性冷水的冷冻温度也不是随便定的。第二个问题是设备模型。燃气轮机的发电效率、余热回收量、溴化锂机组的制冷性能系数都随着负载率变化不是固定常数。第三个问题是时间维度。储能设备蓄电、蓄热、蓄冷的引入让调度变成了跨时段决策白天电价高、光伏出力多的时候可能多充电存下来晚上用或者夜间谷电时段把蓄热锅炉烧起来白天峰电时段放热。这些是传统电力调度里不太会集中出现的情况。我自己就踩过一个很典型的坑第一次做这个项目时把热负荷平衡方程和电负荷平衡方程分开写没考虑燃气轮机发电和余热回收之间的换算关系结果算出来的方案里燃气轮机使劲发电但余热又用不完白白浪费。后来才意识到设备之间的能量流必须通过联产比、余热回收率这些参数建立约束否则模型在物理上就是错的。2. 优化调度数学建模目标函数与约束条件的取舍2.1 目标函数设计经济性、环保性还是两者兼顾建模第一步是确定优化目标这也是最容易反复的一步。我个人习惯先把单目标做好再谈多目标。最常见的单目标是运行成本最小化min C Σ( C_fuel C_grid_buy - C_grid_sell C_maint )其中 C_fuel 是天然气消耗成本C_grid_buy 是向电网购电的成本分时电价下不同时段价格不同C_grid_sell 是上网售电的收益C_maint 是设备运维成本按发电量或功率线性折算。实测下来天然气价格和分时电价的比例关系对调度结果影响非常显著如果天然气价格高而峰谷电价差拉大系统会自动倾向于多购电、少发电反过来气价低的时候燃气轮机就会多出力。如果想兼顾环保性可以把 CO2 排放量化进目标函数。天然气燃烧有排放系数电网购电对应间接排放注意不同省份电网的排放因子不一样然后可以加一个碳税权重变成成本项。我见过有人做加权多目标优化给运行成本乘以权重 w1给碳排放乘以权重 w2然后扫描权重画出 Pareto 前沿。这个思路适合发论文但工程上我建议还是先把单目标跑透再去考虑多目标加权。这里有一个工程经验值得分享目标函数的数量级差异会直接影响求解器表现。如果成本在 1e5 量级功率约束在 100 量级部分求解器在数值上会不稳定。我习惯把成本统一除以一个基准值比如 10000或者把成本单位从“元”换成“万元”收敛速度可能提升数倍。2.2 关键约束条件解析约束条件决定模型是否可信。以下是综合能源系统调度中绕不开的几个核心约束电功率平衡P_gt(t) P_grid(t) P_bat_dis(t) - P_bat_chg(t) P_load(t)每个时段 t 都要满足。热功率平衡Q_hr(t) × η_hx - Q_heat_load(t) Q_tank_dis(t) - Q_tank_chg(t) 0η_hx 是热交换器效率一般在 0.85~0.95。冷功率平衡Q_ac(t) × COP_ac - Q_cool_load(t) 0如果有电制冷机还要加上电制冷部分。设备出力上下限每个设备出力有最小值和最大值燃气轮机有最小技术出力低于这个值运行不稳定。爬坡约束|P_gt(t) - P_gt(t-1)| ≤ ramp_rate × Δt。燃气轮机爬坡率一般取额定容量的 20%~30% 每小时。储能状态约束SOC(t1) SOC(t) (P_chg × η_ch - P_dis / η_dis) × Δt / E_cap同时 SOC 要限制在 [SOC_min, SOC_max]调度周期结束时 SOC 要回到初始值或者满足一个设定值。启停约束如果需要考虑机组启停引入 0-1 变量限制频繁启停。初学者最容易漏掉的是爬坡约束和储能 SOC 的周期闭环。我审过不少论文里面储能 SOC 曲线跳来跳去或者蓄电池前一天晚上充满、第二天早上放空这种情况在物理上根本不可行。约束条件宁多勿少但也要注意冗余约束会让求解变慢需要平衡。2.3 模型参数设置的经验值参考这里给一组我在实际项目中常用的初始参数你可以根据自己项目的具体设备情况调整参数取值示例备注燃气轮机额定功率500 kW根据实际负荷定发电效率0.30 ~ 0.40随负载率变化余热回收率0.40 ~ 0.55随工况变化溴化锂机组COP0.70 ~ 1.30单效/双效差异大蓄电池容量1000 kWh对应2小时额定功率蓄电池充放效率0.90 / 0.90电芯效率加损耗SOC范围[0.2, 0.9]保护电池寿命分时电价峰/平/谷1.2 / 0.8 / 0.4 元/kWh各地差异较大燃气轮机的效率和余热回收率可以做成关于负载率的分段函数或者二次曲线但初学阶段先用常数近似也够用。等你把整个调度框架跑通之后再去把设备模型精细化通常收益更大。3. Matlab程序实现从建模到求解的全流程3.1 程序框架与模块划分用 Matlab 做这个项目我习惯把程序分为五个模块数据输入模块、设备建模模块、约束生成模块、求解模块、结果输出模块。数据输入模块读入负荷曲线24 小时的电/热/冷负荷、分时电价、天然气价格、设备参数通常用 Excel 或 .mat 文件存储。设备建模模块把每个设备封装成输入参数加输出可行域的函数。约束生成模块把上一章的各种约束写成矩阵形式Aeq·x beq、A·x ≤ b、lb ≤ x ≤ ub。求解模块负责调用求解器。结果输出模块画图各设备出力曲线、储能 SOC 曲线、成本累计曲线、负荷平衡检查。对于初学阶段我不建议直接上 YALMIP 这种高级工具箱。先用 Matlab 自带的函数把线性模型跑通理解约束矩阵是怎么构造的再上工具箱。很多同学一上来就装 YALMIP 加 Gurobi结果模型写出来全是 bug都不知道从哪开始调试。先写底层、再上框架这个顺序能让你对模型本身有更扎实的理解。3.2 核心代码实现详解下面给一个最小示例展示简化 CCHP 系统的 Matlab 调度代码框架。这里把变量定义为三段x(1)~x(T) 是燃气轮机发电功率x(T1)~x(2T) 是从电网购电功率x(2T1)~x(3T) 是吸收式制冷机消耗的热量。用linprog求解这个示例的核心是展示约束矩阵的构造方式。%% 综合能源系统CCHP简化调度示例 clc; clear; close all; T 24; % 调度周期单位小时 % 负荷数据示例实际项目从Excel读入 t (0:T-1); P_load 200 80*sin(2*pi*t/24 pi/2) 20*randn(1,T); % 电负荷 H_load 100 40*sin(2*pi*t/24 pi); % 热负荷 C_load 80 30*cos(2*pi*t/24); % 冷负荷 % 设备参数 eta_gt 0.35; % 燃气轮机发电效率 eta_hr 0.50; % 余热回收效率 COP_ac 1.0; % 吸收式制冷机COP P_gt_min 50; P_gt_max 300; % 燃气轮机出力上下限 % 分时电价峰平谷三段示例 price_buy zeros(1,T); price_buy(8:11) 1.2; % 峰 price_buy(12:17) 0.8; % 平 price_buy(18:22) 1.2; % 峰 price_buy(23:24) 0.4; % 谷 price_buy(1:7) 0.4; % 谷 price_sell 0.5 * price_buy; % 上网电价按购电价50% % 天然气参数 gas_price 3.0; % 元/立方米 LHV 9.7; % 天然气低热值 kWh/m3 % 决策变量: x [P_gt(1:T), P_grid(1:T), P_ac(1:T)] nvar 3*T; % 目标函数系数 f最小化 c * x f zeros(nvar, 1); for i 1:T % 燃气轮机成本项燃气耗量 P_gt / eta_gt / LHV 方标每小时 f(i) gas_price / (eta_gt * LHV); % 对应 P_gt f(Ti) price_buy(i); % 对应 P_grid购电成本 % 注售电收益在约束中处理成本函数里处理 % 吸收式制冷机侧本身不直接产生燃料成本余热利用成本已计入P_gt % 运维成本按功率线性近似 f(i) f(i) 0.05; % 单位元/kWh end % 变量边界 lb zeros(nvar, 1); ub Inf(nvar, 1); lb(1:T) P_gt_min; ub(1:T) P_gt_max; lb(T1:2*T) 0; ub(T1:2*T) 500; % 购电上限 lb(2*T1:3*T) 0; ub(2*T1:3*T) 200; % 制冷机组输入热量上限 % 等式约束 Aeq * x beq % 这里暂时只展示电平衡热平衡和冷平衡同理扩展 Aeq zeros(T, nvar); beq zeros(T, 1); for i 1:T % 电功率平衡: P_gt(i) P_grid(i) P_load(i) Aeq(i, i) 1; % P_gt Aeq(i, Ti) 1; % P_grid beq(i) P_load(i); end % 不等式约束 A * x b热平衡以不等式形式近似实际需要更精细建模 % 这里演示燃气轮机余热约束P_gt * eta_hr / eta_gt 必须大于等于热负荷 A zeros(T, nvar); b zeros(T, 1); for i 1:T A(i, i) eta_hr / eta_gt; % 余热产热量系数乘P_gt b(i) H_load(i); % 余热应满足热负荷 end % 求解线性规划 options optimoptions(linprog, Display, iter, Algorithm, dual-simplex); [x, fval] linprog(f, A, b, Aeq, beq, lb, ub, options); % 提取结果 P_gt_opt x(1:T); P_grid_opt x(T1:2*T); P_ac_opt x(2*T1:3*T); % 可视化 figure; subplot(2,2,1); bar(1:T, P_gt_opt); hold on; bar(1:T, P_grid_opt); legend(燃气轮机出力,电网购电); xlabel(时段/h); ylabel(功率/kW); subplot(2,2,2); stairs(1:T, P_load, r); hold on; plot(1:T, P_gt_optP_grid_opt, b--); legend(电负荷,实际供电); subplot(2,2,3); bar(1:T, P_ac_opt); xlabel(时段/h); ylabel(制冷机输入热量/kW); subplot(2,2,4); plot(1:T, cumsum(x .* f), k); xlabel(时段/h); ylabel(累计成本/元);上面这个代码在物理上做了很大的简化热平衡只用了不等式近似冷负荷也没有真正闭合。但它的价值在于展示了约束矩阵的构造过程。等你理解了这个过程再用 YALMIP 写起来会顺手很多。YALMIP 的写法更接近数学表达式比如Constraint [P_gt(1:T) P_grid(1:T) P_load(1:T)]可读性好很多但底层逻辑跟上面是一样的。3.3 求解器选型与参数配置Matlab 自带的求解器基本能满足学习和大多数工程场景问题类型适用求解器说明线性规划 LPlinprog适合入门速度快混合整数线性规划 MILPintlinprog设备启停、0-1变量二次规划 QPquadprog成本函数为二次非线性规划 NLPfmincon设备效率曲线非线性全局优化ga / particleswarm智能算法不保证最优我的建议路线是先用linprog跑通纯线性模型第二步引入储能和启停逻辑用intlinprog。储能引入需要加 SOC 递推约束此时变量量级会翻一倍但你会在实践中理解为什么 SOC 约束要用等式写。第三步如果设备效率想用更精确的二次曲线尝试quadprog。等这些都通了再去考虑 YALMIP Gurobi 或者 Cplex。原因很简单越高级的工具一旦结果不对定位 bug 越困难。我特别强调一点用intlinprog时0-1 变量的规模直接决定求解时间。如果一个 24 时段的调度里有 10 台设备需要启停变量那就是 240 个整数变量默认分支定界可能要跑几分钟。如果数据量再大建议先把松弛问题算一遍检查约束是否合理再引入整数变量。我遇到过很多初学者一上来就在大模型里塞整数变量结果求解器跑了一个小时还没收敛其实问题不是模型难而是约束冗余太多。4. 微网优化调度基础从园区级到楼宇级4.1 微网与综合能源系统的区别与联系微网可以理解为综合能源系统的一种典型实现形式但侧重点略有不同。微网强调“网”的概念一个区域内分布式电源光伏、风电、燃气发电、储能、负荷通过公共耦合点与主网相连既可以并网运行也可以孤岛运行。综合能源系统则更强调能源形式的多样性电、热、冷、气微网更强调运行模式的可切换性。学习调度的时候这两块是可以放在一起学的微网里解决“什么时候充放电、什么时候并网买电”的问题综合能源系统里解决“什么时候开机、余热往哪送、制冷还是供热”的问题。实际工程中绝大多数园区微网本身就是 CCHP 加光伏加储能的构型。所以你完全可以把微网调度看作综合能源系统调度的一个子集先把微网那套充放电逻辑吃透再往里面加冷热电联产设备循序渐进。4.2 典型微网调度场景与目标一个典型的微网优化场景是这样的系统里有一台燃气轮机、一块光伏板、一台蓄电池、一个电锅炉外加热负荷。调度目标是在 24 小时内通过控制燃气轮机出力、蓄电池充放电、电锅炉启停使总运行成本最低同时满足所有电负荷和热负荷。光伏出力有预测误差蓄电池有寿命损耗充放电次数可以折算成成本燃气轮机有最小出力限制。这个场景特别适合作为学习案例因为麻雀虽小五脏俱全。我强烈建议初学者先不要碰复杂的大系统先把“单一蓄电池加单一燃气轮机加固定负荷加分时电价”这个最简单的微网调度做透。在这个简化场景下最优策略其实非常直观谷电时段充电峰电时段放电燃气轮机在气价相对电价低的时候多出力。当你的优化结果能自然呈现出这个规律说明你的模型基本是对的。4.3 从简单到复杂的进阶路线我的建议路线分五步。第一步只做蓄电池调度固定负荷、分时电价结果应该复现“低电价充电、高电价放电”。第二步引入燃气轮机考虑发电成本和购电成本的权衡。第三步加入热负荷和余热利用变成冷热电联产这时要处理的不再只是电平衡还有热平衡和冷平衡。第四步加入预测误差的场景用确定性预测做滚动时域控制也就是每到一个新时刻利用最新数据重新优化一次。第五步加入多场景随机优化或鲁棒优化。走完这五步你基本就从“只会跑通示例代码”进化到“能独立设计调度策略”的程度。我自己带过一些研究生最快的一个用了一个半月走完这五步后面做实际项目的能源站调度时已经能独立完成建模和求解。关键不是快而是每一步都要亲手写代码、亲手调参、亲手看结果。5. 常见问题与排查技巧实录5.1 求解不收敛或时间过长遇到求解不收敛或者跑很久最常见的几个原因模型规模太大、约束存在冗余、0-1 变量过多、目标函数数值量级差异过大。最后一个最好处理把目标函数系数归一化或者统一单位口径。我印象很深的一次光把成本单位从“元”换成“万元”同样的模型求解速度就快了近十倍。约束冗余的问题比较隐蔽一般表现在我们为了保险把上下限约束重复写了。比如设备出力的 lb / ub 已经限制了范围又额外加了一个 A·x ≤ b 限制同一组变量求解器在预处理阶段要花时间去消元。建议写完模型之后把 A 矩阵和 Aeq 矩阵打印出来人工检查一下是否有全零行、重复行。这一步虽然麻烦但非常有效。5.2 结果不合理结果不合理的几种典型情况要单独说。第一种是储能 SOC 曲线跳变大概率是 SOC 更新约束写错或者漏了自放电。SOC 递推公式里充放电效率符号搞反是高频 bug充电效率是正贡献放电效率是分母。第二种是燃气轮机在低负荷区间反复启停大概率没写最小开关机时间约束或者在连续时间模型里没考虑启停次数惩罚。第三种是明明有光伏结果却在电网大额购电先检查光伏出力数据的时刻是否对齐——时区不对、小时错位这类低级错误我见得太多了。我还有一个通用排查套路对最终解做回代验证。把求解得到的控制量代回原始平衡方程手工手算一两个时段的平衡关系看是否成立。很多时候一算就暴露问题。这个小习惯帮我在项目里省了大量时间。5.3 代码调试日常坑变量下标错位是 Matlab 调试里最隐蔽的问题之一。比如P_gt(t)和P_grid(t)索引搞混不会报错但结果非常诡异。建议变量命名层次清晰禁止用x1、x2这种毫无语义的名字。在拼接约束矩阵时每完成一行就disp打印出来核对一次。另外提一下 Matlab 版本和安装调试的建议我建议用 R2022b 或更新的版本自带的intlinprog已经相当稳健。如果你需要调用 Gurobi 或 Cplex记得先装好对应的 Matlab 接口插件再用addpath加载对应路径。如果不想折腾外部求解器就用自带的linprog和intlinprog完成 90% 的学习场景完全没问题。6. 项目后续还可以怎么扩展6.1 从确定性调度走向不确定性优化目前大部分学习案例都是确定性调度假设负荷、光伏、电价都是精确已知的。实际工程中不可能这么理想光伏出力受天气影响负荷预测也有误差。你可以从最简单的鲁棒优化开始给光伏出力设一个波动区间优化目标变成“最坏情况下的成本最小化”。这时候模型会变成两阶段Matlab 里可以借助 YALMIP 的鲁棒模块来实现也可以自己写迭代算法。这一步做完你简历上写“具备不确定性优化能力”就名副其实了。6.2 从离网调度走向实时控制与数字孪生更进阶的方向是把调度程序和实时控制结合起来。调度给出 24 小时的设备计划实时控制根据分钟级数据做反馈修正。Matlab 的 Simulink 可以用来建设备动态模型调度程序通过接口把指令传给 SimulinkSimulink 再把响应状态反馈回来形成闭环。再加上历史数据训练的设备效率模型这就接近工业界说的数字孪生框架了。这个方向比较重适合研究生课题或者企业预研项目但不适合初学阶段。6.3 学习资源与工具建议最后说点学习资源方面的建议。中文资料方面清华、天大、华电的几位老师发表过不少综合能源系统优化调度的综述文章可以顺着引用链去追原始文献。英文资料的话Applied Energy 和 IEEE Transactions on Power Systems 上面这个方向的文章比较多。代码方面GitHub 上搜CCHP optimization或microgrid scheduling能找到不少开源项目注意甄别代码质量优先看有完整 README 和数据文件的仓库。视频教程可以搜 B 站上关于 YALMIP 求解器使用的入门视频但只看视频远远不够一定要亲手敲代码。我在实际项目里体会最深的一点是综合能源系统优化调度这个方向模型框架看起来很简单但真正让结果可信的全是细节——设备效率曲线怎么拟合、SOC 初始值怎么定、约束矩阵有没有重复行、目标函数数量级是否合理。每一个细节都可能是结果不合理的原因。你亲手踩过这些坑之后才会对调度算法本身建立真正的信任感。所以我的建议还是一句话先跑通一个最简单的微网蓄电池模型再一步步加复杂度。这个过程急不得但每一步都会实实在在提升你对系统的理解。