火箭6自由度弹道计算与飞行仿真系统

一、完整算法流程

1. 坐标系定义

  • 地心惯性坐标系(ECI):原点在地心,X轴指向春分点
  • 发射坐标系:原点在发射点,X轴指向射向,Y轴垂直向上
  • 体坐标系:原点在火箭质心,X轴沿纵轴向前
  • 速度坐标系:基于速度方向定义

2. 状态变量定义

状态向量包含18个变量:

ini 复制代码
X = [x, y, z,              # 位置(ECI) [m]
     vx, vy, vz,           # 速度(ECI) [m/s]
     q0, q1, q2, q3,       # 姿态四元数
     ωx, ωy, ωz,           # 角速度(体坐标系) [rad/s]
     m]                    # 质量 [kg]

3. 主计算流程

ini 复制代码
初始化:
  - 读取火箭参数
  - 设置初始状态
  - 定义控制程序(如俯仰程序)

主循环(t=0 到 t_max):
  1. 环境参数计算
     - 计算高度、经纬度
     - 调用大气模型(温度、压强、密度)
     - 计算重力(考虑J2项)
     - 计算科氏加速度
  
  2. 气动参数计算
     - 计算马赫数、雷诺数
     - 基于攻角、侧滑角、马赫数查表获取:
       * 阻力系数 Cx
       * 升力系数 Cy, Cz
       * 力矩系数 Cl, Cm, Cn
     - 计算动压:q = 0.5 * ρ * V²
     - 计算气动力/力矩
  
  3. 推进系统计算
     - 计算燃料质量流量:ṁ = F_vac / (Isp * g0)
     - 计算推力(随高度变化):
       F = F_vac - p * A_e
     - 计算推力偏心矩
  
  4. 力与力矩合成
     - 总力:F_total = F_thrust + F_aero + F_gravity
     - 总力矩:M_total = M_thrust + M_aero
  
  5. 运动方程求解
     a. 平动方程:
         d²r/dt² = F_total/m + ω_earth × (ω_earth × r) + 2ω_earth × v
     
     b. 转动方程:
         I * dω/dt + ω × (I * ω) = M_total
         dq/dt = 0.5 * Ω * q
     
     c. 质量方程:
         dm/dt = -ṁ
  
  6. 数值积分
     使用四阶龙格-库塔法:
         k1 = f(t, X)
         k2 = f(t + h/2, X + h*k1/2)
         k3 = f(t + h/2, X + h*k2/2)
         k4 = f(t + h, X + h*k3)
         X_{n+1} = X_n + (h/6)*(k1 + 2k2 + 2k3 + k4)
  
  7. 坐标系转换
     - 计算欧拉角(俯仰、偏航、滚转)
     - 体坐标系 ↔ 惯性坐标系转换
  
  8. 终止条件检查
     - 燃料耗尽
     - 高度 < 0(落地)
     - 程序时间结束
  
  9. 记录与输出

4. 主要数学模型

4.1 平动方程

ini 复制代码
m * dv/dt = ΣF - m * (ω_earth × (ω_earth × r) + 2ω_earth × v)

4.2 转动方程

css 复制代码
I * dω/dt = ΣM - ω × (I * ω)

4.3 四元数微分方程

css 复制代码
dq/dt = 0.5 * [ 0  -ωx -ωy -ωz               ωx   0   ωz -ωy               ωy -ωz   0   ωx               ωz  ωy -ωx   0 ] * q

4.4 质量变化

scss 复制代码
m(t) = m0 - ∫₀ᵗ ṁ dt

二、完整配套代码

ini 复制代码
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import solve_ivp
from scipy.interpolate import interp1d
from dataclasses import dataclass
from typing import Tuple, List, Dict, Optional
import json

