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

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

* empty log message *

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