【OV】VINS协方差矩阵维护:描述状态的不确定性及各状态变量之间的相关性

【OV】VINS协方差矩阵维护:描述状态的不确定性及各状态变量之间的相关性

      • 1. 协方差维护更新数学推导
        • 1.1 状态扩展的背景
        • 1.2 原始协方差矩阵的结构
        • 1.3. 协方差矩阵扩展的数学原理
        • 1.4. 实现中的具体步骤
          • (1) 矩阵扩展
          • (2) 新增部分的赋值
          • (3) 更新完成后的结构
        • 1.5. 原理总结
      • 2. 目的和作用:
        • 2.1 算法流程:
        • 2.2 代码中的一些关键点:
      • 3. 代码实现:
      • 4. part 2: RegisterPoints
        • 4.1 目的和作用:
        • 4.2 算法流程:
        • 4.3代码中的一些关键点:

cov 是协方差矩阵,用于描述状态的不确定性及各状态变量之间的相关性。在 SchurVINS::AugmentState 函数中,它通过扩展协方差矩阵来表示新增状态变量的不确定性。下面是 cov 的更新步骤的推导与原理说明:

1. 协方差维护更新数学推导

1.1 状态扩展的背景

在 VINS (Visual-Inertial Navigation System) 中,状态向量通常包含如下元素:
x = [ x i m u , x k 1 , x k 2 , … , x k n ] \mathbf{x} = [\mathbf{x}_{imu}, \mathbf{x}_{k_1}, \mathbf{x}_{k_2}, \dots, \mathbf{x}_{k_n}] x=[ximu,xk1,xk2,,xkn]
其中:

  • x i m u \mathbf{x}_{imu} ximu: IMU 的状态(如位姿、速度、偏置等)。
  • x k i \mathbf{x}_{k_i} xki: 第 i i i个关键帧(keyframe)的状态,包括位姿信息。

AugmentState 中新增了一个关键帧 x k n + 1 \mathbf{x}_{k_{n+1}} xkn+1。这需要更新协方差矩阵 P \mathbf{P} P 以适应扩展后的状态向量。


1.2 原始协方差矩阵的结构

在状态扩展前,协方差矩阵的大小为:
P o l d ∈ R ( 15 + 6 n ) × ( 15 + 6 n ) \mathbf{P}_{old} \in \mathbb{R}^{(15 + 6n) \times (15 + 6n)} PoldR(15+6n)×(15+6n)
其中:

  • 15: 表示 IMU 状态的维度。
  • 6n: 表示 (n) 个关键帧的状态维度,每个关键帧有 6 个自由度(旋转 + 平移)。

1.3. 协方差矩阵扩展的数学原理

扩展状态向量后,新的状态维度为 (15 + 6(n+1))。协方差矩阵扩展为:
P n e w = [ P o l d Q Q ⊤ R ] \mathbf{P}_{new} = \begin{bmatrix} \mathbf{P}_{old} & \mathbf{Q} \\ \mathbf{Q}^\top & \mathbf{R} \end{bmatrix} Pnew=[PoldQQR]
其中:

  • P o l d \mathbf{P}_{old} Pold: 原始协方差矩阵。
  • Q \mathbf{Q} Q: 原状态与新增状态之间的协方差。
  • R \mathbf{R} R: 新增状态的协方差。

