☰
综合能源系统优化调度与需求响应建模:MILP求解与代码实现
2026/10/10 20:23:37 网站建设 项目流程

简介:MATLAB平台上的社区综合能源系统双层优化代码,面向研究微网、综合能源、需求响应与动态定价的科研人员与研究生。程序以综合能源系统整体收益为上层目标,将电价、热价等作为决策变量,下层运营商与负荷聚合商作为跟随者,构建Stackelberg主从博弈模型,并计入电/热功率平衡约束;上层采用DE优化算法,下层调用CPLEX求解器,实现上下层嵌套寻优,解决多主体交互决策问题。压缩包共11个文件,全部为m脚本,大小约13KB,包含主函数与多个子函数,注释清晰,运行即可输出全部图,支持在原始数据基础上修改与扩展。目前已有1805人学习下载。代码创新性较强,适合理解主从博弈、双层优化及综合能源动态定价的读者上手学习。

1. 考虑需求响应微网与社区综合能源系统优化代码:先搞清它优化的是什么

拿到一套带注释、能跑通、还能扩展的微网/社区综合能源系统优化代码,第一件事不是点运行,而是先问一句:这套代码到底在算什么?在综合能源系统领域,所谓“优化”,主体永远是设备出力与能量平衡,核心诉求是“在满足电、热、冷负荷的前提下,把一天24小时的运行成本压到最低”。需求响应则是这个框架里的一层柔性手段——它把一部分用户负荷当作可调节资源,让负荷曲线跟着电价或补偿信号走。这套代码的价值在于:把需求响应、冷热电联供、储电储热储冷放进同一个混合整数线性规划(MILP)模型里,用求解器在几十秒内给出全局最优的调度方案,并把全部结果画成可用于EI论文的曲线。适合谁?正在做微网、社区综合能源系统优化调度方向的研究生,需要一套可复现、可扩展的基线代码来支撑对比实验的人。

2. 模型先立住:目标函数与约束的写法,决定代码能不能扩展

优化代码的骨架是数学模型。代码可以换语言、换求解器,但只要目标函数和约束的表达方式不变,结果就基本一致。这章节先讲清楚模型层面的三种核心选择——如何选目标、如何写能量平衡、如何处理设备非线性——再去对照代码看实现。

2.1 目标函数:运行成本最小化,但成本项不是只有购电

综合能源系统的运行成本,最常见的表达式是:

min C = C_grid + C_gas + C_om + C_dr + C_curtail

其中:

  • C_grid 是向电网购电的费用,购电单价随24小时分时电价变化;
  • C_gas 是燃气轮机和燃气锅炉消耗天然气折合成的费用,按天然气热值和单价计算;
  • C_om 是各设备的运行维护成本,一般按出力量乘以运维单价,比如燃料电池每发1kWh电对应0.02元的维护费用;
  • C_dr 是需求响应补偿成本;
  • C_curtail 是弃风弃光的惩罚项,设成很高的单价(比如5元/kWh),让求解器主动避免切出力。

这套写法在EI期刊里很常见,也是代码默认的目标。做扩展时你要注意一点:大多数模型不会在目标函数里直接写“碳排放最小”,而是把碳排放转成碳税或配额成本加进去。如果你的研究方向是双碳,建议保留这个目标结构,在C_gas里增加一个碳税系数即可,不需要推翻重写。

2.2 能量平衡约束:电、热、冷三条母线的写法

微网/社区综合能源系统的核心约束是能量平衡,代码里通常会把它写成三条母线方程:

  • 电平衡:购电 + 光伏出力 + 燃气轮机发电 + 储能放电 + 需求响应削减量 = 电负荷 + 电锅炉耗电 + 电制冷机耗电 + 储能充电
  • 热平衡:燃气轮机余热回收 + 燃气锅炉供热 + 储热罐放热 = 热负荷 + 吸收式制冷机耗热
  • 冷平衡:电制冷机供冷 + 吸收式制冷机供冷 + 储冷罐放冷 = 冷负荷

注意,热平衡里的吸收式制冷机耗热这一项,是冷热电联供系统特有的耦合约束——燃气轮机的排烟余热既能直接供热,也能驱动溴化锂机组制冷。代码里会用一个系数把吸收式制冷机的出力折算成耗热量,这个折算系数通常在1.3到1.5之间,取决于COP(制冷效能比)。调试时如果热平衡总是对不上,先检查这个系数是否写反。

2.3 设备模型:燃气轮机、储能与需求响应的线性化

燃气轮机的发电效率和出力区间是非线性的,代码常用的做法是把出力区间分成几段,用分段线性化逼近效率曲线,或者按工程惯例让效率在某个负荷率区间内近似恒定。另一种更常见的做法是给燃气轮机加一个最小出力约束,比如“出力的连续变量取值落在[Pg_min, Pg_max]区间内”,用半连续变量实现——这也是YALMIP或Gurobi里最容易处理的方式。

