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.SNR16: , 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정보를 보조 정보로 활용하는것이 효과적이다.
댓글 없음:
댓글 쓰기