电动汽车充电负荷预测这个事,做配电网规划的朋友应该都不陌生。要评估一个小区、一座园区或者一片区域在新增电动汽车之后会有多少充电负荷、什么时候出现用电高峰,不能靠拍脑袋估个数,得有一套能把用户随机行为反映出来的方法。我这次用的就是蒙特卡洛模拟,在Matlab里把每辆车的充电行为当成随机事件去抽样,跑几千辆车叠加成区域负荷曲线,整个建模到出图的代码量并不大,但对概率模型的理解要求比较高。
这个方法适合来做充电桩容量配置、配变容量校核、有序充电策略的底座分析,也适合正在做课程设计或毕业论文的同学,直接作为负荷预测模块的主算法。核心思路一句话讲透:用大量随机样本逼近真实场景,把随机性背后的统计规律挖出来。用到的东西主要有Matlab(版本要求不高,R2019b以上就够)、随机数生成函数和基础矩阵运算,不需要额外的专业工具箱,有统计工具箱当然更方便,没有也能用基础函数补上。
1. 内容整体设计与思路拆解
1.1 为什么是蒙特卡洛:相比确定性方法的优势
蒙特卡洛这个词听起来唬人,其实思想特别朴素。你可以理解成“撒豆子统计”:想知道豆子落在某个区域的比例,不用把每颗豆子的轨迹算得清清楚楚,只要撒足够多,统计落在每个格子里的数量就接近真实概率。充电负荷也是一样,每辆车几点到家、今天跑了多远、电池剩多少电、插上充电枪功率多大,全是随机事件,直接给一个平均值算出来的曲线,会丢掉太多真实世界的波动信息。
传统确定性算法会把所有变量取典型值,比如假设所有车辆统一在晚上19点插枪、统一需要充3小时,得到的结果是一条光滑但偏理想的曲线。实际情况下,通勤距离有长有短,到家时间受路况和加班影响,晚高峰不能用一条均值曲线来代表。蒙特卡洛的优势在于每次模拟都产生一个“可能的世界”,跑几百上千次之后,不仅能拿到最可能出现的负荷曲线,还能给出概率区间。做配变容量选择时,光看平均曲线是不够的,要看P90甚至P95场景下的峰值,否则夏天傍晚容易跳闸。
另外,蒙特卡洛不需要历史负荷数据也能建模,这对新建小区、电动汽车渗透率快速提升的规划场景特别有用。你只需要确定“用户行为服从什么分布”,剩下的交给随机抽样和统计收敛。比起神经网络、时间序列这类依赖数据量的算法,它的可解释性也更好,算出来峰值偏高或偏低,能直接追溯到是哪个参数分布设置不合理,调试起来方向非常明确。
1.2 整体技术路线与适用场景
整个项目分六步走:第一步,确定输入参数和对应的概率分布;第二步,初始化一个车辆队列,每辆车带好自己的电池容量、充电功率等属性;第三步,对每天每辆车,抽取起始充电时间、日行驶里程、初始SOC这些随机变量;第四步,计算每辆车的充电需求电量和充电时长;第五步,把每辆车的充电功率映射到24小时时间轴上,逐点累加;第六步,多次重复仿真,统计负荷的均值、分位数曲线。
这套流程最典型的应用是居民区慢充场景,因为家用充电桩绝大多数是慢充,功率集中在3.5kW到7kW之间,充电行为高度集中在傍晚到深夜,对配电网晚高峰影响最明显。公共快充站则要换一套参数体系来建模,比如起始充电时间更分散、功率高很多、充电时长短很多,建模思路可以复用,但概率分布的参数必须重新标定。我在后面的示例中会以居民区慢充为基准来展开,需要扩展快充场景的话,替换分布参数和功率配置即可。
这里也要说明一下模型边界。本文做的是“无序充电”场景,也就是车辆到家就充、充满为止,不考虑价格激励或者智能调度对充电行为的挪移。有序充电涉及的是优化问题,需要在负荷预测基础上叠加控制策略,那是另一个话题。先把无序充电的负荷预测做扎实,后续加策略才有可靠的基线。
2. 核心参数与概率模型选择
2.1 影响充电负荷的四个关键变量
充电负荷是大量用户行为的叠加结果,但真正主导曲线形状的变量其实就四个:起始充电时间、日行驶里程、动力电池容量和充电功率。理解了这四个变量,整个模型就已经完成了一半。
起始充电时间决定了负荷迁移到傍晚的具体位置。绝大多数私家车用户下班回家后插枪,所以起始时间大概率集中在17点到21点之间,峰值在19点左右,这个规律不同城市的调研数据都高度一致。日行驶里程决定电池消耗了多少、需要补多少电,正常情况下是右偏分布,大部分用户每天跑三四公里到四五十公里,少数跑长途的会到一两百公里甚至更多。电池容量和车型相关,微型车可能在30kWh上下,中型轿车五六十,长续航车型可到80甚至100kWh,不同车型混在一起要按比例混合。充电功率由充电桩决定,私人慢充桩常见3.5kW和7kW两档,公共慢充也有7kW,但本文场景先以家用桩为主,功率相对统一。
这四个变量不是孤立存在的,它们通过充电需求电量公式串起来。日行驶里程越大,到达时剩余电量比例越低,需要充入的电量越多,充电时长就越长。起始充电时间越晚,加上充电时长之后,充电结束时间直接关系到有没有跨过零点、并入第二天的负荷曲线。所以建模的时候不能只单独抽样每个变量,要按逻辑链条逐步计算,最后才能得到物理上自洽的结果。
2.2 概率分布选择的依据与参数设定
概率分布怎么选,我建议优先看调研数据画出来的直方图长什么样,然后去匹配常见分布族。起始充电时间在实测里通常表现为单峰、左右基本对称,用正态分布描述是业界最普遍的做法,均值在18到19点之间,标准差大约2到2.5小时。日行驶里程则是典型的右偏长尾分布,对数正态分布是最常用的选择,因为里程不可能为负,且大多数人的里程集中在一个相对较低的区间,少数人的里程特别长,对数正态的偏态形状正好贴合这个特征。
电池容量和充电功率,如果模拟的是单一车型或单一小区,可以直接用固定值和两三个离散档位来建模,没必要强上连续分布。如果要做城市级或者多车型混行的预测,就用正态分布并配合车型比例做混合抽样。充电效率这个参数很多人会忽略,实际从电网侧取电到电池存储,中间有车载充电机和电池管理系统的损耗,一般取0.85到0.92,具体看充电方式,慢充效率略高一些。
下面这张表是我在做仿真时常用的一组参数基线,参考了多篇公开文献里美国家庭出行调查和国内部分城市的出行统计结果,具体数值可以根据你手头的实际数据替换:
| 参数 | 分布/取值 | 典型值 | 备注 |
|---|---|---|---|
| 起始充电时间 | 正态分布 | N(18.5, 2.5^2) | 单位小时,以0点为0 |
| 日行驶里程 | 对数正态分布 | 均值e^(3.2),方差0.88 | 单位km,取lognrnd(3.2,0.88) |
| 电池容量 | 分段常数/正态分布 | 40~60 kWh | 按车型比例混合 |
| 百公里电耗 | 固定值 | 15 kWh/100km | 或按车型细分 |
| 充电功率 | 分段常数 | 3.5kW / 7kW | 慢充为主 |
| 充电效率 | 固定值 | 0.9 | 慢充典型效率 |
| 目标SOC | 固定值 | 1.0 | 充满为止 |
这里要特别提醒一个新手很容易踩的坑:对数正态分布的参数不是直接填“均值”,而是填对数域上的均值mu和标准差sigma。如果看到文献里写“日行驶里程均值为32km,标准差为20km”,直接拿这两个数填lognrnd就错了,需要先转换到对数域,或者用分布拟合工具从原始数据里估计mu和sigma。我自己第一次做的时候就犯过这个错误,结果模拟出来的充电负荷峰值特别离谱,检查半天才发现是分布参数没转换。
3. Matlab代码实现与核心环节拆解
3.1 代码总体框架与初始化设置
整个Matlab程序不需要多复杂的结构,一个主脚本就能跑通全部流程,建议再加一个参数配置区放在文件头部,这样调参不用满文件翻。我习惯把仿真参数分成两类:一类是模型本身的物理参数,比如电池容量、充电功率、效率;另一类是蒙特卡洛的控制参数,比如模拟车辆数、仿真天数、时间分辨率。区分清楚之后,后面做参数敏感性分析会很方便。
时间分辨率建议设成10分钟或者15分钟,也就是DT = 1/6小时,太粗会丢失高峰细节,太细会让计算量成倍增长。24小时对应144个时间槽,单次叠加上千辆车在Matlab里也就是毫秒级运算,不用担心性能。循环部分,建议把“模拟天数”和“车辆数”分开,因为每天的重随机抽样是独立的,画最终曲线时用一个“场景”的概念:每一天就是一次场景抽样,所有天数的结果汇总后取均值和分位数。
初始化部分还有一个习惯值得养成——固定随机数种子。代码开头加上rng(2024)或者任意你喜欢的数字,就能保证每次运行结果完全一致。这对调试阶段和论文可复现性都特别重要。如果没有固定种子,每次跑出来的曲线细微差别会被误判成算法问题,实际上只是随机波动,白白浪费时间排查。
下面这段是参数配置和初始化区的骨架:
%% 参数设置区 N_VEH = 1000; % 单日模拟车辆数 N_DAY = 200; % 模拟天数,用于统计概率区间 DT = 1/6; % 时间分辨率,单位小时(10分钟) T_SLOTS = 24 / DT; % 24小时对应的时间槽数量 rng(2024); % 固定随机种子,保证可复现 % 车辆与充电参数 batteryCap = 50; % 电池容量,kWh powerCharge = 7; % 充电功率,kW chargeEff = 0.9; % 充电效率 energyPerKM = 15/100; % 百公里电耗15kWh => 每公里0.15kWh targetSOC = 1.0; % 目标SOC,默认充满3.2 核心环节一:车辆行为随机抽样
抽样是整个蒙特卡洛模型的心脏。每次模拟开始前,要为每辆车抽取三个核心随机数:起始充电时间、日行驶里程、以及可能的车型参数。这里的技巧是向量化操作,也就是一次性生成N辆车的数据,而不是用for循环逐辆车抽样。Matlab对向量化运算的优化非常好,几百辆车的循环体感觉不出来,但如果后续扩展到上万辆,循环和向量化的效率差距就非常明显了。
起始充电时间用normrnd生成正态分布随机数,日行驶里程用lognrnd生成对数正态随机数,这一步对应前面选好的概率模型。生成完参数后,紧接着计算每辆车到达时的剩余SOC。计算公式是:到达SOC = 1 - 日行驶里程 / (电池容量 / 每公里能耗)。这里行驶里程如果超过续航里程,说明电池完全耗尽,但现实中用户一般会提前充电,所以要对SOC设置一个下限,比如不低于0.1,防止出现负SOC导致充电时长计算异常。
这里有个细节值得讲一下:起始充电时间和到家时间不完全是一回事。调研数据显示,不少用户回到家并不会立刻插枪,可能先吃饭、处理些杂事再充电,这个时间差本身也可以建模成一段随机延迟。在基础模型中,我更倾向于直接把“起始充电时间”作为抽样对象,而不是先抽到家时间再叠加延迟。因为很多文献给出的统计参数本身就是针对插枪时刻的,直接使用可以减少一个环节的假设误差。如果你手里只有到家时间的数据,再加上一个均值30到60分钟的伽马分布延迟,是更严谨的做法。
抽样部分的核心代码如下:
%% 单日场景抽样 % 起始充电时间:正态分布,均值19点,标准差2.2小时 arriveHour = normrnd(19, 2.2, N_VEH, 1); % 日行驶里程:对数正态分布,单位km mileage = lognrnd(3.2, 0.88, N_VEH, 1); % 计算到达时SOC,下限截断到0.1 socArrive = 1 - mileage ./ (batteryCap / energyPerKM); socArrive = max(socArrive, 0.1); % 充电需求电量 energyNeed = batteryCap .* (targetSOC - socArrive) / chargeEff; % 充电时长 chargeHours = energyNeed / powerCharge; % 充电结束时刻 endHour = arriveHour + chargeHours;3.3 核心环节二:充电负荷在时间轴上的聚合
每辆车的充电功率是多少、什么时候开始、什么时候结束,这些信息都有了,接下来要做的就是把所有充电过程叠加到24小时的时间轴上。叠加方法有两种:一种是把每辆车的充电区间按时间槽切分,挨个往对应的槽里加功率;另一种是按矩阵索引的方式,用向量化操作一次性完成累加。第一种好理解,第二种效率高,实际使用中我更倾向于先用循环把每辆车的起止槽位算清楚,再用accumarray来聚合,代码简洁也不容易出错。
跨零点充电的情况必须处理。假设辆车19点开始充电,需要充6小时,直接算到凌晨1点,如果索引只有24个槽位,就会越界报错。我习惯的做法是把时间轴拉长到48小时,也就是用T_SLOTS * 2个槽位,每辆车在起始时间和起始时间加充电时长内映射功率,最后只取前24小时的数据作为当天负荷,后24小时的数据丢弃。这样处理跨天充电比较自然,也方便后续做连续多日仿真时拼接曲线。
聚合计算的代码可以是:
%% 负荷聚合 % 计算起止槽位,时间轴扩展到48小时 startSlot = floor(arriveHour / DT) + 1; endSlot = floor((arriveHour + chargeHours) / DT) + 1; loadCurve = zeros(T_SLOTS * 2, 1); for k = 1:N_VEH s = startSlot(k); e = min(endSlot(k), T_SLOTS * 2); if e <= s, continue; end loadCurve(s:e) = loadCurve(s:e) + powerCharge; end % 只取前24小时的负荷 loadToday = loadCurve(1:T_SLOTS);用循环处理聚合是因为不同车辆的区间长度不同,向量化写法在边界处理上比较绕。N_VEH是1000时循环完全能接受,如果车辆规模到了几万辆觉得循环慢了,再考虑用cellfun或者accumarray的进阶写法。性能问题不是这个模型的主要矛盾,正确性和可调试性才是。
3.4 外部循环与概率区间统计
单日负荷曲线有了,接下来就是蒙特卡洛最核心的重复模拟过程。外层循环N_DAY次,每次独立抽样得到一条日负荷曲线,最后把所有天的曲线存进一个矩阵里,行是时间槽,列是模拟天数。然后对每一行求均值,就得到平均负荷曲线;求5%和95%分位数,就能得到概率区间带。这一整套操作非常直白,但对结果的理解要到位:均值和分位数的差,反映的是“随机性带来的不确定范围”,而不是测量误差。
绘制概率区间时,我会用fill函数把P10到P90的区间涂上浅色,再用深色实线画均值曲线,这样一张图就能同时表达最可能场景和风险边界。论文或者报告里的典型配图基本就是这种样式。如果只想看某一置信水平的极端场景,直接画P95曲线就行,配变容量校核一般参考的就是这个级别的峰值。
多日仿真与区间统计的代码框架如下:
%% 多日蒙特卡洛仿真 dailyProfiles = zeros(T_SLOTS, N_DAY); for d = 1:N_DAY % 这里放入3.2和3.3的抽样与聚合代码 dailyProfiles(:, d) = loadToday; end % 统计平均曲线及分位数区间 avgLoad = mean(dailyProfiles, 2); p10Load = prctile(dailyProfiles, 10, 2); p90Load = prctile(dailyProfiles, 90, 2); % 画图 t = (0:T_SLOTS-1) * DT; figure; fill([t fliplr(t)], [p10Load; flipud(p90Load)], 'b', 'FaceAlpha', 0.2, 'EdgeColor', 'none'); hold on; plot(t, avgLoad, 'b-', 'LineWidth', 1.8); xlabel('时刻(小时)'); ylabel('负荷功率(kW)');## 4. 仿真实验与结果解读 ### 4.1 三种典型场景的参数对比 算法跑通之后,最有价值的应用就是做场景对比。我整理了三个典型场景来做演示:基准居民区场景、高渗透率场景、快充混入场景。基准场景全部是7kW慢充,车辆电池容量统一取50kWh,起始充电时间集中在19点左右,这就是一个典型的城市居民区。高渗透率场景把车辆数从1000提升到3000,相当于电动汽车渗透率更高的小区,其他参数不变,看负荷峰值随数量的变化关系。 快充混入场景稍微复杂一些,假设有20%的车辆使用60kW快充桩,充电行为不集中在晚间,而是分散在白天和傍晚。快充的充电功率高、时间短,对电网的冲击形态和慢充完全不同。参数对比表如下: | 场景 | 车辆数 | 充电功率 | 起始时间分布 | 平均充电时长 | |---|---|---|---|---| | 基准居民区 | 1000 | 7kW | N(19, 2.2) | 约3.5h | | 高渗透率 | 3000 | 7kW | N(19, 2.2) | 约3.5h | | 快充混入 | 800慢充+200快充 | 7kW / 60kW | 慢充晚间,快充全天 | 慢充约3.5h,快充约0.8h | 这组对比能回答两个实际问题:第一,小区电动汽车数量增加一倍,晚高峰配变容量是否需要跟着翻倍;第二,引入快充桩后,负荷曲线形状会发生什么变化,是否需要额外配置储能来削峰。在做这些分析之前,先把三个场景跑一遍,把曲线画出来,心里就有底了。 ### 4.2 结果曲线的典型规律与解读 基准场景跑完,曲线的形态一定有这些特征:下午四五点之前负荷几乎为零,因为用户基本还没开始充电;傍晚六七点开始陡增,到晚上八点到九点之间达到峰值;随后缓慢下降,到凌晨三四点彻底归零。峰值时刻比起始充电时间分布的均值略晚,原因很简单——负荷是功率的叠加结果,到达时间集中在均值附近,叠加后峰值自然滞后了一些。 概率区间在高峰时段最宽,低谷时段几乎为零。这个现象不难解释:在高峰时段,哪些车来了、哪些车没来、来了充多久,各种随机性全部叠加在一起,波动自然最大;而在凌晨时段,几乎所有车都充完了,随机性没有发挥空间。这也是为什么单日模拟曲线没有参考价值,必须用大量天数做统计才能看到稳定的规律。 高渗透率场景的峰值不是简单按车辆数线性增长。因为负荷曲线本身就是多辆车充电区间的叠加,车辆数增加时峰值区间变宽,叠加更加充分,峰值增长率会略低于车辆数增长率。这就是蒙特卡洛方法的体现——它能帮你发现简单的倍数估算容易忽略的“随机性平滑效应”。快充混入场景则要注意,白天的负荷会明显抬高,但是晚高峰的抬升幅度并没有想象中那么高,因为快充桩本身的利用率分散在全天。 ## 5. 常见问题与排查技巧实录 ### 5.1 高频问题速查表 做这个项目过程中最容易遇到下面几类问题,我整理成了一张速查表,每一条都是实际踩过坑之后总结出来的: | 问题现象 | 可能原因 | 解决思路 | |---|---|---| | 负荷曲线出现负值或SOC小于0 | 行驶里程大于续航,SOC计算超出范围 | 对SOC做下限截断,或过滤掉超长里程样本 | | 模拟结果每次运行都不一样 | 没有固定随机种子 | 在代码开头加rng函数固定种子 | | 峰值时刻和预期偏差很大 | 起始充电时间的分布参数设置不合理 | 核对是不是把标准差设太大或者均值偏了 | | 充电结束时索引越界报错 | 起始时刻加充电时长超过24小时 | 把时间轴扩展到48小时后截取前24小时 | | 负荷曲线毛刺特别多不光滑 | 模拟天数太少或车辆数太少 | 增加N_DAY和N_VEH,随机波动会被平均掉 | | 不同车型混合时曲线有突兀跳变 | 电池容量或功率按比例混合时概率没归一化 | 检查车型比例之和是否为1,抽样逻辑是否写对 | ### 5.2 实操避坑心得 第一个心得是分布检验。很多同学从论文里抄来分布参数,抄完直接跑,根本不验证抽样数据长什么样。我建议每次抽样完,先对抽样结果做一次简单的可视化检查,比如histogram画一下起始充电时间,看是不是符合预期的钟形分布。再计算一下抽样均值和标准差,和理论的设定值做对比,偏差太大多半是参数理解有误。如果数据量允许,用Matlab的fitdist函数对原始调研数据做分布拟合,比抄参数可靠得多。 第二个心得是关于收敛性判断。蒙特卡洛的结果依赖样本量,那到底模拟多少天才够?我判断收敛的方式很简单:把模拟天数从50逐步增加到500,记录峰值的变化,如果峰值随天数增加还在明显波动,说明还没收敛;如果峰值变化缩小到1%以内,基本就够了。实际操作中200天到500天通常就能得到稳定的均值曲线,分位数区间再多的天数差别也不大,没必要一味追求上万次模拟。 第三个心得是收敛性检验的另一面:不要以为固定了随机种子、结果稳定了,就代表模型正确。固定种子只能保证“可复现”,不能保证“正确”。如果某个分布的参数输错了,结果每次会一致地错,反而不容易发现。所以我会在不同的随机种子下跑几次对比,确认曲线的形态和量级基本一致,同时用实际常识做验证——比如说1000辆车的居民小区,晚间充电峰值大概在一两千千瓦这个数量级,如果算出来峰值接近一万千瓦,肯定哪里出了问题。 第四个心得和代码结构有关。我建议把参数配置、单日模拟、多日统计分别写成独立的section甚至函数,方便调试。尤其是单日模拟逻辑,单独封装成函数后,可以直接在命令行测试抽样和聚合逻辑,不用每次跑完整的多日循环。排查问题时,先用一个很小的车辆数比如10辆车单步调试,看每辆车的充电区间和聚合值是否符合预期,确认无误后再放大规模。直接跑1000辆车还指望一眼看出问题,不现实。 ## 6. 最后再分享一点扩展思路 蒙特卡洛负荷预测模型做到这个程度,已经是一个可以直接交付的预测工具,但它更像是整个配用电分析的第一块积木。往上可以加有序充电策略——把负荷预测结果当成优化模型的输入,用价格信号或者功率限制来引导充电行为;往旁边可以接入光伏出力的随机模拟,结合本模型做光储充一体化项目的容量配置;往下还可以把时间分辨率细化到分钟级,研究单台配变或台区线路的短时过载风险。 我个人在实际使用中体会最深的一点是:蒙特卡洛方法本身的代码实现并不难,难的是对随机模型的敬畏。每个分布参数背后都是真实的用户行为,需要花时间去校核、验证、修正,而不能停留在“能跑出图”的层面。宁可多做几次分布检验和异常场景测试,也别急着把结果拿去出报告——这一点在负荷预测这类直接关联电网投资决策的问题上尤其关键。