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

Last change on this file since 253 was 253, checked in by mervart, 18 years ago

* empty log message *

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