☰
基于蒙特卡洛模拟的电动汽车充电负荷预测与可配置参数实现
2026/10/17 5:19:25 网站建设 项目流程

做充电负荷预测的朋友应该都有一个共识:拍脑袋估数是最容易翻车的事。同一批电动车,有人下班到家就插上慢充桩充一整夜,有人中午逛商场顺手快充半小时,还有人一天补三次电。这些零散行为混在一起,最终落在配电变压器上的负荷曲线完全不是一个形状。我那会儿做某园区充电方案评估时,就是靠蒙特卡洛模拟,把一充、二充、三充、快充、慢充这几种行为揉进一个可配置的仿真框架里,输出日充电功率曲线,而且每天充电数量的比例随手就能改。今天就把这套思路和完整实现拆开聊一聊,适合做配电网规划、充电站运营、有序充电策略研究的工程师和同学参考。

1. 项目思路:为什么充电负荷模拟绕不开蒙特卡洛

1.1 充电行为的随机性来自哪里

电动汽车充电负荷和传统居民负荷有个本质区别:传统负荷虽然也在变,但大体上跟着气温和作息走,规律性强;充电负荷则是大量随机事件的叠加。每一辆车的充电行为,至少受四层随机因素影响。

第一层是用户习惯,也就是一天充几次、什么时间充。有的人通勤距离短,两三天才充一次;有的人每天跑得多,中午得补一次电,晚上回家再充满。第二层是车辆状态,主要是起始SOC,也就是开始充电时电池里还剩多少电。这跟用户的出行里程、路况、空调开没开都有关,同一个用户每天的SOC都不一样。第三层是充电设施,用户去充电时遇到的是快充还是慢充,取决于停车场景和充电桩类型。第四层是充电持续时长,它不是一个固定值,而是由“需要补充的电量”和“充电功率”共同决定的。

如果把这些因素全部简化成固定值,比如“晚上8点开始充、功率7kW、充5小时”,算出来的结果当然很干净,但和真实情况差得远。真实场景里,晚上8点是平均值,可能6点就有人充,也有人拖到11点才插枪。蒙特卡洛模拟的核心价值,就是把这些随机因素全部显式建模,一辆车一辆车地“抽样—计算—叠加”,大量重复之后,负荷曲线的统计特征自然浮现出来。

1.2 蒙特卡洛方法在这个场景里的定位

蒙特卡洛不是什么高深算法,本质就是“用大量随机试验逼近真实概率分布”。你可以把它类比成抽签:一万辆车,每辆都从行为分布里抽一组参数,算出它今天的充电时段和功率,加到一起,得到一天的总负荷;然后整个试验重复300次,得到300条“可能的一天”,再求平均、取分位数。

那为什么不用解析公式直接算期望负荷?理论上可以,但实际操作中非常困难。充电起始时间是多峰分布,充电时长有截断(快充不能超过某个时间、慢充也不能无限充),充电可能跨天,SOC有上下限,这些约束条件叠在一起,期望负荷的闭合表达式根本写不出来。即使写出来,稍微改一个参数,整个表达式又得重推。蒙特卡洛的好处是“模型与人分离”:参数随便改,核心抽样逻辑不用动,跑一遍就有新结果。尤其在方案阶段,需要快速回答“如果一充用户比例从60%降到40%会怎样”“如果快充比例翻倍会怎样”这类问题,蒙特卡洛几乎是最高效的手段。

1.3 整体建模框架与数据流向

整个模型的输入参数可以分成五类:车辆规模与用户分类比例、快慢充功率、电池参数与SOC分布、充电起始时间分布、模拟迭代次数。输出则是一天96个时间点(15分钟粒度)的日充电功率曲线,以及峰值、总电量等衍生指标。

数据流向是单向的:先固定所有参数,然后对每一辆车抽取“用户类别—充电次数—快慢充类型—起始充电时间—起始SOC”这一组随机参数,根据SOC和目标SOC算出需要补充的电量,再除以功率得到充电时长,把功率平铺到对应的时间槽上。一辆车算完就加到总负荷数组里,下一辆车继续独立抽样。这样循环N辆车,得到一条“模拟日”的负荷曲线。外层再重复M次,得到M条曲线,用于统计平均曲线和置信区间。

