卡尔曼滤波算法demo

news2024/12/23 9:17:20

在这里插入图片描述

代码

learn_kalman.py

#coding=utf-8
import numpy as np
import time
from kinematic_model import freedrop
from controller import kalman_filter

import matplotlib.pyplot as plt
#   支持中文
import matplotlib as mpl
mpl.rcParams['font.family']='SimHei'
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号

class Scene:
    '''
        场景
    '''
    def __init__(self,windSpd=np.array([0.7,0.3,0.0]),\
                 initialSpd=np.array([120.0,0.0,120.0])):
        '''
            我现在是一个防空兵
            防空炮打出一枚炮弹,真实的炮弹轨迹,它可能会受风的影响,可能会有随机因素导致偏离目标导致打不中飞机...
            我们可以使用指挥所观测到的炮弹轨迹,因为炮弹距离很远,所以这个观测不是很靠谱...
            所以我们所使用了卡尔曼滤波算法,得到了一条真实的炮弹轨迹...
        '''
        #   真实的炮弹
        self.realShell=freedrop.FreeDropBinder(windSpd=windSpd,initialSpd=initialSpd)
        #   理论上炮弹的落点
        self.theoShell=freedrop.FreeDropBinder(windSpd=np.array([0.0,0.0,0.0]),initialSpd=initialSpd,randRatio=0.0)
        #   卡卡尔曼滤波器
        self.kf=kalman_filter.KF_Onmi3D()
        self.kf.initState[3:6]=initialSpd

        #   绘图区
        self.fig=plt.figure('炮弹弹道图')
        self.ax = self.fig.gca(projection="3d")


        #   数据缓存
        self.realCoord=[]
        self.theoCoord=[]
        self.kalmanCoord=[]
        self.observeCoord=[]

    def UpdateData(self,delta_t=0.2):
        '''
            更新虚拟环境的数据
        :return:
        '''
        #   真实炮弹轨迹
        self.realShell.StateUpdate(delta_t=delta_t)
        #   理论炮弹轨迹
        self.theoShell.StateUpdate(delta_t=delta_t)
        #   观测到的炮弹轨迹
        self.observeCoord.append(self.realShell.position + np.random.random(3) * self.realShell.position[0]/20.0 - self.realShell.position[0]/40.0)
        #   卡尔曼滤波
        '''
            基于卡尔曼滤波,结合理论炮弹轨迹 对观测的炮弹轨迹进行修正
        '''
        self.kf.Predict(velocity=self.theoShell.spd)
        Hybrid_Position=self.kf.Update(self.observeCoord[-1])
        #   绘图(真实的弹道)
        plt.cla()
        self.ax.set_xlim(0, 1000)
        self.ax.set_ylim(-200, 200)
        self.ax.set_zlim(0, 300)
        self.ax.set_xlabel("X坐标(米)")
        self.ax.set_ylabel("Y坐标(米)")
        self.ax.set_zlabel("X坐标(米)")
        #   计算三个类型的炮弹

        self.realCoord.append(np.copy(self.realShell.position))     #   真实炮弹
        self.theoCoord.append(np.copy(self.theoShell.position))     #   理论模型
        self.kalmanCoord.append(np.copy(Hybrid_Position))


        self.curve2Draw=np.array(self.realCoord)
        self.curve2 = np.array(self.observeCoord)
        self.curve3 = np.array(self.theoCoord)
        self.curve4 = np.array(self.kalmanCoord)

        self.ax.plot(self.curve2Draw[:,0],self.curve2Draw[:,1],self.curve2Draw[:,2],label='真实炮弹',color='red')
        self.ax.scatter(self.curve2[:, 0], self.curve2[:, 1], self.curve2[:, 2],'rv+', label='炮弹观测数据', color='blue',alpha=0.5,s=1)
        self.ax.plot(self.curve3[:, 0], self.curve3[:, 1], self.curve3[:, 2], label='炮弹理论轨迹', color='green', alpha=0.5)
        self.ax.plot(self.curve4[:, 0], self.curve4[:, 1], self.curve4[:, 2], label='炮弹融合轨迹', color='yellow', alpha=1.0)
        self.ax.legend()
        plt.pause(0.05)

#   开始模拟环境
#plt.ion()

s=Scene()

for i in range(1000):
    if s.realShell.position[2]<0: break
    s.UpdateData()
plt.ioff()
plt.show()

freerop.py

#coding=utf-8
import time

import numpy as np
'''
    3D自由落体模型(含有风阻)
'''

class FreeDropBinder:
    '''
        为实体绑定自由落体属性
    '''
    def __init__(self,windSpd=np.array([0.0,0.0,0.0]),
                 resRatio=0.0004,
                 G=9.8,
                 initialPos=np.array([0.0,0.0,0.0]),
                 initialSpd=np.array([0.0,0.0,0.0]),
                 randRatio=0.1):
        '''
        :param windSpd:  风速(三维)
        :param resRatio: 风阻比例(全向)
        :param G: 重力加速度
        :param initialPos:  物体初始位置
        :param initialSpd:  物体初始速度
        '''
        self.position=initialPos
        self.spd=initialSpd
        self.windSpd=windSpd
        self.resRatio=resRatio
        self.G=G
        self.randRatio=randRatio

    def StateUpdate(self,delta_t=0.05,driveForce=np.array([0.0,0.0,0.0])):
        '''
        更新实体位置信息
        :param delta_t:
        :return:
        '''
        #   重力因素
        self.spd+=np.array([0,0,-self.G*delta_t])
        #   风阻因素
        self.spd=np.where(self.spd>0,self.spd-self.resRatio*self.spd*self.spd,self.spd)
        self.spd = np.where(self.spd <= 0, self.spd + self.resRatio * self.spd * self.spd, self.spd)
        #   风力因素

        #   驱动因素
        self.spd+=(driveForce+self.windSpd)*delta_t
        #   随机因素
        self.spd+=(np.random.rand(3)-0.5)*2*self.randRatio*delta_t
        #   更新坐标
        self.position=self.position+self.spd*delta_t

if __name__=='__main__':

    box=FreeDropBinder(initialSpd=np.array([10.0,0.0,100.0]))

    for i in range(30):
        print(box.Update())

kalman_filter.py

import numpy as np
import matplotlib.pyplot as plt

class KF_Onmi3D:
    '''
        三维,无方向场景下的卡尔曼滤波算法模组
    '''
    def __init__(self):
        # 初始状态                 x  y  z vx vy vz
        self.initState=np.array([0, 0, 0, 0, 0, 0],dtype=np.float)
        # 初始协方差,可以看出是每个维度都是一一对应的关系
        '''
        [ 1 0 0 0 0 0 ]
        [ 0 1 0 0 0 0 ]
        [ 0 0 1 0 0 0 ]
        [ 0 0 0 1 0 0 ]
        [ 0 0 0 0 1 0 ]
        [ 0 0 0 0 0 1 ]
        '''
        self.initCov=np.eye(6)
        #   状态转移矩阵
        self.stateTransMatrix=np.array([[1,0,0,1,0,0],
                                      [0,1,0,0,1,0],
                                      [0,0,1,0,0,1],
                                      [0,0,0,1,0,0],
                                      [0,0,0,0,1,0],
                                      [0,0,0,0,0,1]],dtype=np.float)
        #   观测矩阵                    X  Y  Z  Vx Vy Vz
        self.observeMatrix=np.array([[1, 0, 0, 0, 0, 0],
                                     [0, 1, 0, 0, 0, 0],
                                     [0, 0, 1, 0, 0, 0]],dtype=np.float)
        #   过程噪声(先设定一个初始值,这个需要跟据你系统的评估来确定)
        self.procNoise=np.eye(6)*0.001
        #   观测噪声的协方差矩阵
        self.observeNoiseCov=np.eye(3)*1
        self.InitParams()
    def InitParams(self):
        '''
        初始化状态变量
        :return:
        '''
        self.currentState=self.initState.copy()
        self.predictState=self.initState.copy()
        self.currentCov=self.initCov
        self.predictedCov=self.currentCov

    def Predict(self,velocity=np.array([0,0,0],dtype=np.float)):
        '''
            预测过程
            :param v:
            :return:
        '''


        #   基于当前的速度,预测机器人下一个状态的状态数值
        self.predictState=self.stateTransMatrix.dot(self.currentState)
        #   预测三维环境下的协方差矩阵
        self.predictedCov=self.stateTransMatrix.dot(self.currentCov).dot(self.stateTransMatrix.T)+self.procNoise
        #   把速度赋值给状态中的“速度”属性
        self.currentState[3:6] = velocity

    def Update(self,observed_Pos=np.array([0,0,0],dtype=np.float)):
        '''
        更新数据
            :param observed_Pos: 带有误差的位置观测值
            :return:
        '''
        #   卡尔曼增益(Kalman Gain)计算
        '''
            K=\frac{估计的误差}{估计的误差+测量的误差}=\frac{\hat{P_k}C}{C\hat{P_k}C^T+Error}
        '''
        self.Kalman_Gain = self.predictedCov.dot(self.observeMatrix.T) \
            .dot(np.linalg.inv( \
            self.observeMatrix.dot(self.predictedCov).dot(self.observeMatrix.T) + self.observeNoiseCov))

        '''
            基于Kalman Gain估算当前状态
        '''
        self.currentState = self.predictState + self.Kalman_Gain.dot(observed_Pos-self.observeMatrix.dot(self.predictState))

        '''
            当前协方差估计
        '''
        self.currentCov = (np.eye(6) - self.Kalman_Gain.dot(self.observeMatrix)).dot(self.predictedCov)

        return self.currentState[0:3]

参考

https://www.bilibili.com/video/BV1gF411f78t/?spm_id_from=333.337.top_right_bar_window_history.content.click&vd_source=667c3d14dbb51ec849c0bc7c38329d10

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

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

相关文章

每天一道leetcode:剑指Offer 25.合并两个链表

今日份题目&#xff1a; 输入两个递增排序的链表&#xff0c;合并这两个链表并使新链表中的节点仍然是递增排序的。 示例 输入&#xff1a;1->2->4, 1->3->4 输出&#xff1a;1->1->2->3->4->4 提示 0 < 链表长度 < 1000 题目思路 递归…

BL302嵌入式ARM控制器:高性能处理器驱动的储能优化利器

嵌入式ARM控制器钡铼技术BL302系列是工业级坚固型工业控制器&#xff0c;采用NXP的高性能处理器I.MX6ULL&#xff0c;搭配先进的ARM Cortex-A7构架&#xff0c;运行速度高达800MHz&#xff0c;具有高度的稳定性。本产品最高可提供4路RS485/RS232&#xff0c;1路CAN口&#xff0…

嵌入式开发学习(STC51-13-温度传感器)

内容 通过DS18B20温度传感器&#xff0c;在数码管显示检测到的温度值&#xff1b; DS18B20介绍 简介 DS18B20是由DALLAS半导体公司推出的一种的“一线总线&#xff08;单总线&#xff09;”接口的温度传感器&#xff1b; 与传统的热敏电阻等测温元件相比&#xff0c;它是一…

SpringBoot整合达梦数据库

近期接到了一个需要国产化的项目&#xff0c;用到了达梦数据库&#xff0c;没想到一开始配置就出现了问题&#xff0c;下面把配置给大家粘贴出来&#xff0c;大家少踩点坑。 一、先下载达梦数据库 这是达梦数据库下载链接&#xff0c;达梦数据库没有免费的&#xff0c;个人好…

Chapter 12: Regular expressions | Python for Everybody 讲义笔记_En

文章目录 Python for Everybody课程简介Regular ExpressionsRegular ExpressionsCharacter matching in regular expressionsExtracting data using regular expressionsCombining searching and extractingEscape characterSummaryBonus section for Unix / Linux usersDebugg…

[保研/考研机试] 约瑟夫问题No.2 C++实现

题目要求&#xff1a; 输入、输出样例&#xff1a; 源代码&#xff1a; #include<iostream> #include<queue> #include<vector> using namespace std;//例题5.2 约瑟夫问题No.2 int main() {int n, p, m;while (cin >> n >> p >> m) {//如…

【LeetCode】字符串与栈的练习

