
简介2024年华中杯数学建模竞赛B题完整解决方案包聚焦行车轨迹估计交通信号灯周期问题面向参赛队伍及建模学习者提供源代码、论文与配套文档。资源共95个文件总大小15.66MB以MATLAB脚本/函数为主辅以fig/png结果图、csv/mat数据文件、vsdx流程图与PDF论文m文件用于建模与求解csv等表格存放轨迹和信号灯数据图片与图文件便于快速查看输出效果。目前已有135人浏览学习。内容包含B题论文全文、多个求解程序pro1pro4、附件数据与支撑材料、程序运行结果和流程图可辅助复现算法、理解从轨迹数据处理到信号灯周期估计的完整思路。支撑材料与结果表格对应赛题要求便于逐项核对代码均经过运行测试在毕业答辩中获评高分可靠性和完整性较好适合作为数学建模备赛、课程设计和算法入门参考。1. 行车轨迹估计信号灯周期从数据到方案的完整链路2024年华中杯B题给了一个很现实的问题只有车辆轨迹没有信号灯配时方案怎么把路口红绿灯周期估计出来。实际道路数据集通常是低频GPS点包含车辆位置、瞬时速度和方向但没有任何信号灯状态标注。这类问题在数学建模里做起来不难难点在于轨迹噪声和周期性推断的衔接——你既要清洗数据又得用排队长度动态反推信号相位。按项目源码pro1.m到pro4.m的推进顺序数据预处理、停车点聚类、周期估计和交叉验证可以串成一条可复现链路。适合参赛队伍以及做交通轨迹数据挖掘的从业者参考。2. 轨迹数据清洗与速度-时间曲线构建MATLAB预处理细节B题附件原始轨迹来自车载GPS或网约车平台时间戳间隔并不固定高频时1秒一个点拥堵时可能10秒才更新一次。如果不做对齐后面的聚类和相位估计都会引入偏差。我按源码pro1.m的思路把清洗过程分成三步字段修正、速度平滑、停车点定位。这里的核心原则是宁可丢点不要留错点因为一个GPS漂移点就可能让排队长度多算30米。2.1 原始轨迹字段与常见噪声先看一张原始字段表原贴数据里字段名可能略有差异但含义一致。字段名示例值清洗说明vehicle_idSH-xxx按ID分组保证轨迹连续timestamp2024-04-20 08:00:00统一转成秒并按ID和时间排序longitude114.3035用路口包围盒过滤剔除漂移点latitude30.5942与经度一起做平面投影speed12.5与相邻点间距离算出的速度对照direction45区分进口道与出口道这张表对应了pro1.m里做的字段操作。实际项目中我见过轨迹在桥上漂移500米的情况这会让停止线判断完全失效。所以第一步不是滤波而是按经纬度画散点图人工框出路口周围500米的范围只保留这个范围内的轨迹点。也就是说地理围栏比速度滤波更优先。2.2 基于移动中值与阈值的速度滤波GPS输出的瞬时速度在停车和起步瞬间会跳变有时车已经停了速度还显示5 km/h。移动均值滤波会把低速带拉宽把红灯排队误判成缓行移动中值更适合因为能保持速度降到0的跳变沿。下面的函数是从pro2.m里抽出来的。% filter_speed.m function v_filt filter_speed(v_raw, win) % 移动中值滤波window必须为奇数 v_filt movmedian(v_raw, win); % 低速吸附到0消除传感器噪声 v_filt(v_filt 0.5) 0; end参数win通常取5或7。win太小毛刺消不掉win太大起步加速过程被抹平停车点会被延迟几个采样点。0.5 km/h这个阈值不是固定的如果原始数据GPS精度较差可以调到1.0但注意不要吞掉真正的缓行。代码背后逻辑很简单先用中值消掉单一跳变点再用硬阈值把缓慢抖动归零这样停车起点就是v_filt从正值变成0的位置。需要补充说明的是这种滤波方式对网约车轨迹尤其有效因为网约车在路边接客时会出现长时间速度为零但不一定是在路口排队。后续聚类会把这些点排除掉因为它们的空间位置不在停止线附近。2.3 停车点提取与时间对齐速度序列变0后还要判断车辆是否真的在排队。单点速度为0可能是因为GPS逗留但连续3个以上重采样点为0且位置变化小于10米才记为一个停车事件。时间对齐方面先用线性插值把所有车辆轨迹重采样到1秒间隔然后给每条轨迹补上距路口的纵向距离。% extract_stops.m function [stops, t_stops] extract_stops(v_filt, t_uni, pos, min_dur) % v_filt: 滤波后速度; t_uni: 等间隔时间轴; pos: 距停止线距离 % min_dur: 最小停车时长(秒) v_zero v_filt 0; d diff([0, v_zero, 0]); starts find(d 1); ends find(d -1) - 1; stop_idx (ends - starts 1) min_dur; stops pos(starts(stop_idx)); t_stops t_uni(starts(stop_idx)); end这里min_dur设3秒可以滤掉等红灯前的一次短暂停顿。如果你发现周期长度稳定在60秒附近min_dur设为5反而更干净因为它能把同一条轨迹里因前车起步延误造成的二次停车也合并起来。代码里diff([0, v_zero, 0])是找连续零段的起止索引这个技巧在轨迹数据处理里很常用比for循环快得多。也许有人会问为什么不直接用原始速度序列做周期分析因为原始速度包含太多自由流和跟驰片段停车点和速度零段才是红灯排队最直接的证据。把停车点的时间序列单独拿出来后续聚类和FFT才有意义。3. 基于停车点聚类的排队长度计算与可视化第2章得到的stops只是每辆车在红灯期间静止时的位置。同一个信号周期里多辆车会在停止线后排成一条线这些点的纵向坐标差异就是排队长度。直接取最大值减最小值会被离群点带偏所以先要做空间聚类。DBSCAN不需要预先指定簇数适合这种点密度不均匀的情况。3.1 停车点提取与DBSCAN聚类在得到一组候选停车点之后需要对它们进行空间聚类目的是把同一周期、同一车道的排队点分到同一个簇。DBSCAN的两个参数eps和minpts在高密度路口表现比较稳定。对于低频轨迹一辆车在一个周期里只会贡献一个停车点所以一个簇的点数对应一个周期的排队车辆数。% pro3_dbscan_cluster.m idx dbscan(stop_xy, eps, minpts);eps需要归一化。我通常先把经纬度投影成平面坐标或者直接换算成距停止线的纵向距离让x方向尺度远小于y方向。然后eps设8~12米minpts设3~5。路口每条车道宽度约3.5米排队车辆间距约6米eps太小会把同一排队点拆成两簇太大又把对向车道并进来。这部分对应的数据文件cluster_idx_12.mat就是dbscan输出的标签结果里面包含每个停车点的簇编号。参数影响可以看下面这张表。参数推荐范围对应现象eps8~12米小于8会把一列车队拆碎大于12会合并相邻车道minpts3~5小于3噪声点成簇大于5会丢弃稀疏周期这里有一个容易被忽略的点一个周期内同一个车道可能出现两队停车比如左转车和直行车停在相邻位置。如果只做二维DBSCAN很可能把这两队合并成一个簇。所以在聚类前我通常先用direction字段把不同流向的轨迹分开再进行聚类。B题数据里虽然没有明说方向字段但轨迹的方向角可以按起点和终点连线估算出来。3.2 排队长度与停止线距离估计停止线位置在簇的最前端也就是纵向距离最小的那个点。排队长度不直接取最大距离而是用第85百分位点距离减停止线距离因为队尾可能有掉头、变道等行为最长车辆不一定是排队车辆。下面的函数对应pro4.m里的排队长度计算。% queue_length.m function q queue_length(stop_dist, percentile) % stop_dist: 某簇内停车点的纵向距离 q quantile(stop_dist, percentile) - min(stop_dist); endpercentile取0.85时能避开队尾的零星车辆如果样本量少于6中位数更稳定。这个q就是红灯期间排队长度单位是米。源码pro4.m里还计算了排队的消散率公式是排队长度除以该周期的绿灯起步时间差。消散率可以用来估计饱和流率是后面绿信比估计的中间量。排队长度本身也有诊断作用如果某个周期的排队长度明显短于其他周期说明该周期到达车辆少或者该周期不是红灯排队而是偶发事件停车。这种异常点应该在后续FFT之前剔除而不是直接参与平均。3.3 可视化排队时空图只用数字不直观我习惯画一张“时间-距停止线距离”散点图横轴是时间纵轴是位置颜色代表瞬时速度。红色点集中在停止线附近不同周期的排队过程在图上会形成重复的三角形图案。scatter(t, dist, 8, speed, filled); ylim([0, 300]); xlabel(时间 (s)); ylabel(距停止线距离 (m)); colormap(flipud(hot)); colorbar;图里每条斜线代表一辆车从停止线起步进入下游的过程。红灯时点都堆在某一小段纵坐标上绿灯后斜线开始向右上延伸。如果看不到清晰的三角形说明聚类参数或者停止线位置有问题不要急着做周期估计。我在B题附件里看到一张程序运行结果和流程图里面画的时空图用的就是这种配色队尾和队头一眼就能区分。这张图写论文时可以直接引用作为模型中间结果的证据。4. 信号周期与绿信比估计从频谱分析到交叉验证4.1 用排队长度时序做周期谱估计停车事件本质上是红灯开始的标记所以停车点时间序列天然带有信号周期信息。把每5秒窗口内的停车事件数量统计出来得到一个计数序列再做FFT峰值频率对应信号周期的倒数。相比用平均速度做频谱停车计数的优势是消除了自由流车速差异的干扰只保留与信号相关的停车特征。% period_fft.m N length(count_series); Fs 0.2; % 5秒一个采样点 Y fft(count_series - mean(count_series)); P2 abs(Y/N); P1 P2(1:N/21); f Fs*(0:(N/2))/N; [~, idx] max(P1(2:end)); period 1/f(idx);注意FFT要求序列足够长至少要有4个完整周期。如果采集时间是15分钟实际可取片段是8~10分钟能覆盖6个周期谱峰足够稳定。P1(2:end)跳过了直流分量避免零频掩盖实际峰值。这个周期是排队计数的主周期它与信号灯周期一致的前提是每个周期都有车在红灯期间排队。如果某个周期恰好没有车辆到达谱峰值会变矮但主峰位置不会被小缺口改变。有些参赛队会用小波变换代替FFT理由是信号非平稳。但实际上固定配时路口的信号周期在半小时内基本不变FFT已经足够稳定如果路口是感应控制周期本身就在变应该改用滑动窗口FFT而不是整体做谱估计。4.2 绿信比估计排队消散时间法周期只告诉一个循环总时长绿信比还要靠消散时间来推算。绿灯亮起后排队车辆从停止线开始加速尾车通过停止线的时间相对红灯开始时刻的延迟就是红灯时长加启动损耗。用停车点时间的最小值和消散结束时间之差可以估算有效红灯时长。% green_split.m red_start prctile(t_stop_in_cycle, 20); % 红灯开始簇 green_start prctile(t_move_in_cycle, 80); % 车流启动簇 red_time green_start - red_start; green_ratio (period - red_time) / period;这里的prctile是为了剔除离群车不是直接用最早和最晚。red_start取该周期内停车点出现时刻的第20百分位数因为第一辆停车车不一定正好是红灯开始可能晚了几秒green_start取起步行车时间的第80百分位代表大部分车已通过。用这种方法算出来的绿信比误差在0.1以内足以判断路口是红灯长还是绿灯长。注意这里的red_time是有效红灯时间包含黄灯和全红清空时间与配时方案里显示的红灯时长会有几秒偏差这是正常的。启动损耗在低频轨迹下尤其明显。驾驶员从静止到通过停止线通常需要2~3秒如果轨迹采样间隔是5秒red_time会被高估。我的处理办法是对每个周期单独做线性回归把排队消散段的斜率延长到速度零时刻用交点作为绿灯实际开始时间能减小一个采样周期的影响。4.3 交叉验证与相位差校核单路口估计容易受样本量干扰B题附件里给出了多组轨迹对应的pro4.m把相邻两个方向的停车时间做了互相关。理想情况下南北向和东西向的红灯开始时间应该相差半个周期再加上一个固定相位差。互相关峰值位置就是相位差如果算出来不是周期的一半说明某个方向的数据量不够或者停止线位置标错了。[c, lag] xcorr(series_ns, series_ew, normalized); [~, I] max(abs(c)); phase_diff lag(I);phase_diff除以周期接近0.5是正常的十字交叉口接近0或1说明两个方向同步放行可能是T型路口或搭接相位。这个校核能发现周期估计是否正确如果主频已经算错相位差会随机跳动而不是稳定在0.5附近。实际写论文时把相位差加一张散点图评委一眼就能看出模型有效性。在我处理过的项目里多次发现相位差校核能提前暴露停止线偏移问题比单纯看周期拟合误差更敏感。5. 参数鲁棒性调优用轨迹数据验证周期估计的实用技巧5.1 聚类半径与最小样本量的联动选择eps和minpts不是独立参数。常见做法是从eps8、minpts4开始画一遍聚类结果如果簇内停车点纵向距离超过50米说明eps偏大两个不同车道的排队点被并成一簇如果簇数大于进口道数量说明eps偏小同一排车队被切成了多段。可以写一个扫描脚本记录不同参数下的簇数和簇内平均距离30秒内就能跑完。% tune_dbscan.m for eps 6:2:14 idx dbscan(stop_xy, eps, 4); n_cluster max(idx); fprintf(eps%d, clusters%d\n, eps, n_cluster); end判断依据是一个路口的停车点簇数应当接近车道数乘以周期数。如果你统计的15分钟内有12个周期、3条车道期望簇数在30~40之间。簇数明显偏少就把eps调小簇内点数量稀疏就增大minpts来抑制噪声。5.2 周期估计自洽性检查估计完周期T后不要直接信结果。按T和绿信比重建一个理想停车时间窗口再与实际停车点匹配。我的做法是把时间轴切成若干个T的整数段统计每个窗口内停车点数如果大多数窗口点数接近且没有空窗说明周期可靠。% consistency_check.m window mod(t_stop, period); hit sum(window red_time | window red_time 5); ratio hit / length(t_stop);ratio高于0.8说明80%的停车点确实落在红灯区间附近低于0.7就回去查聚类参数。这种自洽性检查可以写进论文的模型检验部分比单看均方误差更直观。使用这个方法时最好把周期附近的停车点都纳入匹配因为黄灯期间到达的车辆也可能停车这些点本身就落在红灯边缘。5.3 结果表与答辩图表组织最后把所有路口的周期、绿信比、相位差写入“附件5结果表格”。图控制在三张原始轨迹图、排队时空图、频谱图。三张图对应三个处理阶段也对应论文的三个方法部分。答辩时按图讲流程比贴公式更省时间。特别是排队时空图要标出停止线位置和一次完整周期的起止评委能直接看到你做了数据校核。本文还有配套的精品资源点击获取