尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

考虑交通流量的电动汽车充电站规划Matlab实现与优化

考虑交通流量的电动汽车充电站规划Matlab实现与优化 搞电动汽车充电站规划的人十有八九都会被一个问题卡住明明建了不少站用户还是觉得不好用运营商还是觉得不赚钱。问题出在哪出在“站是拍脑袋定的”。真正靠谱的做法应该是让数据说话尤其要让“交通流量”这个变量参与到规划里来。今天要聊的标题是“考虑交通流量的电动汽车充电站规划Matlab实现”我会把从交通数据预处理、充电需求折算、混合整数规划建模到Matlab代码实现和结果分析的完整链路从头到尾过一遍。内容适合正在做充电站布局研究的在读研究生、刚接触选址优化问题的工程师以及想用Matlab把交通数据和运筹模型结合起来的同学。我会尽量少讲虚的多讲能直接用的东西。1. 问题建模与整体思路1.1 为什么一定得考虑交通流量先想一个问题充电站规划的本质是什么本质是“服务设施选址”。而任何选址问题核心都是回答两件事——需求在哪里我应该把设施放在哪里才能最大化满足需求。如果只是按“哪个小区人口多、哪条街车多”来猜那其实是用静态数据替代动态需求。实际情况是一辆电动车是在路上跑的时候才会产生“我需要充电”的想法而不是停在家里才想起来充。换句话说充电需求的触发点是移动的分布在城市路网的不同路段上。这就是交通流量的意义。它告诉你的是一天之内有多少辆电动车会从A地到B地经过哪些路段在哪些位置附近“有概率”停下来充电。把交通流量纳入规划本质上是把“需求点从离散小区网格”升级成“需求沿路径分布”这会直接改变选址结果。举个实际例子两个候选站一个在大型商场旁边周围车辆保有量大但车辆经过时基本都是短停另一个在快速路出口附近经过的车流量大、停留意愿也强。如果只看静态数据会选商场如果考虑交通流量大概率会选快速路出口。这个差异就是“考虑交通流量”带来的核心价值。1.2 规划目标、决策变量与约束条件怎么定义现在我们把问题形式化。一个经典的、被大量研究者采用的模型是“截获流量选址模型”Flow Capturing Location Model, FCLM。这个模型的思想非常直接把道路网抽象成图把OD出行起讫点对上的流量看成“可以被截获的目标”充电站如果建在某个路径上就能“截获”这些流量。决策变量有两类。一类是“是否在候选站点i建站”记作x_i取值0或1另一类是“OD对q的流量是否被截获”记作y_q取值0或1。目标函数是所有被截获流量的总和最大化max Σ(q∈Q) f_q · y_q其中f_q是OD对q上的交通流量标准化后也可以理解为充电需求强度。约束条件包括截获逻辑约束y_q ≤ Σ(i∈P_q) x_i意思是“只有OD路径上至少有一个被选中站点时这个OD对的流量才算被截获”。建设数量约束Σ(i∈S) x_i ≤ p或者预算约束 Σ c_i x_i ≤ Bp是计划建设的站点数量上限。变量取值约束x_i, y_q ∈ {0, 1}。如果直接照这个模型跑已经能解决很多基础问题。但在实际工程里我建议你在此基础上扩展两到三组约束它们会显著提高方案的落地性。第一是容量约束。每个站的充电桩数量有限截获流量的总和不能超过该站的服务能力。比如一个站规划了10个快充桩那它能服务的车辆数是有上限的。第二是服务半径约束。有些用户愿意绕行但绕行距离不能无限制。如果OD路径上的候选站离路径本身太远实际上用户是不会去的这条流量等于没有被截获。第三是最大绕行系数约束。很多文献会把绕行系数作为单独的约束处理比如绕行不超过原路径的1.2倍。我更推荐在候选站点生成阶段就做这道过滤等到模型里再加约束变量规模会变大算起来也更慢。1.3 算法选型用intlinprog还是遗传算法很多第一次接触选址问题的人上来就想着用遗传算法、粒子群等启发式算法。原因是这类问题看起来是NP难的觉得精确算法解不了。这个认知其实有偏差。FCLM模型本身的约束矩阵很多情况下满足“完全幺模”性质线性松弛后往往就能得到整数解。更关键的是Matlab里有intlinprog这个分支定界求解器几百个候选站点、几千个OD对的问题在普通电脑上往往几十秒到几分钟就能找到全局最优解。这个表现已经足够应付大多数教学和工程场景了。遗传算法当然有它的价值——当模型里加入非线性容量约束、非线性成本函数、站点间协同服务等复杂因素时intlinprog无法直接用这时启发式算法才是合适的选择。但我的建议是优先用精确求解器跑通基线方案把约束弄清楚、把结果验证好再决定要不要上复杂算法。不要在模型还没完全理解之前就去调遗传算法的参数那样只会浪费时间。2. 数据准备与交通流量计算2.1 用Matlab构建路网图结构不管模型多漂亮没有数据就是纸上谈兵。在Matlab里构建路网最基础的是两类数据节点坐标和路段连接关系。节点可以理解成交叉口或路网的拓扑端点路段是相邻节点之间的道路。如果你的项目有真实路网数据比如从OpenStreetMap下载的shapefile可以用shaperead读进来。但真实路网数据通常很乱节点编号不连续、道路有重复线段直接用来跑优化模型会非常痛苦。我个人的习惯是先用shaperead读取然后用graph对象重新编号把重复节点合并把非连通子图剔除掉最后只保留最大连通子图。如果你只是想验证算法没有真实数据那完全可以自己生成一个测试路网。比如在一个平面上随机撒30到50个点作为节点用Delaunay三角剖分或者按距离阈值生成路段。这样生成的路网虽然不够真实但足够测试模型和代码逻辑。这里用Matlab的graph对象是强烈推荐的。它的好处在于内置了很多图论算法比如shortestpath直接就能用而且graph对象支持稀疏邻接矩阵的运算处理几百个节点毫无压力。2.2 OD矩阵与最短路径流量分配路网建好之后下一步是生成OD矩阵。OD矩阵描述的是“从哪个起点到哪个终点有多少辆车”。在实际项目中OD矩阵的来源包括交通调查、手机信令数据、年度的居民出行调查。对于没有这些数据的场景可以通过随机生成来近似随机选择一些节点对作为OD对给每个OD对随机赋一个流量值流量大小可以服从对数正态分布或者幂律分布这样可以模拟少数通路承载大量流量的典型交通特征。有了OD矩阵之后要计算每个OD对的最短路径。这里有一个常见误区直接用Floyd-Warshall算法求所有节点对之间的最短路径。当节点数低于200时倒无所谓但如果节点数多了这个算法的O(n^3)复杂度会非常难受。更好的做法是用graph对象的shortestpath函数对每个OD对单独计算Dijkstra算法的复杂度是O(E log V)远好于Floyd-Warshall。计算完最短路径后把OD流量分配到路径经过的路段上。这一步是把“OD需求”变成“路段流量”的关键操作。如果你做的是最简单的全有全无分配那只需要对每对OD的路径做累加。如果你希望更贴近现实可以让路径有一定的随机性模拟驾驶员不完全按最短路径行驶的情况。2.3 从车流到充电需求的折算方法路段流量不等于充电需求。并不是每辆经过的车都会停下来充电所以需要做一个折算。一个简化但实用的折算公式是需求q 路段流量 f_q × 电动车渗透率 α × 临时充电概率 β电动渗透率α是指所有机动车中电动车占比这个数值可以从城市的新能源汽车保有量比例估算。临时充电概率β是指经过的电动车中“当前电量不足、需要在这附近充电”的比例这个和平均续航里程、途中消耗电量、用户充电习惯都有关系。如果你手头有比较详细的出行数据可以把β拆得更细比如根据OD距离和车辆续航如果OD距离超过续航的70%认为有较大充电需求如果OD距离较短充电概率就给得很低。这种基于距离阈值的分段函数比拍脑袋给一个固定值要合理得多。有一点必须强调这个折算看起来只是乘了两个系数但它决定了最终需求规模的大小直接影响选址结果对站点数量的敏感性分析。所以建议在项目一开始就把α和β作为可调参数模块化放到配置文件里而不是写死在代码中。这样后续做敏感性分析会方便很多。3. Matlab代码实现核心函数与关键步骤逐段拆解3.1 计算路径经过的候选站点集合这一步是整个代码链路的起点也是最容易写错的地方。逻辑很简单对每一条OD路径检查路径经过哪些候选站点。候选站点不是随便定的。我建议在路网节点上筛优先选择进出城主干道附近的节点、快速路出口节点、大型商业区或产业园区周边节点。筛选出来后把候选站点的节点编号存入一个数组。核心代码如下% G: graph对象Nodes是节点坐标数组 % OD_pairs: nOD x 2 矩阵每一行是起点节点和终点节点 % candidateNodes: 候选站点节点编号向量 nOD size(OD_pairs, 1); P cell(nOD, 1); % P{q} 存放第q个OD对路径经过的候选站点 for q 1:nOD path shortestpath(G, OD_pairs(q,1), OD_pairs(q,2)); P{q} intersect(path, candidateNodes); end这里有两个细节值得注意。第一个是intersect默认会排序如果你想保留路径上的先后顺序可以考虑用ismember加逻辑索引P{q} path(ismember(path, candidateNodes));第二个是性能优化。如果OD对数量很大比如几万对每对都跑一次shortestpath会有点慢。这时可以加一个进度显示观察大概需要多长时间如果太慢可以先计算全源最短路径矩阵再从中提取路径节点。后者虽然前期开销大但OD对很多时总时间反而更短。3.2 混合整数规划模型落地模型已经在1.2节给出了。在Matlab里用intlinprog求解关键是把目标函数系数和约束矩阵正确写出来。变量排列顺序我建议这样定义前m个变量是x_1到x_m候选站m是候选站点数量后n个变量是y_1到y_nOD对n是OD对数量。总变量数N m n。目标函数系数f因为intlinprog默认求解的是最小化问题而我们的目标是最大化截获流量所以要加负号。好在只有y变量有系数x变量系数为0m length(candidateNodes); n nOD; N m n; f zeros(N, 1); f(m1:end) -flow_q; % flow_q是n维列向量每个OD对的流量约束矩阵的构建是重点。截获逻辑约束 y_q ≤ Σ(i∈P_q) x_i 需要写成 Aineq * [x;y] ≤ bineq 的标准形式即 y_q - Σ(i∈P_q) x_i ≤ 0Aineq zeros(n, N); bineq zeros(n, 1); for q 1:n Aineq(q, mq) 1; % y_q 的系数 idx P{q}; % 路径经过的候选站编号 Aineq(q, idx) -1; % x_i 的系数取负号 end建设数量约束 Σ x_i ≤ pAineq [Aineq; [ones(1,m), zeros(1,n)]]; bineq [bineq; p];变量类型设置和上下界intcon 1:N; % 所有变量都是整数 lb zeros(N, 1); ub ones(N, 1); % 0-1变量最后调用求解器options optimoptions(intlinprog, Display, final, CutGeneration, advanced); [x_opt, fval_opt, exitflag] intlinprog(f, intcon, Aineq, bineq, [], [], lb, ub, options);如果一切正常x_opt(1:m)就是各候选站点的建设方案x_opt(m1:end)就是哪些OD对的流量被截获fval_opt取绝对值就是最大截获流量。这里提醒一个坑P{q}里的编号是“候选站点在candidateNodes数组中的索引”而不是“路网节点编号”。如果你直接用路网节点编号去索引x变量会访问越界或者引用到错误的位置。我建议在初始化P时就把候选站点在candidateNodes中的位置记录下来而不是记录节点编号。3.3 结果评估与可视化求解得到方案后不要急着写报告先做两层验证。第一层是计算覆盖率。覆盖率 被截获流量 / 总流量。这个值能直观反映方案的质量。不同的p值站点数量上限会得到不同的覆盖率通常画一条“站点数量-覆盖率”曲线用来向决策者展示“多建一个站还能提升多少覆盖率”。这也是项目汇报里最有说服力的图之一。第二层是可视化。把站点标在路网上看看它们在空间上的分布是否合理。Matlab里这个操作很简单figure; plot(G, XData, nodeXY(:,1), YData, nodeXY(:,2), LineStyle, -, NodeColor, [0.7 0.7 0.7]); hold on; selected find(x_opt(1:m) 0.5); scatter(nodeXY(candidateNodes(selected),1), nodeXY(candidateNodes(selected),2), 100, r, filled);从图上你很快能发现一些模型看不到的问题比如多个站点挤在一起形成重复覆盖、站点全部集中在高流量干道上但城市边缘完全没有服务、又或者某条高流量路径上连续设了三个站但旁边区域全是空白。这些都是实际决策中要考虑的现实因素也是为什么我一直强调“模型结果只能作为参考不能直接当最终方案”。4. 我在实际调试中总结的避坑清单4.1 模型解不出来或收敛缓慢时先查这三处第一处是数据本身。候选站点数量超过200个、OD对超过5000对时完整构建的约束矩阵可能让intlinprog跑得很慢。这时我一般先做一步简化计算每条OD路径经过的候选站点数量如果某个OD路径经过0个候选站点那这个OD对肯定无法被截获直接从模型中删掉对应的y变量也可以去掉。这样一下就能减少很多变量。第二处是约束矩阵是否病态。如果Aineq里同时存在接近线性相关的行求解器数值稳定性会变差。检查方法是在构建约束矩阵后查看矩阵的秩是否等于行数如果不等于就需要检查是否有重复或冗余约束。第三处是intlinprog的参数。不要直接用默认参数。把CutGeneration设为advanced把LPMaxIterations调大通常对中等规模问题有明显提升。如果还是慢还可以把NodeSelection设成maxmincost策略但具体效果取决于问题特征需要测试。4.2 交通数据不完整的处理策略真实项目中你拿到的OD矩阵往往是不完整、有噪声的。这时候不要试图把数据“填平”更聪明的做法是生成多个场景。把OD矩阵随机抖动生成高峰和平峰两个场景分别求解然后取两个方案的交集作为推荐方案。如果某个站点在两种场景下都被选中那它大概率是一个稳健的选址。如果某个站点只在高峰场景被选中那它对流量波动很敏感可能需要谨慎决策。这个方法成本很低只需要在OD矩阵生成阶段做一个seed随机控制就可以批量生成不同场景的输入数据。在最终报告里以“多场景稳健性分析”为标题来呈现比单场景结果要有说服力得多。4.3 运行时间过长从三个方面压缩第一个优化点是候选站点数量。不要一次性把所有路网节点都作为候选站点先做一轮预筛选。比如只保留周边500米范围内有道路等级高于支路的节点把候选从几百个压缩到几十个。这样既加速求解也能避免优化结果落在明显不合理的位置。第二个优化点是OD对数量。OD对通常有大量低流量对它们对目标函数的贡献很小却占用了大量最短路径计算时间。建议把流量低于某个阈值的OD对合并或删除比如阈值取总流量的千分之一通常能削减一半以上的OD对数量。第三个优化点是预先计算候选站点在各OD路径上的可达关系。也就是把P{q}的计算结果保存到.mat文件中下次直接加载而不是每次都重新算最短路径。数据没变的情况下这步能省下几十分钟。4.4 Matlab环境相关的几个细节如果你的Matlab版本是R2023a或更高建议把代码文件保存为UTF-8编码。如果中文注释出现乱码一般是因为默认编码不是UTF-8可以设置编码方式为UTF-8或者写注释时统一用英文避免这个困扰。intlinprog需要Optimization Toolbox这是收费工具箱。如果电脑上没有安装可以考虑先跑通一个小规模版本验证算法逻辑。另外Matlab的在线版本网页版也可以运行基本的优化代码但性能明显偏慢大规模数据不建议在网页版上跑。最后提一个习惯问题项目代码建议全部写成脚本函数的形式用一个主脚本控制流程把数据加载、模型构建、求解、可视化拆成独立的函数。这样既方便调试也方便后续换数据重复实验。我见过太多人把所有代码堆在一个脚本里问题小的时候还好一旦要改模型或者换数据那场面只能用灾难形容。5. 从教学案例到实际工程的扩展方向如果你手头的题目是课程作业或者毕业设计做到上面第3节基本就够了。但如果你想把这个项目继续往前推或者你的研究方向就是充电设施规划这里有几个值得投入的扩展方向。第一个扩展方向是多目标优化。实际决策中运营商追求利润最大化政府追求覆盖率最大化用户追求可达性最好。这三个目标放在一个模型里往往是冲突的需要引入多目标优化框架比如NSGA-II生成Pareto前沿最后综合比较选择折中方案。第二个扩展方向是动态交通仿真。用静态OD矩阵是假设交通需求在时间上均匀分布但实际情况是早晚高峰和平峰的流量差异巨大。如果能把动态OD数据加到模型中让模型输出不同时间段的差异化选址和定价策略这就更贴近V2G和有序充电等实际业务场景了。第三个扩展方向是充电站容量与配电网耦合规划。充电站选址不仅仅是交通问题还涉及配电网的容量约束。一个站如果同时接入大量快充桩对配电网的冲击可能很大。把交通流量模型和配电网潮流模型耦合起来做协同规划是现在学术界和工业界都非常关注的方向。每个方向深挖下去都能成一个独立的课题。但从“做出来”到“做深入”前提都是你能把基础模型在Matlab里稳定地跑通、能自由地改参数和看结果。所以如果你现在还处在搭建模型的阶段先把文章里这些步骤吃透把代码跑熟后面的一切会顺很多。
返回列表