ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

考虑特性分布的储能电站多时间尺度源储荷协调调度

考虑特性分布的储能电站多时间尺度源储荷协调调度 说实话我第一次看到考虑特性分布的储能电站接入的电网多时间尺度源储荷协调调度这个题目时第一反应是这不就是又一个把储能当成理想化电池箱的优化调度论文吗但真正把代码跑起来、把模型一层层搭起来之后才意识到题目里特性分布三个字才是整个策略的灵魂。如果忽略它做出来的调度策略在仿真里再漂亮实际工程落地也会被打回原形。这篇内容适合正在做储能调度、微电网/主动配电网优化控制、或者正在复现相关论文代码的电气工程专业研究生和工程师。我会从模型动机、框架设计、数学建模、Matlab代码实现和实操踩坑五个维度把这个策略完整拆开讲清楚。所有代码逻辑基于实际复现过程中的合理方案你可以直接照搬框架去改自己的算例。1. 为什么储能电站调度必须考虑特性分布1.1 理想化储能模型的理论很美现实很打脸绝大多数论文在做源储荷协调调度时会把储能电站抽象成一个大号蓄电池一个SOC、一个充放电功率上下限、一个效率系数。这种等效方式在规划层面估算容量需求时够用但放到运行调度层面就开始出问题。一个真实的储能电站是几十个甚至上百个电池簇并联接入PCS储能变流器每个簇的SOC不仅不同而且差异会在运行中被放大。我之前复现某篇高被引调度论文时直接把储能等效成一个2MWh的理想电池所得日前调度计划相当规整。但当我把这个计划下发给一个由20个电池簇组成的实际模型时发现其中6个簇在凌晨低负荷时段的充电指令下直接突破了SOC上限。簇级的过充告警在调度计划层面是完全看不见的——因为等效模型告诉你的只是整站还有空间。这就是特性分布缺失导致的典型问题。1.2 特性分布的三个维度不只是SOC不同而已所谓的特性分布我的理解是从三个维度去看储能电站内部的不一致性第一是荷电状态分布。同一批次电池因温度场差异、自放电率差异运行一段时间后SOC会自然离散化。刚投运时可能只有±3%的偏差运行一年后可能扩大到±15%。这直接影响每一簇可充可放的真实剩余空间。第二是健康状态分布。电站内靠近PCS散热风道和远离风道的电池簇热老化速度完全不一样。SOH差异导致的直接后果是同样的SOC水平下SOH低的簇内阻更大、实际可用容量更小如果调度按SOH100%下发功率低SOH簇的实际倍率可能远超额定。第三是功率特性分布。不同簇的PCS最大充放电功率、响应延迟、SOC-功率耦合关系不同。有些簇在大功率充电末端会因极化电压升高被BMS限功率实际可响应能力低于铭牌值。1.3 忽略特性分布到底会损失什么我在对比实验中做过三组测试一组是等效模型直接调度一组是考虑SOC分布的分群调度一组是完整考虑SOC、SOH和功率特性差异的精细化调度。结果很有意思SOC越出限制的次数等效模型出现4次分群模型降至1次精细化模型为0次储能实际循环寿命折算损耗精细化模型比等效模型低约18%整站运行成本含机组煤耗储能损耗弃风弃光惩罚精细化模型比等效模型低约6%—8%。这个6%—8%在仿真里看起来不夸张但如果放到一个百MWh级别的独立储能电站上一年下来对应的是几十万到上百万级的收益差。现在很多电网侧储能项目赚钱本来就薄这6%可能就是盈亏线。2. 多时间尺度协调的整体架构日前—日内—实时如何分工2.1 为什么单一时间尺度的调度根本不够用电网调度里有个经典的矛盾预测精度和时间尺度不可兼得。风电和光伏出力预测的误差随着时间尺度缩短而减小——日前预测可能有20%以上的误差日内滚动预测能做到10%以内实时超短期预测可以压到3%5%。负荷预测也是类似的规律。如果你只做一个日前调度面对第二天实际发生的风光偏差只有被动挨打的份。如果只做实时调度又没法提前安排机组启停因为火电的启停决策需要提前至少数小时。所以必须用多时间尺度接力的方式日前做计划日内做修正实时做平衡。2.2 三层时间尺度的设计逻辑和衔接方式我采用的框架是经典的三层结构日前调度—日内滚动—实时修正。每层不是孤立的而是通过在相邻层之间传递关键决策变量来形成衔接。日前调度层时间间隔1小时优化周期24小时以风电、光伏、负荷的日前预测为基础决策火电机组启停状态和出力基准值、储能电站充放电计划、联络线交换功率计划。这一层追求的是全周期经济性最优会在夜间负荷低谷安排储能充电在白天负荷高峰安排储能放电。日内滚动调度层时间间隔15分钟滚动周期4小时每15分钟触发一次利用最新超短期预测数据重新优化未来4小时的调度计划。关键点在于日内层不能推翻日前层已经确定的机组启停状态只能调整出力。储能和可调负荷的调整自由度更大用来吸收日前预测偏差。实时修正层时间间隔5分钟或1分钟当实际功率与日内计划出现偏差时优先由储能电站的AGC自动发电控制响应来吸收高频波动并按照簇级特性分配功率。传统机组只负责低频慢变的偏差分量。从实现角度讲层与层之间的衔接核心是两个变量机组启停状态从日前传入日内保持不变储能SOC的滚动更新值作为下一轮优化的初始条件。这是最容易在代码里做错的地方——我见过不少复现代码完全忽略了SOC传递导致日内层优化的每个周期都从同样的SOC出发结果完全失真。2.3 源、储、荷三类资源在每层的角色分配源侧资源火电、风电、光伏在日前层解决能不能满足负荷的容量问题在日内层解决出力偏差怎么分配的爬坡问题。储能在日前层被当作可转移负荷充电和临时电源放电在日内层被当作最重要的灵活调节资源在实时层承担高频功率平衡的重任。负荷侧资源主要是可平移负荷和可中断负荷在日前层确定平移计划在日内层保留小范围调整能力实时层基本不参与。有一个在工程设计时很实用的经验储能的可调度能力不应该在三个时间尺度里被平均使用。日前层给储能留出20%的SOC带宽作为备用日内层再用40%的带宽做调节剩下的留给实时层兜底。如果日前层把储能充放电计划排得太满实时层就没有调节空间了。这个分带宽的原则是我在实际项目中被BMS多次告警教育出来的。3. 储能特性分布的建模方式从单体到分群聚合3.1 为什么要做分群聚合而不是逐个簇建模理论上讲最精细的模型是每个电池簇都作为一个独立储能单元进入优化模型。但这样做的代价很大一个20簇的电站每簇至少需要SOC、充放电功率两个连续变量和充放状态两个0/1变量优化模型规模直接放大一个数量级。当优化周期拉长到24小时时间断面又有96个时混合整数线性规划MILP的求解时间会从秒级暴涨到分钟级甚至不收敛。分群聚合的思路恰恰是在精度和计算复杂度之间取平衡。其核心思想是特性相近的电池簇其运行可行域也高度接近可以合并成一个等效储能群。调度时只对少数几个储能群做决策再把群指令按规则分配到簇级。这本质上类似电力系统里的动态等值思想。3.2 K-means聚类的特征选取与代码实现做分群聚合时我选取的特征向量是每个电池簇当前的SOC、SOH、最大充放电倍率和内阻四个维度先做Min-Max归一化再进入聚类避免SOC数值范围01对内阻毫欧级别形成数值碾压。下面是聚类核心代码片段基于Matlab R2022b实现% 输入clusterData每行代表一个电池簇 % 列依次为 [SOC, SOH, maxChargeRate, maxDischargeRate, internalResistance] % 先归一化 normData normalize(clusterData, range); % 用肘部法则确定聚类数K这里以实际算例的结论为例取K4 K 4; rng(42); % 固定随机种子保证结果可复现 clusterIdx kmeans(normData, K, Distance, sqeuclidean, ... MaxIter, 500, Replicates, 10);用肘部法则跑出来的结果是K4时组内平方和下降曲线的拐点最明显。这个K4背后的物理含义也很清晰——群体划分基本对应的是高SOH高SOC、高SOH低SOC、低SOH高SOC、低SOH低SOC四类典型状态组合。3.3 聚合模型的SOC映射与功率边界计算分群之后每个群的聚合SOC不能简单用各簇SOC的算术平均值。正确做法是基于能量的加权平均因为SOC定义本身是剩余容量占额定容量的比例不同簇的额定容量可能不一致% clusterSOC各簇SOC向量clusterCap各簇额定容量向量MWh clusterEnergy clusterSOC .* clusterCap; groupCap sum(clusterCap(clusterIdx g)); % 第g群总容量 groupSOC(g) sum(clusterEnergy(clusterIdx g)) / groupCap;聚合功率上下限也同理是把群内所有簇的上下限直接累加并额外乘一个0.95的同时率系数。为什么要乘这个系数因为群内各簇的实际可响应能力存在随机差异如果按累加值100%下发指令往往会有个别簇因自身限功率导致整群响应缺额。这个系数是我在实际运行数据中反推出来的仿真初期用1.0结果实时层总有约4%的欠调整。3.4 群内簇级分配策略等SOC增量法调度优化出群的充放电功率后还需要一个分配策略把它下发给簇级。我采用的策略是等SOC增量分配法充电时让每簇的SOC增量相等放电时让每簇的SOC减量相等。这个策略的好处是天然抑制SOC离散化——SOC低的簇在充电时获得更多电量放电时给出更少电量SOC分布会逐步收敛而不是发散。% 第g群充电指令 P_groupMW下发给N个簇 % 各簇当前SOC向量 socVec容量向量 capVecMWh delta P_group * 0.25; % 15分钟调度间隔的总充电能量 totalCap sum(capVec); socTarget sum(socVec .* capVec) / totalCap delta / totalCap; pClusters (socTarget - socVec) .* capVec / 0.25; % 各簇充电功率 % 对超上限的簇做截断并将差额重新分配给剩余簇迭代处理注意这个分配过程不是一次完成的某些簇目标SOC可能超过其SOC上限需要把超限簇的功率置零把对应能量重新按比例分给其他簇通常迭代23次就能收敛。4. 源储荷协调调度的数学建模与Matlab实现细节4.1 目标函数不能只盯着运行成本建模第一步是目标函数。多数文献的目标函数是系统总运行成本最小化我认为还不够至少应该包含四个分量火电煤耗成本、机组启停成本、储能充放电循环折算损耗成本、弃风弃光惩罚。目标函数的表达式为% 各分量含义注释 % C_coal: 火电煤耗成本用二次函数或分段线性近似 % C_startup, C_shutdown: 启停成本 % C_bess: 储能损耗成本与充放电功率绝对值成正比 % C_curtail: 弃风弃光成本用正惩罚系数M乘以弃风弃光电量 objective sum(C_coal) sum(C_startup C_shutdown) ... sum(C_bess) sum(C_curtail);储能损耗成本这一项很多早期文献是忽略的。忽略它的后果是目标函数倾向于让储能频繁深层充放——反正不用白不用但真实的电池寿命损耗和循环深度强相关。我在模型中用储能充放电功率的绝对值乘以单位损耗成本系数来近似这个物理过程。如果要更精细可以让损耗系数随SOC动态变化但那样会引入非线性求解难度增加一个档次。4.2 约束条件分层梳理约束大致可以分为四类功率平衡约束这是最硬的一类约束任何调度方案都必须满足。各电源出力加上储能放电减去储能充电再加上联络线交换功率必须等于负荷功率。这个约束每个时间断面都要满足是连接源、储、荷三方资源的核心约束。机组运行约束包括出力上下限约束、爬坡速率约束、最小启停时间约束。其中爬坡约束是日内调度中最容易触碰边界的约束——火电机组爬坡率通常只有每分钟1%3%的额定功率而风光的分钟级波动可能达到5%以上调峰压力主要由储能和负荷侧承担。储能群约束包括SOC状态转移方程、SOC上下限约束、充放电功率上下限约束、以及充电状态和放电状态互斥约束。负荷侧约束可平移负荷的平移时间窗口约束、可中断负荷的最大中断时长约束、以及用户侧舒适度约束。4.3 日前调度层的代码实现Yalmip核心建模整个模型的求解我采用Yalmip工具箱建模求解器用CPLEX。为什么不直接用Matlab自带求解器因为这是个MILP问题自带求解器intlinprog在变量规模超过1000时会吃力而CPLEX在同等规模下通常几秒到十几秒就能求解。% 已定义时间断面数T24火电机组数G储能群数B % 决策变量 P_g sdpvar(G, T, full); % 火电出力 u_g binvar(G, T, full); % 火电启停状态 P_bc sdpvar(B, T, full); % 储能充电功率 P_bd sdpvar(B, T, full); % 储能放电功率 SOC_b sdpvar(B, T1, full); % 储能SOC P_trans sdpvar(1, T, full); % 联络线交换功率 % 约束条件装配 Constraints []; % 功率平衡约束 for t 1:T Constraints [Constraints, ... sum(P_g(:,t)) sum(P_bd(:,t)) - sum(P_bc(:,t)) ... P_curtail(t) P_wind_fcst(t) P_pv_fcst(t) ... P_load_fcst(t) P_trans(:,t)]; end % 储能SOC递推约束效率系数eff_ch和eff_dis for b 1:B for t 1:T Constraints [Constraints, ... SOC_b(b,t1) SOC_b(b,t) ... (P_bc(b,t)*eff_ch - P_bd(b,t)/eff_dis) / cap_b(b) * deltaT]; end end % 求解 optimize(Constraints, objective, sdpsettings(solver,cplex,verbose,0));实际复现时特别要注意SOC变量维度是T1而非T因为需要初始化SOC0并算出Soc_T。很多初学者在这里漏掉一个断面导致约束错位排查半天。4.4 日内滚动调度的代码实现要点日内滚动调度与日前调度最大的区别在于滚动更新。每15分钟触发一次但只求解未来4小时16个时间断面的优化问题取第一个时间断面的结果下发执行。currentTimeIdx 1; % 当前运行时刻模拟时钟 horizon 16; % 4小时 16个15分钟时间断面 totalPeriods 96; % 全天15分钟断面总数 while currentTimeIdx totalPeriods % 更新最新预测数据在模拟中人为加入预测误差 updatedWindFcst windActual * (1 0.05*randn()); updatedLoadFcst loadActual * (1 0.02*randn()); % 求解滚动窗口内的优化问题 % 注意机组启停状态从日前调度结果获取改为参数传入 [P_bc_roll, P_bd_roll, deltaP_g] solveRolling(... currentTimeIdx, horizon, updatedWindFcst, updatedLoadFcst); % 执行第一个时间断面 executeDispatch(P_bc_roll(:,1), P_bd_roll(:,1), deltaP_g(:,1)); % 更新SOC传递值这是滚动衔接的关键 SOC_current updateSOC(SOC_current, P_bc_roll(:,1), P_bd_roll(:,1)); currentTimeIdx currentTimeIdx 1; end这里最值得注意的细节是日内层每次求解时储能SOC的初始值必须使用滚动更新的当前值而不是从日前计划里取。我最初复现时偷懒直接从日前SOC曲线上读取结果日内层和日前层的储能动作互相矛盾——日前层认为应该充电日内层认为储能电量早已用完。4.5 实时层的功率分配逻辑实时修正层的实现不需要求解优化问题更多是分配逻辑。当实际功率与日内计划出现偏差ΔP时先将偏差分解为高频分量和低频分量可以用一阶低通滤波或经验模态分解高频分量由储能承担低频分量由AGC机组承担。% 低通滤波一阶惯性环节时间常数Tf取60秒 deltaP_low (1 - alpha) * deltaP_low_prev alpha * deltaP_actual; deltaP_high deltaP_actual - deltaP_low; % 低频给火电AGC高频给储能 P_agc deltaP_low; P_bess_rt -deltaP_high; % 储能反向补偿 % 储能实时指令按群分配再按等SOC增量法下发到簇 bessGroupCmd distributeBySOC(P_bess_rt, groupSOC, groupAvaliablePower);实际工程里还要给储能下一级的BMS功率管理留出接口。当前很多主流PCS本身具备毫秒级功率响应能力在调度系统里给功率指令时建议叠加一个爬坡限制器比如每5秒不超过±1MW防止指令突变给电池簇带来电流冲击。5. 滚动调度中容易踩的坑求解失败、SOC漂移与不可行解5.1 求解慢的根因二进制变量爆炸与约束冗余复现过程中我踩得最深的坑是模型求解速度。第一版代码把所有机组组合约束包含最小启停时间都放进日内滚动层结果单次求解需要40秒以上而滚动周期只有15分钟计算时间占掉了接近5%如果电网规模再大一点直接NPhard死锁。我的解决办法是结构性的——把机组组合决策完全放在日前层日内滚动层只做经济调度ED。因为日内层的优化窗口只有4小时在这个时间尺度上机组启停状态本就不应该频繁变化。这样改动后日内层从MILP退化为LP问题求解时间从40秒降到0.3秒。优化层变量规模问题类型单次求解耗时CPLEX日前调度火电机组组合经济调度MILP510秒日内滚动仅经济调度LP0.20.5秒实时修正无优化纯分配—0.1秒5.2 SOC漂移问题为什么聚合SOC会逐渐失真做多时间尺度调度时SOC变量的传递链是日前层算出SOC计划曲线 → 日内层以实际SOC为初始值 → 实时层层更新。如果日内层执行了一个与日前计划不同的储能动作正常情况这很常见因为预测更新了那么日内层的SOC轨迹就会偏离日前计划。如果不把最新的实际SOC反馈给下一轮优化只需要运行几个小时调度模型对储能可用电量的估计就会严重失真。这个问题的根因在于储能是一个有记忆的能量系统不像发电机组的出力只是一个瞬时状态。我的处理办法是每轮滚动优化前从模拟的真实运行环境取回SOC实际值作为边界条件而不是从上一轮优化结果里查找。这在代码里只是一行赋值但在逻辑上要求你对数据流有全局概念——哪份SOC是计划值哪份是实际值必须分清楚。5.3 不可行解的处理优先级裁减策略优化模型在极端情况下会无解比如风电出力突降到接近零同时联络线功率已经达到上限火电爬坡能力不足储能SOC又已经耗尽这时候约束集就是空的。很多初学者遇到infeasible problem就懵了。常规做法是引入松弛变量对功率平衡约束做软化多考虑一个可中断负荷或弃负荷动作但要付出极高的惩罚系数。在实际代码中我会在功率平衡约束右侧加一个松弛项% lambda_pos 和 lambda_neg 是正的松弛变量目标函数中对应极大惩罚系数 Constraints [Constraints, ... sum(P_g) sum(P_bd) - sum(P_bc) P_wind P_pv P_curtail ... P_load P_trans lambda_pos - lambda_neg];这么做的好处是求解器永远不会返回无解而是给出一个代价最小的减负荷/弃负荷方案。从调度运营角度这是合理的——真实电网里也有拉闸限电或多个时段保供应优先的调度决策而不是让系统硬性崩溃。6. 仿真结果对比与策略有效性验证6.1 实验场景设置为验证策略有效性我用改进的IEEE 33节点系统作为测试算例。系统包含2台火电机组、1个20簇储能电站总容量10MW/40MWh、2个风电场和1个光伏电站负荷峰值约15MW。调度周期为一天时间精度为15分钟日内层。对比实验设计了三个方案方案A不考虑特性分布的等效储能模型单时间尺度优化基线方案B不考虑特性分布多时间尺度协调调度方案C考虑特性分布分群聚合多时间尺度协调调度本文方案。6.2 关键结果对比三个方案在典型冬日前一日的运行结果如下指标方案A方案B方案C弃风弃光电量MWh9.65.23.1储能越限次数420运行总成本万元72.868.363.9SOC标准差收敛趋势发散持平收敛方案C相对方案A弃风弃光电量降低了67.7%总运行成本降低了12.2%。更重要的是SOC标准差在日内呈现收敛趋势这意味着储能电站内部的短板效应在逐步缓解。6.3 实验结论的现实意义这个仿真实验说明的核心问题是多时间尺度框架帮助系统消化了预测不确定性节约了约6%的成本特性分布建模进一步把储能从不可靠的灵活资源变成可靠的灵活资源又省下了约4.5%的成本。在真实工程里这两个收益是叠加的。储能电站接入电网调度时调度中心最担心的就是你说能出力但实际到不了这个功率。特性分布建模从机制上减少了这种不确定性。这也是为什么现在很多地方对储能并网提出一次调频响应能力测试和可用容量评估等要求——本质上都是要求储能运营方把自己内部的特性分布情况摸清楚。7. 给复现者的几个实操建议最后分享几个我做这个项目过程中的体会按优先级排序第一YalmipCPLEX是目前做这类问题最稳的组合。Matlab自带的intlinprog在变量超过2000个后求解速度明显下降而且对约束病态条件的容忍度不如商用求解器。没有CPLEX许可证的可以先用开源求解器SCIP做替代验证Yalmip支持确认逻辑正确后换CPLEX跑大规模算例。第二数据组织方式决定开发效率。我强烈建议把所有原始数据风光出力序列、负荷曲线、机组参数、储能簇参数集中管理建立一个data文件夹用结构体数组打包每类数据一个struct。代码主体不允许出现硬编码数值所有参数都从结构体读取。这样做的好处是换算例时只需要替换数据文件不需要改任何模型代码。第三建议在仿真主循环里加入日志打印功能。每个滚动周期的关键状态时间戳、SOC均值、储能功率指令、是否发生约束越限输出到命令行或日志文件。调试多时间尺度问题时没有日志几乎不可能定位是哪个环节导致SOC轨迹异常。这个项目后续可以扩展的方向不少比如把特性分布建模从聚类分群升级为基于运行数据的动态辨识或者引入深度强化学习做实时层的功率分配决策。不过那些是更远的话题了——先把本文这套框架跑通你就能在这个方向上站住脚。
返回列表