You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

赛车圈数计算误计数问题: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)

问题分析

  1. 参数与全局变量冲突:函数定义接收df参数,但内部全程使用全局变量result,导致传入的DataFrame无效;同时覆盖了传入的starting_y和tolerance_y参数,参数设置完全失效。
  2. 圈数判断逻辑过于简单:仅通过Y坐标穿越起点线判断,未结合赛道完整绕行的逻辑,赛车在起点线附近的小范围抖动(比如来回穿越Y线)会被多次计数。
  3. 方向处理缺失:没有区分顺时针/逆时针方向,无法判断赛车是否完成完整的赛道绕行,仅靠Y线穿越会把往返移动误判为圈数。
  4. 冗余变量初始化:函数内部重复初始化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)

代码说明

  1. 极坐标角度累计:通过计算赛车相对于赛道中心的极角变化,累计角度绝对值超过2π(约6.28弧度)时,说明完成了一圈绕行(顺时针为负,逆时针为正)。
  2. 起点区域验证:只有当赛车离开起点区域后,再次回到起点附近,且累计角度满足一圈的条件,才会计数,避免了起点附近抖动的误判。
  3. 方向自适应:无需提前指定方向,通过角度累计的正负自动适配顺时针/逆时针的情况。

内容的提问来源于stack exchange,提问作者Researcher_m

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 22:49:54