这个框架的核心优势是模块化:你想改充电次数比例,只动一个变量;你想把慢充功率从7kW改成11kW,也只动一个变量;你想让三充用户更多用快充,改一个交叉矩阵就行。模型逻辑本身不用重建。下面详细拆解参数体系设计。

2. 参数体系设计:一充二充三充和快慢充怎么落地

2.1 “一充、二充、三充”的用户分类逻辑

日充电次数是描述用户充电行为最粗粒度也最稳定的一个维度。按一天充电1次、2次、3次把用户分成三类,物理含义很直观。

一充用户对应典型通勤场景:白天开车上班,晚上回家插上充电桩,第二天满电出发。这类用户的充电起始时间高度集中在傍晚到夜间,充电位置多为小区或单位停车场,慢充占比明显更高。二充用户通常有两种典型画像:一种是中午有较长午休时间,在外面顺手补一次电,晚上回家再充满;另一种是营运车辆,白天利用接单间隙快充一次,晚上收工后慢充充满。三充用户的充电行为就更加碎片化,常见于城市配送、网约车、公务用车等高频用车场景,早中晚都可能补电,单次充电量不大,但每次停留时间短,对快充的依赖明显更强。

这里有一个关键设计决策:为什么按“充电次数”而不是“车辆类型”作为第一层分类?我的经验是,充电次数是结果变量,它天然综合了运营强度、出行距离和充电便利性等多重信息。如果直接按“出租车、私家车、物流车”来分,你会发现每一类内部的行为差异依然巨大,反而把模型做复杂了。而按充电次数分类后,每一类内部的时间分布、SOC分布、快慢充偏好都更集中,抽样出来的结果更符合直觉。日充电数量的比例,也就是代码里的ratio_1、ratio_2、ratio_3,是用户可以自行修改的最核心参数。

2.2 快充慢充的功率参数与交叉矩阵

快充和慢充的功率差异非常悬殊。慢充典型值在7kW左右,对应家用交流充电桩;一些新建小区或单位的交流桩能达到11kW或22kW。快充一般取60kW到120kW,对应直流充电桩;现在有些超充已经到250kW,但落地量还不大。建议模型默认取慢充7kW、快充60kW,这两组值最稳妥,也最容易和实际配电数据对上。

功率类型不能只是一个全局比例,而应该和用户类别交叉。我的做法是构造一个“充电次数类别×快慢充占比”的矩阵。一充用户快充占比取10%左右,二充用户取30%左右,三充用户取60%左右。这样设计的理由是:一充用户绝大多数在家里或单位充,慢充就够了;二充用户在外面补电的时间相对有限,快充比例明显上升;三充用户单次停留时间最短,补电场景多在途中,快充是刚需。

2.3 日充电功率的统一口径与输出形式

输出曲线的时间粒度建议统一为15分钟,也就是一天96个点。为什么不用1分钟或1小时?1分钟粒度噪声太大,而且配电自动化系统里常见的历史数据粒度就是15分钟;1小时粒度又太粗,晚高峰的形态会被抹平,峰值功率明显失真。15分钟是工程上最实用的折中。

日充电功率曲线有两种输出口径。一种是“平均曲线”,就是M次模拟逐点求平均,代表典型日的负荷形态;另一种是“分位数曲线”,比如95%分位数,代表“比较恶劣但还不能忽略”的负荷情形。做配变容量校核时,我一般建议看95%分位数的峰值,而不是平均曲线的峰值,更稳妥,也不像最大峰值那样容易过度设计。

另外还要统计两个标量指标:日最大充电功率(峰值)和日总充电电量。这两个指标是后续做变压器容量选择、充电桩数量配置时最直接的输入。峰值乘以适当系数可以用来校核配变容量,总电量则和电费测算直接挂钩。

3. 实操过程与核心代码实现

3.1 从参数到结果的完整流程

