【51单片机快速入门指南】4.4.1:python串口接收磁力计数据并进行最小二乘法椭球拟合

目录

  • 硬知识
  • Python代码
  • 使用方法
    • 串口收集数据
    • 椭球拟合
    • 验证

STC15F2K60S2 16.384MHz
Keil uVision V5.29.0.0
PK51 Prof.Developers Kit Version:9.60.0.0
Python 3.8.11 (default, Aug 6 2021, 09:57:55) [MSC v.1916 64 bit (AMD64)] :: Anaconda, Inc. on win32


参考资料:
笔记:python读取串口数据并保到本地txt文件 —— 大头工程师笔记
最小二乘法拟合—基本原理 —— 铁头娃-wefly

硬知识

椭球面的标准方程为:
        ((x−xo)/A)2+((y−yo)/B)2+((z−zo)/C)2=1((x-x_o)/A)^2+((y-y_o)/B)^2+((z-z_o)/C)^2=1((xxo)/A)2+((yyo)/B)2+((zzo)/C)2=1
需要拟合的参数有
        xo,yo,zo,A,B,Cx_o,y_o,z_o,A,B,CxoyozoABC
六个,他们分别是椭球的球心坐标和半轴长。
将标准方程写成一般形式为:
        x2+ay2+bz2+cx+dy+ez+f=0x^2+ ay^2+ bz^2+cx+dy +ez+f=0x2+ay2+bz2+cx+dy+ez+f=0
通过对参数a,b,c,d,e、fa,b,c,d,e、fabcdef的求解间接求出参数xo,yo,zo,A,B,Cx_o,y_o,z_o,A,B,CxoyozoABC
将实测得到的点代入一般形式,可得到对应的误差项,所有点的误差平方和记作
        E(a,b,c,d,e,f)=∑i=1Nei(a,b,c,d,e,f)2E(a,b,c,d,e,f) = \sum_{i=1}^{N}e_i(a,b,c,d,e,f)^2E(a,b,c,d,e,f)=i=1Nei(a,b,c,d,e,f)2
求偏导数并令其为0:
        ∂E/∂a=0\partial E/\partial a = 0E/a=0,
        ∂E/∂b=0\partial E/\partial b = 0E/b=0,
        ∂E/∂c=0\partial E/\partial c = 0E/c=0,
        ∂E/∂d=0\partial E/\partial d = 0E/d=0,
        ∂E/∂e=0\partial E/\partial e = 0E/e=0,
        ∂E/∂f=0\partial E/\partial f = 0E/f=0

        (2y4)∗a+(2y2z2)∗b+(2xy2)∗c+(2y3)∗d+(2y2z)∗e+(2y2)∗f+2x2y2=0(2y^4)*a+(2y^2z^2)*b+(2xy^2)*c+(2y^3)*d +(2y^2z)*e+(2y^2)*f+2x^2y^2=0(2y4)a+(2y2z2)b+(2xy2)c+(2y3)d+(2y2z)e+(2y2)f+2x2y2=0
        (2y2z2)∗a+(2z4)∗b+(2xz2)∗c+(2yz2)∗d+(2z3)∗e+(2z2)∗f+2x2z2=0(2y^2z^2)*a +(2z^4)*b+(2xz^2)*c +(2yz^2)*d+(2z^3)*e +(2z^2)*f +2x^2z^2=0(2y2z2)a+(2z4)b+(2xz2)c+(2yz2)d+(2z3)e+(2z2)f+2x2z2=0
        (2xy2)∗a+(2xz2)∗b+(2x2)∗c+(2xy)∗d+(2xz)∗e+(2x)∗f+2x3=0(2xy^2)*a+(2xz^2)*b+(2x^2)*c+(2xy)*d+(2xz)*e +(2x)*f+2x^3=0(2xy2)a+(2xz2)b+(2x2)c+(2xy)d+(2xz)e+(2x)f+2x3=0
        (2y3)∗a+(2yz2)∗b+(2xy)∗c+(2y2)∗d+(2yz)∗e+(2y)∗f+2x2y=0(2y^3)*a +(2yz^2)*b+(2xy)*c+(2y^2)*d+(2yz)*e+(2y)*f+2x^2y=0(2y3)a+(2yz2)b+(2xy)c+(2y2)d+(2yz)e+(2y)f+2x2y=0
        (2y2z)∗a+(2z3)∗b+(2xz)∗c+(2yz)∗d+(2z2)∗e+(2z)∗f+2x2z=0(2y^2z)*a+(2z^3)*b+(2xz)*c+(2yz)*d+(2z^2)*e+(2z)*f+2x^2z=0(2y2z)a+(2z3)b+(2xz)c+(2yz)d+(2z2)e+(2z)f+2x2z=0
        (2y2)∗a+(2z2)∗b+(2x)∗c+(2y)∗d+(2z)∗e+(2)∗f+2x2=0(2y^2)*a+(2z^2)*b+(2x)*c+(2y)*d+(2z)*e+(2)*f+2x^2=0(2y2)a+(2z2)b+(2x)c+(2y)d+(2z)e+(2)f+2x2=0

