JSBSim 导弹气动模型 xml 文件
xml
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="http://jsbsim.sourceforge.net/JSBSim.xsl"?>
<!--
JSBSim 飞行动力学模型配置文件
模型名称: AIM-9
用途: 高机动红外制导空空导弹的标准物理基线模型
特点:
- 无机翼气动布局 (小展弦比)
- 高过载、高舵效
- 火箭发动机推进
注意: 所用数据并非真实数据,部分数据是接合 DeepSeek 生成的假数据,仅用于模拟学习
-->
<fdm_config name="AIM-9X" version="2.0" release="BETA"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://jsbsim.sourceforge.net/JSBSim.xsd">
<!-- ================= 文件头信息 ================= -->
<fileheader>
<!-- UP -->
<author>昵称已被吞噬QAQ</author>
<!-- 模型描述,JSBSim GUI / 日志中可见 -->
<description>AIM-9X Standard Physics Baseline</description>
</fileheader>
<!-- ================= 几何与参考面积 ================= -->
<!--
metrics 定义的是"等效气动几何参数"
并不一定是真实几何,而是用于气动力计算的参考量
-->
<metrics>
<!-- 等效参考面积 Sw,用于升力 / 阻力 / 侧力 -->
<wingarea unit="FT2"> 0.85 </wingarea>
<!-- 等效翼展 b,用于滚转 / 偏航力矩 -->
<wingspan unit="FT" > 0.92 </wingspan>
<!-- 等效平均气动弦长 c̄,用于俯仰力矩 -->
<chord unit="FT" > 3.0 </chord>
<!-- 等效水平尾翼面积(主要影响俯仰稳定) -->
<htailarea unit="FT2"> 0.25 </htailarea>
<!-- 等效垂直尾翼面积(主要影响偏航稳定) -->
<vtailarea unit="FT2"> 0.25 </vtailarea>
</metrics>
<!-- ================= 质量与惯性 ================= -->
<!--
mass_balance 决定刚体动力学行为
对导弹而言:
- 转动惯量远比飞机重要
- Iyy / Izz 决定过载能力和转弯半径
-->
<mass_balance>
<!-- 空重 (不含燃料变化),单位磅 -->
<emptywt unit="LBS" > 175.0 </emptywt>
<!--
转动惯量估算说明:
- Ixx: 沿弹体轴线(滚转)
导弹细长,对滚转不敏感
- Iyy/Izz: 俯仰 / 偏航惯量
决定最大角加速度和瞬态响应
注意: 这部分是瞎给的,为了平衡一些东西进行了调整
-->
<ixx unit="SLUG*FT2"> 1600.0 </ixx>
<iyy unit="SLUG*FT2"> 1600.0 </iyy>
<izz unit="SLUG*FT2"> 1600.0 </izz>
<!--
质心位置
这里设在机体系原点
对导弹建模是常见简化
-->
<location name="CG" unit="IN">
<x> 0 </x>
<y> 0 </y>
<z> 0 </z>
</location>
</mass_balance>
<!-- ================= 地面接触模型 ================= -->
<!--
ground_reactions 仅用于:
- 发射前
- 地面测试
对空中飞行基本无影响
-->
<ground_reactions>
<contact type="STRUCTURE" name="Belly">
<!-- 接触点位置(机腹) -->
<location unit="IN">
<x>60</x>
<y>0</y>
<z>-3</z>
</location>
<!-- 导弹无滑跑需求,摩擦设为 0 -->
<static_friction> 0.0 </static_friction>
<dynamic_friction> 0.0 </dynamic_friction>
<!-- 接触弹簧刚度 -->
<spring_coeff unit="LBS/FT"> 1000.0 </spring_coeff>
<!-- 接触阻尼,防止数值震荡 -->
<damping_coeff unit="LBS/FT/SEC"> 100.0 </damping_coeff>
</contact>
</ground_reactions>
<!-- ================= 外部作用力 ================= -->
<!--
external_reactions 用于:
- 火箭发动机
- 推进器
- 非气动外力
-->
<external_reactions>
<!-- 火箭推力 -->
<force name="RocketThrust" frame="BODY">
<!-- 推力作用点,靠近尾部 -->
<location unit="IN">
<x>118</x>
<y>0</y>
<z>0</z>
</location>
<!-- 推力方向:沿机体 X 正方向 -->
<direction>
<x>1</x>
<y>0</y>
<z>0</z>
</direction>
<!--
推力时间函数:
- 恒定推力
- 5 秒后自动归零
-->
<function>
<product>
<!-- 推力大小 (lbs) -->
<value> 2500.0 </value>
<!-- 燃烧时间限制 -->
<lt>
<property>simulation/sim-time-sec</property>
<value> 5.0 </value>
</lt>
</product>
</function>
</force>
</external_reactions>
<!-- ================= 飞控系统 (FCS) ================= -->
<!--
飞控系统职责:
- 将归一化指令 (-1 ~ 1)
- 映射为真实舵面偏转角 (rad)
-->
<flight_control name="FCS">
<!-- 俯仰控制通道 -->
<channel name="Pitch">
<pure_gain name="Elevator Control">
<input> fcs/elevator-cmd-norm </input>
<gain> 0.2 </gain>
<output> fcs/elevator-pos-rad </output>
</pure_gain>
</channel>
<!-- 滚转控制通道 -->
<channel name="Roll">
<pure_gain name="Aileron Control">
<input> fcs/aileron-cmd-norm </input>
<gain> 0.01 </gain>
<output> fcs/left-aileron-pos-rad </output>
</pure_gain>
</channel>
<!-- 偏航控制通道 -->
<channel name="Yaw">
<pure_gain name="Rudder Control">
<input> fcs/rudder-cmd-norm </input>
<gain> 0.2 </gain>
<output> fcs/rudder-pos-rad </output>
</pure_gain>
</channel>
</flight_control>
<!-- ================= 气动力模型 ================= -->
<!--
aerodynamics:
- 所有气动力/力矩均通过 q̄*S*(...) 构造
- 系数已"物理化",避免纯数值炸飞
-->
<aerodynamics>
<!-- ========== 升力轴 ========== -->
<axis name="LIFT">
<!-- α 升力 -->
<function name="aero/coefficient/CLalpha">
<product>
<property>aero/qbar-psf</property>
<property>metrics/Sw-sqft</property>
<property>aero/alpha-rad</property>
<!-- 高升力斜率,适配高迎角导弹 -->
<value> 12.0 </value>
</product>
</function>
<!-- 升降舵升力 -->
<function name="aero/coefficient/CLde">
<product>
<property>aero/qbar-psf</property>
<property>metrics/Sw-sqft</property>
<property>fcs/elevator-pos-rad</property>
<value> 3.0 </value>
</product>
</function>
</axis>
<!-- ========== 阻力轴 ========== -->
<axis name="DRAG">
<!-- 基础阻力,随马赫数变化 -->
<function name="aero/coefficient/CD0">
<product>
<property>aero/qbar-psf</property>
<property>metrics/Sw-sqft</property>
<table>
<independentVar lookup="row">velocities/mach</independentVar>
<!--
体现跨音阻力突增
-->
<tableData>
0.00 0.04
0.80 0.04
0.95 0.09
1.05 0.10
1.20 0.08
2.00 0.06
4.00 0.05
</tableData>
</table>
</product>
</function>
<!-- 诱导阻力 ~ α² -->
<function name="aero/coefficient/CDi">
<product>
<property>aero/qbar-psf</property>
<property>metrics/Sw-sqft</property>
<property>aero/alpha-rad</property>
<property>aero/alpha-rad</property>
<value> 3.0 </value>
</product>
</function>
</axis>
<!-- ========== 侧向力 ========== -->
<axis name="SIDE">
<!-- 侧滑稳定 -->
<function name="aero/coefficient/CYbeta">
<product>
<property>aero/qbar-psf</property>
<property>metrics/Sw-sqft</property>
<property>aero/beta-rad</property>
<value> -12.0 </value>
</product>
</function>
<!-- 偏航舵侧力 -->
<function name="aero/coefficient/CYdr">
<product>
<property>aero/qbar-psf</property>
<property>metrics/Sw-sqft</property>
<property>fcs/rudder-pos-rad</property>
<value> 3.0 </value>
</product>
</function>
</axis>
<!-- ========== 滚转力矩 ========== -->
<axis name="ROLL">
<!-- 滚转阻尼 -->
<function name="aero/coefficient/Clp">
<product>
<property>aero/qbar-psf</property>
<property>metrics/Sw-sqft</property>
<property>metrics/bw-ft</property>
<property>aero/bi2vel</property>
<property>velocities/p-aero-rad_sec</property>
<value> -20.0 </value>
</product>
</function>
<!-- 副翼滚转 -->
<function name="aero/coefficient/Clda">
<product>
<property>aero/qbar-psf</property>
<property>metrics/Sw-sqft</property>
<property>metrics/bw-ft</property>
<property>fcs/left-aileron-pos-rad</property>
<value> 10.0 </value>
</product>
</function>
</axis>
<!-- ========== 俯仰力矩(核心) ========== -->
<axis name="PITCH">
<!-- 静稳定 -->
<function name="aero/coefficient/Cmalpha">
<product>
<property>aero/qbar-psf</property>
<property>metrics/Sw-sqft</property>
<property>metrics/cbarw-ft</property>
<property>aero/alpha-rad</property>
<value> -8.0 </value>
</product>
</function>
<!-- 升降舵俯仰 -->
<function name="aero/coefficient/Cmde">
<product>
<property>aero/qbar-psf</property>
<property>metrics/Sw-sqft</property>
<property>metrics/cbarw-ft</property>
<property>fcs/elevator-pos-rad</property>
<value> -15.0 </value>
</product>
</function>
<!-- 俯仰阻尼 -->
<function name="aero/coefficient/Cmq">
<product>
<property>aero/qbar-psf</property>
<property>metrics/Sw-sqft</property>
<property>metrics/cbarw-ft</property>
<property>aero/ci2vel</property>
<property>velocities/q-aero-rad_sec</property>
<value> -100.0 </value>
</product>
</function>
</axis>
<!-- ========== 偏航力矩 ========== -->
<axis name="YAW">
<!-- 方向稳定 -->
<function name="aero/coefficient/Cnbeta">
<product>
<property>aero/qbar-psf</property>
<property>metrics/Sw-sqft</property>
<property>metrics/bw-ft</property>
<property>aero/beta-rad</property>
<value> 8.0 </value>
</product>
</function>
<!-- 偏航舵 -->
<function name="aero/coefficient/Cndr">
<product>
<property>aero/qbar-psf</property>
<property>metrics/Sw-sqft</property>
<property>metrics/bw-ft</property>
<property>fcs/rudder-pos-rad</property>
<value> -15.0 </value>
</product>
</function>
<!-- 偏航阻尼 -->
<function name="aero/coefficient/Cnr">
<product>
<property>aero/qbar-psf</property>
<property>metrics/Sw-sqft</property>
<property>metrics/bw-ft</property>
<property>aero/bi2vel</property>
<property>velocities/r-aero-rad_sec</property>
<value> -100.0 </value>
</product>
</function>
</axis>
</aerodynamics>
</fdm_config>
测试用 Python 代码
python
import jsbsim
import os
import math
import numpy as np
def run_straight_test():
root_dir = os.path.abspath(os.getcwd())
fdm = jsbsim.FGFDMExec(root_dir)
fdm.set_aircraft_path(os.path.join(root_dir, "aircraft"))
fdm.load_model("aim9x")
fdm['ic/lat-gc-deg'] = 37.2
fdm['ic/long-gc-deg'] = -115.8
fdm['ic/h-sl-ft'] = 15000.0
fdm['ic/psi-true-deg'] = 90.0
fdm['ic/theta-deg'] = 0.0
target_init_vel = 928.0
fdm['ic/u-fps'] = target_init_vel
fdm.run_ic()
# ACMI
acmi_file = open("straight_test.acmi", "w", encoding="utf-8")
acmi_file.write("FileType=text/acmi/tacview\n")
acmi_file.write("FileVersion=2.1\n")
acmi_file.write("0,ReferenceTime=2023-10-27T12:00:00Z\n")
acmi_file.write("1,Name=AIM-9X-Basic,Type=Missile,Color=White\n")
dt = 1 / 60
fdm.set_dt(dt)
total_times = 180
print(
f"{'Time':>5} | {'Mach':>4} | {'Alt':>6} | "
f"{'Pitch':>6} | {'AoA':>6} | "
f"{'Nx':>6} | {'Ny':>6} | {'Nz':>6} | {'NT':>6}"
)
print("-" * 80)
for i in range(int(total_times / dt)):
t = fdm['simulation/sim-time-sec']
# === 测试逻辑 ===
if t < 5.0:
cmd = [0.0, 0.0, 0.0] # 平飞(发动机点火加速阶段)
elif t < 10.0:
cmd = [-0.2, 0.0, 1.0] # 测试偏航(左)
elif t < 15.0:
cmd = [-0.2, 0.0, -1.0] # 测试偏航(右)
elif t < 24.0:
cmd = [-0.2, 0.0, 0.0] # 测试俯仰(上)
elif t < 40.0:
cmd = [0.2, 0.0, 0.0] # 测试俯仰(下,拉平)
elif t < 68:
cmd = [-0.2, 0.0, 1.0] # 测试偏航(左)
elif t < 78:
cmd = [-0.2, 0.0, -1.0] # 测试偏航(右)
elif t < 120:
cmd = [0.2, 0.0, 0.0] # 测试俯仰(拉平)
elif t < 150:
cmd = [1.0, 1.0, -1.0] # 测试滚转
else:
cmd = [-1.0, 0.0, 0.0] # 失速,触底爆炸,boom!!!
cmd = np.array(cmd)
fdm['fcs/elevator-cmd-norm'] = cmd[0]
fdm['fcs/aileron-cmd-norm'] = cmd[1]
fdm['fcs/rudder-cmd-norm'] = cmd[2]
fdm.run()
# 记录
if i % 20 == 0:
mach = fdm['velocities/mach']
alt = fdm['position/h-sl-ft']
pitch = fdm['attitude/theta-deg']
aoa = fdm['aero/alpha-deg']
nx = fdm['accelerations/n-pilot-x-norm']
ny = fdm['accelerations/n-pilot-y-norm']
nz = fdm['accelerations/n-pilot-z-norm']
n_total = math.sqrt(nx*nx + ny*ny + nz*nz)
print(
f"{t:5.1f} | {mach:4.2f} | {alt:6.0f} | "
f"{pitch:6.1f} | {aoa:6.1f} | "
f"{nx:6.1f} | {ny:6.1f} | {nz:6.1f} | {n_total:6.1f}"
)
# ACMI
m_lon = fdm['position/long-gc-deg']
m_lat = fdm['position/lat-gc-deg']
m_alt = fdm['position/h-sl-meters']
roll = fdm['attitude/phi-deg']
pitch = fdm['attitude/theta-deg']
yaw = fdm['attitude/psi-deg']
acmi_file.write(f"#{t:.2f}\n")
acmi_file.write(f"1,T={m_lon:.7f}|{m_lat:.7f}|{m_alt:.2f}|{roll:.2f}|{pitch:.2f}|{yaw:.2f}\n")
if __name__ == "__main__":
run_straight_test()
TacView 可视化
