2009년 10월 29일 목요일

GPGSV,GPGSA를 이용한 위성정보 표시

0. 참고

 NMEA sentence : http://aprs.gids.nl/nmea/

 용어정리 : http://www.cgrer.uiowa.edu/cgrer_lab/gps/gpsdefs.html

 참고프로젝트 : http://www.codeproject.com/KB/mobile/WritingGPSApplications1.aspx

 

1. 목적

GPGSV 와 GPGSA 정보를 이용한 주변의 GPS위성 상태를 알아보는 프로그램 작성

 

2. 개념정리

 2-1. GPGSV

    - satellite view(SV) 정보를 가진다.(GPS가 잡은 위성 정보)

    - GPGSA의 SV영역을 고려하면 최대 12개의 위성으로 부터 정보를 수신

    - 구문분석

       - 예.$GPGSV,3,1,11,03,03,111,00,04,15,270,00,06,01,010,00,13,06,292,00*74

          - 노란색 :

             - 첫번째자리 : GPGSV메세지의 총 갯수, 3이면 한번 수신할때 $GPGSV~ 메세지가 3개 넘어옴

             - 두번째자리 : GPGSV메세지의 순번

             - 세번째자리 : 총 수신한 위성 정보 수

 

          - 주황색 :

             - 4개가 한세트(예에서는 4개의 위성정보가 수신되었음)

             - 첫번째자리 : PRN number

             - 두번째자리 : Elevation in degrees ,최대 90도 ,

                                 0도면 수평 90도면 수직(머리위), 쉽게 달을 볼때 지평면에서 각도를 생각하면 될듯

             - 세번째자리 : Azimuth , 북쪽을 중심으로 한 위성의 위치, 범위 = 0~359

             - 네번째자리 : SNR

 

    - 그럼 이메시지로 무엇이 가능한가?

        - 위성의 위치, 수신상태 확인 가능

 

 2-2. GPGSA

    - active satellite 라고 해야하나....

    -  SV의 ID들과 DOP정보를 가진다.

    - 구문분석 : 생략

    - 정확도를 계산할때 사용할 수 있다.

 

3. 용어정리

 - 3-1. PRN

      - Pseudo-random noise

      - 위성 아이디쯤 된다. 그 밖의 의미를 두기 힘듬

 - 3-2. SNR

      - Signal to Noise Ratio

      - 정보 수신률(높을수록 위성으로부터 정보를 잘 수신함)

      - 0~00 범위이지만, 참고의 글에서 보면, 50을 넘는 경우를 못봤다고도 하고.....

 - 3-3. DOP

      - Dilution of Precision

      - 정보 오차율 정도의 의미를 가진다.

      - PDOP , HDOP , VDOP의 종류가 있고, 각각, percent , horizontal , vertical 의 의미가 있다.

       

