1. GPS两种格式及转换

常见的GPS数据有两种格式,一种为度(DDD)格式,一种为度分秒(DMS)格式:

  • 度分秒(DMS):   118°48′54.152″E                32°04′10.461″N
  • 度(DDD):          118.815042°E                     32.069572°

两种格式的转换:

  1. 从DMS 到 DDD,保留度数 D 不变,加上分数 M / 60,再加上秒数 S / 3600;
    例如:DMS = 118°48′54.152,DDD=118 + 48/60 + 54.152/3600 = 118.815042。
  2. 从DDD 到 DMS,保留度数 D 不变(向下取整),小数部分乘以 60 并向下取整为分数,分数剩下的小数部分再乘以 60 得到秒数。
    例如:DDD=118.815042,D=118,0.815042*60=48.902520, M=48,S=0.902520*60=54.1512

MATLAB程序如下:

% 将度度度格式转化为度分秒
function [d m s] = ddd2dms(ddd)
d = floor(ddd);
temp = (ddd - d) * 60;
m = floor(temp);
s = (temp - m) * 60;
end

% 将度分秒转化为度度度
function ddd = dms2ddd(d, m, s)
ddd = d + m/60 + s/3600;                                                                                                    
end

2. 两点间距离计算

更多信息参考这个链接:http://www.movable-type.co.uk/scripts/latlong-vincenty.html

原文还给出一个网页测试效果,可以编程后与之对比。

 

公式如下:

java gps 度分格式转换 gps度分秒坐标转换_算法

其中 :a, b 分别是椭球两点长半轴、短半轴;

fai1, fai2, L 分别是第一点纬度、第二点纬度,两点经度差;

s 是最终计算出的两点距离。

MATLAB程序如下:

% 使用度度度格式计算两点间距离
% 输入:待求两点的坐标(经度1, 纬度1, 经度2, 纬度2)
% 输出:两点间距离

function s = gps_dis(lng1, lat1, lng2, lat2)
a = 6378137.0;              % 椭球最大半径(地心到赤道)
b = 6356752.31425;          % 椭球最小半径(地心到两极)
f = (a-b) / a;              % 椭球扁率(flattening)

fai1 = lat1 * pi /180;          % 第一点纬度,要转化为弧度!
fai2 = lat2 * pi /180;          % 第二点纬度,要转化为弧度!
L = (lng2 - lng1) * pi / 180;   % 两点纬度间弧度差

tanU1 = (1-f) * tan(fai1);      % 中间变量,由于多次计算使用,为了提高速度,设置为变量
cosU1 = 1 / sqrt(1 + tanU1^2);  
sinU1 = tanU1 * cosU1;
tanU2 = (1-f) * tan(fai2);
cosU2 = 1 / sqrt(1 + tanU2^2);
sinU2 = tanU2 * cosU2;

lamda = L;                      % 初始化 lamda
for k = 1:100                   % 最大允许迭代100次,一般几次就完成了
    sin_lamda = sin(lamda);
    cos_lamda = cos(lamda);
    sinSq_sigma = (cosU2*sin_lamda)^2 + (cosU1*sinU2-sinU1*cosU2*cos_lamda)^2;
    sin_sigma = sqrt(sinSq_sigma);
    if (sin_sigma == 0)
        break;
    end
    cos_sigma = sinU1*sinU2 + cosU1*cosU2*cos_lamda;
    sigma = atan2(sin_sigma, cos_sigma);
    sin_alpha = cosU1 * cosU2 * sin_lamda / sin_sigma;
    cosSq_alpha = 1 - sin_alpha^2;
    cos_2sigmaM = cos_sigma - 2 * sinU1 * sinU2 / cosSq_alpha;
    if (isnan(cos_2sigmaM))
        cos_2sigmaM = 0;
    end
    C = f/16 * cosSq_alpha * (4 + f*(4-3*cosSq_alpha));
    lamda_2 = lamda;
    lamda = L + (1-C) * f * sin_alpha * (sigma + C*sin_sigma* (cos_2sigmaM + C*cos_sigma* (-1 + 2* cos_2sigmaM^2)));
    if abs(lamda - lamda_2) < 1e-12
        break;
    end
end

uSq = cosSq_alpha * (a^2 - b^2) / b^2;
A = 1 + uSq/16384 * (4096 + uSq*(-768 + uSq*(320-175*uSq)));
B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
delta_sigma = B * sin_sigma * (cos_2sigmaM + B/4*(cos_sigma*(-1+2*cos_2sigmaM^2) - B/6*cos_2sigmaM * (-3+4*sin_sigma^2)*(-3+4*cos_2sigmaM^2)));
s = b*A*(sigma-delta_sigma);        % 最终距离
alpha1 = atan2(cosU2 * sin(lamda), cosU1 * sinU2 - sinU1 * cosU2 * cos(lamda)); % 起点到终点的方向,弧度制,正北为0,顺时针依次增加到 2*pi
alpha2 = atan2(cosU1 * sin(lamda), (-sinU1) * cosU2 + cosU1 * sinU2 * cos(lamda)); % 终点到起点的方向
end

