From 504b07cf39375988814d78a14096474da22a9e39 Mon Sep 17 00:00:00 2001 From: wangxu <1318272526@qq.com> Date: Thu, 4 Dec 2025 17:27:26 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B7=A1=E6=A3=80bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/cross_evaluate_worker.py | 1 + app/eva_common.py | 164 ++++++++++++++++++++++++----------- app/monitor_common.py | 12 +-- 3 files changed, 120 insertions(+), 57 deletions(-) diff --git a/app/cross_evaluate_worker.py b/app/cross_evaluate_worker.py index 62ec449..68a5aad 100644 --- a/app/cross_evaluate_worker.py +++ b/app/cross_evaluate_worker.py @@ -393,6 +393,7 @@ def query_cross_examine_records_detail(params): else: phase_type_dir_dict[int(item_type)].append(item_detail) days_records[date] = phase_type_dir_dict + days_records = days_records[-14:] res = make_common_res(0, 'ok') res['data'] = { 'days_records': days_records, diff --git a/app/eva_common.py b/app/eva_common.py index bfa9bb7..6c22946 100644 --- a/app/eva_common.py +++ b/app/eva_common.py @@ -81,7 +81,7 @@ def gen_avg_cross_delay_pb(cross_delay_data_list): for item in cross_delay_pb_list: # print(MessageToJson(item, indent=None, always_print_fields_with_no_presence=True)) item_delay_info = item.delay_info - item_car_num = item_delay_info.car_num + item_car_num = item_delay_info.turn_ratio_0 + item_delay_info.turn_ratio_1 if item_car_num != 0: sum_car_num += item_car_num delay_time += item_delay_info.delay_time * item_car_num @@ -131,18 +131,19 @@ def gen_avg_cross_delay_pb(cross_delay_data_list): ffs, capacity = road_delay_infos[0].delay_info.ffs, road_delay_infos[0].delay_info.capacity turn_ratio_0, turn_ratio_1, turn_ratio_2, turn_ratio_3 = 0, 0, 0, 0 for road_delay_info in road_delay_infos: - inroad_sum_car_num += road_delay_info.delay_info.car_num - inroad_delay_time += road_delay_info.delay_info.delay_time * road_delay_info.delay_info.car_num - inroad_stop_times += road_delay_info.delay_info.stop_times * road_delay_info.delay_info.car_num - inroad_queue_len += road_delay_info.delay_info.queue_len * road_delay_info.delay_info.car_num - inroad_speed += road_delay_info.delay_info.speed * road_delay_info.delay_info.car_num - inroad_jam_index += road_delay_info.delay_info.jam_index * road_delay_info.delay_info.car_num - inroad_park_time += road_delay_info.delay_info.park_time * road_delay_info.delay_info.car_num - inroad_high_park_percent += road_delay_info.delay_info.high_park_percent * road_delay_info.delay_info.car_num - inroad_truck_percent += road_delay_info.delay_info.truck_percent * road_delay_info.delay_info.car_num - inroad_park_percent += road_delay_info.delay_info.park_percent * road_delay_info.delay_info.car_num - inroad_move_speed += road_delay_info.delay_info.move_speed * road_delay_info.delay_info.car_num - inroad_travel_time += road_delay_info.delay_info.travel_time * road_delay_info.delay_info.car_num + inroad_sum_car_num += (road_delay_info.delay_info.turn_ratio_0 + road_delay_info.delay_info.turn_ratio_1) + inroad_car_num = road_delay_info.delay_info.turn_ratio_0 + road_delay_info.delay_info.turn_ratio_1 + inroad_delay_time += road_delay_info.delay_info.delay_time * inroad_car_num + inroad_stop_times += road_delay_info.delay_info.stop_times * inroad_car_num + inroad_queue_len += road_delay_info.delay_info.queue_len * inroad_car_num + inroad_speed += road_delay_info.delay_info.speed * inroad_car_num + inroad_jam_index += road_delay_info.delay_info.jam_index * inroad_car_num + inroad_park_time += road_delay_info.delay_info.park_time * inroad_car_num + inroad_high_park_percent += road_delay_info.delay_info.high_park_percent * inroad_car_num + inroad_truck_percent += road_delay_info.delay_info.truck_percent * inroad_car_num + inroad_park_percent += road_delay_info.delay_info.park_percent * inroad_car_num + inroad_move_speed += road_delay_info.delay_info.move_speed * inroad_car_num + inroad_travel_time += road_delay_info.delay_info.travel_time * inroad_car_num # inroad_imbalance_index += delay_info.imbalance_index * delay_info.car_num inroad_std_flow += road_delay_info.delay_info.std_flow turn_ratio_0 += road_delay_info.delay_info.turn_ratio_0 @@ -157,30 +158,30 @@ def gen_avg_cross_delay_pb(cross_delay_data_list): inroad_delay_info.delay_info.ffs = ffs inroad_delay_info.delay_info.capacity = capacity inroad_delay_info.delay_info.car_num = inroad_sum_car_num - inroad_delay_info.delay_info.delay_time = int(inroad_delay_time / inroad_sum_car_num) - inroad_delay_info.delay_info.stop_times = inroad_stop_times / inroad_sum_car_num + inroad_delay_info.delay_info.delay_time = int(inroad_delay_time / inroad_sum_car_num) if inroad_sum_car_num > 0 else 0 + inroad_delay_info.delay_info.stop_times = inroad_stop_times / inroad_sum_car_num if inroad_sum_car_num > 0 else 0 if inroad_delay_info.delay_info.stop_times > max_stop_times: max_stop_times = inroad_delay_info.delay_info.stop_times if inroad_delay_info.delay_info.stop_times < min_stop_times: min_stop_times = inroad_delay_info.delay_info.stop_times - inroad_delay_info.delay_info.queue_len = int(inroad_queue_len / inroad_sum_car_num) - inroad_delay_info.delay_info.speed = int(inroad_speed / inroad_sum_car_num) - inroad_delay_info.delay_info.jam_index = inroad_jam_index / inroad_sum_car_num - inroad_delay_info.delay_info.park_time = int(inroad_park_time / inroad_sum_car_num) - inroad_delay_info.delay_info.high_park_percent = int(inroad_high_park_percent / inroad_sum_car_num) - inroad_delay_info.delay_info.truck_percent = int(inroad_truck_percent / inroad_sum_car_num) - inroad_delay_info.delay_info.park_percent = int(inroad_park_percent / inroad_sum_car_num) - inroad_delay_info.delay_info.move_speed = int(inroad_move_speed / inroad_sum_car_num) - inroad_delay_info.delay_info.travel_time = int(inroad_travel_time / inroad_sum_car_num) + inroad_delay_info.delay_info.queue_len = int(inroad_queue_len / inroad_sum_car_num) if inroad_sum_car_num > 0 else 0 + inroad_delay_info.delay_info.speed = int(inroad_speed / inroad_sum_car_num) if inroad_sum_car_num > 0 else 0 + inroad_delay_info.delay_info.jam_index = inroad_jam_index / inroad_sum_car_num if inroad_sum_car_num > 0 else 0 + inroad_delay_info.delay_info.park_time = int(inroad_park_time / inroad_sum_car_num) if inroad_sum_car_num > 0 else 0 + inroad_delay_info.delay_info.high_park_percent = int(inroad_high_park_percent / inroad_sum_car_num) if inroad_sum_car_num > 0 else 0 + inroad_delay_info.delay_info.truck_percent = int(inroad_truck_percent / inroad_sum_car_num) if inroad_sum_car_num > 0 else 0 + inroad_delay_info.delay_info.park_percent = int(inroad_park_percent / inroad_sum_car_num) if inroad_sum_car_num > 0 else 0 + inroad_delay_info.delay_info.move_speed = int(inroad_move_speed / inroad_sum_car_num) if inroad_sum_car_num > 0 else 0 + inroad_delay_info.delay_info.travel_time = int(inroad_travel_time / inroad_sum_car_num) if inroad_sum_car_num > 0 else 0 # inroad_delay_info.delay_info.imbalance_index = inroad_imbalance_index / inroad_sum_car_num - inroad_delay_info.delay_info.std_flow = int(inroad_std_flow / len(road_delay_infos)) + inroad_delay_info.delay_info.std_flow = int(inroad_std_flow / len(road_delay_infos)) if len(road_delay_infos) > 0 else 0 inroad_delay_info.delay_info.turn_ratio_0 = turn_ratio_0 inroad_delay_info.delay_info.turn_ratio_1 = turn_ratio_1 inroad_delay_info.delay_info.turn_ratio_2 = turn_ratio_2 inroad_delay_info.delay_info.turn_ratio_3 = turn_ratio_3 inroad_delay_pb_list.append(inroad_delay_info) - avg_road_stop_times = sum(item.delay_info.stop_times for item in inroad_delay_pb_list) / len(inroad_delay_pb_list) if len(inroad_delay_pb_list) > 0 else 0 - cross_imbalance_index = round((round(max_stop_times, 2) - round(min_stop_times, 2)) / round(avg_road_stop_times, 2), 2) if round(avg_road_stop_times, 2) != 0 else 0 + avg_road_stop_times = sum(item.delay_info.stop_times for item in inroad_delay_pb_list) / len(inroad_delay_pb_list) if len(inroad_delay_pb_list) > 0 else 0 + cross_imbalance_index = (max_stop_times - min_stop_times) / avg_road_stop_times if avg_road_stop_times != 0 else 0 avg_cross_delay.delay_info.imbalance_index = cross_imbalance_index for flow_delay_info in flow_delay_list: @@ -734,11 +735,11 @@ def calc_tide_index(crossid, nodeid, date_list, roads_dir_dict, date_type=None): Fam = max(max_am_flow, subtend_road_am_flow) / min(max_am_flow, subtend_road_am_flow) Fpm = max(max_pm_flow, subtend_road_pm_flow) / min(max_pm_flow, subtend_road_pm_flow) if Fam >= 1.5 and Fpm >= 1.5 and max_pm_flow_road == subtend_road_pair[max_am_flow_road]: - tide_index = round(min(Fam, Fpm) / max(Fam, Fpm), 2) + tide_index = round(Fam * Fpm, 2) if min(Fam, Fpm) <= 0: tide_index = 0 if max_pm_flow_road == max_am_flow_road: - tide_index = round(Fam * Fpm, 2) + tide_index = round(min(Fam, Fpm) / max(Fam, Fpm), 2) tide_index_list.append(tide_index) return tide_index_list @@ -1041,7 +1042,7 @@ def gen_cross_problems(crossid, nodeid, area_id, time_range, start_hm, date_list operating_efficiency_problems = gen_operating_efficiency_problems(avg_cross_delay_info, roads_dir_dict, cross_phase, is_peak) balanced_control_problems = gen_balanced_control_problems(crossid, nodeid, date_list, avg_cross_delay_info, roads_dir_dict, inroad_static_info_dict, cross_phase) phase_problems = gen_phase_problems(nodeid, area_id, crossid, time_range, date_list, min(date_list), max(date_list), start_hm) - cross_channelized_problems = gen_cross_channelized_problems(avg_cross_delay_info, roads_dir_dict, inroad_static_info_dict, cross_ledger_info) + cross_channelized_problems = gen_cross_channelized_problems(avg_cross_delay_info, roads_dir_dict, inroad_static_info_dict, cross_ledger_info, time_range) problems = { 'operating_efficiency_problems': operating_efficiency_problems, 'balanced_control_problems': balanced_control_problems, @@ -1160,14 +1161,16 @@ def gen_high_stop_time_problems(avg_cross_delay_info, is_peak): if avg_cross_delay_info: if avg_cross_delay_info.delay_info.stop_times > max_stop_times and avg_cross_delay_info.delay_info.car_num >= 10: total_num = 1 - detail = [{ - 'child_detail': [ - { - 'desc': desc, - 'text': '车辆多次停车时长过长(' + str(round(avg_cross_delay_info.delay_info.stop_times, 2)) + '),整体运行效率不高', - } - ] - }] + detail = [[ + { + 'child_detail': [ + { + 'desc': desc, + 'text': '车辆多次停车时长过长(' + str(round(avg_cross_delay_info.delay_info.stop_times, 2)) + '),整体运行效率不高', + } + ] + } + ]] suggestion = [ { 'child_detail': [ @@ -1557,9 +1560,9 @@ def gen_err_phase_problems(max_date, crossid, min_date, time_range): # 路口渠化 -def gen_cross_channelized_problems(avg_cross_delay_info, roads_dir_dict, inroad_static_info_dict, cross_ledger_info): +def gen_cross_channelized_problems(avg_cross_delay_info, roads_dir_dict, inroad_static_info_dict, cross_ledger_info, time_range): road_delay_infos = avg_cross_delay_info.inroad_delay_infos - inroad_num_detail, inroad_num_suggestion, inroad_num_err_total_num = gen_inroad_num_problems(road_delay_infos, inroad_static_info_dict, roads_dir_dict) + inroad_num_detail, inroad_num_suggestion, inroad_num_err_total_num = gen_inroad_num_problems(road_delay_infos, inroad_static_info_dict, roads_dir_dict, time_range, avg_cross_delay_info.delay_info.car_num) inout_lane_num_gap_problems, inout_lane_num_gap_suggestions, inout_lane_num_gap_total_num = gen_in_out_lane_num_gap_problems(cross_ledger_info) cross_channelized_problems = { 'item': '路口渠化', @@ -1573,7 +1576,7 @@ def gen_cross_channelized_problems(avg_cross_delay_info, roads_dir_dict, inroad_ { 'item': '车道资源不匹配', 'detail': inroad_num_detail, - 'reason': '同一进口道,直行或左转的流量占比大于50%,且相对流量占比大于60%,且车道数量占比小于流量占比的一半(多方向放行车道每个方向各算0.5)', + 'reason': '路口的单位小时流量大于20, 同一进口道,针对直行、左转,如果该流向的流量占比大于20%,且该流向的车道数量占比小于流量占比的一半(多方向放行车道每个方向各算0.5)', 'suggestions': inroad_num_suggestion } ) @@ -1592,12 +1595,13 @@ def gen_cross_channelized_problems(avg_cross_delay_info, roads_dir_dict, inroad_ # 路口渠化-车道资源不匹配 -def gen_inroad_num_problems(road_delay_infos, inroad_static_info_dict, roads_dir_dict): +def gen_inroad_num_problems(road_delay_infos, inroad_static_info_dict, roads_dir_dict, time_range, car_num): detail = [] suggestions, err_src_dirs, total_num = [], {}, 0 road_src_dict = {v['in']: k for k, v in roads_dir_dict.items()} - max_flow_car_num = 0 - + # 20251204 调整计算逻辑,取消相对流量占比大于60% 更换为 路口 单位小时流量大于20 + hours = calculate_hours(time_range) + hour_car_num = car_num / hours for road_delay in road_delay_infos: inroadid = road_delay.inroadid src_dir = road_src_dict[inroadid] if inroadid in road_src_dict else None @@ -1605,9 +1609,6 @@ def gen_inroad_num_problems(road_delay_infos, inroad_static_info_dict, roads_dir continue lane_info = inroad_static_info_dict[inroadid]['lane_turn_info'] flow_delay_infos = road_delay.flow_delay_infos - max_car_num = max([item.delay_info.car_num for item in flow_delay_infos if item.turn_type in [0, 1]]) if flow_delay_infos else 0 - if max_car_num > max_flow_car_num: - max_flow_car_num = max_car_num road_car_num = road_delay.delay_info.car_num turn_delay_dict = {item.turn_type: item for item in flow_delay_infos} left_lane_num_half, straight_lane_num_half, right_lane_num_half = count_lsr_half(lane_info) @@ -1625,9 +1626,8 @@ def gen_inroad_num_problems(road_delay_infos, inroad_static_info_dict, roads_dir turn_type_str = '左转' lane_num_rate = left_lane_num_rate flow_car_num = turn_delay_dict[turn_type].delay_info.car_num - relative_rate = flow_car_num / max_flow_car_num flow_rate = flow_car_num / road_car_num - if flow_rate > 0.2 and relative_rate > 0.6 and lane_num_rate < 0.5: + if flow_rate > 0.2 and hour_car_num > 20 and lane_num_rate < 50: if src_dir in err_src_dirs.keys(): err_src_dirs[src_dir].append({ 'turn_type': turn_type_str, @@ -1657,7 +1657,7 @@ def gen_inroad_num_problems(road_delay_infos, inroad_static_info_dict, roads_dir src_detail['child_detail'].append( { 'turn_type': turn_type['turn_type'], - 'text': '分流转向比过大(' + str(int(round(turn_type['flow_rate'], 2) * 100)) + '%),但分配的转向车道占比不足(' + str(int(round(turn_type['lane_num_rate'], 2) * 100)) + '%),分配车道资源不匹配' + 'text': '分流转向比过大(' + str(int(round(turn_type['flow_rate'], 2) * 100)) + '%),但分配的转向车道占比不足(' + str(int(round(turn_type['lane_num_rate'], 2))) + '%),分配车道资源不匹配' } ) detail.append( @@ -1690,6 +1690,30 @@ def gen_inroad_num_problems(road_delay_infos, inroad_static_info_dict, roads_dir return detail, suggestions, total_num +def calculate_hours(time_range): + """ + 计算时间区间包含多少小时,返回浮点数 + + 参数: + time_range: 字符串,格式为"HH:MM-HH:MM",不跨天 + + 返回: + float: 小时数(浮点数) + """ + # 解析时间段 + start_str, end_str = time_range.split('-') + + # 将小时和分钟转换为整数 + start_h, start_m = map(int, start_str.split(':')) + end_h, end_m = map(int, end_str.split(':')) + + # 计算总分钟数并转换为小时 + start_minutes = start_h * 60 + start_m + end_minutes = end_h * 60 + end_m + + return (end_minutes - start_minutes) / 60.0 + + # 路口渠化-进出口道数不匹配 def gen_in_out_lane_num_gap_problems(cross_ledger_info): detail = [] @@ -1734,7 +1758,45 @@ def check_is_peak_tp(time_range, area_id, nodeid): peak_tp = ['07:00-09:00', '17:00-19:00'] if tp_desc and len(tp_desc) > 0: peak_tp = tp_desc[0]['peak_tp'].split(',') - return time_overlap(time_range, peak_tp) + for item_peak in peak_tp: + start_hm, end_hm = int(time_range.split('-')[0].split(':')[0]) * 100 + int(time_range.split('-')[0].split(':')[1]), int(time_range.split('-')[1].split(':')[0]) * 100 + int(time_range.split('-')[1].split(':')[1]) + res = check_peak_time_range(start_hm, end_hm, item_peak) + if res: + return True + return False + + +def check_peak_time_range(startHm, endHm, peak_time_range): + # 将 startHm 和 endHm 转换为小时和分钟 + start_hour = startHm // 100 + start_minute = startHm % 100 + end_hour = endHm // 100 + end_minute = endHm % 100 + + # 解析 time_range + start_time_range, end_time_range = peak_time_range.split('-') + start_hr, start_min = map(int, start_time_range.split(':')) + end_hr, end_min = map(int, end_time_range.split(':')) + + # 将所有时间转换为分钟(自午夜以来的总分钟数) + def to_minutes(hour, minute): + return hour * 60 + minute + + # 转换所有时间点 + start = to_minutes(start_hour, start_minute) + end = to_minutes(end_hour, end_minute) + range_start = to_minutes(start_hr, start_min) + range_end = to_minutes(end_hr, end_min) + + # 计算重叠部分 + overlap_start = max(start, range_start) + overlap_end = min(end, range_end) + + if overlap_start < overlap_end: + overlap_duration = overlap_end - overlap_start + return overlap_duration * 2 >= (end - start) # 重叠时长大于等于60分钟返回True + else: + return False def get_flow_phase_detail(src_dir, turn_type_list, cross_phase): diff --git a/app/monitor_common.py b/app/monitor_common.py index bd61945..5f51262 100644 --- a/app/monitor_common.py +++ b/app/monitor_common.py @@ -139,7 +139,7 @@ def gen_monitor_overview_data(cross_report_pb, date_type, routing_crosses, speci for cross_delay_info in cross_delay_info_list: if special_time_range != '' and not is_overlap_greater_than_one_hour(cross_delay_info.tp.start_hm, cross_delay_info.tp.end_hm, special_time_range): continue - service_level = calc_service_level(cross_delay_info.delay_info.delay_time, stop_times) + service_level = calc_service_level(cross_delay_info.delay_info.delay_time, cross_delay_info.delay_info.stop_times) if service_level != '-': overview['cross_service_levels']['total'] += 1 if service_level in ('A', 'B'): @@ -1081,7 +1081,7 @@ def turn_imbalance_problems(turn_imbalance_crosses, routing_crosses, special_tim 'time_range': time_range, 'weekdays_str': weekdays_str, 'weekdays': weekdays, - 'imbalance_index': '、'.join(inroad_imbalance_index_list), + 'imbalance_index': '、'.join(list(set(inroad_imbalance_index_list))), 'detail': detail, 'is_new': is_new, 'cont_times': cont_times, @@ -1793,15 +1793,15 @@ def gen_cross_problem_detail(routing_crosses, high_park_problems, too_many_stop_ item_desc = '【' + item['weekdays_str'] + '】' + item['plan_info'] cross_insufficient_ped_time_list.append(item_desc) insufficient_ped_time = cross_insufficient_ped_time_list - if crossid in inroad_turnlane_mismatch.keys(): - inroad_turnlane_problems = inroad_turnlane_mismatch[crossid] + if crossid in inroad_turnlane_mismatch['problems'].keys(): + inroad_turnlane_problems = inroad_turnlane_mismatch['problems'][crossid] inroad_turnlane_mismatch_list = [] for item in inroad_turnlane_problems: inroad_turnlane = '【' + item['weekdays_str'] + ' ' + item['time_range'] + '】' + item['src_info'] inroad_turnlane_mismatch_list.append(inroad_turnlane) inroad_turnlane = inroad_turnlane_mismatch_list - if crossid in unmatch_lane_num_problem.keys(): - cross_unmatch_problem = unmatch_lane_num_problem[crossid] + if crossid in unmatch_lane_num_problem['problems'].keys(): + cross_unmatch_problem = unmatch_lane_num_problem['problems'][crossid] unmatched_lane_num = [cross_unmatch_problem[0]['src_dir']] cross_problem_detail.append({ 'crossid': crossid,