液体火箭发动机简化数字仿真系统

0 阅读8分钟

以下是一个简化的液体火箭发动机数字仿真系统的Python实现。这个系统包含了基本的推进剂流量、燃烧室、喷管和性能计算模块。

"""
液体火箭发动机数字仿真系统
简化版本 - 教学演示用途
日期: 2026年3月16日
"""

import numpy as np
from dataclasses import dataclass
from typing import Dict, List, Optional, Tuple
import matplotlib.pyplot as plt
from scipy.integrate import odeint
import warnings
warnings.filterwarnings('ignore')

@dataclass
class EngineConfig:
    """发动机配置参数"""
    name: str = "RL-10型液氢液氧发动机"
    chamber_pressure: float = 3.5e6  # 燃烧室压力, Pa
    mixture_ratio: float = 6.0  # 混合比 (氧化剂/燃料)
    nozzle_area_ratio: float = 40.0  # 喷管面积比
    chamber_temp: float = 3500.0  # 燃烧室温度, K
    specific_heat_ratio: float = 1.2  # 比热比
    molar_mass: float = 0.022  # 燃气摩尔质量, kg/mol
    efficiency_combustion: float = 0.98  # 燃烧效率
    efficiency_nozzle: float = 0.96  # 喷管效率
    
class Propellant:
    """推进剂类"""
    def __init__(self, name: str, density: float, specific_heat: float):
        self.name = name
        self.density = density  # kg/m³
        self.specific_heat = specific_heat  # J/(kg·K)
        self.temperature = 293.0  # K, 初始温度
        
