GNSS的经纬度使用float还是doubble数据类型存储传输?

1. 背景

        当你在使用导航、打车、定位等等场景下,一定会有形或者无形的使用位置服务,位置服务的基础功能功能就是向你提供位置信息,而经纬度是位置信息的主要信息,一般情况可以简单的认为位置信息就是经纬度信息。经纬度使用小数进行表示,小数在计算机内部以浮点表示,在IEEE754浮点原理 - 计算机存储小数的误差有多少-CSDN博客文章浏览阅读1k次,点赞11次,收藏21次。本质上计算机内部使用浮点就是二进制小数的科学计算法表示,与相同长度的整数(如都为32位长度)相比能表示更大的范围,但是浮点并不是全范围内等精度,它会随着要表示的数的绝对值变大而精度逐渐变小。https://blog.csdn.net/bitslink/article/details/139078980        已知,使用浮点可能存在误差,而且这个误差会随这个数增加而增大。那经纬度应该使用单精度浮点float还是双精度浮点doubble类型呢?首先应该清楚什么是经纬度?

2. 什么是经纬度

        经纬度是一套球面的坐标系统,纬度是指球面任意一点与球心连线与赤道面的夹角,范围在-90°~90°,赤道面以北成为北纬(一般使用正数表示),赤道面以南成为南纬(一般使用负数表示)。经度是指地球面上一点与两极的连线与0度经线所在平面的夹角,范围-180~+180(负东经,正西经)。经纬度如下图在球面上如下图所示:

经纬度示意图

3. 经纬度使用Float(单精度)的误差

        经纬度浮点数的最大范围在-180°~+180°,参考IEEE754浮点原理 - 计算机存储小数的误差有多少-CSDN博客对该范围内浮点小数进行分辨率分析,分析源码如下:

#include "stdio.h"
#include "stdint.h"

#define  NUM 19
int main()
{
    float ff[NUM];
    float yy[NUM];
    float dd[NUM];
    uint32_t *p;

    for(int i=0;i<NUM;i++)
    {
        if(0 == i)
        {
            ff[i] = 0.1;
            yy[i] = ff[0];
            p = (uint32_t *)&yy[i];
            *p += 1;
        }
        else
        {
            ff[i] = ff[i-1]+10;
            yy[i] = ff[i];
            p = (uint32_t *)&yy[i];
            *p += 1;
        }

        dd[i] = yy[i] - ff[i];

        printf("%0.2f\t %0.9f\n",ff[i],dd[i]);
    }

    printf("x=[");
    for(int i=0;i<NUM;i++)
    {
        printf("%0.2f,",ff[i]);
    }
    printf("]\n"); 
    printf("y=[");
    for(int i=0;i<NUM;i++)
    {
        printf("%0.9f,",dd[i]);
    }
    printf("]"); 
}

         浮点分析源码的运行结果如下:

0.10 0.000000007

5.10 0.000000477

10.10 0.000000954

15.10 0.000000954

20.10 0.000001907

25.10 0.000001907

30.10 0.000001907

35.10 0.000003815

40.10 0.000003815

45.10 0.000003815

50.10 0.000003815

55.10 0.000003815

60.10 0.000003815

65.10 0.000007629

70.10 0.000007629

75.10 0.000007629

80.10 0.000007629

85.10 0.000007629

90.10 0.000007629

95.10 0.000007629

100.10 0.000007629

105.10 0.000007629

110.10 0.000007629

115.10 0.000007629

120.10 0.000007629

125.10 0.000007629

130.10 0.000015259

135.10 0.000015259

140.10 0.000015259

145.10 0.000015259

150.10 0.000015259

155.10 0.000015259

160.10 0.000015259

165.10 0.000015259

170.10 0.000015259

175.10 0.000015259

180.10 0.000015259

185.10 0.000015259

        将运行结果,绘图后如下: 

浮点小数在0~180内使用float分辨率(纵轴分辨率、横轴浮点数)

        上图中浮点小数在130~180时分辨率最低,此时float分辨率仅为1.5259*10^{-5}(十万分子1.5),由分辨率引入的误差也为1.5259*10^{-5},弧长计算公式 l=\frac{\pi*r*\theta}{180}

角度与弧长

        根据弧长公式以及地球半径约为6371km,将上面曲线图纵轴转换成弧长的分辨率后,结果如下:

0.10 0.000828467

5.10 0.053021874

10.10 0.106043749

15.10 0.106043749

20.10 0.212087497

25.10 0.212087497

30.10 0.212087497

35.10 0.424174994

40.10 0.424174994

45.10 0.424174994

50.10 0.424174994

55.10 0.424174994

60.10 0.424174994

65.10 0.848349988

70.10 0.848349988

75.10 0.848349988

80.10 0.848349988

