iNav开源代码之Filters

iNav开源代码之Filters

  • 1. 源由
  • 2. 滤波器应用类型
    • 2.1 一般滤波
    • 2.1.1 pt1Filter
    • 2.1.2 pt2Filter
    • 2.1.3 pt3Filter
    • 2.1.4 biquadFilter
    • 2.2 kalman滤波
    • 2.3 动态gyro带通滤波
      • 2.3.1 dynamicGyroNotchFilters
      • 2.3.2 secondaryDynamicGyroNotchFilters
    • 2.4 rpm滤波
  • 3. 滤波器技术类型
    • 3.1 常见滤波原理
    • 3.2 卡尔曼滤波简介
  • 4. 参考资料

1. 源由

iNav 6.1.1远航出现异常:RC断链&GPS信号丢失导致炸机。

根据当前Emergency landing tumbled crash? – inav 6.1.1 #9184最新获得的信息看,IMU姿态原始数据正常,IMU滤波数据异常,PID控制器内部数据出现了溢出。但尚不清楚是什么原因导致的该情况发生?

从事件顺序的角度看,“【传感数据】IMU姿态”滤波似乎更靠近出问题的前端。

因此,我们看下iNav的滤波器设计,当然从目前Git代码改动情况看,如果存在问题更倾向接口参数类型变更导致精度出现问题,比如:double修改为float。

2. 滤波器应用类型

  • 一般滤波
  • kalman滤波
  • 动态gyro带通滤波
  • rpm滤波

2.1 一般滤波

代码详见:src\main\common\filter.c

typedef union { 
    biquadFilter_t biquad; 
    pt1Filter_t pt1;
    pt2Filter_t pt2;
    pt3Filter_t pt3;
} filter_t;

void initFilter(uint8_t filterType, filter_t *filter, float cutoffFrequency, uint32_t refreshRate);
void assignFilterApplyFn(uint8_t filterType, float cutoffFrequency, filterApplyFnPtr *applyFn);

细分类型:

  • pt1Filter
  • pt2Filter
  • pt3Filter
  • biquadFilter
typedef enum {
    FILTER_PT1 = 0,
    FILTER_BIQUAD,
    FILTER_PT2,
    FILTER_PT3
} filterType_e;

2.1.1 pt1Filter

一阶低通滤波

  • 低通
  • 解耦
  • 滤波器配置参数(对象):pt1Filter_t *filter
typedef struct pt1Filter_s {
    float state;
    float RC;
    float dT;
    float alpha;
} pt1Filter_t;

void pt1FilterInit(pt1Filter_t *filter, float f_cut, float dT);
void pt1FilterInitRC(pt1Filter_t *filter, float tau, float dT);
void pt1FilterSetTimeConstant(pt1Filter_t *filter, float tau);
void pt1FilterUpdateCutoff(pt1Filter_t *filter, float f_cut);
float pt1FilterGetLastOutput(pt1Filter_t *filter);
float pt1FilterApply(pt1Filter_t *filter, float input);
float pt1FilterApply3(pt1Filter_t *filter, float input, float dT);
float pt1FilterApply4(pt1Filter_t *filter, float input, float f_cut, float dt);
void pt1FilterReset(pt1Filter_t *filter, float input);

2.1.2 pt2Filter

二阶低通滤波

  • 低通
  • 解耦
  • 滤波器配置参数(对象):pt2Filter_t *filter
typedef struct pt2Filter_s {
    float state;
    float state1;
    float k;
} pt2Filter_t;

float pt2FilterGain(float f_cut, float dT);
void pt2FilterInit(pt2Filter_t *filter, float k);
void pt2FilterUpdateCutoff(pt2Filter_t *filter, float k);
float pt2FilterApply(pt2Filter_t *filter, float input);

2.1.3 pt3Filter

三阶低通滤波

  • 低通
  • 解耦
  • 滤波器配置参数(对象):pt3Filter_t *filter