# ==================== 常量定义 ====================
G = 6.67430e-11          # 引力常数 [m³/kg/s²]
M_EARTH = 5.9722e24      # 地球质量 [kg]
R_EARTH = 6378137.0      # 地球赤道半径 [m]
OMEGA_EARTH = 7.292115e-5  # 地球自转角速度 [rad/s]
G0 = 9.80665            # 海平面重力加速度 [m/s²]
J2 = 1.08263e-3         # 地球扁率系数

# ==================== 数据类定义 ====================
@dataclass
class RocketConfig:
    """火箭配置参数"""
    # 质量特性
    dry_mass: float = 500.0      # 干质量 [kg]
    prop_mass: float = 1500.0    # 推进剂质量 [kg]
    prop_density: float = 1800.0  # 推进剂密度 [kg/m³]
    
    # 发动机特性
    thrust_vac: float = 200000.0  # 真空推力 [N]
    thrust_sl: float = 180000.0  # 海平面推力 [N]
    isp_vac: float = 280.0       # 真空比冲 [s]
    isp_sl: float = 250.0        # 海平面比冲 [s]
    burn_time: float = 120.0     # 工作时间 [s]
    nozzle_area: float = 0.5     # 喷管面积 [m²]
    throttle: List[float] = None # 油门程序
    
    # 几何特性
    length: float = 10.0         # 长度 [m]
    diameter: float = 1.0        # 直径 [m]
    ref_area: float = 0.7854     # 参考面积 [m²]
    center_of_mass: float = 6.0  # 质心位置(距尾部)[m]
    center_of_pressure: float = 5.5  # 压心位置(距尾部)[m]
    
    # 惯性特性
    inertia_roll: float = 100.0   # 滚转惯量 [kg·m²]
    inertia_pitch: float = 10000.0  # 俯仰惯量 [kg·m²]
    inertia_yaw: float = 10000.0  # 偏航惯量 [kg·m²]
    
    def __post_init__(self):
        if self.throttle is None:
            self.throttle = [1.0]  # 默认全油门
        self.ref_area = np.pi * (self.diameter/2)**2
        
    @property
    def inertia_tensor(self) -> np.ndarray:
        """转动惯量张量"""
        return np.diag([self.inertia_roll, 
                       self.inertia_pitch, 
                       self.inertia_yaw])

@dataclass
class AeroData:
    """气动数据"""
    # 攻角范围 [deg]
    alpha: np.ndarray = None
    # 马赫数范围
    mach: np.ndarray = None
    # 阻力系数 Cx(alpha, mach)
    Cx: np.ndarray = None
    # 法向力系数 Cz(alpha, mach)
    Cz: np.ndarray = None
    # 俯仰力矩系数 Cm(alpha, mach)
    Cm: np.ndarray = None
    
    def __post_init__(self):
        if self.alpha is None:
            self.alpha = np.linspace(-20, 20, 9)  # -20° 到 20°
        if self.mach is None:
            self.mach = np.array([0, 0.5, 1.0, 1.5, 2.0, 3.0, 5.0])
        if self.Cx is None:
            # 默认阻力系数
            self.Cx = np.zeros((len(self.alpha), len(self.mach)))
            for i, m in enumerate(self.mach):
                if m < 1.0:
                    self.Cx[:, i] = 0.5 + 0.1 * np.abs(self.alpha)  # 亚音速
                else:
                    self.Cx[:, i] = 0.3 + 0.05 * np.abs(self.alpha)  # 超音速
        if self.Cz is None:
            # 默认法向力系数
            self.Cz = 0.05 * np.deg2rad(self.alpha).reshape(-1, 1) * np.ones((len(self.alpha), len(self.mach)))
        if self.Cm is None:
            # 默认力矩系数
            self.Cm = -0.01 * np.deg2rad(self.alpha).reshape(-1, 1) * np.ones((len(self.alpha), len(self.mach)))
    
    def get_coefficients(self, alpha: float, mach: float) -> Tuple[float, float, float]:
        """通过插值获取气动系数"""
        alpha_rad = np.deg2rad(alpha)
        alpha_deg = np.rad2deg(alpha_rad)
        
        # 确保在数据范围内
        alpha_clip = np.clip(alpha_deg, self.alpha[0], self.alpha[-1])
        mach_clip = np.clip(mach, self.mach[0], self.mach[-1])
        
        # 二维插值
        from scipy.interpolate import RectBivariateSpline
        Cx_interp = RectBivariateSpline(self.alpha, self.mach, self.Cx)
        Cz_interp = RectBivariateSpline(self.alpha, self.mach, self.Cz)
        Cm_interp = RectBivariateSpline(self.alpha, self.mach, self.Cm)
        
        Cx_val = float(Cx_interp(alpha_clip, mach_clip))
        Cz_val = float(Cz_interp(alpha_clip, mach_clip))
        Cm_val = float(Cm_interp(alpha_clip, mach_clip))
        
        return Cx_val, Cz_val, Cm_val

