首页 > 其他分享 >(2)从txt读取GPS数据 真实GPS和slam定位GPS匹配 坐标系ecef和enu转化 计算均方根误差和单帧误差 画图

(2)从txt读取GPS数据 真实GPS和slam定位GPS匹配 坐标系ecef和enu转化 计算均方根误差和单帧误差 画图

时间:2023-01-25 22:34:20浏览次数:48  
标签:误差 txt list 方根 slam enu error GPS gps

 

 

 

 

#!/usr/bin/python
# -*- coding: UTF-8 -*-
  
import numpy as np
import os
  


  
#==========================1坐标系转换函数API===============================
import math

a = 6378137
b = 6356752.3142
f = (a - b) / a
e_sq = f * (2-f)
pi = 3.14159265359


'''
功能: # gps转化到大地坐标系ECEF
输入:
等待转换的GPS   坐标 lat, lon, h
输出:
ecef  坐标 x, y, z 
'''


def geodetic_to_ecef(lat, lon, h):
    lat=float(lat)
    lon=float(lon)
    h=float(h)

    # (lat, lon) in degrees
    # h in meters
    lamb = math.radians(lat)
    phi = math.radians(lon)
    s = math.sin(lamb)
    N = a / math.sqrt(1 - e_sq * s * s)

    sin_lambda = math.sin(lamb)
    cos_lambda = math.cos(lamb)
    sin_phi = math.sin(phi)
    cos_phi = math.cos(phi)

    x = (h + N) * cos_lambda * cos_phi
    y = (h + N) * cos_lambda * sin_phi
    z = (h + (1 - e_sq) * N) * sin_lambda

    return x, y, z

    

'''
功能: # 大地坐标系 转化到GPS第一帧为原点的本地ENU坐标系
输入:
等待转换的ecef       坐标 x, y, z 
作为原点的GPS第一帧   坐标lat0, lon0, h0
输出:
本地第一帧GPS为原点的 ENU 坐标系 xEast, yNorth, zUp

'''
def ecef_to_enu(x, y, z, lat0, lon0, h0):

    x=float(x)
    y=float(y)
    z=float(z)
    lat0=float(lat0)
    lon0=float(lon0)
    h0=float(h0)

    lamb = math.radians(lat0)
    phi = math.radians(lon0)
    s = math.sin(lamb)
    N = a / math.sqrt(1 - e_sq * s * s)

    sin_lambda = math.sin(lamb)
    cos_lambda = math.cos(lamb)
    sin_phi = math.sin(phi)
    cos_phi = math.cos(phi)

    x0 = (h0 + N) * cos_lambda * cos_phi
    y0 = (h0 + N) * cos_lambda * sin_phi
    z0 = (h0 + (1 - e_sq) * N) * sin_lambda

    xd = x - x0
    yd = y - y0
    zd = z - z0

    t = -cos_phi * xd -  sin_phi * yd

    xEast = -sin_phi * xd + cos_phi * yd
    yNorth = t * sin_lambda  + cos_lambda * zd
    zUp = cos_lambda * cos_phi * xd + cos_lambda * sin_phi * yd + sin_lambda * zd

    return xEast, yNorth, zUp

'''
功能: enu坐标转化到ecef坐标
输入:
等待转换的ENU坐标   坐标 xEast, yNorth, zUp
GPS第一帧原点      坐标 lat0, lon0, h0
输出:
ecef  坐标 x, y, z 
'''

def enu_to_ecef(xEast, yNorth, zUp, lat0, lon0, h0):
    xEast=float(xEast)
    yNorth=float(yNorth)
    zUp=float(zUp)
    lat0=float(lat0)
    lon0=float(lon0)
    h0=float(h0)

    lamb = math.radians(lat0)
    phi = math.radians(lon0)
    s = math.sin(lamb)
    N = a / math.sqrt(1 - e_sq * s * s)

    sin_lambda = math.sin(lamb)
    cos_lambda = math.cos(lamb)
    sin_phi = math.sin(phi)
    cos_phi = math.cos(phi)

    x0 = (h0 + N) * cos_lambda * cos_phi
    y0 = (h0 + N) * cos_lambda * sin_phi
    z0 = (h0 + (1 - e_sq) * N) * sin_lambda

    t = cos_lambda * zUp - sin_lambda * yNorth

    zd = sin_lambda * zUp + cos_lambda * yNorth
    xd = cos_phi * t - sin_phi * xEast 
    yd = sin_phi * t + cos_phi * xEast

    x = xd + x0 
    y = yd + y0 
    z = zd + z0 

    return x, y, z

'''
功能: # 大地坐标系ECEF转化到gps
输入:
等待转换的ecef  坐标 x, y, z 
输出:
GPS   坐标 lat, lon, h

'''
def ecef_to_geodetic(x, y, z):
    x=float(x)
    y=float(y)
    z=float(z)
   # Convert from ECEF cartesian coordinates to 
   # latitude, longitude and height.  WGS-84
    x2 = x ** 2 
    y2 = y ** 2 
    z2 = z ** 2 

    a = 6378137.0000    # earth radius in meters
    b = 6356752.3142    # earth semiminor in meters 
    e = math.sqrt (1-(b/a)**2) 
    b2 = b*b 
    e2 = e ** 2 
    ep = e*(a/b) 
    r = math.sqrt(x2+y2) 
    r2 = r*r 
    E2 = a ** 2 - b ** 2 
    F = 54*b2*z2 
    G = r2 + (1-e2)*z2 - e2*E2 
    c = (e2*e2*F*r2)/(G*G*G) 
    s = ( 1 + c + math.sqrt(c*c + 2*c) )**(1/3) 
    P = F / (3 * (s+1/s+1)**2 * G*G) 
    Q = math.sqrt(1+2*e2*e2*P) 
    ro = -(P*e2*r)/(1+Q) + math.sqrt((a*a/2)*(1+1/Q) - (P*(1-e2)*z2)/(Q*(1+Q)) - P*r2/2) 
    tmp = (r - e2*ro) ** 2 
    U = math.sqrt( tmp + z2 ) 
    V = math.sqrt( tmp + (1-e2)*z2 ) 
    zo = (b2*z)/(a*V) 

    height = U*( 1 - b2/(a*V) ) 
    
    lat = math.atan( (z + ep*ep*zo)/r ) 

    temp = math.atan(y/x) 
    if x >=0 :    
        long = temp 
    elif (x < 0) & (y >= 0):
        long = pi + temp 
    else :
        long = temp - pi 

    lat0 = lat/(pi/180) 
    lon0 = long/(pi/180) 
    h0 = height 

    return lat0, lon0, h0

'''
功能: # gps直接转化到enu坐标系
       相对于指定GPS_ref为原点(一般都是第一帧)的enu坐标系
输入:
等待转换的GPS   坐标 lat, lon, h
参考原点GPS     坐标 lat_ref, lon_ref, h_ref
输出:
enu坐标 x, y, z

'''
def geodetic_to_enu(lat, lon, h, lat_ref, lon_ref, h_ref):
    lat=float(lat)
    lon=float(lon)
    h=float(h)
    lat_ref=float(lat_ref)
    lon_ref=float(lon_ref)
    h_ref=float(h_ref)

    x, y, z = geodetic_to_ecef(lat, lon, h)
    
    return ecef_to_enu(x, y, z, lat_ref, lon_ref, h_ref)
'''
功能: # enu直接转化到gps坐标系
       相对于指定GPS_ref为原点(一般都是第一帧)的enu坐标系
输入:
等待转换的enu   坐标 xEast, yNorth, zUp
参考原点GPS     坐标 lat_ref, lon_ref, h_ref
输出:
GPS   坐标 lat, lon, h

'''
def enu_to_geodetic(xEast, yNorth, zUp, lat_ref, lon_ref, h_ref):
    xEast=float(xEast)
    yNorth=float(yNorth)
    zUp=float(zUp)

    lat_ref=float(lat_ref)
    lon_ref=float(lon_ref)
    h_ref=float(h_ref)
    x,y,z = enu_to_ecef(xEast, yNorth, zUp, lat_ref, lon_ref, h_ref)

    return ecef_to_geodetic(x,y,z)





 
 

'''
#功能: 计算两个GPS之间的距离

输入 
gps坐标 lat1,lng1,high1
gps坐标 lat2,lng2,high2
输出
直角坐标系下的 distance=sqrt(x^2+y^2+z^2)

'''
 
