赛车圈数计算误计数问题:Python逻辑或数据异常排查请求
赛车圈数统计误计数问题排查与解决
背景与问题
需要统计赛车完成赛道的圈数,规则为赛车穿过参考线后回到起点即计为一圈。现有CSV坐标数据,场景尺寸为height=0.33、width=0.342,以CSV首行数据作为起点。游戏不同关卡赛车行驶方向不同(第一关逆时针,后续顺时针)。
当前编写的Python函数返回圈数为19,但实际正确圈数应为11,存在严重误计数,需排查问题并修正。
原代码
def count_laps(df, width, height, starting_y, tolerance_y=0.01): """ Count the number of laps completed by a car based on its coordinates, without assuming a specific direction. Args: df (DataFrame): DataFrame containing the car's coordinates with columns 'XCoordinate' and 'YCoordinate'. width (float): Width of the track. height (float): Height of the track. starting_x (float): X-coordinate of the starting point. tolerance_y (float): Tolerance value for starting point's Y-coordinate. Default is 0.01. Returns: int: Number of laps completed by the car. """ center_x = width / 2 center_y = height / 2 lap_count = 0 crossed_ref = False prev_y = None starting_x = result.iloc[0]['XCoordinate'] starting_y = result.iloc[0]['YCoordinate'] # Starting y-coordinate of the horizontal line tolerance_y = 0.001 # Tolerance for determining if a point is near the starting point prev_y = result.iloc[0]['YCoordinate'] # Initialize previous y-coordinate to None crossed_ref = False # Initialize crossed_ref to False lap_count = 0 # Initialize lap count to 0 for i in range(len(result)): x = result.iloc[i]['XCoordinate'] y = result.iloc[i]['YCoordinate'] # Check if the car has crossed the horizontal line and completed a lap if not crossed_ref and prev_y is not None and ((y <= (starting_y + tolerance_y) and y > starting_y and prev_y <= starting_y) or (y >= (starting_y - tolerance_y) and y < starting_y and prev_y >= starting_y)): crossed_ref = True # Check if the car has crossed the reference position and is near the starting point if crossed_ref and prev_y is not None and ((y > (starting_y - tolerance_y) and prev_y <= starting_y and y > starting_y) or (y < (starting_y + tolerance_y) and prev_y >= starting_y and y < starting_y)): crossed_ref = False lap_count += 1 #print("Point crossed the reference position and is near the starting point:") print("x:", x, "y:", y) points.append((x,y)) prev_y = y return lap_count points=[] #starting_x = 0.1912601 #starting_y = 0.0777104 starting_y = result['YCoordinate'].iloc[0] #result is the data from csv file width = 0.342 height = 0.33 lap_count = count_laps(result, width, height, starting_y, tolerance_y=0.01) print("Lap Count: ", lap_count)
问题分析
- 参数与全局变量冲突:函数定义接收
df参数,但内部全程使用全局变量result,导致传入的DataFrame无效;同时覆盖了传入的starting_y和tolerance_y参数,参数设置完全失效。 - 圈数判断逻辑过于简单:仅通过Y坐标穿越起点线判断,未结合赛道完整绕行的逻辑,赛车在起点线附近的小范围抖动(比如来回穿越Y线)会被多次计数。
- 方向处理缺失:没有区分顺时针/逆时针方向,无法判断赛车是否完成完整的赛道绕行,仅靠Y线穿越会把往返移动误判为圈数。
- 冗余变量初始化:函数内部重复初始化
lap_count、crossed_ref等变量,虽然不影响运行,但会导致逻辑混乱。
解决方案
核心修正思路
- 抛弃仅靠Y线穿越的判断逻辑,改为极坐标角度累计+起点区域验证的方式,确保只有完成完整圆周绕行(顺时针/逆时针均可)且回到起点才计数。
- 修复变量与参数的冲突问题,函数内部仅使用传入的参数。
- 增加起点区域的进出判断,避免坐标抖动导致的误计数。
修正后的代码
import pandas as pd import math def count_laps(df, width, height, tolerance=0.01): # 获取起点坐标 start_x = df.iloc[0]['XCoordinate'] start_y = df.iloc[0]['YCoordinate'] center_x = width / 2 center_y = height / 2 lap_count = 0 prev_angle = None total_angle = 0.0 # 标记当前是否处于起点附近区域 near_start = True for idx, row in df.iterrows(): x = row['XCoordinate'] y = row['YCoordinate'] # 计算当前点相对于赛道中心的极角(弧度) dx = x - center_x dy = y - center_y current_angle = math.atan2(dy, dx) if prev_angle is not None: # 计算角度差,处理跨-π/π的边界情况(比如从π到-π的跳转) angle_diff = current_angle - prev_angle if angle_diff > math.pi: angle_diff -= 2 * math.pi elif angle_diff < -math.pi: angle_diff += 2 * math.pi total_angle += angle_diff # 判断当前是否回到起点附近区域 current_near_start = abs(x - start_x) < tolerance and abs(y - start_y) < tolerance # 只有当离开起点区域后,累计角度完成一圈(绝对值≥2π)且回到起点,才计为一圈 if not near_start and current_near_start: if abs(total_angle) >= 2 * math.pi - 0.1: # 预留少量误差容忍 lap_count += 1 total_angle = 0.0 # 重置角度累计,准备下一圈计数 near_start = current_near_start prev_angle = current_angle return lap_count # 使用示例 # 替换为你的CSV文件路径 result = pd.read_csv("car_coordinates.csv") width = 0.342 height = 0.33 lap_count = count_laps(result, width, height) print("Lap Count: ", lap_count)
代码说明
- 极坐标角度累计:通过计算赛车相对于赛道中心的极角变化,累计角度绝对值超过2π(约6.28弧度)时,说明完成了一圈绕行(顺时针为负,逆时针为正)。
- 起点区域验证:只有当赛车离开起点区域后,再次回到起点附近,且累计角度满足一圈的条件,才会计数,避免了起点附近抖动的误判。
- 方向自适应:无需提前指定方向,通过角度累计的正负自动适配顺时针/逆时针的情况。
内容的提问来源于stack exchange,提问作者Researcher_m
相关产品推荐
相关产品推荐