# ==================== 大气模型 ====================
class Atmosphere1976:
    """US Standard Atmosphere 1976"""
    
    def __init__(self):
        # 定义大气层分段 (高度: m, 温度梯度: K/m, 基础温度: K, 基础压强: Pa)
        self.layers = [
            (0, 11000, -0.0065, 288.15, 101325.0),
            (11000, 20000, 0.0, 216.65, 22632.0),
            (20000, 32000, 0.001, 216.65, 5474.9),
            (32000, 47000, 0.0028, 228.65, 868.02),
            (47000, 51000, 0.0, 270.65, 110.91),
            (51000, 71000, -0.0028, 270.65, 66.939),
            (71000, 84852, -0.002, 214.65, 3.9564)
        ]
        self.R = 287.053  # 气体常数 [J/kg/K]
        self.g0 = 9.80665
        self.gamma = 1.4  # 空气比热比
    
    def get_atmosphere(self, altitude: float) -> Tuple[float, float, float, float]:
        """获取大气参数
        返回: (温度[K], 压强[Pa], 密度[kg/m³], 声速[m/s])
        """
        h = max(0.0, altitude)
        
        for i, (h0, h1, a, T0, p0) in enumerate(self.layers):
            if h0 <= h <= h1 or (i == len(self.layers)-1 and h > h1):
                if a == 0:  # 等温层
                    T = T0
                    p = p0 * np.exp(-self.g0 * (h - h0) / (self.R * T0))
                else:  # 温度梯度层
                    T = T0 + a * (h - h0)
                    if abs(a) > 1e-10:
                        p = p0 * (T / T0) ** (-self.g0 / (a * self.R))
                    else:
                        p = p0 * np.exp(-self.g0 * (h - h0) / (self.R * T0))
                
                rho = p / (self.R * T)
                sound_speed = np.sqrt(self.gamma * self.R * T)
                return T, p, rho, sound_speed
        
        # 超过最高层,使用指数外推
        h0, h1, a, T0, p0 = self.layers[-1]
        T = T0
        p = p0 * np.exp(-self.g0 * (h - h0) / (self.R * T0))
        rho = p / (self.R * T)
        sound_speed = np.sqrt(self.gamma * self.R * T)
        return T, p, rho, sound_speed