解方程组可得a,b,c,d,e,fa,b,c,d,e,fabcdef,进而可得xo,yo,zo,A,B,Cx_o,y_o,z_o,A,B,CxoyozoABC
上面的六个等式中,设参数矩阵为AMatrixA_{Matrix}AMatrix,常数项移至右边为BMatrixB_{Matrix}BMatrix,参数项为x=[a,b,c,d,e,f]Tx=[a,b,c,d,e,f]^Tx=[a,b,c,d,e,f]T
AMatrix⋅x=BMatrixA_{Matrix}·x=B_{Matrix}AMatrixx=BMatrix
x=AMatrix−1⋅BMatrixx=A_{Matrix}^{-1}·B_{Matrix}x=AMatrix1BMatrix
        xo=−c/2x_o=-c/2xo=c/2
        yo=−d/(2a)y_o=-d/(2a)yo=d/(2a)
        zo=−e/(2b)z_o=-e/(2b)zo=e/(2b)
        A=xo2+a⋅yo2+b⋅zo2−fA = \sqrt{x_o^2 + a · y_o^2 + b · z_o^2 - f}A=xo2+ayo2+bzo2f
        B=A/aB = A / \sqrt{a}B=A/a
        C=A/bC = A / \sqrt{b}C=A/b

Python代码

