程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> .NET Compact Framework下的GPS NMEA data數據分析(上)

.NET Compact Framework下的GPS NMEA data數據分析(上)

編輯:關於.NET

提供GPS功能的Wince和Windows Mobile都需要一個GPS接收器(GPS Receiver )。GPS receiver就像一個收音機,他從太空中各個GPS衛星(Satellites)接 收信號,通過自身的算法(一般在Firmware裡面)計算出位置等信息,然後以 NMEA data的格式輸出。GPS receiver就是接收衛星信號轉換成NMEA data的設備 。

進行GPS的開發需要從GPS receiver取出NMEA data,分析出關心的數 據。關心的數據包括經度(Longitude),維度(Latitude)和海拔(Altitude )等等。在Windows Mobile 5以上MS提供了GPS Intermediate Driver,開發人 員不再需要自己分析NMEA data了。但是Wince5以及以下版本不提供GPS Intermediate Driver,還是需要自己分析NMEA data來取出關心的信息。本文講 述如何使用C#進行NMEA data的分析。第一眼看,分析NMEA有自己做輪子之嫌, 其實了解NMEA的分析也是有好處的,由於各個生產GPS receiver的廠商在硬件工 藝和算法的不一樣,各個廠商都提供自己擴展的NMEA data,這些數據GPS Intermediate Driver是不支持的,需要自己分析。

NMEA 全稱NMEA 0183 ,是電子與數據的通信規范,也就是協議。實現該協議的設備輸出這種規范的數 據,其他應用就可以基於這協議分析出相關的數據。NMEA開始用在航海設備上, 現在廣泛用在GPS設備上,這就是為什麼NMEA的原始速度使用Knot(海裡/小時) 表示。下面是一段GPS NMEA data的范例

$GPRMC,000006,A,3754.6240,S,14509.7720,E,010.8,313.1,0101 08,011.8,E*6A
$GPGGA,201033,3754.6240,S,14509.7720,E,1,05,1.7,91.1,M,-1.1,M,,*75
$GPGSA,A,3,,05,10,,,,21,,29,30,,,2.9,1.7,1.3*32
$GPGSV,3,3,12,29,74,163,41,30,53,337,40,31,09,266,00,37,00,000,00*78 $PGRME,6.3,M,11.9,M,13.5,M*25
$PGRMB,0.0,200,,,,K,,N,W*28
$PGRMM,WGS 84*06

GPS NMEA data有以下特點:

* 每一條 NMEA data的數據都是以dollar符號開頭。

* 從第二個字符開始的前2個 字符表示發送者(talker)和接著3個字符表示數據(message)。其中上面的 talker中,GP表示通用的GPS NMEA data,而PG為特定廠商的NMEA data。

* 所有數據字段(data fields)都是使用逗號隔開(comma-delimited) 。

* 最後一個數據段接著一個星號(asterisk)。

* 星號後面是兩 位數字的校正碼(checksum),checksum的計算方法是或計算在 '$' 和 '*'之間的所有字符。

* 最後以回車換行 (<CR><LF>)結尾。

有了上述規范,開發NMEA的分析器就變 得十分簡單,分析流程是:先接收一條NMEA語句(NMEA sentence),然後檢查 語句格式,檢查checksum,然後再根據talker和message進行分發,使用不同的 算法進行分析。下面為核心分析流程。

public bool Parse (string sentence)
        {
            string rawData = sentence;
            try
            {
                if (!IsValid(sentence))
                {
                    return false;
                }

                 sentence = sentence.Substring(1, sentence.IndexOf('*') - 1);
                string[] Words = Getwords(sentence);
                switch (Words[0])
                {
                    case "GPRMC":
                        return ParseGPRMC (Words);
                    case "GPGGA":
                        return ParseGPGGA (Words);
                    case "GPGSA":
                        return ParseGPGSA (Words);
                    case "GPGSV":
                        return ParseGPGSV (Words);
                    default:
                        return false;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message + rawData);
                return false;
            }
}

代碼1

Parse為分析接 口,所有從GPS Receiver接收到NMEA data全部調用這個接口進行分析。

IsValid檢驗該NMEA sentence是否有效。

Checksum進行Checksum 運算,檢驗校驗碼是否有效。

