第二节:相对运动学基础——坐标系与运动方程

各位同学好,我是老张。今天咱们聊聊相对运动学里最基础、也最容易搞混的部分——坐标系定义和运动方程推导。

说实话,我见过不少新手工程师,一上来就急着写代码、调参数,结果仿真跑出来弹道乱飞,最后发现是坐标系搞错了。嗯,这种坑我自己也踩过。所以这节课,咱们把坐标系这件事彻底讲清楚。

2.1 三大坐标系:你总得知道自己在哪

做制导控制,说白了就是回答三个问题:我在哪?目标在哪?我怎么过去?这三个问题分别对应三个坐标系。

2.1.1 惯性坐标系(Inertial Frame)

惯性系,我习惯叫它“上帝视角”。它固定不动,不随飞行器旋转或移动。通常我们取地面某点为原点,比如发射点。

  • 定义:原点O固定在地面(或某惯性空间),X轴指向正北或发射方向,Y轴垂直向上,Z轴按右手定则确定。
  • 特点:牛顿定律在这里成立。说白了,所有动力学方程都得在惯性系里写。
  • 我的经验:做半实物仿真时,惯性系的原点我一般选在发射架底部。这样后续算重力势能、初始位置都方便。
重要提醒:惯性系不是随便选的。一旦选定,整个仿真过程中不能变。我见过有人中途换原点,结果弹道数据全乱了。

2.1.2 弹体坐标系(Body Frame)

弹体坐标系,顾名思义,是“长在导弹身上的”。它跟着导弹一起动、一起转。

  • 定义:原点Ob在导弹质心,Xb轴沿弹体纵轴指向头部,Yb轴在纵向对称面内垂直Xb轴向上,Zb轴按右手定则指向右侧。
  • 用途:描述导弹的姿态(俯仰、偏航、滚转),以及气动力、推力在弹体上的作用方向。
  • 避坑指南:我曾经犯过一个低级错误——把弹体坐标系的原点放在了弹头。结果算力矩时,质心位置总是不对。后来才意识到,原点必须取在质心。

2.1.3 视线坐标系(Line-of-Sight Frame)

视线坐标系,是连接导弹和目标的那条“看不见的线”。比例导引法里,这个坐标系是核心。

  • 定义:原点Os在导弹质心,Xs轴沿视线方向指向目标,Ys轴在包含视线的垂直平面内垂直于Xs轴向上,Zs轴按右手定则确定。
  • 特点:这个坐标系一直在旋转。随着导弹和目标相对运动,视线方向不断变化。
  • 为什么重要:比例导引法的核心——控制导弹的加速度垂直于视线方向——就是在这个坐标系里定义的。
小技巧:我个人习惯把视线坐标系叫做“导引坐标系”。因为所有导引律的计算,最后都要回到这个坐标系里。你想想看,如果连视线角速率都算不准,那还导引什么?

2.2 坐标系之间的转换:数学才是硬道理

三个坐标系之间怎么转?说白了就是旋转矩阵。我建议你记住一个原则:从A系到B系,先转哪个角,后转哪个角,顺序不能乱

2.2.1 惯性系 → 弹体系

这个转换通常用三个欧拉角:俯仰角θ、偏航角ψ、滚转角φ。转换顺序我习惯用3-2-1(先偏航、再俯仰、最后滚转)。

# 惯性系到弹体系的旋转矩阵(3-2-1顺序)
import numpy as np

def inertial_to_body(theta, psi, phi):
    """
    theta: 俯仰角 (rad)
    psi:   偏航角 (rad)
    phi:   滚转角 (rad)
    """
    cθ, sθ = np.cos(theta), np.sin(theta)
    cψ, sψ = np.cos(psi), np.sin(psi)
    cφ, sφ = np.cos(phi), np.sin(phi)
    
    # 绕Z轴转偏航角
    Rz = np.array([[cψ, sψ, 0],
                   [-sψ, cψ, 0],
                   [0, 0, 1]])
    # 绕Y轴转俯仰角
    Ry = np.array([[cθ, 0, -sθ],
                   [0, 1, 0],
                   [sθ, 0, cθ]])
    # 绕X轴转滚转角
    Rx = np.array([[1, 0, 0],
                   [0, cφ, sφ],
                   [0, -sφ, cφ]])
    
    return Rx @ Ry @ Rz