class LiquidRocketEngine:
    """液体火箭发动机仿真主类"""
    
    def __init__(self, config: EngineConfig):
        self.config = config
        self.propellants = {}
        self.mass_flow_rate = 0.0
        self.thrust = 0.0
        self.isp = 0.0
        self.time = 0.0
        self.operating = False
        
        # 状态历史记录
        self.history = {
            'time': [],
            'thrust': [],
            'pressure': [],
            'temperature': [],
            'mass_flow': [],
            'isp': []
        }
        
    def add_propellant(self, prop_type: str, prop: Propellant):
        """添加推进剂"""
        self.propellants[prop_type] = prop
        
    def calculate_mass_flow(self, fuel_flow_rate: float) -> Tuple[float, float]:
        """计算质量流量"""
        if 'oxidizer' not in self.propellants or 'fuel' not in self.propellants:
            raise ValueError("需要先添加氧化剂和燃料")
            
        # 基于混合比计算氧化剂流量
        oxidizer_flow_rate = fuel_flow_rate * self.config.mixture_ratio
        total_flow_rate = fuel_flow_rate + oxidizer_flow_rate
        
        self.mass_flow_rate = total_flow_rate
        return oxidizer_flow_rate, total_flow_rate
    
    def combustion_chamber_model(self, mass_flow: float) -> Dict:
        """燃烧室模型"""
        # 简化的燃烧室计算
        R_specific = 8314.462618 / self.config.molar_mass  # 气体常数, J/(kg·K)
        
        # 燃烧室出口参数
        chamber_velocity = np.sqrt(
            R_specific * self.config.chamber_temp * 
            self.config.specific_heat_ratio *
            (2 / (self.config.specific_heat_ratio + 1))
        )
        
        # 喉部面积计算 (简化)
        throat_area = mass_flow * np.sqrt(R_specific * self.config.chamber_temp) / (
            self.config.chamber_pressure * np.sqrt(self.config.specific_heat_ratio) *
            (1 + (self.config.specific_heat_ratio - 1) / 2) ** 
            (-(self.config.specific_heat_ratio + 1) / (2 * (self.config.specific_heat_ratio - 1)))
        )
        
        return {
            'throat_area': throat_area,
            'chamber_velocity': chamber_velocity,
            'characteristic_velocity': np.sqrt(R_specific * self.config.chamber_temp / 
                                              self.config.specific_heat_ratio)
        }
    
    def nozzle_model(self, chamber_params: Dict, altitude: float = 0.0) -> Dict:
        """喷管模型 - 包括高度补偿"""
        # 大气压力随高度变化 (简化模型)
        p_ambient = 101325 * np.exp(-altitude / 8500)  # Pa
        
        # 喷管膨胀计算
        gamma = self.config.specific_heat_ratio
        Pc = self.config.chamber_pressure
        Pe = Pc * (1 + (gamma - 1) / 2) ** (-gamma / (gamma - 1))  # 出口压力
        Ae_At = self.config.nozzle_area_ratio
        
        # 计算推力系数
        Cf = np.sqrt(
            (2 * gamma ** 2 / (gamma - 1)) *
            (2 / (gamma + 1)) ** ((gamma + 1) / (gamma - 1)) *
            (1 - (Pe / Pc) ** ((gamma - 1) / gamma))
        )
        
        # 考虑环境压力修正
        if Pe > p_ambient:
            Cf += (Pe - p_ambient) * Ae_At / Pc
            
        Cf *= self.config.efficiency_nozzle
        
        return {
            'exit_pressure': Pe,
            'ambient_pressure': p_ambient,
            'thrust_coefficient': Cf,
            'expansion_ratio': Ae_At
        }
    
    def calculate_thrust(self, mass_flow: float, nozzle_params: Dict, 
                        chamber_params: Dict) -> float:
        """计算推力"""
        # 特征速度
        c_star = chamber_params['characteristic_velocity']
        
        # 推力
        thrust = mass_flow * c_star * nozzle_params['thrust_coefficient']
        
        # 应用燃烧效率
        thrust *= self.config.efficiency_combustion
        
        self.thrust = thrust
        return thrust
    
    def calculate_isp(self, thrust: float, mass_flow: float) -> float:
        """计算比冲"""
        if mass_flow <= 0:
            return 0.0
            
        isp = thrust / (mass_flow * 9.80665)  # 地球重力加速度
        self.isp = isp
        return isp
    
    def transient_model(self, state: List[float], t: float, 
                       control_params: Dict) -> List[float]:
        """瞬态模型 - 用于ODE求解"""
        # 状态变量: [燃烧室压力, 燃烧室温度, 涡轮转速]
        Pc, Tc, N = state
        
        # 控制参数
        valve_position = control_params.get('valve_position', 0.5)
        target_pressure = control_params.get('target_pressure', 
                                           self.config.chamber_pressure)
        
        # 简化的动态方程
        tau_p = 0.1  # 压力时间常数
        tau_t = 0.2  # 温度时间常数
        tau_n = 0.3  # 转速时间常数
        
        dPc_dt = (target_pressure * valve_position - Pc) / tau_p
        dTc_dt = (self.config.chamber_temp - Tc) / tau_t
        dN_dt = (1000 - N) / tau_n  # 目标转速1000 rad/s
        
        return [dPc_dt, dTc_dt, dN_dt]
    
    def run_transient_simulation(self, duration: float = 10.0, 
                                dt: float = 0.1) -> Dict:
        """运行瞬态仿真"""
        if not self.propellants:
            raise ValueError("需要先添加推进剂")
            
        # 初始状态
        initial_state = [
            1e5,  # 初始压力 (Pa)
            293.0,  # 初始温度 (K)
            0.0  # 初始转速
        ]
        
        # 时间点
        time_points = np.arange(0, duration, dt)
        
        # 控制参数
        control_params = {
            'valve_position': 0.0,
            'target_pressure': self.config.chamber_pressure
        }
        
        # 模拟阀门开启
        results = []
        for i, t in enumerate(time_points):
            # 阀门开启曲线
            if t < 1.0:
                control_params['valve_position'] = t
            else:
                control_params['valve_position'] = 1.0
                
            # 使用欧拉法积分
            if i == 0:
                state = initial_state
            else:
                derivatives = self.transient_model(state, t, control_params)
                state = [s + d * dt for s, d in zip(state, derivatives)]
                
            # 记录结果
            results.append({
                'time': t,
                'pressure': state[0],
                'temperature': state[1],
                'rpm': state[2] * 9.5493,  # 转换为RPM
                'valve_position': control_params['valve_position']
            })
            
        return results
    
    def run_steady_state(self, fuel_flow: float = 5.0, 
                        altitude: float = 0.0) -> Dict:
        """运行稳态仿真"""
        print(f"运行稳态仿真 - 燃料流量: {fuel_flow} kg/s, 高度: {altitude} m")
        
        # 计算质量流量
        oxidizer_flow, total_flow = self.calculate_mass_flow(fuel_flow)
        
        # 燃烧室计算
        chamber = self.combustion_chamber_model(total_flow)
        
        # 喷管计算
        nozzle = self.nozzle_model(chamber, altitude)
        
        # 推力计算
        thrust = self.calculate_thrust(total_flow, nozzle, chamber)
        
        # 比冲计算
        isp = self.calculate_isp(thrust, total_flow)
        
        # 记录状态
        self.history['time'].append(self.time)
        self.history['thrust'].append(thrust)
        self.history['pressure'].append(self.config.chamber_pressure)
        self.history['temperature'].append(self.config.chamber_temp)
        self.history['mass_flow'].append(total_flow)
        self.history['isp'].append(isp)
        
        results = {
            'fuel_flow': fuel_flow,
            'oxidizer_flow': oxidizer_flow,
            'total_flow': total_flow,
            'thrust_N': thrust,
            'thrust_kgf': thrust / 9.80665,
            'specific_impulse': isp,
            'chamber': chamber,
            'nozzle': nozzle,
            'mixture_ratio': self.config.mixture_ratio
        }
        
        return results
    
    def plot_results(self, transient_data: Optional[List] = None):
        """绘制结果"""
        fig, axes = plt.subplots(2, 3, figsize=(15, 10))
        fig.suptitle(f'{self.config.name} 仿真结果', fontsize=16)
        
        if transient_data and len(transient_data) > 0:
            # 绘制瞬态响应
            time = [d['time'] for d in transient_data]
            pressure = [d['pressure'] / 1e6 for d in transient_data]  # 转换为MPa
            temperature = [d['temperature'] for d in transient_data]
            rpm = [d['rpm'] for d in transient_data]
            valve = [d['valve_position'] for d in transient_data]
            
            # 压力响应
            axes[0, 0].plot(time, pressure, 'b-', linewidth=2)
            axes[0, 0].set_xlabel('时间 (s)')
            axes[0, 0].set_ylabel('燃烧室压力 (MPa)')
            axes[0, 0].set_title('压力瞬态响应')
            axes[0, 0].grid(True, alpha=0.3)
            
            # 温度响应
            axes[0, 1].plot(time, temperature, 'r-', linewidth=2)
            axes[0, 1].set_xlabel('时间 (s)')
            axes[0, 1].set_ylabel('燃烧室温度 (K)')
            axes[0, 1].set_title('温度瞬态响应')
            axes[0, 1].grid(True, alpha=0.3)
            
            # 阀门和转速
            ax2 = axes[0, 2].twinx()
            axes[0, 2].plot(time, valve, 'g-', linewidth=2, label='阀门位置')
            ax2.plot(time, rpm, 'm-', linewidth=2, label='涡轮转速', alpha=0.7)
            axes[0, 2].set_xlabel('时间 (s)')
            axes[0, 2].set_ylabel('阀门位置', color='g')
            ax2.set_ylabel('转速 (RPM)', color='m')
            axes[0, 2].set_title('控制系统响应')
            axes[0, 2].legend(loc='upper left')
            ax2.legend(loc='upper right')
            axes[0, 2].grid(True, alpha=0.3)
        
        if len(self.history['time']) > 0:
            # 绘制稳态性能
            mixtures = np.linspace(4, 8, 10)
            thrusts = []
            isps = []
            
            for mr in mixtures:
                self.config.mixture_ratio = mr
                result = self.run_steady_state(fuel_flow=5.0)
                thrusts.append(result['thrust_N'] / 1000)  # 转换为kN
                isps.append(result['specific_impulse'])
            
            # 推力 vs 混合比
            axes[1, 0].plot(mixtures, thrusts, 'b-o', linewidth=2, markersize=6)
            axes[1, 0].set_xlabel('混合比 (O/F)')
            axes[1, 0].set_ylabel('推力 (kN)')
            axes[1, 0].set_title('推力 vs 混合比')
            axes[1, 0].grid(True, alpha=0.3)
            
            # 比冲 vs 混合比
            axes[1, 1].plot(mixtures, isps, 'r-o', linewidth=2, markersize=6)
            axes[1, 1].set_xlabel('混合比 (O/F)')
            axes[1, 1].set_ylabel('比冲 (s)')
            axes[1, 1].set_title('比冲 vs 混合比')
            axes[1, 1].grid(True, alpha=0.3)
            
            # 高度对性能的影响
            altitudes = np.linspace(0, 50000, 10)
            thrusts_alt = []
            
            for alt in altitudes:
                result = self.run_steady_state(fuel_flow=5.0, altitude=alt)
                thrusts_alt.append(result['thrust_N'] / 1000)
            
            axes[1, 2].plot(altitudes, thrusts_alt, 'g-o', linewidth=2, markersize=6)
            axes[1, 2].set_xlabel('高度 (m)')
            axes[1, 2].set_ylabel('推力 (kN)')
            axes[1, 2].set_title('推力 vs 高度')
            axes[1, 2].grid(True, alpha=0.3)
        
        plt.tight_layout()
        plt.show()
    
    def print_results(self, results: Dict):
        """打印仿真结果"""
        print("\n" + "="*60)
        print(f"发动机: {self.config.name}")
        print("="*60)
        print(f"燃料流量:           {results['fuel_flow']:.2f} kg/s")
        print(f"氧化剂流量:         {results['oxidizer_flow']:.2f} kg/s")
        print(f"总质量流量:         {results['total_flow']:.2f} kg/s")
        print(f"混合比 (O/F):       {results['mixture_ratio']:.2f}")
        print(f"推力:               {results['thrust_N']/1000:.2f} kN")
        print(f"推力:               {results['thrust_kgf']:.2f} kgf")
        print(f"比冲:               {results['specific_impulse']:.2f} s")
        print(f"特征速度:           {results['chamber']['characteristic_velocity']:.2f} m/s")
        print(f"推力系数:           {results['nozzle']['thrust_coefficient']:.2f}")
        print(f"喉部面积:           {results['chamber']['throat_area']*10000:.2f} cm²")
        print(f"喷管面积比:         {results['nozzle']['expansion_ratio']:.2f}")
        print(f"出口压力:           {results['nozzle']['exit_pressure']/1000:.2f} kPa")
        print(f"环境压力:           {results['nozzle']['ambient_pressure']/1000:.2f} kPa")
        print("="*60)

