ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

分时电价负荷需求响应仿真:弹性系数法Matlab实现与削峰填谷分析

分时电价负荷需求响应仿真:弹性系数法Matlab实现与削峰填谷分析 做园区级负荷预测和需求响应仿真这几年我越来越觉得分时电价下的负荷需求响应模型是一块特别值得啃的方向。电网峰谷差的代价、变压器容量的浪费、新能源消纳的压力最后都得靠“把高峰负荷搬到低谷去”来消化。最近我用Matlab把一套基于弹性系数法的负荷需求响应模型完整跑通了实现起来并不复杂但里面的坑不少。这篇就把模型原理、Matlab实现、参数标定和仿真结果完整拆一遍适合正在做电力市场、需求侧响应、虚拟电厂、微电网优化方向的朋友参考。1. 先搞清楚分时电价下的负荷响应到底在算什么1.1 峰谷差是电力系统的“效率黑洞”电力系统有一个绕不开的现实发、输、配设备都是按最大负荷来建设的。可一天里负荷波动太大白天晚高峰可能顶到148 MW凌晨最低只有65 MW峰和谷之间差了80多MW。为了伺候这一个多小时的尖峰调度侧得额外开一台机组配网侧得多留几十MVA的变电容量但这些容量一年里真正满功率运行的时长非常有限。峰谷差越大系统平均利用效率越低单位供电成本被摊得越高。需求响应这个词听起来很学术落到实际操作上就是把高峰时段的用电需求往低谷时段“搬”。搬的方式可以靠价格信号比如分时电价也可以靠激励补偿比如可中断负荷合同。价格型需求响应是最常见、也最适合放在仿真模型里提前评估的一类。我做的这个模型就是模拟用户看到分时电价之后主动调整用电曲线然后量化削峰填谷的效果。1.2 分时电价如何让“负荷搬家”分时电价的核心思路很简单峰时段电价抬高谷时段电价压低让用户觉得“这时候用电不划算那挪到便宜的时候再用”。哪些负荷搬得动电动汽车充电、洗衣机、热水器、蓄冷空调、工商业里不连续运行的产线都是典型的可转移负荷。搬不动的呢照明、电梯、医院手术设备这种价格再高也得用这部分对电价基本无感。在数学模型里“用户对价格的敏感程度”被量化为价格弹性。自弹性描述的是当前时段电价变化对当前时段负荷的影响通常是负值电价涨了负荷就降交叉弹性描述的是其他时段电价变化对本时段负荷的影响一般是正值其他时段电价涨了本时段反而会多承接一些转移过来的负荷。分时电价下的负荷响应本质就是自弹性和交叉弹性共同作用下的“负荷搬家”。1.3 模型的输入输出与适用人群这个模型的输入就三样24小时原始负荷曲线、分时电价方案、弹性系数参数。输出是响应后的负荷曲线以及削峰率、填谷率、峰谷差缩减率这几个关键指标。模型本身不大跑一轮不到一秒但它能帮你回答一个很实际的问题一套给定的峰平谷电价到底能把尖峰削下去多少、把低谷填起来多少。谁适合参考这个做电网规划的可以用它估算需求响应后的容量需求售电公司和综合能源服务商可以用它设计套餐并测算用户响应带来的收益做微电网或者虚拟电厂调度策略的人可以直接把这个模型嵌进日前优化里作为用户侧负荷参与调节的简化表达。研究生做课题也合适弹性系数法成熟、解释性好Matlab跑通之后画几张漂亮的对比曲线整套故事就完整了。2. 建模思路与关键数学表达2.1 弹性系数法需求响应模型的“主力方程”我把模型的主干放在了弹性系数法上这也是需求响应仿真里最经典的表达方式。它的核心公式是[ \frac{\Delta L_i}{L_{0,i}} \sum_{j1}^{24} E_{i,j} \cdot \frac{\Delta P_j}{P_{0,j}} ](L_{0,i}) 是第 (i) 时段原来的负荷(\Delta L_i) 是第 (i) 时段响应后的负荷变化量(P_{0,j}) 和 (\Delta P_j) 分别代表第 (j) 时段的参考电价和电价变化量(E_{i,j}) 是弹性系数矩阵。这个式子的直观含义是第 (i) 个时段的负荷变化率不是只取决于第 (i) 时段的电价变化而是24个时段电价变化的加权和。权重就是弹性系数。为什么必须用矩阵而不是单点的弹性因为用户跨时段转移负荷的行为天然是全局的你让晚高峰电价翻倍用户不会凭空不用电他更可能在中午或者夜里把这件事干了。如果只看自弹性会严重低估负荷从峰时段向谷时段的转移量。2.2 弹性矩阵的行和、列和与电量守恒问题弹性矩阵的构建是最容易埋坑的地方这里多说几句。对角线上的自弹性 (E_{i,i}) 取负值我这次取的是-0.25也就是电价涨1%对应时段负荷降0.25%这个量级和多数文献里的短时弹性是吻合的。非对角线上的交叉弹性 (E_{i,j}) 取正值我设定为0.02。需要特别注意的是如果只把0.02直接填进所有非对角位置整个矩阵的行和就不为零一旦所有时段电价等比例变化每个时段的负荷也会跟着变这不符合“纯价格转移”的设定。我在代码里把交叉弹性做了均摊也就是每个时段的交叉弹性总和保持为0.02矩阵行和正好是零。这样处理之后如果所有时段电价统一上涨用户总负荷不变只有相对价格变化才会引起负荷转移逻辑上更干净。但行和为零只是必要条件由于峰谷时段的负荷基数不一样实际算完总电量还是会有一点变化。这一点我放在后面的工程化修正里一起讲。2.3 工程化修正限幅与可削减系数纯理论模型跑出来经常有一种“理论上成立、实际上离谱”的问题。比如弹性系数取大了某个谷时段负荷可能直接翻倍或者峰时段被削到快变成零。为了让结果更像真实用户的行为我加了两层修正。第一层是单时段变化率限幅。我限制每个时段负荷变化幅度不超过原始负荷的30%。实际当中即便电价变化很大也没有哪类用户会在一个小时内突然砍掉一半负荷这是受用电习惯和设备物理特性约束的。限幅其实就是给模型加了一个“用户最大响应意愿”的约束。第二层是电量修正。需求响应分两类一类是负荷转移电量不变另一类是负荷削减用户直接放弃一部分用电电量下降。现实中两类并存峰时电价高了有一部分用户确实会选择少用、不用。我在代码里引入一个可削减系数 ( \eta )默认取0.02表示系统总用电量允许下降2%。修正方式是对限幅后的负荷曲线整体乘以一个比例系数让总电量等于原始总电量乘以 (1-\eta)。这两个修正加进去模型才真正能拿去和调度结果对标。3. Matlab完整实现从数据准备到结果输出3.1 基础数据负荷曲线与电价方案数据是一切仿真的前提。我先准备一条典型的夏季工作日负荷曲线24个点单位是MW。曲线形状是常见的双峰上午10点到12点有一个小高峰晚上18点到21点出现全天最大负荷。凌晨负荷最低出现在4点左右。这条曲线可以直接用真实采集数据替换代码里只需要改数组。分时电价我按典型的峰平谷三段设置峰段10:00-12:00和18:00-21:00电价0.85元/kWh平段8:00-9:00、13:00-17:00和22:00电价0.55元/kWh谷段0:00-7:00和23:00电价0.30元/kWh。参考电价取0.55元/kWh也就是不分时时的单一电价。换算一下峰段相对参考电价上涨了54.5%谷段相对下降了45.5%峰谷价比大约是2.83比1这是国内工商业分时电价里常见的量级。3.2 核心代码弹性矩阵与响应计算下面是完整的主程序我加了注释可以直接复制到Matlab里跑。需要注意的地方我会在代码后面单独说明。%% 负荷需求响应模型分时电价下的负荷响应与削峰填谷评估 clc; clear; close all; %% 1. 基础数据 % 24小时原始负荷MW从0点开始 L0 [75, 70, 68, 66, 65, 68, 78, 90, ... 105, 118, 128, 135, 132, 126, 122, 120, ... 122, 130, 142, 148, 145, 138, 120, 95]; % 分时电价元/kWh price_tou [0.30, 0.30, 0.30, 0.30, 0.30, 0.30, 0.30, 0.30, ... 0.55, 0.55, 0.85, 0.85, 0.85, 0.55, 0.55, 0.55, ... 0.55, 0.55, 0.85, 0.85, 0.85, 0.85, 0.55, 0.30]; price_ref 0.55; % 参考电价不分时时的单一电价 n length(L0); % 时段数 24 %% 2. 电价变化率 dp_rate (price_tou - price_ref) / price_ref; %% 3. 构建弹性矩阵 e_self -0.25; % 自弹性系数 e_cross 0.02; % 交叉弹性系数 E eye(n) * e_self; for i 1:n for j 1:n if i ~ j E(i,j) e_cross / (n - 1); % 交叉弹性均摊到其他时段 end end end %% 4. 计算理论响应负荷变化率 dL_rate (E * dp_rate(:)); % 1x24各时段负荷变化率 L_theory L0 .* (1 dL_rate); % 理论响应负荷 %% 5. 单时段变化率限幅避免响应曲线畸变 max_delta_rate 0.30; % 单时段最大允许变化率30% delta min(max(dL_rate, -max_delta_rate), max_delta_rate); L_limited L0 .* (1 delta); %% 6. 电量修正计及小部分负荷被削减/中断 eta 0.02; % 允许整体电量下降2% target_sum sum(L0) * (1 - eta); scale target_sum / sum(L_limited); L_resp L_limited * scale; %% 7. 结果评估与输出 peak0 max(L0); peak1 max(L_resp); valley0 min(L0); valley1 min(L_resp); pv_diff0 peak0 - valley0; pv_diff1 peak1 - valley1; peak_shave (peak0 - peak1) / peak0 * 100; valley_fill (valley1 - valley0) / valley0 * 100; pv_reduce (pv_diff0 - pv_diff1) / pv_diff0 * 100; fprintf(原始峰值: %.2f MW, 响应后峰值: %.2f MW, 削峰率: %.2f%%\n, ... peak0, peak1, peak_shave); fprintf(原始谷值: %.2f MW, 响应后谷值: %.2f MW, 填谷率: %.2f%%\n, ... valley0, valley1, valley_fill); fprintf(峰谷差由 %.2f MW 降至 %.2f MW, 缩减率: %.2f%%\n, ... pv_diff0, pv_diff1, pv_reduce);有几个Matlab细节提醒一下。dp_rate刚开始是行向量dp_rate(:)转成列向量才能和24x24的矩阵正确相乘。算完的dL_rate是列向量我在后面加了一个转置把它变回行向量再点乘L0。这一步维度不匹配的话Matlab R2016b以后的版本会触发隐式扩展直接给你生成一个24x24矩阵结果全乱掉还找不到原因。建议代码里随时检查size(dL_rate)。3.3 指标计算与可视化指标计算部分已经写在上面了。可视化我一般这样写figure; plot(0:23, L0, o-, LineWidth, 2); hold on; plot(0:23, L_resp, s-, LineWidth, 2); grid on; legend(原始负荷, 响应后负荷, Location, northwest); xlabel(时刻 (h)); ylabel(负荷 (MW)); title(分时电价下的负荷需求响应曲线);画出来的图就是博文里最常见的“削峰填谷对比图”两条曲线一对比效果直观得多。如果你要把结果写进报告可以把这三组指标再写成表格输出用writetable直接存成Excel后面做敏感性分析也方便。4. 仿真结果分析削峰填谷能到什么程度4.1 响应前后曲线对比我直接把上述代码跑了一遍得到的关键时段数据如下。原始负荷最大值出现在19点148 MW响应后负荷的整体形态变了峰值位置也发生了迁移先卖个关子下面详细说。时刻原始负荷 (MW)响应后负荷 (MW)变化率4:006573.312.7%7:0090101.412.7%10:00128109.4-14.5%12:00132112.8-14.5%17:00130130.40.3%19:00148126.5-14.5%23:0095107.112.7%看这个表基本就能感受到“削峰填谷”的含义峰时段的10点、12点、19点负荷全部明显下降下降幅度在14.5%左右谷时段的4点、7点、23点负荷全部抬升抬升幅度在12.7%左右。这正是自弹性把高价时段用电压下去、交叉弹性把用电需求引向低谷时段的联合效果。4.2 关键指标量化评估代码输出的核心指标整理如下削峰率原始峰值148 MW响应后曲线最大值130.4 MW削峰率11.9%填谷率原始谷值65 MW响应后谷值73.3 MW填谷率12.7%峰谷差缩减峰谷差由83 MW降至57.2 MW缩减率31.1%总用电量由2606 MWh降至2554 MWh下降2%对应设定的eta值。削峰率11.9%意味着什么放在一个园区场景里如果原峰负荷刚好卡在变压器容量的边缘这个模型告诉你通过分时电价大概率能让容量需求降下来一截变压器的增容改造可以往后推一年这就是实打实的投资节省。峰谷差缩减31.1%对电网调度也有意义峰谷差减小意味着调峰机组开机容量可以下调系统运行的经济性和安全性都受益。4.3 一个容易忽略的现象峰荷迁移细心的朋友会发现响应后曲线的最大值不在19点而在17点数值是130.4 MW。原始曲线里17点只有130 MW当时它被19点的148 MW掩盖着根本不是关注对象。响应后18点到21点的负荷被压低了15%左右17点这个“原来的平段次高峰”反而冒了出来成为新的日负荷最高点。这不是模型算错了而是分时电价时段划分的边界效应。17点电价还是0.55元/kWh没涨它的自弹性响应几乎为零交叉弹性带来的影响也只有0.3%左右。但紧挨着的18点开始就是峰段负荷从142 MW降到121.3 MW。削了18到21点的峰17点就“被迫”变成了峰。做实际项目时看到这种结果千万别直接怀疑模型更不需要把弹性系数改小去强行压住它。正确的做法是迭代优化时段划分把新的高峰时段并入峰段或者把峰段提前到17点开始重新设置电价再做一轮需求响应仿真一般迭代两三次就能让峰荷位置稳定下来。5. 常见问题与避坑指南5.1 弹性系数别拍脑袋弹性系数是整个模型里对结果影响最大的参数也是坑最多的地方。自弹性取-0.1和取-0.5得出的削峰率能差出一倍以上。我这次的-0.25参考了文献里的典型值但不同用户群体差异很大工业用户弹性低商业用户居中居民用户对价格更敏感弹性相对高。有历史数据的话建议用最小二乘回归估计一下本地区或者本园区的弹性把过去几个月的负荷和对应电价拉出来拟合 (\Delta L/L a b \cdot \Delta P/P)得到的 (b) 就是自弹性的近似值。没数据的时候至少做一个参数敏感性分析把自弹性从-0.1扫到-0.5看看削峰率的变化范围给结论带上区间报告里也站得住脚。5.2 总量守恒到底要不要强制不少教科书模型默认需求响应前后总电量不变实际做项目时别死守这个假设。我见过一个方案为了强制守恒把削减的峰负荷全部等比例加回到所有时段结果谷时段负荷被抬到离谱填谷率虚高反而误导了决策。现实中总会有用户因为电价高直接放弃一部分用电也会有用户把峰时用电转移到自己分布式的光伏或者储能上这部分电量并不经过电网结算。所以保留一个温和的电量下降系数比如2%到3%比强行守恒更贴近实际。如果你的模型后续要耦合到日前经济调度里再用严格的电量守恒约束也不迟届时的做法是在调度模型里加一个电量平衡约束而不是在需求响应模型里硬掰曲线。5.3 响应后曲线出现新的尖峰怎么办我把这个问题单独拎出来因为太常见了。分时电价时段边界处特别容易出现“削了旧峰、冒出新高”的尴尬。除了前面说的迭代优化时段划分还有一个技巧是先跑一次不设限幅的模型看看理论上哪些时段负荷会飙升这些时段基本就是用户转移负荷的首选目标。然后针对性地调整这些时段的电价或者把它们划入高一级的时段类别。本质上分时电价方案设计是一个电价时段和价格的联合优化问题单靠一次仿真很难找到最佳点手动迭代几轮是完全可以接受的。5.4 模型往哪扩展弹性系数法虽然是单点静态模型扩展性其实很好。可以在电价方案上做文章把峰平谷三段改成多时段阶梯电价可以在用户侧做分类工业、商业、居民分别用不同的弹性矩阵合成一个综合响应曲线还可以把“负荷响应后的曲线”作为约束条件接入微电网优化调度或者虚拟电厂的日前申报流程。我下一步准备把这套模型往强化学习方向推用DQN或者PPO去自动搜索最优的分时电价时段划分和价格倍率替代现在手动枚举的笨办法可以让电价方案优化这件事真正自动化起来。最后再给一个能立刻用上的技巧上面的主程序跑通之后建议用Matlab的function把“输入负荷曲线、返回响应曲线和指标”封装成一个小函数比如[L_resp, metrics] demand_response(L0, price_tou, e_self, e_cross, eta)。这样后面做电价敏感性分析、时段组合枚举都是几十行代码的事不用每次复制粘贴一大段脚本。我实际项目里大多数迭代工作都依赖这个函数前期把参数接口设计清楚了后期能省下大量时间。
返回列表