Author: Antonio Tabernero (ant@fi.upm.es) Last modified: 9/14/2000 (with Etrex info) Following the thread about obtaining raw data from a Garmin GPS12 via async messages, I have prepare a brief report concerning those messages more related to raw data. Send comments, errors, suggestions to ant@fi.upm.es Antonio. History ----------------------------------------------------------------- The original starting point was the compilation by William Soley of the undocumented commands of the Garmin units. Then there was a post indicating that a commercial product (gringo) was available for postprocessing pseudorange and phase info acquired from a GPS12 (or XL), followed by the post from Jose Maria Munoz describing most of the interesting async events. The main expansion of this document over Jose Maria's post concerns messages 0x16, 0x37, 0x39 and a couple fields in 0x38. I also would like to thank Sam Storm van Leeuwen, whose comments and explanations on the peculiarities of the GPS12 receiver made me waste a bit more time on my GPS12. He also found a more general way of obtaining the fractional phase. D.J. Johnson was kind enough to provide me with a binary log of an Garmin Etrex from which I was able to (more or less) find out where the raw data is output in those units. Programs ------------------------------------------------------------------ As I understand that the info presented is necessarily of a local (both in time and space) nature and that the best way to learn more is to get more people involved, I have prepared the programs that I have been using so that they can be useful to other people. Have a look at the following address to download or learn more about these programs: http://artico.lma.fi.upm.es/numerico/miembros/antonio/async The following report also lives there. REPORT ---------------------------------------------------------------- ---------------------------------------------------------------- INDEX: 1. ASYNC EVENTS IN THE GARMIN GPS12 AND RAW DATA INFORMATION: 1.1 Message 0x1a 1.2 Message 0x33 1.3 Message 0x38 1.4 Message 0x39 1.5 Message 0x16 1.6 Message 0x37 2. TYPICAL POWER-ON PROCEDURE. 3. GENERATION OF RINEX2 FILES FROM YOUR GPS12. 4. RAW DATA IN THE GARMIN ETREX -------------------------------------------------------------------- 1. ASYNC EVENTS IN THE GARMIN GPS12 AND RAW DATA INFORMATION I describe records 0x1a, 0x33, 0x38, 0x39, 0x16, and 0x37 (in that order). I have named the different fields of each record (at least those that I think we know what they are) so that they can be referred in different parts of the document. ----------------------------------------------------------------- 1.1 Message ID: 0x1a (12 x 8 bytes) ----------------------------------------------------------------- General description: 12 messages (one for each channel) indicating the SV that the channel is tracking, its elevation, signal strenght, etc. Each message is composed of the following fields: Name svid Position byte 1 Type BYTE Description SVID (PRN-1). If ff, no sat is being tracked in that channel. Name elev Position byte 2 Type BYTE Description Elevation in degrees. Name Fractional Phase Position bytes 3-4 Type unsigned int Description Only 11 bits are used. Divided by 2048 it will give us the fractional carrier phase corresponding to the time of the previous bunch of 0x38 records. BEWARE: there are reports that these field is version dependent. The above interpretation is valid for GPS12 ver 4.0 and XL ver 4.55, but it is not for the XL ver 3.62 Name signal_Q Position bytes 5-6 Type unsigned int Description Signal strenght. Identical to the corresponding field of the preceding 0x38 record. Name tracking_status Position bytes 7-8 Type BYTE[2] Description Two bytes that seems to describe the tracking status of the satellite. The first one can vary betweem 1 and 4. The second one seems to be a flag (0-1). The most important value seems to be the first one. Observed values: ** Correct tracking status: (4,1) or (4,0) The sat is properly tracked, and the tracked_byte of the 0x38 record is non zero. It seems that (4,1) is a previous step to 4,0 (normal situation). ** Abnormal tracking status: (2,0) (3,0) (4,0) In this cases, the tracked_byte of the corresponding 0x38 records is zero, and a new record 0x37 is sent just after each 0x38. (2,0) Initial status at power-on of the sats with low signal. It seems that the GPS don't pay attention to them at that point. Few 0x38 are sent and those show an null tracked_byte. (1,0) Similar results to (2,0) (tracked_byte=0 in 0x38), but it is not an initial situation. It looks as though that sat has been declared unusable. (3,0) Special status in which a sat can fall after being tracked for a while. -------------------------------------------------------------------- 1.2 Message ID: 0x33 (64 bytes) -------------------------------------------------------------------- Corresponds to Garmin documented D800_Pvt_Data_Type. So no guess here, but not useful for postprocessing either. It is interesting to monitor, though, to check when the GPS is able to get a fix and what kind of a fix. 4 bytes float altitude above WGS84 ellipsoid 4 bytes float Position error 4 bytes float Horizontal pos. error 4 bytes float Vertical pos. error 2 bytes int Type of fix 8 bytes double time of week (sec) 8 bytes double latitude 8 bytes double longitude (radians) 4 bytes float velocity east 4 bytes float vel north 4 bytes float vel up 2 bytes int leap seconds 4 bytes long week number days ------------------------------------------------------------------ 1.3 Message ID: 0x38 (37 byte long) ------------------------------------------------------------------- Data related to a particular sat (indicated in the last byte). It is in this record where the most interesting info seems to be sent. Name phase_counter Position bytes 1-4 Type unsigned long Description A counter that gets increased by about 60-70 millions per seconnd. The lower 11 bits give us the fractional phase (it mirrors the corresponding field in the 0x1a record), while the upper bits (12-32) represent the integer number of cycles. Just after starting the unit those bits will be equal to the Integrated_phase field (see below), but after a while the won't, because the phase_counter will roll over. The best way to compute the carrier phase is thus: carrier_phase = integrated_phase (whole cycles) + (phase_counter AND 2047)/2048. that is, the integrated_phase field keeps track of the integer number of cycles, so we don't have to worry about the rollover of phase_counter. From phase_counter we use only its lower 11 bits to get the fractional phase. Name track_byte Position byte 5 Type Byte Description 0x00 indicates some sort or problem with the sat. This is the case for sats with low elevation and weak signal. In that case, the other data may be unreliable. Name unknown Position bytes 6-8 Type byte[3] Description Seem to be grouped into an integer (bytes 6-7) and a flag byte (byte 8) that is always? 00 or ff. The integer?? moves while the tracked_byte is 00 (the sat is not properly tracked). When the sat is locked, the number gets frozen. Name delta_f Position bytes 9-10 Type unsigned int (interpreted as signed by substracting 32768) Description If we consider this field a signed integer (not as usually interpreted by the machine, but considering 32768 as the zero so that the value we use is actually delta_f-32768), it is positive for those sats with larger increments of pseudoranges (going away from us) and negative for those with smaller increments of pseudoranges (approaching us): Sat Id delta_pseudorange delta_f-32768 ------------------------------------------- 10 6329 1323 02 5638 -2402 05 6534 2428 15 5863 -1186 The relation between those two quantities is linear and the constant relating them (in a least squares fit) is very close to the L1 wavelenght. That would mean that this field could be a measurement/estimation? of the Doppler shift (in Hertz) for each sat. For the above data an aproximate fit is: delta_f = (delta_pr - 6080) / lambda delta_pr is obviouly a measure of the relative speed of the satellite, and the origin 6080 m/s would be the false speed caused by the clock drift. Once that bias is removed, the relation would be: delta_f = relative_speed / lambda = L1 * (relative_speed/c) = Doppler shift (Hz) Name Integrated Phase Position Bytes 11-14 Type unsigned long Description integrated phase (whole cycles). The ratio of its increment with the increment of the pseudorange field corresponds with the inverse of the L1 wavelenght. Once locked, the difference between both fields rarely exceed 100 cm. Name pseudorange Position Bytes 15-22 Type double Description Pseudorange in meters. Due to the particular idiosincrasy of the GPS12, these numbers can get real large, because the GPS12 allows the clock error to accumulate in them, at a rate (in my unit) of about 6000 m/s. Name c_511500 Position Bytes 23-26 Type Unsigned long Description 511500 Hz timer. 511500 ticks corresponds to a receiver's second. At the start it is incremented by exactly 511500 units, but once enough sats have been acquired, it can vary one or two units (probably as the GPS tries to sync its measurements to an exact GPS system time second. Name signal_Q Position Bytes 27-28 Type Unsigned int. Description Measure of the signal strength or quality for that satellite. It has the same value as in the corresponding field of the next 0x1a record. Name tow Position Bytes 29-36 Type Double Description Time of week in seconds. At the start it is incremented exactly by one second (511500 units of c_511500). However, after enough sats have been acquired, the GPS gets an idea of its internal clock drift, and (in my unit) 511500 units of c_511500 correspond to about 1.00002 sec of the receiver time. These 20 microseconds per second correspond to aprox. 6000 m/sec, the drift of the internal clock reflected in the pseudoranges. Monitoring this field we can check our clock drift. Also, as I have already said, the increments of c_511500 are not exactly 511500, as the GPS tries to take each measurement synced to a GPS second. Name svid Position Byte 37 Type Byte Description Space Vehicle ID (PRN-1) ------------------------------------------------------------------ 1.3 Message ID: 0x39 (35 byte long) ------------------------------------------------------------------- BYTES 1-2 : changing. BYTES 3-10 : fixed for each start. BYTES 11-19: changing. BYTES 20-34: fixed for each start. BYTE 35 : SVID (PRN-1) General description: This record is sent once per satellite when the GPS first locks to that satellite (svid field) and it's able to compute a valid pseudorange. I don't know if it is sent again if the sat is lost and later re-acquired. Tipycally, you will see a 0x38 record with an invalid pseudorange field, then a record 0x39, and the the same 0x38 record with all its counters unmodified except for the pseudorange field, that nows is something around 22,000,000 mts. More on the relation of this event with others is explained later, in the section about the start procedure. -------------------------------------------------------------- 1.4 Message ID: 0x36 --------------------------------------------------------------- General description: timing info + something else. These records are only sent once we have computed a valid pseudorange for a satellite (see power-on description below), and disappear if there is troubles (when tracked_byte of record 0x38 becomes 0). Name c_50 Position Bytes 1-4 Type unsigned long Description 50 Hz counter, STARTING from the beginning of the week, that is, c_50/50 corresponds to TOW. It gets incremented in 30 count intervals, so that the resolution is 0.6 sec. Name unknown Position bytes 5-8 Type BYTE[4] Description seem to vary randomly. Name svid Position byte 9 Type BYTE Description SVID (PRN-1) ----------------------------------------------------------------- 1.5 Message ID: 0x16 ----------------------------------------------------------------- General description: several hints indicate that this record could be related to velocity??/Doppler??? information: * The delta_pseudorange_rate field is very similar to the difference in pseudoranges divided by the time increment. * Also, using the phase field of the 0x38 record as a reference, and studying the behaviour of this field compared to the rate of increase of that phase we found the following: Sat Id Signal_Q Mean(cm) std (cm) 10 12000 2.0 19 02 8500 -1.3 16 05 6000 0.3 18 15 12500 0.8 17 18 6500 -0.2 18 We find that this delta_pseudorange rate follows the phase rate a bit more closely than the differences of pseudoranges shown in the other table. The improvement is more clearly seen in those sats with a lower signal. That would be consistent with its being a more precise measurement (integrated Doppler??) of the same quantity. Again, beware that this has been obtained by examining a couple minutes of data, and this interpretation could be wrong. * These 0x16 records are not sent until enough sats are acquired. * F1 and F2 seems to be some sort of correction (Kalman filter parameters/variances??) that is used when aditional info is gathered. Some observations: - F1 has similar values (usually 0 point something) for each group of messages that are sent together for the different sats. - F2 can be real big (in the order of thousands) in a cold start for a different position for the FIRST satellites. After a while, F2 drops to its normal values of about 5. - In a warm start (same position,a bit later) F2 values are very low from the beginning. - In its stable state, F2 used to be larger (about 20-30 as opposed to 3-5) with SA on. Name delta_pseudorange_rate (m/s) Position bytes 1-4 Type float Description A float that closely (usually within a meter) resembles the increment of the pseudorange for that sat in a second. Name f1 Position bytes 5-8 Type float Description Similar values for a group of messages that are sent together for the different sats. See general description above. Name pseudorange Position bytes 9-16 Type double Description Pseudorange (ms). Same as in the preceding 0x38 record. Name f2 Position bytes 17-20 Type float Description See general description above. Name svid Position byte 21 Type BYTE Description SVID (PRN-1) ----------------------------------------------------------------- 1.5 Message ID: 0x37 (33 bytes) ----------------------------------------------------------------- General description: This message is associated to a abnormal tracking status of a satellite, namely, (3,0) (2,0) or (1,0) in the tracking_status bytes of a 0x1a record. When this situation appears, the tracked_byte field of the 0x38 records is put to 00, and a 0x37 record follows each 0x38 (at that point the 0x36 records disappear). Name c1 Position bytes 1-2 Type unsigned int Description (??) counter, increasing, but not exceeding a relatively small value (depending on the tracking status). The values within a group of 0x37 messages with the same time tag are strongly correlated. Name ?? Position bytes 3-4 Type BYTE[2] Description flags?? Mostly 00 00 Name c2 Position bytes 5-6 Type unsigned int Description similar description as previous field c1. At power-on, this field is the same for all 0x37 messages with the same time-tagging (for different sats), but later on they differ. Name delta_f Position bytes 7-8 Type unsigned int (interpreted as signed by substracting 32768) Description Correlated with the delta_f field of the 0x38 record. In that case it would be the Doppler shift?? in Hz. When 0x37 records are being sent, this field (in normal conditions a slow drifter) is frozen, and is the same in both (0x38 and 0x37) records. When it changes, the change is first seen on this field, and reflected on the next 0x38 record. Name countdown Position bytes 9-10 Type unsigned int Description (??) Similar as c1 and c2 above. It also shows same values for each group of 0x37 records with the same timing at power-on. Later this sinchrony dissappears. A particular case is when the sat falls in a (3,0) status. In that case, the value is always? between 0 and 1024. If it is lower than 64, the situation remains unchanged. When it gets larger than 64, it increases at a rate of 16 per second (60'' countdown). When it reaches 1024 (but not before) the sat can be either correctly tracked again, or a new cycle starts. Name pseudorange Position bytes 11-18 Type double Description Pseudorange looking value, but slightly different from the value in the same field of the 0x38 record. My guess is that this value is a sort of dead-reckoning when the sat is not being tracked. This is based on the fact that, when first powered, while the 0x38 (tracked_byte=00) may show an incorrect pseudorange field for the sats with a tracking_status of (2,0), the pseudorange field in the 0x37 record has at least the ``right'' aspect (it could be an educated guess based on the stored almanaq info). Name c511 Position bytes 19-22 Type unsigned long Description 511500 Hz counter. Same value as the preceding 0x38 record. Name tow Position bytes 23-30 Type double Description time of week. Same value as in the corresponding field of the preceding 0x38 record. Name ?? Position bytes 31-32 Type BYTE[2] Description flags?? Mostly 00 00, sometimes 01 or ff Name svid Position byte 33 Type BYTE Description SVID (PRN-1) -------------------------------------------------------------------- 2. TYPICAL POWER-ON PROCEDURE: The GPS starts sending 0x38 records for the most visible/strong sats. The pseudorange fields are invalid (although its increments are correct and coherent with the phase increments). The increment of the c_511500 counter and tow are exactly 511500 units and 1'' respectively. At about 5 secs the first 0x1a (combining several sats info) is sent. A 0x39 record is sent for a particalar sat. The pseudorange field of the 0x38 record is replaced by a valid number: 0x38 ---------------------------------------------------------------- SVID 10: TRACK_BYTE 49 Sgn Q 9580 CC2 1684 FLAG 00 PseudoRange 24262.1 (Counter = 593122866) Phase 289610 TOW 201131.00703 (Counter 0.5 Mhz = 5115000) Cont (?) 34323 0x39 --------------------------------------------------------- SVID 10: Meaningful Pseudorange 0x38 ---------------------------------------------------------------- SVID 10: TRACK_BYTE 49 Sgn Q 9580 CC2 1684 FLAG 00 PseudoRange 21548541.7 (Counter = 593122866) Phase 289610 TOW 201127.21737 (Counter 0.5 Mhz = 5115000) Cont (?) 34323 ---------------------------------------------------------------------- Inmediately after a 0x39 record is sent, we start receiving records 0x36 for that particular sat. Also the tow is reset to something more close to real GPS time, in the above example the GPS clock was almost 4'' fast (it was a cold start). Only when 3 0x39 records for three different sats have been sent, the GPS is able to get a (2D) fix, and the corresponding 0x33 records (position/vel,etc) start coming once a second. If a fourth satellite is locked (another 0x39 record), the fixes are 3D: 0x39 --------------------------------------------------------- SVID 15: Meaningful Pseudorange 0x39 --------------------------------------------------------- SVID 16: Meaningful Pseudorange 0x39 --------------------------------------------------------- SVID 10: Meaningful Pseudorange 0x33 ---------------------------------------------------------------- Pos: (N,E,H ) (0.7048 -0.0651 686.2358) H_ellip=-52 FIX 1D Wdays 3808 TOW 118123.631 Leap 13 0x33 ---------------------------------------------------------------- Pos: (N,E,H ) (0.7048 -0.0651 686.2358) H_ellip=-52 FIX 2D Wdays 3808 TOW 118124.631 Leap 13 0x33 ---------------------------------------------------------------- Pos: (N,E,H ) (0.7048 -0.0651 686.2358) H_ellip=-52 FIX 2D Wdays 3808 TOW 118126.000 Leap 13 0x33 ---------------------------------------------------------------- Pos: (N,E,H ) (0.7048 -0.0651 686.2358) H_ellip=-52 FIX 2D Wdays 3808 TOW 118129.000 Leap 13 0x39 --------------------------------------------------------- SVID 14: Meaningful Pseudorange 0x33 ---------------------------------------------------------------- Pos: (N,E,H ) (0.7048 -0.0651 691.3297) H_ellip=-52 FIX 3D -------------------------------------------------------------------- Note the frozen height while in a 2D fix. Also when the GPS has sent 4 0x39 records (four sats locked) the GPS is able to precisely estimate its clock error, and the tow is synced more precisely to GPS time. From now on, the increments of tow begins to reflect the clock drift, being in my case of about 1.00002 seconds. The increment of the 511500 counter can change in 1 or 2 units, as the GPS tries to takes measurements in full GPS time seconds. Another record that only shows when at least 3 sas are locked are the 0x16 records with ???Doppler??? info. --------------------------------------------------------------------- 3. GENERATION OF RINEX2 FILES FROM YOUR GPS12. Once we think we know where pseudorange and phase info is sent in the async messages, it is time to try to see if something useful can be done with it. Writing a postprocessing software without knowing wheather or not we have something real to work with seems a waste of time. The easiest way to check things out would be to take advantage of the postprocessing soft available. Usually those packages work with something called the RINEX (Receiver INdependent Exchange) format. As its name implies, this RINEX format is simply a way of putting all the pseudorange, phase, timing info into a file, so that postprocessing packages can work with it independently of the receiver which collected the data. The advantage of the RINEX format is that the reference stations (CORS, EUREF, CDDIS) around the globe also publish their data in RINEX format. IN this way (with the proper software) our G12 generated RINEX files could be directly postprocessed against those reference stations. If you want to know the state-of-the-art in this RINEX-from-GPS12 bussiness, check this \hlink{link}{http://artico.lma.fi.upm.es/numerico/miembros/antonio/async} ----------------------------------------------------------------------- 4. RAW DATA IN THE GARMIN ETREX. As it was pointed out the Garmin Etrex doesnt output raw data information in the same format as the G12 family. However, after a brief examination of a binary log kindly supplied by D.J. Johnson it seems that very similar info is present in the async messages sent by the Etrex. It only happens that Garmin thought to improve on its undocumented messages by shuffling the fields within most messages. Here comes a brief description of where the interesting info is to be found in the Etrex. There is no description of the fields as they are common with the already described above. Since the interesting info seems to be there all right it would also be possible to generate a Rinex file from a log of the Etrex. In order to do so the latest version of gar2rnx has an -etrex option. I havent done any testing whatsoever since I dont ve access to an Etrex. Let me know if this is working for you. --------------------------------------------- RECORD 0x1a (L=12 x 8 bytes) --------------------------------------------- Same as in the G12 family. Twelve eight-byte records, one for each channel. The fields are exactly the same though most are in different positions: Bytes 1-2: Fractional Phase Bytes 3-4: signal_Q Bytes 5 : elev Bytes 6 : svid Bytes 7-8: tracking status -------------------------------------------- RECORD 0x36 (L=12 bytes) -------------------------------------------- Bytes 1-4 : c_50 Bytes 5-8 : unknown Byte 9 : svid Bytes 10-12: three aditional new bytes. In my (very) short piece of evidence they are fixed for all sats. -------------------------------------------- RECORD 0x38 (L=40 bytes) ------------------------------------------- Same info as in the G12 messages with three additional bytes added at the end. The position of the old fields is as follows: Bytes 1 - 8 : Pseudorange Bytes 9 -16 : Tow Bytes 17-20 : Phse_counter Bytes 21-24 : tracked Bytes 25-28 : Integer Integrated phase Bytes 29-32 : c_511500 Bytes 33-34 : delta_f Bytes 35-36 : signal_Q Bytes 37 : svid Bytes 38-40 : new bytes. -------------------------------------------- RECORD 0x16 (L=24 bytes) -------------------------------------------- Bytes 1 - 8 : Pseudorange Bytes 9 -12 : Delta Pseudorange Bytes 13-16 : f1 Bytes 17-20 : f2 Bytes 21 : svid Bytes 22-24 : new bytes