接下來,講述關鍵語句的分析。進行語句 的分析,需要一個NMEA的規范手冊,這個手冊可以從GPS廠商下載,例如從 Garmin下載 NMEA手冊

在該手冊的第24頁可以看到GPRMC的協議定義。

圖1

根據手冊的規范定義,抽取想要的信息。如下代碼:

private bool ParseGPRMC(string[] Words)
        {
            if (Words[1].Length > 0 & Words [9].Length > 0)
            {
                int UtcHours = Convert.ToInt32(Words [1].Substring(0, 2));
                int UtcMinutes = Convert.ToInt32(Words [1].Substring(2, 2));
                int UtcSeconds = Convert.ToInt32(Words [1].Substring(4, 2));
                int UtcMilliseconds = 0;

                 // Extract milliseconds if it is available
                if (Words[1].Length > 7)
                {
                    UtcMilliseconds = Convert.ToInt32(Words[1].Substring(7));
                }

                 int UtcDay = Convert.ToInt32(Words[9].Substring(0, 2));
                int UtcMonth = Convert.ToInt32(Words [9].Substring(2, 2));
                // available for this century
                int UtcYear = Convert.ToInt32(Words [9].Substring(4, 2)) + 2000;

                utcDateTime = new DateTime(UtcYear, UtcMonth, UtcDay, UtcHours, UtcMinutes, UtcSeconds, UtcMilliseconds);
            }

            fixStatus = (Words[2][0] == 'A') ? FixStatus.Obtained : FixStatus.Lost;

            if (Words[3].Length > 0 & Words [4].Length == 1 & Words[5].Length > 0 & Words[6].Length == 1)
            {
                latitude.Hours = int.Parse(Words [3].Substring(0, 2));
                latitude.Minutes = int.Parse(Words [3].Substring(2, 2));
                latitude.Seconds = Math.Round (double.Parse(Words[3].Substring(5, 4)) * 6 / 1000.0, 3);
                if ("S" == Words[4])
                {
                    latitude.Hours = - latitude.Hours;
                }

                 longitude.Hours = int.Parse(Words[5].Substring(0, 3));
                longitude.Minutes = int.Parse(Words [5].Substring(3, 2));
                longitude.Seconds = Math.Round (double.Parse(Words[5].Substring(6, 4)) * 6 / 1000.0, 3);
                if ("W" == Words[6])
                {
                    longitude.Hours = - longitude.Hours;
                }
            }

            if (Words [8].Length > 0)
            {
                azimuth = decimal.Parse(Words[8], NmeaCultureInfo);
            }

            if (Words [7].Length > 0)
            {
                velocity = decimal.Parse(Words[7], NmeaCultureInfo) * KMpHPerKnot;
            }
            return true;
}

代碼2

從 ParseGPRMC看,傳遞的參數是一個string的數組,分析要做的事情就是把數組的 元素根據手冊翻譯成需要的信息,例如字段1為UTC的日期信息,字段9為UTC的時 間信息。字段2為fix信息,就是GPS是否完成了初始化的信息。字段3,4為經度 ,字段5,6為維度。字段7為速度。字段8為角度。

private bool ParseGPGGA(string[] Words)
        {
            if (Words[6].Length > 0)
            {
                switch (Convert.ToInt32(Words[6]))
                {
                    case 0:
                        differentialGpsType = DifferentialGpsType.NotSet;
                        break;
                    case 1:
                        differentialGpsType = DifferentialGpsType.SPS;
                        break;
                    case 2:
                        differentialGpsType = DifferentialGpsType.DSPS;
                        break;
                    case 3:
                        differentialGpsType = DifferentialGpsType.PPS;
                        break;
                    case 4:
                        differentialGpsType = DifferentialGpsType.RTK;
                        break;
                    default:
                        differentialGpsType = DifferentialGpsType.NotSet;
                        break;
                }
            }

            if (Words [7].Length > 0)
            {
                satellitesInUsed = Convert.ToInt32 (Words[7]);
            }

            if (Words [8].Length > 0)
            {
                horizontalDilutionOfPrecision = Convert.ToDecimal(Words[8]);
            }

            if (Words [9].Length > 0)
            {
                altitude = Convert.ToDecimal(Words [9]);
            }
            return true;
}

