火箭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自由度弹道计算框架,可用于火箭初步设计、弹道分析和控制系统设计。

相关推荐
钰珠AIOT2 个月前
【无标题】创业,摸爬滚打?
创业
产品人卫朋2 个月前
卫朋:IPD流程落地 - 为什么要采用产品线模式?
产品经理·创业·ipd流程·华为ipd
产品人卫朋2 个月前
卫朋:AI硬件产品怎么做?—— AI录音豆
人工智能·创业
孟健2 个月前
出海收款门槛又低了:PayPal 支持个人卖家账户(亲测 30 分钟通过)
ai编程·产品·创业
是江迪呀2 个月前
小程序上线半年我赚了多少钱?
微信小程序·产品·创业
产品人卫朋2 个月前
「产品、IPD、战略、流程」知识图谱速查清单.v7.0
人工智能·知识图谱·产品经理·需求分析·创业·ipd流程·华为ipd
孟健2 个月前
我终于把 AdSense 提现到国内银行卡了(PIN 信/税务/电汇/结汇全流程)
ai编程·产品·创业
程序员码歌2 个月前
短思考第270天,2025年赚麻的风口,2026年必冲赛道
前端·ai编程·创业
产品人卫朋2 个月前
卫朋:IPD流程市场管理篇 - 业务模式vs盈利模式vs交易模式
大数据·产品经理·创业·ipd流程·流程咨询·华为ipd