def geodistance(lat1,lng1,high1,lat2,lng2,high2):
    lat1=float(lat1)
    lng1=float(lng1)
    high1=float(high1)
    lat2=float(lat2)
    lng2=float(lng2)
    high2=float(high2)

    xyz1=geodetic_to_ecef(lat1,lng1,high1)#转化为ecef坐标系
    xyz2=geodetic_to_ecef(lat2,lng2,high2)#转化为ecef坐标系
    #distance=sqrt((xyz1[0]-xyz2[0])**2+(xyz1[1]-xyz2[1])**2+(xyz1[2]-xyz2[2])**2)

    distance=sqrt((xyz1[0]-xyz2[0])**2+(xyz1[1]-xyz2[1])**2)

    #lng1,lat1,lng2,lat2 = (120.12802999999997,30.28708,115.86572000000001,28.7427)
    #lng1, lat1, lng2, lat2 = map(radians, [float(lng1), float(lat1), float(lng2), float(lat2)]) # 经纬度转换成弧度
    #dlon=lng2-lng1
    #dlat=lat2-lat1
    #a=sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
    #distance=2*asin(sqrt(a))*6378137.0 # 地球平均半径,6371km C_EARTH=6378137.0
    #distance=sqrt(distance*distance+(high2-high1)*(high2-high1))
    distance=round(distance,3)

    return distance


#=======================2ENU时间戳XYZ读取=============================
#函数功能 从TXT读取ENU
"""
输入  path_txt  txt文件名字
数据格式 时间戳 x y z
497.12283301353455', '34.0344212093', '108.756020573', '400.164

输出
positionList   x y z

"""
def readtxt_ENU(path_txt,fengefu=" "):
  
    f = open(path_txt, mode='r+', encoding='utf-8')  # 打开txt文件,以‘utf-8’编码读取
    lines = f.readlines()   # 以行的形式进行读取文件
  
    positionList=[]
    list_x=[]
    list_y=[]
    list_z=[]

    
 
    for line in lines:
 

        lines=line.strip().split(fengefu)    # x.strip()#除去每行的换行符 按照:分割
        #print(lines)
        positionList_i=[0,0,0]
        
        timesharp = lines[0:1]
        timesharp="".join(timesharp).strip()

        ENU_X_N = lines[1:2] # list--str
        ENU_X_N="".join(ENU_X_N).strip()
        ENU_Y_E = lines[2:3] # list--str
        ENU_Y_E="".join(ENU_Y_E).strip()
        ENU_Z_U = lines[3:4] # list--str
        ENU_Z_U="".join(ENU_Z_U).strip()


        #positionList_i[0]=float(timesharp)
        positionList_i[0]=float(ENU_X_N)
        positionList_i[1]=float(ENU_Y_E)
        positionList_i[2]=float(ENU_Z_U)

 
        positionList.append(positionList_i)
        list_x.append(float(ENU_X_N))
        list_y.append(float(ENU_Y_E))
        list_z.append(float(ENU_Z_U))
      

    #是否排序
    #gps_list_1t2lon3lathigh = sorted(positionList,key=lambda x: float(x[0]))#以时间戳排序
    #print(gps_list_1t2lon3lathigh)
    
    f.close()
  
    return positionList,list_x,list_y,list_z



#函数功能 从TXT读取ENU 各轴的误差
"""
输入  path_txt  txt文件名字
数据格式 时间戳 x y z  error_x error_y error_z 
497.12283301353455', '34.0344212093', '108.756020573', '400.164 3.1 12 3.4

输出
positionList   error_x error_y error_z 

"""
def readtxt_ENU_Error(path_txt,fengefu=" "):
  
    f = open(path_txt, mode='r+', encoding='utf-8')  # 打开txt文件,以‘utf-8’编码读取
    lines = f.readlines()   # 以行的形式进行读取文件
  
    positionList=[]
    list_x=[]
    list_y=[]
    list_z=[]

    
 
    for line in lines:
 

        lines=line.strip().split(fengefu)    # x.strip()#除去每行的换行符 按照:分割
        #print(lines)
        positionList_i=[0,0,0]
        
        timesharp = lines[0:1]
        timesharp="".join(timesharp).strip()

        ENU_X_N = lines[4:5] # list--str
        ENU_X_N="".join(ENU_X_N).strip()
        ENU_Y_E = lines[5:6] # list--str
        ENU_Y_E="".join(ENU_Y_E).strip()
        ENU_Z_U = lines[6:7] # list--str
        ENU_Z_U="".join(ENU_Z_U).strip()

        try:
            #positionList_i[0]=float(timesharp)
            positionList_i[0]=float(ENU_X_N)
            positionList_i[1]=float(ENU_Y_E)
            positionList_i[2]=float(ENU_Z_U)

    
            positionList.append(positionList_i)
            list_x.append(float(ENU_X_N))
            list_y.append(float(ENU_Y_E))
            list_z.append(float(ENU_Z_U))
        except ValueError :
            print("转化失败",i)
      

    #是否排序
    #gps_list_1t2lon3lathigh = sorted(positionList,key=lambda x: float(x[0]))#以时间戳排序
    #print(gps_list_1t2lon3lathigh)
    
    f.close()
  
    return positionList,list_x,list_y,list_z



#=======================2GPS时间戳读取=============================
#函数名 读取txt中指定位置参数内容
#函数输入:
# path_txt  txt文件地址
# canshu    要从txt读取的内容
# fengefu   参数名字和值的分隔符号 默认 -
  
#gps数据格式
'''
gps.txt数据格式
  
编号 time  time 状态 真实gps 经度 纬度 高度 定位gps 经度 纬度 高度   
6.205903053283691 20230106172032520 1 108.75606035 34.0343725537 401.804 108.756070682 34.0343699087 401.72557778 1.14883264001 0.24373170974 0.0784222199544 -0.613050855174 -3.07510515832 62.2546435577 0.932564436131
1 6.407103061676025 20230106172032580 1 108.75606035 34.0343725537 402.142 108.756070552 34.0343699422 402.066939582 1.13442871038 0.240639960882 0.0750604180848 -0.737572900119 -3.47568977187 61.9155967908 0.937691115842
2 6.474128007888794 20230106172032621 1 -1 -1 -1 108.756070391 34.0343699572 402.139887106 0 0 0 -0.576328599814 -3.69308815477 61.8199687376 1
'''
  
#函数输出
# gps_list_1t2lon3lathigh 按照时间戳排序的位置列表
  
# 返回字符型结果
   
def readtxt_gps_havegps_we(path_txt,fengefu=" "):
  
    f = open(path_txt, mode='r+', encoding='utf-8')  # 打开txt文件,以‘utf-8’编码读取
    lines = f.readlines()   # 以行的形式进行读取文件
  
    positionList=[]
    
    first_line=0# 跳过第一行 有乱码
    for line in lines:
        if first_line==0:
            first_line=1
            continue

        lines=line.strip().split(fengefu)    # x.strip()#除去每行的换行符 按照:分割
        #print(lines)
        positionList_i=[0,0,0,0,0,0,0]
        
        timesharp = lines[1:2]
        timesharp="".join(timesharp).strip()
        #state = lines[3:4] # list--str    
        #state="".join(state).strip()

        real_gps_lon = lines[4:5] # list--str
        real_gps_lon="".join(real_gps_lon).strip()
        real_gps_lat = lines[5:6] # list--str
        real_gps_lat="".join(real_gps_lat).strip()
        real_gps_high = lines[6:7] # list--str
        real_gps_high="".join(real_gps_high).strip()

        
        slam_gps_lon = lines[7:8] # list--str
        slam_gps_lon="".join(slam_gps_lon).strip()
        slam_gps_lat = lines[8:9] # list--str
        slam_gps_lat="".join(slam_gps_lat).strip()
        slam_gps_high = lines[9:10] # list--str
        slam_gps_high="".join(slam_gps_high).strip()

        positionList_i[0]=timesharp

        positionList_i[1]=slam_gps_lat
        positionList_i[2]=slam_gps_lon
        positionList_i[3]=slam_gps_high

        positionList_i[4]=real_gps_lat
        positionList_i[5]=real_gps_lon
        positionList_i[6]=real_gps_high

        
        #positionList_i[7]=state

        positionList.append(positionList_i)
      

    #是否排序
    #gps_list_1t2lon3lathigh = sorted(positionList,key=lambda x: float(x[0]))#以时间戳排序
    
    #print(gps_list_1t2lon3lathigh)
    
    f.close()
  
    return positionList