def main():
    """主函数 - 演示如何使用仿真系统"""
    
    # 1. 创建发动机配置
    config = EngineConfig(
        name="液氢液氧上面级发动机",
        chamber_pressure=4.0e6,  # 4 MPa
        mixture_ratio=6.0,
        nozzle_area_ratio=80.0,
        chamber_temp=3600.0,
        specific_heat_ratio=1.2,
        molar_mass=0.016,
        efficiency_combustion=0.99,
        efficiency_nozzle=0.97
    )
    
    # 2. 创建发动机实例
    engine = LiquidRocketEngine(config)
    
    # 3. 添加推进剂
    lh2 = Propellant("液氢", density=70.0, specific_heat=14300.0)
    lox = Propellant("液氧", density=1141.0, specific_heat=1700.0)
    
    engine.add_propellant("fuel", lh2)
    engine.add_propellant("oxidizer", lox)
    
    # 4. 运行稳态仿真
    print("正在进行稳态仿真...")
    results = engine.run_steady_state(fuel_flow=5.0, altitude=0.0)
    engine.print_results(results)
    
    # 5. 运行瞬态仿真
    print("\n正在进行瞬态仿真 (启动过程)...")
    transient_results = engine.run_transient_simulation(duration=5.0, dt=0.05)
    
    # 6. 绘制结果
    print("\n生成仿真图表...")
    engine.plot_results(transient_results)
    
    # 7. 运行参数扫描
    print("\n进行参数扫描分析...")
    print("\n混合比对性能的影响:")
    print("-"*50)
    print("混合比 | 推力(kN) | 比冲(s)")
    print("-"*50)
    
    for mr in [4.0, 5.0, 6.0, 7.0, 8.0]:
        engine.config.mixture_ratio = mr
        scan_result = engine.run_steady_state(fuel_flow=5.0)
        print(f"{mr:6.1f} | {scan_result['thrust_N']/1000:8.2f} | {scan_result['specific_impulse']:7.2f}")
    
    return engine

