2. 价格型需求响应:分时电价(TOU)、实时电价(RTP)、尖峰电价(CPP)原理与建模
价格型需求响应,说白了就是「用价格杠杆撬动用户行为」。我做了这么多年电力系统算法,最深的体会是:用户其实不关心电是怎么来的,他们只关心电费贵不贵。你只要把价格信号设计得足够聪明,用户自然会帮你削峰填谷。
这一章,我们重点拆解三种最主流的电价机制:分时电价、实时电价、尖峰电价。这三种机制,我都在实际项目中碰过壁、踩过坑,今天一并分享给你。
2.1 分时电价(TOU)—— 最经典的「三段式」
分时电价,你肯定不陌生。就是把一天切成几个时段:峰、平、谷。每个时段定一个固定电价。用户看到峰时电价贵,自然会把洗衣机挪到谷时用。
核心逻辑: 用固定的时间分段,引导用户转移负荷。
2.1.1 数学模型
我个人习惯用下面的公式来描述分时电价下的用户响应:
# 分时电价下的负荷转移模型
def tou_response(original_load, price_peak, price_valley, price_flat, elasticity=-0.2):
"""
original_load: 原始负荷曲线 (list)
price_peak/valley/flat: 各时段电价
elasticity: 需求价格弹性系数(默认-0.2,表示价格涨1%,需求降0.2%)
"""
# 定义时段划分(假设峰:10-12, 17-21;谷:0-8;平:其余)
peak_hours = list(range(10,13)) + list(range(17,22))
valley_hours = list(range(0,9))
flat_hours = [h for h in range(24) if h not in peak_hours and h not in valley_hours]
new_load = original_load.copy()
avg_price = (price_peak + price_valley + price_flat) / 3
for h in range(24):
if h in peak_hours:
# 价格上升,负荷下降
delta = elasticity * (price_peak - avg_price) / avg_price
new_load[h] = original_load[h] * (1 + delta)
elif h in valley_hours:
# 价格下降,负荷上升
delta = elasticity * (price_valley - avg_price) / avg_price
new_load[h] = original_load[h] * (1 + delta)
# 平时段基本不变
return new_load
嗯,这里要注意:弹性系数 elasticity 是个负值。我见过不少新手把它设成正数,结果价格越高负荷越大——那不成奢侈品了?
2.1.2 避坑指南
我曾经踩过的坑: 分时电价的时段划分不能拍脑袋。有一次我直接把峰时段定在10-12点和14-17点,结果发现用户把负荷全挤到了12-14点,反而制造了一个新尖峰。后来我学乖了——划分时段前,一定要先做负荷曲线的聚类分析。
2.2 实时电价(RTP)—— 最灵活,也最「刺激」
实时电价,就是电价每15分钟或每小时变一次,完全跟着批发市场走。用户端的智能设备根据电价自动调整用电行为。说白了,这是把市场风险直接传导给了用户。
我参与过一个大型工业园区的RTP项目,效果确实好——峰时负荷下降了将近30%。但问题也很明显:用户抱怨「电费像过山车」,心理上接受不了。
2.2.1 建模思路
实时电价下,用户的响应模型通常用「价格-负荷弹性矩阵」来描述:
import numpy as np
def rtp_response(load_profile, price_profile, elasticity_matrix):
"""
load_profile: 原始负荷 (24个点)
price_profile: 实时电价 (24个点)
elasticity_matrix: 24x24 的弹性矩阵
- 对角元:自弹性(当前时段价格对当前时段负荷的影响)
- 非对角元:交叉弹性(其他时段价格对当前时段负荷的影响)
"""
n = len(load_profile)
delta_p = (price_profile - np.mean(price_profile)) / np.mean(price_profile)
# 负荷变化率 = 弹性矩阵 × 价格变化率
delta_l = elasticity_matrix @ delta_p
new_load = load_profile * (1 + delta_l)
return new_load
我的经验: 交叉弹性矩阵的标定是最难的。我建议用历史数据做岭回归,别用普通最小二乘——不然矩阵里会出现很多离谱的负值,物理上根本解释不通。
2.3 尖峰电价(CPP)—— 平时温柔,关键时刻「一刀」
尖峰电价,你可以理解为「分时电价的升级版」。平时还是峰平谷三段,但系统预测到明天下午要出现尖峰负荷时,会提前通知用户:明天下午2点到5点,电价翻三倍。
用户可以选择:要么忍着高价,要么提前把空调温度调低两度。我见过最极端的案例——一个水泥厂,接到CPP通知后直接把生产线停了半天,省了十几万电费。
2.3.1 触发条件
尖峰电价不会天天有。通常触发条件是这样的:
| 触发条件 | 典型阈值 | 说明 |
|---|---|---|
| 负荷率 | ≥ 95% 的变压器容量 | 系统接近满载时触发 |
| 温度 | ≥ 38°C 且持续3天 | 热浪天气容易导致空调负荷暴增 |
| 备用容量 | ≤ 5% 的旋转备用 | 系统安全裕度不足 |
2.3.2 建模代码
def cpp_trigger(load_forecast, temp_forecast, capacity, reserve_limit=0.05):
"""
判断是否触发尖峰电价
返回: (trigger_flag, cpp_hours)
"""
peak_load = max(load_forecast)
load_rate = peak_load / capacity
max_temp = max(temp_forecast)
# 条件1:负荷率超过95%
cond1 = load_rate >= 0.95
# 条件2:温度超过38度
cond2 = max_temp >= 38
# 条件3:备用容量不足
reserve = 1 - load_rate
cond3 = reserve <= reserve_limit
if cond1 and (cond2 or cond3):
# 找到尖峰时段(负荷最高的3个小时)
sorted_hours = sorted(range(24), key=lambda i: load_forecast[i], reverse=True)
cpp_hours = sorted(sorted_hours[:3])
return True, cpp_hours
else:
return False, []
注意: CPP的提前通知时间很关键。我见过一个项目只提前2小时通知,结果用户根本来不及反应。行业惯例是至少提前12小时,最好提前24小时。
2.4 三种机制的对比与选择
你可能会问:这三种机制到底选哪个?我的建议是看场景:
- 居民用户 → 用TOU:简单易懂,用户不需要装智能设备,靠习惯就能省钱。
- 工商业大用户 → 用RTP:他们有能源管理系统,能自动响应电价变化,省下来的钱足够覆盖设备成本。
- 系统尖峰压力大 → 用CPP:一年也就触发十几次,平时不影响用户体验,关键时刻能救命。
当然,实际项目中往往是混合使用。比如「TOU为主,CPP为辅」——平时用分时电价引导,遇到极端天气再启动尖峰电价。我在浙江的一个园区就是这么做的,效果相当不错。
2.5 知识体系总览
下面这张图,是我梳理的三种电价机制的核心逻辑。你可以把它当作本章的「思维导图」:
三种机制各有千秋,没有绝对的优劣。关键是要根据用户类型、系统条件、市场成熟度来灵活搭配。我个人的经验是:别追求「最先进」,要追求「最合适」。一个让用户看不懂的电价机制,再完美也是白搭。
最后分享一个心得: 做价格型需求响应,算法只占30%,剩下的70%是用户沟通和机制设计。你算得再准,用户不买账,一切都是零。所以,建模的时候多想想:这个价格信号,用户能看懂吗?他们愿意配合吗?
公众号:蓝海资料掘金营,微信deep3321