typedef struct pt3Filter_s {
    float state;
    float state1;
    float state2;
    float k;
} pt3Filter_t;

float pt3FilterGain(float f_cut, float dT);
void pt3FilterInit(pt3Filter_t *filter, float k);
void pt3FilterUpdateCutoff(pt3Filter_t *filter, float k);
float pt3FilterApply(pt3Filter_t *filter, float input);

2.1.4 biquadFilter

  • 支持低通、带通
  • 解耦
  • 滤波器配置参数(对象):biquadFilter_t *filter
typedef enum {
    FILTER_LPF,
    FILTER_NOTCH
} biquadFilterType_e;

typedef struct biquadFilter_s {
    float b0, b1, b2, a1, a2;
    float x1, x2, y1, y2;
} biquadFilter_t;

void biquadFilterInit(biquadFilter_t *filter, uint16_t filterFreq, uint32_t samplingIntervalUs, float Q, biquadFilterType_e filterType);

API接口:

void biquadFilterInitNotch(biquadFilter_t *filter, uint32_t samplingIntervalUs, uint16_t filterFreq, uint16_t cutoffHz);
void biquadFilterInitLPF(biquadFilter_t *filter, uint16_t filterFreq, uint32_t samplingIntervalUs);
float biquadFilterApply(biquadFilter_t *filter, float sample);
float biquadFilterReset(biquadFilter_t *filter, float value);
float biquadFilterApplyDF1(biquadFilter_t *filter, float input);
float filterGetNotchQ(float centerFrequencyHz, float cutoffFrequencyHz);
void biquadFilterUpdate(biquadFilter_t *filter, float filterFreq, uint32_t refreshRate, float Q, biquadFilterType_e filterType);

2.2 kalman滤波

代码详见:src\main\flight\kalman.c

【1】Kalman filter

void gyroKalmanInitialize(uint16_t q);
float gyroKalmanUpdate(uint8_t axis, float input);
void gyroKalmanUpdateSetpoint(uint8_t axis, float setpoint);

注:后面会重点介绍这款滤波器,详见第三章节。

2.3 动态gyro带通滤波

这里的带通滤波主要应用一般滤波biquadFilter中的FILTER_NOTCH滤波器。

2.3.1 dynamicGyroNotchFilters

代码详见:src\main\flight\dynamic_gyro_notch.c

#define DYNAMIC_NOTCH_DEFAULT_CENTER_HZ 350

/*
 * Number of peaks to detect with Dynamic Notch Filter aka Matrix Filter. This is equal to the number of dynamic notch filters
 */
#define DYN_NOTCH_PEAK_COUNT 3
typedef struct dynamicGyroNotchState_s {
    uint16_t frequency[XYZ_AXIS_COUNT][DYN_NOTCH_PEAK_COUNT];
    float dynNotchQ;
    uint32_t looptime;
    uint8_t enabled;
    
    biquadFilter_t filters[XYZ_AXIS_COUNT][DYN_NOTCH_PEAK_COUNT];
    filterApplyFnPtr filtersApplyFn[XYZ_AXIS_COUNT][DYN_NOTCH_PEAK_COUNT];
} dynamicGyroNotchState_t;

void dynamicGyroNotchFiltersInit(dynamicGyroNotchState_t *state);
void dynamicGyroNotchFiltersUpdate(dynamicGyroNotchState_t *state, int axis, float frequency[]);
float dynamicGyroNotchFiltersApply(dynamicGyroNotchState_t *state, int axis, float input);

2.3.2 secondaryDynamicGyroNotchFilters

代码详见:src\main\flight\secondary_dynamic_gyro_notch.c

/**

  • Secondary dynamic notch filter.
  • In some cases, noise amplitude is high enough not to be filtered by the primary filter.
  • This happens on the first frequency with the biggest aplitude
    */