#从slam保存轨迹读取 时间戳是带图像名字
"""
输入 path_txt
格式
名字(时间戳) x z y
54.55198812484741.png -0 0 -0
54.7531681060791.png -0.0088182097 -0.0730422019 -0.00989559283
54.82018804550171.png -0.00635520236 -0.0877061512 -0.0110012228
54.954188108444214.png -0.00269816031 -0.118492937 -0.0137271836


"""
def readtxt_slamSaveTraceEnu(path_txt,fengefu=" "):
  
    f = open(path_txt, mode='r+', encoding='utf-8')  # 打开txt文件,以‘utf-8’编码读取
    lines = f.readlines()   # 以行的形式进行读取文件
  
    positionList=[]
    
    
    for line in lines:
        

        lines=line.strip().split(fengefu)    # x.strip()#除去每行的换行符 按照:分割
        #print(lines)
        positionList_i=[0,0,0,0]
        
        timesharp = lines[0:1]
        timesharp="".join(timesharp).strip()
        timesharp=timesharp[:-4]
        #timesharp.replace(".png","0")
        #print(timesharp)

        slam_x = lines[1:2] # list--str
        slam_x="".join(slam_x).strip()   
        slam_y = lines[2:3] # list--str
        slam_y="".join(slam_y).strip()
        slam_z = lines[3:4] # list--str
        slam_z="".join(slam_z).strip()

        positionList_i[0]=float(timesharp)
        positionList_i[1]=float(slam_x)
        positionList_i[2]=float(slam_y)
        positionList_i[3]=float(slam_z)

      

        
        #positionList_i[7]=state

        positionList.append(positionList_i)
      

    #是否排序
    #gps_list_1t2lon3lathigh = sorted(positionList,key=lambda x: float(x[0]))#以时间戳排序
    
    #print(gps_list_1t2lon3lathigh)
    
    f.close()
  
    return positionList



#函数名 读取txt中指定位置参数内容
#函数输入:
# path_txt  txt文件地址
# canshu    要从txt读取的内容
# fengefu   参数名字和值的分隔符号 默认 -
  
#gps数据格式
'''
gps.txt数据格式
  
编号 time  time 状态 真实gps 经度 纬度 高度 定位gps 经度 纬度 高度   
0.6401629447937012 34.0343737663 108.756061354 399.997
0.7071881294250488 34.0343737663 108.756061354 399.998
0.8412330150604248 34.0343737663 108.756061354 400.001
'''
  
#函数输出
# gps_list_1t2lon3lathigh 按照时间戳排序的位置列表
  
# 返回字符型结果
   
def readtxt_realgps(path_txt,fengefu=" "):


  
    f = open(path_txt, mode='r+', encoding='utf-8')  # 打开txt文件,以‘utf-8’编码读取
    lines = f.readlines()   # 以行的形式进行读取文件
  
    positionList=[]
    
    i=1
    for line in lines:
        #print(line)
        
        lines=line.strip().split(fengefu)    # x.strip()#除去每行的换行符 按照:分割
        #print(lines)
        positionList_i=[0,0,0,0]
        
        timesharp = lines[0:1]
        timesharp="".join(timesharp).strip()
        
        real_gps_lat = lines[1:2] # list--str
        real_gps_lat="".join(real_gps_lat).strip()
        real_gps_lon = lines[2:3] # list--str
        real_gps_lon="".join(real_gps_lon).strip()
        real_gps_high = lines[3:4] # list--str
        real_gps_high="".join(real_gps_high).strip()

        if real_gps_lat == "-1" or real_gps_lon=="-1" or real_gps_high=="-1":

            pass
        elif real_gps_lat == " " or real_gps_lon==" " or real_gps_high==" ":
            pass

        else :
            try:
                positionList_i[0]=float(timesharp)
                positionList_i[1]=float(real_gps_lat)
                positionList_i[2]=float(real_gps_lon)
                positionList_i[3]=float(real_gps_high)
            except ValueError :
                print("转化失败",i)
                i=i+1

            #if fixHigh>-1:
            #positionList_i[3]=fixHigh
            #print(positionList_i)
            positionList.append(positionList_i)
            #print(timesharp,real_gps_lat,real_gps_lon,real_gps_high)
      

    #是否排序
    #gps_list_1t2lon3lathigh = sorted(positionList,key=lambda x: float(x[0]))#以时间戳排序
    
    #print(gps_list_1t2lon3lathigh)
    
    f.close()
  
    return positionList

# 将对其的GPS 按照图像的名字重新保存成TXT
def save_TXT_realGPS_slamGPS(real_slam_gps_time,save_name):
 
    newgps_txtfile = open(save_name,'w')#若文件不存在,系统自动创建。'a'表示可连续写入到文件,保留原内容,在原内容之后写入。可修改该模式('w+','w','wb'等)
 
    for i in range(0,len(img_gps_sortlist)):

        img_time_name=real_slam_gps_time[i][6]

        gps_lat=(real_slam_gps_time[i][0])
        gps_lon=(real_slam_gps_time[i][1])
        gps_high=(real_slam_gps_time[i][2])

        slam_lat=(real_slam_gps_time[i][3])
        slam_lon=(real_slam_gps_time[i][4])
        slam_high=(real_slam_gps_time[i][5])   

        
 
        msggps=str(img_time_name)+" "+str(gps_lat)+" "+str(gps_lon)+" "+str(gps_high)+"\n"
        newgps_txtfile.write(msggps)
        #print("写入",i,msggps)
         
    newgps_txtfile.close()
    print("txt保存完毕,总计行数",len(img_gps_sortlist))






  

  
 
 
  
  
  

  
  





# 根据真实gps轨迹 查找slam的gps轨迹 匹配 并计算ecef下误差m
# 输出 时间戳  真实gps 纬度 经度 高度  匹配的SLAM gps 纬度 经度 高度 
# 775.079558134079 7747 10801 [775.079558134079, '34.0343986246', '108.756028006', '396.896', '34.0343943644', '108.75602437', '396.817510377']
#  
def from_realGPSFindslamGPS(realGPSlist,slamGPSlist):

    real_slam_list=[]
    real_slam_list_fail_nomarl=[]#没有匹配的gps集合
    real_slam_list_fail_error=[]#没有匹配的gps集合
    slam_last=0
    print(slamGPSlist[0][0],slamGPSlist[len(slamGPSlist)-1][0])
    time_begin=float(slamGPSlist[0][0])
    time_stop =float(slamGPSlist[len(slamGPSlist)-1][0])

    for i in range(0,len(realGPSlist)):

        realGPS_timesharp=float(realGPS_List[i][0])
        realGPS_lat=realGPS_List[i][1]
        realGPS_lon=realGPS_List[i][2]
        realGPS_high=realGPS_List[i][3]
        
        pipei=0

        for j in range(slam_last,len(slamGPSlist)):
            
            slamGPS_timesharp=float(slamGPSlist[j][0])

            if realGPS_timesharp==slamGPS_timesharp:



                slamGPS_lat =slamGPSlist[j][1]
                slamGPS_lon =slamGPSlist[j][2]
                slamGPS_high=slamGPSlist[j][3]
                
                #计算单个误差
                distance=geodistance(realGPS_lat,realGPS_lon,realGPS_high,slamGPS_lat,slamGPS_lon,slamGPS_high)
                

                real_slam_list_i=[realGPS_timesharp,realGPS_lat,realGPS_lon,realGPS_high,slamGPS_lat,slamGPS_lon,slamGPS_high,distance]
                real_slam_list.append(real_slam_list_i)

                

                slam_last=j
                pipei=1

                #print(realGPS_timesharp,i,j,real_slam_list_i)

                break
            else:
                pass

        if pipei==0:
            if realGPS_timesharp<time_begin or realGPS_timesharp>time_stop:# gps采集时间在slam外面
                real_slam_list_fail_nomarl.append([realGPS_timesharp,realGPS_lat,realGPS_lon,realGPS_high,"正常失败"])
            else:
                real_slam_list_fail_error.append([realGPS_timesharp,realGPS_lat,realGPS_lon,realGPS_high,"异常失败"])
        nomarl_fail=len(real_slam_list_fail_nomarl)
        error_fail=len(real_slam_list_fail_error)


    
    print("匹配成功数目",len(real_slam_list),"真值gps数目",len(realGPSlist),"slam定位gps数目",len(slamGPSlist),"正常失败",nomarl_fail,"异常失败",error_fail)
    return real_slam_list       