85.10 0.848349988

90.10 0.848349988

95.10 0.848349988

100.10 0.848349988

105.10 0.848349988

110.10 0.848349988

115.10 0.848349988

120.10 0.848349988

125.10 0.848349988

130.10 1.696699977

135.10 1.696699977

140.10 1.696699977

145.10 1.696699977

150.10 1.696699977

155.10 1.696699977

160.10 1.696699977

165.10 1.696699977

170.10 1.696699977

175.10 1.696699977

180.10 1.696699977

185.10 1.696699977

角度与弧长分辨率(纵轴为弧长单位米、横轴为角度)

        经纬度在180°内对应弧长最低分辨率约为1.7米,而由分辨率导致的误差等于分辨率,最大存储误差为1.7米。若使用float对经纬度进行存储传输,那么由于采用了float单精度浮点会存在一定误差,这个误差最大值小于1.5米。对于中国经纬度范围为73.33~135.05,3.51~53.33,采用单精度浮点flaot最大的存储误差为1.7米,最小的存储误差为0.85米。

4. 经纬度使用double(双精度)的误差

        与float类似首先对0~180内的浮点数进行进度分析,分析C语言源码如下:

#include "stdio.h"
#include "stdint.h"
#include "math.h"

#define  NUM 40
int main()
{
    double ffd[NUM];
    double yyd[NUM];
    double ddd[NUM];
    uint64_t *pd;

    for(int i=0;i<NUM;i++)
    {
        if(0 == i)
        {
            ffd[i] = 0.1;
            yyd[i] = ffd[0];
            pd = (uint64_t *)&yyd[i];
            *pd += 1;
        }
        else
        {
            ffd[i] = ffd[i-1]+5;
            yyd[i] = ffd[i];
            pd = (uint64_t *)&yyd[i];
            *pd += 1;
        }
        
        ddd[i] = (yyd[i] - ffd[i])*M_PI*6371000/180.0;

        printf("%0.2f\t %0.17lf\n",ffd[i],ddd[i]);
    }

    printf("x=[");
    for(int i=0;i<NUM;i++)
    {
        printf("%0.2lf,",ffd[i]);
    }
    printf("]\n"); 
    printf("y=[");
    for(int i=0;i<NUM;i++)
    {
        printf("%0.17lf,",ddd[i]);
    }
    printf("]"); 
}

运行结果如下:

0.10 0.00000000000154314

5.10 0.00000000009876093

10.10 0.00000000019752187

15.10 0.00000000019752187

20.10 0.00000000039504374

25.10 0.00000000039504374

30.10 0.00000000039504374

35.10 0.00000000079008747

40.10 0.00000000079008747

45.10 0.00000000079008747

50.10 0.00000000079008747

55.10 0.00000000079008747

60.10 0.00000000079008747

65.10 0.00000000158017495

70.10 0.00000000158017495

75.10 0.00000000158017495

80.10 0.00000000158017495

85.10 0.00000000158017495

90.10 0.00000000158017495

95.10 0.00000000158017495

100.10 0.00000000158017495

105.10 0.00000000158017495

110.10 0.00000000158017495

115.10 0.00000000158017495

120.10 0.00000000158017495

125.10 0.00000000158017495

130.10 0.00000000316034990

135.10 0.00000000316034990

140.10 0.00000000316034990

145.10 0.00000000316034990

150.10 0.00000000316034990

155.10 0.00000000316034990

160.10 0.00000000316034990

165.10 0.00000000316034990

170.10 0.00000000316034990

175.10 0.00000000316034990

180.10 0.00000000316034990

185.10 0.00000000316034990

将结果绘制曲线图,如下:

浮点在0~180内使用double分辨率(纵轴分辨率、横轴浮点数)

        根据弧长公式:l=\frac{​{\pi}r\theta}{180},其中r为地球半径约为6371米、θ为角度,然后将上图的纵轴转换成弧长,如下图所示: 

角度与弧长分辨率(纵轴为弧长单位米、横轴为角度)

        使用double类型后,分辨率为3.16*10-9米(3.16纳米),由分辨率导致的存储误差等于分辨率除2,最大误差约为1.58纳米。 

5. 总结

        对于经纬度使用单精度float存储传输,分辨率误差随所在地的经纬度增加而增加,当经纬度大于130°后存储误最大的存储误差约为1.7米。对于普通GNSS测量误差一般10米数量级,此时使用单精度float后对总的误差影响不大;但使用了双频GNSS或者RTK GSNSS后测量,前者测量误差在2~3米,否则测量误差约为10cm数量级,这时若仍然使用单精度float存储,此时可能存在存储误差要大于测量误差,此次可以使用双精度浮点进行存储,虽然这可能带来存储空间的翻倍。

  • 50
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值