上周和一个做园区微网的工程师朋友吃饭,他问我一个特别现实的问题:调度方案里储能电池到底能不能当成“免费调节池”来用?他那边分布式光伏占比超过一半,中午净负荷断崖式下跌,傍晚又直线飙升,只能靠储能顶着。可原来的模型只要发现储能好用,就会拼命用,结果投运不到三年电池容量衰减到80%以下,换电池的钱直接把收益吃掉一大半。这个问题恰好就是高比例可再生能源并网里最扎心的一组矛盾:要灵活性就得让储能频繁出力,要控制成本就必须把衰减建模放进优化目标。
我最近刚照着某篇顶刊论文的方法,用Matlab把一套虚拟电厂多时间尺度调度框架完整复现了一遍,核心就是把储能衰减建模、灵活性量化、弃电惩罚和运行成本全部放进同一个优化问题里,再通过日前、日内、实时三层调度去反复权衡。今天这篇文章就把里面的数学建模、衰减成本折算逻辑、代码骨架和复现过程中踩过的坑全部写出来,特别适合正在做电力系统调度、虚拟电厂运营策略、储能经济性分析的研究生和相关工程师参考。
1. 高比例新能源并网的两难:越灵活越烧钱,越省钱越脆弱
1.1 一个园区微网工程师的真实困惑
先说那个工程师朋友遇到的怪事。他们园区里装了约4MW分布式光伏、2MW风机,外加一套2MWh储能,柴油发电机基本是备用状态。以前净负荷波动小的时候,调度员手工操作也忙得过来,光伏和风机尽量全发,储能只在电价高的时候充放两轮。后来新能源占比提上来,中午光伏大发导致倒送功率逼近变压器上限,调度系统会自动让储能大量充电,傍晚光伏出力快速回落时又要求储能紧急放电撑住负荷。
问题就出在这里:调度策略越“聪明”,储能循环次数越多、放电深度越大。他们做了个统计,储能年等效满循环次数从最初的200次一下子涨到500多次,平均放电深度从40%升到接近80%,第二年电池容量衰减明显加快。工程师自己也清楚,如果不改调度模型,再过一两年就要发生更换储能模组的费用,整个项目的投资回报模型全部推翻。
这其实不是个例。高比例可再生能源并网后,系统净负荷曲线会呈现典型的“鸭型曲线”,爬坡速率非常快,火电、燃气机组往往跟不上,灵活性缺口必须靠储能、可调负荷甚至需求响应来补。可是储能不是“无耗材”的调节资源,每一次充放电都在消耗循环寿命。问题从“能不能调”变成了“调多少次才划算”,于是调度模型必须把储能衰减成本作为一项真实的、可量化的账目放进去。
1.2 复现顶刊模型前,先想清楚“灵活性”是什么
很多人一听到灵活性就说“就是备用容量呗”,其实不够。调度场景里的灵活性,是指在任意时段系统可调资源能够跟随净负荷变化的速率和方向。我们做优化模型时用一个很直接的约束来量化:
[ \sum_i R_i^{up}(t) + R_{ess}^{up}(t) \ge \Delta L_{net}^{up}(t) ]
简单解释:净负荷在某一段时间内突然上升了,那么所有可调机组和储能能在对应时间内增加的出力总和,必须不小于这个上升量,否则就要切负荷;反过来,净负荷突然下降,系统要有能力压低出力,否则就要弃风弃光。这个约束看起来简单,可一旦加入,调度模型就会自动区分哪些时刻灵活性是“紧张的”,哪些时刻是“富余的”。
我习惯把灵活性通俗比作开车。前方路况突然收窄,你既要有动力储备(爬坡能力),又要有刹车冗余(降出力能力),还要保证这些储备在关键时刻真的可用(约束生效)。如果不建灵活性约束,哪怕备用容量设置得很高,也可能出现“备而不用、用而不达”的情况。
1.3 为什么大多数代码复现只复现了“结果”
我读一些复现代码时经常发现,大家把原文的目标函数、约束条件抄得很完整,求解器跑出来的结果也很漂亮,但一到储能寿命部分就含糊了:要么用一个固定折旧率,要么把电池折旧当成线性损耗。结果就是,同样一套调度策略,在论文模型里“总成本最优”,放到真实项目里却因为电池提前报废而亏钱。
原因主要有三个。第一,原文的衰减模型往往嵌入在某个迭代或分段线性化结构里,不像其他约束那样能一眼看清楚,复现时容易跳过。第二,仿真数据随机生成,没有刻意构造不同DOD工况,导致退化模型无法体现效果。第三,有些复现只做了日前调度,没有把多时间尺度滚动机制和衰减迭代耦合起来,等于只复现了半套系统。
所以我这次刻意按照“先建模、再拆解、后编码”的顺序写,把储能衰减如何进入目标函数、如何在滚动调度中迭代更新,完整地讲一遍。如果你也想复现类似论文,直接按这个链路去对号入座。
2. 把调度问题写成数学:虚拟电厂优化模型的主干
2.1 虚拟电厂里到底聚合并控制了什么
虚拟电厂不是一个物理电厂,而是把分布式光伏、风电、储能、可调负荷、小容量燃气机组等分散资源聚合起来,统一参与调度和交易。建模时每种资源都有各自的数学描述:
- 光伏和风电:预测出力上限,可以弃电,弃电有惩罚或机会成本;
- 储能:充放电功率、SOC上下限、充放电效率、循环寿命约束;
- 可调负荷:可平移或可削减,有成本和响应速度限制;
- 燃气/柴油机组:出力上下限、爬坡速率、启动成本和运行成本。
在Matlab代码里,我会把每个资源的变量统一用“时段索引”定义,比如P_g(gen, t)表示第gen台机组在第t时段的出力,SOC(t)表示储能荷电状态。时间分辨率在日前是1小时,日内可以细化到15分钟。把这些变量放在同一个优化问题里,用约束把它们连接起来,就得到了虚拟电厂的“骨架”。
2.2 目标函数:运行成本、电池损耗、弃电与失负荷的四本账
我复现时用的目标函数大概长这样(简写):
[ \min \sum_t \left[ C_{op}(t) + C_{age}(t) + \lambda_{curtail} \cdot P_{curtail}(t) + \lambda_{loss} \cdot P_{loss}(t) \right] ]
第一项C_op是运行成本,包括燃气机组燃料成本、从电网购电成本、储能运维成本;第二项C_age是储能老化成本,也就是这一轮调度中储能循环寿命的折算金额;第三项是弃电惩罚,代表可再生能源没有消纳完;第四项是失负荷惩罚,代表灵活性不足导致负荷损失。
很多人问我这四个账目到底怎么权衡。答案是通过惩罚系数。如果你把弃电惩罚设得特别高,模型会优先消纳新能源,储能会被调用得更频繁;如果你把老化成本系数设得准确,模型又会尽量避免深度充放。调参过程本质上就是在“消纳率、可靠性、储能寿命”三件事之间找平衡点,而这恰恰是标题里“平衡灵活性与储能成本”的核心。
2.3 约束条件里最容易翻车的三个细节
第一,功率平衡方程的符号方向。净负荷等于系统负荷减去新能源出力,但是新能源出力到底是“预测可用出力”还是“实际消纳出力”?很多新手把两者混用,导致弃电变量形同虚设。正确写法是:功率平衡中用的是调度后实际消纳的新能源出力,可用出力 - 实际出力 = 弃电量,这样弃电惩罚才能生效。
第二,SOC的状态转移方程。写成:
[ SOC(t+1) = SOC(t) + \eta_{ch} \cdot P_{ch}(t) \cdot \Delta t - \frac{1}{\eta_{dis}} \cdot P_{dis}(t) \cdot \Delta t ]
要特别注意Δt的单位和功率单位是否一致。如果功率是MW、时间步长是小时,那么充进去的能量就是MWh,可是储能容量单位往往也是MWh,这时直接算没毛病;如果时间步长改成15分钟,就一定要把Δt写成0.25小时,否则SOC每步都会偏差很大。
第三,充放电互斥约束。很多模型允许充电功率和放电功率同时取正数,这样目标函数会通过“充放同时发生”来刷成本,得到无意义结果。要引入二进制变量或线性化约束,确保同一时刻P_ch和P_dis至多一个为正。
2.4 我用的最小算例参数表
为了代码能跑通,我设计了一个规模不大但能体现核心矛盾的系统。参数如下:
| 参数 | 数值 | 说明 |
|---|---|---|
| 系统峰值负荷 | 5 MW | 算例最大值 |
| 光伏装机 | 4 MW | 可弃 |
| 风电装机 | 2 MW | 可弃 |
| 储能额定容量 | 2 MWh | 磷酸铁锂类 |
| 储能最大功率 | 0.5 MW | 充放同值 |
| 充放电效率 | 0.95 | 双向 |
| 储能初始SOC | 0.5 | 百分比 |
| 燃气机组容量 | 1 MW | 爬坡0.3 MW/h |
| 时间段数 | 96 | 15分钟一点 |
| 弃电惩罚系数 | 0.3 货币单位/kWh | 相对较高 |
| 失负荷惩罚系数 | 5 货币单位/kWh | 远高于运行成本 |
这个参数表看起来很朴素,但跑出来的结果能很清楚地看到灵活性约束什么时候起作用,储能老化项什么时候改变调度决策。
3. 储能衰减建模:一道绕不过去的“寿命税”
3.1 衰减为什么会被调度模型漏掉
储能衰减之所以经常被忽略,是因为它在短期内“看不见”。运行成本、购电成本每小时都在发生,而电池寿命衰减是几个月甚至几年后才显现的,优化模型天然喜欢把看不见的成本当成零。问题是高比例新能源并网后储能会成为灵活性主力,每天几百次循环,衰减速度远远超出预期。
我跟踪过一组仿真数据:如果不考虑老化成本,储能在净负荷波动最大的场景下几乎每天都是“满充满放”,SOH以一个夸张的速度下滑;把老化成本加入目标函数后,模型自动把部分高成本深度放电换成燃气机组出力和负荷侧响应,储能的等效循环次数下降了接近30%,总运行成本略高但全生命周期成本明显降低。这就是“寿命税”的作用:让调度决策者看见远期代价。
3.2 等效循环次数与充放电深度(DOD)的计算方式
要计算储能老化,先得把不规则的充放电行为折算成等效循环次数。工程上最常用的做法是:
[ N_{eq} = \frac{\sum_t P_{dis}(t) \cdot \Delta t}{E_{rated}} ]
即把一段时间内累计放电量除以额定容量,得到的数值就是这段时间的等效满循环次数。这个指标简单、透明,很适合放进调度模型里做线性处理。但问题是它没有考虑放电深度DOD的影响。
DOD对寿命的影响不是线性的。同样放1 MWh电,分成10次浅放和分成2次深放,对电池寿命的伤害完全不同。大量实验数据能拟合出循环寿命与DOD的近似关系:
[ L_{cycle}(DOD) = a \cdot DOD^{-p}
其中`a`和`p`是电池特性参数,典型范围`p`在0.8到1.5之间。从公式能看出,DOD越高,允许的循环次数越少,而且是加速变少。这就是为什么我在目标函数里不能只放一个固定循环次数,而是要把每一次充放电的DOD折算成对应的寿命消耗。 具体做调度优化时,DOD和决策变量耦合后模型会变成非线性。我的处理办法是分段线性化:把DOD分成几个区间,每个区间用不同的线性老化系数逼近,然后引入分段插值约束。这样既能保留“深度放电更伤电池”的核心特征,又不会把求解速度拖垮。 ### 3.3 把SOH变化翻译成目标函数里的货币量 更精细的做法是建一个SOH状态变量,让它随调度决策逐步下降: \[ SOH(t+1) = SOH(t) - \frac{N_{eq}(t)}{L_{ref}} \cdot k_{stress} \] `L_ref`是某个参考工况下的额定循环寿命,`k_stress`是考虑DOD、温度等因素的修正系数。当SOH降到80%时,一般认为电池寿命终结,需要更换或退役。 但调度模型不能直接用SOH做目标,还要把SOH损失换算成钱。我的做法是在每次调度前算一个“平均老化成本系数”: - 假设更换整组储能需要`C_replace`; - 在参考DOD下电池总循环次数为`L_ref`; - 那么每个等效满循环的老化成本近似为 `C_replace / L_ref`; - 再把每时段的放电量除法折算成“等效循环数”,乘上该成本,得到`C_age(t)`。 举个例子:如果电池更换成本是100万元,参考条件下能循环4000次,那么每个等效满循环的寿命折旧就是250元。某次调度让储能多放了0.5 MWh,额定容量2 MWh,则等效循环数是0.25,对应老化成本就是62.5元。每15分钟都算一笔账,目标函数自然不敢乱用储能。 ### 3.4 加入衰减项后,灵活性-成本曲线开始真正被“看见” 我做一个实验,在同样的新能源出力曲线下,把老化成本系数从0逐步调到实际值,再记录系统的弃电率、储能循环次数和总成本,能看到一条典型的“权衡曲线”:老年化系数刚开始上升时,调度会转向燃气机组,弃电率稍微上升,但总成本下降,这是因为减少的电池更换费用比多烧的气费还要明显;随着系数继续增大,储能几乎不再被调度,灵活性缺口只能靠更高弃电和少量失负荷来弥补,总成本又开始上升。 这条曲线的转折点,就是“灵活性-储能成本”最优平衡点。很多顶级论文复现的最终价值并不是得到某个固定解,而是能画出这条曲线并解释每个转折背后的物理原因。我在Matlab里只需要循环调用优化求解器,每次修改老化系数,就能把这条曲线完整描出来。 ## 4. 多时间尺度调度:日前、日内、实时到底怎么配合 ### 4.1 为什么要拆成三个时间尺度,而不是一个尺度跑到底 新能源预测误差随着时间尺度的延长急剧变大。提前24小时预测的光伏出力,可能和实际差30%以上;提前4小时预测,误差能降到10%左右;到了实时分钟级,误差相对小很多。如果把所有决策都压在日前一步做完,一旦预测不准,就会因为机组启停不够、储能SOC预留不当,在运行中出现灵活性缺口。 多时间尺度调度的思路是把决策分层:日前决定“哪些机组开、哪些不开”,日内用滚动窗口去修正“每台机组出多少、储能充放多少”,实时再做最后的偏差纠正。这样每一层只决策它能决策好的事,整体鲁棒性会强很多。 ### 4.2 滚动时域控制的基本信息流 我在Matlab里用的是非常标准的滚动时域控制,流程可以概括成四步: 1. 在时刻`t0`获取最新预测曲线,覆盖`t0`到`t0+H`; 2. 求解从`t0`到`t0+H`的优化问题; 3. 只执行第一步的调度指令,例如只下发`t0`到`t0+ΔT`的储能功率; 4. 到了`t0+ΔT`,更新预测,重新执行第1步。 这四步循环起来,日内调度就能跟随最新信息不断修正。代码结构也很简单,`for`循环加一个`solveWindow`函数即可。关键在于每轮滚动之后,储能SOC要传下去作为下一轮的初始状态,否则计划会整体漂移。 ### 4.3 跨尺度计划如何对齐,避免指令“打架” 我一开始做滚动调度时踩过一个很蠢的坑:日前计划让机组在晚上20点停机,但日内预测发现20点负荷上升,滚动优化又把机组重新启停,结果启停成本被算了两次,调度指令前后矛盾。后来我采用两种方式解决: 第一,把日前确定的整数变量(机组启停、储能是否深度充放区间)锁定为硬约束,日内只优化连续变量。这种方法牺牲一点日内灵活性,但保证了计划的稳定执行。第二,在日内目标函数里加一个“追踪日前计划”的软惩罚项: \[ \min \sum_t \left[ C_{op}(t) + C_{age}(t) + \beta \cdot \left( P(t) - P^{DA}(t) \right)^2 \right] \] 系数`β`取一个合适的值,让日内设备出力尽量贴近日前计划,除非遇到特别大的预测偏差才能偏离。储能成本在不同时间尺度里也要注意重复计算:如果在日前已经把未来24小时的老化成本都算过了,日内滚动就应该只计算“新增的、超过日前预计”的等效循环部分,否则相当于给储能寿命算了两次账,成本偏高。 ## 5. Matlab复现的代码骨架与完整流程 ### 5.1 数据准备:96点曲线和参数表 我建议用`struct`把算例参数集中管理,别散落在脚本各处。例如: ```matlab % 基础参数设置 mpc = struct(); mpc.T = 96; % 15分钟一个点,共24小时 mpc.dt = 0.25; % 时间步长,小时 mpc.Pload = loadProfile(1:96); % 负荷曲线,单位MW mpc.Ppv = pvProfile(1:96); % 光伏预测出力上限 mpc.Pwt = windProfile(1:96); % 风电预测出力上限 mpc.Erated = 2; % 储能额定容量,MWh mpc.Pmax = 0.5; % 储能最大功率,MW mpc.eta = 0.95; % 充放电效率 mpc.SOC0 = 0.5; % 初始SOC mpc.curtailPrice = 0.3; % 弃电惩罚 mpc.lossPrice = 5; % 失负荷惩罚 mpc.replaceCost = 1e6; % 更换储能成本 mpc.Lref = 4000; % 参考循环寿命负荷和新能源曲线我是先用正弦叠加随机扰动生成的。这样做的好处是曲线形状可控,能突出净负荷陡升陡降的区间;缺点是预测误差分布不够真实。你迁移到真实项目时,直接从数据中台导出CSV替换即可。
5.2 日前调度模型怎么落地
我用YALMIP搭建优化模型,因为它写约束比手拼矩阵容易读很多。核心代码如下:
%% 定义决策变量 P_g = sdpvar(1, mpc.T); % 燃气机组出力 P_ch = sdpvar(1, mpc.T); % 储能充电功率 P_dis = sdpvar(1, mpc.T); % 储能放电功率 SOC = sdpvar(1, mpc.T+1); % 荷电状态 P_cur = sdpvar(1, mpc.T); % 弃电功率 P_loss = sdpvar(1, mpc.T); % 失负荷功率 z = binvar(1, mpc.T); % 充放电互斥变量,1表示充电 %% 约束条件 Constraints = []; % 功率平衡:负荷+充电 = 光伏+风电+燃气+放电+购电 Constraints = [Constraints, ... mpc.Pload - P_pv_used - P_wt_used - P_g - P_dis + P_ch + P_loss == 0]; % SOC状态转移 Constraints = [Constraints, ... SOC(2:end) == SOC(1:end-1) + mpc.eta * P_ch * mpc.dt ... - P_dis / mpc.eta * mpc.dt]; % 充放电互斥与功率限制 Constraints = [Constraints, ... 0 <= P_ch <= mpc.Pmax * z, ... 0 <= P_dis <= mpc.Pmax * (1 - z)]; % SOC上下限 Constraints = [Constraints, 0.2 <= SOC <= 0.9, SOC(1) == mpc.SOC0]; %% 目标函数 C_op = sum(P_g * gasPrice + P_ch * omPrice + P_dis * omPrice); C_cur = sum(P_cur * mpc.curtailPrice); C_loss = sum(P_loss * mpc.lossPrice); N_eq = sum(P_dis * mpc.dt) / mpc.Erated; % 等效循环 C_age = N_eq * mpc.replaceCost / mpc.Lref; Objective = C_op + C_age + C_cur + C_loss; %% 求解 ops = sdpsettings('solver', 'auto', 'verbose', 0); sol = optimize(Constraints, Objective, ops);这里要注意P_pv_used和P_wt_used不能直接用预测上限,要额外定义,同时加约束:
P_pv_used = mpc.Ppv - P_cur_pv; Constraints = [Constraints, 0 <= P_cur_pv <= mpc.Ppv];这样弃电变量才真正进入模型。
5.3 日内滚动和实时修正的循环结构
日内滚动我写成一个循环,每次只更新窗口数据并求解。伪代码如下:
mpc.T_window = 24; % 滚动窗口长度,比如6小时 mpc.T_step = 1; % 每步执行1个点 for k = 1:mpc.T_step:mpc.T % 截取从当前时刻开始的预测窗口 idx = k:min(k+mpc.T_window-1, mpc.T); data_window = prepareWindow(mpc, idx); % 求解窗口优化问题,日前整数变量锁定 [plan, SOC_next] = solveWindow(data_window, fixed_int); % 只执行第一步调度 dispatch(k) = plan(1); % 更新储能SOC和系统状态 mpc.SOC0 = SOC_next; end滚动优化的关键是要把“窗口末尾SOC可自由变化但需要在最终时刻回到合理区间”这件事处理好。我在目标函数里加了一个终值约束或惩罚:
Constraints = [Constraints, SOC(end) >= mpc.SOC0 - 0.05];避免前几个窗口疯狂放电,后面无电可用。
5.4 衰减迭代更新SOH的实现细节
衰减迭代我没有放进单次优化里,因为那样会把DOD非线性直接塞给求解器,速度很慢。我的做法是“调度-更新SOH-再调度”的外层迭代:
SOH = 1.0; for iter = 1:maxIter % 用当前SOH修正老化成本系数 mpc.cycleCost = (mpc.replaceCost / mpc.Lref) / SOH; % 执行日前和滚动调度 [result] = runMultiTimeScale(mpc); % 根据实际充放电历史更新SOH N_eq_total = sum(result.P_dis) * mpc.dt / mpc.Erated; SOH_new = SOH - N_eq_total / mpc.Lref * stressFactor(result); if abs(SOH_new - SOH) < 1e-4 break; end SOH = SOH_new; end内层调度是线性优化,外层更新SOH是迭代修正。这样既保住了求解速度,又让老化成本系数随电池健康状态逐步变化,比固定寿命折旧要真实得多。实测时两三轮迭代就能收敛。
5.5 三种方案的结果对比
我跑了三个版本的模型作对比,结果很有说服力:
| 方案 | 年等效循环次数 | 弃电率 | 年化运行成本 | 储能更换成本 |
|---|---|---|---|---|
| 不建衰减模型 | 约520次 | 4.1% | 低 | 极高,第3年触发更换 |
| 固定折旧系数 | 约430次 | 5.2% | 中 | 中,寿命约5年 |
| 动态SOH迭代+滚动 | 约360次 | 5.8% | 中高 | 低,寿命约7年 |
动态方案放弃了一点弃电率,换来储能寿命几乎翻倍,把全生命周期总成本拉到最低。这组数据说明,只盯“当前运行成本”的调度方案在高比例新能源场景下很容易自欺欺人。复现论文的真正价值就是让这种长期成本显性化。
6. 实测中的坑与迁移方法
6.1 我踩过的三个典型坑
第一个坑发生在SOC状态转移上。我把dt直接写成1,后来换到15分钟数据忘了改,结果SOC每步都过冲,第二天直接越界。现在所有时间相关参数都从mpc.dt引用,再也不手动填数。
第二个坑是充放电互斥约束。最开始漏了z变量,求解器钻空子让P_ch和P_dis同时为0.2MW,目标函数里老化成本被无数倍的循环次数刷爆,结果调度结果完全不可解释。加上二进制变量后,模型才恢复正常。
第三个坑出现在滚动窗口目标函数。如果只让SOC>=0.2,不限制终值,前几个窗口会尽可能放电,等净负荷高峰时SOC已经偏低,后面会频繁弃电。这相当于“寅吃卯粮”。后来我在滚动窗口的末尾加软约束,才把调度曲线拉回合理区间。
6.2 从“能跑”到“跑得稳”的三次迭代
第一次跑通代码时,结果很漂亮,但把储能循环次数一统计,等效循环高得吓人,因为模型为了压低运行成本,让储能几乎包办所有爬坡。这就是缺乏衰减建模的典型症状。
第二次加入固定老化成本系数后,储能使用明显收敛,但电池实际劣化速度并非恒定,固定系数无法反映后期电池加速老化的规律。
第三次把动态SOH迭代和滚动窗口耦合后,调度策略才真正稳定下来:储能浅充浅放,燃气机组承担基荷,弃电率虽然略升,但全寿命成本最优。每次调参数时,我都习惯先把老化系数和灵活性惩罚系数画成二维扫参图,先看清趋势再定参数。
6.3 把这段代码迁移到你的项目前要改什么
如果你的项目有真实负荷和新能源预测数据,第一步是替换loadProfile、pvProfile、windProfile三个函数的返回值,同时检查时间分辨率是否一致。如果原始数据是5分钟颗粒度,建议先按15分钟聚合,别直接塞进模型。
如果虚拟电厂里还有温控负荷、电动汽车充电桩,适当增加对应的功率上下限和可调量约束即可。新增资源时要同步修改:变量定义、约束拼接、成本项、灵活性供给项,四处缺一不可。尤其注意别把新增资源只加进约束,忘了加进灵活性表达式,否则会出现“能出力但不算备用”的矛盾。
如果想把代码从研究环境搬到生产环境,建议把求解器从通用求解器换成适合嵌入式部署的轻量MILP求解器,并将滚动窗口从6小时压缩到2小时,减少单次求解时间。模型精度会有少量下降,但实时性会好很多。
复现完这套模型后,我最大的感受是:储能衰减不是给调度“添麻烦”,而是帮调度看清真实的账。以前我也习惯把电池当大号电容用,直到看见SOH迭代后储能主动从深度放电退回到浅充浅放,才发现顶刊论文里那些复杂的建模,本质上都是在回答一个朴素的问题——怎么让系统在新能源高占比下既保持灵活,又不让未来为今天买单。如果你也正被“多装电池还是少用电池”卡住,我建议先别急着改电池配置,把衰减建模加进调度目标函数里跑一遍,你会看到不一样的答案。