# 把匹配后的gps结果保存后才能txt 
# time_realgps_slamgps_list 匹配的数组
# save_realgpsname 真值保存txt名字
# save_slamgpsname slam保存txt名字
# 保存格式 时间戳 经度 纬度 高度
#            
def save_TXT_realGps_SLAMgps(time_realgps_slamgps_list,save_realgpsname,save_slamgpsname):
 
    realgps_txtfile = open(save_realgpsname,'w')#若文件不存在,系统自动创建。'a'表示可连续写入到文件,保留原内容,在原内容之后写入。可修改该模式('w+','w','wb'等)
    slamgps_txtfile = open(save_slamgpsname,'w')

    #time_realgps_slamgps_list=from_realGPSFindslamGPS(realGPS_List,slamGPS_List)
    for i in range(0,len(time_realgps_slamgps_list)):
        #print(i,time_realgps_slamgps_list[i])
        
        timesharp=time_realgps_slamgps_list[i][0]

        realGPS_lat=time_realgps_slamgps_list[i][1]
        realGPS_lon=time_realgps_slamgps_list[i][2]
        realGPS_high=time_realgps_slamgps_list[i][3]

        slamGPS_lat=time_realgps_slamgps_list[i][4]
        slamGPS_lon=time_realgps_slamgps_list[i][5]
        slamGPS_high=time_realgps_slamgps_list[i][6]


       

        #print("时间戳  真实gps 纬度 经度 高度  匹配的SLAM gps 纬度 经度 高度")

 
        realGPS_lat_msg=str(timesharp)+" "+str(realGPS_lat)+" "+str(realGPS_lon)+" "+str(realGPS_high)+"\n"
        realgps_txtfile.write(realGPS_lat_msg)

        slamgps_txtfilet_msg=str(timesharp)+" "+str(slamGPS_lat)+" "+str(slamGPS_lon)+" "+str(slamGPS_high)+"\n"
        slamgps_txtfile.write(slamgps_txtfilet_msg)
       
         
    realgps_txtfile.close()
    slamgps_txtfile.close()
    print("txt保存完毕,总计行数",len(time_realgps_slamgps_list))

# 把匹配后的enu结果保存后才能txt 
# time_realgps_slamgps_list 匹配的数组
# save_realgpsname 真值保存txt名字
# save_slamgpsname slam保存txt名字
# gps_ref[lat,lon,high] 参考原点
# threath 要剔除的阈值
# 保存格式 时间戳 x-n y-e z-u
#            
def save_TXT_realEnu_SLAMEnu(time_realgps_slamgps_list,save_realgpsenuname,save_slamgpsenuname,gps_ref,threath=99999):
 
    realgps_txtfile = open(save_realgpsenuname,'w')#若文件不存在,系统自动创建。'a'表示可连续写入到文件,保留原内容,在原内容之后写入。可修改该模式('w+','w','wb'等)
    slamgps_txtfile = open(save_slamgpsenuname,'w')

    #time_realgps_slamgps_list=from_realGPSFindslamGPS(realGPS_List,slamGPS_List)
    for i in range(0,len(time_realgps_slamgps_list)):
        #print(i,time_realgps_slamgps_list[i])
        
        timesharp=time_realgps_slamgps_list[i][0]

        realGPS_lat =time_realgps_slamgps_list[i][1]
        realGPS_lon =time_realgps_slamgps_list[i][2]
        realGPS_high=time_realgps_slamgps_list[i][3]

        xEast, yNorth, zUp=geodetic_to_enu(realGPS_lat,realGPS_lon,realGPS_high,gps_ref[0],gps_ref[1],gps_ref[2])
        realGPS_lat_msg=str(timesharp)+" "+str(xEast)+" "+str(yNorth)+" "+str(zUp)+"\n"
        realgps_txtfile.write(realGPS_lat_msg)
        
        
        slamGPS_lat =time_realgps_slamgps_list[i][4]
        slamGPS_lon =time_realgps_slamgps_list[i][5]
        slamGPS_high=time_realgps_slamgps_list[i][6]
        slamxEast, slamyNorth, slamzUp=geodetic_to_enu(slamGPS_lat,slamGPS_lon,slamGPS_high,gps_ref[0],gps_ref[1],gps_ref[2])

        #计算各轴误差
        error_xEast=slamxEast-xEast
        error_yEast=slamyNorth-yNorth    
        error_zEast=slamzUp-zUp
        
        #threath=10
        if abs(error_xEast)>threath or abs(error_yEast)>threath or abs(error_zEast)>threath:
            pass
        
        else:  
        #pass
        #打包信息保存一行
            error_msg=str(error_xEast)+" "+ str(error_yEast)+" "+ str(error_zEast)
            slamgps_txtfilet_msg=str(timesharp)+" "+str(slamxEast)+" "+str(slamyNorth)+" "+str(slamzUp)+" "+error_msg+"\n"
            slamgps_txtfile.write(slamgps_txtfilet_msg)




        #print("时间戳  真实gps 纬度 经度 高度  匹配的SLAM gps 纬度 经度 高度")

 



       
         
    realgps_txtfile.close()
    slamgps_txtfile.close()
    print("txt保存完毕,总计行数",len(time_realgps_slamgps_list))

from math import radians, cos, sin, asin, sqrt




from pyecharts import Line3D

import math

from pyecharts import Line

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
import numpy as np

# matplotlib画一条单独的3D轨迹
def Draw_trace1(x,y,z):
    fig = plt.figure()
    ax = fig.gca(projection='3d')

    ax.set_title("3D_Curve")
    ax.set_xlabel("x(m)")
    ax.set_ylabel("y(m)")
    ax.set_zlabel("z(m)")
    figure = ax.plot(x, y, z, c='r')
    
    plt.show()


# matplotlib将多条3D轨迹画在同一个图里

def Draw3D_trace_more(tracelist):

    fig = plt.figure()
    ax = fig.gca(projection='3d')
    

    #ax.set_title("3D_Curve")
    ax.set_xlabel("x(m)")
    ax.set_ylabel("y(m)")
    ax.set_zlabel("z(m)")

    
    ax.set_aspect("auto")#设置x,y z轴等比例

    color=["blue","green","red","orange","purple","pink","yellow"]
    linestyle=["-","--","-.","-"] #":"


    for i in range(0,len(tracelist)):

        xi_list=tracelist[i][0]
        yi_list=tracelist[i][1]
        zi_list=tracelist[i][2]
        
        color_i=color[i]
        figure = ax.plot(xi_list, yi_list, zi_list, c=color_i,linestyle=linestyle[0])

        
        #plt.xlim(-1500,100)
        #plt.ylim(-600,1600)

    #plt.zlim(-2,15)

    plt.grid()#网格线
    plt.show()

#画单个2维平面轨迹
def Draw2D_trace_gpsvreal(x1,y1,x2,y2):
    
    #绘画轨迹
    print("画轨迹图")
    plt.title('Error mapped onto trajectory')
    plt.ylabel('Y(m)')
    plt.xlabel('X(m)')
    #plt.annotate('blue ', xy=(2,5), xytext=(2, 10),arrowprops=dict(facecolor='black', shrink=0.01),)
    #x=[1, 2, 3, 4,3,2,1]
    #y=[1, 4, 9, 16,3,5,6]
    plt.plot(x1,y1,color='b',linestyle='dashed')

    '''
    color:线条颜色,值r表示红色(red)
    marker:点的形状,值o表示点为圆圈标记(circle marker)
    linestyle:线条的形状,值dashed表示用虚线连接各点
    '''
    #x=[3, 4, 5, 6]
    #y=[1, 4, 9, 16]

    #plt.plot(x2, y2, color='r',marker='o',linestyle='dashed')
    plt.plot(x2, y2, color='r')

    '''
    axis:坐标轴范围
    语法为axis[xmin, xmax, ymin, ymax],
    也就是axis[x轴最小值, x轴最大值, y轴最小值, y轴最大值]
    '''

    #plt.axis([0, 6, 0, 20])
    plt.grid()#网格线
    #plt.grid(axis='x',color = 'r', linestyle = '--', linewidth = 0.5)## 设置 y 就在轴方向显示网格线
    plt.show()   

#画3个对对比 2维平面轨迹
"""
输入 data_list 多个轨迹的enu列表
     要画的x轴 xlabel='X(m)' "Y(m)" "Z(m)"
     要画的y轴 ylabeln='X(m)' "Y(m)" "Z(m)"


"""


