做楼宇微网调度有一件事让我印象很深:某园区办公楼可用的配电容量只剩不到300kW,想再增加充电桩和实验室负荷,电气负责人第一反应是上一套100kW/200kWh的磷酸铁锂储能柜。供应商报价接近80万,算上电芯衰减、消防改造和EMS调试,峰谷价差收益一年只有不到8万,静态回收期接近十年。后来我们把思路从“铁柜子”挪到楼里的空调、蓄冷蓄热水箱和新风机组上,用需求侧的虚拟储能系统去承担大部分削峰填谷工作,整体改造费用几乎可以忽略,调度效果却不输给一套中小型实体储能。这就是本文想聊的融合需求侧虚拟储能系统的楼宇微网优化调度,以及我手头一直在用的Matlab实现流程。
这类问题在工程里非常常见:楼宇微网已经装了光伏,可能也装了少量电池,但真正能落地的收益往往不在于多买几组电芯,而是把“死负荷”变成“活资源”。本文不会只停留在概念层面,我会从物理模型、数学优化、Matlab代码、算例对比到调试踩坑完整过一遍,给出一份可以直接复现和改用的调度方案。如果你正在做园区微网、综合能源或者建筑节能相关的优化调度,这篇内容应该能帮你少走不少弯路。
1. 从“储能不够”到“虚拟储能”:楼宇微网调度的现实困境
虚拟储能这个词听着玄,拆开看其实很朴素。传统的楼宇微网调度,核心是在光伏出力、电网购电、电池充放电、负荷用电之间做功率平衡。这里面的“调”字是重点:光伏出力不可控,负荷需求又跟着人员作息走,电网分时电价下午两点贵、凌晨两点便宜,如果楼宇没有足够的储能,峰时只能硬着头皮高价买电,谷时只能看着光伏或电网便宜电白白浪费。
实体储能可以解决“时移”问题,但它的成本结构决定了在很多楼宇场景下并不可行。我曾经算过一笔账:一套落地的工商业储能系统,除了电芯和PCS之外,还要配并网柜、隔离变压器、消防系统、监控屏、施工费、设计费,单位瓦时成本远高于电芯报价本身。而且楼宇微网的负荷特点是“有人才有高峰”,办公园区一年中有大量非工作日,实体储能就会在那段时间闲置。更麻烦的是,很多老旧楼宇变压器余量有限,储能系统要增加并网容量,需要重新做供电方案,这一环就能卡住项目几个月。
虚拟储能的思路完全不同。楼宇里大量的用电设备本身就有蓄能或热惯性属性,比如中央空调的蓄冷水箱、蓄热电锅炉的水箱、风机盘管带来的建筑围护结构热容。这些设备在运行时本来就在“存能量”或“释放能量”,只是没有被纳入调度视野。把它们当成一组可以充放电的“虚拟电池”,让它在电价低谷时多耗电蓄冷/蓄热,在电价高峰时少耗电释放冷/热量,效果和实体电池“低谷充电、高峰放电”几乎一样,且不需要新增任何电化学设备。
我把这类资源的本质总结为一句话:实体储能搬的是电能,虚拟储能搬的是用电行为。空调提前两个小时开,把楼板、墙体、水箱的温度降下来,等电价进入高峰段时下调制冷功率,室内的冷量短时间不会明显反弹,这就是一种“负荷转移”。对电网来看,楼宇在高峰时段的取电功率实实在在下去了,且整个过程的能量没有凭空消失,只是利用了设备蓄热能力和建筑热容来做缓冲。
这里有一个容易被忽略的点:虚拟储能并不创造能量,它做的是在不降低用户体验的前提下,把用电行为在时间轴上平移。这个“不降低体验”的边界,恰恰是优化模型里最关键的约束。比如室内温度允许在24-26℃之间浮动,蓄冷水箱温度允许在4-7℃之间变化,这就是舒适度约束和蓄能状态约束。把这些边界量化进目标函数,就是完整的虚拟储能建模。
2. 虚拟储能的数学建模:把空调和水箱装进优化模型
很多初学者看到“虚拟储能”会觉得这只是一个商业概念,没法写进优化模型。其实它的建模完全可以类比电化学储能:用等效充电功率、等效放电功率、储能状态、能量上下限、爬坡约束来描述。只不过对象从电池变成了冷量、热量和用能行为。
2.1 统一用“等效SOC”表达各类受控负荷
要做到在一个模型里同时处理蓄冷水箱、空调热惯性、可平移负荷,最省事的办法是为每类资源定义一个等效SOC和一套充放能功率。等效SOC的递推方程可以统一写成:
E(t+1) = eta_s * E(t) + P_ch(t) * eta_ch - P_dis(t) / eta_dis其中E(t)表示t时刻该资源的等效储能水平,P_ch和P_dis分别为充电(蓄能)和放电(释能)功率,eta_s是自损耗系数,eta_ch和eta_dis是充放能效率。约束上再加:
0 <= E(t) <= E_max 0 <= P_ch(t) <= P_ch_max 0 <= P_dis(t) <= P_dis_max这组式子和电池储能模型几乎没有区别,区别只在P_ch和P_dis在物理世界对应的具体动作。对蓄冷水箱来说,P_ch对应制冷机组的额外制冷功率,把水箱里的水从7℃降到4℃;P_dis对应高峰时段利用水箱冷水供冷,少开制冷机组。对于建筑的围护结构热容来说,P_ch对应低谷时段让室内温度更低一些,P_dis对应高峰时段允许室内温度往上漂移,从而减少当前制冷输入。
2.2 蓄冷蓄热水箱的储放能模型
蓄冷水箱是虚拟储能里最“硬”的一类资源,因为它的能力边界接近实体储能,且控制手段成熟。对一个容量为V立方米的水箱,可用冷量与水温差的关系是:
Q_available = rho * Cp * V * (T_return - T_supply)如果冷冻水供水温度范围是4-7℃,回水温度12℃左右,那么一个100m³的水箱,可用冷量大约在1200-2400 kWh之间。这个量级已经比很多楼宇配的电池容量大得多。
在优化模型里,我会把蓄冷水箱的SOC直接用可用冷量来定义,单位用kWh,而不是用百分比。这样目标函数里的成本计算能直接和电价相乘。蓄冷工况下,主机多出力裕度P_ch受冷水机组额定制冷量限制;放冷工况下,P_dis受板换器或二次泵的最大供冷能力限制。这些参数在Matlab代码里都以结构体字段存在,便于统一读入。
2.3 空调热惯性与室内温度的可调区间
空调负荷占楼宇用电的比例通常在40%以上,是虚拟储能里潜力最大的一块。空调热惯性的建模我用一阶等效热参数模型,它描述的是室内温度变化与制冷功率、室外温度之间的关系:
C_b * dT_in/dt = (T_out - T_in) / R_b + P_cool其中C_b是建筑热容,R_b是围护结构热阻,P_cool是制冷功率。对离散化后的模型做改写,可以得到室内温度和一小时制冷功率的递推关系。在调度模型中,我不会要求室内温度严格盯在设定值,而是给定一个舒适度窗口,比如夏季24-26℃。低谷电价时让T_in往24℃靠,高峰电价时允许它漂到26℃。光这一步,在典型办公楼里就能转移10%-20%的空调峰值功率。
单独把室内温度作为变量放进模型会引入额外的计算量,实践中的做法是创建一个虚拟储能对象去封装它:把“当前室内温度距下限的可下调空间”映射为等效SOC,把“允许室内温度上升”映射为等效放电功率。这样空调热惯性的逻辑就能和蓄冷水箱完全对齐,不用在约束里直接写温度动态微分方程。
2.4 可平移/可削减负荷的灵活性参与方式
除了蓄冷蓄热和空调惯性,楼宇里还有一类负荷叫可平移负荷,比如洗衣房、充电桩、实验室可延迟设备。它们的特征是总用电量固定,但用电时间可以调整。建模方式是在优化中引入日用电总量守恒约束:
sum(P_flex_shift(t)) = E_flex_total同时限制每个时段允许工作的上下限。还有一类可削减负荷,比如景观照明、非关键办公设备,在需求响应时可以切断,对应的就是时段最大功率限制的动态调整。
需要提醒的是,可平移负荷的建模容易过度乐观。因为实际运行中的楼宇用户不会愿意把所有洗衣任务排到凌晨三点。我的经验是:能够进入优化模型的可平移负荷,必须是管理者有明确控制权的设备,且用户侧可接受窗口要提前确认。调度模型可以做得很漂亮,但如果把不可控负荷硬写成可控,日内运行一定会出问题。
3. 融合虚拟储能的微网日前优化调度模型
模型是整个方案的心脏。这套调度模型我按日前优化的思路来做,时间区间为24小时,时间分辨率为1小时。也做过15分钟粒度的版本,但考虑到虚拟储能的热惯性时间常数较长,1小时粒度在运行稳定性和求解速度上更有优势。
3.1 典型场景与基础配置
以一个典型办公园区微网为例,拓扑结构包括:光伏、电网公共连接点、电池储能、蓄冷水箱、多台空调冷水机组、常规电负荷。为了保持模型可读性,我做了几项简化:光伏和负荷按预测值输入;电池储能只考虑能量约束和功率约束,不细化到电芯温度;空调系统只建模蓄冷水箱和室内温度变化,不做水力管网仿真。
| 资源对象 | 关键参数 | 数值 | 说明 |
|---|---|---|---|
| 光伏 | 峰值功率 | 300 kW | 按日前预测曲线输入 |
| 电池储能 | 容量 | 200 kWh | 最大充/放功率80 kW |
| 电池储能 | 充/放效率 | 0.95 | 统一按单程效率折算 |
| 蓄冷水箱 | 可用冷量上限 | 1500 kWh | 等效SOC定义在冷量维度 |
| 蓄冷水箱 | 最大充放冷功率 | 200 kW | 对应制冷机可调裕度 |
| 空调热惯性 | 等效容量 | 600 kWh | 由建筑热容折算 |
| 分时电价 | 峰/平/谷 | 1.12/0.68/0.35 元/kWh | 峰时段10-16、18-22点 |
这套参数来自我对多个类似项目的数据核对,不是精确到某个特定楼宇,但量级对办公楼是比较典型的。实际使用时,需要把真实项目的负荷特性和设备铭牌参数替换进去。
3.2 目标函数里三笔钱怎么算
调度目标我选择最小化系统日运行总成本。主要包含三部分:电网购电费用、电池充放电损耗折算、舒适度偏差惩罚。
min sum_t(price(t)*P_grid(t)*dt) + sum_t(lambda_bat*(P_bat_ch(t)+P_bat_dis(t))*dt) + sum_t(lambda_comf*(d_temp_plus(t)+d_temp_minus(t))*dt)第一项是电网购电成本,也是最核心的成本。price(t)按峰平谷分段,P_grid是楼宇从电网取电的功率。第二项是电池损耗,用充放功率的一次函数近似。第三项是舒适度惩罚,d_temp_plus和d_temp_minus表示室内温度超出舒适度窗口的偏差量。这个惩罚不是简单用一个大数禁止越界,而是保留一定的软化空间,避免模型因为温度约束过紧而找不到可行解。
从实际效果看,舒适度惩罚系数lambda_comf的取值很关键。太小,模型会为了省电钱把室内温度拉得很高,用户投诉;太大,温度就死死钉在设定值上,空调柔性完全发挥不出来。经验做法是在夏季取舒适度每偏差1℃的等效成本约等于峰时电价的2-3倍,作为初始值,然后根据仿真结果微调。
3.3 关键约束:功率平衡、SOC递推、充放互斥、温度窗口
约束条件是MILP模型的主干。我按四条线组织:
功率平衡约束,这一条保证任意时刻微网内部功率守恒。光伏出力加电网购电加电池放电,等于常规电负荷加电池充电加虚拟储能充电功率减去虚拟储能放电功率。
P_pv(t) + P_grid(t) + P_bat_dis(t) = P_load_base(t) + P_bat_ch(t) + P_vs_ch(t) - P_vs_dis(t)P_vs_ch和P_vs_dis是虚拟储能的充放能功率。把“减去P_vs_dis”放在负荷侧,含义是虚拟储能释放能量等效代替了实际用电功率,这是本例中不会出现能量凭空消失的关键写法。
电池SOC递推约束,与2.1节类似,但增加了充放互斥的整数变量。电池充电和放电状态用两个二进制变量X_ch和X_dis标识,强制约束X_ch+X_dis<=1,并且功率上限通过大M法关联:
P_bat_ch(t) <= M * X_ch(t) P_bat_dis(t) <= M * X_dis(t)不加这个互斥约束的话,求解器很可能给出“同时充电和放电”的荒唐结果:有功功率对消,SOC不变,但目标函数里白白多算损耗,结果失真。虚拟储能对象的SOC递推和功率约束同样要写,公式和电池一致,只是效率、上下限、爬坡率参数不同。
温度窗口约束,对应空调热惯性对象。用离散化的一阶热参数模型建立室内温度逐时递推,然后将舒适度窗口写成不等式:
T_in_min - d_temp_minus <= T_in(t) <= T_in_max + d_temp_plusT_in_min和T_in_max是舒适度边界,d_temp变量是松弛量。温度递推公式里的制冷功率要和虚拟储能对象的总充放能功率关联,这样空调的电耗变化才真正反映到电网购电功率上。
电网交互功率约束,还要求P_grid在变压器允许范围内,通常设下限为0(不向电网倒送电),上限为变压器最大受电容量。如果当地允许余电上网,可以在模型里把下限改为负值,但购电价格与上网价格不同,需要再引入0/1变量区分买卖状态。
3.4 模型类型为什么是MILP,以及如何线性化
这个模型是混合整数线性规划,原因是里面同时存在连续变量和0/1整数变量。整数变量的来源有两个:电池充放互斥和变压器购售电状态区分。其他所有功率、SOC、温度变量都是连续变量。MILP模型最直接的好处是能保证全局最优,并且主流的商业求解器处理MILP已经非常成熟。
舒适度惩罚项里如果直接写绝对值,函数是非线性的。标准线性化手法是拆成两个非负变量之和:
T_dev(t) = d_temp_plus(t) - d_temp_minus(t) d_temp_plus(t) >= 0 d_temp_minus(t) >= 0目标函数里用的惩罚项就是这两个变量的和。价格分段不是连续阶梯时,同样可以通过引入辅助分段变量做线性化。Yalmip的sum和reshape语法让这些处理变得非常直观,这也是我选Matlab做原型验证的原因。
4. Matlab+Yalmip代码实现与关键片段解析
Matlab是整个方案建模和验证的主阵地。我用Yalmip做建模层,求解器用Cplex或Gurobi,整个流程从数据输入到结果输出不到200行核心代码。下面按模块拆开讲。
4.1 数据准备:负荷、光伏、分时电价怎么结构化
数据准备阶段最忌讳的是把数值散落在Matlab工作区里。我习惯把所有时序数据放在一个结构体里,这样后续做参数改动、方案对比时不会搞混。
num_t = 24; dt = 1; price = [0.35*ones(1,7), 0.68*ones(1,3), 1.12*ones(1,6), ... 0.68*ones(1,2), 1.12*ones(1,4), 0.68*ones(1,2)]'; load_base = [140,130,125,120,115,118,150,260,380,420,450,470, ... 430,410,445,460,480,420,390,360,310,280,220,180]'; pv_power = [0,0,0,0,10,60,150,220,270,290,300,285, ... 240,220,180,120,60,20,0,0,0,0,0,0]'; data.price = price; data.load_base = load_base; data.pv_power = pv_power;这里load_base是楼宇的基础电负荷,不含空调制冷电耗。空调制冷电耗会在约束中通过虚拟储能充放功率体现。这样拆分的好处是:如果把空调负荷直接算进基础负荷里,P_vs_ch和P_vs_dis就没有挂接点了,虚拟储能也就无从建模。
4.2 变量定义:连续决策量、整数决策量、复合量怎么创建
Yalmip的变量创建几乎和数学符号完全一致。我按连续变量和整数变量分组定义,方便后面约束和结果提取。
P_grid = sdpvar(num_t,1); % 电网购电功率 P_bat_ch = sdpvar(num_t,1); % 电池充电功率 P_bat_dis = sdpvar(num_t,1); % 电池放电功率 soc_bat = sdpvar(num_t+1,1); % 电池SOC soc_vs = sdpvar(num_t+1,1); % 虚拟储能SOC P_vs_ch = sdpvar(num_t,1); % 虚拟储能充电功率 P_vs_dis = sdpvar(num_t,1); % 虚拟储能放电功率 T_in = sdpvar(num_t,1); % 室内温度 d_temp_plus = sdpvar(num_t,1); d_temp_minus = sdpvar(num_t,1); X_ch = binvar(num_t,1); % 电池充电状态 X_dis = binvar(num_t,1); % 电池放电状态soc_bat和soc_vs定义成num_t+1维,是为了让第1个元素表示调度开始前的初始SOC,第25个元素表示一天结束后的SOC。这样做的好处是最终结果可以直接检查“日末SOC是否回到合理区间”,方便做能量守恒校核。
4.3 虚拟储能SOC递推与充放互斥约束的Yalmip写法
电池和虚拟储能的状态递推写成约束集合。以电池为例:
Constraints = []; Constraints = [Constraints, soc_bat(1)==0.2*cap_bat]; Constraints = [Constraints, soc_bat(2:end)==soc_bat(1:end-1) ... + (eta_bat_ch*P_bat_ch - P_bat_dis/eta_bat_dis)*dt]; Constraints = [Constraints, 0.1*cap_bat <= soc_bat <= 0.9*cap_bat]; Constraints = [Constraints, P_bat_ch <= M*X_ch]; Constraints = [Constraints, P_bat_dis <= M*X_dis]; Constraints = [Constraints, X_ch + X_dis <= 1];这里M取值要略大于电池最大功率上限,取100就够了。这个约束表达方式对Yalmip来说非常自然,它会自动把整数变量和连续变量的关联转换成标准MILP格式。
虚拟储能对象的递推写法完全复刻电池,效率稍微不同:
Constraints = [Constraints, soc_vs(1)==0.2*cap_vs]; Constraints = [Constraints, soc_vs(2:end)==soc_vs(1:end-1) ... + (eta_vs_ch*P_vs_ch - P_vs_dis/eta_vs_dis)*dt]; Constraints = [Constraints, 0.15*cap_vs <= soc_vs <= cap_vs]; Constraints = [Constraints, 0 <= P_vs_ch <= rate_vs_ch]; Constraints = [Constraints, 0 <= P_vs_dis <= rate_vs_dis];温度递推约束我单独封装成了一个函数,输入是室外温度序列、制冷功率和初始室内温度,输出就是一组逐时温度等式约束。制冷功率P_cool与P_vs_ch、P_vs_dis的关系为:
P_cool = P_cool_base + P_vs_ch - P_vs_dis;其中P_cool_base是维持室温在设定点的基准制冷电耗。这样虚拟储能充电时,空调多耗电把冷量存起来;放电时,空调少耗电用水箱冷量或热容量供冷。逻辑闭环,模型不会出现“无中生有”的能量。
4.4 求解器调用与结果输出
模型组装完成后,直接调用Yalmip的optimize函数:
ops = sdpsettings('solver','cplex','verbose',1, ... 'showprogress',1, 'savesolveroutput',1); diagnostic = optimize(Constraints, Objective, ops); if diagnostic.problem == 0 P_grid_val = value(P_grid); P_bat_ch_val = value(P_bat_ch); P_bat_dis_val = value(P_bat_dis); soc_vs_val = value(soc_vs); T_in_val = value(T_in); else yalmiperror(diagnostic.problem); end结果我习惯直接对比三张图:电网交互功率曲线、电池和虚拟储能的充放能曲线、室内温度曲线。诊断信息里如果出现Infeasible problem,不要慌,通常是三件事:SOC初始值设定不合理、功率平衡约束方向写反、或者某个上限参数为0。排查方法我放在第6节详细讲。
5. 算例结果对比与调度行为分析
算例先把“无虚拟储能”和“含虚拟储能”两种方案分别求解,再对比结果差异。这是一个最有说服力的项目交付方式,也是我每次给业主汇报时都用的展示逻辑。
5.1 交互功率曲线对比:削峰效果是直接证据
无虚拟储能的方案里,空调只在需要时启动,不受电价引导,楼宇在10-16点这个时段从电网取电功率基本跟着基础负荷走,峰值大约在560kW左右。含虚拟储能后,系统会在凌晨2-6点的谷价时段启动“充能模式”,让制冷机组多出力,把冷水机组生产的大量冷量蓄进水箱和建筑热容;到了10-16点峰价时段,P_vs_dis开始释放冷量,制冷机组的实时电耗大幅下降,楼宇从电网取电功率明显压低,峰值降到430kW附近。
这个130kW左右的削峰量完全来自需求侧,不需要增配任何实体电池。换算成变压器容量价值,按需量电费16元/kW·月来算,一年光是降需量费就能省两万多元,而且这是每个月都发生、不随时间衰减的收益。
5.2 成本明细:峰时购电和谷时蓄能之间的账
从成本结构看,含虚拟储能的方案一天总成本比无方案下降大概15%-20%。下降的核心动因是峰时段购电量的削减。分时电价场景下,峰时电价1.12元/kWh,谷时只有0.35元/kWh,谷时蓄能虽然增加了一些低谷购电,但谷电价格只有峰电的三分之一,只要转移过程存在效率损失,转移量越大节省越明显。蓄冷水箱和空调热惯性的充放能效率都接近0.9以上,帐基本是划算的。
这里必须强调:虚拟储能的削峰填谷收益和电价峰谷差直接相关。峰谷价差小于0.3元/kWh时,实体和虚拟储能的收益都会大幅缩水。做项目测算时,第一件事不是写优化模型,而是确认当地的实际分时电价和政策是否支持这类套利逻辑。
5.3 虚拟储能SOC一天里的“充电-静置-放电”轨迹
SOC曲线是判断模型行为是否合理的直观手段。正常的虚拟储能SOC曲线应该是:凌晨谷价时段平滑上升,上午平段保持平台,午后峰价时段逐渐下降,晚间峰价后再做一次小幅度充放,次日回到初始值。
我在调试过程中遇见过不合理的SOC曲线,比如虚拟储能在没有任何约束的情况下一天内反复剧烈充放,这通常是目标函数里缺少了充放电次数惩罚,或者充放互斥约束没写全。加入次数或功率变化率惩罚后,SOC曲线会变得更平滑,更符合实际设备操作习惯。好的调度结果,看SOC曲线应该能讲出一个完整的故事,而不是一堆乱跳的数字。
6. 实操中遇到的坑与调试经验
这一节的内容不是教科书写得出来的,每条都是我至少在两个以上项目里踩过的真坑。模型正确只是第一步,落到工程可用还需要跨过这些细节。
6.1 “同时充放”乱象:二进制互斥约束是怎么被跳过的
电池同时充放这种错误,最容易被忽视的情况是二进制互斥约束的M法系数取小了。如果M刚好等于最大功率上限,而求解器在中间迭代时数值误差导致变量稍微越界,约束可能被违反。我一般把M取为最大功率的1.5倍,同时给X_ch和X_dis都加上一个极小的惩罚系数,哪怕数值上出现同时充放,也会被目标函数压下去。
还有一种情况是虚拟储能对象没有定义互斥变量。蓄冷水箱的充冷和放冷在物理上不会同时发生,但如果模型里直接用两个独立变量P_ch和P_dis,没有加互斥约束,求解器同样会给出同时充放的结果。处理方式和电池一致,用二进制变量加互斥约束。
6.2 求解器报错、无解、尺度问题怎么一步步定位
求解器报Infeasible,90%以上不是模型逻辑错,而是边界条件冲突。我的排查顺序很固定:先检查所有初始SOC是否在上下限范围内;再检查一天总能量是否平衡,比如虚拟储能的日放电量不能超过日充电量与初始SOC之和;最后再全部变量上界扫一遍,看有没有负值或过度约束。
数值尺度问题在混合整数规划里很常见,典型现象是求解器返回数值警告,或“小量变量”优化结果不可信。这时我会把所有涉及能量单位的变量统一换算到kWh,价格统一换算到元/kWh,尽量让目标函数的量级落在1e2到1e5之间。避免出现某个变量是1e-6、另一个变量是1e6的极端尺度差异。
Cplex或Gurobi的license问题也容易让新同事卡住。如果用的是试用license,求解规模限制很紧,一个24时段楼宇微网模型可能直接报错。此时要么换用免费的开源求解器,要么和求解器厂商申请学术license。Yalmip对求解器有统一的调用接口,切换求解器只是sdpsettings里改一个名称的事,非常方便。
6.3 分时电价与需求响应基线信号的一致性
分时电价的时段划分,必须和需求响应基线保持完全一致。我遇到过这样的情况:目标函数里用的峰谷时段和实际需求响应邀约的削减时段不一致,导致模型给出的最优策略在响应日完全不适用。正确做法是把电价时段和响应时段都作为外部参数输入模型,不要写死在代码里。
还有一点容易踩坑:如果楼宇参与了电网的月度需求响应,基线负荷的计算方式往往是用前几个工作日同类型日的平均负荷。虚拟储能的最优调度必须考虑“响应时段内的削减量是否足够”,光靠谷时蓄能可能不够,还需要在响应时段前安排一段强化蓄能。这部分需要额外把响应约束写入模型,而不能单纯依赖分时电价套利逻辑。
6.4 从日前到日内:虚拟储能的滚动修正方法
日前调度模型输出的是未来24小时的计划,但实际运行中光伏出力偏差和负荷扰动总会让计划“走样”。我的做法是做简单的滚动修正:每隔1小时,把日前优化得到的未来4小时SOC参考轨迹作为追踪目标,对当前时段的P_vs_ch和P_vs_dis进行微调。追踪逻辑可以用一个很轻量的二次规划,也可以用比例积分控制器。
这个修正环节最大的价值是避免虚拟储能设备在小扰动下频繁启停。蓄冷水箱一天内启停次数如果超过设备承受限制,会显著影响设备寿命。在日前模型里加上相邻时段功率变化率约束或启停计数约束,比在日内靠控制器去限制要省事得多。如果你做的是工程落地项目,这条一定要提前考虑,不要等设备商来投诉才想起来。
最后说点实在的
做虚拟储能项目这两年,我最深的体会是:优化模型只是其中一环,真正决定项目成败的是边界条件是不是摸得足够清楚。实体储能设备的参数铭牌上有明确标称值,但“楼宇热容”“空调可调裕度”“用户舒适度容忍范围”这些参数不会印在任何说明书上,必须靠实测、靠历史数据回归、靠跟运维人员聊出来。虚拟储能建模这件事,代码可以很快写完,但让模型里的数字和现实世界真正对上,需要花的时间远超过写代码本身。
如果你刚开始做这类项目,我建议从一台中央空调加一个蓄冷水箱开始,先跑通单类资源的调度,再逐步叠加其他柔性负荷。一开始就把所有资源都塞进模型,参数标定和问题定位都会变得非常困难。另外别忽视结果的可视化:把每条曲线画出来和业主方一起核对,很多模型里看不出来的问题,一看图就明白了。