
风电光伏配储能做互补调度听起来像是个标准课题但真正把模型跑起来、把代码实现出来的时候坑远比想象中多。我最近刚完整做完了一个“风电、光伏与储能含电池和废弃矿井小型抽水蓄能互补调度运行研究”的Python实现版本从数学建模到代码落地再到结果分析整整折腾了几周。这篇就当作一个详细的项目复盘把我踩过的坑、关键参数怎么定、代码怎么组织一次性讲透。这个项目主要研究的是什么简单说就是在一个风、光、储互补的电力系统里怎么安排风电场、光伏电站、磷酸铁锂电池储能系统以及一个利用废弃矿井巷道改造的小型抽水蓄能电站让它们在不同时间尺度上配合出力实现“弃风弃光最少、运行成本最低、储能寿命消耗最合理”这几个目标。适合谁来看如果你是电力系统方向的学生正在为毕业设计或小论文发愁或者你在新能源场站做运行优化想把理论模型转成可复现的Python代码又或者你只是想搞明白“抽水蓄能和电池储能到底怎么分工”这件事——这篇文章都能给你一个可以直接抄作业的答案。1. 项目背景与核心思路拆解1.1 为什么风电光伏必须配储能风电和光伏的出力受天气影响极大风速快的时候风机满发没风的时候出力可能掉到额定功率的10%以下光伏更直接白天有日照才能发电晚上出力为零。这种波动性和间歇性给电网调度带来了一个很现实的问题新能源大发的时候电网消纳不了只能被迫弃风弃光新能源出力小的时候又需要常规电源顶上甚至可能不够用。储能就是在这个背景下被推到台前的。我一开始做这个项目的时候只有一个很朴素的想法给风电场和光伏电站加上一块大电池白天光伏多充一点晚上放出来用不就解决了吗但真正建模之后发现事情没有这么简单。电池储能的容量有限而且用得太狠会加速衰减它的响应速度快但持续放电能力受容量约束另外一个关键问题是不同时间尺度上的供需不平衡单靠电池很难全部解决。这时候就需要一种“大容量、长时间尺度”的储能类型来搭配。1.2 电池和废弃矿井抽蓄的分工逻辑这个项目很有意思的一个设计是把常规的磷酸铁锂电池储能和废弃矿井小型抽水蓄能放进了同一个调度框架里。很多人对抽水蓄能的印象还停留在“需要修上下两个水库、大规模投资建设”那种国家级工程上但这里做的是一种分布式的小型化方案利用废弃煤矿已经存在的巷道和竖井改造出上库和下库不需要重新征地也不需要大规模开挖。在调度逻辑上电池和抽蓄的定位完全不同。电池储能响应速度是毫秒到分钟级适合处理光伏云层遮挡、风速突然变化这类短时间尺度的出力波动抽蓄虽然响应也有几分钟但它更擅长做“电量搬运”——光伏中午大发的时候把电用来抽水到了晚高峰再放水发电一次循环可以持续4到6个小时单日调峰能力远超同容量的电池。我在模型里把这两类储能的运行窗口做了时间解耦电池以1小时为分辨率的短周期充电放电为主抽蓄电站以日内的峰谷时段转移为主。这样设计的好处是两个储能不能抢同一块电量而是各管一段最终的互补效果会比单种储能好很多。1.3 调度运行研究的根本难题把风、光、储放在一个系统里建模最核心的难题不是约束条件的多少而是不确定性怎么处理。风电功率预测不可能100%准确光伏更是受云量变化影响。如果调度模型里用的是预测值的“点估计”那么实际运行中一旦预测偏差大整个调度方案就会失效。在这个项目里我采用的是确定性等价加鲁棒修正的处理方式先用一组典型场景比如晴日、多云、阴雨、大风等生成基准调度计划再在约束里加入旋转备用容量、储能SOC安全边界等“缓冲条款”让生成的计划在面对实际扰动时有一定的鲁棒性。这种做法的运算量远小于完全的两阶段随机优化但对工程场景来说已经足够实用。2. 系统建模方法与关键技术细节2.1 风电光伏出力模型与场景生成风电出力模型我采用的是“风速→功率”的两段式映射。先用威布尔分布拟合当地的风速统计数据生成一组风速时间序列然后通过风力发电机的标准功率曲线切入风速、额定风速、切出风速把风速折算成出力。功率曲线的计算很简单切入风速以下出力为0在切入和额定之间按三次方关系增长额定以上锁定为额定功率超过切出风速则切机保护。光伏出力相对更“规整”一些我采用的是基于太阳辐照度、环境温度以及光伏板标称效率的计算模型。标准公式是光伏出力 光伏板额定容量 × 辐照度折算系数 × 温度修正系数。辐照度按日地关系计算理论值再叠加上随机波动模拟云层影响温度修正则是为了避免光伏板在夏天高温下效率下降导致的出力失真。这两个模型的输出都是24小时的日前出力序列时间分辨率为1小时。这一点必须提前说明整个调度模型的时间尺度是日前调度day-ahead scheduling分辨率1小时不考虑超短期AGC和秒级响应。如果想做多时间尺度协同那需要在现有框架上再叠加一层日内滚动优化工作量会大很多。2.2 电池储能建模与寿命约束电池储能我选用的是工程中常用的“能量型”磷酸铁锂电池模型不考虑详细的电化学特性而是在外特性层面建了三个维度容量、功率、SOC状态。电池的SOC荷电状态是整个调度的关键变量我给它设置的安全运行区间是0.1到0.9。为什么不设成0到1因为锂离子电池在过充过放边缘时电压极化严重内阻升高还会加速析锂和活性物质损失寿命衰减远比在中间区间循环要快得多。模型里还必须考虑充放电效率我取的充电效率是92%放电效率是95%单次循环的往返效率约87%这个是磷酸铁锂电池在0.5C倍率下的典型实测值。寿命衰减这一块很多初学建模的人容易忽略。我在目标函数里加入了电池等效循环折旧成本每次充放电循环都会折算成寿命损耗费用等效循环寿命按6000次计算。这样模型在优化的时候自己会有“舍不得乱用电池”的倾向把充放电时段尽量安排在峰谷差大的时刻而不是随意充放电。不加这个约束的时候求解器会给出一个看似特别优秀但实际会把电池一个月干报废的方案这一点值得特别注意。2.3 废弃矿井小型抽水蓄能模型废弃矿井抽蓄的建模是这次项目里最花精力的一环。普通抽水蓄能电站的建模核心是上下库水量平衡和水头-功率耦合关系废弃矿井的特别之处在于它没有天然的地形落差优势只能依靠矿井竖井和巷道的既有结构上库设在地面下库利用井下老巷道落差一般在30到80米属于典型的“低水头、大流量、小容量”类型。在模型里我建立了这样几个核心约束首先是发电功率与水头的关系约束。低水头机组的出力上限不是恒定值而是随水头变化的。我简化成线性函数发电时段水头高可发功率大水头低可发功率减小。这样做比直接设定恒定额定功率更贴近实际。其次是水量平衡约束。上库的变化水量 抽水水量 - 发电用水量 - 蒸发渗漏损失。抽蓄电站在抽水工况和发电工况之间存在水量损失和能量转换损失整体循环效率如果按实际项目经验取大概在65%到70%之间。我在模型里设置的是68%。就是说抽水消耗1千瓦时电最终放出来最多0.68千瓦时剩下的变成了热损耗和水头损失。很多人在论文里闭着眼睛写85%的效率实际工程中根本达不到。还有一个容易被忽略的点是机组启停状态约束。抽蓄机组不能像电池一样说变就变从抽水转发电之间需要时间切换和状态准备。模型里我设置了最小运行时间和状态转换逻辑避免优化结果出现某一个小时内既抽水又发电这种物理不可能的运行方式。2.4 系统互补策略与目标函数设计整个系统模型的决策变量有两组第一组是各时段风电场、光伏电站、电池、抽蓄的出力值第二组是电池和抽蓄的运行状态充电/放电或抽水/发电。在Python里我用的是混合整数线性规划MILP框架来表达。目标函数包含四个部分系统总运行成本最小、新能源弃电量最小、储能寿命损耗最小、购电成本最小。这四块权重不是拍脑袋定的而是通过层次分析法加场景试算确定的。初始权重下优化结果会优先保证不弃新能源然后考虑运行经济性最后才考虑储能寿命。如果反过来先考虑储能寿命结果就会倾向于少用储能反而导致弃电率上升。约束条件这块除了上面讲到的各设备模型约束外还有系统的功率平衡约束各时段风、光、储、抽蓄的实际出力之和必须等于系统负荷需求不平衡的差额由外部电网交换电量补足。外部电网交互是为了让系统模型具备“买电卖电”的弹性避免系统在极端场景下无解。3. Python代码实现与实操过程3.1 数据准备与预处理代码的第一步是把所有输入数据整理成标准格式。这一步看似简单却是最容易出问题的地方。我全部使用了CSV文件来管理输入数据包括风电场24小时预测出力曲线、光伏24小时预测出力曲线、系统24小时负荷曲线以及电池和抽蓄的参数表。数据预处理里最容易踩的坑是单位统一。风电出力可能是兆瓦MW光伏用的是千瓦kW负荷用的又是兆瓦时MWh如果不在一开始全部统一成一套单位后面算功率平衡的时候差之毫厘谬以千里。我最终统一使用的是以MW为功率单位、MWh为能量单位、小时为时间单位。代码里专门加了一个单位转换函数块在数据读入后立即转换并校验数据范围。还要做的是数据平滑和异常值剔除。实测数据经常会出现个别时刻的毛刺比如一个0到2之间的辐照度系数突然跳到15这是传感器故障或者通讯错误导致的。我在代码里设置了一个简单的滑动窗口异常检测如果某个点的数值偏离前后两个点的均值超过三倍标准差就替换为前后均值。这样处理之后模型求解的数值稳定性会好很多。3.2 核心建模与求解器对比建模求解部分我对比了两种方案一种是直接用Pyomo抽象建模再用开源求解器求解另一种是手动构建系数矩阵调用商业求解器求解。最终我选的是Pyomo Gurobi的组合因为Pyomo的约束表达式写起来直观Gurobi求解MILP的速度和稳定性在同类求解器里是最好的尤其对带整数变量的储能启停问题有压倒性优势。Pyomo负责模型框架建立、约束表达、求解器接口Gurobi负责实际求解MILP问题如果没有商业授权可以用开源的GLPK或CBC替代但求解速度会慢一截尤其是状态变量的整数性约束多的时候核心代码里有一个函数专门处理抽蓄机组的运行状态约束这里最关键的操作是引入了一个二元变量0或1表示抽蓄机组是在发电工况、抽水工况还是停机状态。这个二元变量在MILP求解时会被分支定界算法处理所以模型整体求解时间会比纯线性规划LP要长一些。我实测下来24个时段的模型规模在Gurobi下大约5到20秒可以找到全局最优解GLPK则需要几分钟差距还是很明显的。这里分享一个建模技巧把目标函数里的绝对值项和max/min项先做线性化。比如要表达“弃电量最小”直接写“目标函数里减去新能源出力与消纳量之差的最小化”这是一个非线性项。我的做法是引入一个新的非负辅助变量加上上下界约束把差值表达出来变成线性不等式。这样整个模型才是标准MILP能够被求解器高效处理。如果直接写非线性项进约束求解器要么报错要么陷入局部最优。3.3 调度结果可视化和关键指标检验优化的结果不能只是一堆数字必须可视化才能看出趋势。我使用了Matplotlib绘制了三张核心图表第一张是24小时系统的功率平衡图把风、光、负荷、储能的出力堆叠在一起第二张是电池SOC和抽蓄上库水位的联合变化图能直观看出两类储能的互补节奏第三张是不弃风弃光率、系统运行成本、储能循环次数等关键指标的比较柱状图。功率平衡图是最容易出“结果对不上”的地方。我遇到过一种情况图中显示某一时刻的风电出力加光伏出力已经超过了负荷需求可储能和抽蓄并没有在充电也就是说系统“多”出来的电找不到去处。排查后发现这是因为外部电网交互的约束设置得不严求解器选择了向电网卖掉多余电量这本身不违反模型约束但从系统消纳的角度来说卖掉新能源电并不等于弃电指标统计口径错了。修正方法是把“弃电”定义为新能源出力超过负荷、储能充电功率和可外送功率三者之和的部分这样才符合实际工程中弃电的定义。关键指标检验方面我专门写了一段代码在每次求解完成后自动计算五个指标新能源消纳率、系统运行成本、电池等效循环次数、抽蓄日循环次数、储能综合利用率。这套指标可以横向对比不同参数配置下的调度效果也可以直接复制到任何相似项目里使用。4. 实测结果分析与调度效果评估4.1 无储能、单电池、电池抽蓄三组对比为了验证互补调度的实际效果我设计了三组仿真实验第一组是无储能状态下的新能源直供系统第二组是只配电池储能第三组是电池加废弃矿井抽蓄联合运行。输入数据使用同一个典型日气象场景和同一个负荷曲线。实验结果非常直观。无储能时弃风弃光率高达28%左右因为在负荷低谷时段比如凌晨和午后新能源出力无法完全消纳又没有储能来吸纳。加了电池之后弃电量降到12%左右因为电池在负荷低谷充电、在高峰放电把一部分电量搬到了需要的时候。但12%的弃电量仍然不算低原因是电池容量有限在午后光伏大发时段2小时左右就会充满之后剩余的新能源电量还是只能丢弃。加上抽蓄之后弃电率降到了约4.5%。为什么会有这么大的提升因为抽蓄电站的“水库”容量远大于电池它可以连续4小时吸收光伏电量把电量从白天“搬”到傍晚高峰时段使用这个时间尺度的转移能力正好弥补了电池容量受限的短板。数据对比这里我放在一张表里方便看得更清楚配置方案新能源消纳率系统运行成本万元/日弃电率无储能72.0%16.828.0%仅电池储能88.0%12.512.0%电池抽蓄95.5%8.74.5%4.2 电池与抽蓄的互补运行节奏把电池SOC曲线和抽蓄水库水位曲线放在同一张时间轴上观察会发现一个很有趣的互补特征。典型晴日场景下光伏在10点到15点之间出力旺盛系统的负荷并没有那么高。此时调度策略是先让电池充电SOC在11点左右到顶然后启动抽蓄机组把剩余电量用于抽水上库水位持续上升。到了18点到21点的晚高峰时段负荷抬升而光伏出力降到零电池率先放电因为它响应快、爬坡能力强能迅速支撑负荷抽蓄机组在电池放了一部分电之后接力发电持续为系统提供稳定出力。这种“电池打头阵、抽蓄做接力”的模式正是互补调度想要的效果。电池做快速反应抽蓄做长时支撑两种储能特性互补之后整个系统在应对日内负荷变化时表现得比单一储能从容得多。4.3 关键参数对调度结果的影响我还专门做了一轮灵敏度分析分别改变了电池容量、抽蓄装机功率上限和负荷峰值三个参数观察系统弃电率的变化规律。电池容量从10MWh增加到30MWh时弃电率从15%降到了9%左右但继续增加到50MWh时弃电率只下降了一个百分点。这说明电池容量在某个范围里存在边际效益递减系统需要的短时功率支撑有限容量过大了之后新增的部分很少被充分利用。更明显的规律出现在抽蓄装机功率上。抽蓄最大出力从5MW翻倍到15MW时弃电率从12%直接降到4%出头效果非常显著。这是因为抽蓄的“电量搬运能力”直接受抽水功率和发电功率制约功率越大白天能吸纳的新能源电量就越多。这个发现对工程实践的启示是在废弃矿井抽蓄项目的可行性论证中装机功率的选择比库容大小对新能源消纳的边际影响更大前期设计中应当优先保障装机规模而非一味扩大库容。5. 常见问题排查与Python工程化经验5.1 求解器报错与模型无解问题怎么处理做MILP优化最怕遇到的一句话就是“Model is infeasible”模型不可行。第一次遇到时我几乎想删库跑路。后来总结出套路化的排查顺序先检查约束是否矛盾再检查变量上下界是否合理最后检查数据单位。最常见的原因是约束里有一个“必须满足”的硬性条件和另一个硬性条件冲突了。比如我前面提到过给抽蓄机组设置了“最小运行时间”约束同时又有“某一时刻只能是抽水、发电或停机三选一”的状态约束如果两者的时间窗口设置不匹配求解器就会报无解。解决办法是给约束加一个“软化系数”把最小运行时间从固定值改成基于前一时刻状态的动态判断也就是只有在上一个时段机组处于运行状态时才强制连续运行否则允许启停。另一个高频问题出现在电池SOC界约束上。如果负荷曲线的峰值时段恰好出现在电池已经放空、无法继续放电的时刻而系统又必须满足负荷平衡模型就会无解。应急方案有两个要么增加外电网交换功率上限让系统可以从电网购电要么在模型里设置一个虚拟的“切负荷”变量用很大的惩罚系数约束它趋近于零。从工程实践角度这里推荐第二种因为切负荷变量可以帮助定位哪些时段最缺电对后续扩容方案的制定也有参考价值。5.2 数值求解精度异常与单位换算的坑有一次仿真结果出现了一个特别离谱的现象同一个条件下的两次运行结果完全相同但其中一次求解器给出的最优值比另一次小了几百块钱。这个问题花了我大半天才找到原因——是浮点数精度问题数据量纲太小导致部分约束在求解精度内被忽略。解决办法是对模型中的所有系数做归一化处理。把功率、能量这些动辄几百兆瓦的数字同时除以系统容量的标幺基准值让核心变量保持在1到100这个量级。在目标函数里加一个后处理还原系数把标幺值乘回去得到一个真实的物理值。这个操作做完之后同样的模型求解时间缩短了约30%数值稳定性也好很多。如果求解出现“Gap is too small”之类的警告不要慌先在变量量纲上找问题而不是去调求解器的公差参数那通常只会把问题掩盖掉。5.3 Python环境配置与依赖包版本的选择建议最后聊一下Python环境和依赖包的坑。我做这个项目用的Python版本是3.9Pyomo的版本建议选6.x以上因为这几个新版本对求解器接口更友好尤其是Gurobi 11版本的兼容性。依赖包尽量减少重点只用pandas、numpy、matplotlib、pyomo这四个核心库scipy和sklearn只在做场景聚类时用到不影响主流程。如果你用Windows环境做开发我建议装一个Anaconda管理环境直接用conda创建独立环境安装pyomo和gurobi库如果是在Linux服务器上跑批量仿真可以用虚拟环境加pip安装。还有一点很实用Gurobi在默认安装后需要在命令行里跑一次licence激活授权没激活就调用Python接口会一直卡在许可证等待状态看起来像程序死循环实际上只是授权校验。开源替代方案GLPK虽然不用授权但求解整数变量稍多的模型效率会掉得比较明显如果你的模型规模在几百个变量之内用GLPK跑通路径测试是完全可以接受的。整个项目写下来我最大的体会是做这种互补调度研究的核心难点不在算法本身而在对每一类设备的运行特性理解够不够深。电池不是一个大功率无限供电器抽蓄也不只是一个“大水桶”它们的物理特性都在约束里而约束写得好不好直接决定了优化结果在现实中可用不可用。把这个模型吃透之后再往前扩展多能互补、现货市场接口之类的问题都是在同一套框架上做增量路会顺很多。