typedef struct secondaryDynamicGyroNotchState_s {
    uint16_t frequency[XYZ_AXIS_COUNT];
    float dynNotchQ;
    uint32_t looptime;
    uint8_t enabled;
    
    biquadFilter_t filters[XYZ_AXIS_COUNT];
    filterApplyFnPtr filtersApplyFn[XYZ_AXIS_COUNT];
} secondaryDynamicGyroNotchState_t;

void secondaryDynamicGyroNotchFiltersInit(secondaryDynamicGyroNotchState_t *state);
void secondaryDynamicGyroNotchFiltersUpdate(secondaryDynamicGyroNotchState_t *state, int axis, float frequency[]);
float secondaryDynamicGyroNotchFiltersApply(secondaryDynamicGyroNotchState_t *state, int axis, float input);

2.4 rpm滤波

在rpm滤波器内部实现中,仍然使用biquadFilter中的FILTER_NOTCH带通滤波器。代码详见:src\main\flight\rpm_filter.c

typedef struct rpmFilterConfig_s {
    uint8_t gyro_filter_enabled;
    uint8_t dterm_filter_enabled;

    uint8_t  gyro_harmonics;
    uint8_t  gyro_min_hz;
    uint16_t gyro_q;

    uint8_t  dterm_harmonics;
    uint8_t  dterm_min_hz;
    uint16_t dterm_q;

} rpmFilterConfig_t;

PG_DECLARE(rpmFilterConfig_t, rpmFilterConfig);

#define RPM_FILTER_UPDATE_RATE_HZ 500
#define RPM_FILTER_UPDATE_RATE_US (1000000.0f / RPM_FILTER_UPDATE_RATE_HZ)

void disableRpmFilters(void);
void rpmFiltersInit(void);
void rpmFilterUpdateTask(timeUs_t currentTimeUs);
float rpmFilterGyroApply(uint8_t axis, float input);

3. 滤波器技术类型

  • pt1Filter
  • pt2Filter
  • pt3Filter
  • biquadFilter
  • kalmanFilter

3.1 常见滤波原理

关于前面四种滤波器的原理,可参考:BetaFlight模块设计之二十九:滤波模块分析。这里着重介绍下kalman滤波器。

3.2 卡尔曼滤波简介

卡尔曼滤波非常适合不断变化的系统,其优点是内存占用较小(只需保留前一个状态)、速度快,是实时问题和嵌入式系统的理想选择。

结合一个物体(飞行器)位置和速度的关系来简单的描述下kalman滤波。

在速度-位置坐标系中表示:

在这里插入图片描述
在物体匀速运动时:

在这里插入图片描述
经过变化,可以表示为:

在这里插入图片描述
通常来说,变速运动比较常见,因此引入加速度概念后:

在这里插入图片描述
经过变化,可以表示为:

在这里插入图片描述
然后,这个位置-速度坐标系下,可以表达为:

在这里插入图片描述
当我们监控无人机时,它可能会受到风的影响;当我们跟踪轮式机器人时,它的轮胎可能会打滑,或者粗糙地面会降低它的移速。这些因素是难以掌握的,如果出现其中的任意一种情况,预测结果就难以保障。

这要求我们在每个预测步骤后再加上一些新的不确定性,来模拟和“世界”相关的所有不确定性:

在这里插入图片描述
X k X_k Xk的每个预测状态都可能会移动到另一点,也就是蓝色的高斯分布会移动到紫色高斯分布的位置,并且具有协方差 Q k Q_k Qk。换句话说,我们把这些不确定影响视为协方差 Q k Q_k Qk的噪声。

在这里插入图片描述

这个紫色的高斯分布拥有和原分布相同的均值,但协方差不同。表达式:
在这里插入图片描述

简而言之,这里:

  • 新的最佳估计是基于 原最佳估计 和 已知外部影响校正后得到的预测。

  • 新的不确定性是基于 原不确定性 和 外部环境的不确定性 得到的预测。

详细参考资料:
【1】卡爾曼濾波器的原理和應用
【2】尔曼滤波,一份通俗易懂的教程

在这里插入图片描述

注:数学上的推导过程相对更为严谨,这里也就不多码字了,请大家参考:kalman_intro在这里插入图片描述

