IGS上的外部GPS数据的WGS84大地水准面高度高度偏移

 吴家大少wu_415 发布于 2023-01-19 19:49

对于我正在编写的应用程序,我们正在将IOS设备与外部传感器连接,外部传感器通过本地wifi网络输出GPS数据.这些数据以海拔高度的"原始"格式出现.通常,所有GPS高度需要具有与基于当前位置的WGS84大地水准面高度相关的校正因子.

例如,在以下地理控制点(http://www.ngs.noaa.gov/cgi-bin/ds_mark.prl?PidBox=HV9830)位于Lat 38 56 36.77159和Lon 077 01 08.34929

HV9830* NAD 83(2011) POSITION- 38 56 36.77159(N) 077 01 08.34929(W)   ADJUSTED  
HV9830* NAD 83(2011) ELLIP HT-    42.624 (meters)        (06/27/12)   ADJUSTED
HV9830* NAD 83(2011) EPOCH   -  2010.00
HV9830* NAVD 88 ORTHO HEIGHT -    74.7    (meters)     245.    (feet) VERTCON   
HV9830  ______________________________________________________________________
HV9830  GEOID HEIGHT    -        -32.02  (meters)                     GEOID12A
HV9830  NAD 83(2011) X  -  1,115,795.966 (meters)                     COMP
HV9830  NAD 83(2011) Y  - -4,840,360.447 (meters)                     COMP
HV9830  NAD 83(2011) Z  -  3,987,471.457 (meters)                     COMP
HV9830  LAPLACE CORR    -         -2.38  (seconds)                    DEFLEC12A

你可以看到大地水准面高度是-32米.因此,如果在此点附近进行RAW GPS读数,则必须应用-32米的校正以计算正确的高度.(注意:校正是负的,所以你实际上要减去负数,从而将读数移动32米).

与Android相反,我们的理解是,关于coreLocation,这个GeoidHeight信息由IOS在内部自动计算.我们遇到困难的地方是我们正在使用带有传感器的本地wifi网络,该传感器计算未校正的GPS并收集外部传感器数据以及GPS的核心位置读数.我想知道是否有人知道有一个具有大地水准面信息的库(C/Objective-C),当我从传感器包中读取原始GPS信号时,它可以帮助我即时进行这些计算.

谢谢您的帮助.

旁注:请不要建议我查看以下帖子:在Android中获取经度和纬度的高度这是一个很好的解决方案,但我们没有实时的互联网连接,因此我们无法对Goole或USGS进行实时查询.

1 个回答
  • 我已经走了,在这里解决了我的问题.我所做的是创建一个使用fortran代码的ac实现的ObjectiveC实现来完成我需要的工作.原始c可以在这里找到:http://sourceforge.net/projects/egm96-f477-c/

    您需要从source forge下载项目才能访问此代码所需的输入文件: CORCOEFEGM96

    我的Objective-c实现如下:

    GeoidCalculator.h

    #import <Foundation/Foundation.h>
    
    @interface GeoidCalculator : NSObject
    + (GeoidCalculator *)instance;
    
    
    -(double) getHeightFromLat:(double)lat    andLon:(double)lon;
    -(double) getCurrentHeightOffset;
    -(void) updatePositionWithLatitude:(double)lat andLongitude:(double)lon;
    
    @end
    

    GeoidCalculator.m

    #import "GeoidCalculator.h"
    #import <stdio.h>
    #import <math.h>
    
    
    #define l_value    (65341)
    #define _361    (361)
    
    @implementation GeoidCalculator
    
    static int nmax;
    
    static double currentHeight;
    
    static double cc[l_value+ 1], cs[l_value+ 1], hc[l_value+ 1], hs[l_value+ 1],
            p[l_value+ 1], sinml[_361+ 1], cosml[_361+ 1], rleg[_361+ 1];
    
    + (GeoidCalculator *)instance {
        static GeoidCalculator *_instance = nil;
    
        @synchronized (self) {
            if (_instance == nil) {
                _instance = [[self alloc] init];
                init_arrays();
                currentHeight = -9999;
            }
        }
    
        return _instance;
    }
    
    
    - (double)getHeightFromLat:(double)lat andLon:(double)lon {
        [self updatePositionWithLatitude:lat andLongitude:lon];
        return [self getCurrentHeightOffset];
    }
    
    
    - (double)getCurrentHeightOffset {
        return currentHeight;
    }
    
    - (void)updatePositionWithLatitude:(double)lat andLongitude:(double)lon {
        const double rad = 180 / M_PI;
        double flat, flon, u;
        flat = lat; flon = lon;
    
        /*compute the geocentric latitude,geocentric radius,normal gravity*/
        u = undulation(flat / rad, flon / rad, nmax, nmax + 1);
    
        /*u is the geoid undulation from the egm96 potential coefficient model
           including the height anomaly to geoid undulation correction term
           and a correction term to have the undulations refer to the
           wgs84 ellipsoid. the geoid undulation unit is meters.*/
        currentHeight = u;
    }
    
    
    double hundu(unsigned nmax, double p[l_value+ 1],
            double hc[l_value+ 1], double hs[l_value+ 1],
            double sinml[_361+ 1], double cosml[_361+ 1], double gr, double re,
            double cc[l_value+ 1], double cs[l_value+ 1]) {/*constants for wgs84(g873);gm in units of m**3/s**2*/
        const double gm = .3986004418e15, ae = 6378137.;
        double arn, ar, ac, a, b, sum, sumc, sum2, tempc, temp;
        int k, n, m;
        ar = ae / re;
        arn = ar;
        ac = a = b = 0;
        k = 3;
        for (n = 2; n <= nmax; n++) {
            arn *= ar;
            k++;
            sum = p[k] * hc[k];
            sumc = p[k] * cc[k];
            sum2 = 0;
            for (m = 1; m <= n; m++) {
                k++;
                tempc = cc[k] * cosml[m] + cs[k] * sinml[m];
                temp = hc[k] * cosml[m] + hs[k] * sinml[m];
                sumc += p[k] * tempc;
                sum += p[k] * temp;
            }
            ac += sumc;
            a += sum * arn;
        }
        ac += cc[1] + p[2] * cc[2] + p[3] * (cc[3] * cosml[1] + cs[3] * sinml[1]);
    /*add haco=ac/100 to convert height anomaly on the ellipsoid to the undulation
    add -0.53m to make undulation refer to the wgs84 ellipsoid.*/
        return a * gm / (gr * re) + ac / 100 - .53;
    }
    
    void dscml(double rlon, unsigned nmax, double sinml[_361+ 1], double cosml[_361+ 1]) {
        double a, b;
        int m;
        a = sin(rlon);
        b = cos(rlon);
        sinml[1] = a;
        cosml[1] = b;
        sinml[2] = 2 * b * a;
        cosml[2] = 2 * b * b - 1;
        for (m = 3; m <= nmax; m++) {
            sinml[m] = 2 * b * sinml[m - 1] - sinml[m - 2];
            cosml[m] = 2 * b * cosml[m - 1] - cosml[m - 2];
        }
    }
    
    void dhcsin(unsigned nmax, double hc[l_value+ 1], double hs[l_value+ 1]) {
    
    
        // potential coefficient file
        //f_12 = fopen("EGM96", "rb");
        NSString* path2 = [[NSBundle mainBundle] pathForResource:@"EGM96" ofType:@""];
        FILE* f_12 = fopen(path2.UTF8String, "rb");
        if (f_12 == NULL) {
            NSLog([path2 stringByAppendingString:@" not found"]);
        }
    
    
    
        int n, m;
        double j2, j4, j6, j8, j10, c, s, ec, es;
    /*the even degree zonal coefficients given below were computed for the
     wgs84(g873) system of constants and are identical to those values
     used in the NIMA gridding procedure. computed using subroutine
     grs written by N.K. PAVLIS*/
        j2 = 0.108262982131e-2;
        j4 = -.237091120053e-05;
        j6 = 0.608346498882e-8;
        j8 = -0.142681087920e-10;
        j10 = 0.121439275882e-13;
        m = ((nmax + 1) * (nmax + 2)) / 2;
        for (n = 1; n <= m; n++)hc[n] = hs[n] = 0;
        while (6 == fscanf(f_12, "%i %i %lf %lf %lf %lf", &n, &m, &c, &s, &ec, &es)) {
            if (n > nmax)continue;
            n = (n * (n + 1)) / 2 + m + 1;
            hc[n] = c;
            hs[n] = s;
        }
        hc[4] += j2 / sqrt(5);
        hc[11] += j4 / 3;
        hc[22] += j6 / sqrt(13);
        hc[37] += j8 / sqrt(17);
        hc[56] += j10 / sqrt(21);
    
    
        fclose(f_12);
    
    }
    
    void legfdn(unsigned m, double theta, double rleg[_361+ 1], unsigned nmx)
    /*this subroutine computes  all normalized legendre function
    in "rleg". order is always
    m, and colatitude is always theta  (radians). maximum deg
    is  nmx. all calculations in double precision.
    ir  must be set to zero before the first call to this sub.
    the dimensions of arrays  rleg must be at least equal to  nmx+1.
    Original programmer :Oscar L. Colombo, Dept. of Geodetic Science
    the Ohio State University, August 1980
    ineiev: I removed the derivatives, for they are never computed here*/
    {
        static double drts[1301], dirt[1301], cothet, sithet, rlnn[_361+ 1];
        static int ir;
        int nmx1 = nmx + 1, nmx2p = 2 * nmx + 1, m1 = m + 1, m2 = m + 2, m3 = m + 3, n, n1, n2;
        if (!ir) {
            ir = 1;
            for (n = 1; n <= nmx2p; n++) {
                drts[n] = sqrt(n);
                dirt[n] = 1 / drts[n];
            }
        }
        cothet = cos(theta);
        sithet = sin(theta);
        /*compute the legendre functions*/
        rlnn[1] = 1;
        rlnn[2] = sithet * drts[3];
        for (n1 = 3; n1 <= m1; n1++) {
            n = n1 - 1;
            n2 = 2 * n;
            rlnn[n1] = drts[n2 + 1] * dirt[n2] * sithet * rlnn[n];
        }
        switch (m) {
            case 1:
                rleg[2] = rlnn[2];
                rleg[3] = drts[5] * cothet * rleg[2];
                break;
            case 0:
                rleg[1] = 1;
                rleg[2] = cothet * drts[3];
                break;
        }
        rleg[m1] = rlnn[m1];
        if (m2 <= nmx1) {
            rleg[m2] = drts[m1 * 2 + 1] * cothet * rleg[m1];
            if (m3 <= nmx1)
                for (n1 = m3; n1 <= nmx1; n1++) {
                    n = n1 - 1;
                    if ((!m && n < 2) || (m == 1 && n < 3))continue;
                    n2 = 2 * n;
                    rleg[n1] = drts[n2 + 1] * dirt[n + m] * dirt[n - m] *
                            (drts[n2 - 1] * cothet * rleg[n1 - 1] - drts[n + m - 1] * drts[n - m - 1] * dirt[n2 - 3] * rleg[n1 - 2]);
                }
        }
    }
    
    void radgra(double lat, double lon, double *rlat, double *gr, double *re)
    /*this subroutine computes geocentric distance to the point,
    the geocentric latitude,and
    an approximate value of normal gravity at the point based
    the constants of the wgs84(g873) system are used*/
    {
        const double a = 6378137., e2 = .00669437999013, geqt = 9.7803253359, k = .00193185265246;
        double n, t1 = sin(lat) * sin(lat), t2, x, y, z;
        n = a / sqrt(1 - e2 * t1);
        t2 = n * cos(lat);
        x = t2 * cos(lon);
        y = t2 * sin(lon);
        z = (n * (1 - e2)) * sin(lat);
        *re = sqrt(x * x + y * y + z * z);/*compute the geocentric radius*/
        *rlat = atan(z / sqrt(x * x + y * y));/*compute the geocentric latitude*/
        *gr = geqt * (1 + k * t1) / sqrt(1 - e2 * t1);/*compute normal gravity:units are m/sec**2*/
    }
    
    
    double undulation(double lat, double lon, int nmax, int k) {
        double rlat, gr, re;
        int i, j, m;
        radgra(lat, lon, &rlat, &gr, &re);
        rlat = M_PI / 2 - rlat;
        for (j = 1; j <= k; j++) {
            m = j - 1;
            legfdn(m, rlat, rleg, nmax);
            for (i = j; i <= k; i++)p[(i - 1) * i / 2 + m + 1] = rleg[i];
        }
        dscml(lon, nmax, sinml, cosml);
        return hundu(nmax, p, hc, hs, sinml, cosml, gr, re, cc, cs);
    }
    
    void init_arrays(void) {
        int ig, i, n, m;
        double t1, t2;
    
    
    
    
    
    
        NSString* path1 = [[NSBundle mainBundle] pathForResource:@"CORCOEF" ofType:@""];
    
    
        //correction coefficient file:  modified with 'sed -e"s/D/e/g"' to be read with fscanf
        FILE* f_1 = fopen([path1 cStringUsingEncoding:1], "rb");
        if (f_1 == NULL) {
            NSLog([path1 stringByAppendingString:@" not found"]);
        }
    
    
        nmax = 360;
        for (i = 1; i <= l_value; i++)cc[i] = cs[i] = 0;
    
        while (4 == fscanf(f_1, "%i %i %lg %lg", &n, &m, &t1, &t2)) {
            ig = (n * (n + 1)) / 2 + m + 1;
            cc[ig] = t1;
            cs[ig] = t2;
        }
    /*the correction coefficients are now read in*/
    /*the potential coefficients are now read in and the reference
     even degree zonal harmonic coefficients removed to degree 6*/
        dhcsin(nmax, hc, hs);
        fclose(f_1);
    }
    
    
    @end
    

    我对Geoid Height计算器(http://www.unavco.org/community_science/science-support/geoid/geoid.html)进行了一些有限的测试,看起来一切都很匹配

    更新iOS8或更高版本

    自IOS8起,此代码可能无法正常工作.您可能需要更改捆绑包的加载方式:

    [[NSBundle mainBundle] pathForResource:@"EGM96" ofType:@""];

    做一些谷歌搜索或在这里添加评论.

    2023-01-19 19:52 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有