if not 1:   # 0为串口收集数据,1为椭球拟合import serialser = serial.Serial(port='COM8',baudrate=1200,parity=serial.PARITY_NONE,  # 校验位stopbits=serial.STOPBITS_ONE,  # 停止位bytesize=serial.EIGHTBITS  # 数据位)First_Flag = 0while True:data = ser.readline()if First_Flag:  # 丢掉第一次的,避免写入半截数据f = open('./Data.txt', 'a')data = data.decode('utf-8')[:-1]f.write(data)f.close()print(data)First_Flag = 1
else:Data_Path = r'./Data.txt'f = open(Data_Path, 'r')X = []Y = []Z = []for _ in f:List = _.replace(",", " ").split()X.append(int(List[0]))Y.append(int(List[1]))Z.append(int(List[2]))f.close()from matplotlib.font_manager import FontPropertiesfrom numpy.linalg import invfrom numpy import arange, zerosfrom math import sqrt, sin, cosfrom matplotlib import pyplot as pltdef dot_Mul(arr1, arr2):return [a * b for a, b in zip(arr1, arr2)]PI = 3.1415926535897932384626433832795# 实测数据f = open(Data_Path, 'r')x = []y = []z = []for _ in f:List = _.replace(",", " ").split()x.append(int(List[0]))y.append(int(List[1]))z.append(int(List[2]))f.close()# 数据总数num_points = len(x)# 一次项均值x_avr = sum(x) / num_pointsy_avr = sum(y) / num_pointsz_avr = sum(z) / num_points# 二次项均值xx_avr = sum(dot_Mul(x, x)) / num_pointsyy_avr = sum(dot_Mul(y, y)) / num_pointszz_avr = sum(dot_Mul(z, z)) / num_pointsxy_avr = sum(dot_Mul(x, y)) / num_pointsxz_avr = sum(dot_Mul(x, z)) / num_pointsyz_avr = sum(dot_Mul(y, z)) / num_points# 三次项均值xxx_avr = sum(dot_Mul(dot_Mul(x, x), x)) / num_pointsxxy_avr = sum(dot_Mul(dot_Mul(x, x), y)) / num_pointsxxz_avr = sum(dot_Mul(dot_Mul(x, x), z)) / num_pointsxyy_avr = sum(dot_Mul(dot_Mul(x, y), y)) / num_pointsxzz_avr = sum(dot_Mul(dot_Mul(x, z), z)) / num_pointsyyy_avr = sum(dot_Mul(dot_Mul(y, y), y)) / num_pointsyyz_avr = sum(dot_Mul(dot_Mul(y, y), z)) / num_pointsyzz_avr = sum(dot_Mul(dot_Mul(y, z), z)) / num_pointszzz_avr = sum(dot_Mul(dot_Mul(z, z), z)) / num_points# 四次项均值yyyy_avr = sum(dot_Mul(dot_Mul(dot_Mul(y, y), y), y)) / num_pointszzzz_avr = sum(dot_Mul(dot_Mul(dot_Mul(z, z), z), z)) / num_pointsxxyy_avr = sum(dot_Mul(dot_Mul(dot_Mul(x, x), y), y)) / num_pointsxxzz_avr = sum(dot_Mul(dot_Mul(dot_Mul(x, x), z), z)) / num_pointsyyzz_avr = sum(dot_Mul(dot_Mul(dot_Mul(y, y), z), z)) / num_points# 系数矩阵A_Matrix = [[yyyy_avr, yyzz_avr, xyy_avr, yyy_avr, yyz_avr, yy_avr],[yyzz_avr, zzzz_avr, xzz_avr, yzz_avr, zzz_avr, zz_avr],[xyy_avr, xzz_avr, xx_avr, xy_avr, xz_avr, x_avr],[yyy_avr, yzz_avr, xy_avr, yy_avr, yz_avr, y_avr],[yyz_avr, zzz_avr, xz_avr, yz_avr, zz_avr, z_avr],[yy_avr, zz_avr, x_avr, y_avr, z_avr, 1]]# 等式右边的常数项矩阵B_Matrix = [[-xxyy_avr], [-xxzz_avr], [-xxx_avr], [-xxy_avr], [-xxz_avr], [-xx_avr]]result = inv(A_Matrix) @ B_Matrixxo = -result[2] / 2  # 拟合出的x坐标yo = -result[3] / (2 * result[0])  # 拟合出的y坐标zo = -result[4] / (2 * result[1])  # 拟合出的z坐标# 拟合出的x方向上的轴半径A = sqrt(xo * xo + result[0] * yo * yo + result[1] * zo * zo - result[5])# 拟合出的y方向上的轴半径B = A / sqrt(result[0])# 拟合出的z方向上的轴半径C = A / sqrt(result[1])ABC_avr = (A + B + C) / 3kA = ABC_avr / AkB = ABC_avr / BkC = ABC_avr / Cxo = xo[0]yo = yo[0]zo = zo[0]print("拟合结果: ")print("xo = ", xo)  # 椭球球心x坐标print("yo = ", yo)  # 椭球球心y坐标print("zo = ", zo)  # 椭球球心z坐标print("A = ", A)  # 拟合出的x方向上的轴半径print("B = ", B)  # 拟合出的y方向上的轴半径print("C = ", C)  # 拟合出的z方向上的轴半径print("kA = ", kA)print("kB = ", kB)print("kC = ", kC)num_alpha = 90num_sita = 45alfa = arange(0, num_alpha) * 1 * PI / num_alphasita = arange(0, num_sita) * 2 * PI / num_sitaX = zeros((num_alpha, num_sita))Y = zeros((num_alpha, num_sita))Z = zeros((num_alpha, num_sita))for i in range(0, num_alpha):for j in range(0, num_sita):X[i, j] = xo + A * sin(alfa[i]) * cos(sita[j])Y[i, j] = yo + B * sin(alfa[i]) * sin(sita[j])Z[i, j] = zo + C * cos(alfa[i])X = [i for arr in X for i in arr]Y = [i for arr in Y for i in arr]Z = [i for arr in Z for i in arr]fig = plt.figure()Font = FontProperties(fname=r"c:\windows\fonts\simsun.ttc", size=20)ax1 = fig.add_subplot(221, projection='3d')ax1.set_title('实测、拟合对比', fontproperties=Font)ax1.scatter3D(X, Y, Z)  # 拟合ax1.scatter3D(x, y, z)  # 实测ax2 = fig.add_subplot(222)ax2.set_title('x-y投影', fontproperties=Font)ax2.scatter(X, Y)ax2.scatter(x, y)ax3 = fig.add_subplot(223)ax3.set_title('x-z投影', fontproperties=Font)ax3.scatter(X, Z)ax3.scatter(x, z)ax4 = fig.add_subplot(224)ax4.set_title('y-z投影', fontproperties=Font)ax4.scatter(Y, Z)ax4.scatter(y, z)plt.show()