4. 参考资料

【1】iNav开源代码之严重炸机 – 危险隐患
【2】iNav开源代码之严重炸机 – FAILSAFE
【3】iNav开源代码之严重炸机 – 紧急降落
【4】iNav开源代码之EmergencyLanding
【5】BetaFlight模块设计之二十九:滤波模块分析

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

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

相关文章

C# SolidWorks 二次开发 -从零开始创建一个插件(2)

上一篇我详细讲解了如何创建一个插件,但是无界面无按钮,这种插件适合配合事件偷偷的在后台做点什么事情。今天这篇讲一下如何增加一些按钮到工具栏、菜单上去。 先告诉大家这个东西注册表在哪,因为solidworks在这方面做的不太好,…

prometheus监控mysql8.x以及主从监控告警

mysql8.x主从部署请看下面文档 docker和yum安装的都有 Docker部署mysql8.x版本互为主从_争取不加班!的博客-CSDN博客 Mysql8.x版本主从加读写分离(一) mysql8.x主从_myswl8双主一从读写分离_争取不加班!的博客-CSDN博客 安装部署…

uniapp 微信小程序 placeholder字体、颜色自定义

效果图&#xff1a; 1、template <input type"text" placeholder"搜索标题" placeholder-class"placeholder-style"></input>2、style .placeholder-style{color: #2D94FF; }

通过nexus3部署公司内部的私有npm仓库

简介&#xff1a; 登录时使用默认用户admin&#xff0c;密码不知道就需要找默认的&#xff0c;点击Sign in时会提示你路径&#xff0c;这里我是这样查的&#xff0c;在linux服务器上输入以下命令 ​编辑 前言&#xff1a; 准备工作&#xff0c;可能需要一台linux服务器&#x…

讯为RK3568开发板入门之-tftpnfs的配置

基础条件 VMware虚拟机 Ubuntu18.04 【网络配置陈桥接模式】 RK3568开发板【我是用讯为的RK3568】 网线连接路由器或者和电脑直连 配置TFTP和NFS的作用 使用tftp和nfs网络挂载可以很方便的进行软件的调试&#xff0c;挂载成功后只要把Ubuntu下编译好的文件程序放到挂载的目录…

思科路由器交换机密码破解教程

1. 路由器密码的恢复. 2600、3600等新系列路由器步骤&#xff1a; 1、启动路由器&#xff0c;60秒内按下ctrlbreak键2、rommon>confreg 0x21423、rommon>reset4、router#copy startup-config running-config5、router(config)#no enable secrect //可以删除密码也可以更…

一键批量JSON标注转PNG图片工具V1.1,支持labelme快捷矩形、圆以及轮廓标注

上次发布了一个批量将labelme标注的json文件转换为png文件工具&#xff0c;但是当时只是想着自己用的&#xff0c;功能相当简单&#xff0c;一些网友使用之后跟我反馈这玩意真”垃圾“&#xff0c;很多情况都没有进行设想&#xff0c;所以在功能上很欠缺。由于小陶这几天在外地…

如何提升环境、生态、水文、土地、土壤、农业、大气等领域的数据分析能力

专题一、空间数据获取与制图 1.1 软件安装与应用讲解 1.2 空间数据介绍 1.3海量空间数据下载 1.4 ArcGIS软件快速入门 1.5 Geodatabase地理数据库 专题二、ArcGIS专题地图制作 2.1专题地图制作规范 2.2 空间数据的准备与处理 2.3 空间数据可视化&#xff1a;地图符号与…

HTTP超本文传输协议

HTTP超本文传输协议 HTTP简介HTTP请求与响应HTTP请求请求行请求头空行请求体 HTTP响应响应行响应头空行响应体 HTTP请求方法GET和POST之间的区别HTTP为什么是无状态的cookie原理session 原理cookie 和 session 的区别cookie如何设置cookie被禁止后如何使用session HTTP简介 HT…

