
风电和光伏出力看天吃饭风大的时候太阳不一定好白天光照强的时候风经常很小反正跟用户用电曲线对不上。新能源占比一旦上来调度问题立刻变得具体大发时段用不完只能弃掉少发时段又得靠火电或购电硬顶。我这两年一直在做风电、光伏与储能含电池和废弃矿井小型抽水蓄能互补调度运行研究用Matlab搭了一套联合调度模型把电池的快速响应能力和废弃矿井抽蓄的大容量结合起来做日前调度结果比单一储能方案好不少。这篇文章把整个研究过程整理出来——从风光出力建模、两类储能数学模型的差异到优化调度模型怎么建、粒子群算法怎么调再到案例仿真和踩过的坑希望能给正在做新能源调度或储能研究的同行一些参考。说明文中涉及的参数、数据和结论来自我个人的研究项目属于工程实践层面的经验总结。不同地区的风资源和光照资源差异很大具体项目要根据自己的实测数据重新标定参数不能直接照搬。1. 出力曲线拟合与场景削减风光模型不是简单抄公式1.1 风电出力风速威布尔分布与功率曲线的配合风电建模第一步是把风资源描述清楚。实际项目中我不直接用历史风速序列做确定性场景而是先拟合风速的概率分布再生成足够多的代表性场景。风速通常用威布尔分布描述f(v) (k/c) * (v/c)^(k-1) * e^(-(v/c)^k)k是形状参数c是尺度参数。用Matlab的wblfit函数对历史风速数据做极大似然估计直接得到k和c。我这边用了某风电场一年的实测小时风速数据拟合出来的k2.1c7.8平均风速约6.9m/s属于典型的低风速风电场特征。有了风速分布还得有风速到出力的转换关系核心是功率曲线。理想化的功率曲线是分段函数低于切入风速不发电切入风速和额定风速之间出力随风速近似线性增长额定风速和切出风速之间保持额定功率超过切出风速停机保护。但实际风机的功率曲线在额定点附近有一个平滑过渡段直接用理想分段函数会导致出力在额定点附近出现突变优化求解时容易引发数值震荡。我在代码里用三阶样条插值拟合厂家提供的功率曲线散点效果比硬分段好得多。这里有个容易忽略的细节风机功率曲线通常是在标准空气密度下标定的高原地区或者冬夏温差大的地方空气密度变化会影响实际出力建模时最好加一个空气密度修正系数。我第一次仿真时没注意这个结果冬季场景的出力整体偏低了差不多6%。1.2 光伏出力辐照度分布与温度修正光伏建模的核心是辐照度和温度。短时间的辐照度波动可以近似用Beta分布描述但日前调度场景下我倾向于直接利用历史辐照度数据做场景削减而不是先拟合分布再抽样。原因是日前调度关注的是典型日的辐照度形态也就是一天内的形状而不是统计分布本身。出力计算用工程上常见的简化公式P_pv eta * S * I * (1 - beta * (T - T_ref))eta是光伏板转换效率S是光伏阵列总面积I是辐照强度beta是温度系数一般取0.004~0.005每摄氏度T_ref是标准测试温度25度。T是光伏板表面温度可以近似用环境温度加辐照度影响来估算。这块的实际难点在数据质量。辐照度传感器偶尔会出现阴影遮挡、积灰导致的异常低值不预处理直接进模型优化结果会非常离谱。我后来在代码里加了一个滑动窗口异常检测辐照度超过相邻时刻均值3倍标准差就标记为异常并做线性插值替换。数据预处理这一步看似简单但对最终调度结果的影响比很多人在建模上的精细调整都大。1.3 场景削减从8760小时到12个典型日全年8760小时的时序数据直接丢进优化模型求解规模非常大尤其是储能状态变量之间存在时间耦合。我采用的方案是K-medoids聚类做场景削减聚类特征选取每天的24小时出力曲线形态而不是简单的日均值。这样能把一年的数据压缩成12个典型日每月一个每个典型日附带一个权重系数表示对应月份的日数占比。聚类有几个细节值得注意。一是把风电和光伏的日曲线合并成一个48维的特征向量24小时风加24小时光再归一化到0~1否则光伏和风电的量纲差异会导致聚类结果偏向数值大的那一类。二是K-medoids相比K-means对异常日的鲁棒性更好因为聚类中心是实际数据点而不是均值不会被少数极端天气日拉偏。三是聚类完成后要检查每个聚类的出力形态是否真的有区分度。我调了一次之后发现风大的日子和光强的日子还是混在一起改成48维特征并增加归一化处理后就好了。2. 电池储能与废弃矿井抽水蓄能的数学建模差异2.1 电池储能SOC递推与充放电不对称效率电池储能建模的核心是SOC荷电状态的递推关系。设电池在t时刻的SOC为S_t充放电功率分别为P_ch和P_dis那么S_{t1} S_t eta_ch * P_ch * dt / E - P_dis * dt / (eta_dis * E)E是电池容量eta_ch和eta_dis分别是充电和放电效率dt是时间步长。这里充电和放电效率不相等一般磷酸铁锂电池的充放电效率在92%~96%之间但实际建模时要注意效率点依赖工作电流大倍率充电时的效率比标称值低一些。在优化模型里出于保守考虑我把充放电效率分别取0.93和0.94并且把SOC的运行范围限制在20%~90%避免深充深放损伤电池寿命也避免在SOC边界附近效率剧烈变化导致模型失真。电池响应速度是毫秒级的这个特性在调度模型里其实很难体现因为日前调度的最小时间分辨率一般是15分钟或1小时。我处理的办法是把电池的爬坡约束放宽到几乎不起作用的程度但在目标函数里加入充放电次数和SOC波动惩罚防止优化器把电池当成无限容量的垃圾桶频繁地充了又放、放了又充。2.2 废弃矿井抽水蓄能库容、水头与效率曲线都要进模型废弃矿井改造成小型抽水蓄能电站是近年来比较受关注的方向。它的原理和常规抽水蓄能一样用电低谷时把水从下水库抽到上水库蓄能用电高峰时放水发电。不同的是常规抽蓄靠建设大型水库废弃矿井方案利用的是现成的矿井巷道和采空区把浅层巷道改造成上水库深层采空区作为下水库。这个方案的数学建模和常规抽蓄相比有几个关键差异。第一库容小矿井巷道能利用的储水空间有限蓄能容量通常只有几万千瓦时到几十万千瓦时跟大型抽蓄的百万千瓦时量级没法比但在分布式新能源配套的尺度下恰好够用。第二水头低且有变化废弃矿井的垂直落差一般在几十米到两百米而且随着抽水和发电的进行上下水库水位会明显变化导致有效水头跟着变化不能像常规抽蓄那样假设水头恒定。第三效率偏低由于水头低、水头损失占比大小型抽蓄的综合效率通常在60%~75%之间。建模时我采用了简化的变水头模型。设发电状态下的出力P_gen与水流流量Q和水头H的关系近似为P_gen rho * g * Q * H * eta_trho是水的密度g是重力加速度eta_t是水轮机效率。抽水状态则反过来P_pump rho * g * Q * H / eta_peta_p是水泵效率。水位和库容的关系通过库容曲线关联这里用简化的线性关系拟合矿井实测数据。需要说明的是矿井巷道的水位-库容关系实际上是非线性的因为巷道断面不是规则的圆柱形实测数据足够的话最好用分段线性函数来近似。还要处理运行状态约束。抽水蓄能机组有发电、抽水、停机三种状态发电和抽水不能同时进行这需要引入二进制变量。另外机组不能频繁启停我设置了最小运行时间和最小停机时间约束避免优化结果中出现状态的频繁跳变——这在物理上不现实也容易损坏设备。由于我用粒子群算法求解二进制变量处理起来比较麻烦我采用了连续化松弛加罚函数的方式用一个S型函数近似状态的切换把发电和抽水的互斥性作为罚项加进目标函数。2.3 两类储能的互补逻辑功率型与能量型的配合为什么要同时配置电池和废弃矿井抽蓄从调度运行角度看两类储能的特性差异非常明显。电池的功率密度高响应速度快但能量容量有限持续放电时间一般只有1~2小时废弃矿井抽蓄的能量容量大持续放电时间可以达到6~8小时但启动和爬坡相对慢从停机到满发一般需要几分钟到十几分钟。在调度模型中体现这种互补性最直接的方法是时间尺度上的分工电池负责平抑短时功率波动和跟踪负荷的快速变化抽蓄负责削峰填谷和跨时段的能量搬移。在目标函数和约束设计上我给电池一个较高的充放电次数惩罚让它只在真正需要快速调节的时刻动作给抽蓄设置爬坡速率限制让它自然承担起大时间尺度的能量调节任务。实际仿真中有个很有意思的规律当新能源渗透率较低时单配电池的效果和双储能联合方案差异不大但新能源渗透率超过40%以后电池的容量瓶颈开始凸显仅靠电池无法实现跨时段的能量搬移而抽蓄的容量优势正好补上这个缺口。这也是我坚持在模型里同时纳入两种储能的原因。3. 互补调度优化模型与求解方法选型3.1 目标函数设计经济性、消纳率与储能损耗的权衡调度模型的目标函数采用最小化综合运行成本的形式包含三个部分。第一是系统运行维护成本主要是风电场、光伏电站的运维成本加上储能系统充放电带来的磨损成本。第二是弃风弃光惩罚成本新能源出力超出系统可接纳范围被迫切掉时按惩罚系数计入成本这个系数设得越高优化器越倾向于让储能多充电来消纳新能源。第三是购电成本如果系统不能完全自平衡需要从上级电网购电或者向电网售电这部分也计入目标函数。目标函数形式为min C sum_t ( C_om C_curtail C_grid )其中 C_curtail lambda_c * (P_wind_cur P_pv_cur)lambda_c取运维成本的5~8倍比较合适。我调试中发现这个惩罚系数既能保证消纳率大幅提升又不会让储能超频动作、牺牲设备寿命。设得过低弃风弃光得不到有效遏制设得过高储能长时间满充满放优化结果看起来很漂亮实际运营中设备会提前报废。平抑功率波动这个需求我没有直接放进目标函数因为把波动方差加进目标函数会导致量纲混乱权重很难标定。我的做法是在约束里对联络线功率变化率做限制间接平抑系统净功率波动效果更好也更容易处理。3.2 约束条件功率平衡、SOC递推与设备运行边界约束条件的设计直接决定模型是否物理可行我把约束分成三类。一是等式约束包括每个时刻的系统功率平衡方程风电出力加光伏出力加电池放电功率加抽蓄发电功率加购电功率等于负荷需求加电池充电功率加抽水功率加售电功率加弃电功率。这个等式是模型的核心任何调度方案都必须满足。二是不等式约束包括各设备出力的上下限、电池SOC的范围、抽蓄上下水库的水位范围、联络线传输功率上限以及爬坡约束和最小运行时间约束。三是逻辑约束包括抽蓄机组的状态互斥发电、抽水、停机只能选一个、电池不能同时充电和放电。这些约束在处理时最麻烦也是容易出错的地方。特别注意一个细节在功率平衡方程里电池的充电和放电应该设为两个独立的非负变量而不是用一个可正可负的单一变量表示。很多初学者会图省事用带符号的P_bat统一表示充放电这在目标函数和约束里看起来简洁但到了启发式算法求解环节会导致可行域出现大量冗余空间收敛极慢。我把P_ch和P_dis设为两个非负变量再加上互斥约束效果好了很多。3.3 求解方法为什么最终选了粒子群而不是线性规划模型建好之后面临求解方法的选择。如果全部线性化可以用Yalmip加Cplex或Gurobi求解混合整数线性规划全局最优解有保证速度也快。但这个模型里有一些非线性环节——抽蓄的变水头效率曲线、电池效率随倍率的变化等线性化需要引入大量辅助变量和分段线性约束模型规模迅速膨胀而且分段线性近似的精度不好控制。我最终选择了粒子群算法PSO作为主求解器配合罚函数法处理约束。这个选择的代价是没有全局最优的保证但换来的是建模灵活性和实现速度。对于这类日前调度研究得到一个质量不错的次优解配合仿真结果分析在研究阶段完全可以接受。如果后续要做工程落地再把关键非线性环节精细化线性化切换成MILP求解器也不迟。粒子群求解这个模型的整体流程初始化粒子种群每个粒子代表一组完整的调度决策变量序列24小时的电池充放电功率、抽蓄发电和抽水功率、对应的状态变量计算每个粒子的适应度也就是目标函数值加上约束违反惩罚更新个体最优和全局最优按速度更新公式迭代直到满足收敛条件。3.4 粒子编码维度压缩是收敛速度的关键粒子编码是启发式算法应用中最容易被低估的环节。在这个模型里一个粒子代表整个24小时调度方案的完整编码电池充电功率24个值、电池放电功率24个值、抽蓄发电功率24个值、抽水功率24个值以及抽蓄的状态变量。如果再加上风电和光伏的出力变量维度会非常高。高维粒子直接导致粒子群收敛速度急剧下降。我的处理策略是把风电和光伏的出力从决策变量中剔除——它们属于输入场景不是决策变量。真正的决策变量只有电池充放电功率、抽蓄发电和抽水功率的控制系数以及对应的状态变量。这样一来粒子维度大幅下降收敛速度提升明显。另外我用了双层编码的思路第一层是连续变量表示各类储能的有功功率设定值第二层是逻辑变量表示抽蓄机组的运行状态。罚函数法处理约束时把状态互斥、SOC边界、水位上下限这些约束作为惩罚项加入适应度函数。罚函数系数需要动态调整前期用较小的值让粒子充分探索后期收敛时再加大惩罚权重避免粒子在不可行域扎堆。4. 粒子群算法调参与核心代码实现细节4.1 PSO核心代码框架下面这段代码是粒子群求解的核心框架我做了删减保留关键逻辑。% 粒子群优化主循环 % nVar: 决策变量维度, nPop: 种群规模, MaxIt: 最大迭代次数 for it 1:MaxIt for i 1:nPop % 计算粒子i的适应度, 包含目标函数值和罚函数项 [fval, violation] FitnessFunction(pop(i).Position, sysData); pop(i).Cost fval penaltyCoeff * violation; % 更新个体最优 if pop(i).Cost pop(i).BestCost pop(i).BestCost pop(i).Cost; pop(i).BestPosition pop(i).Position; end % 更新全局最优 if pop(i).BestCost GlobalBestCost GlobalBestCost pop(i).BestCost; GlobalBestPosition pop(i).BestPosition; end end % 速度与位置更新 % 惯性权重线性递减: 从0.9降到0.4 w 0.9 - (0.9 - 0.4) * it / MaxIt; for i 1:nPop r1 rand(nVar, 1); r2 rand(nVar, 1); pop(i).Velocity w * pop(i).Velocity ... c1 * r1 .* (pop(i).BestPosition - pop(i).Position) ... c2 * r2 .* (GlobalBestPosition - pop(i).Position); pop(i).Position pop(i).Position pop(i).Velocity; % 边界处理: 越界粒子拉回边界 pop(i).Position max(min(pop(i).Position, ub), lb); end end这个框架不复杂但有几个细节需要专门说明。首先是适应度函数的设计拆成两部分一部分是带符号的目标函数值另一部分是约束违反量的绝对值求和。罚函数系数不是固定的迭代前50%用较小的值让粒子可以充分探索可行域之外的区域后50%逐步加大惩罚把粒子拉回可行域。这样比全程固定惩罚系数更容易找到高质量解。其次是粒子位置的边界处理。我试过直接截断、反射反弹、随机重置三种方式实测下来直接截断配合边界处的速度衰减效果最好。如果粒子在边界附近反复反弹容易在可行域边缘形成振荡白白浪费迭代次数。4.2 参数整定记录惯性权重、学习因子与种群规模粒子群算法的参数整定我的经验值是种群规模取80~120最大迭代次数取300~500。种群规模太小容易早熟收敛太大则单次迭代计算量太大。在PSO的几个核心参数里惯性权重w是最重要的它控制着全局探索能力和局部开发能力之间的平衡。惯性权重我采用线性递减策略从0.9线性降到0.4。初始阶段w较大粒子全局探索能力强能在整个搜索空间里快速移动发现可能有希望的区域后期w变小粒子主要做局部精细搜索逐渐收敛到最优解附近。c1和c2分别是自我认知系数和社会认知系数都取2.0这是工程实践里的常用取值。我还做过一组对比实验固定惯性权重0.6的PSO收敛速度明显比线性递减策略慢最终解的质量差5%左右。迭代次数超过300次后再增加迭代次数解的改进非常有限平均不到1%所以300次已经是一个投入产出比很高的设定。4.3 约束处理要分清硬约束和软约束适应度函数是求解过程中最容易出错的地方。我写第一版时就遇到一个典型问题SOC边界约束的罚函数权重设得太大导致所有粒子都被拉向零充放电的保守解优化结果等于没优化。后来我把约束分成硬约束和软约束两类。硬约束包括功率平衡、设备出力上下界这些通过粒子编码和变量取值范围直接保证根本不用进罚函数。软约束包括SOC上下限、抽蓄库容限制、状态互斥这些通过罚函数处理。软约束的罚函数系数设置原则是让不可行解的成本显著高于可行解但不至于完全压过目标函数的梯度信息。实测下来罚函数系数取目标函数典型值的10倍左右比较合适。判断罚函数系数是否合理有个技巧观察群体中不可行粒子的比例。迭代初期如果超过80%的粒子不可行说明罚函数太小搜索大部分时间浪费在无效区域如果初始种群生成时就全部可行说明罚函数设置过于保守限制了搜索空间。通过这个比例反向校准罚函数系数比凭空调参要快得多。5. 案例仿真多储能联合调度的实际效果5.1 仿真场景与参数设置仿真基于一个典型的区域微电网场景装机容量200MW的风电场150MW的光伏电站负荷峰值220MW。电池储能容量为50MW/200MWh即功率50MW、可连续放电4小时。废弃矿井小型抽水蓄能最大发电功率40MW最大抽水功率45MW上水库有效库容对应蓄能容量约300MWh综合效率取0.68。时间尺度选用1小时分辨率调度周期24小时日前调度模式。风电和光伏出力场景从全年数据聚类出的12个典型日中选取这里取夜间风大、白天光照强的典型日作为分析案例因为这种风光互补形态最贴合实际调度需求。5.2 三种方案对比结果下表是无储能、仅电池储能、电池加废弃矿井抽蓄三种配置下的调度结果。方案新能源上网电量/MWh弃风弃光率/%日综合运行成本/万元联络线功率峰谷差/MW无储能203512.658.6132仅电池储能22234.552.196电池废弃矿井抽蓄22792.148.379日综合运行成本包含了运维成本、弃风弃光惩罚成本和购电成本。从仿真结果看双储能联合配置的优势非常明显弃风弃光率从无储能时的12.6%降到2.1%日综合运行成本下降了约17.6%联络线功率峰谷差从132MW缩小到79MW。这说明引入储能不仅提升了新能源消纳能力还显著改善了系统的功率平衡特性。5.3 结果分析互补调度到底补在哪里仔细看调度曲线两类储能的分工非常清晰。在午间光伏大发时段电池主要承担短时的功率接纳任务充电功率在2~3小时内升到满功率附近把光伏骤增的出力吸收掉抽蓄则从午间就启动抽水慢慢把能量搬到晚上负荷高峰期再放出来。到了傍晚负荷高峰时段电池率先放电响应快、爬坡快能顶住负荷上升的初期压力随后抽蓄机组接力持续放出大功率电量支撑晚高峰一直持续到夜里负荷下降。这种电池打前锋、抽蓄当后卫的配合模式恰好兼顾了响应速度和能量容量两个维度。另一个值得关注的指标是电池的充放电次数。双储能方案里电池的充放电次数比单电池方案少了差不多三分之一。原因是抽蓄承担了大部分的能量搬移任务电池只需要做快速调节SOC不再频繁大幅波动这对延长电池寿命有明显的正面意义。折算成等效循环次数双储能方案下电池的循环寿命消耗显著下降全生命周期经济性更好。5.4 储能运行轨迹的微观观察观察电池SOC曲线和抽蓄水库水位的日内变化轨迹能进一步印证两类储能的角色差异。电池SOC在20%~70%之间频繁波动一天内出现多次小幅充放循环正好对应负荷和新能源出力的快速变化抽蓄水位则是缓慢的锯齿形变化——白天抽水蓄能水位上升傍晚发电水位下降单次周期长达6~8小时。这种运行轨迹的差异意味着如果只用单一储能要么是电池频繁深度充放、寿命损耗加大要么是抽蓄响应太慢、无法处理分钟级波动。联合调度让两类储能各司其职既延长了电池寿命又充分发挥了抽蓄的容量优势。这个结论从微观轨迹上得到了直观印证。6. 建模与编码过程中的坑和经验总结6.1 非凸状态约束的处理教训废弃矿井抽蓄的发电和抽水状态切换是一个非凸问题处理起来特别容易出错。我第一版模型里把这个状态切换处理成简单的互斥约束发电功率乘以抽水功率等于零。看起来合理但粒子群求解时这个等式约束让适应度曲面出现大片不可行平台粒子一旦落进去就难以爬出来收敛效果很差。后来改用S型函数平滑近似状态变量用连续值表示接近1表示发电、接近0表示抽水、中间值被罚函数惩罚。这样既保证了状态的互斥性又保留了适应度曲面的梯度信息粒子可以沿着梯度方向持续改进。最终解里状态变量虽然不是严格的0或1但通过阈值判断转成离散状态后物理上是可行的。6.2 数据预处理对结果的影响远超预期这是我最深刻的一个教训。有一段时间仿真结果特别反常弃风率在天气平稳的典型日反而高于天气恶劣的典型日。排查了好久才发现是风电功率曲线拟合时用的风速数据里混入了异常值来自测风塔在结冰期的失效记录导致拟合出的功率曲线整体偏平弱风段的出力估得偏高、强风段又估得偏低。从那以后我把数据预处理写成了独立模块包含三步剔除风速超过物理上限和功率超过风机额定值的异常点对测风塔长时间静默段做插值填补按月分别拟合威布尔参数因为不同月份的风资源特征差异确实明显。这个模块现在成了所有新能源项目里复用的标准组件。6.3 初始解的生成策略启发式加随机混合粒子群的初始种群对收敛速度和最终解质量影响非常大。纯随机初始化虽然简单但会产生大量物理上不合理的解比如电池在SOC很低的情况下仍然放电、抽蓄在库容接近上限时仍继续抽水。这些解最终会被罚函数淘汰但会拖累前几十次迭代的效率。我的做法是采用启发式初始化先跑一个不考虑储能的经济调度得到一个基础解再在这个解附近加上随机扰动生成一半的初始粒子剩下的一半用纯随机方式生成保证种群的多样性。这种部分启发式加部分随机的初始化策略收敛速度提升了差不多一半最终解的质量也更稳定。6.4 面向对象的Matlab代码结构建议这个项目的数据结构比较复杂风电场、光伏电站、电池储能、抽蓄电站、负荷曲线、电网联络线每类对象的参数和状态变量都不一样。我最初用一堆结构体和全局变量组织代码到四千行左右就非常难维护改一个参数要去好几个函数里同步修改。后来我重构成了面向对象的架构用classdef定义了风场类、光伏类、电池类、抽蓄类、调度方案类。每类设备自己封装了参数、状态变量和对应的约束检查方法调度主程序只需要调用各个类的方法。重构之后代码的可读性和复用性提升了一个量级换数据集或改场景配置只需要修改对象的构造参数主程序基本不用动。从整个项目做下来的体会看调度研究的核心工作一半在物理建模的准确性另一半在求解框架的工程实现。物理建模做扎实了场景数据靠谱、约束条件完整优化算法的压力就会小很多反过来如果模型粗糙或者数据有坑再精巧的求解器也救不回来。粒子群这类启发式算法虽然不能保证全局最优但只要编码设计合理、参数整定到位在日前调度这个应用尺度上已经完全够用。后面如果有时间我打算把这个模型改成滚动时域预测控制的形式把日前计划和日内修正串起来让调度方案更能适应实际运行中的不确定性。