GPS 数据格式
GPS 抖动检测:
关于车辆管理的软件。发现当车辆静止时,GPS接收器收到的数据、方向、速度都在不停的跳动,从而造成车子停止时,车子在地图上不停的乱跳的现象。
GPS 最后的 *后面的两个字符为校验和,其计算方式为从$到*之间所有字符的XOR值(不包括$和*):
function Checksum(const s: string): string;
var
sum: Byte;
i : Integer;
begin
sum := Ord(s[2]);
for i := 3 to Length(s) - 1 do
sum := sum xor ord(s[i]);
Result := IntToHex(sum, 2);
end;
function Test(): string;
begin
//$GPGGA,041147.000,2214.6493,N,11334.9579,E,1,07,1.0,7.8,M,-3.8,M,,0000*4F
Result := Checksum('$GPGGA,041147.000,2214.6493,N,11334.9579,E,1,07,1.0,7.8,M,-3.8,M,,0000*');
end;
这里谈一些解决方法或这方面的资料。
普通GPS误差+/-10m,不乱跑是不正常的
一般的解决办法是读NMEA数据中的速度值为零时,就不去更新地图上的经纬度。如果你的速度和经纬度都是在不断地微动(早期的SurF板就一直解决不了这个问题),那就没办法了。
几个老问题,硬件的因素不好控制,目前还是软件判断做补救工作:
1.检测到的状态为静止时,强制速度为0;
2.速度为0时,强制方向为0;
3.至于漂移问题,可以通过比较上次定位数据的经纬度差的绝对值(同时包括时间)来判定;
至于纯硬件问题,有的模块漂移100m都是可能的
要解决得硬件配合
1、若有行车记录仪检测到车速就能精确解决;
2、或者当车熄火时,硬件定位仪应能检测的到,根据熄火状态去漂移
就目前来看,静态漂移很难完全避免
从硬件的角度,选择好的接收板;从软件的角度,单纯从速度、位置的瞬时值肯定很不好判断。GPS每秒更新数据,而物体的运动轨迹一般是连续的而不是杂乱无章的,状态的变化一般是渐渐的,而不是突变。可以考虑连续的几个瞬时值的变化过程。
建议从以下两个方面综合判断
1.方向的变化:
方向变化过于频繁,一会左转一会右转,一会向东,一会向西,基本上是漂移。 正常行驶很少见方向频繁的不连续变化的。
2.位置的变化
在1秒之内,两个位置之间的距离达到50米以上(180KM/H),对于汽车和轮船基本上有问题,当然,飞机除外。
如果是车载,可以根据速度判断,静态漂移速度值一般不会大于5km/h。
从硬件的角度看,有的gps模块是可以判断是否是在静漂状态的
目前,如果卫星漂移会造成一些问题,开发的轨迹回放是把数据库中的速度为0的过滤掉,这样就没有问题了
Simple Text Output Format:
The simple text (ASCII) output contains time, position, and velocity data in the fixed width fields (not delimited) defined in the following table:
FIELD DESCRIPTION: WIDTH: NOTES:
----------------------- ------- ------------------------
Sentence start 1 Always '@'
----------------------- ------- ------------------------
/Year 2 Last two digits of UTC year
| ----------------------- ------- ------------------------
| Month 2 UTC month, "01".."12"
T | ----------------------- ------- ------------------------
i | Day 2 UTC day of month, "01".."31"
m | ----------------------- ------- ------------------------
e | Hour 2 UTC hour, "00".."23"
| ----------------------- ------- ------------------------
| Minute 2 UTC minute, "00".."59"
| ----------------------- ------- ------------------------
\Second 2 UTC second, "00".."59"
----------------------- ------- ------------------------
/Latitude hemisphere 1 'N' or 'S'
| ----------------------- ------- ------------------------
| Latitude position 7 WGS84 ddmmmmm, with an implied
| decimal after the 4th digit
| ----------------------- ------- ------------------------
| Longitude hemishpere 1 'E' or 'W'
| ----------------------- ------- ------------------------
| Longitude position 8 WGS84 dddmmmmm with an implied
P | decimal after the 5th digit
o | ----------------------- ------- ------------------------
s | Position status 1 'd' if current 2D differential GPS position
i | 'D' if current 3D differential GPS position
t | 'g' if current 2D GPS position
i | 'G' if current 3D GPS position
o | 'S' if simulated position
n | '_' if invalid position
| ----------------------- ------- ------------------------
| Horizontal posn error 3 EPH in meters
| ----------------------- ------- ------------------------
| Altitude sign 1 '+' or '-'
| ----------------------- ------- ------------------------
| Altitude 5 Height above or below mean
\ sea level in meters
----------------------- ------- ------------------------
/East/West velocity 1 'E' or 'W'
| direction
| ----------------------- ------- ------------------------
| East/West velocity 4 Meters per second in tenths,
| magnitude ("1234" = 123.4 m/s)
V | ----------------------- ------- ------------------------
e | North/South velocity 1 'N' or 'S'
l | direction
o | ----------------------- ------- ------------------------
c | North/South velocity 4 Meters per second in tenths,
i | magnitude ("1234" = 123.4 m/s)
t | ----------------------- ------- ------------------------
y | Vertical velocity 1 'U' (up) or 'D' (down)
| direction
| ----------------------- ------- ------------------------
| Vertical velocity 4 Meters per second in hundredths,
\ magnitude ("1234" = 12.34 m/s)
----------------------- ------- ------------------------
Sentence end 2 Carriage return, '0x0D', and
line feed, '0x0A'
----------------------- ------- ------------------------
If a numeric value does not fill its entire field width, the field is padded
with leading '0's (eg. an altitude of 50 meters above MSL will be output as "+00050").
Any or all of the data in the text sentence (except for the sentence start
and sentence end fields) may be replaced with underscores to indicate
invalid data.
GPS 解码函数,NMEA0183解码函数:
const
CIMaxSatInfo = 4;
type
TSatInfo = packed record /// GPS信息
PRN: integer; // 卫星号码
EL,AZ: integer; // 仰角、方位
SN: integer; // 信号噪音比
end;
TGPSInfo = packed record /// 解码后的GPS信息结构
UTCTime: TDateTime; /// GPS时间, UTC 格式,不包含日期
Longitude : Double; /// 经度
Latitude : Double; /// 纬度
LatHemi, LonHemi: Char;// N、S、E、W
Altitude : Double; /// 海拔高度
Speed : Double; /// 速度
Course: Double; /// 方向
Fix: string[10]; /// 定位方式
SatInfo: Array [1..CIMaxSatInfo] of TSatInfo;
end;
TGPSTimePoint = packed record /// GPS 三参数组:时间,经度,纬度
Time: TDateTime;
Longitude: Double;
Latitude: Double;
end;
/// GPS移动方向,八个方向
TDirection = (gdNone, gdW2E, gdE2W, gdS2N, gdN2S, gdES2WN, gdWS2EN, gdWN2ES, gdEN2WS);
// [2007-9-13]Kingron: 解码GPS数据,NMEA0183格式,每次一条信令,非连续
// 处理GPS发来的所有数据
//$PGRME,45.3,M,,M,45.3,M*00
//Estimated Error Information (PGRME)
//The GARMIN Proprietary sentence $PGRME reports estimated position error
//information.
//$PGRME,<1>,M,<2>,M,<3>,M*hh<CR><LF>
//<1> Estimated horizontal position error (HPE), 0.0 to 999.9 meters
//<2> Estimated vertical position error (VPE), 0.0 to 999.9 meters
//<3> Estimated position error (EPE), 0.0 to 999.9 meters
//下面是一些样本数据
//$GPGSV,3,1,09,05,18,043,43,11,04,290,44,14,59,034,43,15,01,184,*70
//$GPGSV,3,2,09,16,13,200,,18,22,153,,23,44,160,,25,54,288,51*7E
//$GPGSV,3,3,09,30,46,061,30,,,,,,,,,,,,*45
//$PGRME,45.3,M,,M,45.3,M*00
//$GPRMC,131558,A,2818.7145,N,10944.4235,E,000.0,000.0,1n0503,002.0,W*61
//$GPGGA,131558,2818.7145,N,10944.4235,E,1,04,4.6,238.2,M,-25.4,M,,*66
//$GPGSA,A,2,05,11,14,,,,,25,,,,,4.6,4.6,*1A
function DecodeGPS(const msg: string; var GPSInfo: TGPSInfo): Boolean;
function GetNextItem(start: integer; len: integer; var tmp: string):integer;
var
i: integer;
begin
tmp := '';
result := 0;
i := start + 1;
while (msg[i] <> '$') and (msg[i] <> ',') and (msg[i] <> '*') and (i<Len) do begin
tmp := tmp + msg[i];
inc(i);
inc(result);
end;
end;
function CountChar(start: integer; len: integer):integer;
var
i: integer;
begin
i:=start;
Result := 0;
while (msg[i] <> Chr($0d)) and (msg[i] <> Chr($0a)) and (msg[i] <> '$') and (i<Len) do begin
if msg[i] = ',' then inc(Result);
inc(i);
end;
end;
var
CurPos,strLen: integer;
tmpStr: string;
tmpFloat: Double;
tmpi,i: integer;
begin
CurPos := 0;
strLen := Length(msg);
while CurPos<strLen do begin
while (msg[CurPos] <> '$') and (CurPos<strLen) do inc(CurPos);
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
if tmpStr = 'GPGGA' then begin
if CountChar(CurPos,strLen) = 14 then begin
//$GPGGA,131558,2818.7145,N,10944.4235,E,1,04,4.6,238.2,M,-25.4,M,,*66
//$GPGGA,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,M,<10>,M,<11>,<12>*hh<CR><LF>
//<1> UTC时间, hhmmss
//<2> 纬度, ddmm.mmmm (输出前导零)
//<3> 南北, N or S
//<4> 经度, dddmm.mmmm (输出前导零)
//<5> 东西, E or W
//<6> GPS质量评估, 0 = 不能定位, 1 = 非差分定位
//, 2 = 差分定位(DGPS), 6 = 估计
//<7> 使用中的卫星数量, 00 to 12 (输出前导零)
//<8> Horizontal dilution of precision, 0.5 to 99.9
//<9> 海拔高度, -9999.9 to 99999.9 米
//<10> Geoidal height, -999.9 to 9999.9 meters
//<11> 差分GPS(RTCM SC-104)数据寿命, number of seconds since last valid
//RTCM transmission (非差分时为空)
//<12> 差分GPS参考站ID, 0000 to 1023 (输出前导零,非差分时为空)
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
GPSInfo.UTCTime := MyTimeToStr(tmpStr, GPSInfo.UTCTime);
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
tmpFloat := StrToFloatDef(tmpStr,0) / 100;
GPSInfo.Longitude := Int(tmpFloat) + (Frac(tmpFloat) * 5) / 3;
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
GPSInfo.LatHemi := tmpStr[1];
if GPSInfo.LatHemi = 'S' then GPSInfo.Latitude := -1 * GPSInfo.Latitude;
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
tmpFloat := StrToFloatDef(tmpStr,0) / 100;
GPSInfo.Longitude := Int(tmpFloat) + (Frac(tmpFloat) * 5) / 3;
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
GPSInfo.LonHemi := tmpStr[1];
if GPSInfo.LonHemi = 'W' then GPSInfo.Longitude := -1 * GPSInfo.Longitude;
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
GPSInfo.Altitude := StrToFloatDef(tmpStr,0);
end;
end else if tmpStr = 'GPGSA' then begin
if CountChar(CurPos,strLen) = 17 then begin
//卫星状态表
//$GPGSA,A,2,05,11,14,,,,,25,,,,,4.6,4.6,*1A
//$GPGSA,<1>,<2>,<3>,<3>,<3>,<3>,<3>,<3>,<3>,<3>,<3>,<3>,<3>,<3>,<4>,<5>,<6>
//*hh<CR><LF>
//<1> Mode, M = manual, A = automatic
//<2> 定位状态, 1 = not available, 2 = 2D, 3 = 3D
//<3> 卫星号码,最多12个
//<4> Position dilution of precision, 0.5 to 99.9
//<5> Horizontal dilution of precision, 0.5 to 99.9
//<6> Vertical dilution of precision, 0.5 to 99.9
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
case StrToIntDef(tmpStr,0) of
2: GPSInfo.Fix := '2D Fix';
3: GPSInfo.Fix := '3D Fix';
else
GPSInfo.Fix := 'No Fix';
end;
end;
end else if tmpStr = 'GPRMC' then begin
if CountChar(CurPos,strLen) = 11 then begin
//Recommended Minimum Specific GPS/TRANSIT Data (RMC)
//$GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh<CR><LF>
//$GPRMC,131558,A,2818.7145,N,10944.4235,E,000.0,000.0,1n0503,002.0,W*61
//<1> UTC time of position fix, hhmmss format
//<2> Status, A = Valid position, V = NAV receiver warning
//<3> Latitude, ddmm.mmmm format (leading zeros will be transmitted)
//<4> Latitude hemisphere, N or S
//<5> Longitude, dddmm.mmmm format (leading zeros will be transmitted)
//<6> Longitude hemisphere, E or W
//<7> Speed over ground, 000.0 to 999.9 knots (leading zeros will be transmitted)
//<8> Course over ground, 000.0 to 359.9 degrees, true (leading zeros will be
//transmitted)
//<9> UTC date of position fix, ddmmyy format
//<10> Magnetic variation, 000.0 to 180.0 degrees (leading zeros will be transmitted)
//<11> Magnetic variation direction, E or W (westerly variation adds to true course)
//<12> Mode indicator (only output if NMEA 2.30 active), A = Autonomous, D =
//Differential, E = Estimated, N = Data not valid
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
GPSInfo.Speed := StrToFloatDef(tmpStr,0);
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
GPSInfo.Course := StrToFloatDef(tmpStr,0);
end;
end else if tmpStr = 'GPGSV' then begin
if CountChar(CurPos,strLen) = 19 then begin
//$GPGSV,3,1,09,05,18,043,43,11,04,290,44,14,59,034,43,15,01,184,*70
//$GPGSV,3,2,09,16,13,200,,18,22,153,,23,44,160,,25,54,288,51*7E
//$GPGSV,3,3,09,30,46,061,30,,,,,,,,,,,,*45
//$GPGSV,<1>,<2>,<3>,<4>,<5>,<6>,<7>,...<4>,<5>,<6>,<7>*hh<CR><LF>
//<1> Total number of GSV sentences to be transmitted
//<2> Number of current GSV sentence
//<3> Total number of satellites in view, 00 to 12 (leading zeros will be transmitted)
//<4> Satellite PRN number, 01 to 32 (leading zeros will be transmitted)
//<5> 卫星仰角, 00-90度
//<6> 卫星方位角, 000-359度
//<7> 卫星信号噪音比 00-99db
//NOTE: Items <4>,<5>,<6> and <7> repeat for each satellite in view to a maximum of
//four (4) satellites per sentence. Additional satellites in view information must be
//sent in subsequent sentences. These fields will be null if unused.
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
tmpi := StrToIntDef(tmpStr,1);
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
for i:= 1 to CIMaxSatInfo do begin
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
GPSInfo.SatInfo[(tmpi-1)*4 + i].PRN := StrToIntDef(tmpStr,0);
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
GPSInfo.SatInfo[(tmpi-1)*4 + i].EL := StrToIntDef(tmpStr,0);
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
GPSInfo.SatInfo[(tmpi-1)*4 + i].AZ := StrToIntDef(tmpStr,0);
CurPos:= CurPos + 1 + GetNextItem(CurPos,strLen,tmpStr);
GPSInfo.SatInfo[(tmpi-1)*4 + i].SN := StrToIntDef(tmpStr,0);
end;
end;
end;
inc(CurPos);
end;
Result := True;
end;