【C语言/Python】嵌入式常用数据滤波处理:卡尔曼滤波器的简易实现方式(Kalman Filter)

news2024/11/15 13:57:34

【C语言/Python】嵌入式常用数据滤波处理:卡尔曼滤波器的简易实现方式(Kalman Filter)

文章目录

  • 卡尔曼滤波
  • 卡尔曼滤波公式
  • 卡尔曼滤波数据处理效果
  • C语言的卡尔曼滤波实现
  • 附录:压缩字符串、大小端格式转换
    • 压缩字符串
      • 浮点数
      • 压缩Packed-ASCII字符串

卡尔曼滤波

卡尔曼滤波适用于在正态分布的情况下 处理数据抖动的问题 常用于温度传感器、加速度传感器等数据滤波处理
这里简单介绍下:

具体关于卡尔曼滤波网上资料很多 这里就不多做介绍
在这里插入图片描述
一点:卡尔曼滤波能有效减小系统方差

卡尔曼滤波公式

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

卡尔曼滤波数据处理效果

我用ADXL345采集了一组数据
然后用Python进行卡尔曼滤波处理
代码如下:

import matplotlib.pyplot as plt

"""
Q 系统噪声
R 测量噪声
X(k|k-1)   上一次状态预测结果
X(k-1|k-1) 上一时刻的最优预测值
P(k|k-1)   X(k|k-1)对应的convariance协方差
P(k-1|k-1) X(k-1|k-1) 对应的convariance协方差
"""

x_last = 0
y_last = 0
z_last = 0
px_last = 0
py_last = 0
pz_last = 0
Q = 0.1  #系统噪声
R = 0.5  #测量噪声

def kalman(measure,result_last=0,prediction_last=0,Q=0.018,R=0.0542):
    result_mid = result_last
    prediction_mid = prediction_last + Q
    kg = prediction_mid/(prediction_mid + R)
    result_now = result_mid + kg*(measure - result_mid)
    prediction_now = (1-kg)*prediction_mid
    prediction_last = prediction_now
    result_last = result_now
    return result_now,result_last,prediction_last
    

f=open("4.txt","r",encoding="UTF-8")
f_list=f.readlines()
f.close()

x = []
y = []
z = []

px=[]
py=[]
pz=[]

ppx=[]
ppy=[]
ppz=[]

for i in f_list:
    try:        
        s=i.split("x: ")[1]
        s=s.split("	y: ")
        x.append(float(s[0]))
        s=s[1].split("	z: ")
        y.append(float(s[0]))
        s=s[1].split("\n")
        z.append(float(s[0]))
    except:
        pass

x_last = x[0]
px_last = x[0]

y_last = y[0]
py_last = y[0]

z_last = z[0]
pz_last = z[0]

    
for i in range(len(x)):
    pred,x_last,px_last = kalman(x[i],x_last,px_last,Q,0.5)

    px.append(pred)
    
    pred,y_last,py_last = kalman(y[i],y_last,py_last,Q,0.5)
    py.append(pred)
    
    pred,z_last,pz_last = kalman(z[i],z_last,pz_last,Q,0.5)
    pz.append(pred)


x_last = px[0]
px_last = px[0]

y_last = py[0]
py_last = py[0]

z_last = pz[0]
pz_last = pz[0]

for i in range(len(px)):
    pred,x_last,px_last = kalman(px[i],x_last,px_last,Q,0.5)

    ppx.append(pred)
    
    pred,y_last,py_last = kalman(py[i],y_last,py_last,Q,0.5)
    ppy.append(pred)
    
    pred,z_last,pz_last = kalman(pz[i],z_last,pz_last,Q,0.5)
    ppz.append(pred)
    
#plt.plot(real,color="b")  #真实值
plt.figure(1)
plt.plot(x,color="g")     
plt.plot(px,color="r")  
plt.plot(ppx,color="b")  
plt.figure(2)
plt.plot(y,color="g")     
plt.plot(py,color="r")  
plt.plot(ppy,color="b")  
plt.figure(3)
plt.plot(z,color="g")  
plt.plot(pz,color="r")   
plt.plot(ppz,color="b")    
plt.show()


运行效果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
绿色的是原始数据 红色的是一次滤波 蓝色的是二次滤波(将红色的结果再次滤波)

C语言的卡尔曼滤波实现