def Draw2D_trace_gpsvreal_list(data_list,xlabel='X(m)',ylabeln='Y(m)'):
    
    color=["blue","green","red","orange","purple","pink","yellow"]
    '''
    '-'       solid    line style
    '--'      dashed   line style
    '-.'      dash-dot line style
    ':'       dotted   line style
    '''
    linestyle=["-","--","-.","-"] #:
    xmax=0
    xmin=0
    ymax=0
    ymin=0
    for i in range(0,len(data_list)):

      
        linexylist=data_list[i]
        linexlist=[]
        lineylist=[]
        #根据轴 决定画的是侧视图还是俯视图
        if xlabel=="X(m)":
            linexlist=linexylist[0]
        elif xlabel=="Y(m)":
            linexlist=linexylist[1]
        elif xlabel=="Z(m)":
            linexlist=linexylist[2]    



        if ylabeln=="X(m)":
            lineylist=linexylist[0]
        elif ylabeln=="Y(m)":
            lineylist=linexylist[1]
        elif ylabeln=="Z(m)":
            lineylist=linexylist[2]

        threah=0
        #if xlabel=="X(m)" and ylabeln=="Y(m)":
            #threah=100
       

        # xmax=int(max(linexlist)+threah)
        # xmin=int(min(linexlist)-threah)
        # ymax=int(max(lineylist)+threah)
        # ymin=int(min(lineylist)-threah)
    
        #绘画轨迹
        #print("画轨迹图")
        #plt.title('Error mapped onto trajectory')
        
        plt.xlabel(xlabel)
        plt.ylabel(ylabeln)
        #plt.annotate('blue ', xy=(2,5), xytext=(2, 10),arrowprops=dict(facecolor='black', shrink=0.01),)
        #x=[1, 2, 3, 4,3,2,1]
        #y=[1, 4, 9, 16,3,5,6]
        color_i=color[i]
        line_i=linestyle[i]
        

        plt.plot(linexlist,lineylist,color=color_i,linestyle=line_i)

        #plt.xlim(xmin,xmax)
        #plt.ylim(ymin,ymax) 



    plt.grid()#网格线
    plt.show()   
       
'''
        color:线条颜色,值r表示红色(red)

            cnames = {
            'aliceblue':            '#F0F8FF',
            'antiquewhite':         '#FAEBD7',
            'aqua':                 '#00FFFF',
            'aquamarine':           '#7FFFD4',
            'azure':                '#F0FFFF',
            'beige':                '#F5F5DC',
            'bisque':               '#FFE4C4',
            'black':                '#000000',
            'blanchedalmond':       '#FFEBCD',
            'blue':                 '#0000FF',
            'blueviolet':           '#8A2BE2',
            'brown':                '#A52A2A',
            'burlywood':            '#DEB887',
            'cadetblue':            '#5F9EA0',
            'chartreuse':           '#7FFF00',
            'chocolate':            '#D2691E',
            'coral':                '#FF7F50',
            'cornflowerblue':       '#6495ED',
            'cornsilk':             '#FFF8DC',
            'crimson':              '#DC143C',
            'cyan':                 '#00FFFF',
            'darkblue':             '#00008B',
            'darkcyan':             '#008B8B',
            'darkgoldenrod':        '#B8860B',
            'darkgray':             '#A9A9A9',
            'darkgreen':            '#006400',
            'darkkhaki':            '#BDB76B',
            'darkmagenta':          '#8B008B',
            'darkolivegreen':       '#556B2F',
            'darkorange':           '#FF8C00',
            'darkorchid':           '#9932CC',
            'darkred':              '#8B0000',
            'darksalmon':           '#E9967A',
            'darkseagreen':         '#8FBC8F',
            'darkslateblue':        '#483D8B',
            'darkslategray':        '#2F4F4F',
            'darkturquoise':        '#00CED1',
            'darkviolet':           '#9400D3',
            'deeppink':             '#FF1493',
            'deepskyblue':          '#00BFFF',
            'dimgray':              '#696969',
            'dodgerblue':           '#1E90FF',
            'firebrick':            '#B22222',
            'floralwhite':          '#FFFAF0',
            'forestgreen':          '#228B22',
            'fuchsia':              '#FF00FF',
            'gainsboro':            '#DCDCDC',
            'ghostwhite':           '#F8F8FF',
            'gold':                 '#FFD700',
            'goldenrod':            '#DAA520',
            'gray':                 '#808080',
            'green':                '#008000',
            'greenyellow':          '#ADFF2F',
            'honeydew':             '#F0FFF0',
            'hotpink':              '#FF69B4',
            'indianred':            '#CD5C5C',
            'indigo':               '#4B0082',
            'ivory':                '#FFFFF0',
            'khaki':                '#F0E68C',
            'lavender':             '#E6E6FA',
            'lavenderblush':        '#FFF0F5',
            'lawngreen':            '#7CFC00',
            'lemonchiffon':         '#FFFACD',
            'lightblue':            '#ADD8E6',
            'lightcoral':           '#F08080',
            'lightcyan':            '#E0FFFF',
            'lightgoldenrodyellow': '#FAFAD2',
            'lightgreen':           '#90EE90',
            'lightgray':            '#D3D3D3',
            'lightpink':            '#FFB6C1',
            'lightsalmon':          '#FFA07A',
            'lightseagreen':        '#20B2AA',
            'lightskyblue':         '#87CEFA',
            'lightslategray':       '#778899',
            'lightsteelblue':       '#B0C4DE',
            'lightyellow':          '#FFFFE0',
            'lime':                 '#00FF00',
            'limegreen':            '#32CD32',
            'linen':                '#FAF0E6',
            'magenta':              '#FF00FF',
            'maroon':               '#800000',
            'mediumaquamarine':     '#66CDAA',
            'mediumblue':           '#0000CD',
            'mediumorchid':         '#BA55D3',
            'mediumpurple':         '#9370DB',
            'mediumseagreen':       '#3CB371',
            'mediumslateblue':      '#7B68EE',
            'mediumspringgreen':    '#00FA9A',
            'mediumturquoise':      '#48D1CC',
            'mediumvioletred':      '#C71585',
            'midnightblue':         '#191970',
            'mintcream':            '#F5FFFA',
            'mistyrose':            '#FFE4E1',
            'moccasin':             '#FFE4B5',
            'navajowhite':          '#FFDEAD',
            'navy':                 '#000080',
            'oldlace':              '#FDF5E6',
            'olive':                '#808000',
            'olivedrab':            '#6B8E23',
            'orange':               '#FFA500',
            'orangered':            '#FF4500',
            'orchid':               '#DA70D6',
            'palegoldenrod':        '#EEE8AA',
            'palegreen':            '#98FB98',
            'paleturquoise':        '#AFEEEE',
            'palevioletred':        '#DB7093',
            'papayawhip':           '#FFEFD5',
            'peachpuff':            '#FFDAB9',
            'peru':                 '#CD853F',
            'pink':                 '#FFC0CB',
            'plum':                 '#DDA0DD',
            'powderblue':           '#B0E0E6',
            'purple':               '#800080',
            'red':                  '#FF0000',
            'rosybrown':            '#BC8F8F',
            'royalblue':            '#4169E1',
            'saddlebrown':          '#8B4513',
            'salmon':               '#FA8072',
            'sandybrown':           '#FAA460',
            'seagreen':             '#2E8B57',
            'seashell':             '#FFF5EE',
            'sienna':               '#A0522D',
            'silver':               '#C0C0C0',
            'skyblue':              '#87CEEB',
            'slateblue':            '#6A5ACD',
            'slategray':            '#708090',
            'snow':                 '#FFFAFA',
            'springgreen':          '#00FF7F',
            'steelblue':            '#4682B4',
            'tan':                  '#D2B48C',
            'teal':                 '#008080',
            'thistle':              '#D8BFD8',
            'tomato':               '#FF6347',
            'turquoise':            '#40E0D0',
            'violet':               '#EE82EE',
            'wheat':                '#F5DEB3',
            'white':                '#FFFFFF',
            'whitesmoke':           '#F5F5F5',
            'yellow':               '#FFFF00',
            'yellowgreen':          '#9ACD32'}



        marker:点的形状,值o表示点为圆圈标记(circle marker)
                '.'       point marker
                ','       pixel marker
                'o'       circle marker
                'v'       triangle_down marker
                '^'       triangle_up marker
                '<'       triangle_left marker
                '>'       triangle_right marker
                '1'       tri_down marker
                '2'       tri_up marker
                '3'       tri_left marker
                '4'       tri_right marker
                's'       square marker
                'p'       pentagon marker
                '*'       star marker
                'h'       hexagon1 marker
                'H'       hexagon2 marker
                '+'       plus marker
                'x'       x marker
                'D'       diamond marker
                'd'       thin_diamond marker
                '|'       vline marker
                '_'       hline marker


        linestyle:线条的形状,值dashed表示用虚线连接各点
                '-'       solid line style
                '--'      dashed line style
                '-.'      dash-dot line style
                ':'       dotted line style
'''

   



