新闻详情

新闻详情

首页 / 资讯中心 / 详情

Python实现风光储互补调度:含电池与废弃矿井抽水蓄能

发布时间:2026/10/1 11:32:04来源:尧图网络
Python实现风光储互补调度:含电池与废弃矿井抽水蓄能
风电和光伏这俩“靠天吃饭”的电源加上储能这个“缓冲池”组合起来做互补调度是新能源领域绕不开的核心话题。这篇博文想分享的是我如何用Python把这套含电池储能和废弃矿井改造小型抽水蓄能的互补调度系统跑起来。标题里“互补”两个字是精髓——不是简单把电源堆在一起而是让风电、光伏、电池、抽蓄在时间和空间上协同出力既平抑波动又提升并网友好度。适合正在做新能源电力系统优化、储能配置或微电网调度的工程师以及想用Python快速验证调度策略的研究者参考。整个项目我拆成了四块系统建模、约束处理、优化求解、结果分析。Python在这里不只是计算工具更是把物理问题翻译成机器能懂的数学语言、再把求解结果还原成工程决策的桥梁。下面我按实际推进的顺序一步步说清楚我是怎么设计、怎么踩坑、怎么调通的。1. 项目整体设计与思路拆解1.1 “互补”的核心逻辑为什么要风电、光伏、储能一起调度先想清楚一个问题为什么单靠风电或单靠光伏不够风电出力夜间大、白天小光伏则恰好相反晴天中午猛发、晚上归零。二者在时间尺度上有天然的“互异性”但都不稳定——云飘过来光伏瞬间掉一半风速降了风电跟着萎。如果只有风加光电网调度员会非常头疼这边负荷高峰可能正好碰上光伏出力低谷那边凌晨风电大发却没人用电。储能的引入改变的是“发电侧被动跟随负荷”的单向逻辑。电池响应快、能量密度高适合平抑秒级到小时级的波动抽水蓄能响应略慢但容量大、寿命长适合做日级以上的能量搬移。两者配合就能在时间维度上把“不听话”的新能源出力重新塑造成相对平稳、可预测的供电曲线。我做的这个系统里还加入了废弃矿井小型抽水蓄能利用现有巷道和竖井改造储水空间相当于把地理资源变成储能资产。1.2 为什么选择纯Python方案而不是商业仿真软件做电力系统调度常见的路线有Matlab/Simulink、商业软件如PSS/E、DIgSILENT以及纯代码方案。我这次偏要全用Python理由是Python生态里有完整的数学优化库如ortools、pulp、scipy.optimize做线性规划、混合整数规划非常顺手。相比Simulink那种图形化拖拽建模代码方案更利于批量跑仿真、做参数敏感性分析。而且配网级、微网级的调度模型用Python维护起来比商业软件更灵活——约束条件改了改几行代码就行不用在图形界面里重新连线。当然这不是说Simulink不好。如果要做电磁暂态分析、逆变器开关级仿真那还得靠专业工具。但“调度运行研究”这个场景计算的是日前/日内计划的功率分配问题关心的是能量平衡和经济效益本质是运筹优化Python天然适配。1.3 模型选型混合整数线性规划的适用性分析调度运行问题的数学本质是在满足一系列等式和不等式约束的前提下找到让目标函数最优比如运行成本最低、弃风弃光最少的功率分配方案。这里有个关键选择用线性规划LP、二次规划QP还是混合整数线性规划MILP我最终选了MILP原因是抽水蓄能的“抽水/发电”两种工况是互斥的存在“是/否”型决策变量——这种逻辑天然需要0-1整数变量来表达。另外电池虽然有连续充放电功率但若要考虑“充满后不能再充”这类非线性特性也倾向于用整数变量分段逼近。MILP的优势在于模型表达能力强、全局最优解有保证只要求解器靠谱对中小规模问题几十到几百个决策变量求解速度完全可接受。打个比方线性规划像在光滑坡面上找最低点MILP像在一层层台阶上找最低点台阶让模型更贴近现实但也增加了求解难度。实际中我用ortools的CP-SAT和SCIP求解器来解MILP几十个时段、十几个设备的问题秒级就能出结果。2. 系统建模与关键技术细节2.1 风电、光伏出力模型从预测曲线到可用功率风电和光伏的“可用出力”是调度的输入条件不是决策变量。我用了典型日或典型周的风速、辐照度数据通过功率曲线换算成风电出力通过光伏组件模型算出光伏出力。这里有个工程细节原始气象数据有分辨率误差直接用于调度会产生尖峰毛刺我的做法是做15分钟滑动平均平滑同时在模型里给风光出力加一个“可弃”约束即实际出力≤可用出力这样调度器可以选择性地弃风弃光而不是被动照单全收。风电功率换算这块我用的风速-功率曲线是分段函数切入风速以下出力为0额定风速以上出力封顶在额定功率中间段近似线性——虽然简化但对日前调度这种时间尺度的研究来说够了。光伏模型则考虑了电池板效率的温度修正温度升高效率略降这个系数虽小但对长时间仿真的电量统计有影响。2.2 电池储能的充放电约束与SOC递推模型电池储能建模有几个硬指标最大充放电功率、电池容量、SOC荷电状态上下限、充放电效率。我用的递推式是SOC(t1) SOC(t) (充电功率 × 充电效率 - 放电功率 / 放电效率) × Δt注意充放电效率不能简单地合二为一因为现实中充进去1度电放出来可能只有0.9度这0.1度损耗体现为电池发热。我实测下来效率系数设在0.9-0.95之间比较合理锂离子电池新的时候高一点老化了会掉。另一个容易被忽略的点电池是有日循环次数限制的。我加了“日累计充放电量上限”这个约束防止调度模型为了省钱让电池过度频繁充放现实中这会大幅缩短电池寿命。算经济账的时候也可以把电池寿命损耗折算成每次充放电的“磨损成本”加进目标函数——这个我后面会细说。2.3 废弃矿井抽水蓄能建模几何约束与工况切换废弃矿井小型抽水蓄能跟常规抽水蓄能的物理原理一样上水库蓄水放水、通过水轮机发电只是上下水库变成了矿井巷道和竖井。模型上需要多考虑三个约束水量平衡上库水量 上时段水量 抽水流量×Δt - 发电流量×Δt还要考虑渗漏损失率废弃矿井的巷道渗漏比新建水库大我按每时段0.5%估算库容约束上库水位有上下限对应水量上下限抽水/发电互斥约束同一时刻要么抽水要么发电要么停机不能同时干互斥约束在MILP里用两个0-1变量实现抽水状态和发电状态二者的和为1停机时加起来是0其实不取等号而是小于等于1。这个模型虽然简单但把抽蓄的本质抓住了它是一个“电能-水的势能-电能”的转换器转换过程损耗不小我按抽水效率70%、发电效率80%设置综合效率56%左右——如果再把日子过细压强损失、水头变化也得考虑进去但对调度研究来说这个精度够了。2.4 功率平衡约束整个模型的中枢调度模型的“纲”是每时段的功率平衡等式风电实际出力 光伏实际出力 电池放电 - 电池充电 抽蓄发电 - 抽水耗电 负荷右边是负荷需求左边是各类电源的净出力。这个等式的左右两边必须每时每刻都相等。调度优化的本质就是在一个可行域里找一组“怎样分配左边各项大小”的解。如果算出来不等式不满足就不是可行解如果某个时段负荷供不上模型会通过切负荷kWh级惩罚成本极高来兜底但正常优化下不应该出现这种情况。我在这加了两个小技巧。一是把“弃风弃光量”和“切负荷量”显式写成变量而不是隐含在实际出力里这样求解结果能直接看统计指标。二是给功率平衡等式加一个很小的松弛项允许±0.001MW的误差防止求解器因浮点误差把可行解误判为不可行。3. Python代码实现与核心环节解析3.1 环境准备与依赖库选择我用的Python版本是3.93.10以上也没问题主要是ortools和pandas的兼容性要确认。核心依赖库ortoolsGoogle的运筹优化库装一次就能用CP-SAT求解器处理MILP非常稳pandas处理时序数据负荷、风速、辐照度numpy数组计算matplotlib画调度结果曲线图安装就一条命令pip install ortools pandas numpy matplotlib为什么不装scipyscipy擅长连续非线性优化但处理MILP不是强项。调度问题的整数变量多ortools才是专业对口。如果你更喜欢开源求解器pulpGLPK/CBC组合也行但ortools的CP-SAT在大规模MILP上性能更好而且自带了很好的调试输出信息。3.2 数据结构设计从原始数据到模型输入的完整流水线写代码的第一步是理清数据流。我定义了这样几个数据结构# 典型日数据96个时段15分钟分辨率 class TimeSeriesData: def __init__(self): self.load [] # 负荷需求MW self.wind_available [] # 风电可用出力MW self.solar_available [] # 光伏可用出力MW class BatteryConfig: def __init__(self): self.capacity 10 # MWh电池容量 self.max_power 5 # MW最大充放电功率 self.soc_min 0.2 # 最低SOC self.soc_max 0.9 # 最高SOC self.eff_charge 0.95 # 充电效率 self.eff_discharge 0.95 # 放电效率 class PumpedStorageConfig: def __init__(self): self.max_turbine 6 # MW发电最大功率 self.max_pump 5 # MW抽水最大功率 self.max_volume 50 # 万m³上库有效容量等价于最大储存电量 self.eff_turbine 0.8 self.eff_pump 0.7数据库我用的pandas DataFrame每一行是一个时段列是负荷、风电、光伏。这样做的好处是后期做数据处理缺失值填充、归一化非常方便。3.3 目标函数设计与权重标定目标函数我设计成四项加权求和minimize: 购电成本 切负荷惩罚 弃风弃光惩罚 电池磨损成本购电成本向大电网购电的单价 × 购电量这个成本驱使系统优先用本地新能源切负荷惩罚单价设得特别高比如1000元/MWh让模型绝不轻易切负荷弃风弃光惩罚单价低于购电价比如300元/MWh允许在极端情况下少量弃电电池磨损成本每次充放电折算成每MWh损耗我在模型中设置成50元/MWh权重标定有个小窍门先把所有惩罚项设成同样的量纲元/MWh再比较量级。如果弃风惩罚低于购电成本模型会优先弃掉本地风电而不是多买电——这在经济上是对的因为弃风等于“不花钱”购电却要花钱。但实际工程中还要考虑政策要求新能源消纳率必须达到某个百分比所以我把弃风弃光惩罚设得比购电价高倒逼模型尽可能消纳新能源。具体多少合适我后面做敏感性分析时说。3.4 约束条件的代码化实现从数学到代码的三步走把数学约束翻译成代码我总结了一个“三步法”先定义变量再写约束表达式最后求解检查。以抽蓄的互斥约束为例# 定义变量pump_status和turbine_status是0-1变量 pump_status [model.NewBoolVar(fpump_{t}) for t in range(T)] turbine_status [model.NewBoolVar(fturb_{t}) for t in range(T)] # 互斥约束同一时刻最多有一个状态为1 for t in range(T): model.Add(pump_status[t] turbine_status[t] 1) # 关联约束抽水功率和抽水状态绑定 # 抽水功率 0 当且仅当 pump_status 1 for t in range(T): model.Add(pump_power[t] pump_max).OnlyEnforceIf(pump_status[t]) model.Add(pump_power[t] 0).OnlyEnforceIf(pump_status[t].Not())注意用OnlyEnforceIf而不是手动乘一个大数后者容易引入数值稳定问题。ortools的CP-SAT支持这种“条件约束”模式比纯线性化写法简洁得多也不容易出错。电池SOC递推的代码化相对直接# SOC递推约束soc[t1] soc[t] (充电功率*eff_ch - 放电功率/eff_dis)*dt for t in range(T-1): model.Add(soc[t1] soc[t] (charge[t]*eff_ch - discharge[t]/eff_dis) * dt)这里有个细节SOC是连续变量为了减小求解规模我可以把它离散化成几十个档位比如步长0.01对日前调度来说精度完全够。CP-SAT对整数变量的处理远优于连续变量离散化能大幅提速。3.5 求解与结果输出把优化结果还原成可读的调度计划模型构建完成后求解就是一键的事solver cp_model.CpSolver() solver.parameters.max_time_in_seconds 300 # 全局求解时间上限5分钟 status solver.Solve(model) if status cp_model.OPTIMAL: print(找到最优解) # 提取结果 schedule pd.DataFrame({ wind: [solver.Value(wind_actual[t]) for t in range(T)], solar: [solver.Value(solar_actual[t]) for t in range(T)], battery_charge: [solver.Value(charge[t]) for t in range(T)], battery_discharge: [solver.Value(discharge[t]) for t in range(T)], pump: [solver.Value(pump_power[t]) for t in range(T)], turbine: [solver.Value(turbine_power[t]) for t in range(T)], buy: [solver.Value(buy_power[t]) for t in range(T)], })提取结果后我用matplotlib画了一张调度图横轴是96个时段纵轴是功率堆叠面积图展示风电、光伏、发电、放电、购电的时序再叠一条负荷曲线。这张图是给导师、甲方或审稿人看的时候最有说服力的东西。图上还能直接看到电池SOC和抽蓄水位的日变化曲线一眼看出储能的“搬移”行为——什么时候充、什么时候放、充放了多少全在图里。4. 典型场景仿真与结果分析4.1 夏季晴天场景光伏大发时储能如何“削峰填谷”我用一组夏季典型数据负荷日峰在18:00光伏大发的时段在12:00-15:00跑了仿真。结果非常有意思中午光伏超过负荷需求电池在11:30-13:30之间以额定功率充电抽蓄也在正午抽水到了傍晚19:00-21:00负荷高峰光伏已经归零风电还没上来电池和抽蓄同时放电把中午存下的能量吐出来补缺口。这组曲线展示了一个标准的多能互补场景光伏负责白天基荷储能做“光伏出力与晚高峰之间的时间搬运工”风电则在夜间——尤其是后半夜负荷低谷时——挑大梁。三个电源的时间互补性一目了然。这也是我文章里常放的“典型日调度图”。4.2 冬季大风夜间场景风电大发与电池/抽蓄的配合另一个典型场景是冬季的夜间风速大风电出力一路狂飙但后半夜负荷很低电送不出去。仿真里出现了两种情况一是电池从凌晨1点开始充电、到6点充满二是抽蓄利用富余风电把水抽到上库白天再发电。电池容量有限10MWh的容量凌晨3点就满了这时候抽蓄顶上——50万m³的水库容量相当于等效电量300MWh左右存储尺度大得多。这组结果说明电池适合做“日内短时缓冲”抽蓄适合做“跨时段能量搬移”。两者不是竞争关系而是不同时间尺度的互补。如果你只配电池不配抽蓄夜间风电大发时段会大量弃风反之只配抽蓄中午光伏的快速波动它跟不上。这个结论对我的配置方案选型很有说服力。4.3 配置容量敏感性分析抽蓄容量翻倍带来多少消纳增益我还做了个敏感性实验把抽蓄库容从50万m³逐步增加到100万、150万m³观察弃风弃光率和系统购电成本的变化。结果发现库容翻倍时弃风率下降了约12个百分点但继续翻倍收益就递减了——原因很简单晚间负荷高峰就那几个小时抽蓄的发电功率上限水轮机容量没变库容再大也放不完。这个实验的工程含义是储能的容量配置不是越大越好得跟“互补系统的短板”匹配。如果瓶颈是晚高峰持续时间上库容就够了如果瓶颈是光伏瞬时峰值该加电池如果瓶颈是输电通道那就得另想办法。我把这个分析写成了结论配合图和数据很有说服力。5. 常见问题与调试经验5.1 求解器报“不可行”怎么办三步定位法第一次跑模型时几乎必然遇到“infeasible”或“status INFEASIBLE”。别慌我总结了一套三步定位法第一步检查数据。负荷曲线里有没有缺失值风电光伏数据有没有突变数据质量是一切的前提第二步检查功率平衡。把每个时段的“左边-右边”打印出来看是否有时段不平衡但又被约束“强行平衡”导致冲突第三步松弛约束。把SOC上下限从[0.2,0.9]放成[0,1]把库容约束去掉看看是否还能求解。如果能说明是边界条件设得太紧逐条加回来定位另外有个实际工程中容易踩的坑15分钟分辨率下充电功率5MW充1个时段0.25h电量增加1.25MWh但SOC步长如果设成0.01即0.1MWh会离散化导致不可行。解决办法是让SOC步长跟功率分辨率匹配或者干脆用连续变量让求解器自己处理。5.2 求解时间过长模型规模控制的实战经验MILP的求解时间随变量数量指数上升有几个实用技巧时段分辨率先粗后细先用1小时分辨率调通逻辑再用15分钟跑精算减少整数变量能连续就连续比如功率只有必须互斥或逻辑分支的地方才用整数调大求解容忍度设置相对gap为1%即允许次优1%求解时间可以缩短一个数量级用热启动把上一轮的结果作为初始解传给求解器能大幅加速收敛我用ortools发现当模型有300个以上0-1变量时求解时间会从秒级跳到分钟级。所以我在模型设计阶段就有意识地分流电池的SOC用连续变量抽蓄的启停用整数变量风电光伏的弃用变量也是连续的。这样总变量数量控制在200个左右5分钟内必出最优解。5.3 结果不合理检查目标函数是否存在隐性陷阱有一次我跑出来的结果特别反常电池每天早上都在充电、下午放电但算出来的“成本”反而比不装储能还高。排查了半天发现是目标函数里电池磨损成本设得太低而小电电价设得比大电网还高导致模型“为了充而充”制造无意义的循环。电池的充放电不应该只看单次电价差得把磨损和寿命损耗一起算进成本里。我把磨损成本从10元/MWh调高到60元/MWh后结果就正常了——电池只在确实有峰谷差的时候才动作。类似地弃风弃光惩罚的权重也要注意。如果设得低于购电价模型会倾向弃掉所有新能源去购电因为购电单价高“省下”的钱比“浪费”的风电多这不符合“绿色优先”的调度逻辑。所以我把弃风弃光惩罚设为购电价的1.5倍以上强制模型优先消纳。5.4 从“能跑”到“可信”结果校验的三道关卡代码能跑、有结果离“真的能信”还差一步。我每次仿真完都做三道校验电量平衡校验全时段风光电量和储能吞吐量、购电量的总电量跟总负荷电量比误差应在0.1%以内SOC完整性校验仿真结束时电池SOC应该跟初始值相同否则说明模型“凭空生电或凭空耗电”库容合理性校验抽蓄上库水位曲线应该在上下限内不能出现负水量或超过库容这三道校验跑完我才敢把结果写进论文或者报告。很多初学者的代码“能跑”但结果说不过去就是缺了这道复盘功夫。6. 一点个人体会这个项目做下来我最大的体会是调度优化这件事模型的物理准确性和数学可解性是一对矛盾。物理模型越细致方程越难解追求求解速度就得在物理细节上做合理简化。我在电池模型上做了一些简化忽略温度影响、内阻变化在抽蓄模型上做了更多简化忽略水头变化、压力管道动态换来的是几十秒内能出全局最优解。对于日前调度这种时间尺度够用了。如果真要细化到机组组合、检修计划、安全约束那就是把模型升级到机组组合问题复杂度又会成倍增加。关于“废弃矿井小型抽水蓄能”这个方向我多说一句这个思路在国内很多资源枯竭型矿区有很强的现实意义等于把废地变成了储能资产。我在模型里用的参数效率、库容是基于公开资料的估算值真要做工程可行性研究还得实测水文地质条件和设备选型。但我这一百多行Python代码最大的价值在于把“能不能行”从想法变成了可量化的数字——这种从抽象到具体的过程是我觉得做研究最有意思的部分。如果你也想在这个方向延伸可以在我的模型基础上做三件事一是把日前调度改成日内滚动优化考虑更短时间尺度的不确定性二是加进碳交易成本看看碳配额对储能配置的影响三是换一个更强的求解器比如Gurobi学术版免费支撑更大规模的算例。调度优化这条路深入下去还有很多有意思的问题。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