有了Python代码 照抄就能改到C语言

typedef struct
{
    float Measure_Now;
    float Result_Now;
    float Result_Last;
    float Prediction_Last;
    float Q;
    float R;
}Kalman_Filter_Normal_Struct;

Kalman_Filter_Normal_Struct Kalman_Filter_Normal(Kalman_Filter_Normal_Struct Stu)
{
   float result_mid = Stu.Result_Last;
   float prediction_mid = Stu.Prediction_Last + Stu.Q;
   float kg = prediction_mid/(prediction_mid + Stu.R);
   Stu.Result_Now = result_mid + kg*(Stu.Measure_Now - result_mid);
   float prediction_now = (1-kg)*prediction_mid;
   Stu.Prediction_Last = prediction_now;
   Stu.Result_Last = Stu.Result_Now;

   return Stu;
}
int main(void)
{
   float buf[10]={85.6,84.3,84.0,86.5,85.5,85.0,84.8,84.5,84.5,85.1};
   uint8_t i=0;
   Kalman_Filter_Normal_Struct Stu;
   Stu.Measure_Now=buf[0];
   Stu.Result_Now=buf[0];
   Stu.Result_Last=buf[0];
   Stu.Prediction_Last=buf[0];
   Stu.Q=0.1;
   Stu.R=0.5;
   for(i=0;i<10;i++)
   {  
      Stu.Measure_Now=buf[i];
      Stu=Kalman_Filter_Normal(Stu);
      printf("%f\n",Stu.Result_Now);
   }
   return 0;
}

最终结果:

85.599998
84.892471
84.511665
85.277679
85.359756
85.229263
85.074692
84.868370
84.736282
84.866631

附录:压缩字符串、大小端格式转换

压缩字符串

首先HART数据格式如下:
在这里插入图片描述
在这里插入图片描述
重点就是浮点数和字符串类型
Latin-1就不说了 基本用不到

浮点数

浮点数里面 如 0x40 80 00 00表示4.0f

在HART协议里面 浮点数是按大端格式发送的 就是高位先发送 低位后发送

发送出来的数组为:40,80,00,00

但在C语言对浮点数的存储中 是按小端格式来存储的 也就是40在高位 00在低位
浮点数:4.0f
地址0x1000对应00
地址0x1001对应00
地址0x1002对应80
地址0x1003对应40

若直接使用memcpy函数 则需要进行大小端转换 否则会存储为:
地址0x1000对应40
地址0x1001对应80
地址0x1002对应00
地址0x1003对应00

大小端转换:

void swap32(void * p)
{
   uint32_t *ptr=p;
   uint32_t x = *ptr;
   x = (x << 16) | (x >> 16);
   x = ((x & 0x00FF00FF) << 8) | ((x >> 8) & 0x00FF00FF);

   *ptr=x;
}

压缩Packed-ASCII字符串

本质上是将原本的ASCII的最高2位去掉 然后拼接起来 比如空格(0x20)
四个空格拼接后就成了
1000 0010 0000 1000 0010 0000
十六进制:82 08 20
对了一下表 0x20之前的识别不了
也就是只能识别0x20-0x5F的ASCII表
在这里插入图片描述

压缩/解压函数后面再写:

//传入的字符串和数字必须提前声明 且字符串大小至少为str_len 数组大小至少为str_len%4*3 str_len必须为4的倍数
uint8_t Trans_ASCII_to_Pack(uint8_t * str,uint8_t * buf,const uint8_t str_len)
{
   if(str_len%4)
   {
      return 0;
   }
	 
   uint8_t i=0;
   memset(buf,0,str_len/4*3);	  
   for(i=0;i<str_len;i++)
   {
      if(str[i]==0x00)
      {
         str[i]=0x20;
      }
   }

   for(i=0;i<str_len/4;i++)
   {
      buf[3*i]=(str[4*i]<<2)|((str[4*i+1]>>4)&0x03);
      buf[3*i+1]=(str[4*i+1]<<4)|((str[4*i+2]>>2)&0x0F);
      buf[3*i+2]=(str[4*i+2]<<6)|(str[4*i+3]&0x3F);
   }

   return 1;
}