整体实现流程可以拆成七个步骤,顺序不能乱,因为后一步总是依赖前一步的输出。

  1. 固定随机种子,保证结果可复现。
  2. 配置全部输入参数:车辆数、类别比例、快慢充占比、功率、电池容量、SOC分布、时间窗口、迭代次数。
  3. 初始化一个长度为96的全零负荷数组。
  4. 随机生成每辆车的用户类别,类别概率由一充、二充、三充的比例决定。
  5. 对每辆车,根据其类别抽起始充电时间、快慢充类型、起始SOC,计算充电时长。
  6. 把充电功率叠加到对应时间槽上,注意充电可能跨天,需要循环填充。
  7. 重复步骤4到6共M次,得到M条日负荷曲线,最后统计平均曲线、分位曲线、峰值和总电量。

第4步到第6步是蒙特卡洛模拟的内核,外层的迭代只是把“抽样—叠加”重复多次,让统计结果稳定下来。理解了这个主循环,整个代码结构就清晰了。

3.2 比例参数怎么改(核心易用性设计)

标题里强调的“可自行修改日充电数量的比例”,在代码里就体现为最上面三个变量。我把参数区单独拎出来,方便随时改:

import numpy as np # ==================== 参数配置区 ==================== # 随机种子,保证结果可复现 SEED = 42 # 一充 / 二充 / 三充 用户占比(可自行修改的核心参数) ratio_1 = 0.60 ratio_2 = 0.30 ratio_3 = 0.10 # 快充占比(同一类别内部的快充比例) fast_ratio_1 = 0.10 fast_ratio_2 = 0.30 fast_ratio_3 = 0.60 # 平均功率(kW) P_fast = 60.0 P_slow = 7.0 # 电池容量(kWh) battery_cap = 60.0 # 不同类别用户的起始SOC均值 / 标准差 soc_mean_1, soc_std_1 = 0.30, 0.12 soc_mean_2, soc_std_2 = 0.50, 0.12 soc_mean_3, soc_std_3 = 0.60, 0.10 # 目标SOC(一般充到90%就停) soc_target = 0.90 # 时间分辨率 RES = 15 # 分钟 TP = 24 * 60 // RES # 96个点 # 模拟车辆数与迭代次数 N = 10000 M = 300 # ==================== 参数配置区结束 ====================

这段代码最需要说明的是:三个比例并不需要在代码里强制相加等于1,程序内部会自动归一化。也就是说,你填0.6、0.3、0.1可以,填6、3、1也可以,结果等价。但建议还是养成习惯写成小数,可读性好,也避免同事误读。

SOC参数这里,我特意让三类用户的均值不同:一充用户平均SOC只有0.3,因为这类用户基本是把电用得差不多了才充;二充用户平均0.5,因为中午已经补过一次,晚上开始充的时候电量不会太低;三充用户平均0.6,高频补电的车辆电量通常维持在中高位。这个细节决定了各类用户单次充电量的差异,对最终曲线形态影响非常大。

3.3 蒙特卡洛采样与负荷叠加的代码实现

先说充电起始时间的采样。现实生活中,用户不会均匀分布在一天24小时里充电,而是有明显的聚集效应:晚高峰、午休、清晨是几个典型窗口。我把它建模为“多峰正态分布”的加权混合,每个峰有均值、标准差和权重。比如一充用户,85%概率落在晚上7点左右,15%概率落在早上8点半左右:

# 一天内充电起始时刻的多峰分布(小时制) # 每个元素为 [均值, 标准差, 权重] time_patterns = { 'one_charge': [ [19.0, 1.5, 0.85], [8.5, 1.0, 0.15], ], 'two_charge': [ [13.0, 1.0, 0.40], [20.5, 1.5, 0.60], ], 'three_charge': [ [8.0, 1.0, 0.30], [13.5, 1.0, 0.30], [20.0, 1.5, 0.40], ], } def sample_start_time(pattern): """从多峰分布中采样一个起始充电时间(小时)""" weights = np.array([p[2] for p in pattern], dtype=float) weights /= weights.sum() idx = np.random.choice(len(pattern), p=weights) mu, sigma, _ = pattern[idx] t = np.random.normal(mu, sigma) t = t % 24.0 return t