注意:不同教材可能用不同的旋转顺序。我建议你固定用一种,别换来换去。我自己一直用3-2-1,十几年没出过问题。

2.2.2 惯性系 → 视线系

这个转换只需要两个角:视线高低角λD和视线方位角λT。为什么只有两个?因为视线坐标系不关心滚转。

def inertial_to_los(lambda_D, lambda_T):
    """
    lambda_D: 视线高低角 (rad)
    lambda_T: 视线方位角 (rad)
    """
    cD, sD = np.cos(lambda_D), np.sin(lambda_D)
    cT, sT = np.cos(lambda_T), np.sin(lambda_T)
    
    # 先绕Z轴转方位角,再绕Y轴转高低角
    Rz = np.array([[cT, sT, 0],
                   [-sT, cT, 0],
                   [0, 0, 1]])
    Ry = np.array([[cD, 0, -sD],
                   [0, 1, 0],
                   [sD, 0, cD]])
    
    return Ry @ Rz

2.3 相对运动方程:核心推导

好,现在咱们进入正题。相对运动方程,说白了就是描述导弹和目标之间位置、速度、加速度关系的微分方程。

2.3.1 基本假设

推导之前,先明确几个假设。这些假设在工程上基本都成立:

  1. 导弹和目标视为质点(不考虑外形)
  2. 地球为平面(短程制导足够用)
  3. 重力加速度恒定(9.81 m/s²)
  4. 大气静止(不考虑风)
我的看法:这些假设在大多数战术导弹的末制导段是合理的。但如果你做远程弹道导弹,那地球曲率和自转就不能忽略了。

2.3.2 相对位置矢量

定义相对位置矢量 r = rt - rm,其中rt是目标位置,rm是导弹位置。

在惯性系中,这个矢量很简单。但我们要的是它在视线系中的表达。为什么?因为比例导引法需要视线角速率。

2.3.3 视线角速率的计算

这是整个推导的关键。视线角速率 ωs 等于相对速度矢量叉乘相对位置矢量,再除以距离的平方。

def compute_los_rate(r, v):
    """
    r: 相对位置矢量 (3x1)
    v: 相对速度矢量 (3x1)
    返回: 视线角速率矢量 (3x1)
    """
    R = np.linalg.norm(r)  # 相对距离
    omega = np.cross(r, v) / (R**2)
    return omega

嗯,这里要注意:ωs 的三个分量分别对应视线坐标系三个轴的旋转角速率。但在比例导引法中,我们只关心垂直于视线方向的两个分量——它们决定了导弹需要产生的横向加速度。

2.3.4 完整的相对运动方程

把上面这些整合起来,得到一组微分方程:

def relative_motion_equations(t, state, a_m, a_t):
    """
    state: [r_x, r_y, r_z, v_x, v_y, v_z] 在惯性系中
    a_m: 导弹加速度 (3x1)
    a_t: 目标加速度 (3x1)
    返回: 状态导数
    """
    r = state[0:3]
    v = state[3:6]
    
    # 相对加速度
    a_rel = a_t - a_m
    
    # 状态导数
    drdt = v
    dvdt = a_rel
    
    return np.concatenate([drdt, dvdt])
实用建议:实际仿真时,我一般把导弹和目标各自的动力学方程分开写,然后在每一步计算相对运动。这样代码更清晰,也方便调试。

2.4 知识体系总览

说了这么多,咱们用一张图把整个知识结构串起来。这张图是我自己画的,你一看就明白。

相对运动学知识体系 惯性坐标系 弹体坐标系 视线坐标系 欧拉角 视线角 相对运动方程推导 相对位置矢量 相对速度矢量 视线角速率 比例导引法:加速度指令计算 图:从坐标系定义到比例导引法的完整知识链路

这张图把咱们这节课的内容串起来了。你从最上面的三个坐标系出发,经过相对运动方程推导,得到三个关键输出,最后落到比例导引法的加速度指令计算。每一步都环环相扣。

核心要点:坐标系是基础,转换是工具,运动方程是核心。这三样东西搞明白了,比例导引法你就掌握了七成。

好了,这节课就到这里。坐标系定义和相对运动方程推导,是后续所有内容的基础。我建议你动手写写代码,把惯性系到视线系的转换矩阵自己实现一遍。纸上得来终觉浅,绝知此事要躬行。


公众号:蓝海资料掘金营,微信deep3321