if __name__ == "__main__":
    print("液体火箭发动机数字仿真系统")
    print("="*60)
    
    # 运行仿真
    engine_sim = main()
    
    print("\n仿真完成!")

系统特性

这个液体火箭发动机数字仿真系统包含以下主要模块:

1. 核心类

  • EngineConfig: 发动机配置参数
  • Propellant: 推进剂物理属性
  • LiquidRocketEngine: 发动机仿真主类

2. 物理模型

  • 质量流量计算(基于混合比)
  • 燃烧室热力学计算
  • 喷管等熵流动计算
  • 推力与比冲计算
  • 瞬态响应模拟

3. 仿真功能

  • 稳态性能分析
  • 瞬态启动过程仿真
  • 参数扫描(混合比、高度等)
  • 结果可视化

4. 使用示例

# 快速使用示例
config = EngineConfig(
    name="自定义发动机",
    chamber_pressure=3.0e6,  # 3 MPa
    mixture_ratio=5.5,
    nozzle_area_ratio=50.0
)

engine = LiquidRocketEngine(config)

# 添加推进剂
engine.add_propellant("fuel", Propellant("RP-1", 810, 2090))
engine.add_propellant("oxidizer", Propellant("液氧", 1141, 1700))

# 运行仿真
results = engine.run_steady_state(fuel_flow=10.0)

系统要求

# 所需Python库
numpy>=1.20.0
matplotlib>=3.5.0
scipy>=1.7.0

扩展建议

这个基础系统可以扩展以下功能:

  1. 真实气体效应​ - 添加实际气体状态方程
  2. 两相流计算​ - 考虑燃烧产物的相变
  3. 传热分析​ - 再生冷却和热防护
  4. 控制系统​ - PID控制器和故障模拟
  5. 优化算法​ - 自动优化发动机参数
  6. 3D可视化​ - 使用PyVista或Mayavi进行流场显示

注意事项

  1. 这是一个教学演示系统,实际工程应用需要更精确的模型
  2. 考虑了基本的等熵流动假设,实际发动机有各种损失
  3. 推进剂属性需要根据实际数据进行调整
  4. 瞬态模型是高度简化的,实际动态响应更复杂

这个系统提供了一个可扩展的框架,您可以根据具体需求添加更多物理模型和仿真功能。