三自由度仿真


============================================================
仿真关键时间点采样(每5秒输出一次)
============================================================
   时间(s)       x(m)       y(m)     V(m/s)   α(deg)   δ(deg)    ny(g)   n_cmd(g)      r(km)
--------------------------------------------------------------------------------
     0.0        0.0     1500.0      250.0     2.00     0.00     0.47       1.57       5.12
     2.5      614.3     1485.1      243.2     2.66     0.66     0.56       1.62       4.54
     5.0     1213.6     1443.7      237.6     2.83     0.71     0.57       1.75       3.96
     7.5     1798.1     1377.5      233.2     3.04     0.76     0.59       1.98       3.39
    10.0     2369.8     1288.3      229.8     3.35     0.83     0.63       2.39       2.84
    12.5     2930.4     1179.2      227.2     3.88     0.97     0.72       3.18       2.30
    15.0     3481.7     1056.1      224.7     4.95     1.23     0.89       4.81       1.77
    17.5     4025.0      930.7      221.1     7.18     1.78     1.26       8.17       1.28
    20.0     4560.2      825.3      214.7    10.08     2.47     1.66      10.59       0.89
    22.5     5083.0      755.1      208.2     4.46     1.17     0.69       2.82       0.78
    25.0     5593.5      686.9      203.2     9.10     2.23     1.35       9.44       0.98
    27.5     6090.2      635.4      196.4     7.99     1.97     1.11       6.01       1.35
    30.0     6572.6      592.0      191.4     5.81     1.44     0.76       3.64       1.77
    32.5     7043.6      536.5      188.4     4.69     1.16     0.60       2.57       2.21
    35.0     7506.4      458.3      187.4     4.13     1.02     0.52       2.05       2.65
    37.5     7963.1      352.8      188.0     3.81     0.95     0.48       1.79       3.08
    40.0     8415.8      217.9      190.2     3.57     0.89     0.46       1.63       3.52
    42.5     8866.1       52.5      193.8     3.37     0.84     0.46       1.55       3.97
    45.0     9315.4     -143.7      198.7     3.18     0.79     0.45       1.49       4.42
    47.5     9765.1     -370.7      204.6     3.00     0.75     0.45       1.46       4.88
    50.0    10216.4     -628.4      211.3     2.82     0.70     0.45       1.44       5.35

============================================================
最终状态
============================================================
仿真结束时间: 50.00 s
最终位置:     x = 10217.7 m,  y = -629.2 m
最终速度:     V = 211.3 m/s
最终攻角:     α = 2.82 °
最终舵偏:     δ = 0.70 °
最终实际过载: ny = 0.45 g
最终指令过载: n^c = 1.44 g
最终脱靶量:   5354.8 m  (5.35 km)
最终质量:     m = 667.0 kg
最终动压:     q = 23445.5 Pa

============================================================
全程统计量
============================================================
攻角 α     最大: 10.11 °   最小: 1.94 °   平均: 4.72 °
舵偏 δ     最大: 2.47 °   最小: 0.00 °   平均: 1.17 °
实际过载 ny 最大: 1.66 g    最小: 0.42 g    平均: 0.74 g
指令过载 n^c 最大: 10.92 g   最小: 0.01 g   平均: 3.54 g

# -*- coding: utf-8 -*-
"""
优化版3:导弹纵向三自由度 + 比例导引 + 姿态控制环
- 已解决中文乱码(使用中文字体)
- 增大控制增益,让导弹能产生明显机动
- 调整过载方向与计算方式
"""

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import solve_ivp
import os

# === 解决中文乱码 ===
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'Arial Unicode MS']  # 优先使用 SimHei
plt.rcParams['axes.unicode_minus'] = False  # 负号显示正常

# ============================= 常数 =============================
g       = 9.8
rho     = 1.05
S       = 0.12
Jz      = 930.0

m0      = 673.0
mdot    = -0.12

P       = 265.0

Cx0     = 0.4
Cx_a    = 0.0778
Cy_a    = 0.3916
mz_a    = -0.0934
mz0     = -0.0036
Cy_de   = -0.08         # 反转符号 + 略增大
mz_de   = 0.38          # 反转符号 + 增大恢复力矩

b_A     = 1.2

# 控制参数(大幅提高增益,让导弹能转弯)
N       = 4.5           # 比例导引常数
Kp_n    = 0.35          # 过载比例增益(增大)
Kd_n    = 18.0          # 角速度阻尼(增大)
tau_e   = 0.10          # 舵面动态时间常数
delta_max     = 30.0    # 最大舵偏角度 °
delta_rate_max = 250.0  # 最大舵偏速率 °/s

# 初始状态
x0      = 0.0
y0      = 1500.0
V0      = 250.0
theta0  = 0.0 * np.pi/180
vartheta0 = 2.0 * np.pi/180   # 初始小扰动
omega0  = 0.0
delta0  = 0.0
integ0  = 0.0

xm      = 4900.0
ym      = 0.0

t_span  = (0, 50)
max_step = 0.004

OUTPUT_DIR = "missile_optimized_results"
os.makedirs(OUTPUT_DIR, exist_ok=True)