储能部分的核心是SOC(荷电状态)递推方程:

SOC(t) = SOC(t-1) + eta_ch * P_ch(t) * dt / Cap - P_dis(t) * dt / (eta_dis * Cap)

约束里还要限制SOC上下限(一般是10%~90%)、充放电功率上限,以及“不能同时充放电”的逻辑。这个逻辑在MILP里就是两个二进制变量之和小于等于1。代码里会写成ch_on + dis_on <= 1,求解器才能正确处理。

需求响应在这层模型里的本质,是给负荷方程增加一个可变量。后面单独章节细讲。

3. 需求响应建模:价格型与激励型,怎么把柔性负荷塞进MILP

需求响应是这套代码最大的亮点,也是新手最容易写烂的地方。社区综合能源系统里的需求响应,一般分两种玩法:价格型需求响应和激励型需求响应。代码里通常同时建模,但实现思路完全不同。

3.1 价格型需求响应:可平移负荷的时段挪移

价格型需求响应的核心思想是:用户会自发地把洗衣、充电等可推迟负荷,从高电价时段挪到低电价时段。代码里用一个可平移负荷矩阵L_shift(t, d)来表达——t是开始时段,d是持续时长。举个例子,一台持续2小时的洗衣机,用户原本打算在18点开始用,系统给它算了一笔账:如果把开始时间挪到凌晨2点,电费能省2.3元,于是求解器把L_shift(18,2)置1,L_shift(2,2)置1,18点对应的2小时负荷被平移走。

代码里对这种负荷的关键约束有三个:

  • 每个可平移负荷只能选择一个开始时段;
  • 被平移后的负荷要保证连续供电,不能拆成两半;
  • 同一时刻开始的可平移负荷总数不能超过线路容量限制。

价格型需求响应不需要在目标函数里加补偿成本,因为用户省下的电费就是激励本身。

3.2 激励型需求响应:可削减负荷的0-1变量

激励型需求响应则完全不同:用户签了协议,允许运营方在高峰时段切掉一部分负荷(比如空调温度上调2度、工业设备降载),作为交换,运营方按削减量给用户补偿。代码里用Load_shed(t)表示每个时段的削减量,并定义一个0-1变量u_shed(t):

  • u_shed(t)=1表示该时段执行了削减;
  • Load_shed(t)的范围是[0, Load_max_shed];
  • 一天内累计削减次数有限制,避免把用户折腾得太过分。

补偿成本在目标函数里单独成项:C_dr = sum( Load_shed(t) * price_dr(t) ),price_dr(t)是单位削减补偿单价,通常比正常电价高出20%~50%,具体数值要看需求响应项目的合同定法。

3.3 需求响应适度参与:为什么负荷平移要设上限

代码里如果允许负荷完全自由平移,求解器会给出一个极端答案:把白天所有负荷都挪到凌晨,电费最小了,但用户舒适度归零了。这在工程上完全不可行。所以代码里定了两个硬约束:

  • 平移负荷占总负荷的比例不超过15%~20%(具体比例可以在参数区修改);
  • 价格型需求响应部分,每个时段的最大平移量受限于该时段可平移负荷总量和线路容量。

类似地,激励型需求响应也有“每日最大削减时长”“连续削减间隔”等约束。这些约束不是论文里堆字数的装饰,它们是决定模型能不能用于实际项目、能不能过审稿人那关的关键细节。

4. 代码落地:从参数区到绘图脚本,逐段拆解运行流程

模型搞清楚之后,再看代码就轻松了。以MATLAB + YALMIP + Gurobi/Cplex这套最常用的技术栈为例,把这套代码从头到尾的典型文件结构和核心片段拆开讲。

4.1 输入参数区:把24小时负荷、电价、天然气价格放在一张表里

代码的第一步永远是载入基础数据。社区综合能源系统的典型做法是直接在脚本里定义一个结构体,或用Excel读入24小时数据。从代码维护角度看,我建议把负荷、电价、天然气价格、光照强度这四组数据单独存成CSV或Excel,主程序用readtable读入。

% 读取24小时基础数据 data = readtable('load_price.xlsx'); P_load = data.P_load; % 电负荷,单位kW,24x1 H_load = data.H_load; % 热负荷,单位kW,24x1 C_load = data.C_load; % 冷负荷,单位kW,24x1 price_e = data.price_e; % 分时电价,单位元/kWh, 24x1 price_g = 0.35; % 天然气单价,元/kWh(按热值折算)