#画单个折线图 水平误差折线 
def Draw2D(realgps_enu_listx,realgps_enu_listy,slamgps_enu_listx,slamgps_enu_listy):

    line = Line("真值和定位轨迹") 
    v_x = [5, 20, 36, 10, 10, 100]
    v_y = [55, 60, 16, 20, 15, 80]
    line.add("真值",
        realgps_enu_listx, 
        realgps_enu_listy, 
        #mark_point=["average"] 
    )

    line.add( 
        "SLAM",
        slamgps_enu_listx,
        slamgps_enu_listy,
        #mark_line=[“average”] 表示补充一条平均值线
        mark_line=["average", "max", "min"],
        #mark_point=["average", "max", "min"],
        #mark_point_symbol="diamond",
        #mark_point_textcolor="#40ff27",
        is_smooth=True,
    )

    line.render()

#画多个折线图 在同一个图里 水平误差折线 
def Draw2D_error_onePic(slam_enu_error_list_xyz):
    # 第一个为真值


    # len(gps_data_list)和 len(slam_data_list)数量应该是对等的
   
    error_list=[]

    hengzuobiao=[]
    fps=20.0
    time_interbval=1.0/fps
    

    for i in range(0,len(slam_enu_error_list_xyz)):

        slam_enu_error_i=slam_enu_error_list_xyz[i]

        #line = Line("Positioning  Error (m) "+ str(i)) 


        error_x_list=slam_enu_error_i[0]
        error_y_list=slam_enu_error_i[1]
        error_z_list=slam_enu_error_i[2]

        for j in range(0,len(error_x_list)):
            hengzuobiao.append((j*time_interbval))


        plt.figure(figsize=(20, 10), dpi=100)
        
        plt.plot(hengzuobiao, error_x_list, c='red', label="x")
        plt.plot(hengzuobiao, error_y_list, c='green', linestyle='--', label="y")
        plt.plot(hengzuobiao, error_z_list, c='blue', linestyle='-.', label="z")
        plt.scatter(hengzuobiao, error_x_list, c='red')
        plt.scatter(hengzuobiao, error_y_list, c='green')
        plt.scatter(hengzuobiao, error_z_list, c='blue')
        plt.legend(loc='best')
        #plt.yticks(range(0, 50, 5))
        plt.grid(True, linestyle='--', alpha=0.5)
        plt.xlabel("Time (s)", fontdict={'size': 16})
        plt.ylabel("Error (m)", fontdict={'size': 16})
        plt.title("Position Error", fontdict={'size': 20})
        plt.show()


#画单组 3个折线图 各自单独一个图里 水平误差折线 
def Draw2D_error_MorePic(slam_enu_error_list_xyz):
    # 第一个为真值
    # len(gps_data_list)和 len(slam_data_list)数量应该是对等的
   
    fps=10.0
    time_interbval=1.0/fps
    
    plt.figure()
    
    '''
    num = None,               # 设定figure名称。系统默认按数字升序命名的figure_num(透视表输出窗口)e.g. “figure1”。可自行设定figure名称,名称或是INT,或是str类型;
    figsize=None,             # 设定figure尺寸。系统默认命令是rcParams["figure.fig.size"] = [6.4, 4.8],即figure长宽为6.4 * 4.8;
    dpi=None,                 # 设定figure像素密度。系统默命令是rcParams["sigure.dpi"] = 100;
    facecolor=None,           # 设定figure背景色。系统默认命令是rcParams["figure.facecolor"] = 'w',即白色white;
    edgecolor=None, frameon=True,    # 设定要不要绘制轮廓&轮廓颜色。系统默认绘制轮廓,轮廓染色rcParams["figure.edgecolor"]='w',即白色white;
    FigureClass=<class 'matplotlib.figure.Figure'>,   # 设定使不使用一个figure模板。系统默认不使用;
    '''
    #fig, axs = plt.subplots(nrows=3, ncols=1)#3行1列  figsize=(20, 6) dpi=100 像素密度
    colors = ['red', 'green', 'blue']
    line_style = ['-', '--', '-.']
    y_labels = ["x Error (m)", "y Error (m)", "z Error (m)"] #Error (m)
    
    
    
     
    slam_enu_error_i=slam_enu_error_list_xyz


    error_x_list=slam_enu_error_i[0]
    error_y_list=slam_enu_error_i[1]


    
    error_z_list=slam_enu_error_i[2]
    x_i=[]
    for j in range(0,len(error_x_list)):
        x_i.append(j)

    x_data=x_i
    y_data = [error_x_list, error_y_list, error_z_list]

    # xmin=int(min(x_data))
    # xmax=int(max(x_data))
    # ymin=int(min(y_data))
    # ymax=int(max(y_data))
    # yth=2

    for i in range(1,4):
        plt.subplot(3,1,i)


        
        #plt.plot([0,1],[0,1])
        i=i-1
        # axs[i].plot(x_data, y_data[i], c=colors[i], label=y_labels[i], linestyle=line_style[i],linewidth=1,marker='.'
    # ,markeredgecolor=colors[i],markersize='1',markeredgewidth=1) #label='total' alpha=0.5
        plt.plot(x_data, y_data[i], c=colors[i], label=y_labels[i], linestyle=line_style[i],linewidth=1,marker='.',markersize=0.1)
        #plt.scatter(x_data, y_data[i], c=colors[i])
        plt.xlabel("ID")
        plt.ylabel(y_labels[i])
        #axs[i].legend(loc='best') #默认: 对于Axes, ‘best’, 对于Figure, 'upper right'
        
        #axs[i].set_aspect(aspect=0.1)#y轴的单位刻度显示长度 与 x轴的单位刻度显示长度 的比例
        #axs[i].axis('equal')#设置y轴和x轴的单位刻度显示长度相同
        
        #axs[i].set_yticks(range(ymin,ymax, 2)) # y轴的间距和显示范围
        
         
        plt.grid(True, linestyle='--', alpha=0.5)#背景网格线
        #plt.set_xlabel("Time (s)", fontdict={'size': 10})#x轴坐标名字 和 字号
        #plt.set_ylabel(y_labels[i], fontdict={'size': 10}, rotation=90) #y轴坐标名字 和 字号
        #plt.set_title("Position {}".format(y_labels[i]), fontdict={'size': 12}) #标题

    #fig.autofmt_xdate()
    plt.show()

#画单组 3个折线图 各自单独一个图里 水平误差折线 
def Draw2D_error_MorePicv2(slam_enu_error_list_xyz):
    # 第一个为真值
    # len(gps_data_list)和 len(slam_data_list)数量应该是对等的
   
    fps=10.0
    time_interbval=1.0/fps
    
    '''
    num = None,               # 设定figure名称。系统默认按数字升序命名的figure_num(透视表输出窗口)e.g. “figure1”。可自行设定figure名称,名称或是INT,或是str类型;
    figsize=None,             # 设定figure尺寸。系统默认命令是rcParams["figure.fig.size"] = [6.4, 4.8],即figure长宽为6.4 * 4.8;
    dpi=None,                 # 设定figure像素密度。系统默命令是rcParams["sigure.dpi"] = 100;
    facecolor=None,           # 设定figure背景色。系统默认命令是rcParams["figure.facecolor"] = 'w',即白色white;
    edgecolor=None, frameon=True,    # 设定要不要绘制轮廓&轮廓颜色。系统默认绘制轮廓,轮廓染色rcParams["figure.edgecolor"]='w',即白色white;
    FigureClass=<class 'matplotlib.figure.Figure'>,   # 设定使不使用一个figure模板。系统默认不使用;
    '''
    fig, axs = plt.subplots(nrows=3, ncols=1)#3行1列  figsize=(20, 6) dpi=100 像素密度
    colors = ['red', 'green', 'blue']
    line_style = ['-', '--', '-.']
    y_labels = ["x Error (m)", "y Error (m)", "z Error (m)"] #Error (m)
    
    
    
     
    slam_enu_error_i=slam_enu_error_list_xyz


    error_x_list=slam_enu_error_i[0]
    error_y_list=slam_enu_error_i[1]


    
    error_z_list=slam_enu_error_i[2]
    x_i=[]
    for j in range(0,len(error_x_list)):
        x_i.append((j*time_interbval))

    x_data=x_i
    y_data = [error_x_list, error_y_list, error_z_list]

    # xmin=int(min(x_data))
    # xmax=int(max(x_data))
    # ymin=int(min(y_data))
    # ymax=int(max(y_data))
    # yth=2

    for i in range(3):
        # axs[i].plot(x_data, y_data[i], c=colors[i], label=y_labels[i], linestyle=line_style[i],linewidth=1,marker='.'
    # ,markeredgecolor=colors[i],markersize='1',markeredgewidth=1) #label='total' alpha=0.5
        axs[i].plot(x_data, y_data[i], c=colors[i], label=y_labels[i], linestyle=line_style[i],linewidth=1,marker='.',markersize=0.1)
        #axs[i].scatter(x_data, y_data[i], c=colors[i])
        #axs[i].legend(loc='best') #默认: 对于Axes, ‘best’, 对于Figure, 'upper right'
        
        #axs[i].set_aspect(aspect=0.1)#y轴的单位刻度显示长度 与 x轴的单位刻度显示长度 的比例
        #axs[i].axis('equal')#设置y轴和x轴的单位刻度显示长度相同
        
        #axs[i].set_yticks(range(ymin,ymax, 2)) # y轴的间距和显示范围
        
         
        axs[i].grid(True, linestyle='--', alpha=0.5)#背景网格线
        axs[i].set_xlabel("Time (s)", fontdict={'size': 10})#x轴坐标名字 和 字号
        axs[i].set_ylabel(y_labels[i], fontdict={'size': 10}, rotation=90) #y轴坐标名字 和 字号
        axs[i].set_title("Position {}".format(y_labels[i]), fontdict={'size': 12}) #标题

    #fig.autofmt_xdate()
    plt.show()

     


