dogfight问题中(UAV 无人机空战——狗斗)—— 状态空间设计

image




  1. 完整状态空间定义(Python)

import numpy as np
from gymnasium import spaces

class AirCombatStateSpace:
    def __init__(self):
        # --------------------------
        # 状态项索引(对应表1序号)
        # --------------------------
        self.state_dim = 20
        
        # 1. 对方飞机距离/km: 0~150 → 归一化到 [0,1]
        # 2. 对方飞机方位角/°: -180~180 → 归一化到 [-1,1]
        # 3. 对方飞机俯仰角/°: -90~90 → 归一化到 [-1,1]
        # 4. 对方雷达状态: 关机/扫描/跟踪 → 离散 0/1/2
        # 5. 对方剩余武器数量: 0~6 → 归一化到 [0,1]
        # 6. 对方武器状态: 未发射/在飞 → 离散 0/1
        # 7. 对方武器方位角/°: -180~180 → 归一化到 [-1,1]
        # 8. 对方武器俯仰角/°: -90~90 → 归一化到 [-1,1]
        # 9. 我方飞机速度/(m·s⁻¹): 300~600 → 归一化到 [0,1]
        # 10. 我方飞机航向角/°: -180~180 → 归一化到 [-1,1]
        # 11. 我方飞机俯仰角/°: -90~90 → 归一化到 [-1,1]
        # 12. 我方飞机滚转角/°: -180~180 → 归一化到 [-1,1]
        # 13. 我方剩余油量/kg: 0~4500 → 归一化到 [0,1]
        # 14. 我方雷达状态: 关机/扫描/跟踪 → 离散 0/1/2
        # 15. 我方雷达已失跟时间/s: 0~150 → 归一化到 [0,1]
        # 16. 我方雷达已开机时间/s: 0~10 → 归一化到 [0,1]
        # 17. 我方雷达已关机时间/s: 0~10 → 归一化到 [0,1]
        # 18. 干扰已持续时间/s: 0~10 → 归一化到 [0,1]
        # 19. 我方剩余武器数量: 0~6 → 归一化到 [0,1]
        # 20. 我方武器状态: 未发射/在飞 → 离散 0/1

        # --------------------------
        # 状态空间(连续 + 离散 统一为 Box 空间)
        # --------------------------
        # 为了兼容大部分 RL 框架,这里把所有状态都转为连续 [-1,1] 或 [0,1]
        # 也可以用 spaces.Dict 或 spaces.Tuple 处理混合空间
        self.observation_space = spaces.Box(
            low=-1.0,
            high=1.0,
            shape=(self.state_dim,),
            dtype=np.float32
        )

    def normalize_state(self, raw_state):
        """
        将原始状态(20维)归一化到 [-1,1] / [0,1] 范围
        输入: raw_state: list/array, 长度 20,对应表1各项原始值
        输出: normalized_state: np.array, shape=(20,), 范围 [-1,1]
        """
        s = np.array(raw_state, dtype=np.float32)
        normalized = np.zeros_like(s)

        # 1. 对方飞机距离 0~150 km → [0,1]
        normalized[0] = np.clip(s[0] / 150.0, 0.0, 1.0)

        # 2. 对方飞机方位角 -180~180° → [-1,1]
        normalized[1] = np.clip(s[1] / 180.0, -1.0, 1.0)

        # 3. 对方飞机俯仰角 -90~90° → [-1,1]
        normalized[2] = np.clip(s[2] / 90.0, -1.0, 1.0)

        # 4. 对方雷达状态(0:关机,1:扫描,2:跟踪)→ [0,1]
        normalized[3] = np.clip(s[3] / 2.0, 0.0, 1.0)

        # 5. 对方剩余武器数量 0~6 → [0,1]
        normalized[4] = np.clip(s[4] / 6.0, 0.0, 1.0)

        # 6. 对方武器状态(0:未发射,1:在飞)→ [0,1]
        normalized[5] = np.clip(s[5], 0.0, 1.0)

        # 7. 对方武器方位角 -180~180° → [-1,1]
        normalized[6] = np.clip(s[6] / 180.0, -1.0, 1.0)

        # 8. 对方武器俯仰角 -90~90° → [-1,1]
        normalized[7] = np.clip(s[7] / 90.0, -1.0, 1.0)

        # 9. 我方飞机速度 300~600 m/s → [0,1]
        normalized[8] = np.clip((s[8] - 300.0) / 300.0, 0.0, 1.0)

        # 10. 我方飞机航向角 -180~180° → [-1,1]
        normalized[9] = np.clip(s[9] / 180.0, -1.0, 1.0)

        # 11. 我方飞机俯仰角 -90~90° → [-1,1]
        normalized[10] = np.clip(s[10] / 90.0, -1.0, 1.0)

        # 12. 我方飞机滚转角 -180~180° → [-1,1]
        normalized[11] = np.clip(s[11] / 180.0, -1.0, 1.0)

        # 13. 我方剩余油量 0~4500 kg → [0,1]
        normalized[12] = np.clip(s[12] / 4500.0, 0.0, 1.0)

        # 14. 我方雷达状态(0:关机,1:扫描,2:跟踪)→ [0,1]
        normalized[13] = np.clip(s[13] / 2.0, 0.0, 1.0)

        # 15. 我方雷达已失跟时间 0~150 s → [0,1]
        normalized[14] = np.clip(s[14] / 150.0, 0.0, 1.0)

        # 16. 我方雷达已开机时间 0~10 s → [0,1]
        normalized[15] = np.clip(s[15] / 10.0, 0.0, 1.0)

        # 17. 我方雷达已关机时间 0~10 s → [0,1]
        normalized[16] = np.clip(s[16] / 10.0, 0.0, 1.0)

        # 18. 干扰已持续时间 0~10 s → [0,1]
        normalized[17] = np.clip(s[17] / 10.0, 0.0, 1.0)

        # 19. 我方剩余武器数量 0~6 → [0,1]
        normalized[18] = np.clip(s[18] / 6.0, 0.0, 1.0)

        # 20. 我方武器状态(0:未发射,1:在飞)→ [0,1]
        normalized[19] = np.clip(s[19], 0.0, 1.0)

        return normalized.astype(np.float32)

    def denormalize_state(self, normalized_state):
        """
        将归一化的状态 [-1,1]/[0,1] 转回原始范围(可选,用于调试/可视化)
        """
        s = np.array(normalized_state, dtype=np.float32)
        raw = np.zeros_like(s)

        raw[0] = s[0] * 150.0
        raw[1] = s[1] * 180.0
        raw[2] = s[2] * 90.0
        raw[3] = s[3] * 2.0
        raw[4] = s[4] * 6.0
        raw[5] = s[5]
        raw[6] = s[6] * 180.0
        raw[7] = s[7] * 90.0
        raw[8] = s[8] * 300.0 + 300.0
        raw[9] = s[9] * 180.0
        raw[10] = s[10] * 90.0
        raw[11] = s[11] * 180.0
        raw[12] = s[12] * 4500.0
        raw[13] = s[13] * 2.0
        raw[14] = s[14] * 150.0
        raw[15] = s[15] * 10.0
        raw[16] = s[16] * 10.0
        raw[17] = s[17] * 10.0
        raw[18] = s[18] * 6.0
        raw[19] = s[19]

        return raw




  1. 使用示例(在自定义 Gym 环境中)

from gymnasium import Env

class AirCombatEnv(Env):
    def __init__(self):
        super().__init__()
        self.state_helper = AirCombatStateSpace()
        self.observation_space = self.state_helper.observation_space
        # 动作空间可根据你的控制量自行定义
        self.action_space = spaces.Discrete(...)  # 或 spaces.Box(...)

    def _get_observation(self):
        # 假设从仿真中读取原始状态 raw_state (长度20)
        raw_state = self._read_raw_state_from_simulation()
        # 归一化后返回给 RL 算法
        obs = self.state_helper.normalize_state(raw_state)
        return obs

    def _read_raw_state_from_simulation(self):
        # 这里替换为你实际读取仿真数据的代码
        return np.zeros(20)




image






posted on 2026-06-27 15:32  Angry_Panda  阅读(3)  评论(0)    收藏  举报

导航