source: ntrip/trunk/BNC/RTCM/RTCM2.cpp@ 464

Last change on this file since 464 was 464, checked in by weber, 17 years ago

* empty log message *

File size: 27.4 KB
Line 
1//------------------------------------------------------------------------------
2//
3// RTCM2.cpp
4//
5// Purpose:
6//
7// Module for extraction of RTCM2 messages
8//
9// References:
10//
11// RTCM 10402.3 Recommended Standards for Differential GNSS (Global
12// Navigation Satellite Systems) Service; RTCM Paper 136-2001/SC104-STD,
13// Version 2.3, 20 Aug. 2001; Radio Technical Commission For Maritime
14// Services, Alexandria, Virgina (2001).
15// ICD-GPS-200; Navstar GPS Space Segment / Navigation User Interfaces;
16// Revison C; 25 Sept. 1997; Arinc Research Corp., El Segundo (1997).
17// Jensen M.; RTCM2ASC Documentation;
18// URL http://kom.aau.dk/~borre/masters/receiver/rtcm2asc.htm;
19// last accessed 17 Sep. 2006
20// Sager J.; Decoder for RTCM SC-104 data from a DGPS beacon receiver;
21// URL http://www.wsrcc.com/wolfgang/ftp/rtcm-0.3.tar.gz;
22// last accessed 17 Sep. 2006
23//
24// Notes:
25//
26// - The host computer is assumed to use little endian (Intel) byte order
27//
28// Last modified:
29//
30// 2006/09/17 OMO Created
31// 2006/09/19 OMO Fixed getHeader() methods
32// 2006/09/21 OMO Reduced phase ambiguity to 2^23 cycles
33// 2006/10/05 OMO Specified const'ness of various member functions
34// 2006/10/13 LMV Fixed resolvedPhase to handle missing C1 range
35// 2006/10/14 LMV Fixed loop cunter in ThirtyBitWord
36// 2006/10/14 LMV Exception handling
37// 2006/10/17 OMO Removed obsolete check of multiple message indicator
38// 2006/10/17 OMO Fixed parity handling
39// 2006/10/18 OMO Improved screening of bad data in RTCM2_Obs::extract
40// 2006/11/25 OMO Revised check for presence of GLONASS data
41// 2007/05/25 GW Round time tag to 100 ms
42//
43// (c) DLR/GSOC
44//
45//------------------------------------------------------------------------------
46
47#include <bitset>
48#include <cmath>
49#include <fstream>
50#include <iomanip>
51#include <iostream>
52#include <string>
53#include <vector>
54
55#include "RTCM2.h"
56
57// Activate (1) or deactivate (0) debug output for tracing parity errors and
58// undersized packets in get(Unsigned)Bits
59
60#define DEBUG 0
61
62using namespace std;
63
64
65// GPS constants
66
67const double c_light = 299792458.0; // Speed of light [m/s]; IAU 1976
68const double f_L1 = 1575.42e6; // L1 frequency [Hz] (10.23MHz*154)
69const double f_L2 = 1227.60e6; // L2 frequency [Hz] (10.23MHz*120)
70
71const double lambda_L1 = c_light/f_L1; // L1 wavelength [m] (0.1903m)
72const double lambda_L2 = c_light/f_L2; // L2 wavelength [m]
73
74//
75// Bits for message availability checks
76//
77
78const int bit_L1rngGPS = 0;
79const int bit_L2rngGPS = 1;
80const int bit_L1cphGPS = 2;
81const int bit_L2cphGPS = 3;
82const int bit_L1rngGLO = 4;
83const int bit_L2rngGLO = 5;
84const int bit_L1cphGLO = 6;
85const int bit_L2cphGLO = 7;
86
87
88//
89// namespace rtcm2
90//
91
92namespace rtcm2 {
93
94
95//------------------------------------------------------------------------------
96//
97// class ThirtyBitWord (implementation)
98//
99// Purpose:
100//
101// Handling of RTCM2 30bit words
102//
103//------------------------------------------------------------------------------
104
105// Constructor
106
107ThirtyBitWord::ThirtyBitWord() : W(0) {
108};
109
110// Clear entire 30-bit word and 2-bit parity from previous word
111
112void ThirtyBitWord::clear() {
113 W = 0;
114};
115
116// Failure indicator for input operations
117
118bool ThirtyBitWord::fail() const {
119 return failure;
120};
121
122// Parity check
123
124bool ThirtyBitWord::validParity() const {
125
126 // Parity stuff
127
128 static const unsigned int PARITY_25 = 0xBB1F3480;
129 static const unsigned int PARITY_26 = 0x5D8F9A40;
130 static const unsigned int PARITY_27 = 0xAEC7CD00;
131 static const unsigned int PARITY_28 = 0x5763E680;
132 static const unsigned int PARITY_29 = 0x6BB1F340;
133 static const unsigned int PARITY_30 = 0x8B7A89C0;
134
135 // Look-up table for parity of eight bit bytes
136 // (parity=0 if the number of 0s and 1s is equal, else parity=1)
137 static unsigned char byteParity[] = {
138 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
139 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
140 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
141 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
142 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
143 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
144 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
145 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0
146 };
147
148 // Local variables
149
150 unsigned int t, w, p;
151
152 // The sign of the data is determined by the D30* parity bit
153 // of the previous data word. If D30* is set, invert the data
154 // bits D01..D24 to obtain the d01..d24 (but leave all other
155 // bits untouched).
156
157 w = W;
158 if ( w & 0x40000000 ) w ^= 0x3FFFFFC0;
159
160 // Compute the parity of the sign corrected data bits d01..d24
161 // as described in the ICD-GPS-200
162
163 t = w & PARITY_25;
164 p = ( byteParity[t &0xff] ^ byteParity[(t>> 8)&0xff] ^
165 byteParity[(t>>16)&0xff] ^ byteParity[(t>>24) ] );
166
167 t = w & PARITY_26;
168 p = (p<<1) |
169 ( byteParity[t &0xff] ^ byteParity[(t>> 8)&0xff] ^
170 byteParity[(t>>16)&0xff] ^ byteParity[(t>>24) ] );
171
172 t = w & PARITY_27;
173 p = (p<<1) |
174 ( byteParity[t &0xff] ^ byteParity[(t>> 8)&0xff] ^
175 byteParity[(t>>16)&0xff] ^ byteParity[(t>>24) ] );
176
177 t = w & PARITY_28;
178 p = (p<<1) |
179 ( byteParity[t &0xff] ^ byteParity[(t>> 8)&0xff] ^
180 byteParity[(t>>16)&0xff] ^ byteParity[(t>>24) ] );
181
182 t = w & PARITY_29;
183 p = (p<<1) |
184 ( byteParity[t &0xff] ^ byteParity[(t>> 8)&0xff] ^
185 byteParity[(t>>16)&0xff] ^ byteParity[(t>>24) ] );
186
187 t = w & PARITY_30;
188 p = (p<<1) |
189 ( byteParity[t &0xff] ^ byteParity[(t>> 8)&0xff] ^
190 byteParity[(t>>16)&0xff] ^ byteParity[(t>>24) ] );
191
192 return ( (W & 0x3f) == p);
193
194};
195
196
197// Check preamble
198
199bool ThirtyBitWord::isHeader() const {
200
201 const unsigned char Preamble = 0x66;
202
203 unsigned char b = (value()>>22) & 0xFF;
204
205 return ( b==Preamble );
206
207};
208
209
210// Return entire 32-bit (current word and previous parity)
211
212unsigned int ThirtyBitWord::all() const {
213 return W;
214};
215
216
217// Return sign-corrected 30-bit (or zero if parity mismatch)
218
219unsigned int ThirtyBitWord::value() const {
220
221 unsigned int w = W;
222
223 if (validParity()) {
224 // Return data and current parity bits. Invert data bits if D30*
225 // is set and discard old parity bits.
226 if ( w & 0x40000000 ) w ^= 0x3FFFFFC0;
227 return (w & 0x3FFFFFFF);
228 }
229 else {
230 // Error; invalid parity
231 return 0;
232 };
233
234};
235
236
237
238// Append a byte with six data bits
239
240void ThirtyBitWord::append(unsigned char b) {
241
242 // Look up table for swap (left-right) of 6 data bits
243 static const unsigned char
244 swap[] = {
245 0,32,16,48, 8,40,24,56, 4,36,20,52,12,44,28,60,
246 2,34,18,50,10,42,26,58, 6,38,22,54,14,46,30,62,
247 1,33,17,49, 9,41,25,57, 5,37,21,53,13,45,29,61,
248 3,35,19,51,11,43,27,59, 7,39,23,55,15,47,31,63
249 };
250
251 // Bits 7 and 6 (of 0..7) must be "01" for valid data bytes
252 if ( (b & 0x40) != 0x40 ) {
253 failure = true;
254 return;
255 };
256
257 // Swap bits 0..5 to restore proper bit order for 30bit words
258 b = swap[ b & 0x3f];
259
260 // Fill word
261 W = ( (W <<6) | (b & 0x3f) ) ;
262
263};
264
265
266// Get next 30bit word from string
267
268void ThirtyBitWord::get(string& buf) {
269
270 // Check if string is long enough
271
272 if (buf.size()<5) {
273 failure = true;
274 return;
275 };
276
277 // Process 5 bytes and remove them from the input
278
279 for (int i=0; i<5; i++) append(buf[i]);
280 buf.erase(0,5);
281
282#if (DEBUG>0)
283 if (!validParity()) {
284 cerr << "Parity error "
285 << bitset<32>(all()) << endl;
286 };
287#endif
288 failure = false;
289
290};
291
292// Get next 30bit word from file
293
294void ThirtyBitWord::get(istream& inp) {
295
296 unsigned char b;
297
298 for (int i=0; i<5; i++) {
299 inp >> b;
300 if (inp.fail()) { clear(); return; };
301 append(b);
302 };
303
304#if (DEBUG>0)
305 if (!validParity()) {
306 cerr << "Parity error "
307 << bitset<32>(all()) << endl;
308 };
309#endif
310 failure = false;
311
312};
313
314// Get next header word from string
315
316void ThirtyBitWord::getHeader(string& buf) {
317
318 unsigned int W_old = W;
319 unsigned int i;
320
321 i=0;
322 while (!isHeader() || i<5 ) {
323 // Check if string is long enough; if not restore old word and exit
324 if (buf.size()<i+1) {
325 W = W_old;
326 failure = true;
327 return;
328 };
329 // Process byte
330 append(buf[i]); i++;
331 };
332
333 // Remove processed bytes from buffer
334
335 buf.erase(0,i);
336
337#if (DEBUG>0)
338 if (!validParity()) {
339 cerr << "Parity error "
340 << bitset<32>(all()) << endl;
341 };
342#endif
343 failure = false;
344
345};
346
347// Get next header word from file
348
349void ThirtyBitWord::getHeader(istream& inp) {
350
351 unsigned char b;
352 unsigned int i;
353
354 i=0;
355 while ( !isHeader() || i<5 ) {
356 inp >> b;
357 if (inp.fail()) { clear(); return; };
358 append(b); i++;
359 };
360
361#if (DEBUG>0)
362 if (!validParity()) {
363 cerr << "Parity error "
364 << bitset<32>(all()) << endl;
365 };
366#endif
367 failure = false;
368
369};
370
371
372//------------------------------------------------------------------------------
373//
374// RTCM2packet (class implementation)
375//
376// Purpose:
377//
378// A class for handling RTCM2 data packets
379//
380//------------------------------------------------------------------------------
381
382// Constructor
383
384RTCM2packet::RTCM2packet() {
385 clear();
386};
387
388// Initialization
389
390void RTCM2packet::clear() {
391
392 W.clear();
393
394 H1=0;
395 H2=0;
396
397 DW.resize(0,0);
398
399};
400
401// Complete packet, valid parity
402
403bool RTCM2packet::valid() const {
404
405 // The methods for creating a packet (get,">>") ensure
406 // that a packet has a consistent number of data words
407 // and a valid parity in all header and data words.
408 // Therefore a packet is either empty or valid.
409
410 return (H1!=0);
411
412};
413
414
415//
416// Gets the next packet from the buffer
417//
418
419void RTCM2packet::getPacket(std::string& buf) {
420
421 int n;
422 ThirtyBitWord W_old = W;
423 string buf_old = buf;
424
425 // Try to read a full packet. If the input buffer is too short
426 // clear all data and restore the latest 30-bit word prior to
427 // the getPacket call. The empty header word will indicate
428 // an invalid message, which signals an unsuccessful getPacket()
429 // call.
430
431 W.getHeader(buf);
432 H1 = W.value();
433 if (W.fail()) { clear(); W=W_old; buf=buf_old; return; };
434 if (!W.validParity()) { clear(); return; };
435
436 W.get(buf);
437 H2 = W.value();
438 if (W.fail()) { clear(); W=W_old; buf=buf_old; return; };
439 if (!W.validParity()) { clear(); return; };
440
441 n = nDataWords();
442 DW.resize(n);
443 for (int i=0; i<n; i++) {
444 W.get(buf);
445 DW[i] = W.value();
446 if (W.fail()) { clear(); W=W_old; buf=buf_old; return; };
447 if (!W.validParity()) { clear(); return; };
448 };
449
450 return;
451
452};
453
454
455//
456// Gets the next packet from the input stream
457//
458
459void RTCM2packet::getPacket(std::istream& inp) {
460
461 int n;
462
463 W.getHeader(inp);
464 H1 = W.value();
465 if (W.fail() || !W.validParity()) { clear(); return; }
466
467 W.get(inp);
468 H2 = W.value();
469 if (W.fail() || !W.validParity()) { clear(); return; }
470
471 n = nDataWords();
472 DW.resize(n);
473 for (int i=0; i<n; i++) {
474 W.get(inp);
475 DW[i] = W.value();
476 if (W.fail() || !W.validParity()) { clear(); return; }
477 };
478
479 return;
480
481};
482
483//
484// Input operator
485//
486// Reads an RTCM2 packet from the input stream.
487//
488
489istream& operator >> (istream& is, RTCM2packet& p) {
490
491 p.getPacket(is);
492
493 return is;
494
495};
496
497// Access methods
498
499unsigned int RTCM2packet::header1() const {
500 return H1;
501};
502
503unsigned int RTCM2packet::header2() const {
504 return H2;
505};
506
507unsigned int RTCM2packet::dataWord(int i) const {
508 if ( (unsigned int)i < DW.size() ) {
509 return DW[i];
510 }
511 else {
512 return 0;
513 }
514};
515
516unsigned int RTCM2packet::msgType() const {
517 return ( H1>>16 & 0x003F );
518};
519
520unsigned int RTCM2packet::stationID() const {
521 return ( H1>> 6 & 0x03FF );
522};
523
524unsigned int RTCM2packet::modZCount() const {
525 return ( H2>>17 & 0x01FFF );
526};
527
528unsigned int RTCM2packet::seqNumber() const {
529 return ( H2>>14 & 0x0007 );
530};
531
532unsigned int RTCM2packet::nDataWords() const {
533 return ( H2>> 9 & 0x001F );
534};
535
536unsigned int RTCM2packet::staHealth() const {
537 return ( H2>> 6 & 0x0003 );
538};
539
540
541//
542// Get unsigned bit field
543//
544// Bits are numbered from left (msb) to right (lsb) starting at bit 0
545//
546
547unsigned int RTCM2packet::getUnsignedBits ( unsigned int start,
548 unsigned int n ) const {
549
550 unsigned int iFirst = start/24; // Index of first data word
551 unsigned int iLast = (start+n-1)/24; // Index of last data word
552 unsigned int bitField = 0;
553 unsigned int tmp;
554
555 // Checks
556
557 if (n>32) {
558 throw("Error: can't handle >32 bits in RTCM2packet::getUnsignedBits");
559 };
560
561 if ( 24*DW.size() < start+n-1 ) {
562#if (DEBUG>0)
563 cerr << "Debug output RTCM2packet::getUnsignedBits" << endl
564 << " P.msgType: " << setw(5) << msgType() << endl
565 << " P.nDataWords: " << setw(5) << nDataWords() << endl
566 << " start: " << setw(5) << start << endl
567 << " n: " << setw(5) << n << endl
568 << " P.H1: " << setw(5) << bitset<32>(H1) << endl
569 << " P.H2: " << setw(5) << bitset<32>(H2) << endl
570 << endl
571 << flush;
572#endif
573 throw("Error: Packet too short in RTCM2packet::getUnsignedBits");
574 }
575
576 // Handle initial data word
577 // Get all data bits. Strip parity and unwanted leading bits.
578 // Store result in 24 lsb bits of tmp.
579
580 tmp = (DW[iFirst]>>6) & 0xFFFFFF;
581 tmp = ( ( tmp << start%24) & 0xFFFFFF ) >> start%24 ;
582
583 // Handle central data word
584
585 if ( iFirst<iLast ) {
586 bitField = tmp;
587 for (unsigned int iWord=iFirst+1; iWord<iLast; iWord++) {
588 tmp = (DW[iWord]>>6) & 0xFFFFFF;
589 bitField = (bitField << 24) | tmp;
590 };
591 tmp = (DW[iLast]>>6) & 0xFFFFFF;
592 };
593
594 // Handle last data word
595
596 tmp = tmp >> (23-(start+n-1)%24);
597 bitField = (bitField << ((start+n-1)%24+1)) | tmp;
598
599 // Done
600
601 return bitField;
602
603};
604
605//
606// Get signed bit field
607//
608// Bits are numbered from left (msb) to right (lsb) starting at bit 0
609//
610
611int RTCM2packet::getBits ( unsigned int start,
612 unsigned int n ) const {
613
614
615 // Checks
616
617 if (n>32) {
618 throw("Error: can't handle >32 bits in RTCM2packet::getBits");
619 };
620
621 if ( 24*DW.size() < start+n-1 ) {
622#if (DEBUG>0)
623 cerr << "Debug output RTCM2packet::getUnsignedBits" << endl
624 << " P.msgType: " << setw(5) << msgType() << endl
625 << " P.nDataWords: " << setw(5) << nDataWords() << endl
626 << " start: " << setw(5) << start << endl
627 << " n: " << setw(5) << n << endl
628 << " P.H1: " << setw(5) << bitset<32>(H1) << endl
629 << " P.H2: " << setw(5) << bitset<32>(H2) << endl
630 << endl
631 << flush;
632#endif
633 throw("Error: Packet too short in RTCM2packet::getBits");
634 }
635
636 return ((int)(getUnsignedBits(start,n)<<(32-n))>>(32-n));
637
638};
639
640
641//------------------------------------------------------------------------------
642//
643// RTCM2_03 (class implementation)
644//
645// Purpose:
646//
647// A class for handling RTCM 2 GPS Reference Station Parameters messages
648//
649//------------------------------------------------------------------------------
650
651void RTCM2_03::extract(const RTCM2packet& P) {
652
653 // Check validity and packet type
654
655 validMsg = (P.valid());
656 if (!validMsg) return;
657
658 validMsg = (P.ID()==03);
659 if (!validMsg) return;
660
661 // Antenna reference point coordinates
662
663 x = P.getBits( 0,32)*0.01; // X [m]
664 y = P.getBits(32,32)*0.01; // Y [m]
665 z = P.getBits(64,32)*0.01; // Z [m]
666
667};
668
669//------------------------------------------------------------------------------
670//
671// RTCM2_23 (class implementation)
672//
673// Purpose:
674//
675// A class for handling RTCM 2 Antenna Type Definition messages
676//
677//------------------------------------------------------------------------------
678
679void RTCM2_23::extract(const RTCM2packet& P) {
680
681 int nad, nas;
682
683 // Check validity and packet type
684
685 validMsg = (P.valid());
686 if (!validMsg) return;
687
688 validMsg = (P.ID()==23);
689 if (!validMsg) return;
690
691 // Antenna descriptor
692 antType = "";
693 nad = P.getUnsignedBits(3,5);
694 for (int i=0;i<nad;i++)
695 antType += (char)P.getUnsignedBits(8+i*8,8);
696
697 // Optional antenna serial numbers
698 if (P.getUnsignedBits(2,1)==1) {
699 nas = P.getUnsignedBits(19+8*nad,5);
700 antSN = "";
701 for (int i=0;i<nas;i++)
702 antSN += (char)P.getUnsignedBits(24+8*nas+i*8,8);
703 };
704
705};
706
707
708//------------------------------------------------------------------------------
709//
710// RTCM2_24 (class implementation)
711//
712// Purpose:
713//
714// A class for handling RTCM 2 Reference Station Antenna
715// Reference Point Parameter messages
716//
717//------------------------------------------------------------------------------
718
719void RTCM2_24::extract(const RTCM2packet& P) {
720
721 double dx,dy,dz;
722
723 // Check validity and packet type
724
725 validMsg = (P.valid());
726 if (!validMsg) return;
727
728 validMsg = (P.ID()==24);
729 if (!validMsg) return;
730
731 // System indicator
732
733 isGPS = (P.getUnsignedBits(118,1)==0);
734 isGLONASS = (P.getUnsignedBits(118,1)==1);
735
736 // Antenna reference point coordinates
737
738 x = 64.0*P.getBits( 0,32);
739 y = 64.0*P.getBits(40,32);
740 z = 64.0*P.getBits(80,32);
741 dx = P.getUnsignedBits( 32,6);
742 dy = P.getUnsignedBits( 72,6);
743 dz = P.getUnsignedBits(112,6);
744 x = 0.0001*( x + (x<0? -dx:+dx) );
745 y = 0.0001*( y + (y<0? -dy:+dy) );
746 z = 0.0001*( z + (z<0? -dz:+dz) );
747
748 // Antenna Height
749
750 if (P.getUnsignedBits(119,1)==1) {
751 h= P.getUnsignedBits(120,18)*0.0001;
752 };
753
754
755};
756
757
758//------------------------------------------------------------------------------
759//
760// RTCM2_Obs (class definition)
761//
762// Purpose:
763//
764// A class for handling blocks of RTCM2 18 & 19 packets that need to be
765// combined to get a complete set of measurements
766//
767// Notes:
768//
769// The class collects L1/L2 code and phase measurements for GPS and GLONASS.
770// Since the Multiple Message Indicator is inconsistently handled by various
771// receivers we simply require code and phase on L1 and L2 for a complete
772// set ob observations at a given epoch. GLONASS observations are optional,
773// but all four types (code+phase,L1+L2) must be provided, if at least one
774// is given. Also, the GLONASS message must follow the corresponding GPS
775// message.
776//
777//------------------------------------------------------------------------------
778
779// Constructor
780
781RTCM2_Obs::RTCM2_Obs() {
782
783 clear();
784 GPSonly = true;
785
786};
787
788// Reset entire block
789
790void RTCM2_Obs::clear() {
791
792 secs=0.0; // Seconds of hour (GPS time)
793 nSat=0; // Number of space vehicles
794 PRN.resize(0); // Pseudorange [m]
795 rng_C1.resize(0); // Pseudorange [m]
796 rng_P1.resize(0); // Pseudorange [m]
797 rng_P2.resize(0); // Pseudorange [m]
798 cph_L1.resize(0); // Carrier phase [m]
799 cph_L2.resize(0); // Carrier phase [m]
800
801 availability.reset(); // Message status flags
802
803};
804
805// Availability checks
806
807bool RTCM2_Obs::anyGPS() const {
808
809 return availability.test(bit_L1rngGPS) ||
810 availability.test(bit_L2rngGPS) ||
811 availability.test(bit_L1cphGPS) ||
812 availability.test(bit_L2cphGPS);
813
814};
815
816bool RTCM2_Obs::anyGLONASS() const {
817
818 return availability.test(bit_L1rngGLO) ||
819 availability.test(bit_L2rngGLO) ||
820 availability.test(bit_L1cphGLO) ||
821 availability.test(bit_L2cphGLO);
822
823};
824
825bool RTCM2_Obs::allGPS() const {
826
827 return availability.test(bit_L1rngGPS) &&
828 availability.test(bit_L2rngGPS) &&
829 availability.test(bit_L1cphGPS) &&
830 availability.test(bit_L2cphGPS);
831
832};
833
834bool RTCM2_Obs::allGLONASS() const {
835
836 return availability.test(bit_L1rngGLO) &&
837 availability.test(bit_L2rngGLO) &&
838 availability.test(bit_L1cphGLO) &&
839 availability.test(bit_L2cphGLO);
840
841};
842
843// Validity
844
845bool RTCM2_Obs::valid() const {
846
847 return ( allGPS() && ( GPSonly || allGLONASS() ) );
848
849};
850
851
852//
853// Extract RTCM2 18 & 19 messages and store relevant data for future use
854//
855
856void RTCM2_Obs::extract(const RTCM2packet& P) {
857
858 bool isGPS,isCAcode,isL1,isOth;
859 int NSat,idx;
860 int sid,prn;
861 double t,rng,cph;
862
863 // Check validity and packet type
864
865 if ( ! ( P.valid() &&
866 (P.ID()==18 || P.ID()==19) &&
867 P.nDataWords()>1 ) ) return;
868
869 // Clear previous data if block was already complete
870
871 if (valid()) clear();
872
873 // Process carrier phase message
874
875 if ( P.ID()==18 ) {
876
877 // Number of satellites in current message
878 NSat = (P.nDataWords()-1)/2;
879
880 // Current epoch (mod 3600 sec)
881 t = 0.6*P.modZCount()
882 + P.getUnsignedBits(4,20)*1.0e-6;
883 // SC-104 V2.3 4-42 Note 1 4. Assume measurements at hard edges
884 // of receiver clock with minimum divisions of 10ms
885 // and clock error less then recommended 1.1ms
886 // Hence, round time tag to 100 ms
887 t = floor(t*100.+0.5)/100.;
888
889 // Frequency (exit if neither L1 nor L2)
890 isL1 = ( P.getUnsignedBits(0,1)==0 );
891 isOth = ( P.getUnsignedBits(1,1)==1 );
892 if (isOth) return;
893
894 // Constellation (for first satellite in message)
895 isGPS = ( P.getUnsignedBits(26,1)==0 );
896 GPSonly = GPSonly && isGPS;
897
898 // Multiple Message Indicator (only checked for first satellite)
899 // pendingMsg = ( P.getUnsignedBits(24,1)==1 );
900
901 // Handle epoch: store epoch of first GPS message and
902 // check consistency of subsequent messages. GLONASS time tags
903 // are different and have to be ignored
904 if (isGPS) {
905 if ( nSat==0 ) {
906 secs = t; // Store epoch
907 }
908 else if (t!=secs) {
909 clear(); secs = t; // Clear all data, then store epoch
910 };
911 };
912
913 // Discard GLONASS observations if no prior GPS observations
914 // are available
915 if (!isGPS && !anyGPS() ) return;
916
917 // Set availability flags
918
919 if ( isL1 && isGPS) availability.set(bit_L1cphGPS);
920 if (!isL1 && isGPS) availability.set(bit_L2cphGPS);
921 if ( isL1 && !isGPS) availability.set(bit_L1cphGLO);
922 if (!isL1 && !isGPS) availability.set(bit_L2cphGLO);
923
924 // Process all satellites
925
926 for (int iSat=0;iSat<NSat;iSat++){
927
928 // Code type
929 isCAcode = ( P.getUnsignedBits(iSat*48+25,1)==0 );
930
931 // Satellite
932 sid = P.getUnsignedBits(iSat*48+27,5);
933 prn = (isGPS? sid : sid+200 );
934
935 // Carrier phase measurement (mod 2^23 [cy]; sign matched to range)
936 cph = -P.getBits(iSat*48+40,32)/256.0;
937
938 // Is this a new PRN?
939 idx=-1;
940 for (unsigned int i=0;i<PRN.size();i++) {
941 if (PRN[i]==prn) { idx=i; break; };
942 };
943 if (idx==-1) {
944 // Insert new sat at end of list
945 nSat++; idx = nSat-1;
946 PRN.push_back(prn);
947 rng_C1.push_back(0.0);
948 rng_P1.push_back(0.0);
949 rng_P2.push_back(0.0);
950 cph_L1.push_back(0.0);
951 cph_L2.push_back(0.0);
952 };
953
954 // Store measurement
955 if (isL1) {
956 cph_L1[idx] = cph;
957 }
958 else {
959 cph_L2[idx] = cph;
960 };
961
962 };
963
964 };
965
966
967 // Process pseudorange message
968
969 if ( P.ID()==19 ) {
970
971 // Number of satellites in current message
972 NSat = (P.nDataWords()-1)/2;
973
974 // Current epoch (mod 3600 sec)
975 t = 0.6*P.modZCount()
976 + P.getUnsignedBits(4,20)*1.0e-6;
977 // SC-104 V2.3 4-42 Note 1 4. Assume measurements at hard edges
978 // of receiver clock with minimum divisions of 10ms
979 // and clock error less then recommended 1.1ms
980 // Hence, round time tag to 100 ms
981 t = floor(t*100.+0.5)/100.;
982
983 // Frequency (exit if neither L1 nor L2)
984 isL1 = ( P.getUnsignedBits(0,1)==0 );
985 isOth = ( P.getUnsignedBits(1,1)==1 );
986 if (isOth) return;
987
988 // Constellation (for first satellite in message)
989 isGPS = ( P.getUnsignedBits(26,1)==0 );
990 GPSonly = GPSonly && isGPS;
991
992 // Multiple Message Indicator (only checked for first satellite)
993 // pendingMsg = ( P.getUnsignedBits(24,1)==1 );
994
995 // Handle epoch: store epoch of first GPS message and
996 // check consistency of subsequent messages. GLONASS time tags
997 // are different and have to be ignored
998 if (isGPS) {
999 if ( nSat==0 ) {
1000 secs = t; // Store epoch
1001 }
1002 else if (t!=secs) {
1003 clear(); secs = t; // Clear all data, then store epoch
1004 };
1005 };
1006
1007 // Discard GLONASS observations if no prior GPS observations
1008 // are available
1009 if (!isGPS && !anyGPS() ) return;
1010
1011 // Set availability flags
1012 if ( isL1 && isGPS) availability.set(bit_L1rngGPS);
1013 if (!isL1 && isGPS) availability.set(bit_L2rngGPS);
1014 if ( isL1 && !isGPS) availability.set(bit_L1rngGLO);
1015 if (!isL1 && !isGPS) availability.set(bit_L2rngGLO);
1016
1017 // Process all satellites
1018
1019 for (int iSat=0;iSat<NSat;iSat++){
1020
1021 // Code type
1022 isCAcode = ( P.getUnsignedBits(iSat*48+25,1)==0 );
1023
1024 // Satellite
1025 sid = P.getUnsignedBits(iSat*48+27,5);
1026 prn = (isGPS? sid : sid+200 );
1027
1028 // Pseudorange measurement [m]
1029 rng = P.getUnsignedBits(iSat*48+40,32)*0.02;
1030
1031 // Is this a new PRN?
1032 idx=-1;
1033 for (unsigned int i=0;i<PRN.size();i++) {
1034 if (PRN[i]==prn) { idx=i; break; };
1035 };
1036 if (idx==-1) {
1037 // Insert new sat at end of list
1038 nSat++; idx = nSat-1;
1039 PRN.push_back(prn);
1040 rng_C1.push_back(0.0);
1041 rng_P1.push_back(0.0);
1042 rng_P2.push_back(0.0);
1043 cph_L1.push_back(0.0);
1044 cph_L2.push_back(0.0);
1045 };
1046
1047 // Store measurement
1048 if (isL1) {
1049 if (isCAcode) {
1050 rng_C1[idx] = rng;
1051 } else {
1052 rng_P1[idx] = rng;
1053 } }
1054 else {
1055 rng_P2[idx] = rng;
1056 };
1057
1058 };
1059
1060 };
1061
1062};
1063
1064//
1065// Resolution of 2^24 cy carrier phase ambiguity
1066// caused by 32-bit data field restrictions
1067//
1068// Note: the RTCM standard specifies an ambiguity of +/-2^23 cy.
1069// However, numerous receivers generate data in the +/-2^22 cy range.
1070// A reduced ambiguity of 2^23 cy appears compatible with both cases.
1071//
1072
1073double RTCM2_Obs::resolvedPhase_L1(int i) const {
1074
1075//const double ambig = pow(2.0,24); // as per RTCM2 spec
1076 const double ambig = pow(2.0,23); // used by many receivers
1077
1078 double rng;
1079 double n;
1080
1081 if (!valid() || i<0 || i>nSat-1) return 0.0;
1082
1083 rng = rng_C1[i];
1084 if (rng==0.0) rng = rng_P1[i];
1085 if (rng==0.0) return 0.0;
1086
1087 n = floor( (rng/lambda_L1-cph_L1[i]) / ambig + 0.5 );
1088
1089 return cph_L1[i] + n*ambig;
1090
1091};
1092
1093double RTCM2_Obs::resolvedPhase_L2(int i) const {
1094
1095//const double ambig = pow(2.0,24); // as per RTCM2 spec
1096 const double ambig = pow(2.0,23); // used by many receivers
1097
1098 double rng;
1099 double n;
1100
1101 if (!valid() || i<0 || i>nSat-1) return 0.0;
1102
1103 rng = rng_C1[i];
1104 if (rng==0.0) rng = rng_P1[i];
1105 if (rng==0.0) return 0.0;
1106
1107 n = floor( (rng/lambda_L2-cph_L2[i]) / ambig + 0.5 );
1108
1109 return cph_L2[i] + n*ambig;
1110
1111};
1112
1113//
1114// Resolution of epoch using reference date (GPS week and secs)
1115//
1116
1117void RTCM2_Obs::resolveEpoch (int refWeek, double refSecs,
1118 int& epochWeek, double& epochSecs ) const {
1119
1120 const double secsPerWeek = 604800.0;
1121
1122 epochWeek = refWeek;
1123 epochSecs = secs + 3600.0*(floor((refSecs-secs)/3600.0+0.5));
1124
1125 if (epochSecs<0 ) { epochWeek--; epochSecs+=secsPerWeek; };
1126 if (epochSecs>secsPerWeek) { epochWeek++; epochSecs-=secsPerWeek; };
1127
1128};
1129
1130}; // End of namespace rtcm2
Note: See TracBrowser for help on using the repository browser.