//传入的字符串和数字必须提前声明 且字符串大小至少为str_len 数组大小至少为str_len%4*3 str_len必须为4的倍数
uint8_t Trans_Pack_to_ASCII(uint8_t * str,uint8_t * buf,const uint8_t str_len)
{
   if(str_len%4)
   {
      return 0;
   }

   uint8_t i=0;

   memset(str,0,str_len);

   for(i=0;i<str_len/4;i++)
   {
      str[4*i]=(buf[3*i]>>2)&0x3F;
      str[4*i+1]=((buf[3*i]<<4)&0x30)|(buf[3*i+1]>>4);
      str[4*i+2]=((buf[3*i+1]<<2)&0x3C)|(buf[3*i+2]>>6);
      str[4*i+3]=buf[3*i+2]&0x3F;
   }

   return 1;
}


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

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

相关文章

TCP三次握手四次挥手 UDP

TCP是面向链接的协议&#xff0c;而UDP是无连接的协议 TCP的三次握手 三次传输过程是纯粹的不涉及数据&#xff0c;三次握手的几个数据包中不包含数据内容。它的应用层&#xff0c;数据部分是空的&#xff0c;只是TCP实现会话建立&#xff0c;点到点的连接 TCP的四次挥手 第四…

JVM堆内存分析

jmap工具查看堆内存 jmap:全称JVM Memory Map 是一个可以输出所有内存中对象的工具&#xff0c;可以将JVM中的heap&#xff08;堆&#xff09;&#xff0c;以二进制输出成文本&#xff0c;打印出Java进程对应的内存 找到pid jmap -heap 19792 Attaching to process ID 19792…

贪心算法-----柠檬水找零

今日题目&#xff1a;leetcode860 题目链接&#xff1a;点击跳转题目 分析&#xff1a; 顾客只会给三种面值&#xff1a;5、10、20&#xff0c;先分类讨论 当收到5美元时&#xff1a;不用找零&#xff0c;面值5张数1当收到10美元时&#xff1a;找零5美元&#xff0c;面值5张数…

bevformer详解(1):论文介绍

3D 视觉感知任务,包括基于多摄像头的3D检测和地图分割对于自动驾驶系统至关重要。本文提出了一种名为BEVFormer的新框架,它通过使用空间和时间的Transformer 学习统一的BEV表示来支持多个自动驾驶感知任务。简而言之,BEVFormer通过预定义的网格形式的Bev Query与空间和时间空…

icap对flash的在线升级

文章目录 一、icap原语介绍&#xff08;针对 S6 系列的 ICap&#xff09;&#xff0c;之后可以拓展到A7、K7当中去二、程序1设计2.1信号结构框图2.2 icap_delay设计2.3 icap_ctrl设计&#xff08;可以当模板使用&#xff0c;之后修改关键参数即可&#xff09; 三、程序2设计四、…

如何同时或者按顺序间隔启动多个程序

首先&#xff0c;需要用到的这个工具&#xff1a; 度娘网盘 提取码&#xff1a;qwu2 蓝奏云 提取码&#xff1a;2r1z 1、打开工具&#xff0c;切换到定时器模块&#xff0c;快捷键&#xff1a;Ctrl3 2、新建一个定时器&#xff0c;我这里演示同时打开多个程序&#xff08;比…

在shell程序里如何从文件中获取第n行

问题&#xff1a; 有没有一种“规范”的方式来做到这一点&#xff1f;我一直在使用 head -n | tail -1&#xff0c;它可以做到这一点&#xff0c;但我一直想知道是否有一个Bash工具&#xff0c;专门从文件中提取一行(或一段行)。 所谓“规范”&#xff0c;我指的是一个主要功…

HTML五彩缤纷的爱心

写在前面 小编准备了一个五彩缤纷的爱心&#xff0c;送给各位小美女们~ 在桌面创建一个.txt文本文件&#xff0c;把代码复制进去&#xff0c;将后缀.txt改为.html&#xff0c;然后就可以双击运行啦&#xff01; HTML简介 HTML&#xff08;超文本标记语言&#xff09;是一种…

Stable Diffusion是什么?

目录 一、Stable Diffusion是什么&#xff1f; 二、Stable Diffusion的基本原理 三、Stable Diffusion有哪些运用领域&#xff1f; 一、Stable Diffusion是什么&#xff1f; Stable Diffusion是一个先进的人工智能图像生成模型&#xff0c;它能够根据文本描述创造出高质量的图…

VMware安装centos7教程