#画多组 多个折线图 各自单独一个图里 水平误差折线 
def Draw2D_error_More33Pic(slam_enu_error_list_xyz):


    fps=10.0
    time_interbval=1.0/fps
    
    '''
    num = None,               # 设定figure名称。系统默认按数字升序命名的figure_num(透视表输出窗口)e.g. “figure1”。可自行设定figure名称,名称或是INT,或是str类型;
    figsize=None,             # 设定figure尺寸。系统默认命令是rcParams["figure.fig.size"] = [6.4, 4.8],即figure长宽为6.4 * 4.8;
    dpi=None,                 # 设定figure像素密度。系统默命令是rcParams["sigure.dpi"] = 100;
    facecolor=None,           # 设定figure背景色。系统默认命令是rcParams["figure.facecolor"] = 'w',即白色white;
    edgecolor=None, frameon=True,    # 设定要不要绘制轮廓&轮廓颜色。系统默认绘制轮廓,轮廓染色rcParams["figure.edgecolor"]='w',即白色white;
    FigureClass=<class 'matplotlib.figure.Figure'>,   # 设定使不使用一个figure模板。系统默认不使用;
    '''
    fig, axs = plt.subplots(nrows=3, ncols=1,dpi=100)#3行1列  figsize=(20, 6) dpi=100 像素密度
    #colors = ['blue','green','red']
    colors = ['blue','green','red']
    line_style = ['-', '--', '-.']
    #datalabls=["nogps-nogps","gps-nogps","gps-gps"]
    datalabls=["true","vio + gps","vio"]
    y_labels = ["x Error (m)", "y Error (m)", "z Error (m)"] #Error (m)



    for i in range(0,len(slam_enu_error_list_xyz)):

     
        slam_enu_error_i=slam_enu_error_list_xyz[i]

        error_x_list=slam_enu_error_i[0]
        error_y_list=slam_enu_error_i[1]
        error_z_list=slam_enu_error_i[2]
        x_i=[]
        for j in range(0,len(error_x_list)):
            x_i.append((j*time_interbval))

        x_data=x_i
        y_data = [error_x_list, error_y_list, error_z_list]

        
        for ii in range(0,3):
           # axs[i].plot(x_data, y_data[i], c=colors[i], label=y_labels[i], linestyle=line_style[i],linewidth=1,marker='.'
        # ,markeredgecolor=colors[i],markersize='1',markeredgewidth=1) #label='total' alpha=0.5
            #添加lable标签显示
            #axs[ii].plot(x_data, y_data[ii], c=colors[i], label=datalabls[i], linestyle=line_style[i],linewidth=1,marker='.',markersize=0.1)
            axs[ii].plot(x_data, y_data[ii], c=colors[i], linestyle=line_style[i],linewidth=1,marker='.',markersize=0.1)


            #axs[ii].scatter(x_data, y_data[ii], c=colors[i])
            axs[ii].legend(loc='best')
            #axs[ii].gca().set_box_aspect((3, 5, 2))  # 当x、y、z轴范围之比为3:5:2时。
            #axs[ii].set_yticks(range(-4, 4, 2))

            #if ii==2:
                #axs[ii].set_yticks(range(-4, 8, 2))
            # if ii==0:
            #     axs[ii].set_yticks(range(-60, 30, 10))
            # elif ii==1:
            #     axs[ii].set_yticks(range(-30, 70, 20)) # y轴的间距和显示范围
            # else:
            #     axs[ii].set_yticks(range(-20, 30, 10)) 
            
            axs[ii].grid(True, linestyle='--', alpha=0.5)#背景网格线
            axs[ii].set_xlabel("Time (s)", fontdict={'size': 10})#x轴坐标名字 和 字号
            axs[ii].set_ylabel(y_labels[ii], fontdict={'size': 10}, rotation=90) #y轴坐标名字 和 字号  Y轴说明是否旋转90度
            axs[ii].set_title("Position {}".format(y_labels[ii]), fontdict={'size': 12}) #标题

    fig.autofmt_xdate()
    plt.show()


     

    






#==========================================================

pipei_sourec_value=0#读取元数据匹配 对其GPS
read_enu_darw=1 #读取处理过的enu 对比画图

