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

船舶未来位置预测遇螺旋异常:高转向速度下的问题排查

船舶位置预测异常:高转向速度下出现螺旋轨迹

我尝试预测船舶在指定时长后的位置,原本以为功能已实现,但当转向速度较高时,预测轨迹出现类似3D螺旋投影至2D平面的异常效果,看起来像是在错误的轴上形成了圆形。我已用HTML Canvas复现了问题代码。

问题复现代码

const canvas = document.createElement("canvas");
document.body.appendChild(canvas);
const ctx = canvas.getContext("2d");

// 基于当前速度计算船舶未来位置
const projectedPosition = (ship, dlta) => {
    const pos = {...ship.position};
    
    // 按秒分步调整位置和角度
    for (let i=0; i < dlta; i++) {
        // 缓存当前位置
        const [cx, cy] = [pos.x, pos.y];

        // 添加线速度到位置
        pos.x += ((ship.linearVelocity.x) / 100); 
        pos.y += ((ship.linearVelocity.y) / 100);
        
        // 绕当前位置旋转未来方向
        const r = (ship.heading + ship.angularVelocity.z * i) * -Math.PI / 180;
        const [cos, sin] = [Math.cos(r), Math.sin(r)];
        pos.x = cx + (cos * (pos.x - cx)) + (sin * (pos.y - cy));
        pos.y = cy + (cos * (pos.y - cy)) - (sin * (pos.x - cx));
    }

    return pos;
}

const draw = () => {
    canvas.width = 1000;
    canvas.height = 1000;

    const ship = {
        position: {x: 500, y: 100}, // 画布中心位置
        angularVelocity: {z: -8.4}, // 转向速度,单位:度/秒
        heading: 35, // 当前船头朝向角度,单位:度
        linearVelocity: {x: 4  * 100, y: -6  * 100} // 线速度,米/秒,×100适配画布比例
    };
            
    // 绘制当前位置红点
    ctx.fillStyle = "red";
    ctx.arc(ship.position.x, ship.position.y, 8, 0, 2 * Math.PI);
    ctx.fill();
            
    // 绘制未来位置绿点
    ctx.fillStyle = "green";
    for (let i=1; i < 50; i++) {
        const dlta = i * 4; // 每次间隔4秒
        const proj_position = projectedPosition(ship, dlta); 
        
        ctx.beginPath()
        ctx.arc(proj_position.x, proj_position.y, 8, 0, 2 * Math.PI);
        ctx.fill();
    }
};

draw();

错误原因分析

1. 2D旋转公式符号错误

你使用的绕点旋转公式存在逻辑错误,标准2D绕点(cx, cy)旋转的正确公式应为:

pos.x = cx + cos*(pos.x - cx) - sin*(pos.y - cy);
pos.y = cy + sin*(pos.x - cx) + cos*(pos.y - cy);

你的代码中颠倒了sin项的符号,导致每一步旋转都偏离正确方向,累积后形成螺旋扭曲效果。

2. 运动顺序与航向更新逻辑错误

代码先基于初始航向移动,再旋转位置,不符合船舶实际运动逻辑:船舶的线速度是相对于船头方向的,正确流程应为:先根据当前航向将船头方向的速度转换为世界坐标系下的移动量,再更新位置;同时每一步都要累积角速度,更新下一秒的船头航向。

修正后的代码

const canvas = document.createElement("canvas");
document.body.appendChild(canvas);
const ctx = canvas.getContext("2d");

const projectedPosition = (ship, dlta) => {
    const pos = {...ship.position};
    let currentHeading = ship.heading; // 实时跟踪当前船头航向

    for (let i=0; i < dlta; i++) {
        // 将航向转换为弧度(负号适配Canvas坐标系y轴向下的特性)
        const rad = currentHeading * -Math.PI / 180;
        const cos = Math.cos(rad);
        const sin = Math.sin(rad);

        // 将船头方向的线速度转换为世界坐标系下的移动分量
        const moveX = (ship.linearVelocity.x / 100) * cos - (ship.linearVelocity.y / 100) * sin;
        const moveY = (ship.linearVelocity.x / 100) * sin + (ship.linearVelocity.y / 100) * cos;

        // 更新位置
        pos.x += moveX;
        pos.y += moveY;

        // 更新下一秒的船头航向
        currentHeading += ship.angularVelocity.z;
    }

    return pos;
}

const draw = () => {
    canvas.width = 1000;
    canvas.height = 1000;

    const ship = {
        position: {x: 500, y: 100},
        angularVelocity: {z: -8.4},
        heading: 35,
        linearVelocity: {x: 4  * 100, y: -6  * 100}
    };
            
    ctx.fillStyle = "red";
    ctx.arc(ship.position.x, ship.position.y, 8, 0, 2 * Math.PI);
    ctx.fill();
            
    ctx.fillStyle = "green";
    for (let i=1; i < 50; i++) {
        const dlta = i * 4;
        const proj_position = projectedPosition(ship, dlta); 
        
        ctx.beginPath()
        ctx.arc(proj_position.x, proj_position.y, 8, 0, 2 * Math.PI);
        ctx.fill();
    }
};

draw();

修正说明

  • 实时跟踪船头航向,每一步都基于当前航向计算世界坐标系下的移动量,符合船舶运动实际逻辑。
  • 使用标准2D旋转公式转换速度方向,避免位置扭曲。
  • 先计算移动分量,再更新位置和航向,保证每一秒的运动状态正确累积。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 10:34:57