使用方法

HMC5883L、QMC5883L的驱动程序见【51单片机快速入门指南】4.4:I2C 读取HMC5883L / QMC5883L 磁力计

串口收集数据

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
转动板子到各个角度
当觉得收集够时停止脚本
在这里插入图片描述

椭球拟合

开始椭球拟合
在这里插入图片描述
得到拟合结果:
在这里插入图片描述
在这里插入图片描述

验证

将计算结果用于矫正输出
在这里插入图片描述
清理掉旧数据后重新收集并拟合,得到如下结果,可见新的球心偏移较未矫正前小,且得到的椭球更接近正球。
在这里插入图片描述

在这里插入图片描述

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

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

相关文章

MATLAB之基本语法之常用命令

1. whos(或者who) 可以查看command window的变量 当调试MATLAB程序时,该条命令经常用到!!! 2. clc 清除命令窗口内容但是不清除变量 3. clear 清除命令窗口内容并且清除变量 4. …

【51单片机快速入门指南】4.4.2:Mahony AHRS 九轴姿态融合获取四元数、欧拉角

目录传感器的方向源码Mahony_9.cMahony_9.h使用方法测试main.c效果STC15F2K60S2 22.1184MHz Keil uVision V5.29.0.0 PK51 Prof.Developers Kit Version:9.60.0.0 上位机:Vofa 1.3.10 移植自MPU6050 获取角度理论推导(三)—9轴融合算法 —— shao15232_1 传感器…

BZOJ 2160 拉拉队排练

2160: 拉拉队排练 Description 艾利斯顿商学院篮球队要参加一年一度的市篮球比赛了。拉拉队是篮球比赛的一个看点,好的拉拉队往往能帮助球队增加士气,赢得最终的比赛。所以作为拉拉队队长的楚雨荨同学知道,帮助篮球队训练好拉拉队有多么的重要…

React Native获取设备信息组件

转载 https://www.jianshu.com/p/907b003835dc本文原创首发于公众号:ReactNative开发圈,转载需注明出处。这次介绍的获取移动设备信息的组件名叫:react-native-device-info,兼容IOS和安卓双平台,可以获取设备ID、设备品…

UNIX网络编程——套接字选项(SO_RCVBUF和SO_SNDBUF)

有时候我们需要控制套接字的行为(如修改缓冲区的大小),这个时候我们就要学习套接字选项。int getsockopt(int sockfd,int level,int optname,void *optval,socklen_t *optlen) int setsockopt(int sockfd,int level,int optname,const void *optval,socklen_t *optlen)level指定…

【51单片机快速入门指南】4.4.3:Madgwick AHRS 九轴姿态融合获取四元数、欧拉角

目录传感器的方向源码Madgwick_9.cMadgwick_9.h使用方法测试main.c效果STC15F2K60S2 22.1184MHz Keil uVision V5.29.0.0 PK51 Prof.Developers Kit Version:9.60.0.0 上位机:Vofa 1.3.10 移植自AHRS —— LOXO,算法作者:SOH Madgwick 传…

关于json格式字符串解析并用mybatis存入数据库

园子里面找了很多关于json解析后存入数据库的方法,不是太乱,就是没有写完,我下面的主题代码多是受下面两位的启发,请按顺序查看 http://www.cnblogs.com/tian830937/p/6364622.html,我沿用了这个例子中的json数据格式,…

【Hibernate3.3复习知识点二】 - 配置hibernate环境(annotations)

配置文件hibernate.cfg.xml中引入&#xff1a;<mapping class"com.bjsxt.hibernate.Teacher"/> <hibernate-configuration><session-factory><!-- Database connection settings --><property name"connection.driver_class"&g…

【51单片机快速入门指南】4.5:I2C 与 TCA6416实现双向 IO 扩展

目录硬知识IO 扩展芯片 TCA6416ATAC6416A 的寄存器IO 输入寄存器IO 输出寄存器IO 反相寄存器IO 方向寄存器TCA6416A 的操作TCA6416A 写数据TCA6416A 读数据TCA6416A 的 IO 输入寄存器硬件布局示例程序TCA6416A.cTCA6416A.h测试程序main.c实验现象普中51-单核-A2 STC89C52 MSP43…

linux/window 下 solr5.1 tomcat7.x 环境搭建即简单功能测试