# ==================== 火箭动力学模型 ====================
class Rocket6DOF:
    """火箭6自由度动力学模型"""
    
    def __init__(self, config: RocketConfig, aero_data: AeroData = None):
        self.config = config
        self.aero_data = aero_data or AeroData()
        self.atmosphere = Atmosphere1976()
        self.g0 = G0
        
        # 预计算惯性张量逆矩阵
        self.I_inv = np.linalg.inv(config.inertia_tensor)
        
        # 状态历史记录
        self.history = {
            'time': [], 'position': [], 'velocity': [], 'mass': [],
            'euler': [], 'accel': [], 'alpha': [], 'mach': []
        }
        
    def ecef_to_eci(self, r_ecef: np.ndarray, t: float) -> np.ndarray:
        """ECEF到ECI坐标转换"""
        theta = OMEGA_EARTH * t
        R = np.array([
            [np.cos(theta), -np.sin(theta), 0],
            [np.sin(theta), np.cos(theta), 0],
            [0, 0, 1]
        ])
        return R @ r_ecef
    
    def eci_to_ecef(self, r_eci: np.ndarray, t: float) -> np.ndarray:
        """ECI到ECEF坐标转换"""
        theta = -OMEGA_EARTH * t
        R = np.array([
            [np.cos(theta), -np.sin(theta), 0],
            [np.sin(theta), np.cos(theta), 0],
            [0, 0, 1]
        ])
        return R @ r_eci
    
    def quaternion_to_dcm(self, q: np.ndarray) -> np.ndarray:
        """四元数转方向余弦矩阵"""
        q0, q1, q2, q3 = q
        return np.array([
            [1-2*(q2**2+q3**2), 2*(q1*q2-q0*q3), 2*(q1*q3+q0*q2)],
            [2*(q1*q2+q0*q3), 1-2*(q1**2+q3**2), 2*(q2*q3-q0*q1)],
            [2*(q1*q3-q0*q2), 2*(q2*q3+q0*q1), 1-2*(q1**2+q2**2)]
        ])
    
    def dcm_to_euler(self, dcm: np.ndarray) -> Tuple[float, float, float]:
        """DCM转欧拉角(3-2-1顺序)"""
        phi = np.arctan2(dcm[2,1], dcm[2,2])  # 滚转
        theta = np.arcsin(-dcm[2,0])          # 俯仰
        psi = np.arctan2(dcm[1,0], dcm[0,0])  # 偏航
        return phi, theta, psi
    
    def gravity_acceleration(self, r_eci: np.ndarray) -> np.ndarray:
        """计算重力加速度(含J2项)"""
        r_norm = np.linalg.norm(r_eci)
        lat = np.arcsin(r_eci[2] / r_norm)
        
        # 中心引力
        g_magnitude = G * M_EARTH / r_norm**2
        
        # J2项修正
        J2_factor = 1.5 * J2 * (R_EARTH/r_norm)**2 * (3*np.sin(lat)**2 - 1)
        g_magnitude_j2 = g_magnitude * (1 + J2_factor)
        
        # 重力加速度向量(指向地心)
        g_eci = -g_magnitude_j2 * r_eci / r_norm
        return g_eci
    
    def get_thrust(self, t: float, p: float) -> Tuple[float, float]:
        """计算推力和质量流量"""
        if t > self.config.burn_time:
            return 0.0, 0.0
        
        # 推力随高度变化
        thrust = self.config.thrust_vac - p * self.config.nozzle_area
        
        # 质量流量
        m_dot = self.config.thrust_vac / (self.config.isp_vac * self.g0)
        
        return thrust, m_dot
    
    def aero_forces_moments(self, v_body: np.ndarray, rho: float, 
                           mach: float, dcm: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
        """计算气动力和力矩"""
        v_norm = np.linalg.norm(v_body)
        if v_norm < 1e-3:
            return np.zeros(3), np.zeros(3)
        
        # 计算攻角和侧滑角
        alpha = np.arctan2(v_body[2], v_body[0])  # 俯仰平面
        beta = np.arcsin(v_body[1] / v_norm)      # 偏航平面
        
        # 获取气动系数
        Cx, Cz, Cm = self.aero_data.get_coefficients(np.rad2deg(alpha), mach)
        
        # 动压
        q_inf = 0.5 * rho * v_norm**2
        
        # 气动力(体坐标系)
        F_aero_body = np.array([
            -q_inf * self.config.ref_area * Cx,
            q_inf * self.config.ref_area * 0.0,  # 侧向力系数暂设为0
            -q_inf * self.config.ref_area * Cz
        ])
        
        # 气动力矩(体坐标系)
        M_aero_body = np.array([
            0.0,  # 滚转力矩
            q_inf * self.config.ref_area * self.config.diameter * Cm,  # 俯仰力矩
            0.0   # 偏航力矩
        ])
        
        return F_aero_body, M_aero_body
    
    def dynamics(self, t: float, state: np.ndarray) -> np.ndarray:
        """6自由度动力学方程"""
        # 解包状态向量
        x, y, z = state[0:3]
        vx, vy, vz = state[3:6]
        q0, q1, q2, q3 = state[6:10]
        omega_x, omega_y, omega_z = state[10:13]
        m = state[13]
        
        # 位置和速度向量
        r_eci = np.array([x, y, z])
        v_eci = np.array([vx, vy, vz])
        
        # 计算高度
        r_norm = np.linalg.norm(r_eci)
        alt = r_norm - R_EARTH
        
        # 大气参数
        T, p, rho, sound_speed = self.atmosphere.get_atmosphere(alt)
        
        # 四元数归一化
        q = np.array([q0, q1, q2, q3])
        q = q / np.linalg.norm(q)
        q0, q1, q2, q3 = q
        
        # 方向余弦矩阵
        dcm = self.quaternion_to_dcm(q)
        
        # 速度转换到体坐标系
        v_body = dcm.T @ v_eci
        v_norm = np.linalg.norm(v_body)
        mach = v_norm / sound_speed if sound_speed > 0 else 0
        
        # 气动力和力矩
        F_aero_body, M_aero_body = self.aero_forces_moments(v_body, rho, mach, dcm)
        
        # 推力和质量流量
        thrust_body, m_dot = self.get_thrust(t, p)
        F_thrust_body = np.array([thrust_body, 0.0, 0.0])
        
        # 总力和力矩(体坐标系)
        F_body = F_thrust_body + F_aero_body
        M_body = M_aero_body  # 简化,不考虑推力偏心
        
        # 转换到惯性系
        F_inertial = dcm @ F_body
        
        # 重力
        g_eci = self.gravity_acceleration(r_eci)
        
        # 科氏加速度和离心加速度
        omega_vec = np.array([0, 0, OMEGA_EARTH])
        coriolis = 2 * np.cross(omega_vec, v_eci)
        centrifugal = np.cross(omega_vec, np.cross(omega_vec, r_eci))
        
        # 平动加速度
        a_eci = F_inertial / m + g_eci - coriolis - centrifugal
        
        # 转动动力学
        omega = np.array([omega_x, omega_y, omega_z])
        I = self.config.inertia_tensor
        
        # 欧拉方程: I * dω/dt + ω × (I * ω) = M
        omega_dot = self.I_inv @ (M_body - np.cross(omega, I @ omega))
        
        # 四元数运动学
        Omega = np.array([
            [0, -omega_x, -omega_y, -omega_z],
            [omega_x, 0, omega_z, -omega_y],
            [omega_y, -omega_z, 0, omega_x],
            [omega_z, omega_y, -omega_x, 0]
        ])
        q_dot = 0.5 * Omega @ q
        
        # 质量变化
        m_dot_val = -m_dot if t <= self.config.burn_time else 0.0
        
        # 组装状态导数
        state_dot = np.zeros(14)
        state_dot[0:3] = v_eci
        state_dot[3:6] = a_eci
        state_dot[6:10] = q_dot
        state_dot[10:13] = omega_dot
        state_dot[13] = m_dot_val
        
        return state_dot
    
    def simulate(self, t_span: Tuple[float, float], initial_state: np.ndarray, 
                dt: float = 0.1, rtol: float = 1e-6, atol: float = 1e-9) -> Dict:
        """执行仿真"""
        # 记录初始状态
        self.history['time'].append(t_span[0])
        self.history['position'].append(initial_state[0:3].copy())
        self.history['velocity'].append(initial_state[3:6].copy())
        self.history['mass'].append(initial_state[13])
        
        # 定义事件函数(落地检测)
        def hit_ground(t, y):
            r = np.linalg.norm(y[0:3])
            return r - R_EARTH
        
        hit_ground.terminal = True
        hit_ground.direction = -1
        
        # 积分
        sol = solve_ivp(
            fun=lambda t, y: self.dynamics(t, y),
            t_span=t_span,
            y0=initial_state,
            method='RK45',
            t_eval=np.arange(t_span[0], t_span[1], dt),
            rtol=rtol,
            atol=atol,
            events=[hit_ground]
        )
        
        # 记录结果
        for i in range(len(sol.t)):
            t = sol.t[i]
            state = sol.y[:, i]
            
            # 记录基本状态
            self.history['time'].append(t)
            self.history['position'].append(state[0:3].copy())
            self.history['velocity'].append(state[3:6].copy())
            self.history['mass'].append(state[13])
            
            # 计算附加信息
            v_eci = state[3:6]
            v_norm = np.linalg.norm(v_eci)
            alt = np.linalg.norm(state[0:3]) - R_EARTH
            
            T, p, rho, sound_speed = self.atmosphere.get_atmosphere(alt)
            mach = v_norm / sound_speed if sound_speed > 0 else 0
            
            dcm = self.quaternion_to_dcm(state[6:10])
            v_body = dcm.T @ v_eci
            alpha = np.arctan2(v_body[2], v_body[0])
            
            self.history['mach'].append(mach)
            self.history['alpha'].append(alpha)
            
            # 计算欧拉角
            phi, theta, psi = self.dcm_to_euler(dcm)
            self.history['euler'].append([phi, theta, psi])
            
            # 计算加速度
            if i > 0:
                dt_hist = self.history['time'][-1] - self.history['time'][-2]
                dv = self.history['velocity'][-1] - self.history['velocity'][-2]
                accel = dv / dt_hist if dt_hist > 0 else np.zeros(3)
                self.history['accel'].append(accel)
            else:
                self.history['accel'].append(np.zeros(3))
        
        return {
            'time': np.array(self.history['time']),
            'position': np.array(self.history['position']),
            'velocity': np.array(self.history['velocity']),
            'mass': np.array(self.history['mass']),
            'euler': np.array(self.history['euler']),
            'accel': np.array(self.history['accel']),
            'mach': np.array(self.history['mach']),
            'alpha': np.array(self.history['alpha'])
        }
    
    def plot_results(self, results: Dict):
        """绘制结果"""
        fig, axes = plt.subplots(3, 3, figsize=(15, 12))
        
        time = results['time']
        
        # 位置
        pos = results['position']
        alt = np.linalg.norm(pos, axis=1) - R_EARTH
        axes[0,0].plot(time, alt / 1000)
        axes[0,0].set_ylabel('高度 (km)')
        axes[0,0].set_xlabel('时间 (s)')
        axes[0,0].grid(True)
        axes[0,0].set_title('飞行高度')
        
        # 速度
        vel = results['velocity']
        vel_mag = np.linalg.norm(vel, axis=1)
        axes[0,1].plot(time, vel_mag)
        axes[0,1].set_ylabel('速度 (m/s)')
        axes[0,1].set_xlabel('时间 (s)')
        axes[0,1].grid(True)
        axes[0,1].set_title('飞行速度')
        
        # 马赫数
        axes[0,2].plot(time, results['mach'])
        axes[0,2].set_ylabel('马赫数')
        axes[0,2].set_xlabel('时间 (s)')
        axes[0,2].grid(True)
        axes[0,2].set_title('马赫数变化')
        
        # 质量
        axes[1,0].plot(time, results['mass'])
        axes[1,0].set_ylabel('质量 (kg)')
        axes[1,0].set_xlabel('时间 (s)')
        axes[1,0].grid(True)
        axes[1,0].set_title('质量变化')
        
        # 攻角
        axes[1,1].plot(time, np.rad2deg(results['alpha']))
        axes[1,1].set_ylabel('攻角 (度)')
        axes[1,1].set_xlabel('时间 (s)')
        axes[1,1].grid(True)
        axes[1,1].set_title('攻角变化')
        
        # 欧拉角
        euler = results['euler']
        axes[1,2].plot(time, np.rad2deg(euler[:, 0]), label='滚转')
        axes[1,2].plot(time, np.rad2deg(euler[:, 1]), label='俯仰')
        axes[1,2].plot(time, np.rad2deg(euler[:, 2]), label='偏航')
        axes[1,2].set_ylabel('角度 (度)')
        axes[1,2].set_xlabel('时间 (s)')
        axes[1,2].grid(True)
        axes[1,2].legend()
        axes[1,2].set_title('姿态角')
        
        # 加速度
        accel = results['accel']
        accel_g = np.linalg.norm(accel, axis=1) / G0
        axes[2,0].plot(time, accel_g)
        axes[2,0].set_ylabel('过载 (g)')
        axes[2,0].set_xlabel('时间 (s)')
        axes[2,0].grid(True)
        axes[2,0].set_title('过载')
        
        # 弹道轨迹
        axes[2,1].plot(pos[:, 0] / 1000, pos[:, 2] / 1000)
        axes[2,1].set_xlabel('X (km)')
        axes[2,1].set_ylabel('Z (km)')
        axes[2,1].grid(True)
        axes[2,1].set_title('弹道轨迹')
        axes[2,1].axis('equal')
        
        # 弹道倾角
        gamma = np.arctan2(vel[:, 2], np.sqrt(vel[:, 0]**2 + vel[:, 1]**2))
        axes[2,2].plot(time, np.rad2deg(gamma))
        axes[2,2].set_ylabel('弹道倾角 (度)')
        axes[2,2].set_xlabel('时间 (s)')
        axes[2,2].grid(True)
        axes[2,2].set_title('弹道倾角')
        
        plt.tight_layout()
        plt.show()

# ==================== 主程序 ====================
def main():
    """主仿真程序"""
    
    # 1. 创建火箭配置
    config = RocketConfig(
        dry_mass=500.0,
        prop_mass=1500.0,
        thrust_vac=200000.0,
        thrust_sl=180000.0,
        isp_vac=280.0,
        isp_sl=250.0,
        burn_time=120.0,
        length=10.0,
        diameter=1.0
    )
    
    # 2. 创建气动数据
    aero_data = AeroData()
    
    # 3. 创建火箭模型
    rocket = Rocket6DOF(config, aero_data)
    
    # 4. 设置初始状态
    # 初始位置:发射点(纬度0°,经度0°,高度0)
    lat0 = np.deg2rad(0.0)  # 赤道
    lon0 = np.deg2rad(0.0)
    alt0 = 0.0
    
    # 地固坐标系位置
    r_ecef = np.array([
        (R_EARTH + alt0) * np.cos(lat0) * np.cos(lon0),
        (R_EARTH + alt0) * np.cos(lat0) * np.sin(lon0),
        (R_EARTH + alt0) * np.sin(lat0)
    ])
    
    # 转换到惯性系
    r_eci = rocket.ecef_to_eci(r_ecef, 0.0)
    
    # 初始速度(考虑地球自转)
    v_ecef = np.array([0.0, 0.0, 0.0])
    omega_earth = np.array([0, 0, OMEGA_EARTH])
    v_eci = v_ecef + np.cross(omega_earth, r_ecef)
    
    # 初始姿态(垂直向上)
    pitch0 = np.deg2rad(90.0)  # 俯仰角90°(垂直)
    yaw0 = np.deg2rad(0.0)     # 偏航角0°
    roll0 = np.deg2rad(0.0)    # 滚转角0°
    
    # 计算初始四元数
    cy = np.cos(yaw0 * 0.5)
    sy = np.sin(yaw0 * 0.5)
    cp = np.cos(pitch0 * 0.5)
    sp = np.sin(pitch0 * 0.5)
    cr = np.cos(roll0 * 0.5)
    sr = np.sin(roll0 * 0.5)
    
    q0 = cr * cp * cy + sr * sp * sy
    q1 = sr * cp * cy - cr * sp * sy
    q2 = cr * sp * cy + sr * cp * sy
    q3 = cr * cp * sy - sr * sp * cy
    
    # 初始角速度
    omega0 = np.array([0.0, 0.0, 0.0])
    
    # 初始质量
    m0 = config.dry_mass + config.prop_mass
    
    # 初始状态向量
    initial_state = np.concatenate([
        r_eci, v_eci, [q0, q1, q2, q3], omega0, [m0]
    ])
    
    # 5. 运行仿真
    print("开始火箭6自由度弹道仿真...")
    print(f"初始质量: {m0:.1f} kg")
    print(f"干质量: {config.dry_mass:.1f} kg")
    print(f"推进剂质量: {config.prop_mass:.1f} kg")
    print(f"真空推力: {config.thrust_vac/1000:.1f} kN")
    print(f"工作时间: {config.burn_time:.1f} s")
    
    results = rocket.simulate(
        t_span=(0.0, 300.0),  # 仿真时间
        initial_state=initial_state,
        dt=0.1,  # 输出步长
        rtol=1e-6,
        atol=1e-9
    )
    
    # 6. 输出结果
    print(f"\n仿真完成,总时间: {results['time'][-1]:.2f} s")
    print(f"最终高度: {np.linalg.norm(results['position'][-1]) - R_EARTH:.2f} m")
    print(f"最终速度: {np.linalg.norm(results['velocity'][-1]):.2f} m/s")
    print(f"最终马赫数: {results['mach'][-1]:.2f}")
    print(f"剩余质量: {results['mass'][-1]:.2f} kg")
    
    # 7. 绘制结果
    rocket.plot_results(results)
    
    return rocket, results

if __name__ == "__main__":
    rocket, results = main()

三、系统特性说明

1. 关键特性

  • 6自由度动力学:完整的平动和转动方程
  • 质量变化:考虑燃料消耗引起的质量和质心变化
  • 大气模型:US Standard Atmosphere 1976标准大气
  • 地球自转:考虑科氏力和离心力
  • J2项重力:考虑地球扁率影响
  • 气动模型:基于攻角和马赫数的插值表
  • 推进系统:考虑推力随高度变化

2. 扩展建议

如需进一步扩展,可考虑:

  1. 增加风场模型
  2. 添加控制系统和制导算法
  3. 考虑弹性振动和液体晃动
  4. 加入多级分离逻辑
  5. 优化气动数据库
  6. 添加蒙特卡洛仿真功能

3. 使用说明

  1. 修改RocketConfig参数定义火箭特性
  2. 准备气动数据表格(可选)
  3. 设置初始发射条件
  4. 运行仿真获取弹道数据
  5. 分析结果并进行优化

此系统提供了完整的火箭6自由度弹道计算框架,可用于火箭初步设计、弹道分析和控制系统设计。

相关推荐
壹方秘境14 小时前
95后中间件研发,放弃高薪裸辞,两年时间做了ChatTCP和ApiCatcher两款网络分析和抓包工具
后端·产品·创业
迈巧克力14 小时前
用OpenClaw实现小红书自动发布:从零到一的完整技术方案
前端·人工智能·创业
AI创业阿彬12 天前
AI困境:一个程序员的困境与觉醒
创业
databook18 天前
在AI的世界里,做一个真实的人
人工智能·程序员·创业
小碗细面20 天前
3分钟搭建AI开发团队:Agency-Agents实战指南
aigc·ai编程·创业
产品人卫朋20 天前
Claude帮我做的ToC智能门锁市场规模评估
人工智能·产品经理·创业
钰珠AIOT2 个月前
【无标题】创业,摸爬滚打?
创业
产品人卫朋2 个月前
卫朋:IPD流程落地 - 为什么要采用产品线模式?
产品经理·创业·ipd流程·华为ipd
产品人卫朋2 个月前
卫朋:AI硬件产品怎么做?—— AI录音豆
人工智能·创业