这几年被问得最多的一个问题:综合能源系统的模型到底要建到什么程度?问这个问题的人里有做毕设的本科生,有准备数学建模竞赛的学生,也有刚转到智慧园区方向的工程师。我的回答通常不是给一个标准答案,而是反问回去:你拿这个模型干什么?做硕士论文的机理分析、跑能量管理优化、还是做并网仿真验证?不同用途对应的模型粒度和建模工具完全是两码事。这篇就以 MATLAB 为主线,把综合能源系统从建模到校核再到优化求解的完整思路串一遍,重点写那些别人不细讲,但你实际操作中大概率会踩的坑。
所谓综合能源系统,说白了就是电、热、冷、气这些能量载体不再是各管各的,而是通过设备耦合在一起协同运行。比如热电联产机组同时出电和热,热泵用电制热,储能电池平抑电力波动,蓄热罐把多余的热存起来等峰值再放。这种多重耦合关系,恰好是 MATLAB/Simulink 最擅长的场景。但擅长归擅长,用不好照样翻车。下面我拆开讲。
1. 建模对象拆解:电热气冷耦合里最难的不是公式,是边界
1.1 先画清楚物理边界,再谈设备方程
我做综合能源项目第一步从来不是打开 MATLAB 敲代码,而是先在纸上画系统的物理边界。这个边界不是随便圈一圈,而是要明确三类东西。
一是能量流边界:系统内部有哪些能源转换设备,外部有哪些联络线。分布式光伏、风机是发电侧,电锅炉、热泵是电转热侧,蓄热罐是存储侧,电网联络线是外部支撑。每条能量流的走向、方向、量级,必须先在表里列出来。
二是数据边界:哪些参数是已知的(比如光照辐照度、环境温度、负荷曲线),哪些是待求解的(比如各设备出力、储能 SOC),哪些是可以简化的(比如忽略管路热损的动态过程,只取稳态效率)。用一张表把输入、输出、状态量列清楚,建模时就不会东一榔头西一棒槌。
我见过一个比较典型的反面案例:某同学做园区冷热电联供系统,上来就把燃气轮机的燃烧室化学反应动力学模型搬进 Simulink,结果调了一个月都没收敛,最后发现自己的需求只是算年度运行成本。这就是典型的物理边界划错了——研究的宏观能量平衡,却引进了微观动态过程。模型粒度这件事,不是越细越好,而是够用就好。
1.2 多能流耦合的本质:一张源-网-荷-储矩阵
综合能源系统区别于单一电力系统的核心,在于"耦合矩阵"概念。以电能母线和热能母线为界,每一台设备都可以理解为连接不同母线之间的转换支路。我习惯用矩阵方式来组织模型:
- 电能平衡方程:光伏出力 + 电网购电 + 燃气轮机发电 - 电负荷 - 热泵用电 - 电锅炉用电 = 0
- 热能平衡方程:燃气轮机余热 + 热泵制热 + 电锅炉制热 + 蓄热罐放热 - 热负荷 - 蓄热罐充热 = 0
这种方式的好处是,设备的物理方程是局部的、独立的,但母线平衡方程把全部设备联系成整体。在 MATLAB 里实现时,每台设备写成一个独立的函数或 Simulink 子模块,母线平衡则用一个求和节点统一表达。改动了某一台设备的参数,不影响整体结构,这就是模块化建模的收益。
1.3 时间尺度差异:同时求解为什么会发散
综合能源系统里特别容易忽略的一个问题是时间尺度差异。电力系统的动态过程是毫秒到秒级,热力系统的动态过程是分钟级,燃气管网的动态过程甚至可以到小时级。如果你在一个 Simulink 模型里同时仿真这三类过程,步长选择就会非常痛苦——步长太小,热力部分计算时间长;步长太大,电力部分的暂态被抹掉。
我对做能量管理方向的同学通常建议:如果研究目标是小时级的调度优化,就不要在 Simulink 里搭电磁暂态模型。把电力部分简化成功率平衡方程,热力部分简化成一阶惯性环节,用 MATLAB 脚本做数值求解就足够了。反过来,做微电网并网切换的暂态研究,才值得在 Simscape Electrical 里精确建模。这个选型判断,决定了你后面是快乐编程还是反复调试。
2. MATLAB 建模三条路线的取舍:纯代码、Simulink、还是 Simscape
2.1 三条路线的本质区别
同样一个光伏发电单元,在 MATLAB 里有三种表达方式。纯代码路线,就是写一个函数,输入辐照度和温度,输出功率;Simulink 信号流路线,是用模块搭出功率传递关系;Simscape 物理网络路线,是直接拖一个 PV Array 模块,连上电气线路。
听起来第三条最省事,但实际用起来不是这么回事。Simscape 的物理模型遵循基尔霍夫定律和能量守恒,模块之间自然满足功率平衡,很适合电气侧细节仿真。但它也有代价:物理变量是隐式求解的,一旦系统规模变大,仿真速度会明显下降,而且跟传统的控制逻辑模块交互时,需要经过物理信号转换器,这一层转换经常是新手调试半天找不出问题的根源。
纯代码路线看起来"原始",但因为它完全掌控在你自己手里,每一步都有明确的物理意义。做优化问题时,我反而更推荐这种方式——因为优化算法需要反复调用模型函数,Simulink 模型每次调用都要初始化、编译模块图,开销很大。而纯函数求解,一秒钟能跑几百次。三年下来我自己的项目里,凡是涉及粒子群、遗传算法做参数寻优的,全部改回纯代码形式。
2.2 一个屋顶微网案例的三路线对比
用一个最小系统举例:屋顶光伏 + 锂电池 + 空气源热泵 + 蓄热水箱 + 电负荷/热负荷。用三种路线建同一个系统,对比起来会更直观。
| 对比维度 | 纯代码 | Simulink 信号流 | Simscape 物理网络 |
|---|---|---|---|
| 建模速度 | 中等,需要自己写方程 | 快,模块拖拽即用 | 快,组件封装完善 |
| 仿真速度 | 最快 | 中等 | 较慢,存在隐式求解开销 |
| 控制逻辑集成 | 自己写调度逻辑 | 最方便 | 需要信号转换 |
| 物理一致性 | 取决于方程质量 | 取决于建模者 | 系统自动保证 |
| 调试难度 | 出问题容易定位 | 模块连线错误暴露慢 | 变量隐式,黑盒感强 |
我能给出一个比较明确的建议:如果做规划优化、能量调度、长期运行分析,选纯代码;如果做控制策略验证,比如光伏逆变器 PQ 控制、热泵温度回路的 PID 调节,选 Simulink 信号流或者 Simscape;如果是做硬件在环或者半实物仿真,那只能选 Simscape,因为需要跟真实的 I/O 和通信协议对接。路线没有绝对的优劣,只有跟需求是否匹配。
2.3 可视化不等于模型可靠,这是最大的误区
很多刚接触 MATLAB 的朋友有个毛病:特别追求 Simulink 模型图的美观,模块排列得整整齐齐,信号线用不同颜色标注,一眼看上去非常专业。但这里有一个真相必须说透——框图规范与模型精度没有任何关系。模型靠不靠谱,取决于你填进去的参数是否来自实测或可靠文献,取决于核心方程是否抓住了主导物理过程。
我见过一个极端的例子:某团队的 Simulink 模型里搭建了精细的微燃机动态模型,转速环、温度环、加速度环全都画出来了,但微燃机排气温度控制参数是从别的论文里抄来的,没有根据当前系统的容量做归一化缩放。最终仿真结果跟试验数据偏差超过 40%。反过来,一个用三个代数方程描述微燃机热电联产的简化模型,参数经过现场数据标定,结果精度反而在 5% 以内。模型的价值永远建立在参数可信度和主导物理过程的正确抽象之上,这一点请务必放在心里。
3. 一套可复现的光-储-热微网模型:从光伏到热泵的落地过程
3.1 系统拓扑与建模假设
我用自己做过的一个屋顶光储热微网项目作为完整案例来拆解。系统结构如下:屋顶 200kW 光伏阵列,一组 100kW/200kWh 的磷酸铁锂电池储能,两台 50kW 的空气源热泵,一个 10m³ 的蓄热水箱,母线上挂电负荷和热水负荷,与外部电网之间有一条联络线。
建模前先做假设,这个不能省。光伏组串不考虑组串间失配和局部阴影,采用单峰值效率模型;储能电池不考虑热效应和老化衰减,使用理想等效电路,SOC 按安时积分法估算;热泵的 COP 只随环境温度变化,忽略部分负荷率的影响,因为实际运行时热泵大多数时间在额定工况附近运行。蓄热水箱假设温度分布均匀,用集总参数法描述。
请注意,这些假设不是为了偷懒,而是经过了需求分析。我们后续要在这个模型上跑全年 8760 小时的运行优化,如果每一步都精细化到毫秒级,计算量完全不可接受。做综合能源系统建模的首要原则,就是用复杂度换时间,在满足研究目标的前提下,尽量降低模型阶数。
3.2 光伏组件的出力模型
光伏出力最实用的模型之一是效率法,通过额定条件下的功率和效率,推算实际环境下的输出功率。核心公式为:
- 光伏实际输出功率:(P_{pv} = P_{stc} \times \frac{G_{ac}}{G_{stc}} \times \eta_{r} \times \eta_{inv})
其中 (G_{ac}) 是实际辐照度,(G_{stc}) 是标准测试条件辐照度,取 1000 W/m²,(P_{stc}) 是标准测试条件下的额定功率,(\eta_{r}) 是综合考虑温度影响后的效率修正系数,(\eta_{inv}) 是逆变器效率。在 MATLAB 里实现时,我会写成函数:
function P_pv = pv_output(G, T_amb, P_stc, k_temp, eta_inv) % G: 实际辐照度 (W/m^2) % T_amb: 环境温度 (degC) % k_temp: 温度系数,通常取 -0.004 / degC % 默认标准测试条件:G_stc=1000, T_stc=25 G_stc = 1000; T_stc = 25; eta_pv = 1 + k_temp * (T_amb - T_stc); P_pv = P_stc .* (G ./ G_stc) .* eta_pv .* eta_inv; % 低于临界辐照度时按零出力处理 P_pv(G < 50) = 0; end这个模型的物理含义很直白:光越强、温度越低,光伏出力越大。温度系数的引入是因为光伏组件在高温下效率确实会下降,这是半导体材料的本征特性。逆变器效率我通常取 0.97,并假设在 30% 负载率以上时基本恒定,低于 30% 时效率会略微下降,但在宏观调度层面用常数更合理。这个函数输出的是直流侧转交流并网后的有功功率,后续直接作为微网电平衡方程的一个源项参与求解。
3.3 储能电池模型:SOC 动态是关键
储能电池模型我采用的是等效电路加能量平衡的混合方式。等效电路部分取理想电压源加串联内阻,因为我们的目标是做调度层而非逆变器开关级仿真,不需要精确模拟电池端电压的动态波动。能量平衡部分则是 SOC 的迭代方程:
- 充电时:(SOC(t+1) = SOC(t) + \frac{P_{ch} \cdot \eta_{ch} \cdot \Delta t}{C_{bat}})
- 放电时:(SOC(t+1) = SOC(t) - \frac{P_{dis} \cdot \Delta t}{C_{bat} \cdot \eta_{dis}})
其中 (\eta_{ch}) 和 (\eta_{dis}) 分别是充放电效率,磷酸铁锂通常取 0.95 左右。注意,充电效率和放电效率不相等,充电时有能量损耗转化为热量,放电时同样有内阻损耗。我实现的版本如下:
function [SOC_next, P_bat_net] = battery_update(SOC, P_req, P_max, C_bat, eta_ch, eta_dis, dt, SOC_min, SOC_max) % P_req: 电池需要吸收(正)/释放(负)的功率 % P_max: 电池最大充放电功率,正数 if P_req >= 0 % 充电时还要考虑剩余容量限制 P_ch_max = min(P_max, (SOC_max - SOC) * C_bat / dt); P_actual = min(P_req, P_ch_max); SOC_next = SOC + P_actual * eta_ch * dt / C_bat; else % 放电时考虑可用容量限制 P_dis_max = min(P_max, (SOC - SOC_min) * C_bat / (dt * eta_dis)); P_actual = max(P_req, -P_dis_max); SOC_next = SOC - P_actual * dt / (C_bat * eta_dis); end P_bat_net = P_actual; end这里有一个实操细节:在储能电池的仿真循环里,判断充电和放电的边界条件必须对称。很多人只写了 SOC 上限限制,忘了放电时的 SOC 下限其实对应的是一个由"当前电量减到最低允许值"所能输出的最大能量。如果这个下限限制写错,仿真的后期会出现 SOC 变成负数或超过 100% 的情况,整个能量平衡就崩了。这也是我在代码里用 SOC_min 和 SOC_max 双边界同时约束的原因。
3.4 空气源热泵与蓄热水箱的耦合建模
热泵是综合能源系统中电热耦合的核心环节。空气源热泵消耗电能,从空气中提取低温热量,压缩后释放到高温水中。评定其性能的关键指标是 COP(制热能效比),即输出的热量与消耗的电能之比。COP 受环境温度影响显著,冬天温度低时 COP 下降,电耗反而上升。我采用的简化 COP 经验公式为:
function [P_th, P_elec] = heatpump(T_amb, T_tank, P_th_req, k_a, k_b) % k_a, k_b 为 COP 经验拟合系数 COP = k_a + k_b * (T_amb - T_tank); % 防止 COP 过小导致电耗爆表 COP = max(COP, 1.5); P_elec = P_th_req / COP; P_elec = min(P_elec, 50); % 单台热泵额定电功率上限 P_th = min(P_th_req, P_elec * COP); % 实际输出热功率 end这里我特意加了额定功率约束,因为在实际设备里,热泵压缩机有功率上限,你在优化时会看到求解器为了满足热负荷,一直推高热泵出力,如果模型里不写上限约束,电功率会无限大。控制变量和输出变量之间的约束映射关系,必须在模型里就固化下来,才能避免优化阶段出现不切实际的解。
蓄热水箱模型更简单,本质是一阶能量守恒。水箱吸收热泵输出的热量,向热负荷侧释放热量:
function T_next = tank_dynamics(T_now, P_th_in, P_th_load, m_w, cp_w, dt, T_env, UA) % m_w: 水箱质量, cp_w: 水的比热容, UA: 水箱与环境的等效传热系数 T_next = T_now + (P_th_in - P_th_load - UA * (T_now - T_env)) * dt / (m_w * cp_w); end水箱旁边的 (UA \times (T_{now} - T_{env})) 这一项代表散热损失,很多教材演示里会忽略,但实际项目中如果忽略,夏天可能没有明显差异,冬天水温会虚高 5 到 8 摄氏度,导致热负荷被低估。真实工程中 UA 值要靠实验测定,如果没有实测数据,可以按水箱保温层厚度和导热系数的理论公式估算。做综合能源建模,这种"不可见"的损耗项特别容易遗漏,而它们恰恰是模型与现场偏差的主要来源。
3.5 模型集成:别忽视时序迭代逻辑
各设备的方程都写好之后,需要在主循环里按时间步长推进。这里的关键是注意迭代顺序:先读入当前时刻的光照、温度、负荷数据,计算光伏出力;然后结合电平衡,计算储能电池的充放电功率;接着看热泵需要多少电功率、能出多少热;再更新水箱温度和 SOC。每一步的计算结果都会影响下一步的输入,这就构成了一条完整的因果链。
我常用 MATLAB 的 for 循环配合结构体数组来管理各时刻的状态值。把气象数据、负荷数据存成列向量,循环里按行读取,状态量用一个 struct 保存。数据量不大时这种写法直观高效,也方便后期做日内调度优化时直接调取任意时刻的系统状态。
4. 模型校核:量纲、能量守恒、极端工况,这三关不过别谈优化
4.1 量纲和单位:最不起眼却最致命的坑
一个让我记忆特别深的教训:某次项目联调,热泵模型输出的制热量单位本来是 kW,但因为代码里有个位置把 1000 倍的换算写反了,结果 50kW 的热泵实际输出变成了 0.05kW,水箱温度几乎不动。排查了整整三天,最后用能量守恒反推才发现是单位问题。
在 MATLAB 里做科学计算,尤其要小心矩阵运算和向量运算中的单位混用。我的习惯是在所有模型函数文件的头部统一写清楚单位注释,并且用一个自检脚本把常用物理量换算成 SI 制:能量一律用 J 或 kWh,功率一律用 W 或 kW,温度一律用摄氏度或开尔文但全篇统一。我还习惯在关键结算结果处做合理性断言,比如水箱温度不在 5~100 摄氏度范围就报错,SOC 不在 0~1 之间就报错。这种"防御式编程"能省下大量排查时间。
4.2 能量守恒检验:把系统闭环再看总账
模型建好之后,第一件事不是看曲线漂不漂亮,而是做全系统能量守恒校验。所谓守恒,就是让仿真跑完一段时间,把这段时间内所有输入的太阳能、购电量、环境吸热,减去内部的电耗、热耗、对外散热,最终应该和系统内储能的变化量相等。用公式写就是:
- 系统净输入能量(光伏发电 + 购电 + 空气源热泵从环境中提取的热量)- 输出能量(电负荷 + 热负荷 + 热损)= 电池 SOC 变化对应的能量 + 水箱热量变化
如果这个等式的残差超过 2%,说明模型内部一定存在系统性偏差。
实操中我会写一个能量审计脚本,每个时间步都累计输入输出,仿真结束后统一算残差。残差过大的时候,重点检查三条线:第一,热泵 COP 的定义是否在空气源热泵的边界上保持一致,一部分人用 (COP = 输出热量/输入电功),另一部分人把热泵从环境中吸收的热量也算进输出热量里,标准不统一就会错;第二,蓄热水箱的散热项是连接水箱能量的外部出口,漏掉散热项会造成能量凭空消失;第三,储能的充放电效率是乘法关系,不是加法关系,充电时的损耗必须放在充电方向单独处理。验证过的模型才配进入优化环节。
4.3 极端工况测试:逼出模型的隐藏缺陷
正常工况跑得通不代表模型没问题。我一般会在正常场景之外再加三组极端工况测试。第一组是零辐照长时运行,模拟连续阴雨天,光伏出力归零,此时系统完全靠电网和储能支撑,测试储能 SOC 是否会突破下限,热泵是否能满足热负荷;第二组是峰值辐照突增,上午 9 点光照从 300 跳到 1000 W/m²,查看电平衡是否正确处理了光伏给储能充电的逻辑;第三组是热负荷阶跃,模拟一群人在早上 8 点同时打开热水龙头,看水箱温度和热泵功率的响应是否在合理范围。
这三组测试能暴露大量问题。比如在零辐照长时运行测试中,如果没有给储能设置 SOC 下限,仿真到第 12 小时 SOC 变成负数,说明能量管理逻辑里缺了缺电保护策略。再比如峰值辐照突增测试,如果光伏出力和电负荷、储能充电功率之间没有做最小值约束,会出现光伏电量被白白浪费的"弃光"场景。极端工况本质上是对模型鲁棒性的检验,这一关不过,后续优化结果往往是不可信的,因为优化算法特别喜欢往边界条件上试探。
4.4 与实测数据对标:精确到度的幸福感
如果项目现场有历史运行数据,模型校核的最后一步就是对标。把同一时段的天气数据和负荷数据输入模型,运行完之后把仿真曲线和实测的蓄热水箱温度、储能 SOC 曲线放在同一张图里对比。我常用的指标是加权平均绝对百分比误差(WMAPE)和均方根误差(RMSE)。一般情况下,宏观能量模型的 WMAPE 在 5% 到 10% 之间就是一个可以接受的结果,如果能到 3% 以内,那说明模型的主要动态都抓准了。
对标过程中让我印象比较深的一次:实测数据里储能电池在夜间会因为站内冷却系统持续用电而缓慢放电,SOC 从 80% 缓慢降到 78%。我最初的模型里没有站用电这一项,怎么仿真都对不上,最后入户排查发现电池仓有个小功率的空调常年运行。从那以后,我建任何微网模型都会留一个"可配置固定负荷"的口子,专用于吸收这种杂散损耗。这个细节不算聪明,但很实用。
5. 从模型到优化求解器的最后一公里:YALMIP 与 intlinprog 实战记录
5.1 优化问题的数学结构:从仿真模型到决策模型
仿真模型和优化模型之间有一道鸿沟。仿真模型接受给定调度指令,输出系统响应;优化模型则是反过来,在满足约束的前提下,自动搜索最优的调度指令。把仿真模型改造成优化模型,本质上要把原来按时间推进的迭代逻辑,改写成一组带决策变量的数学规划表达式。
以这个光储热微网为例,优化的目标函数通常是最小化日运行成本,包括购电费用、热泵电费、电池损耗折损以及可能的弃光惩罚。决策变量是每个时刻的储能充放电功率、热泵开关状态和蓄热罐的充放热功率。约束条件包括:电功率平衡、热功率平衡、储能 SOC 动态约束、电池充放电功率上下限、热泵出力上下限、蓄热罐容量约束等。
在 MATLAB 里做这件事,有三种路线。一是直接用 Optimization Toolbox 的 linprog 或 intlinprog,适用于线性目标、线性约束;二是用 fmincon 做非线性规划,适用于有 COP 随温度变化这类非线性表达的场景;三是用 YALMIP 这个免费工具箱建模,再调用内部求解器。我的个人偏好是,能线性化就线性化,坚决不碰非线性。因为线性规划求解器能保证全局最优,非线性规划则可能陷在局部最优里出不来,到时候你还得分析是不是初值选得不对。
5.2 YALMIP 建模实操:要注意版本兼容问题
YALMIP 的一大优势是建模语言贴近数学表达式,直观,调试效率高。比如定义 24 时段储能充放电功率变量,只需要一行:
P_bat = sdpvar(24, 1); % 决策变量,正为充电,负为放电 P_hp = sdpvar(24, 1); % 热泵电功率 P_grid = sdpvar(24, 1); % 电网购电功率约束条件也是直接看着数学表达式写,比如电平衡约束:
Constraints = [P_pv + P_grid + P_bat == P_load_e + P_hp];SOC 动态约束则需要用到循环,把每个时刻的递推关系列出来:
SOC = sdpvar(25, 1); Constraints = [SOC(1) == 0.5]; % 初始 SOC 50% for t = 1:24 Constraints = [Constraints, SOC(t+1) == SOC(t) + (P_bat(t) * eta_ch / C_bat) * dt]; Constraints = [Constraints, SOC_min <= SOC(t+1) <= SOC_max, -P_dis_max <= P_bat(t) <= P_ch_max]; end这里有个我吃过大亏的地方:YALMIP 的版本更新速度很快,老代码在新版本上有时会报"Unable to convert"或者"Double".
这里有个我吃过大亏的地方:YALMIP 的版本更新速度快,老代码在新版本上有时会报奇怪的报错,比如 "Unable to convert" 或者 "Double" 相关错误,通常不是语法问题,而是内部求解器接口变了。我的处理方式是锁定一个长期稳定的 YALMIP 版本和 MATLAB 版本配套使用,项目进行中不轻易升级工具。在跑优化前,先用一个小规模的线性规划测试 YALMIP 和求解器能正常返回结果,再跑完整项目。这个习惯帮我避开了一堆莫名其妙的兼容性问题。
5.3 混合整数规划为什么比线性规划麻烦
如果热泵需要模拟启停状态,那就不能只用连续变量 P_hp,还要引入 0-1 整数变量表示开/关:
u_hp = binvar(24, 1); % 0-1 变量 Constraints = [Constraints, 0 <= P_hp <= 50 * u_hp];这样一来,问题的性质从线性规划变成了混合整数线性规划(MILP),求解复杂度大幅提升。24 个时段的问题还好,但如果做到全年 8760 个小时,整数变量的数量会变成 8760 个,求解时间会从几秒变成几十分钟甚至更久。为了缩短求解时间,行业内常用滚动时域优化或者聚类时段法,把 8760 个小时聚合成几十个典型日,大大降低问题规模。我自己的做法是先用 K-means 算法把全年的气象和负荷曲线聚成 12 个典型场景,每个场景算完后再按天数加权求和,得到全年总成本估计值。这个思路在工程上非常有效,精度损失控制在 5% 以内,但计算时间几乎可以忽略。
5.4 一个隐藏很深的坑:SOC 初始值对优化结果的影响
不知道大家有没有遇到这种情况:同一组数据,把初始 SOC 从 0.5 改成 0.8,优化结果差异特别大。这并不一定是模型问题,而是因为储能是在一天之内做能量搬移,初始 SOC 决定了这一天开始时电池有多少余量,如果不设置调度周期结束时的 SOC 回补约束,求解器会倾向于把电池在最后时刻放空,从而最小化放电惩罚,这种结果在工程上完全没有意义。
正确做法是在约束里加上末尾 SOC 回补条件,比如 (SOC(24) \ge SOC(1)),代表一天运行前后电池电量不减少。更进一步,还可以在目标函数里加上对 SOC 偏离设定值的惩罚项,鼓励优化算法把 SOC 维持在合理区间。这种约束处理经验不属于教科书写的内容,但实际工程里几乎每次都会遇到。多目标优化其实是多约束博弈,你给求解器定了什么边界条件,它就输出什么策略,边界定得越贴近实际,结果才越可靠。
5.5 优化结果的后处理:解开物理意义这个黑盒
求出最优解之后,不要急着把结果写进报告,先做一次工程合理性审查。我通常把优化结果按小时画成堆叠图,包括每个时刻的光伏出力、购电功率、储能充放电功率、热泵电功率、电负荷,附上 SOC 曲线和热泵启停状态。堆叠图能直观看出调度策略是否符合能量守恒,有没有出现电负荷 + 热泵用电大于光伏+购电+电池放电视这种明显的物理错误。审查优化结果这一步,本质上是用工程直觉给数学求解器当裁判,裁判这个角色不应该偷懒。
有时候优化结果会给出比较"怪异"的策略,比如弃光的同时还在从电网购电。这类结果背后通常是因为分时电价在特定时段特别低,而从电网购电比使用光伏更划算,或者是光伏出力时段电池已经充满,无法消纳更多电能,弃光反而是最优策略。看到这些反直觉结果时,不要急着改模型,先验算一遍成本和约束是否真的支持这个结论,理清楚之后往往能写出更有价值的分析段落。
6. 实操总结与方法论沉淀
光储热微网这个案例做完之后,我对 MATLAB 综合能源系统建模这件事有了几点很实在的体会。第一点,建模工作的核心不是怎么写代码,而是怎么定义模型的目标、边界和粒度。目标决定了你选哪条建模路线,边界决定了你放哪些设备进模型,粒度决定了你用连续模型还是离散模型。想清楚这三件事,代码实现反而是最简单的一环。
第二点,模型校核所占的时间比例应该超过整体项目的一半。很多时候模型看起来曲线合理,但能量守恒残差偏大、极端工况下出现发散,这些问题在优化阶段会加倍放大。宁可多花几天做校核,也不要拿到未验证的模型直接跑优化,否则出来的数据会挑战你的专业判断力。
第三点,优化求解的本质是对工程规律的数学表达。YALMIP 也好,intlinprog 也好,fmincon 也好,都只是工具。真正决定结果优劣的,是对目标函数、约束条件、时间粒度的取舍判断,以及把工程约束准确翻译成数学约束的能力。这些能力需要在一次一次调参、一次一次对标、一次一次复盘里打磨。我建议每个做综合能源方向的朋友都能亲手把从数据到模型的完整流程走一遍,把常见坑都踩一遍,踩过的坑就是以后指导别人最有说服力的素材。