做电动汽车充电负荷计算相关课题的同行,应该都有过这种体会:电网侧要评估大规模电动车接入后的影响,但手头既没有真实充电桩数据,又不想用那种“拍脑袋定一个同时率”的粗糙做法,那么蒙特卡洛抽样基本是绕不开的第一选择。最近我把基于蒙特卡洛抽样的电动汽车充电负荷计算完整代码在MATLAB里跑通了,也调出了比较理想的效果曲线,这篇就把整个实现过程、模型假设、代码思路以及调试中踩过的坑全部摊开讲。内容面对的是正在做充电负荷预测、配电网规划或者电动汽车入网影响分析的工程师和研究生,哪怕你之前没接触过蒙特卡洛,按着这套思路和代码框架也能搭出一版可用模型。
先说结论:这套方案适合做“规模化电动汽车集群负荷评估”,能模拟任一时刻全网/台区范围内的充电功率需求曲线,输出结果包含逐时负荷均值、波动范围以及不同渗透率下的对比,完全可以直接嵌入到后续的配网潮流计算或容量规划里。
1. 项目背景与整体思路
1.1 为什么偏偏选蒙特卡洛抽样
电动汽车充电负荷和常规空调、照明负荷的最大区别,就是它的“用户行为主导”属性。一辆车几点开始充电、前一天跑了多少公里、回家后还剩多少电,这些参数几乎没法用确定性公式描述,只能靠概率分布去刻画。蒙特卡洛抽样就是干这件事的:从已知的概率分布里反复抽取随机场景,每个场景生成一组充电行为,叠加出总负荷,最后用大量场景的统计结果逼近真实期望。
这比传统的“负荷同时率”法高明在两个方面。第一,它能还原负荷曲线的自然形态,尤其是傍晚下班后的充电高峰叠加效应,这是同时率法给不出来的;第二,它能输出负荷的波动范围,也就是置信区间,这对评估配电网设备过载风险特别重要。实际计算中,单次抽样可能有很大的偶然性,但上千次抽样后的均值会收敛到稳定的期望曲线,这就是蒙特卡洛大数定律的直观体现。
1.2 蒙特卡洛方法的底层逻辑
蒙特卡洛的思想可以类比成“用海量实验逼近真相”。好比你想知道一万个人随机到达车站后等车人数的分布,最简单可靠的办法不是列方程,而是真的模拟一万个人的到达行为,统计每个时刻的人数。充电负荷计算同理:每辆车就是一个随机样本,样本里有起始充电时间、日行驶里程、电池容量、充电功率这些属性,抽样一次就是生成一辆车的充电曲线,把所有车的曲线叠加就是某一天的负荷曲线。
关键点在于,单次抽样只是众多个体行为的一种组合,并不代表典型情况。所以要重复抽取N次(比如500到2000次),每次代表一天,把每天的负荷曲线做平均,得到的就是期望负荷曲线;同时统计每一天对应的曲线波动范围,就可以画出置信带。整个流程核心只有三步:构建输入变量的概率模型、逐车抽样形成单日负荷、多次重复后做统计分析。MATLAB在这套流程里最大的优势是随机数生成函数丰富、矩阵运算快、画图方便,调试和结果可视化都不需要额外工具。
1.3 系统总体框架
我搭的整体计算框架分四层:参数层、场景层、计算层、统计层。参数层定义电动汽车保有量、充电桩功率、电池容量、各类概率分布参数;场景层负责对每辆车抽样,生成起始充电时间和初始SOC;计算层按照时间序列累加每一时刻的充电功率;统计层多次循环后计算均值、标准差、分位数并出图。
这四层各司其职,也方便以后扩展。比如想把慢充换成快充桩,只需要修改参数层的充电功率分布;想加入有序充电策略,只需要在计算层增加一个控制逻辑模块,不影响其他部分。项目实际代码也是按这个结构组织的,函数边界清晰,后续维护和改参数都很顺手。
2. 充电负荷计算的关键模型搭建
2.1 影响充电负荷的三大随机因素
做过几轮仿真之后,我总结出对负荷曲线影响最大的三个随机输入:起始充电时间、日行驶里程、充电功率。起始充电时间决定负荷曲线的相位,什么时候出现高峰完全由它决定;日行驶里程决定充电需求电量,也就是每辆车充多久;充电功率决定单车的充电速率,这个参数还直接影响配电网的瞬时冲击。
除此之外还有两个次要因素:电池容量和充电效率。电池容量理论上也可以是随机变量,因为不同车型差异很大,但为了控制复杂度,不少模型里把它设成几种典型值的离散分布;充电效率更多是作为修正系数出现在功率转换环节,不是核心随机源。实际建模时应该把主要精力放在前三个变量上,因为它们对结果的影响是决定性的。
2.2 概率分布选择与参数确定
起始充电时间的分布,不同研究用的模型不太一样。主流文献里常用正态分布,均值在18点到19点之间,标准差1到3小时,这对应的是“下班回家后顺手插枪充电”的主流行为模式。有些精细化研究会把工作日和周末分开建模,或者考虑快充站的随机到达过程,但经典版本用截断正态分布就够用。
日行驶里程更贴近对数正态分布,因为大部分车每天跑几十公里,少数车跑上百公里,右拖尾特征非常明显。MATLAB里直接用lognrnd函数就可以抽取。下面是我常用的参数表:
| 随机变量 | 分布类型 | 参数设置 | 备注 |
|---|---|---|---|
| 起始充电时间 | 截断正态分布 | 均值18.5h,标准差2h,截断到16h~24h | 对应晚归高峰 |
| 日行驶里程 | 对数正态分布 | 均值40km,标准差对应ln分布参数 | 城市通勤为主 |
| 电池容量 | 离散正态分布 | 40/60/80kWh,占比约3:5:2 | 模拟不同车型 |
| 充电功率 | 离散分布 | 7kW慢充为主,少量50kW快充 | 慢充为主场景 |
有人会纠结参数的精确度,我的建议是初期不用追求完美,关键是要让模型行为符合直觉。比如均值参数改了之后,高峰时段确实发生了对应的移动,这就说明模型是敏感的、合理的。后续如果拿到真实充电桩数据,直接替换分布参数做标定即可。
2.3 充电行为约束与边界条件
模型不能只抽样不管过程,还得加上几条物理约束,否则会出现“充满了还继续充”这种不合理的曲线。第一是SOC上下限约束,车载电池一般不允许低于10%,充电目标通常设到90%左右,所以实际可充容量按电池容量的80%计算。第二是充电结束条件,充电时长等于需求电量除以充电功率,达到目标SOC就停止充电,不允许超出。
第三是起始SOC与日行驶里程的耦合约束。起始SOC不应该独立抽样,而是由前一天行驶里程推导:起始SOC等于前一天结束时的SOC减去当天行驶消耗。这个耦合关系我一开始漏掉了,导致大量车出现“电量接近满的还在充电”的假象,曲线失真很严重。
处理完这些约束之后,充电功率曲线在时间轴上的分布就自然呈现出一个特点:大量车集中在晚间开始充电,充电过程持续2到8小时不等,负荷曲线从前一晚的18点开始爬升,到20点到22点之间达到峰值,后半夜逐渐回落。
3. MATLAB实现流程与核心代码拆解
3.1 整体算法框架
MATLAB程序的执行流程我用一个主脚本加若干个函数来组织。主脚本负责设置参数、循环调用单日场景函数、汇总统计结果;函数层面包括场景生成函数、单个车辆充电曲线函数和日负荷叠加函数。这么设计的好处是,后期如果要把慢充换成有序充电,只需要替换或修改场景生成函数,主脚本基本不用动。
主循环结构用for k = 1:N,每轮循环做三件事:抽样生成一批车的参数、累加每辆车的充电功率时间序列、保存这一天的总负荷曲线。N的值我试过500、1000、2000三档,最后选的是1000次。原因后面会在收敛性部分细说。
3.2 随机场景生成代码
场景生成是核心中的核心。起始充电时间我直接用了normrnd生成再截断,日行驶里程用lognrnd,电池容量用randsample按权重抽取,充电功率也按离散概率抽取。截断的逻辑不复杂,生成后把超出范围的样本裁剪到上下限即可,代价是个别样本会堆积在边界,但只要截断点离分布中心足够远,对结果影响可以接受。
% 起始充电时间:截断正态分布(小时) t_start = normrnd(mu_t, sigma_t, N_car, 1); t_start = min(max(t_start, 16), 24); % 日行驶里程:对数正态分布(km) mileage = lognrnd(log(40), 0.5, N_car, 1); % 抽取电池容量和起始SOC capacity = randsample([40;60;80], N_car, true, [0.3;0.5;0.2]); energy_consumed = mileage .* 0.18; % kWh/km soc_start = 0.9 - energy_consumed ./ capacity; soc_start = max(soc_start, 0.1);这段代码里最值得注意的就是randsample按权重抽样电池容量数组,以及SOC起始值由行驶能耗反推,这两行实际上决定了充电需求量的真实度。0.18 kWh/km这个百公里电耗20度左右的能耗系数是可调的,如果模拟的车型偏微型车,可以下调到0.12到0.15。
3.3 负荷累加与迭代收敛逻辑
有了每辆车的起始充电时间、SOC和充电功率,就能叠加载荷了。先把时间轴切成1440分钟或96个15分钟点,然后把每辆车的充电区间映射到对应的时间索引上,把功率加进去。向量化可以这么写:先确定每辆车充多少小时,再根据起始时间计算跨越的索引范围,逐车累加。
t_end = t_start + charge_duration; % 充电结束时间(小时) for i = 1:N_car idx_start = round((t_start(i) - t0) / dt) + 1; idx_end = round((t_end(i) - t0) / dt) + 1; idx_end = min(idx_end, T); P_day(idx_start:idx_end) = P_day(idx_start:idx_end) + P_charge(i); end逐车循环在小规模下很快,但如果车数量超过几万台,可以用histcounts配合权重一次性累加,性能提升明显。收敛性方面,我统计了不同迭代次数下的均值曲线标准差,500次时波动还有约3%,1000次以后波动降到1%以内,所以取1000次作为默认配置,既保证精度又不至于跑太久。
4. 仿真结果与分析
4.1 充电负荷曲线的典型形态
用默认参数跑完1000次仿真后,输出的典型日负荷曲线是很有辨识度的:下午16点前几乎可以忽略不计,17点后开始爬坡,19点到21点之间出现明显峰值,峰值后缓慢下降,凌晨1点后逐步回落到低位。这个形态符合大多数文献和实测数据的规律,本质上就是用户下班回家充电行为的集中反映。
我测试的算例是5000辆电动汽车、慢充7kW为主、电池容量以60kWh为主。这个配置下晚高峰总负荷峰值大约在22MW左右。如果单纯按5000辆车乘以7kW得到35MW,会觉得电网早上天天过载,但实际因为起始充电时间的分散性和SOC差异,叠加后峰值远低于装机总和。这正是蒙特卡洛模型的价值——它还原了“同时率”的真实构成逻辑,而不是拍一个固定系数。
4.2 渗透率与充电功率对曲线的影响
参数敏感性测试我做了两组。第一组固定其他参数,只改变电动汽车数量,从1000辆逐步加到10000辆,负荷峰值基本线性增长,但曲线的形状不变,峰值依然出现在晚间20到21点,这说明起始充电时间的分布对峰谷形态起决定性作用,渗透率只改变纵轴尺度。
第二组只改变充电功率构成,把一部分7kW慢充替换成50kW快充,峰值明显前移且冲击变大,原因很简单:快充功率高,同样电量能在更短时间内完成,大量车会在更集中的时间窗口内形成更陡峭的功率峰。这对配电网的影响尤其大,变压器短时过载的风险比慢充场景高很多。
4.3 结果可信度评估
仿真结果不能只信一次曲线,我习惯把1000次迭代中每一天的负荷曲线的均值和±1倍标准差一起画出来。均值曲线周围会形成一个“走廊”,走廊宽度代表了不确定性。这批算例中,晚高峰时刻的标准差大约在峰值的8%到12%之间,说明这个时段的负荷随机波动比较明显,而深夜时段的走廊则窄得多,因为大部分车已经充满停止充电,随机性主要集中在前半夜。
这种不确定性信息对实际应用特别有价值。规划人员在评估变压器容量时,不仅要看均值是否越限,还要看最坏情况下(比如95%分位数)是否越限。我建议在最终输出中加上P95曲线,作为保守决策的参考,这个操作在MATLAB里用prctile(P_all, 95, 1)一行就能搞定。
5. 常见问题与调试心得
5.1 随机数种子与结果复现
蒙特卡洛仿真第一件要养成习惯的事,就是固定随机数种子。如果不加处理,每次运行结果都会有细微差别,写论文时数据对不上,改参数前后也难以比较。早期我吃过这个亏,改了个功率参数,实验结果变化太大,以为是逻辑错误,后来发现只是随机波动。解决办法很简单,脚本开头加一句:
rng(2024); % 固定随机数种子这样保证同参数下结果完全可复现,改一个参数再跑也只看得到真正由参数引起的变化。实际研究中我会在种子位置留一个变量,批量参数扫描时按组序号动态改种子,保证每组实验独立可复现。
5.2 仿真速度优化
1000次迭代、每轮5000辆车,代码最初跑一轮要将近三分钟,瓶颈在逐车时间序列累加的那层循环上。优化手段有两种:一是把dt从1分钟改成15分钟,时间点从1440降到96个,计算量直接降一个量级;二是对充电起始时间做归并,同一时刻开始的车辆可以合并成一组功率叠加,避免逐车循环。
优化后同样计算规模只需要10到20秒,速度提升非常明显。如果车规模再大,还有一个思路是预先生成场景矩阵,再用单次矩阵运算完成累加,MATLAB对矩阵运算的优化远好于循环,但内存占用会上升,需要权衡。
5.3 参数敏感性踩坑记录
调参过程中的一个大坑,是起始SOC取值过于理想。早期版本里我把起始SOC设为固定0.9,结果单日电量需求全部来自于行驶里程,虽然曲线形态合理,但把电池容量曲线上整体抬高了,高峰更加明显。实际中很多人开完车并不会立刻充满,第二天接着开,所以SOC起始值的随机性必须通过行驶里程耦合进来。
另一个坑是截断正态分布带来的边界堆积。把起始充电时间截断在16到24点后,16点和24点附近的样本明显增多,这是我后来观察直方图发现的。解决办法是把正态分布均值设置在18.5,标准差控制在2小时以内,这样截断区离均值较远,堆积问题基本可以接受。
| 常见问题 | 可能原因 | 解决建议 |
|---|---|---|
| 结果每次运行都不一样 | 未固定随机数种子 | 用rng(seed)固定种子 |
| 曲线出现双峰 | 快充和慢充混用时起始时间分布不匹配 | 分开建模,分别抽样后叠加 |
| 峰值过高失真 | 忽略SOC上限约束或起始SOC恒定 | 用行驶里程反推起始SOC |
| 深夜仍有充电负荷 | 充电时长未截断,超量充电 | 加充电结束时间约束 |
| 运行太慢 | 时间粒度太细且循环累加 | 改用15分钟粒度并向量化 |
做这套代码最大的体会是,蒙特卡洛抽样本身并不难,难得是把行为模型建得“像那么回事”。概率分布参数选择是否合理、行驶里程与SOC是否耦合、充电结束条件是否严密,任何一个环节粗糙了,最终的负荷曲线都会在不经意的地方露出马脚。建议你拿到代码后先跑一遍默认参数,再把起始充电时间均值改成22点试一次,你会立刻看到峰值后移,那种“模型对参数有正确响应”的感觉,是验证代码逻辑最有效的手段。后面如果想继续扩展,可以考虑加入温度对能耗的影响、节假日与工作日的行为差异,甚至把蒙特卡洛生成的负荷序列直接喂给潮流计算模块,做配电网的时序概率评估,这套框架都留好了扩展口子。