# ============================= 动力学 =============================
def dynamics(t, state):
    x, y, V, theta, vartheta, omega, delta_e, integ_n = state

    V = max(V, 10.0)
    m = max(m0 + mdot * t, 120.0)

    q    = 0.5 * rho * V**2
    alpha = vartheta - theta
    alpha_deg = np.degrees(alpha)

    Cx = Cx0 + Cx_a * abs(alpha_deg)
    Cy = Cy_a * alpha_deg + Cy_de * np.degrees(delta_e)
    mz = mz_a * alpha_deg + mz0 + mz_de * np.degrees(delta_e)

    X = q * S * Cx
    Y = q * S * Cy
    Mz = q * S * b_A * mz

    # 加速度(切向 & 法向)
    a_tang = (P * np.cos(alpha) - X - m * g * np.sin(theta)) / m
    a_norm = (P * np.sin(alpha) + Y - m * g * np.cos(theta)) / m

    dV_dt     = a_tang
    dtheta_dt = a_norm / V

    domega_dt = Mz / Jz
    dvartheta_dt = omega

    dx_dt = V * np.cos(theta)
    dy_dt = V * np.sin(theta)

    # 比例导引
    xr, yr = xm - x, ym - y
    r = np.sqrt(xr**2 + yr**2 + 1e-10)
    Vr = np.array([-V * np.cos(theta), -V * np.sin(theta)])
    los_rate = np.cross([xr, yr], Vr) / r**2
    r_dot = np.dot([xr, yr], Vr) / r

    n_cmd = N * abs(r_dot) * abs(los_rate) / g
    n_cmd = np.clip(n_cmd, -20, 30)

    # 当前过载(更直接用力计算)
    ny_meas = (Y + P * np.sin(alpha)) / (m * g)

    # 控制律
    e_n = n_cmd - ny_meas
    delta_cmd = Kp_n * e_n - Kd_n * omega   # 注意:这里未加负号,根据 mz_de 符号已调整
    delta_cmd = np.clip(delta_cmd, -delta_max, delta_max) * np.pi / 180

    ddelta_dt = (delta_cmd - delta_e) / tau_e
    ddelta_dt = np.clip(ddelta_dt, -delta_rate_max*np.pi/180, delta_rate_max*np.pi/180)

    d_integ_dt = e_n * 0.1   # 弱积分,防止累积过大

    dstate = [dx_dt, dy_dt, dV_dt, dtheta_dt, dvartheta_dt, domega_dt, ddelta_dt, d_integ_dt]

    aux = {
        'alpha_deg': alpha_deg,
        'ny': ny_meas,
        'n_cmd': n_cmd,
        'delta_deg': np.degrees(delta_e),
        'r': r,
        'm': m
    }

    return dstate, aux


def main():
    state0 = [x0, y0, V0, theta0, vartheta0, omega0, delta0, integ0]

    sol = solve_ivp(
        lambda t, y: dynamics(t, y)[0],
        t_span, state0,
        method='RK45',
        max_step=max_step,
        rtol=1e-6, atol=1e-8
    )

    if not sol.success:
        print("求解失败:", sol.message)
        return

    t = sol.t
    states = sol.y.T

    auxs = [dynamics(ti, yi)[1] for ti, yi in zip(t, states)]
    results = {k: np.array([a[k] for a in auxs]) for k in auxs[0]}

    # 绘图
    fig, axes = plt.subplots(3, 2, figsize=(14, 10))
    fig.suptitle('导弹三自由度纵向仿真结果(优化版)', fontsize=16)

    # 轨迹
    axes[0,0].plot(states[:,0], states[:,1], 'b-', lw=1.8)
    axes[0,0].plot(xm, ym, 'rx', ms=12, mew=2.5, label='目标')
    axes[0,0].grid(True, alpha=0.5)
    axes[0,0].set_xlabel('x (m)')
    axes[0,0].set_ylabel('y (m)')
    axes[0,0].set_title('弹道轨迹')
    axes[0,0].legend(loc='upper right')

    # 速度
    axes[0,1].plot(t, states[:,2], 'g-')
    axes[0,1].grid(True, alpha=0.5)
    axes[0,1].set_ylabel('速度 (m/s)')
    axes[0,1].set_title('速度随时间变化')

    # 攻角
    axes[1,0].plot(t, results['alpha_deg'], 'r-')
    axes[1,0].grid(True, alpha=0.5)
    axes[1,0].set_ylabel('攻角 (deg)')
    axes[1,0].set_title('攻角 α')

    # 过载
    axes[1,1].plot(t, results['ny'], 'b-', label='实际 ny')
    axes[1,1].plot(t, results['n_cmd'], 'orange', ls='--', label='指令 n^c')
    axes[1,1].grid(True, alpha=0.5)
    axes[1,1].legend()
    axes[1,1].set_ylabel('过载 (g)')
    axes[1,1].set_title('过载对比')

    # 舵偏
    axes[2,0].plot(t, results['delta_deg'], 'm-')
    axes[2,0].grid(True, alpha=0.5)
    axes[2,0].set_ylabel('舵偏 (deg)')
    axes[2,0].set_title('舵偏角 δ_e')

    # 距离
    axes[2,1].plot(t, results['r']/1000, 'c-')
    axes[2,1].grid(True, alpha=0.5)
    axes[2,1].set_ylabel('距离 (km)')
    axes[2,1].set_title('到目标距离')

    plt.tight_layout()

    filename = f"missile_opt3_t{int(t[-1])}s_miss{int(results['r'][-1])}m.png"
    savepath = os.path.join(OUTPUT_DIR, filename)
    plt.savefig(savepath, dpi=180, bbox_inches='tight')
    plt.close()

    print(f"仿真完成")
    print(f"最终位置: x = {states[-1,0]:.1f} m,  y = {states[-1,1]:.1f} m")
    print(f"最终脱靶量: {results['r'][-1]:.1f} m")
    print(f"图片已保存: {savepath}")


if __name__ == "__main__":
    main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值