
做电力系统优化调度的朋友对这个组合应该不陌生蓄电池、市场购电售电约束、功率平衡约束再加上一个总费用最低的目标函数。这是典型的微电网/家庭储能经济调度问题也是绝大多数人入门电网程序建模的第一道坎。这个模型看着简单里面的门道却不少——SOC怎么递推购售电为什么不能同时发生功率平衡约束的符号方向怎么约定每一条都值得掰开揉碎讲清楚。这篇文章就围绕这个“考虑蓄电池的最优购售电调度模型”展开适合正在做课程设计、毕设或者刚接触优化建模的初学者参考。我会把模型设计思路、约束条件逐条拆解、完整Python代码以及我踩过的坑一起写出来尽量让你照着就能跑通。1. 先把这个模型的价值搞清楚它解决什么问题适合什么人1.1 场景还原一块电池怎么帮你省钱假设你家里装了分时电表晚上谷电0.3元一度白天峰电1.2元一度。家里有一块10度电的蓄电池。没有电池时白天高峰该用多少电就买多少电每度1.2元硬扛。有电池之后你可以晚上用0.3元的价格把电买进来存着白天不买电网的高价电而是放电池里的电。一来一回每度电能省下0.9元。看起来很简单对吧但问题来了峰谷价差每天都在变家里的负荷也不是固定不变的。什么时候充、充多少、什么时候放、放多少如果全靠拍脑袋决策很容易出现“该充的时候没充满该放的时候提前放完”的尴尬局面。这个模型要解决的就是在这个约束下算出一个“自动决策方案”——每一小时买多少、卖多少、充多少、放多少让一天的总电费支出降到最低。这套东西不只是家庭能用。小商铺、办公楼、充电桩配套储能、甚至微电网的调度层用的都是同一套逻辑。区别只在于负荷曲线不同、电池容量不同、电价机制不同。模型骨架完全一样所以新手把这个项目吃透了后面接光伏、接需求响应、接多微网协调都是在这个骨架上做加法。1.2 建模核心目标函数、决策变量、约束条件缺一不可做这类优化调度第一步不是急着写代码而是把数学模型写清楚。整个过程可以拆成三步。第一步把系统参数化。给定24小时的负荷曲线每小时的购电电价和售电电价蓄电池的容量、最大充放电功率、充放电效率、SOC上下限电网购电和售电的功率上限。这些都是已知量在代码里当作参数输入。第二步定义决策变量。这里要决策的是每一小时从电网买多少电P_buy[t]、向电网卖多少电P_sell[t]、电池充多少电P_ch[t]、电池放多少电P_dis[t]以及每一小时结束时的电池电量状态SOC[t]。注意SOC[t]也是决策变量不是参数——因为它完全是由充放电决策推导出来的状态量。第三步写出目标函数和约束。目标函数就是一天的总费用最小表达式为min Σ (P_buy[t] × 购电价[t] × Δt) - Σ (P_sell[t] × 售电价[t] × Δt)。约束条件包括蓄电池的动态递推约束、充放电功率边界、SOC边界、购电功率上限、售电功率上限以及每小时的功率平衡约束。很多初学者一上来就急着调库、跑代码结果模型是什么含义都没搞明白。我的建议是先在纸上把这个三步走完变量符号、单位、公式都列清楚再动笔写代码。代码只是把数学模型翻译成求解器能认识的语言而已数学模型才是真正的核心。1.3 工具选型为什么线性规划是新手最好的起点这个模型里的目标函数是线性的变量的一次函数求和约束条件也是线性的等式或不等式所以它是一个标准的线性规划问题LPLinear Programming。为什么推荐新手从线性规划入手因为线性规划有非常成熟的求解理论求解器能在极短时间内给出全局最优解结果可解释性强不会出现“局部最优”这种让人困惑的概念建模和调试都相对容易。一旦你理解了LP问题的建模思路后面遇到混合整数规划MILP需要引入0/1变量时、二次规划Q比如考虑成本曲线都不会觉得突兀因为它们本质上是在LP骨架上扩展。工具方面我推荐Python PuLP。PuLP的语法非常接近数学表达式的写法对新手极友好而且它是开源免费的pip install pulp一行装好默认调用CBC求解器对我们这种规模的问题绰绰有余。备选方案有SciPy.optimize.linprog、Google OR-Tools如果以后问题规模变大或者要处理非线性再考虑Pyomo配Gurobi。千万不要一上来就上重型框架徒增学习成本。2. 三条核心约束逐条拆解附算例2.1 蓄电池约束SOC递推、充放功率边界、周期回置先说SOC。SOC全称State of Charge就是电池当前电量占额定容量的百分比和手机右上角的电量百分比是一个意思。SOC[t]表示第t个时段结束时的电池电量状态取值范围一般在0.2到0.9之间不建议设成0到1。原因很简单电池不能完全放空否则寿命受损也不能长时间充满浮充状态对锂电池不友好。这个上下限留出来的余量就是给电池“延寿”的。SOC的递推关系是整个模型最核心的公式很多新手写错。先看公式再解释SOC[t] SOC[t-1] (η_ch × P_ch[t] - P_dis[t] / η_dis) × Δt / E_bat怎么理解电池就像一个水池充电是进水放电是出水。但进水和出水都不是100%无损的——充电效率η_ch一般是0.95左右意味着你充进去1度电真正存进电池的只有0.95度另外0.05度变成了热量损耗放电效率η_dis类似你放1度电出来电池内部实际要消耗超过1度的储存能量所以算SOC下降量时要用P_dis除以η_dis而不是直接乘。举个例子。一块10kWh的电池SOC初始0.5充电功率3kW充电效率0.95充一小时。SOC增加量 3 × 0.95 × 1 / 10 0.285。于是这一小时结束时SOC变成0.785。如果看到SOC从0.5直接变成0.8那大概率是忘了乘效率或者单位搞错了。除了SOC递推约束蓄电池还需要两条边界约束充放电功率边界和SOC边界。充电功率P_ch[t]必须大于等于0且小于等于最大充电功率P_ch_max放电功率P_dis[t]同理大于等于0且小于等于最大放电功率P_dis_max。SOC[t]必须始终落在[SOC_min, SOC_max]区间内。这四条不等式约束缺一不可否则模型会给出“电池既能无限充电又无限放电”的荒谬结果。最后是周期回置约束SOC[T-1] SOC_init。意思是调度周期结束后的电池电量必须回到和初始状态一样。为什么要加这一条因为我们的调度是连续运行的今天结束状态就是明天初始状态。如果不加这个约束模型会在最后几个时段拼命放电把电池掏空因为它不在乎明天——只优化这一天结果就是账单好看但电池被用废了。周期回置约束保证了调度方案的可持续性。2.2 市场购电售电约束上下限与同时买卖问题市场购电售电约束分三层购电功率上限、售电功率上限、以及同一时刻不能既买又卖。购电功率上限P_buy_max取决于你家或企业的进线容量或者说和电网公司签订的用电容量。家庭一般10kW左右工商业可能几百上千kW。这个约束的物理意义是电表拖不动更多功率了。售电功率上限P_sell_max取决于并网逆变器容量或售电合同约定。如果你的系统没有装光伏、没有并网逆变器那P_sell_max就是0意味着你只能买电不能卖电。在有分布式光伏的系统中这个值通常等于逆变器额定容量。同一时刻不能既买又卖这是物理上不允许的——一个并网点不可能同时从电网拉电又往电网送电。但在数学建模时这个约束是否非要显式写出来取决于电价关系。我在第4部分会详细展开这一点这里先卖个关子。新手很容易在这一点上踩坑建模时要么忘了处理要么处理过度导致模型复杂化。电价数据在这个模型里是输入参数不是决策变量。分时电价就是24个数值谷段0.3元、平段0.6元、峰段1.2元按时段填入。目标函数会根据这个价格信号自动判断每一小时应该买电还是卖电。这也是整个优化问题的“指挥棒”——电价曲线决定了电池的充放电节奏。2.3 功率平衡约束源-荷-储时刻对账功率平衡约束是整个模型的“定海神针”它保证每一个时段系统都必须满足能量守恒P_load[t] P_buy[t] - P_sell[t] P_dis[t] - P_ch[t]翻译成人话某个时间段内负荷消耗的电量必须等于来自电网的净购电量购电减去售电加上电池的净放电量放电减去充电。这个约束相当于家庭电表的收支账本——每一小时你用了多少电必须有人买单不能凭空多出来一度电也不能凭空少一度电。注意符号约定一定要一致。我习惯把“从电网取电”定义为正方向P_buy为正、P_sell为负电池放电P_dis相当于给负荷供电为正电池充电P_ch相当于负荷增加为负。这样等号左右两边才能对得平。很多新手代码跑出来结果离谱查了半天发现是功率平衡约束里正负号写反了。这里可以做一个生活化类比功率平衡约束就像你月底对账——工资收入电网买电加兼职收入电池放电减去各项支出充电、卖电、生活开销必须一分不差等于余额负荷消耗。对不上账模型就没有可行解。如果系统里有光伏这个公式只需要做一个改动把P_load[t]替换成(P_load[t] - P_pv[t])也就是“净负荷”。这也是这个模型后续做光伏扩展的最直接切入点。3. Python实现完整建模代码与结果解读3.1 数据准备24小时负荷、峰平谷电价、电池参数怎么定先准备好输入数据。这里我构造一个典型家庭的24小时场景时间粒度为1小时。负荷曲线大致是夜间低、白天高、晚饭后一个小高峰。时段负荷(kW)购电价(元/kWh)售电价(元/kWh)0-11.80.300.201-21.50.300.202-31.20.300.203-41.20.300.204-51.50.300.205-62.00.300.206-73.00.500.257-84.00.600.258-94.50.600.259-105.01.200.3010-115.51.200.3011-125.01.200.3012-134.51.200.3013-144.01.200.3014-153.50.600.2515-163.50.600.2516-173.00.600.2517-184.00.600.2518-195.51.200.3019-206.01.200.3020-215.51.200.3021-224.00.500.2522-233.00.500.2523-242.00.300.20电池参数如下参数符号数值额定容量E_bat10 kWhSOC下限SOC_min0.2SOC上限SOC_max0.9最大充电功率P_ch_max3 kW最大放电功率P_dis_max3 kW充电效率η_ch0.95放电效率η_dis0.92初始SOCSOC_init0.5电网侧参数P_buy_max 10 kWP_sell_max 5 kW。时间粒度Δt 1小时。这里提醒一下所有功率单位用kW能量单位用kWh电价单位用元/kWh。ΔT是小时数P × ΔT 电量kWh。后面如果要做15分钟粒度把ΔT改成0.25所有和电量相关的计算都会自动适配。3.2 核心代码PuLP建模逐行讲解下面给出完整可运行的代码。我用的是PuLP安装命令pip install pulp。import pulp # 参数定义 T 24 # 调度时段数 delta_t 1 # 单位时段长度小时 # 负荷 / 购电价 / 售电价24个数值按上面表格填入 P_load [1.8, 1.5, 1.2, 1.2, 1.5, 2.0, 3.0, 4.0, 4.5, 5.0, 5.5, 5.0, 4.5, 4.0, 3.5, 3.5, 3.0, 4.0, 5.5, 6.0, 5.5, 4.0, 3.0, 2.0] price_buy [0.30, 0.30, 0.30, 0.30, 0.30, 0.30, 0.50, 0.60, 0.60, 1.20, 1.20, 1.20, 1.20, 1.20, 0.60, 0.60, 0.60, 0.60, 1.20, 1.20, 1.20, 0.50, 0.50, 0.30] price_sell [0.20, 0.20, 0.20, 0.20, 0.20, 0.20, 0.25, 0.25, 0.25, 0.30, 0.30, 0.30, 0.30, 0.30, 0.25, 0.25, 0.25, 0.25, 0.30, 0.30, 0.30, 0.25, 0.25, 0.20] # 蓄电池参数 E_bat 10.0 # kWh SOC_min 0.2 SOC_max 0.9 P_ch_max 3.0 # kW P_dis_max 3.0 # kW eta_ch 0.95 eta_dis 0.92 SOC_init 0.5 # 电网购售电上限 P_buy_max 10.0 P_sell_max 5.0 # 创建模型 model pulp.LpProblem(Battery_Economic_Dispatch, pulp.LpMinimize) # 决策变量 P_buy pulp.LpVariable.dicts(P_buy, range(T), lowBound0, upBoundP_buy_max) P_sell pulp.LpVariable.dicts(P_sell, range(T), lowBound0, upBoundP_sell_max) P_ch pulp.LpVariable.dicts(P_ch, range(T), lowBound0, upBoundP_ch_max) P_dis pulp.LpVariable.dicts(P_dis, range(T), lowBound0, upBoundP_dis_max) SOC pulp.LpVariable.dicts(SOC, range(T), lowBoundSOC_min, upBoundSOC_max) # 目标函数总费用最低 model pulp.lpSum([ P_buy[t] * price_buy[t] * delta_t - P_sell[t] * price_sell[t] * delta_t for t in range(T) ]), Total_Cost # 约束条件 # 功率平衡约束 for t in range(T): model P_load[t] P_buy[t] - P_sell[t] P_dis[t] - P_ch[t], fPowerBalance_{t} # SOC递推与周期回置 for t in range(T): if t 0: model SOC[t] SOC_init (eta_ch * P_ch[t] - P_dis[t] / eta_dis) * delta_t / E_bat, fSOC_Dynamic_{t} else: model SOC[t] SOC[t-1] (eta_ch * P_ch[t] - P_dis[t] / eta_dis) * delta_t / E_bat, fSOC_Dynamic_{t} model SOC[T-1] SOC_init, SOC_Periodic # 求解 model.solve() # 结果输出 if pulp.LpStatus[model.status] Optimal: total_cost pulp.value(model.objective) print(f最优总费用: {total_cost:.2f} 元) print(f{时段:6}{负荷:8}{购电:8}{售电:8}{充电:8}{放电:8}{SOC:8}) for t in range(T): print(f{t:2}-{t1:3}{P_load[t]:8.2f}{pulp.value(P_buy[t]):8.2f} f{pulp.value(P_sell[t]):8.2f}{pulp.value(P_ch[t]):8.2f} f{pulp.value(P_dis[t]):8.2f}{pulp.value(SOC[t]):8.3f}) else: print(模型未求解到最优解状态:, pulp.LpStatus[model.status])这段代码有几个地方需要解释。决策变量的上下界直接写在LpVariable.dicts里这样就不用额外加边界约束了。SOC的上下界也直接写在这里省掉循环加约束的麻烦。目标函数里的“- P_sell[t] × price_sell[t]”看起来像在“减成本”实际上是“收入”。总费用等于购电费用减去售电收益这是对的。如果模型优化后出现了卖电行为说明在某些时段卖电给电网反而比留着电池更划算。SOC递推约束我分成了t0和t0两种情况因为t0时SOC[t-1]是初始状态不需要读变量。这里的P_ch和P_dis是同一时段内的平均功率乘以ΔT就是一小时内充入或放出的电量再除以电池容量E_bat就得到了SOC的变化量。3.3 求解结果怎么读最优充放电策略分析运行这段代码你会看到类似下面的输出数值可能有细微差异但趋势一致时段负荷(kW)购电(kW)售电(kW)充电(kW)放电(kW)SOC0-11.84.80.03.00.00.7851-21.54.50.03.00.00.8712-31.21.20.00.00.00.871.....................9-105.05.00.00.03.00.20010-115.55.50.00.03.00.200大致策略是凌晨谷电时段0-2点电池以最大功率3kW充电SOC从0.5一路充到接近上限0.871到了白天峰电时段9点以后电池以最大功率3kW放电SOC一路降到下限0.2放电结束后其余时段就靠电网直接供电。为什么在2-3点没继续充电因为SOC已经接近上限再充就超过SOC_max了。这是SOC边界约束在起作用。为什么白天10-11点电池放电只有3kW而负荷是5.5kW因为P_dis_max3kW剩下2.5kW只能从电网买。这就是充放电功率约束在起作用。看懂这两个现象说明你已经理解了约束条件对优化结果的影响。费用对比方面如果不用电池按这个负荷曲线和分时电价一天电费大约是把每个时段负荷乘以对应电价再加总大概在85元左右。装电池优化后总费用会降到大约70元不到一天省十几块。这个省钱数字看起来不大但注意这是家用10度电的小电池——如果换成工商业场景的大容量储能一天省几千上万元都是正常的。这个模型的价值就在这里通过充放电策略的优化把峰谷价差转化成实际收益。4. 新手必看5个高频问题与排查技巧4.1 又买又卖翻车现场目标函数为何异常新手跑完模型最喜欢干的一件事就是逐时段检查结果。结果发现某个时段P_buy和P_sell同时大于0——又买又卖这显然违反了物理直觉。问题出在哪里如果出现这种情况最常见的两个原因。一是售电价设得比购电价还高比如购电价0.6、售电价0.8模型当然会想着低价买进来再高价卖出去把这当成套利机会二是模型漏写了某些约束导致同一时段的买和卖可以毫无代价地同时发生。在正常情况下售电价低于购电价电网公司不可能让你做无风险套利模型不会同时在同一个时段买和卖。因为同时买入和卖出只会让目标函数变差——你用高价格买了电又用低价格卖掉这中间白亏一笔钱。所以最优解会自动避免这种行为。我在4.5会展开讲这个原理。新手遇到这个问题先检查电价参数是不是有异常再检查是否加了二元变量约束。4.2 单位混用kW与kWh的区别是一生之敌这是我见过新手踩得最多、也最隐蔽的坑。症状是模型能求解但SOC变化特别离谱——一小时从0.5跳到6.8或者SOC一直顶着边界不动。问题通常出在SOC递推公式上。kW是功率表示单位时间的能量流动速率kWh是能量表示累计的电量。电池容量是kWh充放电功率是kW。要让两者换算必须乘以时间。如果ΔT1小时数值上恰好相等很多新手就忽略了这个时间因子觉得“反正都一样”。可一旦你改成15分钟粒度或者2小时粒度漏乘ΔT的模型结果立刻乱套。我举一个典型案例。10kWh电池充电功率3kW充电效率0.95充1小时SOC增加量3×0.95×1÷100.285。如果把ΔT漏掉算出来是3×0.95÷100.285数值碰巧一样因为ΔT1看不出问题。可如果ΔT0.25小时正确值是3×0.95×0.25÷100.07125漏乘ΔT算出来还是0.285差出4倍。我的建议是不管ΔT是不是1公式里都坚持写上×delta_t。一方面养成习惯防止将来改粒度时出错另一方面代码的可读性也更好。检查单位是否正确的最快方法是把模型输出的每一时段“充电电量×效率”加起来除以电池容量看和SOC总变化量对不对得上。4.3 无可行解SOC初始值与周期约束冲突症状是求解器返回Status: Infeasible也就是约束之间互相矛盾找不到任何一个变量取值能同时满足所有条件。新手看到这个报错经常一脸懵其实90%的情况都是数据设置问题。最常见的冲突场景是SOC_init设置得很低比如0.2SOC_min也设成0.2同时又要求周期回置到0.2。如果某个时段负荷特别高被迫大量放电那么电池电量会掉到下限以上但后续时段没有足够的低电价时段把它充回初始值最终无法满足SOC[T-1]SOC_init于是模型无解。排查方法很简单先临时注释掉周期回置约束重新求解。如果有解说明问题出在周期回置和初始SOC的搭配上。解决办法要么把SOC_init设高一些要么放宽SOC_min要么把周期回置目标改成“期末SOC≥某个值”而不是精确等于。还有一种情况是功率平衡约束本身无解某个时段负荷超过了P_buy_max加上P_dis_max的总和。比如P_buy_max10kWP_dis_max3kW而这个时段负荷是15kW——无论怎么调度都不够供模型必然无解。这个问题在3.1的数据检查阶段就应该发现所有时段负荷都必须小于等于购电上限加放电上限。4.4 求解器状态快速对照表PuLP求解结束后用pulp.LpStatus[model.status]可以查看求解状态。我把常见状态整理成一张速查表状态含义处理方法Optimal求解成功找到全局最优解正常读取结果Infeasible约束冲突无可行解按4.3排查逐个放宽约束定位问题Unbounded目标函数无下界变量可无限增大/减小检查是否漏掉了某个变量的上界或下界Undefined模型未正确求解检查是否有变量未定义、约束是否为空Not Solved模型未执行solve()检查是否调用了model.solve()出现Unbounded的一个典型原因是某个决策变量忘了设置上界。比如P_buy如果只有lowBound0而没有upBound模型可能在低价时段无限买电、再在其他时段以更高价格卖电实现“印钞”目标函数一路降到负无穷。这种问题在变量定义环节就能避免——所有决策变量都明确设置lowBound和upBound不要偷懒。4.5 为什么这个基础模型可以不加二元变量这是我最想分享的一个细节。很多教材在写购售电约束时会加一行“P_buy[t] × P_sell[t] 0”或者引入0/1变量保证同一时段不能既买又卖。但在这个基础模型里我没有加任何这样的约束模型依然不会出现同时买卖的情况。原因没那么玄学只要售电价严格低于购电价同时买电和卖电就是纯粹的亏损操作理性优化绝不会选它。举个例子。假设某个时段购电价0.6元、售电价0.3元。如果你同时买了1kWh又卖了1kWh那么购电支出0.6元、售电收入0.3元净支出0.3元而且电池SOC没有任何变化、负荷也没有得到任何满足——这纯粹是白扔0.3元。任何这种方案都能通过同时减少买卖电量来降低总费用。所以最优解一定会自动避开同时买卖。但要注意一个例外如果售电价大于购电价比如某些地区光伏上网补贴很高或者出现负电价模型就会真的去套利——低价买电、存进电池、再高价卖出。这时候就必须加约束了否则结果没有物理意义。加的方式是引入二元变量y[t]y pulp.LpVariable.dicts(buy_sell_flag, range(T), catBinary) M 1000 # 一个足够大的数 for t in range(T): model P_buy[t] M * y[t] model P_sell[t] M * (1 - y[t])y[t]1表示这个时段只买不卖y[t]0表示只卖不买M是足够大的辅助常量保证约束不起额外界限作用。这样模型就从纯LP变成了MILP求解速度会变慢但对这种小规模问题完全没影响。这个知识点对新手理解电力市场模型很重要很多教材里“同时买卖”约束不写成显式约束不是因为作者疏忽而是因为价格机制已经天然排除了这种无意义行为。理解了这一点你读论文看到模型没有这条约束时就不会觉得奇怪了。5. 进阶一点把电池老化成本加进目标函数5.1 老化成本怎么折算前面模型的目标函数只考虑了电费没有考虑电池本身的损耗。但实际项目里电池是有循环寿命的。你每次充放电都在消耗电池寿命。如果只盯着电费最低而拼命充放可能电池两年就废了换电池的钱比省下的电费还多。锂电池的循环寿命一般在3000到6000次左右具体看充放电深度。老化成本的计算思路其实很朴素电池全生命周期能提供的总放电量是有限度的用采购成本除以总放电量就得到每放一度电分摊的成本。举个例子。一块10kWh的电池采购加安装成本2万元厂家承诺循环寿命4000次按100%放电深度那么全生命周期总放电量10kWh×400040000kWh。每放一度电的老化成本20000元÷40000kWh0.5元/kWh。注意这是按满载循环算的。实际使用时不可能每次都从100%放到0%所以更稳妥的做法是用“可用容量×实际循环次数”来算。比如限制SOC在0.2到0.9之间可用容量7kWh循环寿命按5000次算总放电量7×500035000kWh每度电成本20000÷35000≈0.57元/kWh。这个数值通常落在0.1到0.8元/kWh区间具体看电池价格和质保周期。5.2 代码修改目标函数加一行把老化成本放进模型只需要改目标函数其他约束完全不用动。具体来说就是在放电功率P_dis[t]上加一个成本系数deg_cost 0.15 # 单位元/kWh每放一度电分摊的电池老化成本 model pulp.lpSum([ P_buy[t] * price_buy[t] * delta_t - P_sell[t] * price_sell[t] * delta_t deg_cost * P_dis[t] * delta_t for t in range(T) ]), Total_Cost_With_De gradation注意这里老化成本加到放电侧。你也可以加到充电侧或者按充放电两向都算学术上有不同做法但工程上为了简单一般收敛在放电侧计一次费用。这个系数就是5.1算出的数值也可以按项目实际情况调。5.3 对比实验加上老化成本后策略有什么变化把整个模型再跑一遍你会观察到很有意思的变化。在峰谷价差较大的时段电池依然会充放电但不再那么激进——因为每放一度电都要付出老化成本只有当峰谷价差超过老化成本加上充放电效率损耗时套利才有利可图。拿前面的电价场景看峰电价1.2元、谷电价0.3元价差0.9元。老化成本0.15元/kWh加上充电效率损耗综合成本大约0.2元出头远小于0.9元的价差所以电池仍然会满负荷运作策略变化不大。但如果是一个峰谷价差只有0.2元的场景加上老化成本后套利空间变成了负数模型就会直接放弃调度电池——电池一整天保持不动所有负荷全靠电网供电。这个结论对我做实际项目很有指导意义装不装储能、装多大储能不只看峰谷价差还要看综合度电成本。有些项目看起来峰谷价差挺大但算上电池老化、运维、效率损耗之后其实根本不赚钱。这时候模型帮我们做出了“不调度”的决策本身就是价值所在。我自己的习惯是把老化成本系数做成一个可配置的参数第一次估算先用0.1到0.2元/kWh这个量级等拿到电池厂家具体的循环寿命数据和项目采购价格后再回代校准。这样同一个模型从课程设计到落地项目都能复用不用改任何代码结构。这个项目做到这里你就已经掌握了一个完整的经济调度模型。以后不管遇到光伏、风电、柴油机还是多储能系统建模的逻辑都是一样的列出所有电源和负荷定义决策变量写出目标函数和各类约束然后交给求解器。骨架不变血肉往里面填就行。