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

基于蒙特卡洛的电动汽车行驶里程与充电功率仿真分析

基于蒙特卡洛的电动汽车行驶里程与充电功率仿真分析 ★ FEATURED ARTICLE
做这个电动汽车蒙特卡洛分析的起因是我之前在一个车辆调度项目里被一个简单问题难住假设某个车队有几十台电动车每台车早上出门的电量不一样每天跑的里程不一样路上耗电又受温度和驾驶风格影响那么这批车晚上回来之后到底有多少台需要充电需要的充电功率又落在什么区间如果只按一个“典型值”估算结果往往和实际差很远。后来我改用蒙特卡洛方法在Matlab里把每台车一天的状态当成一次随机试验跑上万次之后所有可能性的分布就浮现出来了。这篇文章把当时的建模思路、代码实现和踩过的坑完整记录下来适合正在做充电设施规划、车队调度或者单纯想用概率思维分析车辆能耗的朋友参考。1. 为什么“单点估算”撑不住电动汽车分析先聊一个很现实的问题一台标称续航500公里的车为什么有人能跑出480有人只能跑出320答案不是车坏了而是驾驶它的人、天气和路况完全不一样。同样道理一个额定功率120kW的充电桩插到不同车上实际充电速度可能差一倍。充电功率不仅取决于桩还取决于车内的电池管理系统、当前电量区间、电池温度甚至旁边几台车是不是在同时充电。很多工程分析习惯用一个确定性数字往外推——比如平均百公里电耗15度平均每天跑60公里平均充电功率60kW。这种做法的最大问题是不回答“概率”问题到底有多少比例的车耗电超过20度每百公里有多少台车在晚高峰同时充电如果不把这些随机性纳入计算对于充电桩数量配置、变压器容量规划这类场景要么投资过度要么高峰时段直接跳闸。蒙特卡洛解决的就是这类问题。它的思路并不复杂把每个不确定因素用一个概率分布来描述然后让计算机大批量地“抽签”——抽一次签就算一台车一天的情况抽一万次就算一万台车一天的情况最后把所有结果汇总成统计分布。这个方法不依赖复杂的数学推导只要能把“单车行为模型”写清楚剩下的就是计算量的问题。这个项目我是在Matlab里做的主要原因是它的随机数生成和统计绘图功能非常顺手。makedist、random、histogram、prctile这些函数基本覆盖了整个流程所需不用自己去写底层抽样逻辑。而且Matlab的矩阵运算可以一次性生成上万条随机参数列比用循环逐个生成快得多。2. 蒙特卡洛分析的核心逻辑拆解2.1 三步走抽样、仿真、统计蒙特卡洛在电动车场景下的执行流程其实只有三步。第一步是抽样也就是确定哪些因素是随机的、怎么分布第二步是仿真把抽出来的随机参数代入物理模型算出一台车的里程结果和充电结果第三步是统计把成千上万次计算的结果汇总成直方图、累计概率曲线或者统计表。举个例子假设每天行驶里程符合对数正态分布大部分车每天开三四十公里少数网约车能开到两百公里以上。那么抽样阶段就是基于这个分布生成一万个行驶里程值仿真阶段把每个里程值换算成消耗的电量再结合初始电量算出最终剩余电量统计阶段就能得到“一万台车里有百分之多少会在收车时电量低于20%”这样的结论。这里不需要追求对单车预测得特别准蒙特卡洛的价值是让随机性明确地体现出来。换句话说我们不是在寻找一个答案而是在描绘一条完整的概率曲线。2.2 关键随机变量的分布设定随机变量的分布选择是整个分析的重中之重。变量设错了后面再多的仿真次数也只是把错误的概率重复一万遍。我整理了一张常用的变量表基本覆盖了电动车里程和充电分析的大多数场景。随机变量分布类型典型参数对应现实含义初始电量SOCBeta分布形状参数6和2映射到0.1~1.0多数车主习惯充满但偶尔有人只有一半电日行驶里程对数正态分布均值约50km长尾到200km以上有通勤短途也有长途和运营车辆环境温度正态分布截断20±8℃截断到-15~38℃季节和地域温度波动单位能耗正态分布叠加修正基准0.15kWh/km附加温度修正驾驶风格和空调负载充电桩额定功率离散分布7kW占20%60kW占50%120kW占30%不同停车场景的桩型占比Beta分布在初始电量上特别合适因为它可以限定在0到1之间的分布曲线而且能模拟出“大部分人电量较高、少数人电量低”的偏态形态。对数正态分布则适合行驶里程因为里程不可能为负而且长尾特征明显。2.3 仿真次数怎么定很多人问蒙特卡洛要跑多少次才够。理论上蒙特卡洛的误差收敛速度和仿真次数的平方根成反比——次数增加一百倍误差才缩小到原来的十分之一。但实际项目里不需要追求极致精度对于充电桩负载这类工程决策上万次仿真已经能让均值和分位数稳定下来。我在这个项目里默认设成20000次。跑一次完整仿真在普通笔记本上大概需要几秒到十几秒完全在可接受范围内。如果模型本身很复杂建议先用5000次快速验证流程确认输出正常后再放大到20000甚至50000次。3. 行驶里程模型从能耗到剩余电量的换算3.1 能量法的基本公式行驶里程分析的核心不是“能跑多远”而是“消耗了多少能量”。这里用最简单也最可靠的能量法soc_end soc_start - (E_consum .* dist_trip) / C_battery;其中E_consum是每公里能耗单位kWh/kmdist_trip是当日行驶里程C_battery是电池总容量。这个公式的逻辑很直观跑掉的电量等于每公里耗电量乘以里程再除以电池容量就得到了SOC的下降幅度。公式虽然简单但几个变量的随机化处理才是关键。我在代码里把能耗拆成了三部分叠加基础能耗、温度修正和驾驶风格扰动。3.2 温度对能耗的影响要单独建出来温度对电动车的能耗影响非常大。低温下电池内阻增加同时暖风系统要额外耗电高温下空调压缩机同样会吃掉不少电量。这个项目里我用了一个线性修正系数加上随机扰动E_base 0.15; % 常温基础能耗kWh/km temp_amb normrnd(20, 8, N, 1); temp_amb min(max(temp_amb, -15), 38); % 温度修正低于25度时每降1度能耗增加约1.2% temp_factor 1 0.012 * max(0, 25 - temp_amb); % 高温修正高于25度时每升1度能耗增加约0.6% temp_factor temp_factor 0.006 * max(0, temp_amb - 25); E_consum E_base * temp_factor .* (1 0.4 * randn(N, 1) / 3);这里最后一项是驾驶风格扰动用正态分布叠加标准差控制在13%左右模拟不同司机的加速刹车习惯。实际数据也验证了这一点同一路段同一台车不同司机开出来的百公里电耗能差两到三度电。3.3 里程抽样的注意事项行驶里程我用的是对数正态分布。直白解释就是大部分车的里程集中在一个较低区间但存在一个较长的尾巴。代码如下dist_trip lognrnd(3.9, 0.45, N, 1); dist_trip min(dist_trip, 400); % 截断避免出现不合理的极端值对数正态分布的参数3.9和0.45对应中位数大约49公里大部分样本落在20到120公里区间偶尔会有200公里以上的长尾。这样设定贴近实际通勤和城市运营场景。这里有个容易犯的错直接用车企标称的续航去做随机抽样。标称续航来自理想工况落地一定会打折。更合理的做法是用“实际能耗×实际里程”的方式反推剩余电量这样续航打折已经隐含在能耗的随机性里了。4. 充电功率模型为什么实际功率永远低于额定值4.1 恒流恒压充电曲线的简化处理充电功率分析比里程分析稍微复杂一点因为充电功率在整个充电过程中不是恒定的。锂电池充电一般分两个阶段恒流阶段和恒压阶段。电量低于80%左右时充电电流可以保持在一个较高水平功率接近额定值过了80%以后进入恒压阶段电流逐渐减小功率明显下降。从充电桩侧看到的现象就是一辆车从20%充到80%可能很快但从80%充到100%反而要花同样甚至更长的时间。在蒙特卡洛模型里我不推荐把充电曲线做成超精细的分段函数那样参数太多反而不容易让结果稳定。一个足够用的简化方案是引入SOC修正系数soc_factor ones(N, 1); soc_factor(soc_end 0.8) 1; soc_factor(soc_end 0.8) 1 - 2.5 * (soc_end(soc_end 0.8) - 0.8); soc_factor max(soc_factor, 0.15);意思是SOC低于80%时功率不打折高于80%后线性下降到SOC等于1的时候功率只剩15%。这个简化虽然不够精确但在车队规模的统计层面已经足够反映现实趋势。4.2 不同桩型的额定功率离散抽样充电桩的额定功率不是一个连续变量而是离散的档位家充7kW、目的地慢充11kW或22kW、公共快充60kW和120kW、超充250kW。建模时要按比例随机选择桩型power_bins [7, 60, 120]; power_prob [0.2, 0.5, 0.3]; charge_type randsample(1:3, N, true, power_prob); P_rated power_bins(charge_type);这个比例可以根据具体的应用场景调整。如果是分析小区夜间充电场景7kW和11kW的占比就要调高如果是分析高速服务区120kW以上的占比要显著增加。4.3 环境温度和随机波动的修正除了SOC曲线电池温度同样会限制充电功率。低温环境下电池管理系统会主动限制充电电流以保护电池这在冬天尤其明显。温度修正系数我使用了分段函数15度以上基本不限制0到15度线性下降低于0度限制更多。temp_factor_charge ones(N, 1); temp_factor_charge(temp_amb 15) 0.6 0.4 * temp_amb(temp_amb 15) / 15; temp_factor_charge max(temp_factor_charge, 0.5);再加上一个随机波动系数模拟充电桩之间的一致性差异rand_factor 0.9 0.1 * rand(N, 1); P_real P_rated .* soc_factor .* temp_factor_charge .* rand_factor;这样算出的实际功率会对标现实——比如额定120kW的桩在电量80%以下、温度正常的理想条件下可能跑到100kW出头但冬天车辆电量较高时实际功率可能只有四五十千瓦。5. Matlab完整实现与代码走读5.1 主体框架与参数区整个仿真代码我组织成了五个区块参数初始化、随机抽样、里程计算、充电计算、统计输出。先把头部参数和安全边界写清楚%% 蒙特卡洛仿真电动车行驶里程与充电功率分析 clear; clc; rng(42); % 固定随机种子让结果可复现 N 20000; % 蒙特卡洛仿真次数 C_battery 60; % 电池容量单位kWh soc_min_limit 0.15; % 电池保护下限低于此值会限功率甚至无法行驶固定随机种子是特别容易被忽略但特别重要的一步。如果不设置rng每次跑代码生成的随机数都不一样结果走势一致但具体数值每次都在变。调试阶段对比参数影响时要能够对齐随机序列否则说不清结果是参数变化引起的还是随机波动引起的。5.2 随机抽样区接下来把所有随机变量一次性生成%% 1. 随机变量抽样 % 初始SOCBeta分布映射到0.1~1.0 soc_start betarnd(6, 2, N, 1) * 0.9 0.1; % 日行驶里程对数正态分布截断到400km dist_trip lognrnd(3.9, 0.45, N, 1); dist_trip min(dist_trip, 400); % 环境温度正态分布截断到[-15, 38]摄氏度 temp_amb normrnd(20, 8, N, 1); temp_amb min(max(temp_amb, -15), 38); % 驾驶风格扰动 style_factor 1 0.4 * randn(N, 1) / 3;这里用向量化方式一次性生成了全部两万个样本。Matlab矩阵运算的效率远高于循环这也是我推荐用Matlab而不是用纯脚本语言做这件事的原因之一。之后所有计算都基于这些列向量代码简洁而且不易出错。5.3 行驶里程仿真循环严格来说这里不需要循环全部可以向量化但为了逻辑清晰我按模块组织%% 2. 行驶里程与末端SOC仿真 E_base 0.15; temp_factor_drive 1 0.012 * max(0, 25 - temp_amb); temp_factor_drive temp_factor_drive 0.006 * max(0, temp_amb - 25); E_consum E_base * temp_factor_drive .* style_factor; % 终点SOC soc_end soc_start - (E_consum .* dist_trip) / C_battery; % 低于下限的记录为亏电 soc_end max(soc_end, 0); soc_low_flag soc_end soc_min_limit;soc_low_flag是一个01向量后面统计“亏电比例”时直接对它求均值就行。这里要留意当计算结果出现SOC为负时意味着车辆无法完成当日行驶计划这本身就代表风险应该单独统计出来不要直接截断后丢入后面的分析。5.4 充电场景仿真充电场景要回答的问题是这批车实际充到的功率有多高充满一台车需要多久核心实现如下%% 3. 充电功率仿真 power_bins [7, 60, 120]; power_prob [0.2, 0.5, 0.3]; charge_type randsample(1:3, N, true, power_prob); P_rated power_bins(charge_type); % SOC修正系数 soc_factor ones(N, 1); high_soc soc_end 0.8; soc_factor(high_soc) max(0.15, 1 - 2.5 * (soc_end(high_soc) - 0.8)); % 温度修正系数 temp_factor_charge ones(N, 1); cold_flag temp_amb 15; temp_factor_charge(cold_flag) max(0.5, 0.6 0.4 * temp_amb(cold_flag) / 15); % 随机一致性波动 rand_factor 0.9 0.1 * rand(N, 1); % 实际充电功率 P_real P_rated .* soc_factor .* temp_factor_charge .* rand_factor; % 从当前SOC充到85%所需时间小时 soc_target 0.85; energy_needed max(0, (soc_target - soc_end) * C_battery); t_charge energy_needed ./ max(P_real, 0.1); % 避免除零这里的逻辑环环相扣SOC低的车辆需要充入更多电量但充电功率受SOC区间影响额定功率高的桩在一定程度上能缩短充电时间但如果是在低温环境下高功率优势也会被明显压制。5.5 统计输出与可视化%% 4. 统计输出 fprintf(末端SOC分位数P10%.2f P50%.2f P90%.2f\n, ... prctile(soc_end, [10 50 90])); fprintf(亏电比例%.2f%%\n, 100 * mean(soc_low_flag)); fprintf(充电功率分位数P10%.2fkW P50%.2fkW P90%.2fkW\n, ... prctile(P_real, [10 50 90])); fprintf(平均充电时间%.2f小时\n, mean(t_charge)); figure; histogram(P_real, 30, Normalization, pdf, FaceColor, [0.3 0.6 0.9]); xlabel(实际充电功率 (kW)); ylabel(概率密度); title(充电功率分布); figure; ecdf(soc_end); xlabel(末端SOC); ylabel(累计概率); title(末端SOC的CDF曲线);prctile函数返回指定分位数工程判断上一般看P10和P90就够了。P10代表了最差情况比如末端SOC的P10说明有10%的车辆收车时电量低于这个值充电功率的P10则说明在最差条件下快充桩能保证的最低实际功率水平。6. 结果怎么读分位数才是工程话语6.1 直方图和CDF跑完两万次仿真后充电功率的直方图通常会呈现一个多峰的复杂形状根本原因是桩型离散分布叠加了功率修正。如果只看平均功率可能得出一个“平均功率55kW”的结论但这个数值对实际决策帮助不大。更好的做法是读分位数。假设输出结果是P1018kWP5046kWP9082kW这意味着10%的车辆充电功率低于18kW一半车辆低于46kW最乐观的10%车辆能超过82kW。如果规划充电设施时按P50配置高峰期会有一半车辆无法在预期时间内完成充电如果按P90配置大部分情况都很从容但投资成本会显著上升。选择哪个分位数本质是成本和风险容忍度的权衡。6.2 充电时间的分布更有决策价值单看功率其实还不够充电时间是用户更关心的指标。充电时间分布同样可以用分位数描述P50一小时二十分钟P90两小时以上。这个数据对充电场站的场地排队设计非常关键直接决定了需要设置多少个车位。这里会看到一个有意思的现象大功率快充桩虽然功率高但受SOC超过80%后降功率的影响如果车队的末端SOC普遍较高实际充电时间的改善幅度并没有想象中大。这从侧面说明盲目堆高充电桩功率不一定能解决充电效率问题反而可能带来电网容量压力和资源浪费。6.3 模型的检验和调参方向跑完结果后不要急着下结论先做一致性检查。一个有效的方法是看末端SOC的均值是否落在合理区间。比如仿真结果平均末端SOC在50%左右但同类车型的实际运营数据也在45%到55%之间说明模型可靠如果仿真结果明显偏离实际运营数据就要回头检查能耗基准、分布参数或者修正系数哪里出了问题。调参的时候建议一次只改一个变量固定随机种子然后对比前后分布曲线。比如怀疑低温影响过大就把温度修正系数从1.2%降到0.8%重新跑一遍看P10是否变化如果P10几乎不变说明这个系数在当前温度分布设定下影响有限不需要过度纠结。7. 实操踩坑记录与心得7.1 固定随机种子否则没法调试这是最容易被新手跳过但调试时最关键的步骤。没有固定随机种子哪怕只是换了一台电脑跑同一个脚本结果也会有细微差异这会让参数敏感度分析变得极其痛苦。rng(42)这行代码现在是我所有仿真脚本的标配没有它就不写后面的代码。7.2 不要忽略随机变量之间的相关性温度和能耗之间存在强相关温度和充电功率之间也存在强相关抽样时如果分别独立抽样就相当于割裂了现实。我最初犯过的错误就是温度和能耗各抽各的导致高温天出现低能耗的极端组合结果完全失真。解决方法是先抽温度再通过温度修正系数影响能耗和充电功率这样相关性就自然带出来了。7.3 分布参数要有现实依据仿真输出的是“假设条件下的概率”不是“现实概率”。分布参数不能拍脑袋最好基于实际运营数据的拟合退而求其次也要和行业经验值对齐。比如日行驶里程的分布参数如果是从网约车群体里统计出来的套用到私家车场景就会出现长尾过长的问题。场景变了分布参数一定要重新校验。7.4 极端值别忽略也别纵容对数正态分布天然会产生长尾值截断处理是合理的但截断值要有依据。比如日行驶里程不会超过某主流车型的极限续航温度则要考虑地域气候极值。另一方面完全消除极端值也不对因为蒙特卡洛的价值恰恰是刻画那5%或1%的极端情况。判断标准就看一个问题这个极端值在现实中是否可能发生。7.5 模型是工具不是答案最后一条心得来自几次方案汇报的教训。蒙特卡洛输出的是一个概率分布但如果理解不透彻落在纸面上很容易变成一组无灵魂的统计数字。汇报时我会强调分位数对应的物理场景——P90的充电时间意味着什么天气、什么桩型、什么电量状态下会出现而非简单报一个数字。这样决策者才能真正理解结果而不是把P90当成一个保守的定值来看待。我在实际项目里体会最深的一点是蒙特卡洛分析的价值并不在于让模型变得复杂而在于把现实世界本来就存在的不确定性端到桌面上。一辆车的行驶里程和充电功率不是由一个公式就能给出的答案而是一条受温度、习惯、桩型和电量状态共同影响的概率带。用Matlab实现这个过程并不困难难的是把每个随机变量的分布设定得有理有据以及把输出的分布翻译成工程决策语言。下次再有人问“电动车一天要充多少电”不妨反问一句你问的是平均情况还是那个必须保证的最坏情况
阅读完成 · 觉得有帮助?
咨询建站