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

Last change on this file since 706 was 706, checked in by weber, 16 years ago

* empty log message *

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