取模操作实际上把超出24小时的时间点折返到凌晨,这样做在慢充跨天场景下是合理的,因为深夜充电和凌晨充电在负荷曲线上都表现为夜间平台。如果你想把边界处理得更精细,也可以用拒绝采样,只保留落在合理区间内的样本,效果更严谨但性能略差。

接下来是单日模拟主函数。每辆车依次做五件事:抽类别、抽充电次数、抽每次的起始时间、抽快慢充、抽SOC、算时长、叠加功率:

def simulate_one_day(): """模拟一天的总充电负荷曲线,返回96点数组""" load_curve = np.zeros(TP) # 归一化用户比例 ratios = np.array([ratio_1, ratio_2, ratio_3], dtype=float) ratios /= ratios.sum() # 随机生成每辆车的用户类别 categories = np.random.choice([1, 2, 3], size=N, p=ratios) for cat in categories: if cat == 1: n_charge, fast_ratio = 1, fast_ratio_1 pattern, soc_mean, soc_std = time_patterns['one_charge'], soc_mean_1, soc_std_1 elif cat == 2: n_charge, fast_ratio = 2, fast_ratio_2 pattern, soc_mean, soc_std = time_patterns['two_charge'], soc_mean_2, soc_std_2 else: n_charge, fast_ratio = 3, fast_ratio_3 pattern, soc_mean, soc_std = time_patterns['three_charge'], soc_mean_3, soc_std_3 # 依次处理每次充电 for _ in range(n_charge): start_h = sample_start_time(pattern) is_fast = np.random.rand() < fast_ratio P = P_fast if is_fast else P_slow # 起始SOC不能低于0.05,也不能高于目标SOC - 0.05 soc = np.random.normal(soc_mean, soc_std) soc = np.clip(soc, 0.05, soc_target - 0.05) # 需要补充的电量(kWh) energy_needed = (soc_target - soc) * battery_cap # 充电时长(小时),并设置上限 duration_h = energy_needed / P max_h = 1.5 if is_fast else 8.0 if duration_h > max_h: duration_h = max_h # 将功率叠加到96个时间槽,注意跨天循环填充 start_idx = int(start_h * 60 / RES) duration_idx = int(round(duration_h * 60 / RES)) idx = start_idx for _ in range(duration_idx): load_curve[idx % TP] += P idx += 1 return load_curve

这里有两个容易被忽略的细节。第一,起始SOC的截断下界设成0.05而不是0,是因为电池管理策略一般不会让电量耗尽到0,而且SOC为0时充电功率也未必是满功率。第二,充电时长上限的设计:快充取1.5小时、慢充取8小时。60kW充1.5小时对应90kWh,7kW充8小时对应56kWh,都略大于电池从最低SOC充到目标所需的最大电量。这样设置既能防止异常抽样值导致时长爆炸,又不会把正常充电行为截断掉。

外层循环只需重复调用simulate_one_day多次,并把结果存起来:

np.random.seed(SEED) curves = [] for _ in range(M): curves.append(simulate_one_day()) curves = np.array(curves) # 形状 (M, 96) mean_curve = curves.mean(axis=0) p95_curve = np.percentile(curves, 95, axis=0) peak_mean = mean_curve.max() energy_total = mean_curve.sum() * RES / 60.0 # kWh print(f"平均日峰值功率: {peak_mean:.2f} kW") print(f"平均日总电量: {energy_total:.2f} kWh")

3.4 运行结果验证与总量守恒校验

模拟结果出来之后,第一步不是画图,而是做校验。我最常做的是“总量守恒校验”:用期望充电次数乘以期望单次充电量,和模拟出来的总电量对比,偏差一般在2%以内才算正常。

以默认参数为例:N=10000辆车,一充、二充、三充比例为0.6、0.3、0.1,那么一天总充电次数的期望值是10000乘以(0.6×1加0.3×2加0.1×3)等于15000次。再看单次充电量:一充用户平均SOC 0.3,单次平均补电0.6×60等于36kWh;二充用户平均SOC 0.5,单次平均补电24kWh;三充用户平均SOC 0.6,单次平均补电18kWh。于是总日电量期望等于一充的6000×36、二充的6000×24、三充的3000×18加起来,约41.4万kWh。