代碼3

分 析ParseGPGGA和分析ParseGPRMC一樣,從數組抽取信息,字段6為fix類型,這個 參數表示使用了那些輔佐衛星或者地面信號站來提高GPS的精度。SPS為普通類型 ,DSPS使用了DGPS 地面信號站fix,DSPS使用了WAAS位置衛星fix(只是用在美 國),PPS使用了EGNOS位置衛星fix(只是用在歐洲),RTK使用了MSAS位置衛星 fix(只是用在亞洲)。字段7為使用衛星的數量。字段8為水平精度。字段9為海 拔。

private bool ParseGPGSA(string[] Words)
        {
            if (Words[1].Length > 0)
            {
                fixMode = Words[1][0] == 'A' ? FixMode.Auto : FixMode.Manual;
            }

            if (Words [2].Length > 0)
            {
                switch (Convert.ToInt32(Words[2]))
                {
                    case 1:
                        fixMethod = FixMethod.NotSet;
                        break;
                    case 2:
                        fixMethod = FixMethod.Fix2D;
                        break;
                    case 3:
                        fixMethod = FixMethod.Fix3D;
                        break;
                    default:
                        fixMethod = FixMethod.NotSet;
                        break;
                }
            }

            foreach (GpsSatellite s in satellites.Values)
            {
                s.InUsed = false;
            }
            satellitesInUsed = 0;
            for (int i = 0; i < 12; ++i)
            {
                string id = Words[3 + i];
                if (id.Length > 0)
                {
                    int nId = Convert.ToInt32 (id);
                    if (!satellites.ContainsKey (nId))
                    {
                        satellites[nId] = new GpsSatellite();
                        satellites[nId].PRC = nId;
                    }
                    satellites[nId].InUsed = true;
                    ++satellitesInUsed;
                }
            }

            if (Words [15].Length > 0)
            {
                positionDilutionOfPrecision = Convert.ToDecimal(Words[15]);
            }

            if (Words [16].Length > 0)
            {
                horizontalDilutionOfPrecision = Convert.ToDecimal(Words[16]);
            }

            if (Words [17].Length > 0)
            {
                verticalDilutionOfPrecision = Convert.ToDecimal(Words[17]);
            }
            return true;
}

代碼4

從 ParseGPGSA看,字段1為fix的狀態,手工fix或者自動fix。字段2為fix的方法, 2D或者3D。字段3到14共12個字段分別為在使用衛星的信息。字段15為位置精度 信息。字段16為水平精度信息。字段17為垂直精度信息。

private bool ParseGPGSV(string[] Words)
        {
            int messageNumber = 0;

             if (Words[2].Length > 0)
            {
                messageNumber = Convert.ToInt32(Words [2]);
            }
            if (Words[3].Length > 0)
            {
                satellitesInView = Convert.ToInt32 (Words[3]);
            }

            if (messageNumber == 0 || satellitesInView == 0)
            {
                return false;
            }

            for (int i = 1; i <= 4; ++i)
            {
                if ((Words.Length - 1) >= (i * 4 + 3))
                {
                    int nId = 0;
                    if (Words[i * 4].Length > 0)
                    {
                        string id = Words[i * 4];
                        nId = Convert.ToInt32 (id);
                        if (! satellites.ContainsKey(nId))
                        {
                            satellites[nId] = new GpsSatellite();
                            satellites [nId].PRC = nId;
                        }
                        satellites[nId].InView = true;
                    }

                     if (Words[i * 4 + 1].Length > 0)
                    {
                        satellites [nId].Elevation = Convert.ToInt32(Words[i * 4 + 1]);
                    }

                     if (Words[i * 4 + 2].Length > 0)
                    {
                        satellites[nId].Azimuth = Convert.ToInt32(Words[i * 4 + 2]);
                    }

                     if (Words[i * 4 + 3].Length > 0)
                    {
                        satellites[nId].SNR = Convert.ToInt32(Words[i * 4 + 3]);
                        satellites [nId].NotTracking = false;
                    }
                    else
                    {
                        satellites [nId].NotTracking = true;
                    }
                }
            }
            return true;
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved