草庐IT

滤波算法 | 无迹卡尔曼滤波(UKF)算法及其Python实现

lovetaozibaby 2023-05-25 原文

文章目录

简介

上一篇文章,我们介绍了UKF滤波公式及其MATLAB代码。在做视觉测量的过程中,基于OpenCV的开发包比较多,因此我们将UKF的MATLAB代码转到python中,实现数据滤波效果。

UKF滤波

1. 概述和流程

UKF的公式这里就不再过多介绍了,具体内容请参见博客:UKF滤波公式及其MATLAB代码

这里简单把上一篇文章的公式和流程图粘贴一下。

求解流程

  1. 相比于一般的卡尔曼滤波,UKF算法增加了两次无迹变换,公式为:

    权重和方差计算公式为:

  2. Sigma点传播:

  1. 计算x的预测值和协方差矩阵:


4. 得到一组新的Sigma点:


5. 代入观测方程中,得到测量量的预估值:

  1. 获得观测量的预测值和协方差矩阵:

  1. 更新状态变量和协方差矩阵:


另外,每次写论文画卡尔曼流程图中,都找不到参考的模板。我自己画了个滤波流程图,不一定符合每个人的审美,以备参考:

2. Python代码

重点来了。。。

上代码。

第一个版本

UKF的python代码我一共写了两个版本。

第一个是我用ChatGPT直接生成了一个,经过数据实测,结果有点奇怪,不太像我想要的结果,每个模块之间的交互也跟我理解的不太一样。为了对比,这里也还是贴出来了,人家写的确实比我写的看着逼格好点。

ChatGPT输出的Python:

a. KF滤波


class KalmanFilter:
    def __init__(self, F, H, Q, R, P, x0):
        self.F = F
        self.H = H
        self.Q = Q
        self.R = R
        self.P = P
        self.x = x0

    def predict(self):
        self.x = self.F @ self.x
        self.P = self.F @ self.P @ self.F.T + self.Q

    def update(self, z):
        y = z - self.H @ self.x
        S = self.H @ self.P @ self.H.T + self.R
        K = self.P @ self.H.T @ np.linalg.inv(S)
        self.x = self.x + K @ y
        self.P = (np.eye(len(self.x)) - K @ self.H) @ self.P

b. UKF滤波


import numpy as np
from scipy.linalg import sqrtm

class UKF:
    def __init__(self, f, h, Q, R, P, x0):
        self.f = f
        self.h = h
        self.Q = Q
        self.R = R
        self.P = P
        self.x = x0
        self.n = x0.shape[0]
        self.m = None


    def predict(self):
        # Generate sigma points
        L = np.linalg.cholesky(self.P)
        W = np.concatenate((np.zeros((self.n, 1)), sqrtm(self.n * self.P)))
        X = np.concatenate((self.x, self.x + W, self.x - W), axis=1)

        # Predict sigma points
        Y = np.zeros((self.n, 2 * self.n + 1))
        for i in range(2 * self.n + 1):
            Y[:, i] = self.f(X[:, i])

        # Compute mean and covariance
        self.x = np.mean(Y, axis=1, keepdims=True)
        self.P = np.cov(Y) + self.Q

    def update(self, z):
        # Generate sigma points
        L = np.linalg.cholesky(self.P)
        W = np.concatenate((np.zeros((self.n, 1)), sqrtm(self.n * self.P)))
        X = np.concatenate((self.x, self.x + W, self.x - W), axis=1)

        # Predict measurements
        Z = np.zeros((self.m, 2 * self.n + 1))
        for i in range(2 * self.n + 1):
            Z[:, i] = self.h(X[:, i])

        # Compute mean and covariance
        z_mean = np.mean(Z, axis=1, keepdims=True)
        z_cov = np.cov(Z) + self.R

        # Compute cross-covariance
        xz_cov = np.zeros((self.n, self.m))
        for i in range(2 * self.n + 1):
            xz_cov += (X[:, i, np.newaxis] - self.x) @ (Z[:, i, np.newaxis] - z_mean).T
        xz_cov /= 2 * self.n

        # Compute Kalman gain
        K = xz_cov @ np.linalg.inv(z_cov)

        # Update estimate
        self.x += K @ (z - z_mean)
        self.P -= K @ z_cov @ K.T

第二个版本

第二个是我自己改的一个。参考MATLAB的流程,直接改成了python代码,没有做代码的优化,结果还挺好的,和MATLAB结果一致。


import math

import numpy as np
from scipy.linalg import sqrtm

