gnss-js 1.39.0 → 1.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-U47XUQAT.js → chunk-EPATQ3LT.js} +137 -55
- package/dist/index.cjs +137 -59
- package/dist/index.js +1 -1
- package/dist/trimble.cjs +220 -55
- package/dist/trimble.d.cts +20 -14
- package/dist/trimble.d.ts +20 -14
- package/dist/trimble.js +3 -1
- package/package.json +1 -1
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getGpsLeap
|
|
3
|
+
} from "./chunk-HVXYFUCB.js";
|
|
4
|
+
|
|
1
5
|
// src/trimble/frame.ts
|
|
2
6
|
var STX = 2;
|
|
3
7
|
var ETX = 3;
|
|
@@ -40,68 +44,139 @@ function* trimbleFrames(data, stats) {
|
|
|
40
44
|
|
|
41
45
|
// src/trimble/nav.ts
|
|
42
46
|
var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
|
|
47
|
+
var BDT_EPOCH_MS = Date.UTC(2006, 0, 1);
|
|
43
48
|
var SEC_PER_WEEK = 7 * 86400;
|
|
44
49
|
var MS_PER_WEEK = SEC_PER_WEEK * 1e3;
|
|
45
50
|
var GPS_PI = 3.1415926535898;
|
|
51
|
+
var BDS_WEEK_OFFSET = 1356;
|
|
52
|
+
var BDS_LEAP_SEC = 14;
|
|
46
53
|
var gpsMs = (week, sec) => GPS_EPOCH_MS + week * MS_PER_WEEK + sec * 1e3;
|
|
47
54
|
var sowOf = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK;
|
|
48
55
|
var SUB_GPS_EPHEMERIS = 1;
|
|
49
56
|
var SUB_ION_UTC = 3;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
57
|
+
var SUB_GLO_EPHEMERIS = 9;
|
|
58
|
+
var SUB_BDS_EPHEMERIS = 21;
|
|
59
|
+
function readKepler(view, base) {
|
|
60
|
+
return {
|
|
61
|
+
svid: view.getUint8(base + 5),
|
|
62
|
+
week: view.getUint16(base + 6, false),
|
|
63
|
+
iode: view.getUint8(base + 11),
|
|
64
|
+
tocSec: view.getInt32(base + 16, false),
|
|
65
|
+
toeSec: view.getUint32(base + 20, false),
|
|
66
|
+
tgd: view.getFloat64(base + 24, false),
|
|
67
|
+
af2: view.getFloat64(base + 32, false),
|
|
68
|
+
af1: view.getFloat64(base + 40, false),
|
|
69
|
+
af0: view.getFloat64(base + 48, false),
|
|
70
|
+
crs: view.getFloat64(base + 56, false),
|
|
71
|
+
deltaN: view.getFloat64(base + 64, false) * GPS_PI,
|
|
72
|
+
m0: view.getFloat64(base + 72, false) * GPS_PI,
|
|
73
|
+
cuc: view.getFloat64(base + 80, false) * GPS_PI,
|
|
74
|
+
e: view.getFloat64(base + 88, false),
|
|
75
|
+
cus: view.getFloat64(base + 96, false) * GPS_PI,
|
|
76
|
+
sqrtA: view.getFloat64(base + 104, false),
|
|
77
|
+
cic: view.getFloat64(base + 112, false) * GPS_PI,
|
|
78
|
+
omega0: view.getFloat64(base + 120, false) * GPS_PI,
|
|
79
|
+
cis: view.getFloat64(base + 128, false) * GPS_PI,
|
|
80
|
+
i0: view.getFloat64(base + 136, false) * GPS_PI,
|
|
81
|
+
crc: view.getFloat64(base + 144, false),
|
|
82
|
+
omega: view.getFloat64(base + 152, false) * GPS_PI,
|
|
83
|
+
omegaDot: view.getFloat64(base + 160, false) * GPS_PI,
|
|
84
|
+
idot: view.getFloat64(base + 168, false) * GPS_PI,
|
|
85
|
+
flags: view.getUint32(base + 176, false)
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function keplerCommon(r) {
|
|
89
|
+
return {
|
|
90
|
+
af0: r.af0,
|
|
91
|
+
af1: r.af1,
|
|
92
|
+
af2: r.af2,
|
|
93
|
+
iode: r.iode,
|
|
94
|
+
crs: r.crs,
|
|
95
|
+
deltaN: r.deltaN,
|
|
96
|
+
m0: r.m0,
|
|
97
|
+
cuc: r.cuc,
|
|
98
|
+
e: r.e,
|
|
99
|
+
cus: r.cus,
|
|
100
|
+
sqrtA: r.sqrtA,
|
|
101
|
+
cic: r.cic,
|
|
102
|
+
omega0: r.omega0,
|
|
103
|
+
cis: r.cis,
|
|
104
|
+
i0: r.i0,
|
|
105
|
+
crc: r.crc,
|
|
106
|
+
omega: r.omega,
|
|
107
|
+
omegaDot: r.omegaDot,
|
|
108
|
+
idot: r.idot,
|
|
109
|
+
tgd: r.tgd
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function decodeGpsEphemeris(view, base) {
|
|
113
|
+
const r = readKepler(view, base);
|
|
114
|
+
if (r.svid < 1 || r.svid > 32) return null;
|
|
115
|
+
const tocMs = gpsMs(r.week, r.tocSec);
|
|
77
116
|
return {
|
|
78
117
|
system: "G",
|
|
79
|
-
prn: `G${String(
|
|
80
|
-
toc: sowOf(
|
|
81
|
-
tocDate: new Date(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
118
|
+
prn: `G${String(r.svid).padStart(2, "0")}`,
|
|
119
|
+
toc: sowOf(tocMs),
|
|
120
|
+
tocDate: new Date(tocMs),
|
|
121
|
+
toe: r.toeSec,
|
|
122
|
+
week: r.week,
|
|
123
|
+
svHealth: r.flags >>> 4 & 127,
|
|
124
|
+
...keplerCommon(r)
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function decodeBdsEphemeris(view, base) {
|
|
128
|
+
const r = readKepler(view, base);
|
|
129
|
+
if (r.svid < 1 || r.svid > 63) return null;
|
|
130
|
+
const bdsWeek = r.week - BDS_WEEK_OFFSET;
|
|
131
|
+
const tocSec = r.tocSec - BDS_LEAP_SEC;
|
|
132
|
+
const toeSec = r.toeSec - BDS_LEAP_SEC;
|
|
133
|
+
const tocDate = new Date(
|
|
134
|
+
BDT_EPOCH_MS + bdsWeek * MS_PER_WEEK + tocSec * 1e3
|
|
135
|
+
);
|
|
136
|
+
return {
|
|
137
|
+
system: "C",
|
|
138
|
+
prn: `C${String(r.svid).padStart(2, "0")}`,
|
|
139
|
+
toc: sowOf(tocDate.getTime()),
|
|
140
|
+
tocDate,
|
|
141
|
+
toe: toeSec,
|
|
142
|
+
week: bdsWeek,
|
|
143
|
+
// Health from the same flags nibble as GPS (0 = healthy for the observed
|
|
144
|
+
// operational BeiDou sats); flags bit 0 is a set-on-all format marker,
|
|
145
|
+
// not SatH1, so it must not be used here.
|
|
146
|
+
svHealth: r.flags >>> 4 & 127,
|
|
147
|
+
...keplerCommon(r)
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function decodeGloEphemeris(view, base) {
|
|
151
|
+
const slot = view.getUint8(base + 5);
|
|
152
|
+
if (slot < 1 || slot > 24) return null;
|
|
153
|
+
const week = view.getUint16(base + 6, false);
|
|
154
|
+
const tow = view.getUint32(base + 8, false);
|
|
155
|
+
const gpsTimeMs = gpsMs(week, tow);
|
|
156
|
+
const leapMs = getGpsLeap(new Date(gpsTimeMs)) * 1e3;
|
|
157
|
+
const tocMs = gpsTimeMs - leapMs;
|
|
158
|
+
return {
|
|
159
|
+
system: "R",
|
|
160
|
+
prn: `R${String(slot).padStart(2, "0")}`,
|
|
161
|
+
tocDate: new Date(tocMs),
|
|
162
|
+
// RINEX stores −τn as the clock bias; the record carries τn (ICD sign).
|
|
163
|
+
tauN: -view.getFloat64(base + 113, false),
|
|
164
|
+
gammaN: view.getFloat64(base + 121, false),
|
|
165
|
+
messageFrameTime: (tocMs - GPS_EPOCH_MS) / 1e3 % SEC_PER_WEEK,
|
|
166
|
+
// State vector: metres / m·s⁻¹ / m·s⁻² → km / km·s⁻¹ / km·s⁻².
|
|
167
|
+
x: view.getFloat64(base + 33, false) / 1e3,
|
|
168
|
+
xDot: view.getFloat64(base + 41, false) / 1e3,
|
|
169
|
+
xAcc: view.getFloat64(base + 49, false) / 1e3,
|
|
170
|
+
y: view.getFloat64(base + 57, false) / 1e3,
|
|
171
|
+
yDot: view.getFloat64(base + 65, false) / 1e3,
|
|
172
|
+
yAcc: view.getFloat64(base + 73, false) / 1e3,
|
|
173
|
+
z: view.getFloat64(base + 81, false) / 1e3,
|
|
174
|
+
zDot: view.getFloat64(base + 89, false) / 1e3,
|
|
175
|
+
zAcc: view.getFloat64(base + 97, false) / 1e3,
|
|
176
|
+
health: 0,
|
|
177
|
+
// Bn health bit not located; observed sats are operational
|
|
178
|
+
freqNum: view.getInt8(base + 29)
|
|
179
|
+
// FCN, signed byte (−7…+6)
|
|
105
180
|
};
|
|
106
181
|
}
|
|
107
182
|
function parseTrimbleNav(data) {
|
|
@@ -116,8 +191,8 @@ function parseTrimbleNav(data) {
|
|
|
116
191
|
if (f.type !== RETSVDATA) continue;
|
|
117
192
|
const sub = data[f.payload];
|
|
118
193
|
retsvCounts[sub] = (retsvCounts[sub] ?? 0) + 1;
|
|
119
|
-
if (sub === SUB_GPS_EPHEMERIS && f.len >= 176) {
|
|
120
|
-
const eph = decodeGpsEphemeris(
|
|
194
|
+
if ((sub === SUB_GPS_EPHEMERIS || sub === SUB_BDS_EPHEMERIS) && f.len >= 176) {
|
|
195
|
+
const eph = sub === SUB_GPS_EPHEMERIS ? decodeGpsEphemeris(view, f.start) : decodeBdsEphemeris(view, f.start);
|
|
121
196
|
if (!eph) continue;
|
|
122
197
|
if (lastIode.get(eph.prn) === eph.iode) continue;
|
|
123
198
|
lastIode.set(eph.prn, eph.iode);
|
|
@@ -133,6 +208,13 @@ function parseTrimbleNav(data) {
|
|
|
133
208
|
ionoCorrections["GPSA"] = alpha;
|
|
134
209
|
ionoCorrections["GPSB"] = beta;
|
|
135
210
|
leapSeconds = Math.trunc(view.getFloat64(p + 94, false));
|
|
211
|
+
} else if (sub === SUB_GLO_EPHEMERIS && f.len >= 125) {
|
|
212
|
+
const eph = decodeGloEphemeris(view, f.start);
|
|
213
|
+
if (!eph) continue;
|
|
214
|
+
const key = eph.tocDate.getTime();
|
|
215
|
+
if (lastIode.get(eph.prn) === key) continue;
|
|
216
|
+
lastIode.set(eph.prn, key);
|
|
217
|
+
ephemerides.push(eph);
|
|
136
218
|
}
|
|
137
219
|
}
|
|
138
220
|
return {
|
package/dist/index.cjs
CHANGED
|
@@ -9590,68 +9590,139 @@ function* trimbleFrames(data, stats) {
|
|
|
9590
9590
|
|
|
9591
9591
|
// src/trimble/nav.ts
|
|
9592
9592
|
var GPS_EPOCH_MS14 = Date.UTC(1980, 0, 6);
|
|
9593
|
+
var BDT_EPOCH_MS4 = Date.UTC(2006, 0, 1);
|
|
9593
9594
|
var SEC_PER_WEEK10 = 7 * 86400;
|
|
9594
9595
|
var MS_PER_WEEK9 = SEC_PER_WEEK10 * 1e3;
|
|
9595
9596
|
var GPS_PI2 = 3.1415926535898;
|
|
9597
|
+
var BDS_WEEK_OFFSET = 1356;
|
|
9598
|
+
var BDS_LEAP_SEC = 14;
|
|
9596
9599
|
var gpsMs3 = (week, sec) => GPS_EPOCH_MS14 + week * MS_PER_WEEK9 + sec * 1e3;
|
|
9597
9600
|
var sowOf4 = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK10;
|
|
9598
9601
|
var SUB_GPS_EPHEMERIS = 1;
|
|
9599
9602
|
var SUB_ION_UTC = 3;
|
|
9600
|
-
|
|
9601
|
-
|
|
9602
|
-
|
|
9603
|
-
|
|
9604
|
-
|
|
9605
|
-
|
|
9606
|
-
|
|
9607
|
-
|
|
9608
|
-
|
|
9609
|
-
|
|
9610
|
-
|
|
9611
|
-
|
|
9612
|
-
|
|
9613
|
-
|
|
9614
|
-
|
|
9615
|
-
|
|
9616
|
-
|
|
9617
|
-
|
|
9618
|
-
|
|
9619
|
-
|
|
9620
|
-
|
|
9621
|
-
|
|
9622
|
-
|
|
9623
|
-
|
|
9624
|
-
|
|
9625
|
-
|
|
9626
|
-
|
|
9603
|
+
var SUB_GLO_EPHEMERIS = 9;
|
|
9604
|
+
var SUB_BDS_EPHEMERIS = 21;
|
|
9605
|
+
function readKepler(view, base) {
|
|
9606
|
+
return {
|
|
9607
|
+
svid: view.getUint8(base + 5),
|
|
9608
|
+
week: view.getUint16(base + 6, false),
|
|
9609
|
+
iode: view.getUint8(base + 11),
|
|
9610
|
+
tocSec: view.getInt32(base + 16, false),
|
|
9611
|
+
toeSec: view.getUint32(base + 20, false),
|
|
9612
|
+
tgd: view.getFloat64(base + 24, false),
|
|
9613
|
+
af2: view.getFloat64(base + 32, false),
|
|
9614
|
+
af1: view.getFloat64(base + 40, false),
|
|
9615
|
+
af0: view.getFloat64(base + 48, false),
|
|
9616
|
+
crs: view.getFloat64(base + 56, false),
|
|
9617
|
+
deltaN: view.getFloat64(base + 64, false) * GPS_PI2,
|
|
9618
|
+
m0: view.getFloat64(base + 72, false) * GPS_PI2,
|
|
9619
|
+
cuc: view.getFloat64(base + 80, false) * GPS_PI2,
|
|
9620
|
+
e: view.getFloat64(base + 88, false),
|
|
9621
|
+
cus: view.getFloat64(base + 96, false) * GPS_PI2,
|
|
9622
|
+
sqrtA: view.getFloat64(base + 104, false),
|
|
9623
|
+
cic: view.getFloat64(base + 112, false) * GPS_PI2,
|
|
9624
|
+
omega0: view.getFloat64(base + 120, false) * GPS_PI2,
|
|
9625
|
+
cis: view.getFloat64(base + 128, false) * GPS_PI2,
|
|
9626
|
+
i0: view.getFloat64(base + 136, false) * GPS_PI2,
|
|
9627
|
+
crc: view.getFloat64(base + 144, false),
|
|
9628
|
+
omega: view.getFloat64(base + 152, false) * GPS_PI2,
|
|
9629
|
+
omegaDot: view.getFloat64(base + 160, false) * GPS_PI2,
|
|
9630
|
+
idot: view.getFloat64(base + 168, false) * GPS_PI2,
|
|
9631
|
+
flags: view.getUint32(base + 176, false)
|
|
9632
|
+
};
|
|
9633
|
+
}
|
|
9634
|
+
function keplerCommon(r) {
|
|
9635
|
+
return {
|
|
9636
|
+
af0: r.af0,
|
|
9637
|
+
af1: r.af1,
|
|
9638
|
+
af2: r.af2,
|
|
9639
|
+
iode: r.iode,
|
|
9640
|
+
crs: r.crs,
|
|
9641
|
+
deltaN: r.deltaN,
|
|
9642
|
+
m0: r.m0,
|
|
9643
|
+
cuc: r.cuc,
|
|
9644
|
+
e: r.e,
|
|
9645
|
+
cus: r.cus,
|
|
9646
|
+
sqrtA: r.sqrtA,
|
|
9647
|
+
cic: r.cic,
|
|
9648
|
+
omega0: r.omega0,
|
|
9649
|
+
cis: r.cis,
|
|
9650
|
+
i0: r.i0,
|
|
9651
|
+
crc: r.crc,
|
|
9652
|
+
omega: r.omega,
|
|
9653
|
+
omegaDot: r.omegaDot,
|
|
9654
|
+
idot: r.idot,
|
|
9655
|
+
tgd: r.tgd
|
|
9656
|
+
};
|
|
9657
|
+
}
|
|
9658
|
+
function decodeGpsEphemeris2(view, base) {
|
|
9659
|
+
const r = readKepler(view, base);
|
|
9660
|
+
if (r.svid < 1 || r.svid > 32) return null;
|
|
9661
|
+
const tocMs = gpsMs3(r.week, r.tocSec);
|
|
9627
9662
|
return {
|
|
9628
9663
|
system: "G",
|
|
9629
|
-
prn: `G${String(
|
|
9630
|
-
toc: sowOf4(
|
|
9631
|
-
tocDate: new Date(
|
|
9632
|
-
|
|
9633
|
-
|
|
9634
|
-
|
|
9635
|
-
|
|
9636
|
-
|
|
9637
|
-
|
|
9638
|
-
|
|
9639
|
-
|
|
9640
|
-
|
|
9641
|
-
|
|
9642
|
-
|
|
9643
|
-
|
|
9644
|
-
|
|
9645
|
-
|
|
9646
|
-
|
|
9647
|
-
|
|
9648
|
-
|
|
9649
|
-
|
|
9650
|
-
|
|
9651
|
-
|
|
9652
|
-
|
|
9653
|
-
|
|
9654
|
-
|
|
9664
|
+
prn: `G${String(r.svid).padStart(2, "0")}`,
|
|
9665
|
+
toc: sowOf4(tocMs),
|
|
9666
|
+
tocDate: new Date(tocMs),
|
|
9667
|
+
toe: r.toeSec,
|
|
9668
|
+
week: r.week,
|
|
9669
|
+
svHealth: r.flags >>> 4 & 127,
|
|
9670
|
+
...keplerCommon(r)
|
|
9671
|
+
};
|
|
9672
|
+
}
|
|
9673
|
+
function decodeBdsEphemeris3(view, base) {
|
|
9674
|
+
const r = readKepler(view, base);
|
|
9675
|
+
if (r.svid < 1 || r.svid > 63) return null;
|
|
9676
|
+
const bdsWeek = r.week - BDS_WEEK_OFFSET;
|
|
9677
|
+
const tocSec = r.tocSec - BDS_LEAP_SEC;
|
|
9678
|
+
const toeSec = r.toeSec - BDS_LEAP_SEC;
|
|
9679
|
+
const tocDate = new Date(
|
|
9680
|
+
BDT_EPOCH_MS4 + bdsWeek * MS_PER_WEEK9 + tocSec * 1e3
|
|
9681
|
+
);
|
|
9682
|
+
return {
|
|
9683
|
+
system: "C",
|
|
9684
|
+
prn: `C${String(r.svid).padStart(2, "0")}`,
|
|
9685
|
+
toc: sowOf4(tocDate.getTime()),
|
|
9686
|
+
tocDate,
|
|
9687
|
+
toe: toeSec,
|
|
9688
|
+
week: bdsWeek,
|
|
9689
|
+
// Health from the same flags nibble as GPS (0 = healthy for the observed
|
|
9690
|
+
// operational BeiDou sats); flags bit 0 is a set-on-all format marker,
|
|
9691
|
+
// not SatH1, so it must not be used here.
|
|
9692
|
+
svHealth: r.flags >>> 4 & 127,
|
|
9693
|
+
...keplerCommon(r)
|
|
9694
|
+
};
|
|
9695
|
+
}
|
|
9696
|
+
function decodeGloEphemeris2(view, base) {
|
|
9697
|
+
const slot = view.getUint8(base + 5);
|
|
9698
|
+
if (slot < 1 || slot > 24) return null;
|
|
9699
|
+
const week = view.getUint16(base + 6, false);
|
|
9700
|
+
const tow = view.getUint32(base + 8, false);
|
|
9701
|
+
const gpsTimeMs = gpsMs3(week, tow);
|
|
9702
|
+
const leapMs = getGpsLeap(new Date(gpsTimeMs)) * 1e3;
|
|
9703
|
+
const tocMs = gpsTimeMs - leapMs;
|
|
9704
|
+
return {
|
|
9705
|
+
system: "R",
|
|
9706
|
+
prn: `R${String(slot).padStart(2, "0")}`,
|
|
9707
|
+
tocDate: new Date(tocMs),
|
|
9708
|
+
// RINEX stores −τn as the clock bias; the record carries τn (ICD sign).
|
|
9709
|
+
tauN: -view.getFloat64(base + 113, false),
|
|
9710
|
+
gammaN: view.getFloat64(base + 121, false),
|
|
9711
|
+
messageFrameTime: (tocMs - GPS_EPOCH_MS14) / 1e3 % SEC_PER_WEEK10,
|
|
9712
|
+
// State vector: metres / m·s⁻¹ / m·s⁻² → km / km·s⁻¹ / km·s⁻².
|
|
9713
|
+
x: view.getFloat64(base + 33, false) / 1e3,
|
|
9714
|
+
xDot: view.getFloat64(base + 41, false) / 1e3,
|
|
9715
|
+
xAcc: view.getFloat64(base + 49, false) / 1e3,
|
|
9716
|
+
y: view.getFloat64(base + 57, false) / 1e3,
|
|
9717
|
+
yDot: view.getFloat64(base + 65, false) / 1e3,
|
|
9718
|
+
yAcc: view.getFloat64(base + 73, false) / 1e3,
|
|
9719
|
+
z: view.getFloat64(base + 81, false) / 1e3,
|
|
9720
|
+
zDot: view.getFloat64(base + 89, false) / 1e3,
|
|
9721
|
+
zAcc: view.getFloat64(base + 97, false) / 1e3,
|
|
9722
|
+
health: 0,
|
|
9723
|
+
// Bn health bit not located; observed sats are operational
|
|
9724
|
+
freqNum: view.getInt8(base + 29)
|
|
9725
|
+
// FCN, signed byte (−7…+6)
|
|
9655
9726
|
};
|
|
9656
9727
|
}
|
|
9657
9728
|
function parseTrimbleNav(data) {
|
|
@@ -9666,8 +9737,8 @@ function parseTrimbleNav(data) {
|
|
|
9666
9737
|
if (f.type !== RETSVDATA) continue;
|
|
9667
9738
|
const sub = data[f.payload];
|
|
9668
9739
|
retsvCounts[sub] = (retsvCounts[sub] ?? 0) + 1;
|
|
9669
|
-
if (sub === SUB_GPS_EPHEMERIS && f.len >= 176) {
|
|
9670
|
-
const eph = decodeGpsEphemeris2(
|
|
9740
|
+
if ((sub === SUB_GPS_EPHEMERIS || sub === SUB_BDS_EPHEMERIS) && f.len >= 176) {
|
|
9741
|
+
const eph = sub === SUB_GPS_EPHEMERIS ? decodeGpsEphemeris2(view, f.start) : decodeBdsEphemeris3(view, f.start);
|
|
9671
9742
|
if (!eph) continue;
|
|
9672
9743
|
if (lastIode.get(eph.prn) === eph.iode) continue;
|
|
9673
9744
|
lastIode.set(eph.prn, eph.iode);
|
|
@@ -9683,6 +9754,13 @@ function parseTrimbleNav(data) {
|
|
|
9683
9754
|
ionoCorrections["GPSA"] = alpha;
|
|
9684
9755
|
ionoCorrections["GPSB"] = beta;
|
|
9685
9756
|
leapSeconds = Math.trunc(view.getFloat64(p + 94, false));
|
|
9757
|
+
} else if (sub === SUB_GLO_EPHEMERIS && f.len >= 125) {
|
|
9758
|
+
const eph = decodeGloEphemeris2(view, f.start);
|
|
9759
|
+
if (!eph) continue;
|
|
9760
|
+
const key = eph.tocDate.getTime();
|
|
9761
|
+
if (lastIode.get(eph.prn) === key) continue;
|
|
9762
|
+
lastIode.set(eph.prn, key);
|
|
9763
|
+
ephemerides.push(eph);
|
|
9686
9764
|
}
|
|
9687
9765
|
}
|
|
9688
9766
|
return {
|
|
@@ -10076,7 +10154,7 @@ function* binexRecords(data, view, stats) {
|
|
|
10076
10154
|
// src/binex/nav.ts
|
|
10077
10155
|
var GPS_EPOCH_MS16 = Date.UTC(1980, 0, 6);
|
|
10078
10156
|
var GLO_DAY0_MS = Date.UTC(1980, 0, 1);
|
|
10079
|
-
var
|
|
10157
|
+
var BDT_EPOCH_MS5 = Date.UTC(2006, 0, 1);
|
|
10080
10158
|
var SEC_PER_WEEK11 = 7 * 86400;
|
|
10081
10159
|
var MS_PER_WEEK11 = SEC_PER_WEEK11 * 1e3;
|
|
10082
10160
|
var SC2RAD = GPS_PI;
|
|
@@ -10245,7 +10323,7 @@ function decodeBeidou(view, p, le) {
|
|
|
10245
10323
|
const iode = flag1 >> 6 & 31;
|
|
10246
10324
|
const svHealth = flag1 & 1;
|
|
10247
10325
|
const tgd = bdsTgd(flag2 >> 4);
|
|
10248
|
-
const tocDate = new Date(
|
|
10326
|
+
const tocDate = new Date(BDT_EPOCH_MS5 + week * MS_PER_WEEK11 + toes * 1e3);
|
|
10249
10327
|
return {
|
|
10250
10328
|
system: "C",
|
|
10251
10329
|
prn: `C${two5(prn)}`,
|
|
@@ -10713,13 +10791,13 @@ var GM_GPS = 3986005e8;
|
|
|
10713
10791
|
var GM_GAL = 3986004418e5;
|
|
10714
10792
|
var GM_BDS = 3986004418e5;
|
|
10715
10793
|
var GPS_EPOCH_MS18 = Date.UTC(1980, 0, 6);
|
|
10716
|
-
var
|
|
10794
|
+
var BDT_EPOCH_MS6 = Date.UTC(2006, 0, 1);
|
|
10717
10795
|
var WEEK_MS = 6048e5;
|
|
10718
10796
|
var BDT_MINUS_GPST_MS = 14e3;
|
|
10719
10797
|
var BDS_GEO_PRNS = /* @__PURE__ */ new Set([1, 2, 3, 4, 5, 59, 60, 61, 62, 63]);
|
|
10720
10798
|
function almanacEpochMs(alm) {
|
|
10721
10799
|
if (alm.system === "C") {
|
|
10722
|
-
return
|
|
10800
|
+
return BDT_EPOCH_MS6 + alm.weekAlm * WEEK_MS + alm.toaSec * 1e3 + BDT_MINUS_GPST_MS;
|
|
10723
10801
|
}
|
|
10724
10802
|
return GPS_EPOCH_MS18 + alm.weekAlm * WEEK_MS + alm.toaSec * 1e3;
|
|
10725
10803
|
}
|
package/dist/index.js
CHANGED
package/dist/trimble.cjs
CHANGED
|
@@ -66,70 +66,228 @@ function* trimbleFrames(data, stats) {
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
// src/constants/time.ts
|
|
70
|
+
var MILLISECONDS_IN_SECOND = 1e3;
|
|
71
|
+
var MILLISECONDS_GPS_TAI = 19e3;
|
|
72
|
+
var START_NTP_TIME = /* @__PURE__ */ new Date("1900-01-01T00:00:00Z");
|
|
73
|
+
|
|
74
|
+
// src/time/gnss.ts
|
|
75
|
+
function getTaiDate(date) {
|
|
76
|
+
return new Date(date.getTime() + MILLISECONDS_GPS_TAI);
|
|
77
|
+
}
|
|
78
|
+
function getNtpTime(date) {
|
|
79
|
+
return getTaiDate(date).getTime() - START_NTP_TIME.getTime();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// src/time/utc.ts
|
|
83
|
+
var LEAP_SECONDS_TABLE = [
|
|
84
|
+
[3692217600, 37],
|
|
85
|
+
// 1 Jan 2017
|
|
86
|
+
[3644697600, 36],
|
|
87
|
+
// 1 Jul 2015
|
|
88
|
+
[3550089600, 35],
|
|
89
|
+
// 1 Jul 2012
|
|
90
|
+
[3439756800, 34],
|
|
91
|
+
// 1 Jan 2009
|
|
92
|
+
[3345062400, 33],
|
|
93
|
+
// 1 Jan 2006
|
|
94
|
+
[3124137600, 32],
|
|
95
|
+
// 1 Jan 1999
|
|
96
|
+
[3076704e3, 31],
|
|
97
|
+
// 1 Jul 1997
|
|
98
|
+
[3029443200, 30],
|
|
99
|
+
// 1 Jan 1996
|
|
100
|
+
[2982009600, 29],
|
|
101
|
+
// 1 Jul 1994
|
|
102
|
+
[2950473600, 28],
|
|
103
|
+
// 1 Jul 1993
|
|
104
|
+
[2918937600, 27],
|
|
105
|
+
// 1 Jul 1992
|
|
106
|
+
[2871676800, 26],
|
|
107
|
+
// 1 Jan 1991
|
|
108
|
+
[2840140800, 25],
|
|
109
|
+
// 1 Jan 1990
|
|
110
|
+
[2776982400, 24],
|
|
111
|
+
// 1 Jan 1988
|
|
112
|
+
[2698012800, 23],
|
|
113
|
+
// 1 Jul 1985
|
|
114
|
+
[2634854400, 22],
|
|
115
|
+
// 1 Jul 1983
|
|
116
|
+
[2603318400, 21],
|
|
117
|
+
// 1 Jul 1982
|
|
118
|
+
[2571782400, 20],
|
|
119
|
+
// 1 Jul 1981
|
|
120
|
+
[2524521600, 19],
|
|
121
|
+
// 1 Jan 1980
|
|
122
|
+
[2492985600, 18],
|
|
123
|
+
// 1 Jan 1979
|
|
124
|
+
[2461449600, 17],
|
|
125
|
+
// 1 Jan 1978
|
|
126
|
+
[2429913600, 16],
|
|
127
|
+
// 1 Jan 1977
|
|
128
|
+
[2398291200, 15],
|
|
129
|
+
// 1 Jan 1976
|
|
130
|
+
[2366755200, 14],
|
|
131
|
+
// 1 Jan 1975
|
|
132
|
+
[2335219200, 13],
|
|
133
|
+
// 1 Jan 1974
|
|
134
|
+
[2303683200, 12],
|
|
135
|
+
// 1 Jan 1973
|
|
136
|
+
[2287785600, 11],
|
|
137
|
+
// 1 Jul 1972
|
|
138
|
+
[2272060800, 10]
|
|
139
|
+
// 1 Jan 1972
|
|
140
|
+
];
|
|
141
|
+
function getLeap(date) {
|
|
142
|
+
const ntp_time = getNtpTime(date);
|
|
143
|
+
for (const [timestamp, leapSeconds] of LEAP_SECONDS_TABLE) {
|
|
144
|
+
if (ntp_time / MILLISECONDS_IN_SECOND - leapSeconds >= timestamp) {
|
|
145
|
+
return leapSeconds;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return 8;
|
|
149
|
+
}
|
|
150
|
+
function getGpsLeap(date) {
|
|
151
|
+
const leap_seconds = getLeap(date);
|
|
152
|
+
if (leap_seconds < 0) return 0;
|
|
153
|
+
return leap_seconds - 19;
|
|
154
|
+
}
|
|
155
|
+
|
|
69
156
|
// src/trimble/nav.ts
|
|
70
157
|
var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
|
|
158
|
+
var BDT_EPOCH_MS = Date.UTC(2006, 0, 1);
|
|
71
159
|
var SEC_PER_WEEK = 7 * 86400;
|
|
72
160
|
var MS_PER_WEEK = SEC_PER_WEEK * 1e3;
|
|
73
161
|
var GPS_PI = 3.1415926535898;
|
|
162
|
+
var BDS_WEEK_OFFSET = 1356;
|
|
163
|
+
var BDS_LEAP_SEC = 14;
|
|
74
164
|
var gpsMs = (week, sec) => GPS_EPOCH_MS + week * MS_PER_WEEK + sec * 1e3;
|
|
75
165
|
var sowOf = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK;
|
|
76
166
|
var SUB_GPS_EPHEMERIS = 1;
|
|
77
167
|
var SUB_ION_UTC = 3;
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
168
|
+
var SUB_GLO_EPHEMERIS = 9;
|
|
169
|
+
var SUB_BDS_EPHEMERIS = 21;
|
|
170
|
+
function readKepler(view, base) {
|
|
171
|
+
return {
|
|
172
|
+
svid: view.getUint8(base + 5),
|
|
173
|
+
week: view.getUint16(base + 6, false),
|
|
174
|
+
iode: view.getUint8(base + 11),
|
|
175
|
+
tocSec: view.getInt32(base + 16, false),
|
|
176
|
+
toeSec: view.getUint32(base + 20, false),
|
|
177
|
+
tgd: view.getFloat64(base + 24, false),
|
|
178
|
+
af2: view.getFloat64(base + 32, false),
|
|
179
|
+
af1: view.getFloat64(base + 40, false),
|
|
180
|
+
af0: view.getFloat64(base + 48, false),
|
|
181
|
+
crs: view.getFloat64(base + 56, false),
|
|
182
|
+
deltaN: view.getFloat64(base + 64, false) * GPS_PI,
|
|
183
|
+
m0: view.getFloat64(base + 72, false) * GPS_PI,
|
|
184
|
+
cuc: view.getFloat64(base + 80, false) * GPS_PI,
|
|
185
|
+
e: view.getFloat64(base + 88, false),
|
|
186
|
+
cus: view.getFloat64(base + 96, false) * GPS_PI,
|
|
187
|
+
sqrtA: view.getFloat64(base + 104, false),
|
|
188
|
+
cic: view.getFloat64(base + 112, false) * GPS_PI,
|
|
189
|
+
omega0: view.getFloat64(base + 120, false) * GPS_PI,
|
|
190
|
+
cis: view.getFloat64(base + 128, false) * GPS_PI,
|
|
191
|
+
i0: view.getFloat64(base + 136, false) * GPS_PI,
|
|
192
|
+
crc: view.getFloat64(base + 144, false),
|
|
193
|
+
omega: view.getFloat64(base + 152, false) * GPS_PI,
|
|
194
|
+
omegaDot: view.getFloat64(base + 160, false) * GPS_PI,
|
|
195
|
+
idot: view.getFloat64(base + 168, false) * GPS_PI,
|
|
196
|
+
flags: view.getUint32(base + 176, false)
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
function keplerCommon(r) {
|
|
200
|
+
return {
|
|
201
|
+
af0: r.af0,
|
|
202
|
+
af1: r.af1,
|
|
203
|
+
af2: r.af2,
|
|
204
|
+
iode: r.iode,
|
|
205
|
+
crs: r.crs,
|
|
206
|
+
deltaN: r.deltaN,
|
|
207
|
+
m0: r.m0,
|
|
208
|
+
cuc: r.cuc,
|
|
209
|
+
e: r.e,
|
|
210
|
+
cus: r.cus,
|
|
211
|
+
sqrtA: r.sqrtA,
|
|
212
|
+
cic: r.cic,
|
|
213
|
+
omega0: r.omega0,
|
|
214
|
+
cis: r.cis,
|
|
215
|
+
i0: r.i0,
|
|
216
|
+
crc: r.crc,
|
|
217
|
+
omega: r.omega,
|
|
218
|
+
omegaDot: r.omegaDot,
|
|
219
|
+
idot: r.idot,
|
|
220
|
+
tgd: r.tgd
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
function decodeGpsEphemeris(view, base) {
|
|
224
|
+
const r = readKepler(view, base);
|
|
225
|
+
if (r.svid < 1 || r.svid > 32) return null;
|
|
226
|
+
const tocMs = gpsMs(r.week, r.tocSec);
|
|
105
227
|
return {
|
|
106
228
|
system: "G",
|
|
107
|
-
prn: `G${String(
|
|
108
|
-
toc: sowOf(
|
|
109
|
-
tocDate: new Date(
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
229
|
+
prn: `G${String(r.svid).padStart(2, "0")}`,
|
|
230
|
+
toc: sowOf(tocMs),
|
|
231
|
+
tocDate: new Date(tocMs),
|
|
232
|
+
toe: r.toeSec,
|
|
233
|
+
week: r.week,
|
|
234
|
+
svHealth: r.flags >>> 4 & 127,
|
|
235
|
+
...keplerCommon(r)
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
function decodeBdsEphemeris(view, base) {
|
|
239
|
+
const r = readKepler(view, base);
|
|
240
|
+
if (r.svid < 1 || r.svid > 63) return null;
|
|
241
|
+
const bdsWeek = r.week - BDS_WEEK_OFFSET;
|
|
242
|
+
const tocSec = r.tocSec - BDS_LEAP_SEC;
|
|
243
|
+
const toeSec = r.toeSec - BDS_LEAP_SEC;
|
|
244
|
+
const tocDate = new Date(
|
|
245
|
+
BDT_EPOCH_MS + bdsWeek * MS_PER_WEEK + tocSec * 1e3
|
|
246
|
+
);
|
|
247
|
+
return {
|
|
248
|
+
system: "C",
|
|
249
|
+
prn: `C${String(r.svid).padStart(2, "0")}`,
|
|
250
|
+
toc: sowOf(tocDate.getTime()),
|
|
251
|
+
tocDate,
|
|
252
|
+
toe: toeSec,
|
|
253
|
+
week: bdsWeek,
|
|
254
|
+
// Health from the same flags nibble as GPS (0 = healthy for the observed
|
|
255
|
+
// operational BeiDou sats); flags bit 0 is a set-on-all format marker,
|
|
256
|
+
// not SatH1, so it must not be used here.
|
|
257
|
+
svHealth: r.flags >>> 4 & 127,
|
|
258
|
+
...keplerCommon(r)
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
function decodeGloEphemeris(view, base) {
|
|
262
|
+
const slot = view.getUint8(base + 5);
|
|
263
|
+
if (slot < 1 || slot > 24) return null;
|
|
264
|
+
const week = view.getUint16(base + 6, false);
|
|
265
|
+
const tow = view.getUint32(base + 8, false);
|
|
266
|
+
const gpsTimeMs = gpsMs(week, tow);
|
|
267
|
+
const leapMs = getGpsLeap(new Date(gpsTimeMs)) * 1e3;
|
|
268
|
+
const tocMs = gpsTimeMs - leapMs;
|
|
269
|
+
return {
|
|
270
|
+
system: "R",
|
|
271
|
+
prn: `R${String(slot).padStart(2, "0")}`,
|
|
272
|
+
tocDate: new Date(tocMs),
|
|
273
|
+
// RINEX stores −τn as the clock bias; the record carries τn (ICD sign).
|
|
274
|
+
tauN: -view.getFloat64(base + 113, false),
|
|
275
|
+
gammaN: view.getFloat64(base + 121, false),
|
|
276
|
+
messageFrameTime: (tocMs - GPS_EPOCH_MS) / 1e3 % SEC_PER_WEEK,
|
|
277
|
+
// State vector: metres / m·s⁻¹ / m·s⁻² → km / km·s⁻¹ / km·s⁻².
|
|
278
|
+
x: view.getFloat64(base + 33, false) / 1e3,
|
|
279
|
+
xDot: view.getFloat64(base + 41, false) / 1e3,
|
|
280
|
+
xAcc: view.getFloat64(base + 49, false) / 1e3,
|
|
281
|
+
y: view.getFloat64(base + 57, false) / 1e3,
|
|
282
|
+
yDot: view.getFloat64(base + 65, false) / 1e3,
|
|
283
|
+
yAcc: view.getFloat64(base + 73, false) / 1e3,
|
|
284
|
+
z: view.getFloat64(base + 81, false) / 1e3,
|
|
285
|
+
zDot: view.getFloat64(base + 89, false) / 1e3,
|
|
286
|
+
zAcc: view.getFloat64(base + 97, false) / 1e3,
|
|
287
|
+
health: 0,
|
|
288
|
+
// Bn health bit not located; observed sats are operational
|
|
289
|
+
freqNum: view.getInt8(base + 29)
|
|
290
|
+
// FCN, signed byte (−7…+6)
|
|
133
291
|
};
|
|
134
292
|
}
|
|
135
293
|
function parseTrimbleNav(data) {
|
|
@@ -144,8 +302,8 @@ function parseTrimbleNav(data) {
|
|
|
144
302
|
if (f.type !== RETSVDATA) continue;
|
|
145
303
|
const sub = data[f.payload];
|
|
146
304
|
retsvCounts[sub] = (retsvCounts[sub] ?? 0) + 1;
|
|
147
|
-
if (sub === SUB_GPS_EPHEMERIS && f.len >= 176) {
|
|
148
|
-
const eph = decodeGpsEphemeris(
|
|
305
|
+
if ((sub === SUB_GPS_EPHEMERIS || sub === SUB_BDS_EPHEMERIS) && f.len >= 176) {
|
|
306
|
+
const eph = sub === SUB_GPS_EPHEMERIS ? decodeGpsEphemeris(view, f.start) : decodeBdsEphemeris(view, f.start);
|
|
149
307
|
if (!eph) continue;
|
|
150
308
|
if (lastIode.get(eph.prn) === eph.iode) continue;
|
|
151
309
|
lastIode.set(eph.prn, eph.iode);
|
|
@@ -161,6 +319,13 @@ function parseTrimbleNav(data) {
|
|
|
161
319
|
ionoCorrections["GPSA"] = alpha;
|
|
162
320
|
ionoCorrections["GPSB"] = beta;
|
|
163
321
|
leapSeconds = Math.trunc(view.getFloat64(p + 94, false));
|
|
322
|
+
} else if (sub === SUB_GLO_EPHEMERIS && f.len >= 125) {
|
|
323
|
+
const eph = decodeGloEphemeris(view, f.start);
|
|
324
|
+
if (!eph) continue;
|
|
325
|
+
const key = eph.tocDate.getTime();
|
|
326
|
+
if (lastIode.get(eph.prn) === key) continue;
|
|
327
|
+
lastIode.set(eph.prn, key);
|
|
328
|
+
ephemerides.push(eph);
|
|
164
329
|
}
|
|
165
330
|
}
|
|
166
331
|
return {
|
package/dist/trimble.d.cts
CHANGED
|
@@ -25,24 +25,29 @@ declare function trimbleFrames(data: Uint8Array, stats: {
|
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Trimble RT17/RT27 navigation-message decoding: RETSVDATA (0x55)
|
|
28
|
-
* GPS ephemeris (subtype 1)
|
|
28
|
+
* GPS ephemeris (subtype 1), GLONASS ephemeris (subtype 9), BeiDou
|
|
29
|
+
* ephemeris (subtype 21) and ION / UTC data (subtype 3).
|
|
29
30
|
*
|
|
30
|
-
*
|
|
31
|
+
* The GPS path is ported field-for-field from RTKLIB's `src/rcv/rt17.c`
|
|
31
32
|
* (`decode_gps_ephemeris` / `decode_ion_utc_data`, tomojitakasu/RTKLIB,
|
|
32
33
|
* Copyright (C) 2014 D. A. Cook / T. Takasu, BSD-2-Clause). All scalar
|
|
33
34
|
* fields are big-endian; the semicircle angular/harmonic fields are
|
|
34
|
-
* scaled by π to radians, exactly as RTKLIB does.
|
|
35
|
+
* scaled by π to radians, exactly as RTKLIB does. BeiDou (subtype 21)
|
|
36
|
+
* reuses the identical 176-byte Keplerian struct — established from a
|
|
37
|
+
* real DLF100NLD1 capture (√a ≈ 5282.6 m^½ ⇒ BeiDou MEO, i₀ ≈ 55°) — with
|
|
38
|
+
* the GPS→BDT time-scale conversion (week − 1356, SOW − 14 s) applied so
|
|
39
|
+
* the record matches `parseSbfNav`'s BDSNav output.
|
|
35
40
|
*
|
|
36
41
|
* Output records mirror what `parseNavFile` produces for the equivalent
|
|
37
|
-
* RINEX 3
|
|
38
|
-
*
|
|
42
|
+
* RINEX 3 navigation record and match the NovAtel/SBF ephemeris paths
|
|
43
|
+
* (GPS: GPS-scale `tocDate`; BeiDou: naive-BDT `tocDate`; angles in rad).
|
|
39
44
|
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* (
|
|
45
|
+
* The subtype→constellation map is confirmed by RTKLIB's rt17.c
|
|
46
|
+
* RETSVDATA table (st[]: 1 = GPS Eph, 9 = GLONASS Eph, 11 = Galileo Eph,
|
|
47
|
+
* 21 = BeiDou Eph) — but RTKLIB only *decodes* subtypes 1 and 3, so the
|
|
48
|
+
* GLONASS/BeiDou field layouts here were reverse-engineered and validated
|
|
49
|
+
* against physics + the 2026-07-27 BRDC. Still not decoded: Galileo
|
|
50
|
+
* (subtype 11) and the QZSS/almanac subtypes (13/23/27 on this stream).
|
|
46
51
|
*/
|
|
47
52
|
|
|
48
53
|
interface TrimbleNavResult {
|
|
@@ -61,9 +66,10 @@ interface TrimbleNavResult {
|
|
|
61
66
|
badChecksum: number;
|
|
62
67
|
}
|
|
63
68
|
/**
|
|
64
|
-
* Decode every RETSVDATA navigation message (GPS
|
|
65
|
-
* a Trimble binary byte stream. Repeated
|
|
66
|
-
* ephemeris are suppressed by issue of data
|
|
69
|
+
* Decode every RETSVDATA navigation message (GPS/BeiDou/GLONASS
|
|
70
|
+
* ephemeris, ION/UTC) in a Trimble binary byte stream. Repeated
|
|
71
|
+
* broadcasts of an unchanged ephemeris are suppressed by issue of data
|
|
72
|
+
* (Keplerian) / reference epoch (GLONASS), as RTKLIB does.
|
|
67
73
|
*/
|
|
68
74
|
declare function parseTrimbleNav(data: Uint8Array): TrimbleNavResult;
|
|
69
75
|
|
package/dist/trimble.d.ts
CHANGED
|
@@ -25,24 +25,29 @@ declare function trimbleFrames(data: Uint8Array, stats: {
|
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Trimble RT17/RT27 navigation-message decoding: RETSVDATA (0x55)
|
|
28
|
-
* GPS ephemeris (subtype 1)
|
|
28
|
+
* GPS ephemeris (subtype 1), GLONASS ephemeris (subtype 9), BeiDou
|
|
29
|
+
* ephemeris (subtype 21) and ION / UTC data (subtype 3).
|
|
29
30
|
*
|
|
30
|
-
*
|
|
31
|
+
* The GPS path is ported field-for-field from RTKLIB's `src/rcv/rt17.c`
|
|
31
32
|
* (`decode_gps_ephemeris` / `decode_ion_utc_data`, tomojitakasu/RTKLIB,
|
|
32
33
|
* Copyright (C) 2014 D. A. Cook / T. Takasu, BSD-2-Clause). All scalar
|
|
33
34
|
* fields are big-endian; the semicircle angular/harmonic fields are
|
|
34
|
-
* scaled by π to radians, exactly as RTKLIB does.
|
|
35
|
+
* scaled by π to radians, exactly as RTKLIB does. BeiDou (subtype 21)
|
|
36
|
+
* reuses the identical 176-byte Keplerian struct — established from a
|
|
37
|
+
* real DLF100NLD1 capture (√a ≈ 5282.6 m^½ ⇒ BeiDou MEO, i₀ ≈ 55°) — with
|
|
38
|
+
* the GPS→BDT time-scale conversion (week − 1356, SOW − 14 s) applied so
|
|
39
|
+
* the record matches `parseSbfNav`'s BDSNav output.
|
|
35
40
|
*
|
|
36
41
|
* Output records mirror what `parseNavFile` produces for the equivalent
|
|
37
|
-
* RINEX 3
|
|
38
|
-
*
|
|
42
|
+
* RINEX 3 navigation record and match the NovAtel/SBF ephemeris paths
|
|
43
|
+
* (GPS: GPS-scale `tocDate`; BeiDou: naive-BDT `tocDate`; angles in rad).
|
|
39
44
|
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* (
|
|
45
|
+
* The subtype→constellation map is confirmed by RTKLIB's rt17.c
|
|
46
|
+
* RETSVDATA table (st[]: 1 = GPS Eph, 9 = GLONASS Eph, 11 = Galileo Eph,
|
|
47
|
+
* 21 = BeiDou Eph) — but RTKLIB only *decodes* subtypes 1 and 3, so the
|
|
48
|
+
* GLONASS/BeiDou field layouts here were reverse-engineered and validated
|
|
49
|
+
* against physics + the 2026-07-27 BRDC. Still not decoded: Galileo
|
|
50
|
+
* (subtype 11) and the QZSS/almanac subtypes (13/23/27 on this stream).
|
|
46
51
|
*/
|
|
47
52
|
|
|
48
53
|
interface TrimbleNavResult {
|
|
@@ -61,9 +66,10 @@ interface TrimbleNavResult {
|
|
|
61
66
|
badChecksum: number;
|
|
62
67
|
}
|
|
63
68
|
/**
|
|
64
|
-
* Decode every RETSVDATA navigation message (GPS
|
|
65
|
-
* a Trimble binary byte stream. Repeated
|
|
66
|
-
* ephemeris are suppressed by issue of data
|
|
69
|
+
* Decode every RETSVDATA navigation message (GPS/BeiDou/GLONASS
|
|
70
|
+
* ephemeris, ION/UTC) in a Trimble binary byte stream. Repeated
|
|
71
|
+
* broadcasts of an unchanged ephemeris are suppressed by issue of data
|
|
72
|
+
* (Keplerian) / reference epoch (GLONASS), as RTKLIB does.
|
|
67
73
|
*/
|
|
68
74
|
declare function parseTrimbleNav(data: Uint8Array): TrimbleNavResult;
|
|
69
75
|
|
package/dist/trimble.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gnss-js",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.41.0",
|
|
4
4
|
"description": "Comprehensive GNSS library for JavaScript — time scales, coordinates, RINEX parsing, RTCM3 decoding, orbit computation, and signal analysis",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|