if __name__ == "__main__":

    #root_path="C:/Users/dongdong/Desktop/slam代码/测试数据/芝加哥_ehang实验结果/ehang/ehang2建图数据测试地图精度结果/"
    root_path="C:/Users/dongdong/Desktop/slam代码/测试数据/芝加哥_ehang实验结果/ehang/ehang4/"
    #root_path="C:/Users/dongdong/Desktop/slam代码/测试数据/芝加哥_ehang实验结果/ehang/ehang3/"
    #root_path="C:/Users/dongdong/Desktop/slam代码/测试数据/芝加哥_ehang实验结果/芝加哥/测试数据/"
    #root_path="C:/Users/dongdong/Desktop/slam代码/测试数据/芝加哥_ehang实验结果/芝加哥/建图数据/"
    #root_path="C:/Users/dongdong/Desktop/slam代码/测试数据/芝加哥_ehang实验结果/科技路数据/测试数据1/"
    #root_path="C:/Users/dongdong/Desktop/slam代码/测试数据/芝加哥_ehang实验结果/科技路数据/建图数据/"

    slamgps_txt_name="结果1.txt"        #slam定位结果txt 名字 結果1
    #slamgps_txt_name="frame_trajectory.txt"

    realgps_txt_name="真实gps.txt"      #真实GPS txt 名字  gps真值 真实gps
    

    # 见图用到的
    #data_name="带gps建图数据定位"
    #data_name="不带gps建图数据定位"

    #定位用到的
                                        #   eh3                             eh4  
    data_name="不带gps建图不带gps定位"  # 12.857068502706884            10.504316957115515
    data_name="带gps建图不带gps定位"    # 7.131057084533781             3.9117045628559612
    data_name="带gps建图带gps定位"      # 1.87419478565561              2.394471786497714
    
    #ENU坐标系参考GPS原点 
    #gps_ref=[47.6289700414 ,-122.167686472 ,111.5]          #仿真芝加哥测试测试数据   
    #gps_ref=[47.6304101698, -122.165953479, 360.334594727]   #仿真芝加哥建图测试数据     

    #gps_ref=[34.2371703354, 108.890706449, 400] #科技路建图数据

    #gps_ref=[34.0343737663,  108.756061354, 400.0]           #ehang4  
    gps_ref=[34.0343737663 , 108.756061354 ,400.0]           #ehang3-4
    #gps_ref=[34.0343829843 , 108.756072317 ,400.0]           #ehang2
    


    slamgps_txt=root_path+data_name+"/"+slamgps_txt_name  #slam定位结果txt 路径
    print(slamgps_txt)
    realgps_txt=root_path+realgps_txt_name                #真实gpstxt 路径
    print(realgps_txt)

    gps_slamgps_txt_savename=root_path+data_name+"/匹配gps_slam"+slamgps_txt_name #匹配后要保存的
    gps_realgps_txt_savename=root_path+data_name+"/匹配gps_real"+slamgps_txt_name

    enu_slamgps_txt_savename=root_path+data_name+"/匹配enu_slam"+slamgps_txt_name #匹配后要保存的
    enu_realgps_txt_savename=root_path+data_name+"/匹配enu_real"+slamgps_txt_name

    
    

    if pipei_sourec_value==1:


        #8810 8381 8638 15880 15863

        #1-1从原始数据中获取slam gps和对应真实GPS(可能没有 -1)
        slamGPS_List=readtxt_gps_havegps_we(slamgps_txt)  # 从自己的SLam输出读取数据
        #slamGPS_List=readtxt_slamSaveTraceEnu(slamgps_txt) # 从slam保存轨迹读取 时间戳是带图像名字
        '''
        
        for i in range(0,len(slamGPS_List)):
            print(i,slamGPS_List[i])
        print("\n",len(slamGPS_List))
        
        '''

        #print("时间戳 定位gps 纬度 经度 高度 真实gps 纬度 经度 高度   ",len(GPS_List))
        
        
        #1-2 读取真实GPS realgps_txt 文件名 fixhigh 高度是否固定 -1 否 其他
        realGPS_List=readtxt_realgps(realgps_txt)
    
        '''
        for i in range(0,len(realGPS_List)):
            print(i,realGPS_List[i])
        '''
        
        
        #print("真实gps 时间戳 纬度 经度 高度 ",len(realGPS_List))

        #2 匹配真实gps和slam gps帧
        time_realgps_slamgps_list=from_realGPSFindslamGPS(realGPS_List,slamGPS_List)
        # for i in range(0,len(time_realgps_slamgps_list)):
        #      print(i,time_realgps_slamgps_list[i])
        # print("时间戳  真实gps 纬度 经度 高度  匹配的SLAM gps 纬度 经度 高度 误差")
        
        # 3-1保存GPS 画轨迹图用
        save_TXT_realGps_SLAMgps(time_realgps_slamgps_list,gps_realgps_txt_savename,gps_slamgps_txt_savename)

        # 3-2保存enu坐标系(指定gps为原点) 画轨迹图用
        #gps_ref=[] #ENU坐标系参考GPS原点
        if data_name=="带gps建图不带gps定位" : 
            #剔除enu大于误差10m的点
            save_TXT_realEnu_SLAMEnu(time_realgps_slamgps_list,enu_realgps_txt_savename,enu_slamgps_txt_savename,gps_ref,10)
        else:
            save_TXT_realEnu_SLAMEnu(time_realgps_slamgps_list,enu_realgps_txt_savename,enu_slamgps_txt_savename,gps_ref,999999)






       



        #3-3单个图和真值对比可视化
        # gps用于画真实轨迹图  enu用于画简略图

        data_list=[] #文件名
        data_list.append(enu_realgps_txt_savename)
        data_list.append(enu_slamgps_txt_savename)
        draw_tracelist=[]# enu数据列表
        for i in range(0,len(data_list)):

            list_txyz0,list_x0,list_y0,list_z0 = readtxt_ENU(data_list[i])
            draw_tracelist.append([list_x0,list_y0,list_z0])




        #折线误差slam值
        errorlist_txyz0_error,list_x0_error,list_y0_error,list_z0_error = readtxt_ENU_Error(enu_slamgps_txt_savename)
        draw_slamEnutraceError_list=[list_x0_error,list_y0_error,list_z0_error]


        
        # 0 累计误差 计算总体转化均方根误差
        error_all=0
        for i in range(0,len(errorlist_txyz0_error)):
            #print(errorlist_txyz0_error[i])

            distance=sqrt((errorlist_txyz0_error[i][1])**2+(errorlist_txyz0_error[i][2])**2)
            #print(i,time_realgps_slamgps_list[i])
            error_all=error_all+time_realgps_slamgps_list[i][7]**2
        error_averrange=sqrt(error_all/len(errorlist_txyz0_error))

        
        print("时间戳  真实gps 纬度 经度 高度  匹配的SLAM gps 纬度 经度 高度 误差")
        print("总误差",data_name,error_averrange)

    
        #=============1 单组折线图画在多个行里
        Draw2D_error_MorePic(draw_slamEnutraceError_list)

        #=============2 画真值和单个slam轨迹 3D轨迹在同一个3D图 对比轨迹
        Draw3D_trace_more(draw_tracelist)
        
        #=============3 画多个3D轨迹的2D侧视图
        Draw2D_trace_gpsvreal_list(draw_tracelist,"X(m)","Y(m)") #-俯视图xy
        Draw2D_trace_gpsvreal_list(draw_tracelist,"X(m)","Z(m)") #-左视图xz
        Draw2D_trace_gpsvreal_list(draw_tracelist,"Y(m)","Z(m)") #-右视图yz

        
   #=======================2对ENU画图操作==========================
    if read_enu_darw==1:
        #4-1 读取enu数据
        # 时间戳 x y z
        
        #enu 坐标路径 
        
        
   
        # #1 gps真值
        # enu_realgps_txt_savename=root_path+"带gps建图数据定位"+"/匹配enu_real"+slamgps_txt_name
        # #2 不同状态的定位
        # enu_slamgps_txt_savename1=root_path+"带gps建图数据定位"+"/匹配enu_slam"+slamgps_txt_name
        # enu_slamgps_txt_savename2=root_path+"不带gps建图数据定位"+"/匹配enu_slam"+slamgps_txt_name
        # data_list=[] #文件名

        # data_list.append(enu_realgps_txt_savename)
        # data_list.append(enu_slamgps_txt_savename1)
        # data_list.append(enu_slamgps_txt_savename2)
        
        

        
        #1 gps真值
        #enu_realgps_txt_savename0=root_path+"真实gps完整.txt"
        enu_realgps_txt_savename0=root_path+"带gps建图带gps定位"+"/匹配enu_real"+slamgps_txt_name
        #2 不同状态的定位
        enu_slamgps_txt_savename2=root_path+"不带gps建图不带gps定位"+"/匹配enu_slam"+slamgps_txt_name
        enu_slamgps_txt_savename1=root_path+"带gps建图不带gps定位"+"/匹配enu_slam"+slamgps_txt_name
        enu_slamgps_txt_savename3=root_path+"带gps建图带gps定位"+"/匹配enu_slam"+slamgps_txt_name
        
        data_list=[] #文件名
        data_list.append(enu_realgps_txt_savename0)
        data_list.append(enu_slamgps_txt_savename1)
        data_list.append(enu_slamgps_txt_savename2)
        data_list.append(enu_slamgps_txt_savename3)
    
        
        
        draw_tracelist=[]# enu数据列表
        for i in range(0,len(data_list)):

            list_txyz0,list_x0,list_y0,list_z0 = readtxt_ENU(data_list[i])
            draw_tracelist.append([list_x0,list_y0,list_z0])


        #==========1 画多个3D轨迹在同一个3D图 对比轨迹
        Draw3D_trace_more(draw_tracelist)
        
        #==========2 画多个3D轨迹的2D侧视图
        Draw2D_trace_gpsvreal_list(draw_tracelist,"X(m)","Y(m)") #-俯视图xy
        Draw2D_trace_gpsvreal_list(draw_tracelist,"X(m)","Z(m)") #-左视图xz
        Draw2D_trace_gpsvreal_list(draw_tracelist,"Y(m)","Z(m)") #-右视图yz


        #============3 画2D折线图误差

        #3-1 加载数据 折线误差slam值

        SlamEnuError_txtNamelist=[]  #保存slam enu error轨迹 文件名
        #SlamEnuError_txtNamelist.append(enu_realgps_txt_savename0)
        SlamEnuError_txtNamelist.append(enu_slamgps_txt_savename3)
        SlamEnuError_txtNamelist.append(enu_slamgps_txt_savename1)
        SlamEnuError_txtNamelist.append(enu_slamgps_txt_savename2)

        draw_slamEnutraceError_list=[] #保存slam enu轨迹 数据

        for i in range(0,len(SlamEnuError_txtNamelist)):

            errorlist_txyz0_error,list_x0_error,list_y0_error,list_z0_error = readtxt_ENU_Error(SlamEnuError_txtNamelist[i])

            errorlist_txyx0_error_skip=[]
            errorlist_txyy0_error_skip=[]
            errorlist_txyz0_error_skip=[]

            # #步长 3
            # for i in range(0,len(errorlist_txyz0_error),100):
            #     errorlist_txyx0_error_skip.append(list_x0_error[i])
            #     errorlist_txyy0_error_skip.append(list_y0_error[i])
            #     errorlist_txyz0_error_skip.append(list_z0_error[i])

            draw_slamEnutraceError_list.append([list_x0_error,list_y0_error,list_z0_error])
            #draw_slamEnutraceError_list.append([errorlist_txyx0_error_skip,errorlist_txyy0_error_skip,errorlist_txyz0_error_skip])
        
        #=============3-2 画数据 2D折线图画在多个行里
        Draw2D_error_More33Pic(draw_slamEnutraceError_list)
  





        
    
        

  

标签:误差,txt,list,方根,slam,enu,error,GPS,gps
From: https://www.cnblogs.com/gooutlook/p/17067377.html

相关文章