如果你的模拟结果和这个估算值偏差超过5%,基本可以断定代码里有bug,多半出在跨天填充或时长截断的处理上。这招在调试阶段能帮你省很多时间。

4. 结果解读与参数敏感性

4.1 典型日充电功率曲线长什么样

默认参数下,日充电功率曲线呈现出明显的“晚峰为主、午峰为辅、夜间平台”三段式形态。

晚高峰出现在19点到21点,对应一充用户下班回家后集中充电,同时叠加二充用户的第二次充电。这个峰的陡峭程度直接受一充用户比例影响,比例越高,峰越尖。午间小峰出现在13点到14点,主要来自二充用户和三充用户的午间补电,幅度大约是晚峰的30%到50%。夜间平台则很有意思:它看起来不像峰,而是一条缓慢下降的曲线,这是因为一充、二充用户的慢充行为持续到深夜,虽然单辆车功率只有7kW,但数量多、时间长,累加起来仍然有可观的负荷。

这里值得专门提一句:很多人做负荷预测时只盯着晚高峰,忽略了夜间平台。但对配电网来说,夜间平台同样重要,因为变压器容量选择不仅看峰值,还要看持续负荷下的热累积效应。夜间平台如果持续五六个小时,对设备寿命的影响不可小觑。

4.2 调整一充二充三充比例后会发生什么

比例参数是标题里强调的“可自行修改”的部分,也是做方案对比时最常用的旋钮。我实际跑过几组对比,规律很明显。

如果把一充比例从0.6降到0.4,同时把二充提到0.4,三充保持0.2,晚高峰峰值会明显下降,因为原本集中在下班后的充电需求被分流到了午间。总量变化不大,但峰谷差缩小。如果把三充比例从0.1提到0.3,同时压缩一充到0.4,二充0.3,曲线会变得更“摊平”:白天多个时段都有小峰,晚高峰从“尖峰”变成“宽峰”。

这背后的逻辑不复杂:充电次数越多的用户,起步充电时间越分散,单次充电量也越小。三充用户每次只补20%左右的电量,快充半小时就走,对负荷曲线的贡献是平滑而连续的。所以你在做充电设施规划时,如果预测某个片区网约车、物流车比例高,就不要按照“晚高峰单峰”的思路去配变压器,那样会高估峰值需求,造成容量浪费。

4.3 快充占比变化对峰值的影响规律

快充占比的影响比想象中更微妙。表面上看,快充功率大,峰值肯定更高,但实际结果还要看充电时长和起始SOC的交互作用。

默认参数下,一充用户快充占比只有10%,晚高峰的主要贡献者是慢充大军,7kW慢慢充。如果把快充占比整体翻倍,比如一充提到0.3、二充提到0.5、三充提到0.8,你会看到晚高峰峰值抬升,但抬升幅度远没有功率差距那么夸张。原因是快充的充电时长大幅缩短,单辆车占用负荷窗口的时间从五六个小时压缩到半小时左右,高峰时段“同时在线充电”的车辆数反而少了。最终峰值的变化取决于“单车道率提升”和“同时率下降”哪个占主导。

我在实际项目中遇到过一版方案,快充比例从30%提到60%,峰值只涨了18%,而总充电量几乎不变。这个结论对充电站运营很有意义:适度提高快充渗透率,可以在不显著增加配电压力的前提下提升充电周转率。当然,如果快充桩集中在同一个配电节点上,局部冲击仍然需要专门校核,这是另一个层面的问题。

5. 常见问题与避坑指南

5.1 随机种子:复现与对比的根基

蒙特卡洛模拟既然带随机性,复现就是头等大事。我在项目里踩过这样的坑:第一次跑出一组结果,第二天想重新看一遍,发现曲线和昨天不一样,峰值差了几个百分点。后来才意识到是没设随机种子。