单卡24G显存实战:从零预训练GPT-2到领域适配全流程 2026/10/1 14:28:57

单卡24G显存实战:从零预训练GPT-2到领域适配全流程

个人开发者想完整走一遍 LLM 从预训练到领域适配的全流程,最大的障碍从来不是算法本身,而是资源约束下的取舍。我手头只有一张 RTX 3090,24GB 显存,这个配置在大厂眼里连入门都算不上,但恰恰是个人开发者最真实的起点。…

阅读更多 →
ThingsBoard MQTT属性上报全攻略:Topic、报文与排错实战 2026/10/1 14:28:51

ThingsBoard MQTT属性上报全攻略:Topic、报文与排错实战

ThingsBoard的MQTT通道其实比我预想的更容易踩坑。最近帮朋友排查一个现场问题,设备明明连着ThingsBoard,控制台能看到设备在线,但打开设备详情页的“属性”标签,里面一片空白。翻MQTT日志,消息发出去了,平…

阅读更多 →
AI开发-python-langchain框架:LangChain 与 Milvus 结合,把向量检索接进 RAG 链路 2026/10/1 14:28:51

AI开发-python-langchain框架:LangChain 与 Milvus 结合,把向量检索接进 RAG 链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
单细胞测序解析肾癌肿瘤血栓中细胞外基质重塑亚群与治疗靶点 2026/10/1 14:28:44

单细胞测序解析肾癌肿瘤血栓中细胞外基质重塑亚群与治疗靶点

一篇高质量的肾癌肿瘤血栓单细胞研究不容易做,从样本收集到数据分析,再到最后结果落笔,中间的坑比想象中多不少。HD系列做到第16篇,正好把肿瘤血栓里细胞外基质重塑这个亚群的故事讲透了,这里面的分析思路和验证方式有…

阅读更多 →
代码签名 OV 跟 EV 有什么不同?该怎么选? 2026/10/1 14:28:44

代码签名 OV 跟 EV 有什么不同?该怎么选?

OV vs EV 代码签名证书核心对比重点更新:2024 年后微软 SmartScreen 机制变更,EV 不再能直接跳过 SmartScreen 警告,OV/EV 都需要靠下载量累积信誉,网上很多旧教程说 EV 可以直接过 SmartScreen 已经失效Microsoft ...表格项目OV&…

阅读更多 →
AI编程工具预算指南:TaoToken统一Key接入免费与付费工具全解析 2026/10/1 14:28:38

AI编程工具预算指南:TaoToken统一Key接入免费与付费工具全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