在大多数实现中,为简化计算,假设新增关键帧的协方差等于某种初始化值,并具有如下特性:

  1. 与原状态的协方差矩阵 ( Q (\mathbf{Q} (Q)可以通过特定假设或传递关系初始化。
  2. 新增状态的协方差 R \mathbf{R} R 初始化为与 IMU 初始状态协方差一致。

1.4. 实现中的具体步骤

代码中的更新过程如下:

(1) 矩阵扩展

通过 cov.conservativeResize(old_rows + 6, old_cols + 6) 将协方差矩阵的维度从 ( 15 + 6 n ) × ( 15 + 6 n ) (15 + 6n) \times (15 + 6n) (15+6n)×(15+6n) 扩展为 ( 15 + 6 ( n + 1 ) ) × ( 15 + 6 ( n + 1 ) ) (15 + 6(n+1)) \times (15 + 6(n+1)) (15+6(n+1))×(15+6(n+1))

(2) 新增部分的赋值

赋值过程如下:

  1. 新增行和列

    cov.block(old_rows, 0, 6, old_cols) = cov.block(0, 0, 6, old_cols);
    cov.block(0, old_cols, old_rows, 6) = cov.block(0, 0, old_rows, 6);
    

    将前 6 × o l d _ c o l s 6 \times old\_cols 6×old_cols 块复制到新增行,表示新增关键帧与其他状态的初始相关性。

  2. 新增状态的协方差

    cov.block(old_rows, old_cols, 6, 6) = cov.block<6, 6>(0, 0);
    

    初始化新增关键帧的协方差,假设与 IMU 初始协方差一致。

(3) 更新完成后的结构

最终扩展后的协方差矩阵形式为:
P n e w = [ P o l d Q Q ⊤ R ] \mathbf{P}_{new} = \begin{bmatrix} \mathbf{P}_{old} & \mathbf{Q} \\ \mathbf{Q}^\top & \mathbf{R} \end{bmatrix} Pnew=[PoldQQR]
其中:

  • Q \mathbf{Q} Q 是由原始状态与新增状态之间的关系初始化的。
  • R \mathbf{R} R是新增关键帧状态的初始协方差。

1.5. 原理总结

协方差扩展的关键在于保持一致性:

  1. 协方差矩阵的维度变化:新增状态的维度与原状态向量保持一致。
  2. 初始化假设:新增状态的协方差与现有状态通过传递模型或初始化值关联。
  3. 数值稳定性:使用与原状态一致的协方差值作为新增部分的初值,避免数值不稳定。

这一过程确保了在扩展状态的同时,系统的不确定性能够正确传播并保持与观测模型一致。

这段代码是C++语言编写的,属于一个名为SchurVINS的类的成员函数AugmentState。这个函数的目的是将一个新的状态(由frame_bundle表示)添

加到当前的状态估计中,并且更新状态协方差矩阵。以下是对这个接口的目的、作用以及算法流程的总结:

2. 目的和作用:

  1. 状态扩展:将新的帧捆绑(frame_bundle)与当前状态合并,以更新状态估计。
  2. 状态ID管理:为新的状态分配一个唯一的ID。
  3. 状态存储:将新的状态存储在一个映射(states_map)中,以便后续访问。
  4. 协方差矩阵更新:更新状态协方差矩阵以包含新的状态信息。
2.1 算法流程:
  1. 检查时间戳:确保传入的frame_bundle的时间戳与当前状态(curr_state)的时间戳相匹配。
  2. 创建新状态:使用当前状态的信息创建一个新的增强状态(aug_ptr),包括时间戳、ID、四元数、位置、加速度和陀螺仪数据。
  3. 复制前向运动估计:将当前状态的四元数和位置的前向运动估计复制到新状态中。
  4. 存储新状态:将新状态添加到状态映射(states_map)中。
  5. 检查状态数量:确保状态映射中的状态数量不超过最大限制(state_max)。
  6. 协方差矩阵尺寸检查:检查当前协方差矩阵的尺寸,并确保其是一个方阵。
  7. 协方差矩阵尺寸更新:将协方差矩阵的行和列尺寸增加6,以容纳新状态的信息。
  8. 协方差矩阵块复制:复制协方差矩阵的块,以保持原有的协方差结构,并为新状态留出空间。
  9. 协方差矩阵块更新:更新协方差矩阵的块,以包含新状态的协方差信息。
2.2 代码中的一些关键点:
  • CHECK_EQCHECK宏用于断言,确保代码的执行符合预期的条件。
  • cov.conservativeResize用于保守地调整协方差矩阵的尺寸,这意味着它不会释放内存,而是可能分配更多的内存。
  • cov.block用于访问和操作协方差矩阵的特定块。
  • 代码中注释掉了日志输出,如果需要调试,可以取消注释以查看协方差矩阵的变化。

这个函数是状态估计算法中的一部分,通常用于视觉-惯性导航系统(VINS)中,用于处理视觉和惯性测量数据,以估计系统的位姿和运动。

3. 代码实现:

void SchurVINS::AugmentState(const svo::FrameBundle::Ptr frame_bundle) {
    CHECK_EQ(frame_bundle->getMinTimestampSeconds(), curr_state->ts);

    curr_state->id = id_creator++;
    svo::AugStatePtr aug_ptr(new svo::AugState(curr_state->ts, curr_state->id, curr_state->quat, curr_state->pos,
                                               curr_state->acc, curr_state->gyr));
    aug_ptr->quat_fej = curr_state->quat_fej;
    aug_ptr->pos_fej = curr_state->pos_fej;
    aug_ptr->frame_bundle = frame_bundle;
    states_map.emplace(aug_ptr->id, aug_ptr);

    CHECK((int)states_map.size() <= state_max);
    size_t old_rows = cov.rows();
    size_t old_cols = cov.cols();
    CHECK(old_rows == old_cols);
    CHECK(old_rows == (15 + states_map.size() * 6 - 6));
    cov.conservativeResize(old_rows + 6, old_cols + 6);

    cov.block(old_rows, 0, 6, old_cols) = cov.block(0, 0, 6, old_cols);
    cov.block(0, old_cols, old_rows, 6) = cov.block(0, 0, old_rows, 6);
    cov.block(old_rows, old_cols, 6, 6) = cov.block<6, 6>(0, 0);

    //LOG(INFO) << " augmented state: \n" << std::setprecision(15) << cov;
}

4. part 2: RegisterPoints

目的是将新的帧捆绑(frame_bundle)中的角点特征注册到当前的状态中,并且更新局部点映射(local_pts

以下是对这个接口的目的、作用以及算法流程的总结:

4.1 目的和作用:
  1. 特征注册:将新帧中的角点特征与当前状态关联起来。
  2. 状态更新:更新当前状态的特征列表,以包含新帧中的角点特征。
  3. 局部点映射更新:更新局部点映射,以包含新帧中的角点。
4.2 算法流程:
  1. 检查状态映射:确保状态映射(states_map)不为空。
  2. 获取当前状态:从状态映射中获取最新的状态指针(state_ptr)。
  3. 获取状态ID:从当前状态指针中获取状态ID(state_id)。
  4. 遍历帧捆绑中的帧:对于frame_bundle中的每个帧(frame):
    • 获取帧的相机索引(camera_id)。
    • 初始化特征计数器(num_feature)。
    • 遍历帧中的特征:对于帧中的每个特征:
      • 检查特征是否有效(非空)并且是否为角点。
      • 如果特征有效,记录特征信息,并创建一个新的局部特征对象(LocalFeature)。
      • 设置局部特征的层级(level)。
      • 检查局部点映射:检查局部点映射(local_pts)中是否已经存在该点的ID:
        • 如果不存在,将点添加到局部点映射中,并更新当前状态的特征列表,以及点的局部观测列表(local_obs_)。
        • 如果存在,只更新当前状态的特征列表和点的局部观测列表。
      • 增加特征计数器。
    • 记录特征数量:记录当前帧的特征数量。
    • 记录相机ID和特征数量:记录相机ID和注册的特征数量。
4.3代码中的一些关键点:
  • CHECK宏用于断言,确保代码的执行符合预期的条件。
  • LOG(INFO)用于记录信息,有助于调试和监控程序的执行过程。
  • svo::isCorner函数用于检查特征是否为角点。
  • svo::LocalFeature是一个共享指针,用于表示局部特征。
  • local_pts是一个映射,用于存储局部点。
  • state_ptr->features是当前状态的特征列表。
  • point->local_obs_是点的局部观测列表。

这个函数是视觉-惯性导航系统(VINS)中的一部分,用于处理视觉测量数据,将新帧中的角点特征与当前状态关联起来,以便于后续的状态估计和优化。


void SchurVINS::RegisterPoints(const svo::FrameBundle::Ptr& frame_bundle) {
    CHECK(!states_map.empty());
    auto& state_ptr = states_map.rbegin()->second;
    const int state_id = state_ptr->id;
    for (const svo::FramePtr& frame : frame_bundle->frames_) {
        const int camera_id = frame->getNFrameIndex();
        int num_feature = 0;
        for (size_t i = 0; i < frame->numFeatures(); ++i) {
            svo::PointPtr point = frame->landmark_vec_[i];
            if (point != nullptr && svo::isCorner(frame->type_vec_[i])) {
                LOG(INFO) << "frame id: " << frame->id() << "point id: " << i << "pos: " << point->pos().transpose();
                const svo::LocalFeaturePtr ft
                    = std::make_shared<svo::LocalFeature>(state_ptr, point, frame, frame->f_vec_.col(i), camera_id);
                ft->level = frame->level_vec_[i];
                svo::LocalPointMap::iterator iter = local_pts.find(point->id());
                if (iter == local_pts.end()) {
                    local_pts.insert({point->id(), point});
                    state_ptr->features.emplace_back(ft);
                    point->local_obs_.insert({state_id, ft});
                } else {
                    state_ptr->features.emplace_back(ft);
                    point->local_obs_.insert({state_id, ft});
                }
                ++num_feature;
            }
        }
        LOG(INFO) << "num of features : " << frame->numFeatures() ;
        LOG(INFO) << "RegisterPoints camera id: " << camera_id << " num feature: " << num_feature;
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

借助 FinClip 跨端技术探索鸿蒙原生应用开发之旅

在当今数字化浪潮汹涌澎湃的时代&#xff0c;移动应用开发领域正经历着深刻的变革与创新。鸿蒙操作系统的崛起&#xff0c;以其独特的分布式架构和强大的性能表现&#xff0c;吸引了众多开发者的目光。而FinClip 跨端技术的出现&#xff0c;为开发者涉足鸿蒙原生应用开发提供了…

UE5.3 虚幻引擎 Windows插件开发打包(带源码插件打包、无源码插件打包)

0 引言 随着项目体量的增大&#xff0c;所有代码功能都放一起很难管理。所以有什么办法可以将大模块划分成一个个小模块吗。当然有&#xff0c;因为虚幻引擎本身就遇到过这个问题&#xff0c;他的解决办法就是使用插件的形式开发。 例如&#xff0c;一个团队开发了文件I/O模块插…

如何轻松关闭 iPhone 上的 HEIC [HEIC 图像技巧]

您是否正在为关闭 iPhone 上的 HEIC 而烦恼&#xff1f;你不是一个人; Apple 的首选图像文件格式仍可能存在一些兼容性问题。当您与某人共享照片或尝试在Windows计算机上打开图像时&#xff0c;就会出现此问题。幸运的是&#xff0c;Apple 使关闭 HEIC iPhone 变得更加容易。 …

GRU-PFG:利用图神经网络从股票因子中提取股票间相关性

“MCI-GRU: Stock Prediction Model Based on Multi-Head Cross-Attention and Improved GRU” 论文地址&#xff1a;https://arxiv.org/pdf/2410.20679 摘要 金融市场因复杂性及大数据时代的来临&#xff0c;使得准确预测股票走势变得尤为重要。传统的时序分析模型&#xff0…

UE5失真材质

渐变材质函数&#xff1a;RadialGradientExponential&#xff08;指数径向渐变&#xff09; 函数使用 UV 通道 0 来产生径向渐变&#xff0c;同时允许用户调整半径和中心点偏移。 用于控制渐变所在的位置及其涵盖 0-1 空间的程度。 基于 0-1 的渐变中心位置偏移。 源自中心的径…

Go语言在实际项目中的应用:从RESTful API到日志监控 (十四)

Go语言在实际项目中的应用&#xff1a;从RESTful API到日志监控 &#x1f680; Go语言&#xff08;又叫Golang&#xff09;作为一种现代化的编程语言&#xff0c;凭借其简洁的语法和强大的性能&#xff0c;已经成为了很多企业技术栈的一部分。在实际项目中&#xff0c;Go不仅仅…

3blue1brow线代笔记

向量 物理&#xff1a;空间中的箭头&#xff0c;长度和方向决定一个向量。只要两者相同&#xff0c;可以任意移动保持不变 计算机&#xff1a;有序的数字列表 &#xff08;数组&#xff09; 数学&#xff1a;向量可以是任何东西&#xff0c;只要保证两个向量相加以及数字与向量…

壁纸样机神器,这个工具适合专业设计师用吗?

壁纸样机神器在一定程度上适合专业设计师使用&#xff0c;但是否适合具体取决于设计师的需求和使用场景&#xff1a; 适合专业设计师的方面 快速实现设计想法&#xff1a;专业设计师在创作过程中&#xff0c;有时需要快速将设计想法变为可视化的效果图&#xff0c;以便进行初…

STM32CUBEIDE FreeRTOS操作教程(十二):std dynamic memory 标准动态内存

STM32CUBEIDE FreeRTOS操作教程&#xff08;十二&#xff09;&#xff1a;std dynamic memory 标准动态内存 STM32CUBE开发环境集成了STM32 HAL库进行FreeRTOS配置和开发的组件&#xff0c;不需要用户自己进行FreeRTOS的移植。这里介绍最简化的用户操作类应用教程。以STM32F40…

在线机考|2024华为实习秋招春招编程题(最新)——第3题_PCB印刷电路板布线_300分(八)

题目内容 在PCB印刷电路板设计中,器件之间的连线需要避免线路的阻抗值增大、而且赛件之间还有别的器件和别的干扰源,在布线时我们希望受到的干扰尽量小。现将电路板简化成一个MN的矩阵,每个位置(单元格)的值表示其源干扰度。 如果单元格的值为0,表示此位置没有干扰源;如果单…

1961-2022年中国大陆多干旱指数数据集(SPI/SPEI/EDDI/PDSI/SC-PDSI/VPD)

DOI: 10.5194/essd-2024-270 干旱指数对于评估和管理缺水和农业风险至关重要;然而&#xff0c;现有数据集中缺乏统一的数据基础&#xff0c;导致不一致&#xff0c;对干旱指数的可比性提出了挑战。本研究致力于创建CHM_Drought&#xff0c;这是一个创新且全面的长期气象干旱数…

建造者模式 Builder Pattern

在创建一个对象的时候&#xff0c;构造器参数有点多&#xff0c;而且有些参数还是可选的&#xff0c;再者还有不少同类型的&#xff0c;那就更应该使用 builder 模式了。 使用 Builder 模式的初衷是 把易变性&#xff08;mutability&#xff09;移动到Builder类&#xff0c;而…

【人工智能机器学习基础篇】——深入详解监督学习之模型评估:掌握评估指标(准确率、精确率、召回率、F1分数等)和交叉验证技术

深入详解监督学习之模型评估 在监督学习中&#xff0c;模型评估是衡量模型性能的关键步骤。有效的模型评估不仅能帮助我们理解模型在训练数据上的表现&#xff0c;更重要的是评估其在未见数据上的泛化能力。本文将深入探讨监督学习中的模型评估方法&#xff0c;重点介绍评估指…

Linux(Ubuntu24.04)源码编译安装VTK7.1.1记录

VTK&#xff08;Visualization Toolkit&#xff09;是一个开源的3D可视化开发工具包&#xff0c;用于开发可视化和图形处理应用程序。VTK提供了一系列的算法和工具&#xff0c;用于创建、渲染和处理复杂的3D图形和数据。VTK由C编写&#xff0c;并提供了Python、Java和Tcl等语言…

FICO财务模块在SAP ECC与S4 HANA系统间的差异有哪些?

【SAP系统研究】 #SAP #FICO #ECC #HANA #Oracle #SAP财务 尽管SAP S4/HANA已经发布很久&#xff0c;但使用SAP ECC系统的企业也仍然很多。 这两个系统在FICO模块中有哪些常见的不同呢&#xff1f; 1、数据库表 ①SAP ECC系统 可以在Oracle、IBM DB2等数据库上运行 ②SAP S…

CDPHudi实战-集成spark

[一]使用Spark-shell 1-配置hudi Jar包 [rootcdp73-1 ~]# for i in $(seq 1 6); do scp /opt/software/hudi-1.0.0/packaging/hudi-spark-bundle/target/hudi-spark3.4-bundle_2.12-1.0.0.jar cdp73-$i:/opt/cloudera/parcels/CDH/lib/spark3/jars/; done hudi-spark3.4-bu…

mac m2 安装 docker

文章目录 安装1.下载安装包2.在downloads中打开3.在启动台打开打开终端验证 修改国内镜像地址小结 安装 1.下载安装包 到官网下载适配的安装包&#xff1a;https://www.docker.com/products/docker-desktop/ 2.在downloads中打开 拖过去 3.在启动台打开 选择推荐设置 …

Power BI如何连接Azure Databricks数据源?

故事背景: 近期有朋友询问&#xff0c;自己公司有一些项目使用了Azure Databricks用于数据存储。如何使用Power BI Desktop桌面开发软件连接Azure Databricks的数据源呢&#xff1f; 解决方案: 其实Power BI是提供了连接Azure Databricks数据源的选项的&#xff0c;只是配置…

Python入门教程 —— 进制转换

找其他编译器&#xff0c;系统解释器&#xff0c;这样速度会快很多。 进制 现代的计算机和依赖计算机的设备里都用到二进制(即0和1)来保存和表示数据&#xff0c;一个二进制表示一个比特(Bit)。 在二进制的基础上&#xff0c;计算机还支持八进制和十六进制这两种进制。 除了…

HTML5新特性|05 CSS3边框CSS3背景

CSS3边框 1、CSS3边框: 通过CSS3&#xff0c;您能够创建圆角边框&#xff0c;向矩形添加阴影&#xff0c;使用图片来绘制边框-并且不需使用设计软件&#xff0c;比如PhotoShop。 属性: border-radius 圆角box-shadow:水平阴影 垂直阴影 阴影的清晰度 阴影的大小 阴影的颜色…