2. 建立火箭动力学模型

任务说明

本案例实现一个二维平面内的火箭动力学模型,包含推力、重力和空气动力(升力与阻力)的作用。模型输出火箭在惯性坐标系下的加速度分量,并基于给定时间步长更新位置与速度状态。该模型可作为后续制导算法仿真的被控对象。

坐标系与受力定义

采用地面惯性坐标系(x水平向右,y竖直向上)。火箭状态由位置 (x, y)、速度 (vx, vy)、质量 m 和俯仰角 θ(速度方向与水平面的夹角)描述。受力包括:

  • 推力 T:沿火箭纵轴方向,与速度方向夹角为攻角 α,因此推力方向角为 θ+α;
  • 重力:竖直向下,大小为 mg;
  • 空气动力:分解为阻力 D(与速度反向)和升力 L(垂直于速度方向,向上为正)。

加速度由牛顿第二定律计算,状态更新采用一阶欧拉积分。

代码实现

import numpy as np

class Rocket2D:
    """二维火箭动力学模型(推力、重力、空气动力)"""
    def __init__(self, x0=0.0, y0=0.0, vx0=0.0, vy0=0.0,
                 m0=500.0, g=9.81, rho=1.225, S=0.25,
                 Cd=0.3, Cl_alpha=2.0):
        self.x = x0
        self.y = y0
        self.vx = vx0
        self.vy = vy0
        self.m = m0
        self.g = g          # 重力加速度
        self.rho = rho      # 空气密度
        self.S = S          # 参考面积
        self.Cd = Cd        # 阻力系数
        self.Cl_alpha = Cl_alpha  # 升力线斜率

    def speed(self):
        return np.hypot(self.vx, self.vy)

    def flight_path_angle(self):
        """速度方向角(与水平面夹角)"""
        return np.arctan2(self.vy, self.vx)

    def aerodynamic_forces(self):
        """计算阻力D和升力L(N)"""
        v = self.speed()
        q = 0.5 * self.rho * v**2   # 动压
        D = q * self.S * self.Cd
        # 升力系数与攻角成正比(小攻角假设)
        alpha = 0.0  # 由外部传入,此处仅返回函数
        return D, q * self.S * self.Cl_alpha * alpha

    def derivatives(self, T, alpha):
        """计算加速度分量 ax, ay 及质量变化率 dmdt"""
        v = self.speed()
        theta = self.flight_path_angle()
        # 空气动力
        D = 0.5 * self.rho * v**2 * self.S * self.Cd
        L = 0.5 * self.rho * v**2 * self.S * self.Cl_alpha * alpha
        # 推力分量
        thrust_angle = theta + alpha
        Tx = T * np.cos(thrust_angle)
        Ty = T * np.sin(thrust_angle)
        # 阻力方向(与速度反向)
        if v > 1e-6:
            Dx = -D * self.vx / v
            Dy = -D * self.vy / v
        else:
            Dx = Dy = 0.0
        # 升力方向(垂直于速度,逆时针旋转90度)
        if v > 1e-6:
            Lx = -L * self.vy / v
            Ly = L * self.vx / v
        else:
            Lx = Ly = 0.0
        # 合力
        Fx = Tx + Dx + Lx
        Fy = Ty + Dy + Ly - self.m * self.g
        ax = Fx / self.m
        ay = Fy / self.m
        # 质量变化率(假设质量流率恒定,由外部给定)
        dmdt = 0.0  # 默认无质量变化
        return ax, ay, dmdt

    def step(self, T, alpha, dt, mdot=0.0):
        """使用欧拉法更新状态"""
        ax, ay, dmdt = self.derivatives(T, alpha)
        # 更新速度
        self.vx += ax * dt
        self.vy += ay * dt
        # 更新位置
        self.x += self.vx * dt
        self.y += self.vy * dt
        # 更新质量
        self.m += mdot * dt
        if self.m < 0:
            self.m = 0.0
        return self.x, self.y, self.vx, self.vy, self.m

# 示例:初始化火箭并执行一步仿真
if __name__ == "__main__":
    # 初始状态:位于原点,静止,质量500kg
    rocket = Rocket2D(x0=0.0, y0=0.0, vx0=0.0, vy0=0.0, m0=500.0)
    # 推力10000N,攻角0度,时间步长0.1s
    T = 10000.0
    alpha = 0.0
    dt = 0.1
    # 执行一步
    x, y, vx, vy, m = rocket.step(T, alpha, dt)
    print(f"位置: ({x:.3f}, {y:.3f}) m")
    print(f"速度: ({vx:.3f}, {vy:.3f}) m/s")
    print(f"质量: {m:.1f} kg")

关键说明

代码中 aerodynamic_forces 方法仅用于展示升力系数与攻角的关系,实际计算在 derivatives 中完成。攻角 α 由外部制导律给出,本模型不包含攻角动力学。质量变化率通过 mdot 参数传入 step 方法,默认无质量消耗。

验证方法

运行上述示例,预期输出为:

位置: (0.000, 0.000) m
速度: (2.000, 0.000) m/s
质量: 500.0 kg

验证逻辑:初始静止,推力水平(α=0),无空气动力(v=0),因此水平加速度 a_x = T/m = 10000/500 = 20 m/s²,经过 0.1s 后 vx = 2.0 m/s,位移 = 0.5×20×0.01 = 0.1m,但欧拉法使用更新前速度计算位移,故 x = 0 + 0×0.1 = 0。竖直方向仅受重力,vy 初始为 0,ay = -g,因此 vy = -0.981 m/s,但示例输出显示 vy=0,这是因为代码中 step 先更新速度再更新位置,且示例中 vy0=0,经过一步后 vy = -0.981 m/s,与预期不符。修正示例验证:

# 正确验证代码
rocket = Rocket2D(x0=0.0, y0=0.0, vx0=0.0, vy0=0.0, m0=500.0)
T = 10000.0
alpha = 0.0
dt = 0.1
x, y, vx, vy, m = rocket.step(T, alpha, dt)
print(f"vx = {vx:.3f} m/s (预期 2.000)")
print(f"vy = {vy:.3f} m/s (预期 -0.981)")
print(f"x = {x:.3f} m (预期 0.000)")
print(f"y = {y:.3f} m (预期 -0.049)")

判定标准:vx 接近 2.0 m/s,vy 接近 -0.981 m/s,x 保持 0,y 约为 -0.049 m(因欧拉法使用旧速度计算位移,y 位移 = vy0×dt = 0,但 vy 更新后为 -0.981,实际 y 更新使用更新后的 vy,因此 y = -0.981×0.1 = -0.0981 m。修正预期:y = -0.098 m)。

火箭受力与状态更新示意图 x y 火箭 V (速度) T (推力) mg (重力) D (阻力) L α 状态更新 (欧拉法) vx += ax·dt vy += ay·dt x += vx·dt y += vy·dt m += mdot·dt ax = (Tx+Dx+Lx)/m ay = (Ty+Dy+Ly-mg)/m

运行与验证

将代码保存为 rocket_dynamics.py,在 Python 3.8+ 环境中运行(需安装 NumPy)。执行 python rocket_dynamics.py 后,观察输出是否符合上述预期值。若 vx 与 vy 的计算结果与手算一致(误差小于 0.001),则模型实现正确。可通过修改初始速度、推力或攻角,进一步验证空气动力项是否按预期方向作用。