字符串相乘 class Solution { public:/** 将两个字符串相乘拆分成两步&#xff1a;* 先将一个字符串的每个字符与另一个字符串相乘得到一个计算结果* 再将所有计算结果的字符串进行相加*/string multiply(string num1, string num2) {string result "0";// 一个字…

微服务——es数据聚合+RestClient实现聚合

数据聚合 聚合的种类 DSL实现Bucket聚合 如图所示&#xff0c;设置了10个桶&#xff0c;那么就显示了数量最多的前10个桶&#xff0c;品牌含有7天酒店的有30家&#xff0c; 品牌含有如家的也有30家。 修改排序规则 限定聚合范围 DSL实现Metrics聚合 如下案例要求对不同的品…

录像模糊变高清:提高录制视频清晰度的方法

录像是记录生活点滴的重要方式之一&#xff0c;然而&#xff0c;由于种种原因&#xff0c;我们可能会遇到一些模糊、不清晰的视频。为了解决这一问题&#xff0c;今天来给大家分享一下如何利用牛学长视频修复工具修复录像视频清晰度的方法&#xff0c;方便快捷&#xff0c;无需…

springBoot集成caffeine,自定义缓存配置 CacheManager

目录 springboot集成caffeine Maven依赖 配置信息&#xff1a;properties文件 config配置 使用案例 Caffeine定制化配置多个cachemanager springboot集成redis并且定制化配置cachemanager springboot集成caffeine Caffeine是一种基于服务器内存的缓存库。它将数据存储在…

批量查询快递信息的最佳解决方案

快递查询是我们日常生活中经常需要进行的操作&#xff0c;然而&#xff0c;当我们有多个快递单号需要查询时&#xff0c;逐个查询就显得非常繁琐和耗时。为了解决这个问题&#xff0c;今天给大家推荐一款实用的软件——【固乔快递查询助手】。 首先&#xff0c;在浏览器中搜索并…

Activity启动过程详解(Android 12源码分析)

Activity的启动方式 启动一个Activity&#xff0c;通常有两种情况&#xff0c;一种是在应用内部启动Activity&#xff0c;另一种是Launcher启动 1、应用内启动 通过startActivity来启动Activity 启动流程&#xff1a; 一、Activity启动的发起 二、Activity的管理——ATMS 三、…

Mysql根据创建时间表分区实践

背景 最近订单表遇到大数据量的问题&#xff0c;并且表中随着时间的积累会变得更大&#xff0c;当数据量较大时&#xff0c;存储的物理文件会变得非常大、使用性能很差。 我们用的是GaussDB。为了提高查询效率&#xff0c;建议表大于500w进行分区&#xff0c;所以在规划阶段我…

opencv基础47 查找图像轮廓cv2.findContours()详解

什么是图像轮廓&#xff1f; 图像轮廓是指图像中物体边缘的连续性曲线。在计算机视觉和图像处理中&#xff0c;轮廓通常被用于检测物体、分割图像以及提取物体特征。 图像轮廓是由一系列连续的像素点组成&#xff0c;这些像素点位于物体边界上。轮廓的特点是在物体和背景之间的…

springboot生成表结构和表数据sql

需求 业务背景是需要某单机程序需要把正在进行的任务导出&#xff0c;然后另一台电脑上单机继续运行&#xff0c;我这里选择的方案是同步SQL形式&#xff0c;并保证ID随机&#xff0c;多个数据库不会重复。 实现 package com.nari.web.controller.demo.controller;import cn…

Android 11 获取启动其他应用

Android 11 获取启动其他应用 本文代码地址 https://gitee.com/chenjim/QueryAppInfo 最新更新地址 https://gitee.com/chenjim/chenjimblog 前言 如果应用以 Android 11&#xff08;API 级别 30&#xff09;或更高版本为目标平台&#xff0c;并查询与设备上已安装的其他应用相…

Python 面试必知必会(一):数据结构

《Python Cookbook》的作者David Beazley的课程PPT开源了&#xff0c;目标用户是希望从编写基础脚本过渡到编写更复杂程序的高级 Python 程序员&#xff0c;课程主题侧重于流行库和框架中使用的编程技术&#xff0c;主要目的是更好地理解 Python 语言本身&#xff0c;以便阅读他…

简易图书管理系统(面向对象思想)

目录 前言 1.整体思路 2.Book包 2.1Book类 2.2BookList类 3.user包 3.1User类 3.2NormalUser类 3.3AdminUser类 4.operation 4.1IOPeration接口 4.2ExitOperation类 4.3FindOperation类 4.4ShowOperation类 4.5AddOperation类 4.6DelOperation类 4.7BorrowOpera…

下半年提速拓店,为什么说屈臣氏引领美妆零售的未来?

屈臣氏过去是美妆零售的先锋&#xff0c;目前来看它或许仍然是先锋。 杰弗里摩尔在《公司进化论》中总结提出&#xff0c;自由市场经济运作的方式&#xff0c;遵循着一些类似自然界有机系统的定律&#xff1a;通俗来说&#xff0c;资源竞争带来“刺激创新”——由消费者偏好形…

看重ARM?苹果、三星、英伟达等知名企业纷纷表示加大投资

根据日经亚洲的报道&#xff0c;芯片设计公司Arm计划进行首次公开募股并在纳斯达克上市。苹果、三星电子、英伟达、英特尔等知名企业计划在Arm美股上市后投资该公司。 据悉&#xff0c;Arm将于9月份上市&#xff0c;预计估值将达到至少600亿美元&#xff08;约合4314亿元人民币…