4. 구현

 4-1. Satellite.cs

  - 기능 : GPGSV , GPGSA 처리

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: using System.Text.RegularExpressions;
   6: using System.Diagnostics;
   9:     public struct SatelliteView{        
  10:         public int PRN{get;set;}
  11:  
  12:         public int Elevation{get;set;}
  13:         public int Azimuth{get;set;}
  14:         public int? SNR{get;set;}
  15:     }
  16:  
  17:     public struct SatelliteDOP {
  18:         public float? Percent { get; set; }
  19:         public float? Horizontal { get; set; }
  20:         public float? Vertical { get; set; }
  21:  
  22:     }
  23:  
  24:     public class Satellite {        
  25:         
  26:         public static List<SatelliteView> GetSatelliteViews(string sentence) {
  27:             List<SatelliteView> result = new List<SatelliteView>();            
  28:             foreach (Match match in Regex.Matches(sentence, @"GPGSV,([0-9]+),([0-9]+),([0-9]+),(.[^*]+)[*]")) {
  29:                 string[] data = match.Groups[4].Value.Split(','); 
  30:                 int svCount = Convert.ToInt32(data.Length / 4);
  31:                 for (int i = 0; i < svCount; i++) {
  32:  
  33:                     SatelliteView entity = new SatelliteView();
  34:                     entity.PRN = Convert.ToInt32(data[i * 4 + 0]);
  35:                     entity.Elevation = Convert.ToInt32(data[i * 4 + 1]);
  36:                     entity.Azimuth = Convert.ToInt32(data[i * 4 + 2]);
  37:                     if (!string.IsNullOrEmpty(data[i * 4 + 3])) entity.SNR = Convert.ToInt32(data[i * 4 + 3]);;
  38:                     result.Add(entity);
  39:                 }
  40:             }            
  41:             return result;
  42:         }
  43:  
  44:         public static SatelliteDOP GetDOP(string sentence) {            
  45:             string expression = @"GPGSA,(.[^*]+)[*]";
  46:             SatelliteDOP result = new SatelliteDOP();
  47:  
  48:             if (!Regex.IsMatch(sentence, expression)) return result;
  49:             Match match = Regex.Match(sentence, expression);
  50:  
  51:             string[] data = match.Groups[1].Value.Split(',');
  52:             if (string.IsNullOrEmpty(data[14])) return result;
  53:             result.Percent = Convert.ToSingle(data[14]);
  54:             result.Horizontal = Convert.ToSingle(data[15]);
  55:             result.Vertical = Convert.ToSingle(data[16]);            
  56:  
  57:             return result;
  58:         }
  59:     }

 

 4-2. ui.cs(winForm class)

   1: void Update(string msg) {
   2:     float radius = this.ImageSize.Width / 2;
   3:     textBox2.Text = "";
   4:     lbDOP.Text = "";
   5:  
   6:     List<SatelliteView> result = Satellite.GetSatelliteViews(msg);
   7:     if (result.Count < 1) {
   8:         textBox2.Text = "no signal";
   9:         return;
  10:     }
  11:  
  12:     this.DrawRectangle();
  13:     foreach (SatelliteView sv in result) {
  14:         textBox2.AppendText(string.Format("prn:{0},elevation:{1},azimuth:{2},snr:{3},distance:{4}\n"
  15:                 , sv.PRN.ToString(), sv.Elevation, sv.Azimuth, sv.SNR
  16:                 , this.GetDistance(radius, sv.Elevation).ToString()
  17:             )
  18:         );
  19:         this.DrawPoint(sv.PRN, this.GetDistance(radius, sv.Elevation), sv.Azimuth, sv.SNR);
  20:     }
  21:  
  22:     SatelliteDOP dop = Satellite.GetDOP(msg);
  23:     this.ShowDOP(dop);        
  24: }
  25:  
  26: void DrawRectangle() {            
  27:     pictureBox1.Image = new Bitmap(this.ImageSize.Width, this.ImageSize.Height);
  28:     pictureBox1.BackColor = Color.WhiteSmoke;
  29:  
  30:     Graphics line = Graphics.FromImage(pictureBox1.Image);
  31:     line.DrawLine(Pens.Black, 0, this.ImageSize.Height / 2, this.ImageSize.Width, this.ImageSize.Height / 2);
  32:     line.DrawLine(Pens.Black, ImageSize.Width / 2, 0, ImageSize.Height / 2, ImageSize.Height);
  33:  
  34:     line.DrawString("N", new Font("arial", 8F), Brushes.Black, this.ImageSize.Width / 2 - 6, 0);
  35:     line.DrawString("E", new Font("arial", 8F), Brushes.Black, this.ImageSize.Width - 12, this.ImageSize.Height / 2 - 6);
  36:     line.DrawString("W", new Font("arial", 8F), Brushes.Black, 0, this.ImageSize.Height / 2 - 6);
  37:     line.DrawString("S", new Font("arial", 8F), Brushes.Black, this.ImageSize.Width / 2 - 6, this.ImageSize.Height - 12);
  38:     
  39: }
  40:  
  41: void DrawPoint(int prn , float distance, int degree , int? snr) {
  42:     double y = 0.0;
  43:     double x = 0.0;        
  44:  
  45:     if (degree <= 90) {
  46:         x += ImageSize.Width / 2;
  47:         y = ImageSize .Height / 2 - Math.Abs(Math.Sin(Math.PI * degree / 180F) * distance);
  48:         x += Math.Abs(Math.Cos(Math.PI * degree / 180F) * distance);                
  49:     }
  50:     if (degree > 90 && degree <= 180) {
  51:         x += ImageSize.Width / 2;
  52:         y += ImageSize.Height / 2;
  53:         degree = degree - 90;
  54:         y += Math.Abs(Math.Sin(Math.PI * degree / 180F) * distance);
  55:         x += Math.Abs(Math.Cos(Math.PI * degree / 180F) * distance);                
  56:     }
  57:     if (degree > 180 && degree <= 270) {
  58:         y += ImageSize.Height / 2;

59: degree = degree - 180;

  60:         y += Math.Abs(Math.Cos(Math.PI * degree / 180F) * distance);
  61:         x = ImageSize.Width / 2 - Math.Abs(Math.Sin(Math.PI * degree / 180F) * distance);                
  62:     }
  63:     if (degree > 270 && degree <= 360) {                
  64:         degree = degree - 270;
  65:         y = ImageSize.Height / 2 - Math.Abs(Math.Sin(Math.PI * degree / 180F) * distance);
  66:         x = ImageSize.Width / 2 - Math.Abs(Math.Cos(Math.PI * degree / 180F) * distance);
  67:     }        
  68:     Graphics circle = Graphics.FromImage(pictureBox1.Image);
  69:     circle.FillEllipse(this.GetSNRColor(snr), Convert.ToInt32(x) - 8, Convert.ToInt32(y) - 8, 16, 16);
  70:     circle.DrawString(prn.ToString(), new Font("arial" , 8F), Brushes.Black, Convert.ToInt32(x)-6, Convert.ToInt32(y)-6);
  71: }
  72:  
  73: Brush GetSNRColor(int? val) {
  74:     if (!val.HasValue) return Brushes.Black;
  75:     if (val < 20) return Brushes.Gray;
  76:     if (val >= 20 && val < 30) return Brushes.Pink;
  77:     if (val >= 30) return Brushes.Red;
  78:  
  79:     return Brushes.Black;
  80: }

4-3. 결과 화면,

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

5. 결론

GPRMC 나 GPGGA를 통해 얻어진 정보의 신뢰가 의심스러울때는,

GPGSV와 GPGSA정보를 보조 정보로 활용하는것이 효과적이다.

 

   

댓글 없음:

댓글 쓰기