固定种子的另一个用途是参数对比。你要比较“一充比例0.6”和“一充比例0.4”两种场景时,如果不固定种子,两次模拟之间的差异里混入了随机噪声,结论可能被噪声干扰。固定种子之后,唯一的变量就是比例参数,结果差异才能完全归因于参数变化。虽然这在统计上不是最严格的做法,但工程方案对比中非常实用。

5.2 迭代次数太少会怎样

外层迭代次数M决定了统计结果的稳定性。我刚开始写这个模型时,为了跑得快,M只设了20次。结果峰值每次跑都不一样,波动幅度能到5%以上,根本没法写进报告。

经验值是:单次模拟车辆数N在5000到20000之间时,M取200到300就足够稳定了。判断标准不用太复杂,你把M从100改成300,看平均曲线的峰值变化是否小于1%。如果满足,就说明收敛了。另外M也不是越大越好,超过500以后,计算时间线性增加,稳定性提升非常有限,纯属浪费算力。

5.3 SOC边界与时长上限的处理

SOC采样看起来简单,实际最容易出bug。正态分布的两端会采出负值或大于1的值,必须做截断。更隐蔽的一个问题是:起始SOC不能大于目标SOC,否则“需要充电量”会变成负数,负荷曲线上就出现“负功率”,这在物理上毫无意义。

我建议截断区间设为0.05到目标SOC减0.05。为什么不直接设到目标SOC?因为如果起始SOC恰好等于目标SOC,充电量是0,时长也是0,这辆车相当于白抽了。预留0.05的余量,能保证每次充电都有一个正的最小时长。充电时长的上限,前面提到快充1.5小时、慢充8小时,也要在代码里显式处理。如果不设上限,极端情况下快充会一直充十几小时,不仅失真,还会把夜间平台抬成一个假高峰。

5.4 参数合法性校验与推荐取值范围

比例参数不是随便填都能得到合理结果。ratio_1加ratio_2加ratio_3如果等于0,np.random.choice会直接报错;快充占比填负数也会让随机数判断失去意义。建议在参数区加一段简单的合法性检查,提前拦截这类低级错误。

推荐取值范围可以参考这样一个区间:一充比例0.4到0.8,二充0.15到0.4,三充0.05到0.3。快充占比方面,一充用户0.05到0.2,二充用户0.2到0.5,三充用户0.4到0.9。SOC均值一充0.2到0.4,二充0.4到0.6,三充0.5到0.7。这些是基于多个项目经验汇总出来的常见区间,不代表绝对的物理边界。如果你做的是某个具体城市或园区,最好用当地充电订单数据反推这些参数,比拍区间更靠谱。

排查对象常见症状处理思路
随机种子未固定两次运行结果不一致在模拟前设置np.random.seed
迭代次数M太小峰值波动超5%增大M到200以上,用峰值变化<1%判断收敛
SOC未截断出现负功率或零时长截断到0.05到目标SOC减0.05
跨天充电溢出深夜负荷丢失或跳变用取模方式循环填充时间槽
比例参数非法程序崩溃或概率失真增加归一化和合法性校验
时长无上限出现超长充电形成假高峰按快慢充分别设置时长上限

我在实际使用这套模型时最大的体会是,它真正的价值不在“算出一个精确的日充电功率数字”——那本来就是个随机问题,任何精确数字都是伪精确——而在于它让你有能力快速回答“如果……会怎样”。方案阶段要对比三种充电桩配置方案,改几个比例参数,跑一遍,曲线和指标摆在桌上,比任何口头论证都有说服力。

最后再分享一个小技巧。我在交付项目时,会把参数区抽到单独的配置文件中,让非程序出身的同事也能直接改一充、二充、三充比例和快充占比,不用碰任何逻辑代码。模型本身反而不需要再改,框架稳定下来之后,剩下的工作几乎都是在调参数、对比曲线、写结论。这套代码后续想扩展也很方便,比如加入温度对充电功率的影响、接入有序充电策略、把车辆按功能类型再细分一层,都是在现有主循环上做加法,不需要推翻重来。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询