ARTICLE DETAIL

资讯详情

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

基于Matlab蒙特卡洛模拟的电动汽车充电负荷曲线仿真方法

基于Matlab蒙特卡洛模拟的电动汽车充电负荷曲线仿真方法 电动汽车负荷曲线这件事做配电网规划、充电站选址、有序充电控制的人几乎天天都要跟它打交道。我最早接触这个项目的时候目标很直接用Matlab跑蒙特卡洛模拟把电动汽车分成“一充、二充、三充”三种充电行为然后仿真出一天24小时的负荷曲线看看不同充电习惯对配电网的影响到底有多大。做完之后发现这套思路不仅适合写论文对实际工程估算也特别有用因为电网侧做容量评估、变压器选型的时候缺的就是这种“有依据的负荷曲线”而不是拍脑袋给个同时率。这篇文章把整个项目从建模思路、概率参数设定、Matlab代码实现到结果分析的完整过程都记录下来。适合正在做电动汽车充电负荷仿真、微电网规划、或者想用蒙特卡洛方法做随机过程建模的读者参考。尤其是那些卡在“二充、三充怎么定义”“充电时间分布怎么取”“结果曲线毛刺太多怎么平滑”这些问题上的朋友我的实测经验可以直接照搬。1. 整体设计与思路拆解1.1 为什么蒙特卡洛适合干这件事电动汽车充电负荷的本质是一个随机过程每辆车什么时候充、充多久、用多大功率、电池剩余电量多少都不是固定值。如果你用“所有车辆统一晚7点开始充、统一充4小时”这种确定性的方法去估算结果会和实际偏差很大因为真实世界里的充电行为分散在一天中的各个时段。蒙特卡洛模拟的思路恰恰就是应对这种随机性的先给每个随机变量设定一个合理的概率分布然后通过大量抽样模拟出尽可能接近现实的事件组合最后把结果统计出来。它不追求“精确预测某一辆车的充电行为”而是通过成百上千辆车的随机组合把充电负荷的统计规律还原出来。用生活化的比喻来说这就相当于你调查1000个人的午饭时间。如果只问一个人然后推断所有人误差会大得离谱但如果把1000个人的吃饭时间都统计出来你就能得到“12点前后是高峰、11点和13点相对较少”这样可靠的结论。蒙特卡洛做的事情就是把这个“抽样统计”过程自动化、规模化。1.2 一充、二充、三充分类的业务逻辑把电动汽车按“一天充电次数”分成三类背后是真实的用户行为画像一充每日单次充电最常见。典型场景是通勤族白天开车上班晚上回家插上充电枪充一夜第二天满电出发。这类用户占大多数充电时间高度集中在傍晚到夜间正好叠加在居民用电晚高峰上。二充每日两次充电常见于单位停车场有充电桩、或者中午有固定补电习惯的用户。早上到公司插上充一两个小时晚上回家再充满。这类用户的负荷会出现“小高峰大晚高峰”的双峰特征对写字楼配电系统影响比较大。三充每日三次及以上充电对应充电频繁的营运车辆网约车、出租车、物流车或通勤距离特别长的用户。这类用户充电时段比较分散单次充电量不大但对充电桩的占用时间长负荷分布也更加随机。这种分类最大的好处是它能让你从“一辆车的充电行为”升级到“一群车的聚合负荷”。做电网侧分析的时候你不需要关心具体某一辆车只需知道这个区域内“一充、二充、三充用户各占多少”就能推算出整体负荷曲线的大致形状。这种分类逻辑还有一个工程上的实用价值不同类别对电能质量的影响不一样。一充用户集中充电会拉高晚高峰峰值二充用户在白天产生额外负荷可能和光伏出力叠加或错开三充用户则因为分散度高反而可能“填谷”。搞清楚三类占比配电网规划时就知道该在哪个时段预留多少容量。1.3 为什么选Matlab而不是PythonMatlab在这个场景里确实比Python顺手尤其是在做概率分布拟合、随机数生成和绘图这三件事上。fitdist、makedist、random这一套概率工具箱几乎为蒙特卡洛量身定做。histogram出频次分布图plot画负荷曲线代码量远小于Python的matplotlib方案。更关键的是Simulink里做微网仿真时很多时候需要把Matlab脚本生成的负荷曲线作为输入数据文件直接喂进去。这个流程在Matlab生态里是无缝衔接的省去跨工具传递数据的麻烦。所以我最终选择了纯Matlab脚本实现整套蒙特卡洛仿真。不过说实话如果你对Python更熟用numpy.random也能实现同样的效果。工具只是手段核心还是搞清楚怎么给每辆车“抽签”。下面这几节内容无论是用Matlab还是Python思路都是通用的。2. 三类充电行为的数学建模与参数设计2.1 核心随机变量起始充电时间、日行驶里程、充电功率仿真前我们得先明确要随机抽样哪些变量。我把影响充电负荷的核心变量归纳为三个第一是起始充电时间。它直接决定负荷落在哪个时段。晚7点开始充和晚10点开始充对晚高峰的叠加效果完全不同。实操中一充用户用正态分布拟合很贴切均值约在19:00到19:30标准差1到2小时二充用户早上的起始时间集中在8:00到9:30晚上的起始时间在19:00到20:30三充用户起始时间则用均匀分布或分段分布更合理因为他们的充电行为太散。第二是日行驶里程。它决定了每次充电需要补充多少电量。工程上通常用对数正态分布来拟合。日均行驶里程一般在30到50公里之间但方差很大——有每天只开10公里的也有开上百公里的。里程越长充电时长越长负荷持续时间越久。第三是充电功率。慢充桩常见7kW快充桩功率可达60kW甚至更高。仿真时不能所有车都用7kW否则结果会太理想化。我建议按用户类型混合设置一充和二充用户以7kW为主三充用户中可以混入一定比例的快充。2.2 充电时长的推导逻辑充电时长不是直接抽一个随机数而是通过“需求电量÷充电功率”推导出来的这样更符合物理规律先由日行驶里程和百公里电耗算出日耗电量D × e其中e一般取15到20kWh/100km。再用日耗电量 ÷ 充电功率得到理论充电时长。但时长不能超过电池容量和可用SOC上下限的限制否则要截断处理。这里有一个容易犯的错误直接用“路程除以功率”或者“时间直接抽个随机数”都会导致充电量不合理。比如一辆车只开了10公里却充了4小时在现实中几乎不会发生。所以我在代码里始终坚持“由里程计算需求电量再由需求电量反推充电时长”的逻辑这也是结果曲线更贴近实测的关键。2.3 三类EV参数的对照表为了让大家快速落地我把三类的典型参数汇总成一张表。这里的数值来自我实测迭代后的经验值和多项公开文献数据基本吻合你可以直接抄作业再根据自己所在城市的情况微调类别起始充电时间分布日行驶里程分布充电功率占比参考一充正态分布均值19:00标准差1.5h对数正态均值约35km波动较大7kW慢充为主50%70%二充早峰8:30±0.8h晚峰19:30±1.2h对数正态均值约60km7kW慢充少量11kW20%35%三充均匀分布或三段式分布覆盖全天对数正态均值约100km7kW慢充60kW快充混合10%20%关于占比别小看这个参数它对结果影响非常大。如果是居民区为主的小区一充比例可能达到70%以上如果是商业区或机场附近三充比例会明显上升。我建议仿真的第一件事就是把“场景”和“占比”绑定起来思考而不是盲目套一个默认值。2.4 时间粒度的选择15分钟还是1小时负荷曲线的时间粒度直接影响曲线平滑度和计算量。用1小时粒度算得快但会掩盖充电负荷的突变特征晚高峰的“尖峰”形状会被拉平用1分钟粒度细节足够但数据量和计算时间会大幅增加。我的经验是15分钟粒度是性价比最高的选择。一天24小时分为96个时点数据量适中曲线形状又保留了足够的时序细节。实测下来15分钟粒度下晚高峰的起峰时刻、峰值大小和回落趋势都能清晰识别这比1小时粒度精细得多。这个精度对于分析“晚高峰叠加效应”足够了。3. Matlab仿真实现流程与核心代码3.1 整体仿真框架整个仿真的流程拆解下来可以概括为五步初始化参数设置车辆数、模拟次数、三类占比、电池参数。对每辆车按概率抽取充电类型。根据类型对应的概率分布抽样起始充电时间和日行驶里程。计算充电时长把功率叠加到当天96个时点对应的负荷曲线上。重复模拟多次取平均得到最终的期望负荷曲线。这里有一个值得强调的细节最终负荷曲线应该用多次模拟的平均值而不是单次模拟的结果。因为单次模拟的随机性太大画出来的曲线毛刺很多波动明显多次模拟取平均之后曲线才会收敛到一个稳定形状。这是蒙特卡洛方法的收敛思想在工程上的直接体现。3.2 参数初始化与三类占比设置%% 参数初始化 clear; clc; close all; rng(2024); % 固定随机种子保证结果可复现 N 1000; % 电动汽车数量 M 100; % 蒙特卡洛模拟次数 T 96; % 一天24小时按15分钟粒度分为96个时点 dt 0.25; % 每个时点对应0.25小时 % 三类充电用户占比一充/二充/三充 ratio [0.6, 0.3, 0.1]; % 电池参数 capacity 60; % 电池容量kWh soc_min 0.1; % 最小允许SOC soc_max 0.9; % 最大允许SOC不追求充满到100% e_consum 0.18; % 百公里耗电kWh/km % 充电功率设定kW P_slow 7; % 慢充 P_fast 60; % 快充固定随机种子这一步很多新手会忽略。如果不写rng(2024)每次运行代码生成的随机数都不同结果曲线会“每次跑都不太一样”。论文复现、方案对比的时候这个差异会让你非常被动。固定种子之后至少同一台机器上结果可完全复现调试和对比参数时也更方便。3.3 对每辆车抽样充电类型与充电参数%% 单日负荷累加容器 P_day zeros(M, T); % 存放每次模拟的96点负荷曲线 for m 1:M P_curve zeros(1, T); % 当前模拟的负荷曲线 for i 1:N % (1) 抽取充电类型 type randsample([1, 2, 3], 1, true, ratio); % (2) 抽取起始充电时间转换为时段索引1~96 if type 1 % 一充晚高峰充电均值19:00标准差1.5小时 start_hour 19 1.5 * randn(); elseif type 2 % 二充早晚各一次本次只模拟晚间的充电段早上另算 start_hour 19.5 1.2 * randn(); else % 三充充电时间较分散用均匀分布覆盖8:00~22:00 start_hour 8 14 * rand(); end % (3) 抽取日行驶里程单位km用对数正态分布 mileage lognrnd(log(35), 0.5); if type 3 mileage lognrnd(log(100), 0.5); % 三充用户里程更长 end % (4) 由行驶里程计算所需充电量 energy_need mileage * e_consum; % (5) 受SOC上下限约束的可用充电量 energy_max capacity * (soc_max - soc_min); energy_need min(energy_need, energy_max); if energy_need 1 energy_need 0; % 电量需求太小认为今天不需要充 end % (6) 根据功率计算充电时长小时 if type 3 rand() 0.3 P_charge P_fast; % 三充用户30%概率用快充 else P_charge P_slow; end charge_hours energy_need / P_charge; charge_slots floor(charge_hours / dt); % 转为时段数 % (7) 将功率叠加到负荷曲线上 start_idx floor(start_hour / dt) 1; for k 1:charge_slots idx start_idx k - 1; if idx T P_curve(idx) P_curve(idx) P_charge; else break; % 超出当天24:00的部分不再累计 end end end P_day(m, :) P_curve; end这段代码是整篇的核心其中三充用户用了均匀分布模拟“分散充电”其逻辑是这类用户的开机充电时间最没有规律。如果你实际数据显示三充用户集中在中午和傍晚各来一次这里可以改成双峰分布不一定非要均匀分布。3.4 修正二充用户的早高峰上面的代码有个偷懒之处二充用户我只模拟了晚间充电。实际上二充用户的特征是早晚各充一次只算晚充会漏掉白天的负荷峰值。完整的做法是早上也叠加一段充电功率%% 二充用户额外叠加早高峰充电段 if type 2 % 早上8:30左右到达单位开始充电充电约2小时 start_morning 8.5 0.8 * randn(); morning_slots floor(2 / dt); % 充电2小时 start_idx_m floor(start_morning / dt) 1; for k 1:morning_slots idx start_idx_m k - 1; if idx T P_curve(idx) P_curve(idx) P_slow; end end end这段代码要放在上面的if type 3语句之后、内层车辆循环结束之前。加入早高峰叠加后二充用户的负荷曲线就会出现“上午小峰晚间大峰”的双峰形态这比只算晚充更真实。我一开始做这个项目时偷懒没加早充电段仿真出来的二充曲线和实际监测数据有明显偏差一度以为是分布参数写错了。后来对比数据才发现是漏了早充电段。你如果拿仿真结果去和实测数据做校验一定要记得补上这一块。3.5 结果统计与曲线绘制%% 统计结果多次模拟取平均 P_final mean(P_day, 1); % 期望负荷曲线 % 转成小时数据 t_axis (0.5:T) * dt; % 每个时点对应的小时数 %% 绘制负荷曲线 figure(Color, w); plot(t_axis, P_final, LineWidth, 2); xlabel(时间 (小时)); ylabel(总充电功率 (kW)); title(电动汽车充电负荷曲线蒙特卡洛模拟); grid on; xlim([0 24]); % 顺便看一下三类车辆的占比和平均值信息 fprintf(仿真车辆总数%d\n, N); fprintf(24小时总充电量%.1f kWh\n, sum(P_final) * dt); fprintf(峰值功率%.2f kW出现在第 %.1f 小时\n, max(P_final), t_axis(P_final max(P_final)));多说一句P_final在纵轴上代表的是所有车的总功率叠加值。如果想看单车的平均负荷用P_final / N就行。论文里通常展示总负荷曲线工程上我们更关心总功率对变压器容量的影响所以这个尺度一般不改。3.6 代码执行性能优化当车辆数N很大比如5000辆以上、模拟次数M也很大比如500次以上时双循环加内层叠加会有点慢。我实测下来1000辆车、100次模拟在普通笔记本上大约需要10到20秒还可以接受。但如果做参数扫描比如对比10组不同的占比总时间就会逼近几分钟。有一个简单的提速方法把最内层的“时点叠加”改为向量化的分段累加。在96个时点的范围里也可以用P_curve(start_idx:end_idx) P_curve(start_idx:end_idx) P_charge来替代循环。不过96次循环本身的代价很低性能瓶颈主要在车辆循环所以实战中我一般直接跑循环代码可读性更重要。另外模拟次数M不是越大越好。M增大到100以上之后mean(P_day, 1)的结果变化非常小计算时间却线性增加。我建议先用M50跑一遍看曲线形状确认逻辑没问题之后再加大到100或200。4. 仿真结果分析与参数敏感性讨论4.1 典型负荷曲线解读我按ratio [0.6, 0.3, 0.1]跑出来的典型曲线形状大致是这样早上8到11点出现一个平缓的小高峰这是二充用户的早充电段和三充用户的分散充电共同贡献的晚上19点到21点出现明显的主峰这是一充和二充用户的晚间充电叠加效应凌晨1点以后负荷逐渐回落但依然有一小部分充电行为持续到深夜。最值得关注的指标是峰值功率和峰值出现时间。晚高峰充电负荷叠加在居民用电晚高峰上是配电变压器夏季最担心的问题。通过仿真你可以定量知道“该区域晚19点30分的充电负荷峰值大约是多少”从而判断变压器的剩余容量是否够用。如果某天看到曲线在晚上19点出现“尖刺”不用慌这恰恰说明一充用户的充电时间高度集中。这时候研究有序充电策略——比如把部分一充用户从19点引导到22点再充电——就能有效削峰。蒙特卡洛仿真可以做“基线场景”有序充电策略可以在它的基础上叠加。4.2 不同参数下的曲线形态变化参数敏感性分析是这个项目最有意思的部分。我建议你重点扫这几个参数车辆数量N。负荷曲线形状不变幅值近似线性增长。100辆车峰值约120kW200辆车峰值约240kW——但实际会因为随机性略有偏差。这个线性关系可以用作快速估算。三类占比ratio。这是影响曲线形态最明显的因素。一充占比高晚高峰越尖锐二充占比高白天会出现更明显的“商业区午间峰”三充占比高曲线变得更加平缓峰值下降。我试着把三充占比从10%提到30%晚高峰峰值下降了约15%但白天的平均负荷明显上移。这对“充电桩应该布局在住宅区还是办公区”的决策很有参考价值。充电功率P_charge。如果全部用快充60kW车辆充电时长大幅缩短部分负荷从夜间转移到傍晚甚至下午峰值可能更高且更陡。但如果适度混入快充总负荷曲线反而更平滑。这颠覆了不少人的直觉——快充不一定推高峰值关键看充电时间是否错峰。4.3 结果的工程校验方法仿真的结果需要和现实对一下账否则就是自嗨。我最常用的校验方法是把24小时总充电量除以车辆数看单车日均充电量是否合理。比如上面那段代码跑出来的结果单辆车日均充电量大概在13到18kWh之间这和一辆日均行驶50公里、百公里耗电18kWh的通勤电车基本吻合。如果计算结果单车日均充电量到了30kWh甚至更高那一定是里程抽样或者SOC限制参数出了问题。另一个校验方式是看峰值负荷率和同时率。充电负荷的峰值同时率一般在0.25到0.6之间。如果算出同时率超过0.8那说明你的充电时间分布太集中大概率是标准差设小了或者随机种子不够多样。5. 常见问题与排查技巧实录5.1 代码层面容易踩的坑问题1随机数和初始化顺序错乱这是新手最容易犯的错误写代码时把概率抽样的顺序搞错比如先抽取了start_hour再根据type判断用哪个分布。虽然代码能跑但结果毫无意义。我的建议是严格按“先类型、后参数”的顺序先抽取充电类型再根据类型抽取对应的起始时间和里程。问题2时间段索引越界报错当start_hour抽到22点以后加上充电时长会超出96个时点的范围。如果没有if idx T的判断Matlab会直接报错或自动扩展数组导致后续结果错乱。代码里一定要加边界条件判断超出24:00的部分直接忽略。问题3正态分布抽到负数时间19 1.5 * randn()理论上可能抽到16点多也可能抽到22点多不会抽到负数。但如果均值设成凌晨2点、标准差设成3小时就可能抽到负值结果出现“负时间”的充电起始点。出现这种异常先检查起始时间的均值是否太小。5.2 仿真结果的“毛刺”问题如果你第一次跑出来的负荷曲线像锯齿一样毛刺丛生不要怀疑代码写错了这是单次模拟的随机波动。解决办法有两个一个是增大车辆数N车辆越多随机波动相对越小另一个是增大模拟次数M取平均曲线会越来越光滑。我试过N从100加到1000后曲线峰值波动从±8%降到±2%左右再结合M100次平均最后的曲线已经非常稳定。如果你画出来的曲线依然“毛毛糙糙”优先检查N不是M。5.3 随机种子导致的复现问题rng(2024)这个固定种子的作用被很多人低估了。没有它你每次运行得到的结果都不同做参数对比时会怀疑“是参数变化导致差异还是随机波动导致差异”。固定种子后重复运行代码能得到完全一致的结果这给调参和论文复现省了很多麻烦。如果你要对比不同占比策略对负荷曲线的影响请务必在每组参数前都用同一个rng()值否则对比结果的差异性可能来自随机数而不是参数本身。我踩过一次这个坑当时以为“两次仿真的差异是占比变化引起的”结果重新固定种子之后发现差异小了一半差点得出完全相反的结论。5.4 不同EV类型划分的交叉验证有时候你会发现仿真结果与某个地区实测数据不吻合最常见的原因是分类占比设错了。比如某市实际以出租车、网约车居多三充比例可能高达三成以上而不是默认的一成。解决方法是手上先找一份目标区域的充电行为统计数据哪怕是问卷调研或充电平台的一周日志先拟合出本地化的分布参数再跑仿真。没有实测数据的城市也建议先做敏感性分析看结果对参数变化是否稳健。最后再多说一句我个人的体会是这类蒙特卡洛仿真的价值不在“精确预测明天每个小时有几辆车在充电”而在于把不同充电行为对电网负荷的冲击量化出来。哪怕只是把三种充电类型的占比从“默认值”改成“某个小区的实测值”你就能得到一条和该小区高度相关的负荷曲线这对变压器容量评估、充电桩布局、有序充电策略设计都是非常实用的输入。最后再分享一个小技巧运行完仿真顺手把P_final保存成.mat或.csv文件后面接入Simulink微网仿真、或者和其他负荷数据做叠加分析时直接读文件就行不用每次重新跑一遍随机过程。如果你后续还想深入可以在这个模型基础上加入温度修正系数冬天电池效率下降、夏天空调耗电、分时电价引导机制以及充电桩数量限制条件模型的工程价值会再上一个台阶。
返回列表