首页 / 资讯中心 / 文章详情

车-电-路网时空负荷预测的Matlab仿真与工程实践

车-电-路网时空负荷预测的Matlab仿真与工程实践 ★ FEATURED ARTICLE
做电力系统仿真的朋友这两年应该都绕不开一个词——车-电-路网时空分布负荷预测。我在评估某城市示范区电动汽车接入配电网的影响时发现单靠电网历史负荷曲线做预测根本没法解释为什么某条馈线会在傍晚突然过载。原因很简单负荷变了负荷的“来源”也变了。以前的负荷主要跟着人口和产业分布走现在还要跟着车轮走。电动汽车既是电力用户又是移动的充电需求源而充电需求发生在哪里、什么时候发生取决于路网上的车流和驾驶者的行为。因此把车辆移动、充电行为、路网交通和电网负荷放在同一个框架里做时空分布预测就成了配电网规划、充电设施布局以及有序充电调度绕不开的基础工作。下面内容完全基于我们在Matlab里的实际代码实现不聊虚的全程走一遍建模、仿真、预测和评估的流程顺便把踩过的坑都交代清楚。不管你是电力系统方向的在读研究生还是刚接手充电负荷预测项目的工程师只要手上有一台装了Matlab的电脑就可以照着这套思路跑起来。1. 车-电-路网联合预测的建模思路1.1 为什么必须把车、电、路网放进同一个框架传统负荷预测模型通常只看电网本身历史功率曲线、温度、节假日、经济增长指标。这些变量对付常规居民负荷、商业负荷还行可是当电动汽车渗透率超过某个阈值不同地区的边界不一样我见过15%~20%就已经很明显的案例充电负荷就会显著改变配电网的负荷分布。这种改变有两个明显特征时间上的不确定性和空间上的不均匀性。时间上用户下班回家集中在傍晚到夜间充电容易和原有用电晚高峰叠加空间上充电负荷集中在居住区、商圈、高速服务区附近而不是均匀分摊到所有变电站。如果只预测全网总负荷而不看空间分布规划人员就没法知道具体哪条馈线需要扩容哪个变压器可能在夏天空调负荷和充电负荷的双重冲击下过载。反过来如果只做路网车流量预测不把这些流量映射到电网节点同样无法评估充电负荷对潮流的影响。所以车-电-路网必须耦合建模路网决定车辆去哪里、何时到达、剩余电量是多少电网决定这些充电负荷加在哪个节点、是否越限。只有把这个闭环打通预测结果才能真正落到电网规划与调度上。1.2 三类数据的时空粒度差异与对齐方法做耦合建模第一个拦路虎是数据粒度不统一。路网数据通常是秒级到分钟级的车辆轨迹或路段流量电网负荷量测一般是15分钟或1小时一个点而车辆出行链里每一次停车的停留时间可能从几分钟到几小时不等。这三类数据不是天然对齐的需要先建立统一的时空基准。我习惯把时间基准定为15分钟因为绝大多数配电网负荷数据是15分钟一个时间断面。路网仿真步长取1分钟车辆在每条路段上的行驶时间通过路阻函数解析计算再按15分钟窗口聚合成一个时段的负荷。空间基准则通过“路网节点—地理位置—电网节点”的映射关系实现把路网节点坐标匹配到最近的变电站或馈线节点或者用地理围栏把充电站划到电网节点下。这里有一点要注意不能简单用直线距离最近来做匹配还要考虑实际道路可达性和行政边界否则会出现车在路网A点充电负荷却算到电网B点的问题。我在项目里宁可手工整理一份对应关系表再辅以自动匹配做校验也不完全信任单纯的最近邻算法。1.3 从出行链到充电负荷两类主流建模路线目前做车-电-路网耦合负荷预测主流有两种路线。第一类是“自上而下”的宏观交通流法先用交通规划软件或者简化路阻函数得到各路段车流量再根据电动汽车渗透率和平均充电功率估算区域充电负荷最后把负荷分配到电网节点做潮流计算。这种方法的优点是计算量小适合城市级大尺度评估跑一年8760小时也不是大问题缺点是无法体现个体充电行为的随机性比如不同的出发时间、不同的SOC、不同的充电偏好。第二类是“自下而上”的多智能体蒙特卡洛法也是我们在Matlab里落地的一套方法。核心思路是逐台模拟电动汽车一整天的出行链每辆车有自己的出发时刻、目的地、路径选择、停车时长、停车期间是否充电以及电池容量和初始SOC。把这些个体行为聚合起来就能得到充电站在时域上的功率需求再映射到电网节点做潮流计算。这个路线能精细反映路网拥堵、充电排队、用户习惯等随机因素缺点是计算量大需要做好并行化设计。实际项目中我在不同尺度下都会用宏观模型用来快速摸底微观模型用来校验关键节点和典型场景。2. Matlab仿真的总体架构与数据预处理2.1 一个可以跑通的总体流程我们在Matlab里实现的仿真主流程可以概括为初始化路网拓扑、生成OD出行需求、模拟每辆车的时空轨迹、根据SOC与充电决策生成充电事件、按电网节点聚合负荷、调用潮流计算评估、导出结果用于训练预测模型。这七个模块之间数据依赖明确每一步的输出都是下一步的输入。主程序建议拆成多个文件不要把所有代码塞在一个脚本里。我常用的文件组织是main.mnetwork_init.mod_generate.mvehicle_sim.mcharge_load_aggregate.mpower_flow.mpredict_grub.mevaluate.m。每个文件只负责一件事后续调参、查bug、给别人讲解都省心很多。下面会逐一说明每个文件里的核心逻辑和关键实现细节这里的顺序就是数据流动的方向照着搭不会乱。2.2 路网拓扑构建与OD需求模拟路网拓扑我用Matlab内置的graph和digraph对象来表示因为shortestpath函数可以直接计算最短路不需要自己写Dijkstra算法。构建路网时每条边要记录道路长度、自由流车速、通行能力这些参数后续会用于计算行程时间。OD起讫点需求模拟是另一个关键模块。如果拿不到真实OD矩阵可以用简化重力模型两个节点之间的出行需求与起点和终点的人口/岗位数乘积成正比与节点间距离的幂次成反比。我们在某个模拟项目X中使用了20个节点的路网每个节点设置了对应的人口权重早高峰出发时刻服从7:00到9:00的高斯分布晚高峰服从17:00到19:00的高斯分布。这里有个容易忽略的点私家车的出发时刻分布和充电站到达时刻分布是两码事。车辆必须经过路网仿真之后才能得到真实到达时间不能默认所有车都在同一时刻到达充电站。如果跳过路网只做充电负荷相当于丢掉了“车-路”环节最重要的耦合信息。2.3 车辆状态与充电行为建模车辆仿真的核心是状态转移。每一台车在路网上移动时我用结构体数组来维护状态字段包括vehicle_id、battery_capacity、soc、energy_consumption_rate、current_node、destination_node、departure_time、arrival_time、charge_intent等。车每到达一个节点先判断是要继续行驶、已经到达最终目的地还是需要触发充电决策。充电决策可以按简化逻辑处理SOC低于某个阈值比如20%并且在当前目的地停留时间超过1小时才会产生充电事件充电功率按充电桩类型区分家用慢充7kW公共快充60kW。SOC的更新使用动态公式SOC_new SOC_old - distance * energy_rate / battery_capacity。如果某辆车算出来的SOC小于0说明它中途就没电了这时需要在路网上的某个节点强制充电。实际仿真中一定要加上这个边界判断否则会出现SOC为负的荒谬结果。这部分代码的运算量非常大。我强烈建议用parfor并行替代普通for循环让每辆车独立仿真最后再聚合。测试中2000台车、20个节点、完整24小时仿真在8核机器上并行后耗时能从20分钟降到4分钟左右。如果不做并行调整参数会等到怀疑人生。2.4 电网潮流与负荷叠加充电负荷聚合到电网节点后还需要做潮流计算。我们用的是Matpower工具箱它可以读取IEEE标准节点的case数据也可以自定义网络拓扑。常规做法是把每个充电站映射成PQ节点给定有功和无功需求假设功率因数0.95左右再调用runpf计算节点电压和支路潮流。这里提醒一句潮流计算的时间尺度是15分钟一个断面但负荷是时变的需要做多断面连续潮流不能试图把一天所有数据一次性塞进潮流计算。正确做法是循环96个断面在每个断面上更新节点注入功率然后调用runpf。我在实际仿真中96个断面的连续潮流跑下来大概需要几十秒到几分钟完全可接受。如果网络规模大、需要连续评估一年8760小时建议用更高效的求解器或者把时间尺度加粗到1小时否则计算负担会很重。3. 核心预测算法与关键参数3.1 用蒙特卡洛生成训练样本车-电-路网仿真输出的是一组“某节点某时刻的充电负荷功率”时序数据。但仿真本身有随机性单次运行只能代表一种场景要训练可靠的预测模型还需要用蒙特卡洛生成覆盖多样化场景的训练集。我会对私家车保有量、出行强度、环境温度、充电价格这些变量做随机扰动生成500到2000组场景每组跑一次仿真得到对应的时空负荷数据。生成样本时随机种子一定要固定。我在每次仿真前会设置rng(k)k是场景编号。这样做的最大好处是可复现调试时能快速定位是哪一组随机数导致异常结果。如果忘记固定随机种子稍后你会发现只是改了一个配网参数之前的仿真结果就再也复现不出来了。写论文、做技术方案比选时这会非常被动。3.2 LSTM和GRU预测模型怎么选时空负荷预测模型有很多选择但在Matlab里最容易落地的是LSTM和GRU。Deep Learning Toolbox提供了现成的lstmLayer和gruLayer不需要自己从零写反向传播。我们在对比实验中发现GRU参数量更少、训练更快精度与LSTM几乎持平所以最终选择了GRU作为主力模型。输入特征设计是建模的关键不要只把历史功率序列丢进去。我使用的输入特征包括过去24小时的节点负荷96个点、当天的环境温度、星期类型工作日/周末、节假日标记以及前一天同时间的路网拥堵指数。输出是对应未来一个时间点的负荷也可以做多步输出比如同时输出未来15、30、45、60分钟。训练之前所有特征要做z-score标准化预测完之后再反标准化到实际功率值。经常有朋友问为什么GRU预测结果里出现负值大概率是忘记反标准化或者训练集和测试集各自用了不同的均值方差。这两个错误都很常见排查起来却往往要花不少时间。3.3 空间维度怎么处理区域聚类与图谱特征时空负荷预测里的“空间”维度不只是把每个节点单独做时序预测还要考虑节点之间的空间相关性。一种做法是先用kmeans对所有节点做空间聚类把地理邻近且负荷曲线形态相似的节点归为一类每一类训练一个预测模型。另一种做法是直接上基于图的模型但Matlab里实现成本高一些。除非有特别强的空间拓扑依赖我不建议一上来就用图神经网络。在模拟项目X中我们用kmeans聚类聚类特征取节点负荷曲线的峰谷形态、节点所属功能区居住、商业、工业和平均充电功率。聚类数量通过肘部法则确定。聚类之后同一类节点可以共用预测模型训练速度提升明显而且某个节点数据缺失时还能用同类节点的均值填充对实际系统的数据质量比较宽容。这也算是“时空负荷预测”在工程落地时的一个实用降维手段。3.4 参数设置与一次完整计算案例下面给出一套我们在模拟项目X中使用的典型参数可以直接对照着设置放到自己的数据上再按实际情况调整。参数名称取值说明仿真步长1分钟路网轨迹更新间隔负荷聚合间隔15分钟对应电网量测周期电动汽车电池容量60 kWh主流长续航车型百公里能耗15 kWh/100km城市工况均值慢充功率7 kW家用单相桩快充功率60 kW公共直流桩充电启动阈值20% SOC低于该值触发充电蒙特卡洛场景数1000用于生成训练样本GRU隐藏单元数128中间层单元数训练轮数200使用早停机制patience为20优化器Adam初始学习率0.001这套参数下我的仿真生成了20个节点、96个时段、1000组场景的训练集规模大约是1000×20×96个数据点。GRU模型在单张GPU上训练约30分钟收敛测试集上的MAPE大约为8.6%如果只用历史负荷序列而不加入路网拥堵特征MAPE会上升到13%左右。这说明车-电-路网耦合信息确实能带来预测精度增益不是花架子。4. 实操过程与代码实现要点4.1 主程序框架怎么搭主程序建议按流程模块化组织代码如下%% 初始化 rng(1); init_network; init_vehicle_param; %% 场景循环 for k 1:num_scenarios rng(k); veh_list generate_vehicles(k); ev_traj simulate_trajectory(veh_list); charge_load aggregate_load(ev_traj); save_single_scenario(charge_load, k); end %% 数据合并与预测 train_data load_all_scenarios(); net train_grub_model(train_data); result predict_grub_model(net, test_data); evaluate_result(result, test_label);函数命名尽量别用难以理解的缩写最好看到名字就知道功能。main.m只放流程控制不要在里面写大段计算代码这样别人review也轻松。每个场景跑完立刻把结果保存到独立的mat文件避免中途程序崩溃导致全部重来。4.2 四个关键函数的实现细节第一个关键函数是路网最短路径与行程时间计算。用digraph对象建立路网后shortestpath可以直接返回路径节点序列。行程时间用路阻函数计算最常用的是BPR公式t t_free * (1 alpha * (v / c) ^ beta)。其中v是路段流量c是通行能力alpha通常取0.15beta取4。这里要注意路网流量会随着车辆位置变化所以行程时间不能一次性算死需要在每个仿真步长里根据当前流量更新。为了加速我提前把20个节点的最短路矩阵算好并缓存每次查询直接查表避免迭代中重复调用图算法。第二个关键函数是车辆仿真器。主要逻辑是while循环只要车辆没到达最终目的地就取出当前节点到下一节点的路径计算行驶时间和电量消耗更新SOC和当前位置。这里最容易出错的点是“充电行为发生在到达后还是离开前”。我的建议是到达节点后先判断是否触发充电如果充电则模拟充电过程充电功率乘以停留时间充电结束后再继续行驶。顺序不要颠倒否则电量的补充会算错。第三个关键函数是充电负荷聚合。先构造一个n_node乘以96的零矩阵再遍历所有车辆把每辆车在每个时段产生的充电功率累加到对应节点和时段。用parfor并行时累加过程容易发生冲突。我通常的做法是让每辆车先生成一个独立的贡献矩阵最后用一次sum完成合并避免多个worker同时写入同一个变量。第四个关键函数是潮流计算接口封装如下function [voltage, flow] run_pf_at_time(load_profile, time_idx) % 根据当前时段节点负荷生成Matpower case并调用runpf mpc loadcase(my_case.m); mpc.bus(:, 3) load_profile(:, time_idx); % 有功负荷 mpc.bus(:, 4) load_profile(:, time_idx) * 0.3; % 无功负荷 results runpf(mpc); voltage results.bus(:, 8); flow results.branch(:, 14); endMatpower默认用牛顿法如果某个断面负荷过高导致不收敛可以先把该断面负荷降低到合理水平或者改用runpf选项中的PQ分解法。我在处理长时段连续潮流时也会用上一时段的潮流解作为当前时段的初值这个方法对收敛性帮助很大。4.3 可视化时空热力图与误差曲线做完预测不能只给数字一定要画图。我常用的图有三张。第一张是负荷热力图横轴是时间24小时或96个断面纵轴是电网节点编号颜色深浅表示充电负荷功率能直观看出负荷在什么时段、什么节点集中。第二张是典型节点的预测值与实际值对比曲线用plot画两条曲线同时标注MAPE。第三张是误差分布直方图看误差是否近似正态判断模型是否存在系统性偏差。热力图我习惯用imagesc或heatmap函数画。因为节点数量不多纵轴显示编号足够。如果想叠加到真实地图上可以用geobubble或Mapping Toolbox做展示。不过调试阶段用表格和普通热力图就够了可视化做得太花哨反而影响排查效率。4.4 运行效率优化与并行化仿真效率是个大坑。初始版本的串行程序跑1000个场景需要十几个小时完全没法调参。我做了三处优化效果非常明显。第一把车辆遍历循环改成parfor用Parallel Computing Toolbox的进程池8核并行下能获得约6倍加速。第二把每个节点到其他所有节点的最短路和行程时间预先计算并保存为cell数组避免每辆车仿真时重复调用shortestpath。第三充电负荷聚合用accumarray一次性完成累加替代两层for循环逐车逐时段相加。注意parfor不是万能的。如果循环内有累加同一个变量的操作或者有迭代间的依赖关系parfor会直接报错。正确做法是让每台车返回独立的负荷矩阵在循环结束后统一合并。另外内存有限时不要一次性把所有场景都加载到内存可以分批生成和训练或者用Matlab的tall数组处理大数据集。5. 常见问题与排查技巧实录5.1 数据对齐问题路网时间与电网时间对不上我最早遇到的典型问题是仿真里车辆到达充电站的时间精确到秒而电网负荷量测是15分钟一个断面直接相加会错位。解决办法是先将车辆事件时间戳转换成以15分钟为边界的时间索引即idx floor(t / (15 * 60)) 1然后把每个索引范围内的充电功率累加。最后一个断面可能不满15分钟需要做边界修正。这里用floor而不是round是为了保证计算时段内的功率不会被挪到下一个时段。如果空间上对不上最常见的错误是路网坐标和电网坐标用了两套不同坐标系。路网数据通常来自地图服务拿到的可能是经纬度电网拓扑则常用投影坐标。做映射前必须先做坐标转换否则最近的匹配结果会完全错乱。我在实际项目中宁可手工维护一份“路网节点到电网节点”的对应表自动匹配结果只作为参考最终以人工校验为准。5.2 潮流计算不收敛怎么办潮流不收敛是仿真中常见的噩梦。导致不收敛的原因一般有三个负荷水平比网络极限高太多、无功缺额严重、某些节点电压初值不合适。排查方法是先看哪个断面不收敛单独提出来跑再把该断面总负荷按比例降低逐步增加找到临界值最后检查无功负荷设置如果功率因数过低容易导致电压崩溃型不收敛。我的经验是在做连续长期仿真时用上一时段的潮流结果作为当前时段的初值能明显提升收敛性。Matpower里可以通过mpopt的initial_cell参数实现热启动。同时聚合充电负荷时要考虑充电站配电容量上限不要无限叠加超过节点变压器容量的负荷。这样既符合实际约束也减少了病态潮流的出现。5.3 预测模型的评估指标怎么选不少同学一上来只看MAPE但MAPE有个坑当实际负荷接近0时相对误差会急剧放大。充电负荷在凌晨往往接近0此时MAPE会被异常点抬得很高不能真实反映模型在晚高峰等关键时段的表现。我建议同时报告RMSE和MAE并按场景分段评估。高峰时段比如17:00到23:00单独计算MAPE低谷时段用MAE或RMSE如果关心区间预测还应加入PICP预测区间覆盖率指标。训练集和测试集的划分也要注意。不要随机打乱所有样本因为时序样本之间有相关性。我一般按时间顺序取前70%作为训练集后30%作为测试集。如果用交叉验证应该用时间序列交叉验证而不是K-Fold随机切分否则会出现用未来数据预测过去的泄漏问题精度虚高没有实际意义。5.4 避坑清单几个容易忽略的细节充电桩约束。不能只看单桩功率还要考虑充电站的总配电容量。很多早期仿真把每个充电桩都按满载算结果负荷高得离谱。初始SOC分布。不要让所有车的初始SOC相同。按截断正态分布或均匀分布给初始SOC会更贴近实际。我常用均值0.7、标准差0.15的截断正态分布上下限为0.1到0.9。路网拥堵影响。拥堵会改变车辆到达时间和剩余电量进而改变充电负荷开始时间。如果忽略拥堵预测的充电负荷会比实际情况更早、更集中。多步预测误差累积。不要只预测一步就把预测值当成真实值继续算下一步除非你专门研究长期预测的稳定性否则要设计多步预测的训练方式或迭代反馈策略。保存中间结果。每次仿真跑完必须把每辆车到达各站时间、SOC、充电功率等中间量保存到mat文件。后面分析异常时能直接回溯省掉反复重跑仿真。我个人在实际仿真中还有一个体会车-电-路网耦合预测的边际收益并不是线性的。当路网信息已经包含节点间通达时间和路段拥堵指数后再增加更精细的个体行为建模精度提升往往并不明显但计算量会成倍上涨。所以工程应用里先用宏观模型摸清底数再看实际需要逐步细化比一上来就追求最复杂模型要实用得多。最后再分享一个小技巧在GRU输入特征中加入“过去24小时同一节点的平均负荷”作为长程特征能让模型在凌晨低谷时段的表现稳定很多。我在调试中发现单独用短时间窗口序列训练出来的模型凌晨会出现明显的过度波动加上这个均值特征之后整体曲线平滑度好了不少代码改动量却很小只是往特征矩阵里多添了一列。如果你正准备做类似的课题建议先不要把目标定在“精确到单台车”的复杂落地上。先把车、电、路网之间的数据流打通让充电负荷能自动从路网转移到电网节点再逐步升级预测模型。这条路径看起来慢实际出成果反而快。
阅读完成 · 觉得有帮助?
咨询建站