这里的price_e是分时电价,代码里常见的是峰谷平三段费率,比如高峰1.2元、平段0.75元、低谷0.4元。注意:天然气价格折算到元/kWh时,要用天然气热值除以锅炉效率。比如天然气低位热值9.7元/Nm³,折合每kWh约0.35元,不同地区差异很大,代码里这个参数要按当地实际气价改。

4.2 决策变量定义:sdpvar与binvar怎么混用

YALMIP里,连续变量用sdpvar定义,0-1整数变量用binvar定义。MILP模型里两类变量同时存在,求解器才能正确处理逻辑约束。

% 决策变量定义 Pg = sdpvar(24,1); % 燃气轮机发电出力 Hg = sdpvar(24,1); % 燃气锅炉供热出力 Pchp = sdpvar(24,1); % 热电联产余热回收功率 Pgrid = sdpvar(24,1); % 从电网购电功率 SOC = sdpvar(24,1); % 储能荷电状态 Pch = sdpvar(24,1); % 储能充电功率 Pdis = sdpvar(24,1); % 储能放电功率 % 需求响应变量 load_shift = binvar(24,1); % 每个时段是否执行可平移负荷 load_shed = sdpvar(24,1); % 每个时段的负荷削减量 u_shed = binvar(24,1); % 负荷削减状态标志 % 储能同时充放电标志 u_ch = binvar(24,1); u_dis = binvar(24,1);

binvar数量会直接影响求解速度。一个典型社区能源系统,只有24个时段、几条母线约束,binvar通常在200个以内,Gurobi在几秒内就能求到MIP gap小于0.1%的最优解。如果你的代码里binvar超过500个,可以先把24小时改成8个时段来验证模型正确性,再逐步加密。

4.3 约束装配:把能量平衡与设备模型写成YALMIP约束数组

约束装配是代码里最长、也最容易出错的部分。每个设备的约束独立写,最后拼成一个约束数组F,交给optimize求解。

% 电平衡约束(含需求响应削减量) F = [F, Pgrid + Pg + Pdis + load_shed == P_load - load_shift + P_eb + P_ec]; % 热平衡约束 F = [F, Pchp + Hg + H_dis == H_load + H_ac]; % 冷平衡约束 F = [F, C_ec + C_ac + C_dis == C_load]; % 燃气轮机约束:出力上下限与爬坡约束 F = [F, 0 <= Pg <= Pg_max]; F = [F, -ramp_limit <= Pg(2:24) - Pg(1:23) <= ramp_limit]; % 储能SOC递推与充放电互斥 F = [F, SOC == [SOC_0; SOC(1:23)] + eta_ch * Pch / Cap - Pdis / (eta_dis * Cap)]; F = [F, 0 <= SOC <= 0.95]; F = [F, u_ch + u_dis <= 1]; F = [F, Pch <= u_ch * Pch_max, Pdis <= u_dis * Pdis_max];

储能SOC这行用了一个技巧:SOC(1:23)表示将SOC的前23个元素作为t-1时刻的值向后推移,在YALMIP里这样可以直接写出一整条时序递推约束,不用for循环,代码更紧凑。很多人第一次接触这段会看不懂,手动展开成24行递推式会更直观。

4.4 求解与结果校验:不要直接信最优解

ops = sdpsettings('solver', 'gurobi', 'showprogress', 1, 'verbose', 2); optimize(F, objective, ops); % 校验求解状态 if sol.problem == 0 Pg_opt = value(Pg); Pgrid_opt = value(Pgrid); % 计算各项成本 cost_grid = sum(Pgrid_opt .* price_e); cost_gas = sum(Pg_opt ./ eta_g) * price_g; else error('Solver failed with code %d', sol.problem); end

求解完成之后,代码里的统计输出会把购电成本、天然气成本、需求响应补偿成本、储能收益拆成清单打印出来。这个成本对账表非常重要——论文里的经济性分析数据全是从这里来的。建议每个实验跑完都先看这张表,对不上账就说明某个约束写错了。

绘图部分截图代码:

figure('Position', [100 100 1200 700]); subplot(3,2,1); bar(1:24, [Pg_opt, Pgrid_opt, Pdis_opt, Pch_opt], 'stacked'); legend('燃气轮机', '购电', '储能放电', '储能充电'); xlabel('时刻(h)'); ylabel('功率(kW)'); title('电功率平衡');

这一组图最后会拼成论文里的“系统优化调度结果图”,要保证图例顺序、坐标单位、字体大小都一致,投稿时才不会被打回。

5. 避坑与常见问题:为什么代码跑不出论文里的图

这套代码能跑通,和能跑出正确结果,是两回事。实际使用中出现的问题大多是模型层和参数层的,不是代码层的。以下是五个高频问题,按“现象→原因→解决”写,照方抓药即可。

5.1 现象:求解器提示infeasible,但模型看着没问题