class ukf:
    def __init__(self, f, h):
        self.f = f
        self.h = h
        self.Q = None
        self.R = None
        self.P = None
        self.x = None
        self.Z = None
        self.n = None
        self.m = None

    def GetParameter(self, Q, R, P, x0):
        self.Q = Q
        self.R = R
        self.P = P
        self.x = x0
        self.n = x0.shape[0]
        self.m = None

    def sigmas(self,x0, c):
        A = c * np.linalg.cholesky(self.P).T
        Y = (self.x * np.ones((self.n,self.n))).T
        Xset = np.concatenate((x0.reshape((-1,1)), Y+A, Y-A), axis=1)
        return Xset


    def ut1(self, Xsigma, Wm, Wc):
        LL = Xsigma.shape[1]
        Xmeans = np.zeros((self.n,1))
        Xsigma_pre = np.zeros((self.n, LL))
        for k in range(LL):
            Xsigma_pre[:,k] = self.f(Xsigma[:,k])
            Xmeans = Xmeans + Wm[0,k]* Xsigma_pre[:, k].reshape((self.n, 1))
        Xdiv = Xsigma_pre - np.tile(Xmeans,(1,LL))
        P  = np.dot(np.dot(Xdiv, np.diag(Wc.reshape((LL,)))), Xdiv.T) + self.Q

        return Xmeans, Xsigma_pre, P, Xdiv

    def ut2(self, Xsigma, Wm, Wc, m):
        LL = Xsigma.shape[1]
        Xmeans = np.zeros((m, 1))
        Xsigma_pre = np.zeros((m, LL))
        for k in range(LL):
            Xsigma_pre[:, k] = self.h(Xsigma[:, k])
            Xmeans = Xmeans + Wm[0, k] * Xsigma_pre[:, k].reshape((m, 1))
        Xdiv = Xsigma_pre - np.tile(Xmeans, (1, LL))
        P = np.dot(np.dot(Xdiv, np.diag(Wc.reshape((LL,)))), Xdiv.T) + self.R

        return Xmeans, Xsigma_pre, P, Xdiv


    def OutPutParameter(self, alpha_msm, x0, Q, R, P):

        z = np.array(alpha_msm).reshape((3, 1))

        self.GetParameter(Q, R, P, x0)

        l = self.n
        m = z.shape[0]
        alpha = 2
        ki = 3 - l
        beta = 2
        lamb = alpha ** 2 * (l + ki) - l
        c = l + lamb
        Wm = np.concatenate((np.array(lamb / c).reshape((-1,1)), 0.5 / c + np.zeros((1, 2 * l))), axis=1)
        Wc = Wm.copy()
        Wc[0][0] = Wc[0][0] + (1 - alpha ** 2 + beta)
        c = math.sqrt(c)

        Xsigmaset = self.sigmas(x0, c)
        X1means, X1, P1, X2 = self.ut1(Xsigmaset, Wm, Wc)
        Zpre, Z1, Pzz, Z2 = self.ut2(X1, Wm, Wc, m)

        Pxz = np.dot(np.dot(X2 , np.diag(Wc.reshape((self.n*2+1,)))), Z2.T)
        K =np.dot(Pxz , np.linalg.inv(Pzz))

        X = (X1means + np.dot(K, z - Zpre)).reshape((-1,))
        self.P = P1 - np.dot(K , Pxz.T)

        return X, self.P

这里把两个代码都公开出来,以供参考。

如有疑问,欢迎提问和指正。

有关滤波算法 | 无迹卡尔曼滤波(UKF)算法及其Python实现的更多相关文章

  1. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  2. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  3. Python 相当于 Perl/Ruby ||= - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。

  4. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  5. 区块链之加解密算法&数字证书 - 2

    目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非

  6. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  7. python - 如何读取 MIDI 文件、更改其乐器并将其写回? - 2

    我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的

  8. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  9. 「Python|Selenium|场景案例」如何定位iframe中的元素? - 2

    本文主要介绍在使用Selenium进行自动化测试或者任务时,对于使用了iframe的页面,如何定位iframe中的元素文章目录场景描述解决方案具体代码场景描述当我们在使用Selenium进行自动化测试的时候,可能会遇到一些界面或者窗体是使用HTML的iframe标签进行承载的。对于iframe中的标签,如果直接查找是无法找到的,会抛出没有找到元素的异常。比如近在咫尺的例子就是,CSDN的登录窗体就是使用的iframe,大家可以尝试通过F12开发者模式查看到的tag_name,class_name,id或者xpath来定位中的页面元素,会抛出NoSuchElementException异常。解决

  10. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

随机推荐