Java基础之stream流最新版,stream流的基本操作

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精…

vue实现仿手写稿样式,可导出成png图片

文章目录 环境实现效果代码 环境 安装html2canvas&#xff0c;用于将指定标签下的全部子节点转换为图片 npm install html2canvas实现 <template><div class"handwrite"><div id"left" class"left"><div id"backImg…

C++ | set与map的用法指南

前言 前面我们学习了vector、list等容器&#xff0c;其实他们都属于序列式容器&#xff0c;因为其底层为线性结构&#xff1b;今天我们学习使用的set与map是属于关联式容器&#xff0c;关联式容器更注重于数据检索访问的效率&#xff1b;本文所有的资料均查阅于文档&#xff0c…

RocketMQ深入分析

RocketMQ深入分析 1. 消息存储 目前的MQ中间件从存储模型来&#xff0c;分为需要持久化和不需要持久化的两种模型&#xff0c;现在大多数的是支持持久化存储的&#xff0c;比如ActiveMQ、RabbitMQ、Kafka、RocketMQ&#xff0c;ZeroMQ却不需要支持持久化存储而业务系统也大多…

BART模型和 Electra模型对比

总结 Electra模型在使用较少的计算资源的情况下能够达到跟大语言模型相近的效果。但BART模型对于传统的BERT中加入了不同种制造noise的方式&#xff0c;是BERT和GPT的结合体。Electra模型主要是Generator模型和Discriminator模型的结合体。 未知参数设置&#xff0c;两个模型…

【历史上的今天】7 月 20 日:人类登上月球;数据仓库之父诞生;Mac OS X Lion 发布

整理 | 王启隆 透过「历史上的今天」&#xff0c;从过去看未来&#xff0c;从现在亦可以改变未来。 今天是 2023 年 7 月 20 日&#xff0c;在 2005 年的今天&#xff0c;时任微软全球副总裁的李开复加盟谷歌担任谷歌全球副总裁及中国区总裁。谷歌公司在发布聘请李开复消息的同…

Rust之通用编程

1、变量与可变性&#xff1a; 在Rust语言中&#xff0c;变量默认是不可变的&#xff0c;所以一旦变量被绑定到某个值上面&#xff0c;这个值就再也无法被改变。 可以通过在声明的变量名称前添加mut关键字来使其可变。除了使变量的值可变&#xff0c;mut还会向阅读代码的人暗示…

【机器学习】分类算法 - KNN算法(K-近邻算法)KNeighborsClassifier

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;零基础快速入门人工智能《机器学习入门到精通》 K-近邻算法 1、什么是K-近邻算法&#xff1f;2、K-近邻算法API3、…

【论文阅读 03】机器学习算法在颈动脉斑块影像学分类中的研究进展

读完之后就是&#xff0c;总结 机器学习&#xff08;SVM、小波&#xff09;和深度学习&#xff08;CNN&#xff09;在 颈动脉斑块影像学中的 分类效果。只讨论了超声、磁共振两种成像 Chin J Clin Neurosci 临床神经科学杂志 复旦大学 颈动脉斑块( carotid plaques) 是一种…

opencv 之 外接多边形(矩形、圆、三角形、椭圆、多边形)使用详解

opencv 之 外接多边形&#xff08;矩形、圆、三角形、椭圆、多边形&#xff09;使用详解 本文主要讲述opencv中的外接多边形的使用&#xff1a; 多边形近似外接矩形、最小外接矩形最小外接圆外接三角形椭圆拟合凸包 将重点讲述最小外接矩形的使用 1. API介绍 #多边形近似 v…

若依微服务整合activiti7.1.0.M6

若依微服务3.6.3版本整合activiti7&#xff08;7.1.0.M6&#xff09; 目前有两种办法集成activiti7 放弃activiti7新版本封装的API&#xff0c;使用老版本的API&#xff0c;这种方式只需要直接集成即可&#xff0c;在7.1.0.M6版本中甚至不需要去除security的依赖。不多介绍&a…