比例导引详解(Proportional navigation guidance,PNG)-及Python程序

news2024/11/26 15:29:39

模型算法推导

比例导引是一种制导算法,其经典程度相当于控制器中的PID,在本文中,只对其二维平面的情况做分析,考虑一个拦截弹拦截机动目标(固定目标相当于目标速度为0),其运动如下图所示:

image-20230517103204578

M i M_i Mi T T T 代表第 i i i 枚拦截弹和目标;连线 M T MT MT 称为拦截弹 M i M_i Mi 与目标 T T T 的视线; r i r_i ri 为弹目间的相对距离, r i r_i ri 关于时间的导数表示为 r ˙ i \dot r_i r˙i q i q_i qi 为拦截弹 M i M_i Mi 视线角,其关于时间的导数为 q ˙ i \dot q_i q˙i V M , V T V_M,V_T VM,VT分别表示拦截弹和目标的速度。 θ i \theta_i θi 为弹目间速度方向与水平线的夹角,称为速度方向角。拦截弹和目标的前置角分别为 ψ i = q i − θ i \psi_i = q_i - \theta_i ψi=qiθi

考虑平面内拦截单一机动目标的制导问题,拦截弹与目标的相对运动关系可以用如下微分方程表示
r ˙ i = V T cos ⁡ ( q i − θ T ) − V M i cos ⁡ ( q i − θ M i ) r i q ˙ i = − V T sin ⁡ ( q i − θ T ) − V M i sin ⁡ ( q i − θ M i ) \begin{align} {\dot{r}}_{i} &= V_{T}\cos\left(q_{i}-\theta_{T}\right)-V_{Mi}\cos\left(q_{i}-\theta_{Mi}\right) \\ r_i {\dot{q}}_{i} &= - V_{T}\sin\left(q_{i}-\theta_{T}\right)-V_{Mi}\sin\left(q_{i}-\theta_{Mi}\right) \\ \end{align} r˙iriq˙i=VTcos(qiθT)VMicos(qiθMi)=VTsin(qiθT)VMisin(qiθMi)
拦截弹与目标的自身位置机动信息可以用如下微分方程表示
{ x ˙ i = V M i cos ⁡ ( θ M i ) y ˙ i = V M i sin ⁡ ( θ M i ) θ ˙ M i = a M i V M i \begin{cases} \dot x_i = V_{Mi} \cos(\theta_{Mi}) \\ \dot y_i = V_{Mi} \sin(\theta_{Mi}) \\ \dot \theta_{Mi} = \frac{a_{Mi}}{V_{Mi}} \\ \end{cases} x˙i=VMicos(θMi)y˙i=VMisin(θMi)θ˙Mi=VMiaMi
{ x ˙ i = V T cos ⁡ ( θ T ) y ˙ i = V T sin ⁡ ( θ T ) θ ˙ T = a T V T \begin{cases} \dot x_i = V_{T} \cos(\theta_{T}) \\ \dot y_i = V_{T} \sin(\theta_{T}) \\ \dot \theta_{T} = \frac{a_{T}}{V_{T}} \\ \end{cases} x˙i=VTcos(θT)y˙i=VTsin(θT)θ˙T=VTaT
比例导引法即使拦截弹速度矢量的旋转角速度与目标线旋转角速度成正比的一种导引方法,这样就可以保证拦截弹拦截到目标,即
a M i = N V M i q ˙ i a_{Mi} = N V_{Mi} \dot q_i aMi=NVMiq˙i
其中N为比例导引系数,一般为2-6之间的一个值,选值应该在 1 < N < ∞ 1<N<\infty 1<N<,比例导引法的弹道特性介于追踪法和平行接近法之间,比例系数越大,弹道越平直,需用法向过载越小。

python代码

我们这里考虑用python实现,并不是matlab,其一python的结构更加清晰一点,其二后期可能考虑用一些数据驱动的方法用在制导上,用python会更方便。程序的github地址为 https://github.com/professorli123/PNG.git

程序效果图,其中蓝线为拦截弹,黄线为目标

image-20230517103204578

main程序是文件的主程序

model程序定义了拦截弹模型,以及中间的视线角距离的计算模型

settings程序定义了一些配置

如果只是使用本程序,只需要考虑修改main程序和settings程序

main.py

# -*- encoding: utf-8 -*-
"""
@File       :   main.py
@Contact    :   lyajpunov@hust.edu.cn
@Author     :   Li Yajun
@Time       :   2023/9/21 9:11
@Version    :   1.0
@Desciption :   
"""

from model import missile, battle
import matplotlib.pyplot as plt
from settings import length

M0 = missile(0)
T0 = missile('T')
B = battle(M0, T0)

if __name__ == '__main__':
    for i in range(length - 10):
        a = 4 * M0.get_v() * B.get_dtheta_l()
        M0.step(a)
        T0.step(1)

        B.step()

        if B.get_r() < 1:
            print(B.get_r())
            break

plt.figure(1)
plt.plot(M0.x[:M0.pos], M0.y[:M0.pos])
plt.plot(T0.x[:T0.pos], T0.y[:T0.pos])
plt.show()

settings.py

# -*- encoding: utf-8 -*-
"""
@File       :   settings.py
@Contact    :   lyajpunov@hust.edu.cn
@Author     :   Li Yajun
@Time       :   2023/9/21 9:15
@Version    :   1.0
@Desciption :   
"""

# 最长仿真时间
t = 100
# 仿真步长
dt = 1e-3
# 预留数组长度
length = int(t / dt)

data = {
    0: {
        'x': 0,
        'y': 0,
        'v': 300,
        'theta': 0,
    },

    'T': {
        'x': 10000,
        'y': 10000,
        'v': 50,
        'theta': 0,
    },
}

model.py

# -*- encoding: utf-8 -*-
"""
@File       :   model.py
@Contact    :   lyajpunov@hust.edu.cn
@Author     :   Li Yajun
@Time       :   2023/9/21 9:11
@Version    :   1.0
@Desciption :
"""

import numpy as np
from settings import dt, length, data


class missile:
    def __init__(self, name):
        self.pos = 0
        self.name = name
        self.length = length
        # x轴位置
        self.x = np.zeros(self.length, dtype='float64')
        # y轴位置
        self.y = np.zeros(self.length, dtype='float64')
        # 速度
        self.v = np.zeros(self.length, dtype='float64')
        # 弹道倾角
        self.theta = np.zeros(self.length, dtype='float64')
        # 控制量:加速度
        self.a = np.zeros(self.length, dtype='float64')
        # 停止标志位
        self.end = False
        # 初始化,重置
        self.reset()

    def reset(self):
        self.pos = 0
        self.x[self.pos] = data[self.name]['x']
        self.y[self.pos] = data[self.name]['y']
        self.v[self.pos] = data[self.name]['v']
        self.theta[self.pos] = np.deg2rad(data[self.name]['theta'])

    def step(self, a):
        # 如果已经结束直接返回
        if self.end:
            return

        # 保存控制量
        self.a[self.pos] = a

        # 形成向量进行迭代
        vector = np.array([self.x[self.pos],
                           self.y[self.pos],
                           self.v[self.pos],
                           self.theta[self.pos],
                           self.a[self.pos], ])
        k1 = dt * self.iterateOnce(vector)
        k2 = dt * self.iterateOnce(vector + 0.5 * k1)
        k3 = dt * self.iterateOnce(vector + 0.5 * k2)
        k4 = dt * self.iterateOnce(vector + k3)
        vector = vector + (k1 + 2 * k2 + 2 * k3 + k4) / 6

        # 保存迭代数据
        self.pos += 1
        self.x[self.pos] = vector[0]
        self.y[self.pos] = vector[1]
        self.v[self.pos] = vector[2]
        self.theta[self.pos] = vector[3]

    def iterateOnce(self, vector):
        x, y, v, theta, a = vector[0], vector[1], vector[2], vector[3], vector[4]

        _x = v * np.cos(theta)
        _y = v * np.sin(theta)
        _v = 0
        _theta = a / v
        _a = 0

        return np.array([_x, _y, _v, _theta, _a])

    '''以下为接口函数'''
    def get_x(self):
        return self.x[self.pos]

    def get_y(self):
        return self.y[self.pos]

    def get_v(self):
        return self.v[self.pos]

    def get_a(self):
        return self.a[self.pos]

    def get_theta(self):
        return self.theta[self.pos]


class battle:
    def __init__(self, M, T):
        self.pos = 0
        self.M = M
        self.T = T
        self.length = length
        # 距离及其导数
        self.r = np.zeros(self.length, dtype='float64')
        self.dr = np.zeros(self.length, dtype='float64')
        # 视线倾角及其导数
        self.theta_l = np.zeros(self.length, dtype='float64')
        self.dtheta_l = np.zeros(self.length, dtype='float64')
        # 初始化
        self.reset()

    def reset(self):
        self.pos = 0
        d_x = self.T.get_x() - self.M.get_x()
        d_y = self.T.get_y() - self.M.get_y()
        d_vx = self.T.get_v() * np.cos(self.T.get_theta()) - self.M.get_v() * np.cos(self.M.get_theta())
        d_vy = self.T.get_v() * np.sin(self.T.get_theta()) - self.M.get_v() * np.sin(self.M.get_theta())

        r = np.sqrt(d_x * d_x + d_y * d_y)
        d_r = (d_x * d_vx + d_y * d_vy) / r
        theta_l = np.arctan(d_y / d_x)
        dtheta_l = d_x * d_x * (d_vy * d_x - d_vx * d_y) / (r * r) / (d_vx * d_vx)

        self.r[self.pos] = r
        self.dr[self.pos] = d_r
        self.theta_l[self.pos] = theta_l
        self.dtheta_l[self.pos] = dtheta_l

    def step(self):
        self.pos += 1

        d_x = self.T.get_x() - self.M.get_x()
        d_y = self.T.get_y() - self.M.get_y()
        d_vx = self.T.get_v() * np.cos(self.T.get_theta()) - self.M.get_v() * np.cos(self.M.get_theta())
        d_vy = self.T.get_v() * np.sin(self.T.get_theta()) - self.M.get_v() * np.sin(self.M.get_theta())

        r = np.sqrt(d_x * d_x + d_y * d_y)
        d_r = (d_x * d_vx + d_y * d_vy) / r
        theta_l = np.arctan(d_y / d_x)
        dtheta_l = d_x * d_x * (d_vy * d_x - d_vx * d_y) / (r * r) / (d_vx * d_vx)

        self.r[self.pos] = r
        self.dr[self.pos] = d_r
        self.theta_l[self.pos] = theta_l
        self.dtheta_l[self.pos] = dtheta_l

    '''下面是接口函数'''
    def get_r(self):
        return self.r[self.pos]

    def get_dr(self):
        return self.dr[self.pos]

    def get_theta_l(self):
        return self.theta_l[self.pos]

    def get_dtheta_l(self):
        return self.dtheta_l[self.pos]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1042638.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

变配电智能化系统:提高效率与安全性

随着科技的发展&#xff0c;电力系统正在逐步向智能化、数字化方向转型。变配电系统作为电力系统的重要组成部分&#xff0c;其智能化水平直接影响着电力系统的运行效率和稳定性。 一、系统概述 力安科技变配电智能化系统是一种采用先进技术&#xff0c;实现对变配电设…

DD5 进制转换

目录 一、题目 二、分析 三、代码 一、题目 进制转换_牛客题霸_牛客网 二、分析 三、代码 #include <iostream> #include <vector> #include <string> using namespace std; string Greater_than_Ten(int digit)//余数大于等于10的时候转换成对应的字母…

低照度增强算法(图像增强+目标检测+代码)

本文介绍 在增强低光图像时&#xff0c;许多深度学习算法基于Retinex理论。然而&#xff0c;Retinex模型并没有考虑到暗部隐藏的损坏或者由光照过程引入的影响。此外&#xff0c;这些方法通常需要繁琐的多阶段训练流程&#xff0c;并依赖于卷积神经网络&#xff0c;在捕捉长距…

从零搭建开发脚手架 顺应潮流开启升级 - SpringBoot 从2.x 升级到3.x

文章目录 涉及升级项导入包修改SpringBoot3.x中spring.factories功能被移除 涉及升级项 升级JDK 8 -> JDK17 Spring Boot 2.3.7 -> Spring Boot 3.1.3 Mysql5.7.x -> Mysql8.x Mybatis-Puls 3.4.2 -> 3.5.3 knife4j 2.x -> 4.3.x sa-token 1.24.x -> 1.…

Apache Derby的使用

Apache Derby是关系型数据库&#xff0c;可以嵌入式方式运行&#xff0c;也可以独立运行&#xff0c;当使用嵌入式方式运行时常用于单元测试&#xff0c;本篇我们就使用单元测试来探索Apache Derby的使用 一、使用IDEA创建Maven项目 打开IDEA创建Maven项目&#xff0c;这里我…

C++: 模板(进阶)

学习目标 1.了解非类型模板参数 2.了解类模板的特化 3.知道模板分离编译会出现的问题 1.非类型模板参数(整型常量) 模板参数: 1.类型形参:在模板参数列表中,class/typename后的参数名称 2.非类型形参:整型常量 示例: template<class T ,size_t N>class arr{public://....…

Docker和Docker compose的安装使用指南

一&#xff0c;环境准备 Docker运行需要依赖jdk&#xff0c;所以需要先安装一下jdk yum install -y java-1.8.0-openjdk.x86_64 二&#xff0c;Docker安装和验证 1&#xff0c;安装依赖工具 yum install -y yum-utils 2&#xff0c;设置远程仓库 yum-config-manager --add-r…

什么是AI问答机器人?它的应用场景有哪些?

近年来&#xff0c;由于技术的进步和对个性化客户体验的需求不断增长&#xff0c;AI问答机器人也是获得了巨大的关注。AI问答机器人&#xff0c;也被称为AI聊天机器人&#xff0c;是一种旨在模拟人类对话并通过基于文本或语音的界面与用户交互的计算机程序。其能够自动执行各种…

idea Springboot在线商城系统VS开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 springboot 在线商城系统是一套完善的信息系统&#xff0c;结合springboot框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用springboot框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有 完整的源代码和数据库&…

SpringCloud篇

SpringCloud五大组件是啥&#xff1f; rabbin gateway feign 注册中心&#xff08;nacos,Eureka&#xff09;,服务保护 &#xff08;sentinel&#xff09; &#xff1b; nacos和eureka的区别是什么&#xff1f; 负载均衡是如何实现的&#xff1f;&#xff1f; ribbon负载策略…

kaggle新赛:Optiver 美股价格预测赛题解析

赛题名称&#xff1a;Optiver - Trading at the Close 赛题链接&#xff1a;https://www.kaggle.com/competitions/optiver-trading-at-the-close 赛题背景 证券交易所是快节奏、高风险的环境&#xff0c;每一秒都很重要。随着交易日接近尾声&#xff0c;强度不断升级&#…

常见逻辑漏洞总结

Web安全测试中常见逻辑漏洞解析&#xff08;实战篇&#xff09; 简要&#xff1a; 越权漏洞是比较常见的漏洞类型&#xff0c;越权漏洞可以理解为&#xff0c;一个正常的用户A通常只能够对自己的一些信息进行增删改查&#xff0c;但是由于程序员的一时疏忽&#xff0c;对信息…

2024年浙江理工大学MBA项目报考形势如何?

浙江理工大学MBA项目怎么样&#xff0c;值不值得报考&#xff1f;2024年的最新招生政策已经出来&#xff0c;浙江理工大学MBA项目有全日制和非全日制两个MBA方向招生&#xff0c;分别招收19人和52人&#xff0c;总体招生规模不大&#xff0c;这也是浙江理工大学MBA项目近些年的…

锐思WMS和金蝶云星辰V1单据接口对接

锐思WMS和金蝶云星辰V1单据接口对接 来源系统:金蝶云星辰V1 金蝶云星辰基于金蝶云苍穹云原生PaaS平台构建&#xff0c;聚焦小型企业在线经营和数字化管理&#xff0c;提供财务云、税务云、进销存云、零售云、订货商城等SaaS服务&#xff0c;支持企业拓客开源、智能管理、实时决…

批量删除wordpress文章修订版本/自动草稿残留数据(3种方法)及四种方法禁用WordPress文章历史修订/自动保存/自动草稿功能

目录 1、批量删除wordpress文章修订版本/自动草稿残留数据&#xff08;3种方法&#xff09; 方法一&#xff1a;SQL命令批量删除 命令&#xff1a; 方法二&#xff1a;利用PHP代码来删除 方法三&#xff1a;利用数据库清理优化插件 WP Clean Up 或 WP Cleaner 批量删除 2…

VEX —— Functions|Math

目录 sign —— 返回给定数的符号标签 abs —— 返回绝对值 avg —— 返回平均值 sum —— 求和 max —— 返回最大值 min —— 返回最小值 rint —— 返回四舍五入后的整数 ceil —— 返回最近的最大整数 floor —— 返回最近的最小整数 frac —— 返回浮点值的小数…

8个值得收藏的免费激光点云数据集

推荐&#xff1a;用 NSDT编辑器 快速搭建可编程3D场景 在 3D 城市点云分析领域&#xff0c;存在多种方法&#xff0c;包括半自动和自动方法。 尽管该领域显示出巨大的潜力&#xff0c;但尚未就最佳检测、分割和分类方法达成共识。 为了鼓励创新&#xff0c;我们收集了 8个免费的…

怎样设置每个月的10号提醒?可每月触发提醒的软件是哪个

在每个月当中总是会有一些需要按时提醒的事情&#xff0c;如每月10号提醒换房贷、每月10号提醒还信用卡、每月10号提醒续交车贷等&#xff0c;当然每月像这样的事情是比较多的&#xff0c;怎样设置每个月的10号提醒自己呢&#xff1f; 可以用来设定定时提醒的工具是比较多的&a…

vue3黑马笔记

一、创建vue3项目 需要node16版本或者以上&#xff0c; npm init vuelatest二、vue3模块 在vue3中所有的创建都用了函数封装&#xff0c;保证了每个实例的独立性 三、setup 1、setup选项 setup组合式api 1、执行时间比beforeCreate还早 2、setup函数&#xff0c;获取不到this…

M1/M2芯片Parallels Desktop 19安装使用教程(超详细)

引言 在Window上VMware最强&#xff0c;在Mac上毫无疑问Parallels Desktop为最强&#xff01; 今天带来的是最新版Parallels Desktop 19的安装使用教程。 1. 下载安装包 Parallels Desktop 19安装包&#xff1a;https://www.aliyundrive.com/s/ThB8Fs6D3AD Parallels Deskto…