2019独角兽企业重金招聘Python工程师标准>>> 之所以想使用solr来进行学习&#xff0c;很大一部分原因就是&#xff0c;solr能够在某种程度上提供RESTFUL相关的URL请求连接&#xff0c;可以把它理解为 以搜索引擎为基础的存储服务系统 &#xff0c;由于他的搜索可以是…

【Java基础总结】多线程

1. 实现多线程的两种方式 1 //第一种&#xff1a;继承Thread类&#xff0c;重写run()方法2 class ThreadTest1 extends Thread{3 public void run(){4 String threadName Thread.currentThread().getName();5 for(int i0;i<10;i){6 System…

【51单片机快速入门指南】5:软件SPI

目录硬知识SPI协议简介SPI接口介绍SPI接口连接图SPI数据传输方向SPI传输模式软件SPI程序源码Soft_SPI.cSoft_SPI.h普中51-单核-A2 STC89C52 Keil uVision V5.29.0.0 PK51 Prof.Developers Kit Version:9.60.0.0 上位机&#xff1a;Vofa 1.3.10 源于软件模拟SPI接口程序代码&…

svn搭建本地服务端

使用VisualSVN Server来完成,下载地址:https://www.visualsvn.com/server/download/ 我安装的版本是3.3.1,安装的时候选择了标准版本&#xff0c;另外一个版本需要付费(日志跟踪、VDFS等功能)更多可以参考https://www.visualsvn.com/server/licensing/安装完成之后&#xff0c;…

【51单片机快速入门指南】5.1:SPI与DS1302时钟芯片

目录硬知识DS1302 简介DS1302 使用控制寄存器日历/时钟寄存器DS1302 的读写时序电路设计示例程序DS1302.cDS1302.h测试程序main.c实验现象普中51-单核-A2 STC89C52 Keil uVision V5.29.0.0 PK51 Prof.Developers Kit Version:9.60.0.0 硬知识 摘自《普中 51 单片机开发攻略》…

【格局视野】三色需求与工作层次

三色需求 人们的社会经济生活本身就是一个互相交换&#xff0c;价值传递的循环&#xff0c;但这个循环有一个核心&#xff0c;这个核心就是社会大众的需求&#xff0c;也可以称为市场需求&#xff0c;围绕这个需求产生了层级递进的需求关系。 第一个层次是蓝色需求 是最基础的社…

关于linux-Centos 7下mysql 5.7.9的rpm包的安装方式

环境介绍>>>>>>>>>>>>>>>>>> 操作系统&#xff1a;Centos 7.1 mysql数据库版本&#xff1a;mysql5.7.9 mysql官方网站&#xff1a;http://www.mysql.com 原文地址&#xff1a;http://www.cnblogs.com/5201351/p/4912614…

【51单片机快速入门指南】5.2:SPI读取 12位ADC XPT2046 芯片

目录硬知识ADC 简介分辨率转换误差转换速率ADC 转换原理逐次逼近型 ADC双积分型 ADCXPT2046 芯片介绍参考电压内部参考电压外部参考电压输入工作模式单端工作模式差分工作模式温度测量电池电压测量压力测量数字接口笔中断输出转换周期16 时钟周期转换数字时序15 时钟周期转换数…

flask中 app.run(host='0.0.0.0', port=5000, debug=False) 不能用外网ip访问的解决办法

pycharm 2018开启debug模式和修改host&#xff1a; 在Pycharm 2018中&#xff0c;如果想要开启debug模式和更改端口号&#xff0c;则需要编辑项目配置。直接在app.run中更改是无效的。示例图如下&#xff1a; 将 app.run() 改成 app.run(debugFalse) 保存文件&#xff0c…

开发第一个spring boot应用

为什么80%的码农都做不了架构师&#xff1f;>>> 我们来用spring boot开发一个简单的“hello world”web应用&#xff0c;使用maven构建。开始之前&#xff0c;先检查你的java与maven的版本&#xff0c;看是否是spring boot1.3支持的版本&#xff1a; $ java -versi…

机器学习中规则化和模型选择知识

1 问题 模型选择问题&#xff1a;对于一个学习问题&#xff0c;可以有多种模型选择。比如要拟合一组样本点&#xff0c;可以使用线性回归&#xff0c;也可以用多项式回归。那么使用哪种模型好呢&#xff08;能够在偏差和方差之间达到平衡最优&#xff09;&#xff1f; 还有一类…