这是MILP模型最常见的问题。原因大概率是某个约束相互矛盾,比如储能的初始SOC、最小SOC和最大充放电功率之间,在24小时的窗口内根本不可能满足。另一种典型原因是SOC递推约束里使用了SOC_0=0.5,但储能容量Cap设得过小,导致某个时段必须同时满足充电需求和放电需求。解决方法是:把SOC_0改成0.5,把Cap的值加大,或者把SOC初始值从固定值改成约束SOC(1)==SOC_0且SOC(24)>=SOC_0,给求解器留余地。也可以用YALMIP的assign和check命令逐一检查每条约束的残差,先定位在哪一行。

5.2 现象:热平衡“差一口气”,吸收式制冷机的耗热老是溢界

现象是优化结果里,热母线的总有功供应与热负荷总是不平,差的那部分刚好等于吸收式制冷机的耗热量。原因很常见:热平衡约束里忘了把“吸收式制冷机消耗的热量H_ac”从热负荷侧扣掉,或者H_ac本身是用COP折算的但折算方向写反了。解决方法是回到公式:吸收式制冷机供出C_ac的冷量,需要消耗H_ac = C_ac / COP_abs的热量,这个量要同时出现在热平衡方程右侧(作为耗热项)和冷平衡方程左侧(作为供冷项)。这两行如果分开写在代码的不同位置,漏写一个就出这种“幽灵差量”。

5.3 现象:SOC曲线乱跳,或者充放电功率同时非零

SOC曲线出现阶梯状跳变,通常是部分SOC值越过上下界导致的。如果SOC曲线一天之内反复冲到0.95又跌回0.1,说明目标函数里缺少对储能“寿命损耗”的考量,求解器让电池满充满放。工程上可以给SOC增加变化幅度惩罚,或者在目标函数里加一个很小的单位容量折旧成本。如果充放电功率同时非零,则是充放电互斥约束没生效,检查u_ch + u_dis <= 1是否真的进入了约束数组F。一个容易犯的错是:在YALMIP里,约束条件用分号结尾,直接就丢掉不装配了,所以这种逻辑约束要单独一行并用逗号或赋值号连接。

5.4 现象:换一台电脑,脚本报“未定义函数或变量”

这通常是路径问题。代码里用到了自定义函数(比如读取数据、画图),但主程序没有把自定义函数所在的文件夹加入MATLAB路径。解决方法是把整个项目目录一次性加进路径,或者把主程序改成用绝对路径引用数据文件。如果代码里用了gurobi和yalmip,还要确认这两个工具箱在新机器上已安装并配置好。建议多看求解器的verbose输出——如果Gurobi的license有问题,YALMIP往往会在求解前直接报错,一查便知。

5.5 现象:画出图来,图例漂移、中文乱码、导出PDF字号太小

中文乱码是老问题。MATLAB在Windows下用SimHei或Microsoft YaHei字体能显示,但exportgraphics导出时经常把中文变成方框。我的常用做法是:所有图例和坐标轴标签用英文,只在标题里放中文;论文中需要中文说明的在PPT里后补。字号方面,MATLAB默认的FontSize是10,期刊图一般要求最小字号不小于6号字,投稿前用exportgraphics(fig, 'result.pdf', 'ContentType', 'vector')导出矢量图,确保所有线条和文字清晰。

6. 在基础上扩展:从单日示范到多场景对比的验证技巧

拿到这套代码后,不要急着改模型,先做一次“论文复现验证”:把代码默认算例的结果和你目标论文里的数据对上。对不上的话,先把目标函数的成本单价、设备容量参数逐项对齐,再往下走。

三个值得优先做的扩展方向:

第一,改成多日连续优化。单日优化的边界问题是储能初始SOC需要猜测,多日优化则让储能连续跨天运行,更贴近工程实态。修改方法是把维度从24扩展为24*N天,循环约束里注意日与日之间的SOC衔接。

第二,加入多场景对比。把光伏出力从单一日照曲线改成晴、多云、阴雨三组数据,分别优化并比较成本和需求响应效果。这种对比是EI论文最吃香的图——一张三维堆叠图就能直观展示不同光照条件下的设备出力与成本差异。

第三,把确定性优化换成鲁棒优化。在现有约束里加入光伏出力的不确定集,目标函数改成“最坏情况下成本最小化”。这一步改动相对独立——在YALMIP里本质上是用bilinear项替换原线性项,但要注意Gurobi对bilinear的处理较慢,建议优先用Cplex或改用线性化公式。

我这几年带学生做这类复现,遇到最多的问题不是模型写不出来,而是“能画图但不敢确认结果是对的”。对付这个问题的土办法就一个:手算一个最简单算例——把设备数量缩减到1台、时段缩减到4个,把结果和代码输出对一遍,确认逻辑通了再放回去跑24小时全模型。这个习惯救过我很多次,也希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询