测试:

(103.000000°, 26.000000°)与(103.000001°, 26.000001°)之间距离:

>> [s alpha1 alpha2] = gps_dis(103, 26, 103.000001, 26.000001)

s = 0.149323101218011

alpha1 = 0.734848600775512

alpha2 = 0.734848608157994

两点间大约 0.15m,夹角为0.7328 rad,大约42°,分辨率高。

C++程序如下:

// GPS距离与方向测量
#include <iostream>
#include <math.h>
using namespace std;

#define pi 3.1415926
/******************************************************************************/
/* 输入: 起始点经纬度(lng1, lat1),终止点经纬度(lng2, lat2)                   */
/* 输出: 起始点到终止点距离 result[0],起始点与终止点夹角 result[1]           */
/* 说明: 正北方向为0°,顺时针旋转增加,采用弧度制                           */
/******************************************************************************/
void gps_cacl(double lng1, double lat1, double lng2, double lat2, double* result)
{
    double a = 6378137.0;        // 椭球最大半径(地心到赤道)
    double b = 6356752.31425;    // 椭球最小半径(地心到两极)
    double f = (a - b) / a;      // 椭球扁率(flattening)
    double fai1 = lat1 * pi / 180;
    double fai2 = lat2 * pi / 180;
    double L = (lng2 - lng1) * pi / 180;

    double tanU1 = (1 - f) * tan(fai1);
    double cosU1 = 1 / sqrt(1 + tanU1 * tanU1);
    double sinU1 = tanU1 * cosU1;

    double tanU2 = (1 - f) * tan(fai2);
    double cosU2 = 1 / sqrt(1 + tanU2 * tanU2);
    double sinU2 = tanU2 * cosU2;

    double lamda = L;
    double sin_lamda;
    double cos_lamda;
    double sinSq_sigma;
    double sin_sigma;
    double cos_sigma = 0;
    double sigma = 0;
    double sin_alpha;
    double cosSq_alpha = 0;
    double cos_2sigmaM = 0;
    double C;
    double lamda_2;
    int k;
    for (k = 0; k < 100; k++)
    {
        sin_lamda = sin(lamda);
        cos_lamda = cos(lamda);
        sinSq_sigma = (cosU2 * sin_lamda) * (cosU2 * sin_lamda) + (cosU1 * sinU2 - sinU1 * cosU2 * cos_lamda) * (cosU1 * sinU2 - sinU1 * cosU2 * cos_lamda);
        sin_sigma = sqrt(sinSq_sigma);
        if (sin_sigma == 0)
            break;
        cos_sigma = sinU1 * sinU2 + cosU1 * cosU2 * cos_lamda;
        sigma = atan2l(sin_sigma, cos_sigma);
        sin_alpha = cosU1 * cosU2 * sin_lamda / sin_sigma;
        cosSq_alpha = 1 - sin_alpha * sin_alpha;
        cos_2sigmaM = cos_sigma - 2 * sinU1 * sinU2 / cosSq_alpha;
        if (isnan(cos_2sigmaM))
            cos_2sigmaM = 0;
        C = f / 16 * cosSq_alpha * (4 + f * (4 - 3 * cosSq_alpha));
        lamda_2 = lamda;
        lamda = L + (1 - C) * f * sin_alpha * (sigma + C * sin_sigma * (cos_2sigmaM + C * cos_sigma * (-1 + 2 * cos_2sigmaM * cos_2sigmaM)));
        if (abs(lamda - lamda_2) < 1e-12)
            break;
    }
    double uSq = cosSq_alpha * (a * a - b * b) / (b * b);
    double A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
    double B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
    double delta_sigma = B * sin_sigma * (cos_2sigmaM + B / 4 * (cos_sigma * (-1 + 2 * cos_2sigmaM * cos_2sigmaM) - B / 6 * cos_2sigmaM * (-3 + 4 * sin_sigma * sin_sigma) * (-3 + 4 * cos_2sigmaM *cos_2sigmaM)));
    result[0] = b * A * (sigma - delta_sigma);// 最终距离
    result[1] = atan2(cosU2 * sin(lamda), cosU1 * sinU2 - sinU1 * cosU2 * cos(lamda));
    // result[2] = atan2(cosU1 * sin(lamda), (-sinU1) * cosU2 + cosU1 * sinU2 * cos(lamda));
}


int main()
{
    double lng1 = 103.00000, lat1 = 26.00000;
    double lng2 = 103.000001, lat2 = 26.000001;
    double result[2];                               // 结果,包括距离及方向
    gps_cacl(lng1, lat1, lng2, lat2, result);

    cout << "distance = " << result[0] << endl;                      // 距离
    cout << "direction = " << result[1] << endl;                      // 方向
    
    return 0;
}

运行结果如下,与MATLAB没什么区别。

distance = 0.149323
direction = 0.734849