文章目录 1、centos7的ios镜像下载2、CentOS7安装3、Centos配置 其他教程&#xff1a; 1、VMware Workstation 16 Pro安装教程 2、VMwarePro16安装Ubuntu16.04图文教程 1、centos7的ios镜像下载 官网&#xff1a;https://vault.centos.org/ 阿里云&#xff1a;https://develo…

Idea入门:一分钟创建一个Java工程

一&#xff0c;新建一个Java工程 1&#xff0c;启动Idea后&#xff0c;选择 [New Project] 2&#xff0c;完善工程信息 填写工程名称&#xff0c;根据实际用途取有意义的英文名称选择Java语言&#xff0c;可以看到还支持Kotlin、Javascript等语言选择包管理和项目构建工具Mav…

新闻资讯微信小程序开发后端+php【附源码,文档说明】

博主介绍&#xff1a;✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3…

2024最新版JavaScript逆向爬虫教程-------基础篇之无限debugger的原理与绕过

目录 一、无限debugger的原理与绕过1.1 案例介绍1.2 实现原理1.3 绕过debugger方法1.3.1 禁用所有断点1.3.2 禁用局部断点1.3.3 替换文件1.3.4 函数置空与hook 二、补充2.1 改写JavaScript文件2.2 浏览器开发者工具中出现的VM开头的JS文件是什么&#xff1f; 三、实战 一、无限…

Java构造方法详解

在Java方法内部定义一个局部变量时&#xff0c;必须要初始化&#xff0c;否则就会编译失败&#xff0c;如下&#xff1a; 要让上述代码通过编译&#xff0c;只需在使用a之前给a赋一个初始值即可 如果是对象&#xff1a;下面用一个日期类演示 我们没有给年月日赋值&#xff0c;…

laravel8 导入 excel常见问题

上传xls 或 xlsx 文件后&#xff0c;文件解析为 zip 格式&#xff0c;输入正常情况&#xff0c;不影响解析 里面的内容 遇到解析内容&#xff0c;解析为空的情况&#xff0c;可能是 因为excel 存在多个 Sheet1 造成&#xff0c;服务器不能解析一个 Sheet1 的情况&#xff0…

阿里开源编程大模型 CodeQwen1.5:64K92编程语言,Code和SQL编程,评测接近GPT-4-Turbo

前言 阿里巴巴最近发布的CodeQwen1.5模型标志着其在编程语言模型领域的一次重大突破。这款开源模型不仅支持高达92种编程语言和64K的上下文长度&#xff0c;而且在多项性能评测中显示出接近或超过当前行业领导者GPT-4-Turbo的能力。 Huggingface模型下载&#xff1a;https://h…

# ERROR: node with name “rabbit“ already running on “MS-ITALIJUXHAMJ“ 解决方案

ERROR: node with name “rabbit” already running on “MS-ITALIJUXHAMJ” 解决方案 一、问题描述&#xff1a; 1、启动 rabbitmq-server.bat 服务时&#xff0c;出错 Error 2、查询 rabbitmqctl status 状态时&#xff0c;出错 Error 3、停止 rabbitmqctl stop 服务时&a…

如何使用CertCrunchy从SSL证书中发现和识别潜在的主机名称

关于CertCrunchy CertCrunchy是一款功能强大的网络侦查工具&#xff0c;该工具基于纯Python开发&#xff0c;广大研究人员可以利用该工具轻松从SSL证书中发现和识别潜在的主机信息。 支持的在线源 该工具支持从在线源或给定IP地址范围获取SSL证书的相关数据&#xff0c;并检索…

A Dexterous Hand-Arm Teleoperation System

A Dexterous Hand-Arm Teleoperation System Based on Hand Pose Estimation and Active Vision解读 摘要1. 简介2.相关工作2.1 机器人遥操作2.2 主动视觉&#xff08;Active Vision&#xff09; 3. 硬件设置4. 基于视觉的机器人手部姿态估计4.1 Transteleop4.2 Dataset 5. 主动…

【基础绘图】 09.小提琴图

效果图&#xff1a; 主要步骤&#xff1a; 1. 数据准备&#xff1a;生成随机数组 2. 数据处理&#xff1a;计算四分位数、中位数、均值、最大最小值 3. 图像绘制&#xff1a;绘制小提琴图 详细代码&#xff1a;着急的直接拖到最后有完整代码 步骤一&#xff1a;导入库包及…