尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Matlab能源优化模型定制实战:储能调度与机组启停关键技巧

Matlab能源优化模型定制实战:储能调度与机组启停关键技巧 在能源优化这个圈子里摸爬滚打这几年我最深的感受是Matlab模型定制听着像个高大上的活儿其实就是把物理规律、设备特性、业务规则翻译成一套能让求解器听懂的数学语言。别管是储能电站的充放电策略、微电网的日前调度还是机组启停组合最后落到代码上都是同一套思路——谁来决策、怎么定义好坏、有哪些规矩不能违反。很多人一开始都会直接用现成的优化函数比如linprog、intlinprog、fmincon发现标准例程一跑就通等真把光伏数据、负荷曲线、电池SOC塞进去立刻翻车。原因不复杂教科书里的问题都太“干净”了真实能源系统的约束多、尺度乱、还带一堆离散状态。这时候就需要动手做模型定制。这篇文章把我这些年做能源优化模型定制积累的经验、踩过的坑以及几个非常规但好用的操作方法整理出来。适合正在做电力调度、储能策略、微电网能量管理或者正准备用Matlab解决能源优化问题的朋友。无论你是刚接触优化工具箱还是已经写了半年.m文件应该都能找到点有用的东西。1. 为什么能源优化这行越来越需要“模型定制”1.1 标准工具箱能吃下的只是问题的一半Matlab自带的优化工具箱确实能打linprog解线性规划、intlinprog解混合整数线性规划、fmincon解非线性规划基本把常规算法都覆盖了。可你要是真拿一套现成的电力调度模型去套十有八九会卡壳。原因在于这些函数本质上只解决一件事在给定目标函数和约束条件之后找出最优解。至于“目标函数怎么设”“约束条件怎么来”工具箱一概不管。你看官方文档里的例子通常都是“min c‘x满足Ax≤b”这种干干净净的数学形式。可实际能源优化问题是什么样功率平衡要考虑光伏出力和负荷曲线储能系统有充电效率、放电效率、SOC上下限火电机组有爬坡速率、最小启停时间电网侧还有购电功率限制。这些东西没有哪个是linprog自带的全都要你自己建模。另外能源优化领域本身跨度很大。有人拿Matlab做有限元、图像处理、随机游走模型也有人拿它做调度策略和路径规划。这个工具之所以好用是因为矩阵运算和优化求解器都经过充分验证。但“万能”的另一面就是“零件需要自己组装”你能拼成什么样取决于你对物理过程的理解有多深。所以模型定制不是锦上添花而是把Matlab真正用起来的前提。1.2 能源场景的特殊性约束、时间尺度与不确定性能源优化问题的第一个特点是时间尺度跨度大。日前调度通常以1小时为步长日内滚动优化可能压缩到15分钟再往下还有AGC这种秒级控制。步长一变状态更新公式、爬坡约束、充放电能量换算全都要跟着改。同一个储能模型在日前调度里SOC变化量可以用“功率×1小时”来算到15分钟步长就得乘0.25小时这个细节漏了整个计划都会错。第二个特点是约束条件多且相互耦合。设备功率上下限、储能SOC区间、充放电效率、机组爬坡速率、启停状态、备用容量需求这些约束不是孤立存在的它们通过能量平衡方程连在一起。比如你要保证系统任意时刻都有足够的旋转备用就会出现一组耦合不等式涉及多台机组的实时出力上限。第三个特点是离散变量。机组要么开要么关设备要么投要么切这在数学上对应0-1整数变量。而Matlab里的linprog只处理连续变量根本接不住这种问题。想处理启停逻辑就得用intlinprog或者自己把逻辑做一些线性化处理。从另一个角度说能源调度本质上就是一个离散时间系统每个时间步的决策依赖于上一个时间步的状态储能SOC、机组启停状态、爬坡位置都是状态量。你越早意识到这一点建模时就越不容易跑偏。第四个特点是不确定性。光伏出力看天吃饭负荷也有预测误差。很多教材里的经典算法假设数据完全已知实际项目里根本不是这么回事。于是就有了场景法、鲁棒优化、随机规划这些处理不确定性的手段。这些手段同样不是工具箱现成的需要定制。1.3 模型定制到底在定什么既然标准工具箱覆盖不了完整问题那“定制”到底定什么我一般会把它拆成五块。决策变量集合。这个最简单也最需要想清楚。储能调度问题里决策变量是购电功率、充电功率、放电功率机组组合问题里还要加入0-1启停变量。变量选得对不对直接影响模型规模和解的质量。目标函数。是购电成本最小还是碳排放最小还是综合收益最大。很多目标之间可以互相转化比如收益最大化等价于成本最小化的负值但如果目标里有非线性项就得仔细考虑求解器的选择。约束条件。这是模型定制最核心的部分。功率平衡、设备限值、SOC转移、爬坡限制、备用容量、启停逻辑每一条约束背后都是真实的物理规则。漏掉一条结果就可能没法落地执行。求解策略。同一类问题用linprog还是intlinprog用默认参数还是调整求解器容差结果可能天差地别。这需要根据问题规模、整数变量数量、非线性程度来决定。外部接口。参数怎么从Excel、数据库或者实测数据里读进来结果怎么输出成调度指令这决定了模型能不能从论文变成可用的工具。说到底模型不过关不是算法不行而是“翻译”本身出了问题。把物理世界压缩成矩阵和向量的过程最能体现一个工程师的功力也是所谓骚操作最多的地方。2. 定制的起点把物理过程翻译成数学语言2.1 储能模型SOC、充放电效率与互斥问题先拿最常见的储能系统举个完整的例子。电池模型里最核心的是SOC荷电状态它描述电池还剩多少能量取值范围通常在0到1之间。用P_ch表示充电功率P_dis表示放电功率E_max表示电池容量eta_c和eta_d分别表示充电和放电效率那么从t-1时刻到t时刻的SOC变化可以写成SOC(t) SOC(t-1) eta_c * P_ch(t) * dt / E_max - P_dis(t) * dt / (eta_d * E_max)这里dt是时间步长单位要和功率、能量一致。比如功率用kW能量用kWhdt用小时那这个式子量纲就是对的。如果你用15分钟步长dt就是0.25漏乘这个系数SOC一天下来会出现离奇的飘移。这里面有个细节特别值得注意充放电效率为什么要分开写因为电能从电网进电池要经过整流、化学反应、电池内阻等损耗实际存入的能量只有充电功率乘效率反过来电池放电到电网同样有损耗实际送出的能量是放电功率除以放电效率。再讲一个模型定制实战里经常出现的坑充放电互斥问题。如果模型里同时设置了充电功率和放电功率两个连续变量理论上最优解完全可能算出同一时刻既充电又放电。为什么因为充电功率是正变量、放电功率是正变量目标函数里如果没有对应的惩罚项求解器不觉得这有什么问题。但在实际物理系统里同时充放电等于把能量从电池左边挪到右边白白消耗效率损失。对付这个问题有种骚操作是在纯电价套利模型里根本不用管互斥约束。因为同时充放电只会额外产生损耗、增加成本求解器在最小化成本的目标下会自动避开。但如果你加了其他成本项或者市场规则比如充电补贴和放电收入都计入目标那就有可能出现同时充放电的最优解。到这时候就得加约束P_ch(t) P_dis(t) P_max或者用0-1变量做严格互斥。这里想表达的核心思路是能用物理特性自动规避的约束就不必额外增加模型复杂度。每少一个整数变量求解速度就快一大截。2.2 功率平衡与设备限值最容易遗漏的约束储能建完之后接着要把整个系统的能量守恒写出来。对一个光储微电网来说功率平衡约束长这样P_buy(t) P_pv(t) P_dis(t) P_load(t) P_ch(t)左边是购电、光伏出力、电池放电右边是负荷加上电池充电。这个约束看起来简单但方向写反的人不在少数。稍微想一下物理含义就知道负荷和充电是消耗功率的光伏和放电是提供功率的而购电只进不出。所以购电、光伏、放电在一边负荷、充电在另一边。然后是各种上下限约束。购电功率一般有上限取决于变压器容量和并网协议充电功率和放电功率不超过电池最大功率机组出力不超过铭牌容量还要满足最小技术出力。这些上下限写起来都很直接用lb和ub就能处理一部分但带条件的上下限就不行了。真正的坑在爬坡约束。很多第一次做调度模型的人会忘记机组出力不能突升突降。一台燃机上一小时还在跑80MW这一小时突然要求它升到120MW它根本做不到。爬坡约束通常写成-P_g_ramp_max * dt P_g(t) - P_g(t-1) P_g_ramp_max * dt这是个线性不等式但在Matlab里实现时要注意变量索引关系。我自己就犯过把t和t-1索引写反的错结果跑出来一个“时间倒流”的调度计划检查半天才找到问题。如果你还要预留旋转备用还要再加一组约束所有在线机组最大出力之和减去当前出力之和必须大于备用容量需求。这类约束在目标函数里没有直接体现但对系统的安全性至关重要漏掉之后模型解出来可能特别省钱但一遇到扰动系统就崩。2.3 不确定性建模场景法与鲁棒化的取舍光伏和负荷预测永远有误差这决定了能源优化不能完全用确定性模型。但不确定性建模的坑在于很多人一上来就想上鲁棒优化或者随机规划结果模型复杂度爆炸最后连可行解都找不到。我的建议是先做确定性模型把基线问题调通再逐步增加不确定性。最常见的做法是场景法生成一组光伏出力场景每个场景给一个权重目标函数变成所有场景成本的期望值。理论上每个场景都要复制一套约束条件模型维度会成倍增长。T是24、场景数N是5MILP规模立马变成原来的5倍求解时间可能不止涨5倍。还有一种更实用的做法是仿射可调鲁棒优化。它假设某些决策变量比如购电功率可以随着不确定参数比如光伏预测误差线性调整在约束里加入调整系数。这种方法稳健性强但实现起来复杂需要对对偶理论和线性化技巧很熟。对于大多数实际项目我倾向于采用折中方案确定性预测加备用约束。先把预测值作为基准场景优化再通过备用容量约束保证最恶劣情况下的安全。这样模型规模不会膨胀太多工程上又足够可靠。等你把这条路径跑通了再根据实际需要升级成多场景或鲁棒版本。3. 核心干货用Matlab优化工具箱实现定制模型3.1 工具箱选型linprog、intlinprog、fmincon、ga怎么选选求解器之前先给问题贴个标签线性还是非线性连续变量还是含整数变量这个判定做对了后面的坑能少一半。函数适用问题典型场景注意事项linprog线性规划(LP)连续变量的成本最小化、储能调度约束必须线性速度快适合大模型intlinprog混合整数线性规划(MILP)机组启停、设备状态切换整数变量越多越慢注意容差设置fmincon非线性规划(NLP)非线性目标、非线性约束容易陷入局部最优多试几组初值ga遗传算法非线性且离散的复杂问题收敛慢建议最后再用选型逻辑其实很简单。先看目标函数和约束是不是关于变量的线性表达式如果是线性那就走linprog或者intlinprog差别只在有没有整数变量。如果问题里有0-1变量比如机组启停、设备投切不用怀疑直接上intlinprog。如果你用linprog去解它会直接报错或者忽略整数要求结果根本不可用。如果目标函数是非线性的比如考虑电池老化成本时加入充放电深度的二次惩罚项fmincon是常见选择。但fmincon对初值很敏感不同初值可能得到完全不同的局部最优解所以实战里会用多组初值跑一遍从中选目标函数值最小的那个。至于ga我一般把它当最后手段。它虽然能处理非线性、整数、非凸等一堆复杂情况但收敛速度感人模型稍微大一点就可能跑几分钟甚至几十分钟。能用解析梯度或线性化的就别用遗传算法。3.2 光储微电网日前调度linprog完整实现下面动手做一个完整案例这个案例我拿过很多次从学生课程设计到工程可行性分析都适用。假设有一个光储微电网包含光伏、储能电池和电网购电通道。已知未来24小时的负荷预测、光伏出力预测和分时购电价目标是决定每个时刻从电网买多少电、电池充多少放多少让总购电成本最低。电池参数容量100kWh最大充放电功率20kW充放电效率都是0.95SOC允许范围0.1到0.9初始SOC和日末SOC都要求0.5。功率单位用kW能量单位用kWh时间步长1小时。完整代码我直接贴出来逐行注释过% 光储微电网日前调度模型 clear; clc; T 24; % 电池参数 E_max 100; % 容量 kWh P_bat_max 20; % 最大充/放电功率 kW eta_c 0.95; % 充电效率 eta_d 0.95; % 放电效率 SOC_min 0.1; SOC_max 0.9; SOC_init 0.5; % 初始SOC也要求日末回到这个值 % 负荷曲线示例数据单位kW P_load [ 18;17;16;15;15;16;22;28;32;35;38;40; 38;36;35;34;36;40;42;38;32;26;22;18 ]; % 光伏出力曲线示例数据单位kW P_pv [ 0;0;0;0;0;2;8;16;24;30;34;36; 34;30;24;18;10;4;0;0;0;0;0;0 ]; % 分时购电价元/kWh price [ 0.35;0.35;0.32;0.30;0.30;0.32;0.50;0.72; 0.90;1.00;1.10;1.05;0.95;0.90;0.80;0.70; 0.68;0.85;1.00;1.15;1.05;0.85;0.60;0.40 ]; % 决策变量 x [P_buy(1..T); P_ch(1..T); P_dis(1..T)] N 3*T; f [price; zeros(T,1); zeros(T,1)]; % 目标只最小化购电成本 % 功率平衡P_buy P_pv P_dis P_load P_ch % 改写为P_buy - P_ch P_dis P_load - P_pv Aeq1 [eye(T), -eye(T), eye(T)]; beq1 P_load - P_pv; % SOC约束 % SOC(t) SOC_init sum_{k1..t}( alpha*P_ch(k) - beta*P_dis(k) ) alpha eta_c / E_max; beta 1 / (eta_d * E_max); L tril(ones(T,T)); % 下三角矩阵用于表达“累计到当前时刻” % SOC(t) SOC_max A_soc_max [zeros(T,T), alpha*L, -beta*L]; b_soc_max ones(T,1) * (SOC_max - SOC_init); % SOC(t) SOC_min等价于 -alpha*L*P_ch beta*L*P_dis SOC_init - SOC_min A_soc_min [zeros(T,T), -alpha*L, beta*L]; b_soc_min ones(T,1) * (SOC_init - SOC_min); % 日末SOC回到初始值sum(alpha*P_ch - beta*P_dis) 0 Aeq2 [zeros(1,T), alpha*ones(1,T), -beta*ones(1,T)]; beq2 0; Aeq [Aeq1; Aeq2]; beq [beq1; beq2]; A [A_soc_max; A_soc_min]; b [b_soc_max; b_soc_min]; lb zeros(N,1); ub [inf(T,1); P_bat_max*ones(T,1); P_bat_max*ones(T,1)]; % 求解 options optimoptions(linprog, Display, iter); [x, fval, exitflag] linprog(f, A, b, Aeq, beq, lb, ub, options); % 结果提取 P_buy x(1:T); P_ch x(T1:2*T); P_dis x(2*T1:3*T); % 打印SOC变化 SOC zeros(T,1); soc SOC_init; for t 1:T soc soc alpha*P_ch(t) - beta*P_dis(t); SOC(t) soc; end % 校验 residual max(abs(P_buy P_pv P_dis - P_ch - P_load)); fprintf(购电成本%.2f 元\n, fval); fprintf(SOC范围[%.2f, %.2f]\n, min(SOC), max(SOC)); fprintf(功率平衡最大残差%.2e\n, residual);这段代码里有几个骚操作值得单独说明。第一变量拼接。把三个物理量写成一个大向量然后用索引切片拆开这在Matlab优化建模里最省事。函数f和约束矩阵A的列数也直接跟着这个顺序走不容易搞乱。第二tril(ones(T))这个下三角矩阵。很多人写SOC累计约束会用for循环一个个时刻描点又慢又乱。用下三角矩阵一行代码就把24个不等式全部写出来了。第三没加充放电互斥约束。在这个模型里同一时刻既充电又放电一定是往成本里添乱求解器不会这么干所以不加二进制变量模型保持纯LP求解速度飞快。运行完这个模型你大概率会看到这样的结果凌晨电价低的时候电池充电中午光伏大发时减少购电甚至把多余的光伏存起来晚上电价冲高的时候电池放电。SOC曲线会在0.1到0.9之间平滑变化日末恰好回到0.5。如果这些现象没出现说明你数据或者约束写错了。3.3 进阶intlinprog处理机组启停与滚动优化前面的光储模型只有连续变量代价是没考虑储能本身的启停状态也没考虑常规机组的组合问题。真做微电网调度经常要决定柴发或者燃气轮机开几台、什么时候开。这时候就要引入0-1变量用intlinprog。机组启停建模的核心思路很简单用u(t)表示第t时刻机组是否在线u(t)1在线u(t)0停机。然后机组的出力范围变成Pg(t) Pmin * u(t) Pg(t) Pmax * u(t)这两个约束保证了机组停机时出力只能为0机组在线时出力必须落在最小技术出力和最大出力之间。就这么简单但缺了哪怕一个模型就可能算出停机机组还在出力的荒谬结果。实际代码里你只需要在变量向量中留出u的位置然后在intcon参数里告诉求解器哪些变量是整数。比如T 24; % 假设决策变量 x [Pg(1..T); u(1..T)]其中u是0-1变量 Pg_index 1:T; u_index T1:2*T; intcon u_index; % 整数约束索引 % 目标燃料成本 启停成本 f [fuel_cost*ones(T,1); start_cost*ones(T,1)]; % Pg(t) - Pmax*u(t) 0 A zeros(2*T, 2*T); b zeros(2*T, 1); for t 1:T A(t, Pg_index(t)) 1; A(t, u_index(t)) -Pmax; % Pg(t) - Pmin*u(t) 0 -Pg(t) Pmin*u(t) 0 A(Tt, Pg_index(t)) -1; A(Tt, u_index(t)) Pmin; end options optimoptions(intlinprog,Display,iter, ... RelativeGapTolerance, 1e-4); [x, fval] intlinprog(f, intcon, A, b, [], [], ... zeros(2*T,1), [Pmax*ones(T,1); ones(T,1)], options);如果还想考虑启动成本就不能简单把u的线性惩罚放目标里因为“机组从0变1”这个上升沿才是真正的启动动作。更严谨的做法是引入辅助变量y(t)加入约束y(t) u(t) - u(t-1)目标函数里对y(t)加启动费用。这个线性化技巧在很多地方都用得上属于模型定制的关键招式。从日前调度到日内滚动优化代码改起来也不复杂。核心就是把24小时的大模型缩到未来N步每一步求解之后只执行第一步控制然后滚动更新预测数据。伪代码长这样for t 1:T-1 updatePrediction(); % 更新未来N步的光伏、负荷预测 buildModel(t); % 构建从t时刻开始的子模型 [x, fval] solveModel(); % 调用 intlinprog 或 linprog applyControl(x(1)); % 只执行当前时刻的第一步动作 end这就是工程上常说的模型预测控制思路。模型本身没变变的只是参数更新和循环方式。4. 实操中那几个最容易翻车的环节4.1 维度爆炸与索引错位我见过太多模型跑飞最后发现矩阵维度对不上。尤其当决策变量用拼接方式组织时索引错位是最隐蔽的错误。比如前面光储模型的变量顺序是[P_buy; P_ch; P_dis]有人写约束时把P_ch取成了x(1:T)把P_buy取成了x(T1:2T)结果功率平衡约束和物理意义完全拧了但求解器还照样返回一组“最优解”。防止这类错误我的习惯是先用T4做调试。T小变量少手动都能算出结果维度对不对一目了然。跑通了再放大到T24。另外每次构造完Aeq和A矩阵都用size函数核对列数assert(size(Aeq,2) numel(f), Aeq列数与决策变量数不一致); assert(size(A,2) numel(f), A列数与决策变量数不一致);T变大以后还要注意内存。24小时还好如果做365天8760小时的长周期规划直接构造全矩阵会吃内存。这时候就要用sparse创建稀疏矩阵。优化问题的约束矩阵大多数是稀疏的用稀疏矩阵能省下几个数量级的内存和求解时间。4.2 求解器选错导致的“假装有解”求解器选错最典型的就是用linprog解整数问题。有些版本甚至不会直接报错而是把整数变量当作连续变量处理返回一个所谓的“最优解”实际上完全没有可行性机组可能开在半开状态、设备可能投切在0.3这种位置。这个坑特别阴险因为exitflag还是1看起来一切正常拿去做调度就会完全失控。另一种常见翻车是用fmincon去解混合整数问题。fmincon压根不支持整数变量你用round强行把变量取整又会破坏约束最后结果既不是原问题的解也不是松弛问题的解处于一种两头不靠的悬浮状态。对付这类问题必须用支持整数的求解器比如intlinprog或者外部求解器。我踩过几次坑之后总结出一个习惯动手写代码前先拿一张纸把问题分类写清楚。决策变量全是连续目标函数和约束都是线性用linprog有整数变量其他线性用intlinprog出现非线性项再看规模决定用fmincon还是优化工具箱里的其他算法。分类这步花五分钟后面能省五小时。4.3 结果合理性快速校验模型能跑出结果不等于结果是对的。能源优化模型尤其如此因为解出来的是一堆调度指令指令不合理执行层根本没法用。我最常做的校验有三项。第一看约束残差。比如功率平衡约束改成等式约束后把最优解代回去算Aeq*x - beq残差应该在1e-6量级附近如果残差达到1e-2说明数值精度有问题需要检查是否出现了极端的数量级差异。第二看边界现象。SOC有没有越界、充放电功率有没有超过最大值、购电功率是不是永远不为负数这些检查一眼就能看出异常。第三手算小案例。这是最土但也是最好用的方法我至今保留这个习惯调一个两时段的简单算例人工推导最优解再拿代码跑一遍两个结果对不上就说明模型有问题。另外一个直观的验证手段是画图。把负荷曲线、光伏出力、购电功率、电池充放电和SOC画在一起调度逻辑是否合理一眼就能看出来。如果电价高峰时段电池在充电电价低谷时段电池在放电不用怀疑模型哪个环节肯定写反了。5. 常见问题与排查技巧实录5.1 求解器一直跑不出来的排查顺序intlinprog跑很久不出结果是能源优化里最常见的求助帖主题。遇到这种情况我一般按固定顺序排查。第一步检查可行域是否为空。调用linprog之前先跑一次不带整数约束的线性松弛模型如果线性松弛都不可行那原问题一定不可行不用浪费时间。第二步检查约束是否互相矛盾。比如SOC min和SOC max写反、Pmin大于Pmax这类低级错误虽然蠢但确实经常发生。第三步尝试缩小模型规模。把24小时缩成6小时看能不能快速解出如果小模型都跑不动问题就在约束或数据上不在规模上。第四步调整求解器参数。intlinprog支持RelativeGapTolerance、MaxTime、Heuristics等选项给一个合理的时间限制比如600秒同时放松间隙容差到1e-3大多数工程问题都能在可接受时间内找到不错的可行解。5.2 数值尺度问题别把模型建成1e100Matlab里1e100就是1乘10的100次方表达起来很简单。但在优化模型里出现这种夸张数值通常意味着你犯了单位错误。变量单位不统一是能源优化数值问题的头号来源。比如光伏功率用的是kW储能容量用的是MWh购电价格用的是元/MWh三个量放在一个约束里数值差距好几个数量级求解器内部的容差判断就会出现错乱。解决这个问题核心就是统一单位。我的习惯是全部用kW、kWh和小时价格用元/kWh。如果模型里有MW级别的机组那就把所有功率统一到MW能量统一到MWh不要混着来。另一个技巧是做归一化把关键的决策变量和约束系数缩放到0.1到1000这个区间内这个范围内的数值对求解器最友好。数值病态的另一个表现是目标函数里各项数量级差太多。比如购电成本是几万元启停成本是几百元电池损耗成本是零点几元合在一起后小数量级项几乎被忽略。这时候就要考虑是否把目标函数拆成多目标或者给各项乘以合适的权重保证每个目标都有实际意义。5.3 关于“代跑程序”的几句实在话搜索热词里总能看到“matlab代跑程序”这确实反映了很多人面临的情况代码写不出来或者跑不通想找人帮忙。我以前也接过一些这种活儿说点实在话。代跑能帮你解决“跑通”但解决不了“理解”。能源优化模型的核心在建模逻辑不在最后一行fprintf。如果模型本身的方向错了比如约束写错、变量定义不清代跑的人也只能把错的东西跑出一个不错的结果这种结果拿回去没有任何意义。真正有效的做法是把模型当回事自己先把问题描述清楚。哪怕你完全不会写代码能说清楚“决策变量是什么、目标函数是什么、约束条件有几类”你离正确答案就已经很近了。我在做模型定制的时候最怕的不是对方代码写得烂而是对方对物理过程一无所知。反过来你只要能把储能SOC、功率平衡、机组启停逻辑说清楚哪怕代码写得丑一点改起来都很快。6. 从模型到落地后续还能怎么扩展6.1 日前调度到日内滚动日前调度用的全是预测数据误差会在执行过程中不断积累。所以工程上更常见的是日内滚动优化每隔15分钟或1小时拿到最新的实际出力和负荷反馈重新优化一次未来一段时间的调度计划。这个扩展对模型定制能力要求很高因为参数化做得好不好直接决定你能不能把离线模型快速切成在线模型。我一般把模型封装成一个函数输入是当前时刻、最新预测曲线、当前SOC、最新电价输出是本时段及未来N步的计划。这样每次滚动调用同一个函数就行不用反复改脚本。封装函数这件事听起来很简单但很多人的模型写着写着就变成一坨不可重用的脚本改一次数据要命。6.2 部署与联合仿真模型验证完之后往往要部署到实际系统里。Matlab Compiler可以把模型编译成独立可执行程序不用装完整Matlab也能运行也可以编译成DLL或者通过Web接口供其他系统调用。我在项目里更常用的是混合部署Matlab负责优化求解Python或者C#负责数据采集和界面展示两边通过文件、数据库或者API通信。部署阶段有两个容易忽视的点。第一个是toolbox授权问题。优化工具箱、编译器的授权方式不同打包给别人用的时候要确认清楚。第二个是求解器超时问题。实际运行环境不可能让你无限等下去一定要给优化过程设置MaxTime之类的限制超时之后要么用当前最可行结果兜底要么切换到一个简化的启发式策略。实时调度对稳定性的要求比对最优性的要求高得多。6.3 优化预测混合模型光伏出力和负荷预测误差会影响优化效果所以很多人在优化前面加一层预测模型。Matlab的Deep Learning Toolbox里可以训练BiLSTM这类循环神经网络用来预测负荷曲线或者SOC变化趋势然后把预测结果作为优化模型的输入参数。很多朋友一听到预测就想上强化学习PPO代码在Matlab里也能跑但我要泼点冷水。PPO适合那种动作空间特别复杂、在线学习收益明显的场景。而能源调度问题通常有清晰的物理约束传统优化方法能给出可解释、可验证的调度策略这对运行人员来说太重要了。预测和优化结合的正确姿势普遍是先做高精度的负荷、光伏预测再把这些预测值作为确定性参数送进优化器。如果实测偏差大再用场景法或者鲁棒优化兜底。至于SOC预测可以单独用BiLSTM做电池状态估计结合温度、电流、电压历史数据效果比简单安时积分要好。但这类模型属于数据驱动需要足够多的历史数据而且要定期重新训练不然电池老化后分布漂移会让模型失效。混合建模的思路是在物理模型基础上叠加数据驱动模块这样既保持物理可解释性又能捕捉一些复杂非线性规律。以我自己的习惯任何一个能源优化模型写完之后我都会先把它缩到两个时段手动算一遍最优解再放回24小时跑。这一步看着土但救过我太多次。Matlab模型定制这件事说到底是把一个复杂的物理世界压缩到矩阵里再让求解器帮我们在里面找答案。压缩得越干净后面的路越好走。
返回列表