ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

基于蒙特卡洛的Matlab电动汽车充电负荷模拟全流程解析

基于蒙特卡洛的Matlab电动汽车充电负荷模拟全流程解析 做配电网规划或者做电动汽车接入影响分析的工程师应该都被同一个问题折腾过怎么把一片区域的充电负荷曲线估出来。用户规模、出行习惯、电池容量、充电功率全都在随机波动指望用一条解析函数去推根本不现实。这时候用蒙特卡洛算法在Matlab里做随机抽样模拟就成了最经典也最容易落地的一套做法。我把自己做这块仿真的完整套路理一遍包括概率模型怎么建、参数怎么定、代码怎么写、结果怎么收敛以及一些文档里不会写的坑。不管你是研究生开题做负荷预测还是项目里需要出一版负荷曲线用于配电网评估这套流程基本都能直接抄作业。1. 蒙特卡洛在充电负荷模拟中的定位与整体思路1.1 为什么这个场景非用随机抽样不可充电负荷本质上是一堆随机事件叠加出来的结果每个用户今天开多少公里、几点回小区、回家插不插枪、用多大功率充电全部是随机变量。单独看任何一辆车你几乎无法预测它今晚到底充不充电但放到群体层面规律就出来了——日行驶里程近似服从对数正态分布回家时刻集中在傍晚到夜间充电功率取决于充电桩类型充电比例大概率落在某条调研曲线附近。蒙特卡洛的核心思路就是把这些“有规律但不确定”的随机事件按概率分布大量抽样生成成千上万个“虚拟用户的一天”再把他们的充电过程累加起来。打个比方你在靶场上随机射箭单支箭落在哪完全随机但射得足够多之后弹孔的整体分布形状会稳定下来和真实的概率分布越来越接近。蒙特卡洛收敛的本质就是大数定律样本量大了统计特征趋近于理论真值。我自己早期也尝试过直接用典型日负荷曲线乘以渗透率来估那属于“拍脑袋修正系数”做宏观估算勉强能用一旦要落到具体台区、具体季节、具体充电策略偏差会大到没法交代。改用蒙特卡洛之后每一个假设都有概率模型支撑最后还能顺手给出置信区间和分位数这让结果在讨论“最坏场景”时非常有说服力。1.2 从“单辆车”到“区域曲线”的完整模拟流程整个模拟框架并不复杂核心链路是这样的确定模拟对象与总量模拟多少辆车、什么车型、电池多大、续航多少、慢充快充比例如何。从概率分布中抽样生成单辆车的出行与充电参数比如日行驶里程、回家时刻、是否充电、充电功率。根据车辆状态计算单辆车的充电功率时段序列本质上是个随时间变化的矩形脉冲。把区域内所有车辆的充电序列按时间对齐后叠加得到当日总负荷曲线。重复执行多次蒙特卡洛迭代每次迭代都会得到一条“可能出现的当日曲线”。对多次迭代结果逐点求平均、求分位数得到期望曲线和置信区间。这个流程之所以要“先单辆、再叠加”是因为所有不确定性都在单辆车层面发生叠加过程只是线性求和。你不需要构造一个超大规模的解析方程组只要能把单辆车的充电过程写清楚后面就是循环、累加、统计。我习惯先在纸面上把这六步画出来再动手写代码。因为后面每次调整参数都是在改第一步和第二步的分布或常量改完就知道结果会受到什么影响。如果一上来就闷头写循环很容易把逻辑绕晕。2. 充电负荷模型的关键模块与数学描述2.1 车辆出行参数日行驶里程与回家时刻充电负荷模型的第一个关键模块是车辆当天到底消耗了多少电。我们通常用“日行驶里程”来推算耗电量行驶越多电池剩余越少回家后需要充的电就越多。日行驶里程在实测数据里呈右偏分布大部分车主每天只开二三十公里少部分跑长途的能开到一两百公里。对这种数据最常用的拟合分布是对数正态分布f(x) 1 / (xσ√(2π)) · exp(−(ln x − μ)² / (2σ²))实际取参数时μ3.3、σ0.6 对应的均值大约在 exp(3.3 0.6²/2) ≈ 33 公里比较接近城市通勤场景。如果你手上有本地交通调查数据直接用 fitdist 拟合实测里程会更准这一点后面会再强调。回家时刻是第二个关键变量。绝大多数家用车充电发生在回家之后因此回家时刻直接决定了充电负荷的起始位置。最常用的做法是用截断正态分布均值取 17~18 点标准差取 1.5 小时再截断到 [16, 24] 区间避免抽样出现凌晨三四点回家这种与场景不符的情况。如果你的研究区域是大型购物中心或高速服务区回家时刻分布就得换成对应的停车时长分布模型不能再套住宅区参数。2.2 充电行为参数充电时刻、功率与目标SOC有了当天耗电量还得确定车辆是否充电、什么时候开始充、用多大功率充、充到多少停。这四个参数对应着四个概率模型。是否充电用充电概率来表示。住宅区夜间充电概率一般在 0.8 到 0.9 之间商业区则低很多可能只有 0.3 左右。开始充电时刻通常是回家时刻加一个随机延迟延迟可以用 0~0.5 小时的均匀分布也可以按实测用指数分布模拟“回家先歇一会儿再插枪”的真实情况。充电功率不能一概而论。慢充桩常见的功率有 3.5kW、7kW、11kW、22kW 几档未来快充渗透率提高后还会有 60kW 以上直流桩参与。我一般通过概率加权抽样的方式为每辆车分配功率比如 3.5kW 占 20%7kW 占 60%11kW 占 15%22kW 占 5%。目标 SOC 取 0.9 比较常见部分车主只充到 0.85 就拔枪这也可以做成一个分布。充电持续时长则由起始 SOC、目标 SOC、电池容量和充电功率共同决定T_charge (SOC_target − SOC_start) × BatteryCap / P_charge这里 SOC_start 1 − D/RangeD 是日行驶里程Range 是续航里程。如果 D/Range 接近 1SOC_start 会很低充电时长就会很长这种情况需要设置物理下限比如 SOC_start 最低取 0.2防止出现“电池完全跑空还继续开”的荒谬场景。2.3 为什么群体叠加之后曲线会自然变光滑单辆车的充电负荷其实非常难看就是几个矩形脉冲从插枪瞬间开始功率跳到 7kW持续两三个小时再突然跳回 0。但如果直接把几百上千辆车叠加起来曲线会出人意料地光滑。原因是大量脉冲的起始时刻、持续时长、功率大小互相错开错位叠加把单车的“棱角”抹平了。这就像食堂打饭单个窗口的排队人数波动很大但整个食堂中午的总人流量曲线是相对稳定的。理解这一点很重要它解释了为什么蒙特卡洛模拟不要求精确预测每一辆车的行为——群体统计特性决定了总负荷曲线的基本形态。从仿真实现角度看这还意味着你不需要用秒级步长。把时间离散成 15 分钟一个点每天 96 个点对充电持续两小时以上的慢充场景来说精度完全够。时间步长取得太小计算量成倍增加曲线并不会因此更准确因为主要的误差来源是概率模型本身而不是时间分辨率。3. Matlab代码实现与参数配置3.1 先把所有参数集中到文件头部我写这类仿真代码有个习惯所有可调参数全部集中放在脚本开头做成一个“参数区”。这样每次换场景只需要改参数区的数值不需要在几十行代码里翻找。参数区至少包含这些内容模拟车辆数、蒙特卡洛迭代次数、时间步长、电池容量、续航里程、目标SOC、充电概率、功率等级与概率、回家时刻分布均值与标准差、日行驶里程分布参数。车辆数和迭代次数是两个非常关键的规模参数。车辆数少了单次模拟曲线会有明显的锯齿迭代次数少了均值曲线在不同随机种子下跳动很大。我常用的组合是 1000 辆车 × 1000 次迭代得到的结果已经足够稳定Matlab 大约几十秒能跑完。如果只是演示或教学500×500 也能看趋势。3.2 核心循环的代码实现与逻辑拆解下面是一段可以直接复用的核心代码我按照“先抽样再计算后叠加”的顺序写方便理解rng(2025); % 固定随机数种子保证结果可复现 N_Veh 1000; % 模拟车辆数 N_MC 1000; % 蒙特卡洛迭代次数 T_step 15; % 时间步长单位分钟 nSteps 24 * 60 / T_step; % 每天96个点 Cap 60; % 电池容量kWh Range 400; % 续航里程km SOC_target 0.9; % 目标充电SOC P_levels [3.5, 7, 11, 22]; % 充电功率等级kW P_probs [0.2, 0.6, 0.15, 0.05]; % 对应概率 Curves zeros(N_MC, nSteps); for iter 1:N_MC % 1. 日行驶里程对数正态分布 D lognrnd(3.3, 0.6, N_Veh, 1); % 2. 回家时刻截断正态分布在16到24点之间 T_home 17 1.5 * randn(N_Veh, 1); T_home max(16, min(24, T_home)); % 3. 起始SOC设0.2下限防止极端情况 SOC0 max(0.2, 1 - D / Range); % 4. 是否当天充电 isCharging rand(N_Veh, 1) 0.85; % 5. 按概率分配充电功率 P datasample(P_levels, N_Veh, Weights, P_probs); curve zeros(1, nSteps); for i 1:N_Veh if ~isCharging(i) continue; end % 回家后延迟0~0.5小时开始充电 startTime T_home(i) * 60 0.5 * rand * 60; if startTime 24 * 60 continue; end % 计算充电持续时长单位小时最长限制8小时 hChg (SOC_target - SOC0(i)) * Cap / P(i); hChg min(hChg, 8); % 充电结束时刻限定在当天24点内跨天部分归到次日 endTime min(startTime hChg * 60, 24 * 60); % 将功率叠加到对应时间步上 tIdx floor(startTime / T_step) 1; eIdx floor(endTime / T_step); curve(tIdx:eIdx) curve(tIdx:eIdx) P(i); end Curves(iter, :) curve; end meanCurve mean(Curves, 1); p95Curve prctile(Curves, 95, 1);这段代码有几个设计点说一下。日行驶里程和回家时刻的抽样我直接用向量化操作一次生成 1000 个样本比在单车循环里逐辆 randn 快得多。充电起始 SOC 的计算也完全向量化了但真正叠加负荷时还是需要逐辆车做因为每辆车的开始时间和结束时刻都不同没法用一次矩阵运算直接解决。叠加时这里采用的是一个工程近似充电从 tIdx 步开始到 eIdx 步开始前结束中间所有整步都按全额功率计。因为 15 分钟步长相对慢充时长来说足够细这一步近似带来的误差通常在 1% 以内为了计算效率完全值得。代码最后对 Curves 沿第一维取平均值和 95 分位数得到的结果既能看期望场景也能看较恶劣场景。3.3 核心参数速查表与调参逻辑把常用参数整理成一张表方便对照设置参数含义取值/分布说明N_Veh模拟车辆数500~2000太少曲线锯齿明显太多计算变慢N_MC蒙特卡洛迭代次数500~2000决定均值曲线稳定性T_step时间步长10~30分钟慢充场景15分钟足够Cap / Range电池容量/续航60kWh / 400km按主流车型调整SOC_target目标电量0.85~0.95反映用户充电习惯充电概率当日充电比例0.75~0.9住宅高、商业低功率档位桩的功率分布3.5~22kW按实际充电桩普查数据回家时刻到家时间分布N(17, 1.5) 截断可换成实测直方图调参有一条经验优先改“充电概率”和“功率分布”因为它们对曲线峰值和形状的影响最显著。日行驶里程分布参数会影响总充电量的绝对值但峰值的出现时段主要由回家时刻和充电开始延迟决定。抓主要矛盾别的细节先放一放。4. 结果分析、收敛性判断与场景扩展4.1 怎么判断你的模拟结果收敛了蒙特卡洛模拟最怕的情况是结果还没收敛你就拿着均值曲线去写报告了。判断收敛不能靠肉眼看曲线变得平滑因为曲线平滑是车辆数多导致的不代表多次迭代之间的重复性足够好。我常用的办法是跑一组“迭代次数递增”的对比实验分别用 100、300、500、1000 次迭代去跑同一组参数观察某几个关键指标——比如晚高峰峰值、总充电电量——随迭代次数增加的波动幅度。当峰值从 900kW 变成 912kW再变成 915kW1000 次时还在 915kW 上下小幅波动基本可以认为曲线收敛了。更正规一点的量化指标是峰值变异系数CV std(Peaks) / mean(Peaks)其中 Peaks 是每次迭代模拟得到的当日负荷峰值序列。CV 降到 0.03 以下通常说明峰值估计已经比较稳定。如果你需要更严格的统计精度就继续增加迭代次数或者把每次迭代的车辆数加大两者的效果略有不同加大车辆数能压低单次模拟的抽样噪声增加迭代次数能提高均值估计的稳定性。一个容易被忽视的点不同时刻的收敛速度不一样。负荷高峰时段因为样本量大、波动被“平均”得比较好收敛快凌晨低谷时段样本稀疏相对波动大收敛慢。因此你看到的均值曲线可能在高峰段非常稳定低谷段却还在轻微抖动这并不奇怪分析时心里有数就行。4.2 除了均值曲线更要看分位数场景做工程评估的人往往会问一句你这曲线是“平均情况”还是“最坏情况”平均值会抹掉极端场景而配电网规划又特别关心极端场景——变压器容量裕度、线路负载率都要按可能出现的高负荷去校核。所以我在给出均值曲线的同时一定会输出分位数曲线。上面的代码里已经有一行 p95Curve prctile(Curves, 95, 1)它的含义是在 1000 次模拟中每个时刻取 95% 分位数的负荷值。把所有时刻的 95% 分位数值连起来就得到一条“有 95% 置信把握不会超过”的负荷曲线上包络。实操中P50 曲线用于做电量估算和全年能耗分析P95 曲线用于设备选型和容量校验。如果项目特别强调极端风险还可以看 P99。需要提醒的是P95 是逐点统计的不代表“同一天内所有时刻都同时达到 95% 分位”的场景真要做联合场景分析需要从 Curves 矩阵里抽取若干条完整曲线作为典型场景再做潮流计算。这一点容易被忽略但做规划评估时非常关键。4.3 三种场景扩展玩法试过都说好用基础版本跑通之后扩展方向其实很灵活。我试过三种最有实用价值的玩法。第一种研究不同区域类型。把充电概率从 0.85 调到 0.6回家时刻分布换成商业区模式就能模拟商业办公区白天充电为主的负荷形态换成高速服务区场景则要新增快充功率档位和高功率比例。区域变了其实只改几个分布参数代码框架完全不用动。第二种研究快充渗透率提升的影响。把功率等级从 [3.5, 7, 11, 22] 改成 [7, 22, 60, 120]并调整概率权重就能看到负荷峰值明显抬高、峰谷差拉大的趋势。这种场景对充电桩规划特别有用可以直接回答“未来三年快充桩占比上升到 30% 以后台区还扛不扛得住”这类问题。第三种进阶一点的多日连续模拟。单日模型假设每天都是从“满电或接近满电”状态出发但实际上智能充电、有序充电应用下车辆连续多日的 SOC 状态是有记忆的。把当天结束时的 SOC 作为次日初始 SOC 的边界条件连续模拟一周甚至一个月就变成了一个马尔可夫链式的迭代过程。这样可以评估夜间谷电时段充电策略的效果也是当前有序充电研究里常见的做法。5. 常见问题排查与工程落地建议5.1 五个容易踩的建模坑与排查思路先说一个最常见的坑起始SOC出现大量0.2的堆叠平台。这个问题几乎每个人都遇到过。原因是日行驶里程分布参数没调好或者续航里程设置偏小导致 D/Range 频繁超过 0.8SOC0 被下限 0.2 截断到同一起点。结果就是充电时长扎堆负荷曲线出现不合理的“同步充电”现象。排查方法是画出 D/Range 的分布直方图看看尾部是否过厚如果尾部很厚要么把对数正态参数调小要么给 SOC0 下限换个更合理的取值。第二个坑是凌晨时段负荷异常地低甚至趋近于零。原因通常是开始充电时刻被截断在 24 点内跨天的充电负荷被直接扔掉。实际中很多车是半夜还在充的凌晨 1~5 点恰恰是慢充负荷的重要时段。我的处理方式是把 endTime 截断到 24 点没错但如果你需要分析次日凌晨的负荷就得把时间轴扩展到次日早晨或者把“跨天未完成部分”记录到单独的变量里再做拼接。单纯把凌晨数据舍弃会让总充电量偏低均值曲线在 0~6 点这一段失真。第三个坑是结果每次跑都不一样复现不了。解决方案就是代码第一行写的 rng 固定种子。有时候你会在循环里用随机数一旦固定了种子整条随机链就固定了。调试时固定一个种子批量跑场景时再放开这样可复现和场景多样性都能兼顾。第四个坑是跑得很慢。一个常见原因是把时间轴写成了最内层循环比如对每辆车、每个15分钟都做一次 if 判断光循环开销就大得惊人。优化方向是把内层循环里的逻辑尽量移到向量化抽样阶段负荷叠加部分用矩阵索引批量赋值就像我上面代码写的 curve(tIdx:eIdx)。如果车辆数超过 5000还可以把外层 for iter 换成 parfor配合 Parallel Computing Toolbox速度提升非常明显。注意 parfor 里不能动态修改共享变量我的做法是把每次迭代结果先存到临时变量循环结束再一次写入 Curves。第五个坑是充电时长的物理合理性。有些车起始 SOC 很低功率又只有 3.5kW算出来的充电时长可能超过 12 小时甚至 20 小时。如果不对充电时长做上限限制深夜负荷会被拉出一长条平顶明显不真实。我一般设 8 小时上限也可以根据小区停车场管理规则设成 10 小时但必须要有上限。把常见问题和排查建议整理成一张速查表方便现场对照现象可能原因排查建议SOC0 大量等于 0.2D/Range 分布尾部过厚检查里程分布参数与续航设置凌晨负荷偏低跨天充电被丢弃扩展时间轴或拼接跨天电量多次运行结果差异大未固定随机数种子在脚本开头加 rng 语句计算耗时过长循环层级设计不合理向量化抽样加批量索引叠加深夜出现异常平顶充电时长未设上限增加最长充电时间限制5.2 从模拟结果到报告输出的整理套路模拟跑完数据怎么交付也是有讲究的。我不会直接把 1000×96 的 Curves 矩阵丢给下游而是整理成三类输出。第一类是关键的统计曲线包括 P50、P90、P95 三条曲线保存成 CSV 文件列是时间点行是不同分位。第二类是单次模拟的典型场景曲线比如从 1000 次迭代里挑出“峰值最高的一天”“总电量最大的一天”“最接近均值的一天”三个典型场景方便给规划人员做潮流计算或储能配置分析。第三类是聚合指标包括日总充电电量、峰值负荷、峰谷差、平均负荷率直接汇总成一个表格。绘图方面Matlab 自带的 plot 就够用了。我会把 P50 画成实线P95 画成虚线再用 fill 命令把 P5 到 P95 之间的区域填充成半透明色一眼就能看出负荷带的范围。图例、坐标轴标签、单位这些细节别偷懒报告里直接能用的图比再加工省很多事。如果项目允许尽量拿实际台区数据做一次校验用实测的日行驶里程分布和回家时刻分布替换默认对数正态参数重跑一遍模拟把输出均值曲线和台区采集到的实际充电负荷曲线叠加对比。偏差在可接受范围内这个模型才算真正在这个场景里落地了。5.3 把参数当变量把场景当输入这套框架真正值钱的地方不在某一次模拟的精确度而在于把“充电负荷估算”从一次性的计算变成了一个可以反复回答问题的工具。我个人的习惯是写一个 runScenario 函数把上面所有参数作为输入结构体传入输出统计曲线和指标。这样每个新项目只需要调整参数区模拟代码完全复用。从一开始就按这个思路组织代码几个月后你会感谢自己当初没把参数硬编码到循环里。做蒙特卡洛模拟这些年最大的体会是别追求“参数绝对准确”因为充电行为本身就是分布式的、动态变化的。更务实的做法是明确告诉使用者这套结果是基于哪些假设得到的参数变化时曲线如何响应。有了这种敏感性分析的意识仿真模型才真正具备工程价值而不是一个只会在固定参数下输出一条曲线的黑盒。
返回列表