gnss-js 1.19.0 → 1.21.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-2IM5VXNI.js → chunk-7RKLWE6R.js} +23 -2
- package/dist/{chunk-QXZZNXE3.js → chunk-B5LU4746.js} +1 -1
- package/dist/{chunk-JW2ICDR7.js → chunk-DLXTTHRK.js} +2 -4
- package/dist/{chunk-OMVL3X7V.js → chunk-JNFV5BYB.js} +186 -8
- package/dist/chunk-K3V3NHWL.js +2541 -0
- package/dist/{chunk-K73SERD5.js → chunk-NOQAAUGY.js} +2 -4
- package/dist/{chunk-6NCMACDO.js → chunk-WZDFZ76K.js} +149 -8
- package/dist/index.cjs +1675 -57
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +23 -8
- package/dist/nav-BYmYoh9A.d.cts +137 -0
- package/dist/nav-CN8rxL4h.d.ts +137 -0
- package/dist/novatel.cjs +230 -15
- package/dist/novatel.d.cts +8 -1
- package/dist/novatel.d.ts +8 -1
- package/dist/novatel.js +2 -2
- package/dist/orbit.cjs +190 -8
- package/dist/orbit.d.cts +90 -1
- package/dist/orbit.d.ts +90 -1
- package/dist/orbit.js +9 -1
- package/dist/positioning.d.cts +1 -0
- package/dist/positioning.d.ts +1 -0
- package/dist/positioning.js +2 -2
- package/dist/rinex.js +2 -3
- package/dist/sbf.cjs +1433 -11
- package/dist/sbf.d.cts +286 -136
- package/dist/sbf.d.ts +286 -136
- package/dist/sbf.js +10 -3
- package/dist/ubx.js +2 -3
- package/package.json +1 -1
- package/dist/chunk-5S5HMAKW.js +0 -1123
- package/dist/chunk-IQ5OIMQD.js +0 -148
package/dist/index.cjs
CHANGED
|
@@ -104,6 +104,8 @@ __export(src_exports, {
|
|
|
104
104
|
WGS84_SEMI_MAJOR_AXIS: () => WGS84_SEMI_MAJOR_AXIS,
|
|
105
105
|
WGS84_SEMI_MINOR_AXIS: () => WGS84_SEMI_MINOR_AXIS,
|
|
106
106
|
WarningAccumulator: () => WarningAccumulator,
|
|
107
|
+
almanacEpochMs: () => almanacEpochMs,
|
|
108
|
+
almanacSatPosition: () => almanacSatPosition,
|
|
107
109
|
analyzeQuality: () => analyzeQuality,
|
|
108
110
|
applyHelmert: () => applyHelmert,
|
|
109
111
|
applyIonoDcb: () => applyIonoDcb,
|
|
@@ -200,6 +202,8 @@ __export(src_exports, {
|
|
|
200
202
|
getWeekNumber: () => getWeekNumber,
|
|
201
203
|
getWeekOfYear: () => getWeekOfYear,
|
|
202
204
|
gloFreq: () => gloFreq,
|
|
205
|
+
glonassAlmanacEpochMs: () => glonassAlmanacEpochMs,
|
|
206
|
+
glonassAlmanacPosition: () => glonassAlmanacPosition,
|
|
203
207
|
glonassPosition: () => glonassPosition,
|
|
204
208
|
greatCircleMidpoint: () => greatCircleMidpoint,
|
|
205
209
|
hdrLine: () => hdrLine,
|
|
@@ -223,7 +227,11 @@ __export(src_exports, {
|
|
|
223
227
|
parseNovatelRange: () => parseNovatelRange,
|
|
224
228
|
parseRinexStream: () => parseRinexStream,
|
|
225
229
|
parseSbfAlmanac: () => parseSbfAlmanac,
|
|
230
|
+
parseSbfBdsNav: () => parseSbfBdsNav,
|
|
226
231
|
parseSbfCnav: () => parseSbfCnav,
|
|
232
|
+
parseSbfGalNav: () => parseSbfGalNav,
|
|
233
|
+
parseSbfGloNav: () => parseSbfGloNav,
|
|
234
|
+
parseSbfHas: () => parseSbfHas,
|
|
227
235
|
parseSbfIonoUtc: () => parseSbfIonoUtc,
|
|
228
236
|
parseSbfMeas: () => parseSbfMeas,
|
|
229
237
|
parseSbfNav: () => parseSbfNav,
|
|
@@ -5414,20 +5422,20 @@ var SIGNALS = {
|
|
|
5414
5422
|
// GLONASS L1OF, L2OF
|
|
5415
5423
|
};
|
|
5416
5424
|
function prnFor(gnssId, svId) {
|
|
5417
|
-
const
|
|
5425
|
+
const two4 = (n) => String(n).padStart(2, "0");
|
|
5418
5426
|
switch (gnssId) {
|
|
5419
5427
|
case 0:
|
|
5420
|
-
return svId >= 1 && svId <= 32 ? `G${
|
|
5428
|
+
return svId >= 1 && svId <= 32 ? `G${two4(svId)}` : null;
|
|
5421
5429
|
case 1:
|
|
5422
|
-
return svId >= 120 && svId <= 158 ? `S${
|
|
5430
|
+
return svId >= 120 && svId <= 158 ? `S${two4(svId - 100)}` : null;
|
|
5423
5431
|
case 2:
|
|
5424
|
-
return svId >= 1 && svId <= 36 ? `E${
|
|
5432
|
+
return svId >= 1 && svId <= 36 ? `E${two4(svId)}` : null;
|
|
5425
5433
|
case 3:
|
|
5426
|
-
return svId >= 1 && svId <= 63 ? `C${
|
|
5434
|
+
return svId >= 1 && svId <= 63 ? `C${two4(svId)}` : null;
|
|
5427
5435
|
case 5:
|
|
5428
|
-
return svId >= 1 && svId <= 10 ? `J${
|
|
5436
|
+
return svId >= 1 && svId <= 10 ? `J${two4(svId)}` : null;
|
|
5429
5437
|
case 6:
|
|
5430
|
-
return svId >= 1 && svId <= 32 ? `R${
|
|
5438
|
+
return svId >= 1 && svId <= 32 ? `R${two4(svId)}` : null;
|
|
5431
5439
|
default:
|
|
5432
5440
|
return null;
|
|
5433
5441
|
}
|
|
@@ -5927,10 +5935,1419 @@ function parseSbfCnav(data) {
|
|
|
5927
5935
|
return { ephemerides, badCrc, messages };
|
|
5928
5936
|
}
|
|
5929
5937
|
|
|
5938
|
+
// src/navbits/gal.ts
|
|
5939
|
+
var GPS_EPOCH_MS6 = Date.UTC(1980, 0, 6);
|
|
5940
|
+
var SEC_PER_WEEK5 = 7 * 86400;
|
|
5941
|
+
var HALF_WEEK2 = 302400;
|
|
5942
|
+
var GST_GPS_WEEK_OFFSET = 1024;
|
|
5943
|
+
function galInavPageCrcOk(page) {
|
|
5944
|
+
if (page.length < 28) return false;
|
|
5945
|
+
return crc24q(page, 196) === getBitU(page, 196, 24);
|
|
5946
|
+
}
|
|
5947
|
+
function galFnavPageCrcOk(page) {
|
|
5948
|
+
if (page.length < 30) return false;
|
|
5949
|
+
return crc24q(page, 214) === getBitU(page, 214, 24);
|
|
5950
|
+
}
|
|
5951
|
+
function gpsDate2(week, sec) {
|
|
5952
|
+
return new Date(GPS_EPOCH_MS6 + (week * SEC_PER_WEEK5 + sec) * 1e3);
|
|
5953
|
+
}
|
|
5954
|
+
function weekOfToe(week, tow, toe) {
|
|
5955
|
+
if (toe - tow > HALF_WEEK2) return week - 1;
|
|
5956
|
+
if (toe - tow < -HALF_WEEK2) return week + 1;
|
|
5957
|
+
return week;
|
|
5958
|
+
}
|
|
5959
|
+
var two2 = (n) => String(n).padStart(2, "0");
|
|
5960
|
+
function decodeGalInavWords(words) {
|
|
5961
|
+
if (words.length < 96) return null;
|
|
5962
|
+
const b = words;
|
|
5963
|
+
let i = 128;
|
|
5964
|
+
const type1 = getBitU(b, i, 6);
|
|
5965
|
+
i += 6;
|
|
5966
|
+
const iodNav1 = getBitU(b, i, 10);
|
|
5967
|
+
i += 10;
|
|
5968
|
+
const toes = getBitU(b, i, 14) * 60;
|
|
5969
|
+
i += 14;
|
|
5970
|
+
const m0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
5971
|
+
i += 32;
|
|
5972
|
+
const e = getBitU(b, i, 32) * 2 ** -33;
|
|
5973
|
+
i += 32;
|
|
5974
|
+
const sqrtA = getBitU(b, i, 32) * 2 ** -19;
|
|
5975
|
+
i = 128 * 2;
|
|
5976
|
+
const type2 = getBitU(b, i, 6);
|
|
5977
|
+
i += 6;
|
|
5978
|
+
const iodNav2 = getBitU(b, i, 10);
|
|
5979
|
+
i += 10;
|
|
5980
|
+
const omega0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
5981
|
+
i += 32;
|
|
5982
|
+
const i0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
5983
|
+
i += 32;
|
|
5984
|
+
const omega = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
5985
|
+
i += 32;
|
|
5986
|
+
const idot = getBitS(b, i, 14) * 2 ** -43 * GPS_PI;
|
|
5987
|
+
i = 128 * 3;
|
|
5988
|
+
const type3 = getBitU(b, i, 6);
|
|
5989
|
+
i += 6;
|
|
5990
|
+
const iodNav3 = getBitU(b, i, 10);
|
|
5991
|
+
i += 10;
|
|
5992
|
+
const omegaDot = getBitS(b, i, 24) * 2 ** -43 * GPS_PI;
|
|
5993
|
+
i += 24;
|
|
5994
|
+
const deltaN = getBitS(b, i, 16) * 2 ** -43 * GPS_PI;
|
|
5995
|
+
i += 16;
|
|
5996
|
+
const cuc = getBitS(b, i, 16) * 2 ** -29;
|
|
5997
|
+
i += 16;
|
|
5998
|
+
const cus = getBitS(b, i, 16) * 2 ** -29;
|
|
5999
|
+
i += 16;
|
|
6000
|
+
const crc = getBitS(b, i, 16) * 2 ** -5;
|
|
6001
|
+
i += 16;
|
|
6002
|
+
const crs = getBitS(b, i, 16) * 2 ** -5;
|
|
6003
|
+
i = 128 * 4;
|
|
6004
|
+
const type4 = getBitU(b, i, 6);
|
|
6005
|
+
i += 6;
|
|
6006
|
+
const iodNav4 = getBitU(b, i, 10);
|
|
6007
|
+
i += 10;
|
|
6008
|
+
const svid = getBitU(b, i, 6);
|
|
6009
|
+
i += 6;
|
|
6010
|
+
const cic = getBitS(b, i, 16) * 2 ** -29;
|
|
6011
|
+
i += 16;
|
|
6012
|
+
const cis = getBitS(b, i, 16) * 2 ** -29;
|
|
6013
|
+
i += 16;
|
|
6014
|
+
const tocs = getBitU(b, i, 14) * 60;
|
|
6015
|
+
i += 14;
|
|
6016
|
+
const af0 = getBitS(b, i, 31) * 2 ** -34;
|
|
6017
|
+
i += 31;
|
|
6018
|
+
const af1 = getBitS(b, i, 21) * 2 ** -46;
|
|
6019
|
+
i += 21;
|
|
6020
|
+
const af2 = getBitS(b, i, 6) * 2 ** -59;
|
|
6021
|
+
i = 128 * 5;
|
|
6022
|
+
const type5 = getBitU(b, i, 6);
|
|
6023
|
+
i += 6 + 11 + 11 + 14 + 5;
|
|
6024
|
+
const bgdE5a = getBitS(b, i, 10) * 2 ** -32;
|
|
6025
|
+
i += 10;
|
|
6026
|
+
i += 10;
|
|
6027
|
+
const e5bHs = getBitU(b, i, 2);
|
|
6028
|
+
i += 2;
|
|
6029
|
+
const e1bHs = getBitU(b, i, 2);
|
|
6030
|
+
i += 2;
|
|
6031
|
+
const e5bDvs = getBitU(b, i, 1);
|
|
6032
|
+
i += 1;
|
|
6033
|
+
const e1bDvs = getBitU(b, i, 1);
|
|
6034
|
+
i += 1;
|
|
6035
|
+
const gstWeek = getBitU(b, i, 12);
|
|
6036
|
+
i += 12;
|
|
6037
|
+
const tow = getBitU(b, i, 20);
|
|
6038
|
+
if (type1 !== 1 || type2 !== 2 || type3 !== 3 || type4 !== 4 || type5 !== 5)
|
|
6039
|
+
return null;
|
|
6040
|
+
if (iodNav1 !== iodNav2 || iodNav1 !== iodNav3 || iodNav1 !== iodNav4)
|
|
6041
|
+
return null;
|
|
6042
|
+
if (svid < 1 || svid > 36) return null;
|
|
6043
|
+
const week = weekOfToe(gstWeek, tow, toes) + GST_GPS_WEEK_OFFSET;
|
|
6044
|
+
const tocDate = gpsDate2(week, tocs);
|
|
6045
|
+
return {
|
|
6046
|
+
system: "E",
|
|
6047
|
+
prn: `E${two2(svid)}`,
|
|
6048
|
+
toc: tocDate.getTime() / 1e3 % SEC_PER_WEEK5,
|
|
6049
|
+
tocDate,
|
|
6050
|
+
af0,
|
|
6051
|
+
af1,
|
|
6052
|
+
af2,
|
|
6053
|
+
iode: iodNav1,
|
|
6054
|
+
crs,
|
|
6055
|
+
deltaN,
|
|
6056
|
+
m0,
|
|
6057
|
+
cuc,
|
|
6058
|
+
e,
|
|
6059
|
+
cus,
|
|
6060
|
+
sqrtA,
|
|
6061
|
+
toe: toes,
|
|
6062
|
+
cic,
|
|
6063
|
+
omega0,
|
|
6064
|
+
cis,
|
|
6065
|
+
i0,
|
|
6066
|
+
crc,
|
|
6067
|
+
omega,
|
|
6068
|
+
omegaDot,
|
|
6069
|
+
idot,
|
|
6070
|
+
week,
|
|
6071
|
+
svHealth: e5bHs << 7 | e5bDvs << 6 | e1bHs << 1 | e1bDvs,
|
|
6072
|
+
tgd: bgdE5a
|
|
6073
|
+
};
|
|
6074
|
+
}
|
|
6075
|
+
function decodeGalFnavPages(pages) {
|
|
6076
|
+
if (pages.length < 124) return null;
|
|
6077
|
+
const b = pages;
|
|
6078
|
+
let i = 0;
|
|
6079
|
+
const type1 = getBitU(b, i, 6);
|
|
6080
|
+
i += 6;
|
|
6081
|
+
const svid = getBitU(b, i, 6);
|
|
6082
|
+
i += 6;
|
|
6083
|
+
const iodNav1 = getBitU(b, i, 10);
|
|
6084
|
+
i += 10;
|
|
6085
|
+
const tocs = getBitU(b, i, 14) * 60;
|
|
6086
|
+
i += 14;
|
|
6087
|
+
const af0 = getBitS(b, i, 31) * 2 ** -34;
|
|
6088
|
+
i += 31;
|
|
6089
|
+
const af1 = getBitS(b, i, 21) * 2 ** -46;
|
|
6090
|
+
i += 21;
|
|
6091
|
+
const af2 = getBitS(b, i, 6) * 2 ** -59;
|
|
6092
|
+
i += 6;
|
|
6093
|
+
i += 8 + 11 + 11 + 14 + 5;
|
|
6094
|
+
const bgdE5a = getBitS(b, i, 10) * 2 ** -32;
|
|
6095
|
+
i += 10;
|
|
6096
|
+
const e5aHs = getBitU(b, i, 2);
|
|
6097
|
+
i += 2;
|
|
6098
|
+
const gstWeek = getBitU(b, i, 12);
|
|
6099
|
+
i += 12;
|
|
6100
|
+
const tow = getBitU(b, i, 20);
|
|
6101
|
+
i += 20;
|
|
6102
|
+
const e5aDvs = getBitU(b, i, 1);
|
|
6103
|
+
i = 31 * 8;
|
|
6104
|
+
const type2 = getBitU(b, i, 6);
|
|
6105
|
+
i += 6;
|
|
6106
|
+
const iodNav2 = getBitU(b, i, 10);
|
|
6107
|
+
i += 10;
|
|
6108
|
+
const m0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
6109
|
+
i += 32;
|
|
6110
|
+
const omegaDot = getBitS(b, i, 24) * 2 ** -43 * GPS_PI;
|
|
6111
|
+
i += 24;
|
|
6112
|
+
const e = getBitU(b, i, 32) * 2 ** -33;
|
|
6113
|
+
i += 32;
|
|
6114
|
+
const sqrtA = getBitU(b, i, 32) * 2 ** -19;
|
|
6115
|
+
i += 32;
|
|
6116
|
+
const omega0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
6117
|
+
i += 32;
|
|
6118
|
+
const idot = getBitS(b, i, 14) * 2 ** -43 * GPS_PI;
|
|
6119
|
+
i = 62 * 8;
|
|
6120
|
+
const type3 = getBitU(b, i, 6);
|
|
6121
|
+
i += 6;
|
|
6122
|
+
const iodNav3 = getBitU(b, i, 10);
|
|
6123
|
+
i += 10;
|
|
6124
|
+
const i0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
6125
|
+
i += 32;
|
|
6126
|
+
const omega = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
6127
|
+
i += 32;
|
|
6128
|
+
const deltaN = getBitS(b, i, 16) * 2 ** -43 * GPS_PI;
|
|
6129
|
+
i += 16;
|
|
6130
|
+
const cuc = getBitS(b, i, 16) * 2 ** -29;
|
|
6131
|
+
i += 16;
|
|
6132
|
+
const cus = getBitS(b, i, 16) * 2 ** -29;
|
|
6133
|
+
i += 16;
|
|
6134
|
+
const crc = getBitS(b, i, 16) * 2 ** -5;
|
|
6135
|
+
i += 16;
|
|
6136
|
+
const crs = getBitS(b, i, 16) * 2 ** -5;
|
|
6137
|
+
i += 16;
|
|
6138
|
+
const toes = getBitU(b, i, 14) * 60;
|
|
6139
|
+
i = 93 * 8;
|
|
6140
|
+
const type4 = getBitU(b, i, 6);
|
|
6141
|
+
i += 6;
|
|
6142
|
+
const iodNav4 = getBitU(b, i, 10);
|
|
6143
|
+
i += 10;
|
|
6144
|
+
const cic = getBitS(b, i, 16) * 2 ** -29;
|
|
6145
|
+
i += 16;
|
|
6146
|
+
const cis = getBitS(b, i, 16) * 2 ** -29;
|
|
6147
|
+
if (type1 !== 1 || type2 !== 2 || type3 !== 3 || type4 !== 4) return null;
|
|
6148
|
+
if (iodNav1 !== iodNav2 || iodNav1 !== iodNav3 || iodNav1 !== iodNav4)
|
|
6149
|
+
return null;
|
|
6150
|
+
if (svid < 1 || svid > 36) return null;
|
|
6151
|
+
const week = weekOfToe(gstWeek, tow, toes) + GST_GPS_WEEK_OFFSET;
|
|
6152
|
+
const tocDate = gpsDate2(week, tocs);
|
|
6153
|
+
return {
|
|
6154
|
+
system: "E",
|
|
6155
|
+
prn: `E${two2(svid)}`,
|
|
6156
|
+
toc: tocDate.getTime() / 1e3 % SEC_PER_WEEK5,
|
|
6157
|
+
tocDate,
|
|
6158
|
+
af0,
|
|
6159
|
+
af1,
|
|
6160
|
+
af2,
|
|
6161
|
+
iode: iodNav1,
|
|
6162
|
+
crs,
|
|
6163
|
+
deltaN,
|
|
6164
|
+
m0,
|
|
6165
|
+
cuc,
|
|
6166
|
+
e,
|
|
6167
|
+
cus,
|
|
6168
|
+
sqrtA,
|
|
6169
|
+
toe: toes,
|
|
6170
|
+
cic,
|
|
6171
|
+
omega0,
|
|
6172
|
+
cis,
|
|
6173
|
+
i0,
|
|
6174
|
+
crc,
|
|
6175
|
+
omega,
|
|
6176
|
+
omegaDot,
|
|
6177
|
+
idot,
|
|
6178
|
+
week,
|
|
6179
|
+
svHealth: e5aHs << 4 | e5aDvs << 3,
|
|
6180
|
+
tgd: bgdE5a
|
|
6181
|
+
};
|
|
6182
|
+
}
|
|
6183
|
+
var dedupKey = (eph) => `${eph.iode}:${eph.toe}:${eph.tocDate.getTime()}`;
|
|
6184
|
+
var GalInavAssembler = class {
|
|
6185
|
+
sats = /* @__PURE__ */ new Map();
|
|
6186
|
+
/**
|
|
6187
|
+
* Push one I/NAV page pair for satellite `prn` (1-36): the 234-bit
|
|
6188
|
+
* even+odd concatenation, even part first with its 6 tail bits
|
|
6189
|
+
* removed, bit 0 = the even part's Even/Odd bit (≥ 17 bytes).
|
|
6190
|
+
* Returns the newly completed ephemeris, or null. Pages that are
|
|
6191
|
+
* not an even/odd nominal pair, alert pages and word types outside
|
|
6192
|
+
* 1-5 are ignored.
|
|
6193
|
+
*/
|
|
6194
|
+
push(prn, page) {
|
|
6195
|
+
if (prn < 1 || prn > 36 || page.length < 17) return null;
|
|
6196
|
+
if (getBitU(page, 0, 1) !== 0 || getBitU(page, 114, 1) !== 1) return null;
|
|
6197
|
+
if (getBitU(page, 1, 1) === 1 || getBitU(page, 115, 1) === 1) return null;
|
|
6198
|
+
const type = getBitU(page, 2, 6);
|
|
6199
|
+
if (type < 1 || type > 5) return null;
|
|
6200
|
+
let sat = this.sats.get(prn);
|
|
6201
|
+
if (!sat) {
|
|
6202
|
+
sat = { words: new Uint8Array(96) };
|
|
6203
|
+
this.sats.set(prn, sat);
|
|
6204
|
+
}
|
|
6205
|
+
for (let k = 0; k < 14; k++)
|
|
6206
|
+
sat.words[type * 16 + k] = getBitU(page, 2 + 8 * k, 8);
|
|
6207
|
+
sat.words[type * 16 + 14] = getBitU(page, 116, 8);
|
|
6208
|
+
sat.words[type * 16 + 15] = getBitU(page, 124, 8);
|
|
6209
|
+
if (type !== 5) return null;
|
|
6210
|
+
const eph = decodeGalInavWords(sat.words);
|
|
6211
|
+
if (!eph || eph.prn !== `E${two2(prn)}`) return null;
|
|
6212
|
+
const key = dedupKey(eph);
|
|
6213
|
+
if (key === sat.lastKey) return null;
|
|
6214
|
+
sat.lastKey = key;
|
|
6215
|
+
return eph;
|
|
6216
|
+
}
|
|
6217
|
+
};
|
|
6218
|
+
var GalFnavAssembler = class {
|
|
6219
|
+
sats = /* @__PURE__ */ new Map();
|
|
6220
|
+
/**
|
|
6221
|
+
* Push one F/NAV page for satellite `prn` (1-36): 244 bits with the
|
|
6222
|
+
* sync field stripped, bit 0 = first page-type bit (≥ 31 bytes).
|
|
6223
|
+
* Returns the newly completed ephemeris, or null. Dummy pages
|
|
6224
|
+
* (type 63) and page types outside 1-4 are ignored.
|
|
6225
|
+
*/
|
|
6226
|
+
push(prn, page) {
|
|
6227
|
+
if (prn < 1 || prn > 36 || page.length < 31) return null;
|
|
6228
|
+
const type = getBitU(page, 0, 6);
|
|
6229
|
+
if (type < 1 || type > 4) return null;
|
|
6230
|
+
let sat = this.sats.get(prn);
|
|
6231
|
+
if (!sat) {
|
|
6232
|
+
sat = { words: new Uint8Array(124) };
|
|
6233
|
+
this.sats.set(prn, sat);
|
|
6234
|
+
}
|
|
6235
|
+
sat.words.set(page.subarray(0, 31), (type - 1) * 31);
|
|
6236
|
+
if (type !== 4) return null;
|
|
6237
|
+
const eph = decodeGalFnavPages(sat.words);
|
|
6238
|
+
if (!eph || eph.prn !== `E${two2(prn)}`) return null;
|
|
6239
|
+
const key = dedupKey(eph);
|
|
6240
|
+
if (key === sat.lastKey) return null;
|
|
6241
|
+
sat.lastKey = key;
|
|
6242
|
+
return eph;
|
|
6243
|
+
}
|
|
6244
|
+
};
|
|
6245
|
+
|
|
6246
|
+
// src/sbf/rawnav-gal.ts
|
|
6247
|
+
var INAV_SOURCES = [17, 21, 22];
|
|
6248
|
+
var FNAV_SOURCES = [20, 22];
|
|
6249
|
+
function parseSbfGalNav(data) {
|
|
6250
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
6251
|
+
const ephemerides = [];
|
|
6252
|
+
const inav = new GalInavAssembler();
|
|
6253
|
+
const fnav = new GalFnavAssembler();
|
|
6254
|
+
let badCrc = 0;
|
|
6255
|
+
let messages = 0;
|
|
6256
|
+
scanSbfFrames(data, view, (id, b, len) => {
|
|
6257
|
+
if (id !== 4022 && id !== 4023 || len < 52) return;
|
|
6258
|
+
messages++;
|
|
6259
|
+
const prnStr = svidToPrn(data[b + 14]);
|
|
6260
|
+
if (!prnStr || prnStr[0] !== "E") return;
|
|
6261
|
+
const prn = parseInt(prnStr.slice(1), 10);
|
|
6262
|
+
const source = data[b + 17] & 31;
|
|
6263
|
+
const page = new Uint8Array(32);
|
|
6264
|
+
for (let k = 0; k < 8; k++) {
|
|
6265
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
6266
|
+
page[4 * k] = w >>> 24;
|
|
6267
|
+
page[4 * k + 1] = w >>> 16 & 255;
|
|
6268
|
+
page[4 * k + 2] = w >>> 8 & 255;
|
|
6269
|
+
page[4 * k + 3] = w & 255;
|
|
6270
|
+
}
|
|
6271
|
+
let eph;
|
|
6272
|
+
let src;
|
|
6273
|
+
if (id === 4023) {
|
|
6274
|
+
src = "inav";
|
|
6275
|
+
if (!INAV_SOURCES.includes(source)) return;
|
|
6276
|
+
if (getBitU2(page, 0) !== 0 || getBitU2(page, 114) !== 1) return;
|
|
6277
|
+
if (!galInavPageCrcOk(page)) {
|
|
6278
|
+
badCrc++;
|
|
6279
|
+
return;
|
|
6280
|
+
}
|
|
6281
|
+
eph = inav.push(prn, page);
|
|
6282
|
+
} else {
|
|
6283
|
+
src = "fnav";
|
|
6284
|
+
if (!FNAV_SOURCES.includes(source)) return;
|
|
6285
|
+
if (isFnavDummy(page)) return;
|
|
6286
|
+
if (!galFnavPageCrcOk(page)) {
|
|
6287
|
+
badCrc++;
|
|
6288
|
+
return;
|
|
6289
|
+
}
|
|
6290
|
+
eph = fnav.push(prn, page);
|
|
6291
|
+
}
|
|
6292
|
+
if (eph) ephemerides.push({ ...eph, source: src });
|
|
6293
|
+
});
|
|
6294
|
+
return { ephemerides, badCrc, messages };
|
|
6295
|
+
}
|
|
6296
|
+
function getBitU2(buff, pos) {
|
|
6297
|
+
return buff[pos >> 3] >> 7 - (pos & 7) & 1;
|
|
6298
|
+
}
|
|
6299
|
+
function isFnavDummy(page) {
|
|
6300
|
+
return page[0] >> 2 === 63;
|
|
6301
|
+
}
|
|
6302
|
+
|
|
6303
|
+
// src/navbits/bds.ts
|
|
6304
|
+
var BDT_EPOCH_MS2 = Date.UTC(2006, 0, 1);
|
|
6305
|
+
var SEC_PER_WEEK6 = 7 * 86400;
|
|
6306
|
+
var MS_PER_WEEK4 = SEC_PER_WEEK6 * 1e3;
|
|
6307
|
+
var HALF_WEEK3 = 302400;
|
|
6308
|
+
var sowOf2 = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK6;
|
|
6309
|
+
var BDS_SUBFRAME_BYTES = 38;
|
|
6310
|
+
function getBitU22(b, p1, l1, p2, l2) {
|
|
6311
|
+
return getBitU(b, p1, l1) * 2 ** l2 + getBitU(b, p2, l2);
|
|
6312
|
+
}
|
|
6313
|
+
function getBitS2(b, p1, l1, p2, l2) {
|
|
6314
|
+
return getBitS(b, p1, l1) * 2 ** l2 + getBitU(b, p2, l2);
|
|
6315
|
+
}
|
|
6316
|
+
function getBitU3(b, p1, l1, p2, l2, p3, l3) {
|
|
6317
|
+
return getBitU(b, p1, l1) * 2 ** (l2 + l3) + getBitU(b, p2, l2) * 2 ** l3 + getBitU(b, p3, l3);
|
|
6318
|
+
}
|
|
6319
|
+
function getBitS3(b, p1, l1, p2, l2, p3, l3) {
|
|
6320
|
+
return getBitS(b, p1, l1) * 2 ** (l2 + l3) + getBitU(b, p2, l2) * 2 ** l3 + getBitU(b, p3, l3);
|
|
6321
|
+
}
|
|
6322
|
+
var mergeS = (hi, lo, n) => hi * 2 ** n + lo;
|
|
6323
|
+
function bchOk(cw) {
|
|
6324
|
+
for (let i = 14; i >= 4; i--) {
|
|
6325
|
+
if (cw & 1 << i) cw ^= 19 << i - 4;
|
|
6326
|
+
}
|
|
6327
|
+
return cw === 0;
|
|
6328
|
+
}
|
|
6329
|
+
function bdsSubframeParityOk(subframe) {
|
|
6330
|
+
if (subframe.length < BDS_SUBFRAME_BYTES) return false;
|
|
6331
|
+
if (!bchOk(getBitU(subframe, 15, 15))) return false;
|
|
6332
|
+
for (let w = 1; w < 10; w++) {
|
|
6333
|
+
const base = 30 * w;
|
|
6334
|
+
const cw1 = getBitU(subframe, base, 11) * 16 + getBitU(subframe, base + 22, 4);
|
|
6335
|
+
const cw2 = getBitU(subframe, base + 11, 11) * 16 + getBitU(subframe, base + 26, 4);
|
|
6336
|
+
if (!bchOk(cw1) || !bchOk(cw2)) return false;
|
|
6337
|
+
}
|
|
6338
|
+
return true;
|
|
6339
|
+
}
|
|
6340
|
+
function buildBdsEphemeris(prn, f) {
|
|
6341
|
+
let week = f.week;
|
|
6342
|
+
if (f.toes < f.sow - HALF_WEEK3) week++;
|
|
6343
|
+
else if (f.toes > f.sow + HALF_WEEK3) week--;
|
|
6344
|
+
const tocDate = new Date(BDT_EPOCH_MS2 + week * MS_PER_WEEK4 + f.tocSec * 1e3);
|
|
6345
|
+
return {
|
|
6346
|
+
system: "C",
|
|
6347
|
+
prn,
|
|
6348
|
+
toc: sowOf2(tocDate.getTime()),
|
|
6349
|
+
tocDate,
|
|
6350
|
+
af0: f.af0,
|
|
6351
|
+
af1: f.af1,
|
|
6352
|
+
af2: f.af2,
|
|
6353
|
+
// AODE is not in the ephemeris subframes; RTKLIB derives the RINEX
|
|
6354
|
+
// IODE/AODE slot from toc per the BDS ICD update schedule.
|
|
6355
|
+
iode: Math.floor(f.tocSec / 720) % 240,
|
|
6356
|
+
crs: f.crs,
|
|
6357
|
+
deltaN: f.deltaN,
|
|
6358
|
+
m0: f.m0,
|
|
6359
|
+
cuc: f.cuc,
|
|
6360
|
+
e: f.e,
|
|
6361
|
+
cus: f.cus,
|
|
6362
|
+
sqrtA: f.sqrtA,
|
|
6363
|
+
toe: f.toes,
|
|
6364
|
+
cic: f.cic,
|
|
6365
|
+
omega0: f.omega0,
|
|
6366
|
+
cis: f.cis,
|
|
6367
|
+
i0: f.i0,
|
|
6368
|
+
crc: f.crc,
|
|
6369
|
+
omega: f.omega,
|
|
6370
|
+
omegaDot: f.omegaDot,
|
|
6371
|
+
idot: f.idot,
|
|
6372
|
+
week,
|
|
6373
|
+
// RINEX BDS week field is the BDT week of toe
|
|
6374
|
+
svHealth: f.svh,
|
|
6375
|
+
// SatH1
|
|
6376
|
+
tgd: f.tgd1
|
|
6377
|
+
// TGD1 (B1) — RINEX slot
|
|
6378
|
+
};
|
|
6379
|
+
}
|
|
6380
|
+
function decodeBdsD1Frame(subframes, opts = {}) {
|
|
6381
|
+
if (subframes.length < 3 * BDS_SUBFRAME_BYTES) return null;
|
|
6382
|
+
const b = subframes;
|
|
6383
|
+
let i = 8 * 38 * 0;
|
|
6384
|
+
const frn1 = getBitU(b, i + 15, 3);
|
|
6385
|
+
const sow1 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
6386
|
+
const svh = getBitU(b, i + 42, 1);
|
|
6387
|
+
const week = getBitU(b, i + 60, 13);
|
|
6388
|
+
const tocSec = getBitU22(b, i + 73, 9, i + 90, 8) * 8;
|
|
6389
|
+
const tgd1 = getBitS(b, i + 98, 10) * 0.1 * 1e-9;
|
|
6390
|
+
const af2 = getBitS(b, i + 214, 11) * 2 ** -66;
|
|
6391
|
+
const af0 = getBitS2(b, i + 225, 7, i + 240, 17) * 2 ** -33;
|
|
6392
|
+
const af1 = getBitS2(b, i + 257, 5, i + 270, 17) * 2 ** -50;
|
|
6393
|
+
i = 8 * 38 * 1;
|
|
6394
|
+
const frn2 = getBitU(b, i + 15, 3);
|
|
6395
|
+
const sow2 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
6396
|
+
const deltaN = getBitS2(b, i + 42, 10, i + 60, 6) * 2 ** -43 * GPS_PI;
|
|
6397
|
+
const cuc = getBitS2(b, i + 66, 16, i + 90, 2) * 2 ** -31;
|
|
6398
|
+
const m0 = getBitS2(b, i + 92, 20, i + 120, 12) * 2 ** -31 * GPS_PI;
|
|
6399
|
+
const e = getBitU22(b, i + 132, 10, i + 150, 22) * 2 ** -33;
|
|
6400
|
+
const cus = getBitS(b, i + 180, 18) * 2 ** -31;
|
|
6401
|
+
const crc = getBitS2(b, i + 198, 4, i + 210, 14) * 2 ** -6;
|
|
6402
|
+
const crs = getBitS2(b, i + 224, 8, i + 240, 10) * 2 ** -6;
|
|
6403
|
+
const sqrtA = getBitU22(b, i + 250, 12, i + 270, 20) * 2 ** -19;
|
|
6404
|
+
const toe1 = getBitU(b, i + 290, 2);
|
|
6405
|
+
i = 8 * 38 * 2;
|
|
6406
|
+
const frn3 = getBitU(b, i + 15, 3);
|
|
6407
|
+
const sow3 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
6408
|
+
const toe2 = getBitU22(b, i + 42, 10, i + 60, 5);
|
|
6409
|
+
const i0 = getBitS2(b, i + 65, 17, i + 90, 15) * 2 ** -31 * GPS_PI;
|
|
6410
|
+
const cic = getBitS2(b, i + 105, 7, i + 120, 11) * 2 ** -31;
|
|
6411
|
+
const omegaDot = getBitS2(b, i + 131, 11, i + 150, 13) * 2 ** -43 * GPS_PI;
|
|
6412
|
+
const cis = getBitS2(b, i + 163, 9, i + 180, 9) * 2 ** -31;
|
|
6413
|
+
const idot = getBitS2(b, i + 189, 13, i + 210, 1) * 2 ** -43 * GPS_PI;
|
|
6414
|
+
const omega0 = getBitS2(b, i + 211, 21, i + 240, 11) * 2 ** -31 * GPS_PI;
|
|
6415
|
+
const omega = getBitS2(b, i + 251, 11, i + 270, 21) * 2 ** -31 * GPS_PI;
|
|
6416
|
+
const toes = (toe1 * 2 ** 15 + toe2) * 8;
|
|
6417
|
+
if (frn1 !== 1 || frn2 !== 2 || frn3 !== 3) return null;
|
|
6418
|
+
if (sow2 !== sow1 + 6 || sow3 !== sow2 + 6) return null;
|
|
6419
|
+
if (tocSec !== toes) return null;
|
|
6420
|
+
return buildBdsEphemeris(opts.prn ?? "C00", {
|
|
6421
|
+
week,
|
|
6422
|
+
sow: sow1,
|
|
6423
|
+
toes,
|
|
6424
|
+
tocSec,
|
|
6425
|
+
svh,
|
|
6426
|
+
tgd1,
|
|
6427
|
+
af0,
|
|
6428
|
+
af1,
|
|
6429
|
+
af2,
|
|
6430
|
+
crs,
|
|
6431
|
+
deltaN,
|
|
6432
|
+
m0,
|
|
6433
|
+
cuc,
|
|
6434
|
+
e,
|
|
6435
|
+
cus,
|
|
6436
|
+
sqrtA,
|
|
6437
|
+
cic,
|
|
6438
|
+
omega0,
|
|
6439
|
+
cis,
|
|
6440
|
+
i0,
|
|
6441
|
+
crc,
|
|
6442
|
+
omega,
|
|
6443
|
+
omegaDot,
|
|
6444
|
+
idot
|
|
6445
|
+
});
|
|
6446
|
+
}
|
|
6447
|
+
function decodeBdsD2Frame(pages, opts = {}) {
|
|
6448
|
+
if (pages.length < 10 * BDS_SUBFRAME_BYTES) return null;
|
|
6449
|
+
const b = pages;
|
|
6450
|
+
let i = 8 * 38 * 0;
|
|
6451
|
+
const pgn1 = getBitU(b, i + 42, 4);
|
|
6452
|
+
const sow1 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
6453
|
+
const svh = getBitU(b, i + 46, 1);
|
|
6454
|
+
const week = getBitU(b, i + 64, 13);
|
|
6455
|
+
const tocSec = getBitU22(b, i + 77, 5, i + 90, 12) * 8;
|
|
6456
|
+
const tgd1 = getBitS(b, i + 102, 10) * 0.1 * 1e-9;
|
|
6457
|
+
i = 8 * 38 * 2;
|
|
6458
|
+
const pgn3 = getBitU(b, i + 42, 4);
|
|
6459
|
+
const sow3 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
6460
|
+
const af0 = getBitS2(b, i + 100, 12, i + 120, 12) * 2 ** -33;
|
|
6461
|
+
const af1p3 = getBitS(b, i + 132, 4);
|
|
6462
|
+
i = 8 * 38 * 3;
|
|
6463
|
+
const pgn4 = getBitU(b, i + 42, 4);
|
|
6464
|
+
const sow4 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
6465
|
+
const af1p4 = getBitU22(b, i + 46, 6, i + 60, 12);
|
|
6466
|
+
const af2 = getBitS2(b, i + 72, 10, i + 90, 1) * 2 ** -66;
|
|
6467
|
+
const deltaN = getBitS(b, i + 96, 16) * 2 ** -43 * GPS_PI;
|
|
6468
|
+
const cucp4 = getBitS(b, i + 120, 14);
|
|
6469
|
+
i = 8 * 38 * 4;
|
|
6470
|
+
const pgn5 = getBitU(b, i + 42, 4);
|
|
6471
|
+
const sow5 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
6472
|
+
const cucp5 = getBitU(b, i + 46, 4);
|
|
6473
|
+
const m0 = getBitS3(b, i + 50, 2, i + 60, 22, i + 90, 8) * 2 ** -31 * GPS_PI;
|
|
6474
|
+
const cus = getBitS2(b, i + 98, 14, i + 120, 4) * 2 ** -31;
|
|
6475
|
+
const ep5 = getBitS(b, i + 124, 10);
|
|
6476
|
+
i = 8 * 38 * 5;
|
|
6477
|
+
const pgn6 = getBitU(b, i + 42, 4);
|
|
6478
|
+
const sow6 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
6479
|
+
const ep6 = getBitU22(b, i + 46, 6, i + 60, 16);
|
|
6480
|
+
const sqrtA = getBitU3(b, i + 76, 6, i + 90, 22, i + 120, 4) * 2 ** -19;
|
|
6481
|
+
const cicp6 = getBitS(b, i + 124, 10);
|
|
6482
|
+
i = 8 * 38 * 6;
|
|
6483
|
+
const pgn7 = getBitU(b, i + 42, 4);
|
|
6484
|
+
const sow7 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
6485
|
+
const cicp7 = getBitU22(b, i + 46, 6, i + 60, 2);
|
|
6486
|
+
const cis = getBitS(b, i + 62, 18) * 2 ** -31;
|
|
6487
|
+
const toes = getBitU22(b, i + 80, 2, i + 90, 15) * 8;
|
|
6488
|
+
const i0p7 = getBitS2(b, i + 105, 7, i + 120, 14);
|
|
6489
|
+
i = 8 * 38 * 7;
|
|
6490
|
+
const pgn8 = getBitU(b, i + 42, 4);
|
|
6491
|
+
const sow8 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
6492
|
+
const i0p8 = getBitU22(b, i + 46, 6, i + 60, 5);
|
|
6493
|
+
const crc = getBitS2(b, i + 65, 17, i + 90, 1) * 2 ** -6;
|
|
6494
|
+
const crs = getBitS(b, i + 91, 18) * 2 ** -6;
|
|
6495
|
+
const omegaDotP8 = getBitS2(b, i + 109, 3, i + 120, 16);
|
|
6496
|
+
i = 8 * 38 * 8;
|
|
6497
|
+
const pgn9 = getBitU(b, i + 42, 4);
|
|
6498
|
+
const sow9 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
6499
|
+
const omegaDotP9 = getBitU(b, i + 46, 5);
|
|
6500
|
+
const omega0 = getBitS3(b, i + 51, 1, i + 60, 22, i + 90, 9) * 2 ** -31 * GPS_PI;
|
|
6501
|
+
const omegaP9 = getBitS2(b, i + 99, 13, i + 120, 14);
|
|
6502
|
+
i = 8 * 38 * 9;
|
|
6503
|
+
const pgn10 = getBitU(b, i + 42, 4);
|
|
6504
|
+
const sow10 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
6505
|
+
const omegaP10 = getBitU(b, i + 46, 5);
|
|
6506
|
+
const idot = getBitS2(b, i + 51, 1, i + 60, 13) * 2 ** -43 * GPS_PI;
|
|
6507
|
+
if (pgn1 !== 1 || pgn3 !== 3 || pgn4 !== 4 || pgn5 !== 5 || pgn6 !== 6 || pgn7 !== 7 || pgn8 !== 8 || pgn9 !== 9 || pgn10 !== 10) {
|
|
6508
|
+
return null;
|
|
6509
|
+
}
|
|
6510
|
+
if (sow3 !== sow1 + 6 || sow4 !== sow3 + 3 || sow5 !== sow4 + 3 || sow6 !== sow5 + 3 || sow7 !== sow6 + 3 || sow8 !== sow7 + 3 || sow9 !== sow8 + 3 || sow10 !== sow9 + 3) {
|
|
6511
|
+
return null;
|
|
6512
|
+
}
|
|
6513
|
+
if (tocSec !== toes) return null;
|
|
6514
|
+
return buildBdsEphemeris(opts.prn ?? "C00", {
|
|
6515
|
+
week,
|
|
6516
|
+
sow: sow1,
|
|
6517
|
+
toes,
|
|
6518
|
+
tocSec,
|
|
6519
|
+
svh,
|
|
6520
|
+
tgd1,
|
|
6521
|
+
af0,
|
|
6522
|
+
af1: mergeS(af1p3, af1p4, 18) * 2 ** -50,
|
|
6523
|
+
af2,
|
|
6524
|
+
crs,
|
|
6525
|
+
deltaN,
|
|
6526
|
+
m0,
|
|
6527
|
+
cuc: mergeS(cucp4, cucp5, 4) * 2 ** -31,
|
|
6528
|
+
e: mergeS(ep5, ep6, 22) * 2 ** -33,
|
|
6529
|
+
cus,
|
|
6530
|
+
sqrtA,
|
|
6531
|
+
cic: mergeS(cicp6, cicp7, 8) * 2 ** -31,
|
|
6532
|
+
omega0,
|
|
6533
|
+
cis,
|
|
6534
|
+
i0: mergeS(i0p7, i0p8, 11) * 2 ** -31 * GPS_PI,
|
|
6535
|
+
crc,
|
|
6536
|
+
omega: mergeS(omegaP9, omegaP10, 5) * 2 ** -31 * GPS_PI,
|
|
6537
|
+
omegaDot: mergeS(omegaDotP8, omegaDotP9, 5) * 2 ** -43 * GPS_PI,
|
|
6538
|
+
idot
|
|
6539
|
+
});
|
|
6540
|
+
}
|
|
6541
|
+
function isBdsGeoPrn(prn) {
|
|
6542
|
+
return prn < 6 || prn > 58;
|
|
6543
|
+
}
|
|
6544
|
+
var BdsAssembler = class {
|
|
6545
|
+
sats = /* @__PURE__ */ new Map();
|
|
6546
|
+
/**
|
|
6547
|
+
* Push one 300-bit subframe (38+ bytes, bit 0 = first bit of the
|
|
6548
|
+
* preamble) for the satellite `prn` ("C06"). Returns the newly
|
|
6549
|
+
* completed ephemeris, or null.
|
|
6550
|
+
*/
|
|
6551
|
+
push(prn, subframe) {
|
|
6552
|
+
if (subframe.length < BDS_SUBFRAME_BYTES) return null;
|
|
6553
|
+
const num = parseInt(prn.slice(1), 10);
|
|
6554
|
+
if (!Number.isFinite(num) || num < 1 || num > 63) return null;
|
|
6555
|
+
const id = getBitU(subframe, 15, 3);
|
|
6556
|
+
if (id < 1 || id > 5) return null;
|
|
6557
|
+
let sat = this.sats.get(prn);
|
|
6558
|
+
if (!sat) {
|
|
6559
|
+
sat = { buf: new Uint8Array(10 * BDS_SUBFRAME_BYTES) };
|
|
6560
|
+
this.sats.set(prn, sat);
|
|
6561
|
+
}
|
|
6562
|
+
let eph = null;
|
|
6563
|
+
if (!isBdsGeoPrn(num)) {
|
|
6564
|
+
sat.buf.set(subframe.subarray(0, BDS_SUBFRAME_BYTES), (id - 1) * 38);
|
|
6565
|
+
if (id === 3) eph = decodeBdsD1Frame(sat.buf, { prn });
|
|
6566
|
+
} else {
|
|
6567
|
+
if (id !== 1) return null;
|
|
6568
|
+
const pgn = getBitU(subframe, 42, 4);
|
|
6569
|
+
if (pgn < 1 || pgn > 10) return null;
|
|
6570
|
+
sat.buf.set(subframe.subarray(0, BDS_SUBFRAME_BYTES), (pgn - 1) * 38);
|
|
6571
|
+
if (pgn === 10) eph = decodeBdsD2Frame(sat.buf, { prn });
|
|
6572
|
+
}
|
|
6573
|
+
if (!eph) return null;
|
|
6574
|
+
const key = `${eph.week}:${eph.toe}`;
|
|
6575
|
+
if (key === sat.lastKey) return null;
|
|
6576
|
+
sat.lastKey = key;
|
|
6577
|
+
return eph;
|
|
6578
|
+
}
|
|
6579
|
+
};
|
|
6580
|
+
|
|
6581
|
+
// src/navbits/glo.ts
|
|
6582
|
+
var GPS_EPOCH_MS7 = Date.UTC(1980, 0, 6);
|
|
6583
|
+
var SEC_PER_WEEK7 = 7 * 86400;
|
|
6584
|
+
var SEC_PER_DAY = 86400;
|
|
6585
|
+
var GLO_STRING_BYTES = 10;
|
|
6586
|
+
function getBitG(b, pos, len) {
|
|
6587
|
+
const value = getBitU(b, pos + 1, len - 1);
|
|
6588
|
+
return getBitU(b, pos, 1) && value !== 0 ? -value : value;
|
|
6589
|
+
}
|
|
6590
|
+
var HAMMING_MASKS = [
|
|
6591
|
+
[85, 85, 90, 170, 170, 170, 181, 85, 106, 216, 8],
|
|
6592
|
+
[102, 102, 108, 204, 204, 204, 217, 153, 179, 104, 16],
|
|
6593
|
+
[135, 135, 143, 15, 15, 15, 30, 30, 60, 112, 32],
|
|
6594
|
+
[7, 248, 15, 240, 15, 240, 31, 224, 63, 128, 64],
|
|
6595
|
+
[248, 0, 15, 255, 240, 0, 31, 255, 192, 0, 128],
|
|
6596
|
+
[0, 0, 15, 255, 255, 255, 224, 0, 0, 1, 0],
|
|
6597
|
+
[255, 255, 240, 0, 0, 0, 0, 0, 0, 2, 0],
|
|
6598
|
+
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 248]
|
|
6599
|
+
];
|
|
6600
|
+
function testGloString(buff) {
|
|
6601
|
+
if (buff.length < 11) return false;
|
|
6602
|
+
let n = 0;
|
|
6603
|
+
let cs = 0;
|
|
6604
|
+
for (const mask of HAMMING_MASKS) {
|
|
6605
|
+
cs = 0;
|
|
6606
|
+
for (let j = 0; j < 11; j++) {
|
|
6607
|
+
let x = buff[j] & mask[j];
|
|
6608
|
+
x ^= x >> 4;
|
|
6609
|
+
x ^= x >> 2;
|
|
6610
|
+
x ^= x >> 1;
|
|
6611
|
+
cs ^= x & 1;
|
|
6612
|
+
}
|
|
6613
|
+
if (cs) n++;
|
|
6614
|
+
}
|
|
6615
|
+
return n === 0 || n === 2 && cs === 1;
|
|
6616
|
+
}
|
|
6617
|
+
function decodeGloStrings(strings, refDate, opts = {}) {
|
|
6618
|
+
if (strings.length < 4 * GLO_STRING_BYTES) return null;
|
|
6619
|
+
const b = strings;
|
|
6620
|
+
let i = 1;
|
|
6621
|
+
const frn1 = getBitU(b, i, 4);
|
|
6622
|
+
i += 4 + 2;
|
|
6623
|
+
i += 2;
|
|
6624
|
+
const tkH = getBitU(b, i, 5);
|
|
6625
|
+
i += 5;
|
|
6626
|
+
const tkM = getBitU(b, i, 6);
|
|
6627
|
+
i += 6;
|
|
6628
|
+
const tkS = getBitU(b, i, 1) * 30;
|
|
6629
|
+
i += 1;
|
|
6630
|
+
const xDot = getBitG(b, i, 24) * 2 ** -20;
|
|
6631
|
+
i += 24;
|
|
6632
|
+
const xAcc = getBitG(b, i, 5) * 2 ** -30;
|
|
6633
|
+
i += 5;
|
|
6634
|
+
const x = getBitG(b, i, 27) * 2 ** -11;
|
|
6635
|
+
i = 80 + 1;
|
|
6636
|
+
const frn2 = getBitU(b, i, 4);
|
|
6637
|
+
i += 4;
|
|
6638
|
+
const bn = getBitU(b, i, 1);
|
|
6639
|
+
i += 1 + 2;
|
|
6640
|
+
i += 1;
|
|
6641
|
+
const tb = getBitU(b, i, 7);
|
|
6642
|
+
i += 7 + 5;
|
|
6643
|
+
const yDot = getBitG(b, i, 24) * 2 ** -20;
|
|
6644
|
+
i += 24;
|
|
6645
|
+
const yAcc = getBitG(b, i, 5) * 2 ** -30;
|
|
6646
|
+
i += 5;
|
|
6647
|
+
const y = getBitG(b, i, 27) * 2 ** -11;
|
|
6648
|
+
i = 160 + 1;
|
|
6649
|
+
const frn3 = getBitU(b, i, 4);
|
|
6650
|
+
i += 4;
|
|
6651
|
+
i += 1;
|
|
6652
|
+
const gammaN = getBitG(b, i, 11) * 2 ** -40;
|
|
6653
|
+
i += 11 + 1;
|
|
6654
|
+
i += 2;
|
|
6655
|
+
i += 1;
|
|
6656
|
+
const zDot = getBitG(b, i, 24) * 2 ** -20;
|
|
6657
|
+
i += 24;
|
|
6658
|
+
const zAcc = getBitG(b, i, 5) * 2 ** -30;
|
|
6659
|
+
i += 5;
|
|
6660
|
+
const z = getBitG(b, i, 27) * 2 ** -11;
|
|
6661
|
+
i = 240 + 1;
|
|
6662
|
+
const frn4 = getBitU(b, i, 4);
|
|
6663
|
+
i += 4;
|
|
6664
|
+
const tauN = getBitG(b, i, 22) * 2 ** -30;
|
|
6665
|
+
i += 22;
|
|
6666
|
+
i += 5;
|
|
6667
|
+
i += 5;
|
|
6668
|
+
i += 14;
|
|
6669
|
+
i += 1;
|
|
6670
|
+
i += 4;
|
|
6671
|
+
i += 3;
|
|
6672
|
+
i += 11;
|
|
6673
|
+
const slot = getBitU(b, i, 5);
|
|
6674
|
+
if (frn1 !== 1 || frn2 !== 2 || frn3 !== 3 || frn4 !== 4) return null;
|
|
6675
|
+
if (slot < 1 || slot > 27) return null;
|
|
6676
|
+
const utcSec = (getUtcDate(refDate).getTime() - GPS_EPOCH_MS7) / 1e3;
|
|
6677
|
+
const week = Math.floor(utcSec / SEC_PER_WEEK7);
|
|
6678
|
+
let tow = utcSec - week * SEC_PER_WEEK7;
|
|
6679
|
+
const tod = tow % SEC_PER_DAY;
|
|
6680
|
+
tow -= tod;
|
|
6681
|
+
let tof = tkH * 3600 + tkM * 60 + tkS - 10800;
|
|
6682
|
+
if (tof < tod - 43200) tof += SEC_PER_DAY;
|
|
6683
|
+
else if (tof > tod + 43200) tof -= SEC_PER_DAY;
|
|
6684
|
+
let toe = tb * 900 - 10800;
|
|
6685
|
+
if (toe < tod - 43200) toe += SEC_PER_DAY;
|
|
6686
|
+
else if (toe > tod + 43200) toe -= SEC_PER_DAY;
|
|
6687
|
+
return {
|
|
6688
|
+
system: "R",
|
|
6689
|
+
prn: `R${String(slot).padStart(2, "0")}`,
|
|
6690
|
+
// RINEX GLONASS epochs are UTC: build the UTC toe Date directly.
|
|
6691
|
+
tocDate: new Date(GPS_EPOCH_MS7 + (week * SEC_PER_WEEK7 + tow + toe) * 1e3),
|
|
6692
|
+
tauN: -tauN,
|
|
6693
|
+
// RINEX stores −τn; the SIS carries τn (ICD sign)
|
|
6694
|
+
gammaN,
|
|
6695
|
+
// v3 message frame time: seconds of the UTC week (RTKLIB tof).
|
|
6696
|
+
messageFrameTime: ((tow + tof) % SEC_PER_WEEK7 + SEC_PER_WEEK7) % SEC_PER_WEEK7,
|
|
6697
|
+
x,
|
|
6698
|
+
xDot,
|
|
6699
|
+
xAcc,
|
|
6700
|
+
y,
|
|
6701
|
+
yDot,
|
|
6702
|
+
yAcc,
|
|
6703
|
+
z,
|
|
6704
|
+
zDot,
|
|
6705
|
+
zAcc,
|
|
6706
|
+
// MSB of the 3-bit Bn word — the unhealthy flag RINEX carries
|
|
6707
|
+
health: bn,
|
|
6708
|
+
freqNum: opts.freqNum ?? 0
|
|
6709
|
+
};
|
|
6710
|
+
}
|
|
6711
|
+
var GloStringAssembler = class {
|
|
6712
|
+
sats = /* @__PURE__ */ new Map();
|
|
6713
|
+
/**
|
|
6714
|
+
* Push one navigation string (10+ bytes, bit 0 = string bit 85) for
|
|
6715
|
+
* the satellite `prn` ("R09"), received at the GPS-scale `time`.
|
|
6716
|
+
* Returns the newly completed ephemeris, or null. The decoded
|
|
6717
|
+
* string-4 slot number must match `prn`, or nothing is emitted.
|
|
6718
|
+
*/
|
|
6719
|
+
push(prn, str, time, freqNum = 0) {
|
|
6720
|
+
if (str.length < GLO_STRING_BYTES) return null;
|
|
6721
|
+
const m = getBitU(str, 1, 4);
|
|
6722
|
+
if (m < 1) return null;
|
|
6723
|
+
const sec = Math.floor(time.getTime() / 1e3);
|
|
6724
|
+
let sat = this.sats.get(prn);
|
|
6725
|
+
if (!sat) {
|
|
6726
|
+
sat = { buf: new Uint8Array(4 * GLO_STRING_BYTES), batchSec: sec };
|
|
6727
|
+
this.sats.set(prn, sat);
|
|
6728
|
+
} else if (Math.abs(sec - sat.batchSec) > 30) {
|
|
6729
|
+
sat.buf.fill(0);
|
|
6730
|
+
sat.batchSec = sec;
|
|
6731
|
+
}
|
|
6732
|
+
if (m > 4) return null;
|
|
6733
|
+
sat.buf.set(str.subarray(0, GLO_STRING_BYTES), (m - 1) * 10);
|
|
6734
|
+
if (m !== 4) return null;
|
|
6735
|
+
const eph = decodeGloStrings(sat.buf, time, { freqNum });
|
|
6736
|
+
if (!eph || eph.prn !== prn) return null;
|
|
6737
|
+
const key = `${eph.tocDate.getTime()}:${eph.health}`;
|
|
6738
|
+
if (key === sat.lastKey) return null;
|
|
6739
|
+
sat.lastKey = key;
|
|
6740
|
+
return eph;
|
|
6741
|
+
}
|
|
6742
|
+
};
|
|
6743
|
+
|
|
6744
|
+
// src/sbf/rawnav-bds.ts
|
|
6745
|
+
var GPS_EPOCH_MS8 = Date.UTC(1980, 0, 6);
|
|
6746
|
+
var MS_PER_WEEK5 = 7 * 86400 * 1e3;
|
|
6747
|
+
var TOW_DNU = 4294967295;
|
|
6748
|
+
var WNC_DNU = 65535;
|
|
6749
|
+
function parseSbfBdsNav(data) {
|
|
6750
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
6751
|
+
const ephemerides = [];
|
|
6752
|
+
const assembler = new BdsAssembler();
|
|
6753
|
+
let badCrc = 0;
|
|
6754
|
+
let messages = 0;
|
|
6755
|
+
scanSbfFrames(data, view, (id, b, len) => {
|
|
6756
|
+
if (id !== 4047 || len < 60) return;
|
|
6757
|
+
messages++;
|
|
6758
|
+
const prn = svidToPrn(view.getUint8(b + 14));
|
|
6759
|
+
if (!prn || prn[0] !== "C") return;
|
|
6760
|
+
const sf = new Uint8Array(38);
|
|
6761
|
+
for (let k = 0; k < 10; k++) {
|
|
6762
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
6763
|
+
sf[4 * k] = w >>> 24;
|
|
6764
|
+
if (k < 9) {
|
|
6765
|
+
sf[4 * k + 1] = w >>> 16 & 255;
|
|
6766
|
+
sf[4 * k + 2] = w >>> 8 & 255;
|
|
6767
|
+
sf[4 * k + 3] = w & 255;
|
|
6768
|
+
} else {
|
|
6769
|
+
sf[37] = w >>> 16 & 240;
|
|
6770
|
+
}
|
|
6771
|
+
}
|
|
6772
|
+
if (!bdsSubframeParityOk(sf)) {
|
|
6773
|
+
badCrc++;
|
|
6774
|
+
return;
|
|
6775
|
+
}
|
|
6776
|
+
const eph = assembler.push(prn, sf);
|
|
6777
|
+
if (eph) ephemerides.push(eph);
|
|
6778
|
+
});
|
|
6779
|
+
return { ephemerides, badCrc, messages };
|
|
6780
|
+
}
|
|
6781
|
+
function parseSbfGloNav(data) {
|
|
6782
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
6783
|
+
const ephemerides = [];
|
|
6784
|
+
const assembler = new GloStringAssembler();
|
|
6785
|
+
let badCrc = 0;
|
|
6786
|
+
let messages = 0;
|
|
6787
|
+
scanSbfFrames(data, view, (id, b, len) => {
|
|
6788
|
+
if (id !== 4026 || len < 32) return;
|
|
6789
|
+
messages++;
|
|
6790
|
+
const prn = svidToPrn(view.getUint8(b + 14));
|
|
6791
|
+
if (!prn || prn[0] !== "R") return;
|
|
6792
|
+
const towMs = view.getUint32(b + 8, true);
|
|
6793
|
+
const wnc = view.getUint16(b + 12, true);
|
|
6794
|
+
if (towMs === TOW_DNU || wnc === WNC_DNU) return;
|
|
6795
|
+
const str = new Uint8Array(11);
|
|
6796
|
+
for (let k = 0; k < 3; k++) {
|
|
6797
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
6798
|
+
str[4 * k] = w >>> 24;
|
|
6799
|
+
if (k < 2) {
|
|
6800
|
+
str[4 * k + 1] = w >>> 16 & 255;
|
|
6801
|
+
str[4 * k + 2] = w >>> 8 & 255;
|
|
6802
|
+
str[4 * k + 3] = w & 255;
|
|
6803
|
+
} else {
|
|
6804
|
+
str[9] = w >>> 16 & 255;
|
|
6805
|
+
str[10] = w >>> 8 & 248;
|
|
6806
|
+
}
|
|
6807
|
+
}
|
|
6808
|
+
if (!testGloString(str)) {
|
|
6809
|
+
badCrc++;
|
|
6810
|
+
return;
|
|
6811
|
+
}
|
|
6812
|
+
const eph = assembler.push(
|
|
6813
|
+
prn,
|
|
6814
|
+
str,
|
|
6815
|
+
new Date(GPS_EPOCH_MS8 + wnc * MS_PER_WEEK5 + towMs),
|
|
6816
|
+
view.getUint8(b + 18) - 8
|
|
6817
|
+
// FreqNr, offset by 8
|
|
6818
|
+
);
|
|
6819
|
+
if (eph) ephemerides.push(eph);
|
|
6820
|
+
});
|
|
6821
|
+
return { ephemerides, badCrc, messages };
|
|
6822
|
+
}
|
|
6823
|
+
|
|
6824
|
+
// src/navbits/rs255.ts
|
|
6825
|
+
var RS255_N = 255;
|
|
6826
|
+
var RS255_K = 32;
|
|
6827
|
+
var EXP = new Uint8Array(510);
|
|
6828
|
+
var LOG = new Int16Array(256).fill(-1);
|
|
6829
|
+
{
|
|
6830
|
+
let x = 1;
|
|
6831
|
+
for (let i = 0; i < 255; i++) {
|
|
6832
|
+
EXP[i] = x;
|
|
6833
|
+
LOG[x] = i;
|
|
6834
|
+
x <<= 1;
|
|
6835
|
+
if (x & 256) x ^= 285;
|
|
6836
|
+
}
|
|
6837
|
+
for (let i = 255; i < 510; i++) EXP[i] = EXP[i - 255];
|
|
6838
|
+
}
|
|
6839
|
+
var gfMul = (a, b) => a === 0 || b === 0 ? 0 : EXP[LOG[a] + LOG[b]];
|
|
6840
|
+
var gfInv = (a) => EXP[255 - LOG[a]];
|
|
6841
|
+
var GEN_POLY = (() => {
|
|
6842
|
+
let g = new Uint8Array([1]);
|
|
6843
|
+
for (let i = 1; i <= 223; i++) {
|
|
6844
|
+
const root = EXP[i];
|
|
6845
|
+
const next = new Uint8Array(g.length + 1);
|
|
6846
|
+
for (let j = 0; j < g.length; j++) {
|
|
6847
|
+
next[j] ^= g[j];
|
|
6848
|
+
next[j + 1] ^= gfMul(g[j], root);
|
|
6849
|
+
}
|
|
6850
|
+
g = next;
|
|
6851
|
+
}
|
|
6852
|
+
return g;
|
|
6853
|
+
})();
|
|
6854
|
+
function rs255Encode(info) {
|
|
6855
|
+
if (info.length > RS255_K)
|
|
6856
|
+
throw new RangeError(`rs255Encode: info length ${info.length} > 32`);
|
|
6857
|
+
const cw = new Uint8Array(RS255_N);
|
|
6858
|
+
cw.set(info, 0);
|
|
6859
|
+
const work = new Uint8Array(RS255_N);
|
|
6860
|
+
work.set(info, 0);
|
|
6861
|
+
for (let i = 0; i < RS255_K; i++) {
|
|
6862
|
+
const coef = work[i];
|
|
6863
|
+
if (coef === 0) continue;
|
|
6864
|
+
for (let j = 1; j < GEN_POLY.length; j++)
|
|
6865
|
+
work[i + j] ^= gfMul(GEN_POLY[j], coef);
|
|
6866
|
+
}
|
|
6867
|
+
cw.set(work.subarray(RS255_K), RS255_K);
|
|
6868
|
+
return cw;
|
|
6869
|
+
}
|
|
6870
|
+
var genMatrix = null;
|
|
6871
|
+
function generatorMatrix() {
|
|
6872
|
+
if (genMatrix) return genMatrix;
|
|
6873
|
+
const rows = [];
|
|
6874
|
+
for (let r = 0; r < RS255_N; r++) rows.push(new Uint8Array(RS255_K));
|
|
6875
|
+
for (let c = 0; c < RS255_K; c++) {
|
|
6876
|
+
const e = new Uint8Array(RS255_K);
|
|
6877
|
+
e[c] = 1;
|
|
6878
|
+
const cw = rs255Encode(e);
|
|
6879
|
+
for (let r = 0; r < RS255_N; r++) rows[r][c] = cw[r];
|
|
6880
|
+
}
|
|
6881
|
+
genMatrix = rows;
|
|
6882
|
+
return rows;
|
|
6883
|
+
}
|
|
6884
|
+
function rs255DecodeErasures(pages, k) {
|
|
6885
|
+
if (k < 1 || k > RS255_K) return null;
|
|
6886
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6887
|
+
const use = [];
|
|
6888
|
+
for (const p of pages) {
|
|
6889
|
+
if (p.pageId < 1 || p.pageId > RS255_N || seen.has(p.pageId)) continue;
|
|
6890
|
+
seen.add(p.pageId);
|
|
6891
|
+
use.push(p);
|
|
6892
|
+
if (use.length === k) break;
|
|
6893
|
+
}
|
|
6894
|
+
if (use.length < k) return null;
|
|
6895
|
+
const width = use[0].octets.length;
|
|
6896
|
+
if (use.some((p) => p.octets.length !== width)) return null;
|
|
6897
|
+
const G = generatorMatrix();
|
|
6898
|
+
const a = use.map((p) => G[p.pageId - 1].slice(0, k));
|
|
6899
|
+
const inv = use.map((_, r) => {
|
|
6900
|
+
const row = new Uint8Array(k);
|
|
6901
|
+
row[r] = 1;
|
|
6902
|
+
return row;
|
|
6903
|
+
});
|
|
6904
|
+
for (let c = 0; c < k; c++) {
|
|
6905
|
+
let pivot = -1;
|
|
6906
|
+
for (let r = c; r < k; r++)
|
|
6907
|
+
if (a[r][c] !== 0) {
|
|
6908
|
+
pivot = r;
|
|
6909
|
+
break;
|
|
6910
|
+
}
|
|
6911
|
+
if (pivot < 0) return null;
|
|
6912
|
+
[a[c], a[pivot]] = [a[pivot], a[c]];
|
|
6913
|
+
[inv[c], inv[pivot]] = [inv[pivot], inv[c]];
|
|
6914
|
+
const s = gfInv(a[c][c]);
|
|
6915
|
+
for (let j = 0; j < k; j++) {
|
|
6916
|
+
a[c][j] = gfMul(a[c][j], s);
|
|
6917
|
+
inv[c][j] = gfMul(inv[c][j], s);
|
|
6918
|
+
}
|
|
6919
|
+
for (let r = 0; r < k; r++) {
|
|
6920
|
+
if (r === c || a[r][c] === 0) continue;
|
|
6921
|
+
const f = a[r][c];
|
|
6922
|
+
for (let j = 0; j < k; j++) {
|
|
6923
|
+
a[r][j] ^= gfMul(a[c][j], f);
|
|
6924
|
+
inv[r][j] ^= gfMul(inv[c][j], f);
|
|
6925
|
+
}
|
|
6926
|
+
}
|
|
6927
|
+
}
|
|
6928
|
+
const out = new Uint8Array(k * width);
|
|
6929
|
+
for (let r = 0; r < k; r++)
|
|
6930
|
+
for (let c = 0; c < width; c++) {
|
|
6931
|
+
let v = 0;
|
|
6932
|
+
for (let j = 0; j < k; j++) v ^= gfMul(inv[r][j], use[j].octets[c]);
|
|
6933
|
+
out[r * width + c] = v;
|
|
6934
|
+
}
|
|
6935
|
+
return out;
|
|
6936
|
+
}
|
|
6937
|
+
|
|
6938
|
+
// src/navbits/has.ts
|
|
6939
|
+
var HAS_DUMMY_HEADER = 11484099;
|
|
6940
|
+
var HAS_VALIDITY_SECONDS = [
|
|
6941
|
+
5,
|
|
6942
|
+
10,
|
|
6943
|
+
15,
|
|
6944
|
+
20,
|
|
6945
|
+
30,
|
|
6946
|
+
60,
|
|
6947
|
+
90,
|
|
6948
|
+
120,
|
|
6949
|
+
180,
|
|
6950
|
+
240,
|
|
6951
|
+
300,
|
|
6952
|
+
600,
|
|
6953
|
+
900,
|
|
6954
|
+
1800,
|
|
6955
|
+
3600,
|
|
6956
|
+
null
|
|
6957
|
+
];
|
|
6958
|
+
var HAS_GPS_SIGNALS = [
|
|
6959
|
+
"L1 C/A",
|
|
6960
|
+
"Reserved",
|
|
6961
|
+
"Reserved",
|
|
6962
|
+
"L1C(D)",
|
|
6963
|
+
"L1C(P)",
|
|
6964
|
+
"L1C(D+P)",
|
|
6965
|
+
"L2 CM",
|
|
6966
|
+
"L2 CL",
|
|
6967
|
+
"L2 CM+CL",
|
|
6968
|
+
"L2 P",
|
|
6969
|
+
"Reserved",
|
|
6970
|
+
"L5 I",
|
|
6971
|
+
"L5 Q",
|
|
6972
|
+
"L5 I+Q",
|
|
6973
|
+
"Reserved",
|
|
6974
|
+
"Reserved"
|
|
6975
|
+
];
|
|
6976
|
+
var HAS_GALILEO_SIGNALS = [
|
|
6977
|
+
"E1-B",
|
|
6978
|
+
"E1-C",
|
|
6979
|
+
"E1-B+E1-C",
|
|
6980
|
+
"E5a-I",
|
|
6981
|
+
"E5a-Q",
|
|
6982
|
+
"E5a-I+E5a-Q",
|
|
6983
|
+
"E5b-I",
|
|
6984
|
+
"E5b-Q",
|
|
6985
|
+
"E5b-I+E5b-Q",
|
|
6986
|
+
"E5-I",
|
|
6987
|
+
"E5-Q",
|
|
6988
|
+
"E5-I+E5-Q",
|
|
6989
|
+
"E6-B",
|
|
6990
|
+
"E6-C",
|
|
6991
|
+
"E6-B+E6-C",
|
|
6992
|
+
"Reserved"
|
|
6993
|
+
];
|
|
6994
|
+
var SYSTEM_OF_GNSS_ID = { 0: "G", 2: "E" };
|
|
6995
|
+
var IOD_BITS = { G: 8, E: 10 };
|
|
6996
|
+
function hasPageCrcOk(page) {
|
|
6997
|
+
if (page.length < 61) return false;
|
|
6998
|
+
return crc24q(page, 462) === getBitU(page, 462, 24);
|
|
6999
|
+
}
|
|
7000
|
+
function parseHasPage(page) {
|
|
7001
|
+
if (getBitU(page, 14, 24) === HAS_DUMMY_HEADER) return null;
|
|
7002
|
+
const body = new Uint8Array(53);
|
|
7003
|
+
for (let i = 0; i < 53; i++) body[i] = getBitU(page, 38 + 8 * i, 8);
|
|
7004
|
+
return {
|
|
7005
|
+
status: getBitU(page, 14, 2),
|
|
7006
|
+
messageType: getBitU(page, 18, 2),
|
|
7007
|
+
messageId: getBitU(page, 20, 5),
|
|
7008
|
+
messageSize: getBitU(page, 25, 5) + 1,
|
|
7009
|
+
pageId: getBitU(page, 30, 8),
|
|
7010
|
+
body
|
|
7011
|
+
};
|
|
7012
|
+
}
|
|
7013
|
+
var Cursor = class {
|
|
7014
|
+
constructor(buf, bits) {
|
|
7015
|
+
this.buf = buf;
|
|
7016
|
+
this.bits = bits;
|
|
7017
|
+
}
|
|
7018
|
+
pos = 0;
|
|
7019
|
+
u(len) {
|
|
7020
|
+
if (this.pos + len > this.bits) throw new RangeError("truncated");
|
|
7021
|
+
const v = getBitU(this.buf, this.pos, len);
|
|
7022
|
+
this.pos += len;
|
|
7023
|
+
return v;
|
|
7024
|
+
}
|
|
7025
|
+
s(len) {
|
|
7026
|
+
if (this.pos + len > this.bits) throw new RangeError("truncated");
|
|
7027
|
+
const v = getBitS(this.buf, this.pos, len);
|
|
7028
|
+
this.pos += len;
|
|
7029
|
+
return v;
|
|
7030
|
+
}
|
|
7031
|
+
};
|
|
7032
|
+
var prnOf = (system, idx) => `${system}${String(idx + 1).padStart(2, "0")}`;
|
|
7033
|
+
function parseMaskBlock(c, maskId) {
|
|
7034
|
+
const nSys = c.u(4);
|
|
7035
|
+
const systems = [];
|
|
7036
|
+
for (let s = 0; s < nSys; s++) {
|
|
7037
|
+
const gnssId = c.u(4);
|
|
7038
|
+
const system = SYSTEM_OF_GNSS_ID[gnssId];
|
|
7039
|
+
if (system === void 0) throw new RangeError(`unknown GNSS ID ${gnssId}`);
|
|
7040
|
+
const prns = [];
|
|
7041
|
+
for (let b = 0; b < 40; b++) if (c.u(1)) prns.push(prnOf(system, b));
|
|
7042
|
+
const signalIndices = [];
|
|
7043
|
+
for (let b = 0; b < 16; b++) if (c.u(1)) signalIndices.push(b);
|
|
7044
|
+
const signalNames = system === "G" ? HAS_GPS_SIGNALS : HAS_GALILEO_SIGNALS;
|
|
7045
|
+
let cellMask = null;
|
|
7046
|
+
if (c.u(1)) {
|
|
7047
|
+
cellMask = prns.map(() => signalIndices.map(() => c.u(1) === 1));
|
|
7048
|
+
}
|
|
7049
|
+
systems.push({
|
|
7050
|
+
gnssId,
|
|
7051
|
+
system,
|
|
7052
|
+
prns,
|
|
7053
|
+
signalIndices,
|
|
7054
|
+
signals: signalIndices.map((i) => signalNames[i]),
|
|
7055
|
+
cellMask,
|
|
7056
|
+
navMessage: c.u(3)
|
|
7057
|
+
});
|
|
7058
|
+
}
|
|
7059
|
+
c.u(6);
|
|
7060
|
+
return { maskId, systems };
|
|
7061
|
+
}
|
|
7062
|
+
function parseOrbitBlock(c, masks) {
|
|
7063
|
+
const validityIndex = c.u(4);
|
|
7064
|
+
const corrections = [];
|
|
7065
|
+
for (const sys of masks.systems) {
|
|
7066
|
+
for (const prn of sys.prns) {
|
|
7067
|
+
const gnssIod = c.u(IOD_BITS[sys.system]);
|
|
7068
|
+
const rad = c.s(13);
|
|
7069
|
+
const inT = c.s(12);
|
|
7070
|
+
const cross = c.s(12);
|
|
7071
|
+
corrections.push({
|
|
7072
|
+
system: sys.system,
|
|
7073
|
+
prn,
|
|
7074
|
+
gnssIod,
|
|
7075
|
+
deltaRadial: rad === -4096 ? null : rad * 25e-4,
|
|
7076
|
+
deltaInTrack: inT === -2048 ? null : inT * 8e-3,
|
|
7077
|
+
deltaCrossTrack: cross === -2048 ? null : cross * 8e-3
|
|
7078
|
+
});
|
|
7079
|
+
}
|
|
7080
|
+
}
|
|
7081
|
+
return {
|
|
7082
|
+
validityIndex,
|
|
7083
|
+
validitySeconds: HAS_VALIDITY_SECONDS[validityIndex],
|
|
7084
|
+
corrections
|
|
7085
|
+
};
|
|
7086
|
+
}
|
|
7087
|
+
function clockValue(c, system, prn, multiplier) {
|
|
7088
|
+
const raw = c.s(13);
|
|
7089
|
+
return {
|
|
7090
|
+
system,
|
|
7091
|
+
prn,
|
|
7092
|
+
deltaClock: raw === -4096 || raw === 4095 ? null : raw * 25e-4 * multiplier,
|
|
7093
|
+
notUsable: raw === 4095
|
|
7094
|
+
};
|
|
7095
|
+
}
|
|
7096
|
+
function parseClockFullBlock(c, masks) {
|
|
7097
|
+
const validityIndex = c.u(4);
|
|
7098
|
+
const multipliers = masks.systems.map((sys) => ({
|
|
7099
|
+
system: sys.system,
|
|
7100
|
+
multiplier: c.u(2) + 1
|
|
7101
|
+
}));
|
|
7102
|
+
const corrections = [];
|
|
7103
|
+
for (let s = 0; s < masks.systems.length; s++) {
|
|
7104
|
+
const sys = masks.systems[s];
|
|
7105
|
+
for (const prn of sys.prns)
|
|
7106
|
+
corrections.push(
|
|
7107
|
+
clockValue(c, sys.system, prn, multipliers[s].multiplier)
|
|
7108
|
+
);
|
|
7109
|
+
}
|
|
7110
|
+
return {
|
|
7111
|
+
validityIndex,
|
|
7112
|
+
validitySeconds: HAS_VALIDITY_SECONDS[validityIndex],
|
|
7113
|
+
multipliers,
|
|
7114
|
+
corrections
|
|
7115
|
+
};
|
|
7116
|
+
}
|
|
7117
|
+
function parseClockSubsetBlock(c, masks) {
|
|
7118
|
+
const validityIndex = c.u(4);
|
|
7119
|
+
const nSys = c.u(4);
|
|
7120
|
+
const multipliers = [];
|
|
7121
|
+
const corrections = [];
|
|
7122
|
+
for (let s = 0; s < nSys; s++) {
|
|
7123
|
+
const gnssId = c.u(4);
|
|
7124
|
+
const sys = masks.systems.find((m) => m.gnssId === gnssId);
|
|
7125
|
+
if (!sys) throw new RangeError(`subset GNSS ID ${gnssId} not in mask`);
|
|
7126
|
+
const multiplier = c.u(2) + 1;
|
|
7127
|
+
multipliers.push({ system: sys.system, multiplier });
|
|
7128
|
+
const selected = [];
|
|
7129
|
+
for (const prn of sys.prns) if (c.u(1)) selected.push(prn);
|
|
7130
|
+
for (const prn of selected)
|
|
7131
|
+
corrections.push(clockValue(c, sys.system, prn, multiplier));
|
|
7132
|
+
}
|
|
7133
|
+
return {
|
|
7134
|
+
validityIndex,
|
|
7135
|
+
validitySeconds: HAS_VALIDITY_SECONDS[validityIndex],
|
|
7136
|
+
multipliers,
|
|
7137
|
+
corrections
|
|
7138
|
+
};
|
|
7139
|
+
}
|
|
7140
|
+
function parseBiasBlock(c, masks, kind) {
|
|
7141
|
+
const validityIndex = c.u(4);
|
|
7142
|
+
const biases = [];
|
|
7143
|
+
for (const sys of masks.systems) {
|
|
7144
|
+
for (let s = 0; s < sys.prns.length; s++) {
|
|
7145
|
+
for (let g = 0; g < sys.signalIndices.length; g++) {
|
|
7146
|
+
if (sys.cellMask && !sys.cellMask[s][g]) continue;
|
|
7147
|
+
const raw = c.s(11);
|
|
7148
|
+
const entry = {
|
|
7149
|
+
system: sys.system,
|
|
7150
|
+
prn: sys.prns[s],
|
|
7151
|
+
signalIndex: sys.signalIndices[g],
|
|
7152
|
+
signal: sys.signals[g],
|
|
7153
|
+
bias: raw === -1024 ? null : raw * (kind === "code" ? 0.02 : 0.01)
|
|
7154
|
+
};
|
|
7155
|
+
if (kind === "phase") entry.discontinuity = c.u(2);
|
|
7156
|
+
biases.push(entry);
|
|
7157
|
+
}
|
|
7158
|
+
}
|
|
7159
|
+
}
|
|
7160
|
+
return {
|
|
7161
|
+
validityIndex,
|
|
7162
|
+
validitySeconds: HAS_VALIDITY_SECONDS[validityIndex],
|
|
7163
|
+
biases
|
|
7164
|
+
};
|
|
7165
|
+
}
|
|
7166
|
+
function parseHasMt1(payload, header, cachedMasks) {
|
|
7167
|
+
const c = new Cursor(payload, payload.length * 8);
|
|
7168
|
+
const toh = c.u(12);
|
|
7169
|
+
const flags = {
|
|
7170
|
+
mask: c.u(1) === 1,
|
|
7171
|
+
orbit: c.u(1) === 1,
|
|
7172
|
+
clockFullSet: c.u(1) === 1,
|
|
7173
|
+
clockSubset: c.u(1) === 1,
|
|
7174
|
+
codeBias: c.u(1) === 1,
|
|
7175
|
+
phaseBias: c.u(1) === 1
|
|
7176
|
+
};
|
|
7177
|
+
c.u(4);
|
|
7178
|
+
const maskId = c.u(5);
|
|
7179
|
+
const iodSetId = c.u(5);
|
|
7180
|
+
const msg = {
|
|
7181
|
+
...header,
|
|
7182
|
+
toh,
|
|
7183
|
+
maskId,
|
|
7184
|
+
iodSetId,
|
|
7185
|
+
flags,
|
|
7186
|
+
maskFromCache: false,
|
|
7187
|
+
parseError: null
|
|
7188
|
+
};
|
|
7189
|
+
try {
|
|
7190
|
+
let masks;
|
|
7191
|
+
if (flags.mask) {
|
|
7192
|
+
masks = parseMaskBlock(c, maskId);
|
|
7193
|
+
} else if (cachedMasks) {
|
|
7194
|
+
masks = cachedMasks;
|
|
7195
|
+
msg.maskFromCache = true;
|
|
7196
|
+
} else {
|
|
7197
|
+
msg.parseError = "mask-unavailable";
|
|
7198
|
+
return msg;
|
|
7199
|
+
}
|
|
7200
|
+
msg.masks = masks;
|
|
7201
|
+
if (flags.orbit) msg.orbit = parseOrbitBlock(c, masks);
|
|
7202
|
+
if (flags.clockFullSet) msg.clockFullSet = parseClockFullBlock(c, masks);
|
|
7203
|
+
if (flags.clockSubset) msg.clockSubset = parseClockSubsetBlock(c, masks);
|
|
7204
|
+
if (flags.codeBias) msg.codeBias = parseBiasBlock(c, masks, "code");
|
|
7205
|
+
if (flags.phaseBias) msg.phaseBias = parseBiasBlock(c, masks, "phase");
|
|
7206
|
+
} catch (e) {
|
|
7207
|
+
msg.parseError = e instanceof Error ? e.message : String(e);
|
|
7208
|
+
}
|
|
7209
|
+
return msg;
|
|
7210
|
+
}
|
|
7211
|
+
var HasAssembler = class {
|
|
7212
|
+
slots = /* @__PURE__ */ new Map();
|
|
7213
|
+
lastMessageId = -1;
|
|
7214
|
+
maskCache = /* @__PURE__ */ new Map();
|
|
7215
|
+
/** Pages a message may span before its slot is restarted (s). */
|
|
7216
|
+
timeoutSec;
|
|
7217
|
+
stats = {
|
|
7218
|
+
pages: 0,
|
|
7219
|
+
dummyPages: 0,
|
|
7220
|
+
skippedPages: 0,
|
|
7221
|
+
duplicatePages: 0,
|
|
7222
|
+
resets: 0,
|
|
7223
|
+
messages: 0,
|
|
7224
|
+
parseErrors: 0
|
|
7225
|
+
};
|
|
7226
|
+
constructor(opts = {}) {
|
|
7227
|
+
this.timeoutSec = opts.timeoutSec ?? 30;
|
|
7228
|
+
}
|
|
7229
|
+
/**
|
|
7230
|
+
* Push one 492-bit C/NAV page (≥ 61 bytes; check the CRC first with
|
|
7231
|
+
* `hasPageCrcOk`). `tow` — a receiver time of week in seconds, any
|
|
7232
|
+
* origin as long as it is common to all pages — enables the slot
|
|
7233
|
+
* timeout and is stamped on completed messages.
|
|
7234
|
+
*/
|
|
7235
|
+
push(page, tow) {
|
|
7236
|
+
const p = parseHasPage(page);
|
|
7237
|
+
if (!p) {
|
|
7238
|
+
this.stats.dummyPages++;
|
|
7239
|
+
return null;
|
|
7240
|
+
}
|
|
7241
|
+
this.stats.pages++;
|
|
7242
|
+
if (p.messageType !== 1 || p.status > 1 || p.pageId === 0) {
|
|
7243
|
+
this.stats.skippedPages++;
|
|
7244
|
+
return null;
|
|
7245
|
+
}
|
|
7246
|
+
if (p.messageId === this.lastMessageId) return null;
|
|
7247
|
+
let slot = this.slots.get(p.messageId);
|
|
7248
|
+
const timedOut = slot?.firstTow !== void 0 && tow !== void 0 && tow - slot.firstTow > this.timeoutSec;
|
|
7249
|
+
if (slot && (slot.messageSize !== p.messageSize || timedOut)) {
|
|
7250
|
+
this.stats.resets++;
|
|
7251
|
+
slot = void 0;
|
|
7252
|
+
}
|
|
7253
|
+
if (!slot) {
|
|
7254
|
+
slot = {
|
|
7255
|
+
messageSize: p.messageSize,
|
|
7256
|
+
status: p.status,
|
|
7257
|
+
pages: [],
|
|
7258
|
+
bodies: /* @__PURE__ */ new Map(),
|
|
7259
|
+
firstTow: tow
|
|
7260
|
+
};
|
|
7261
|
+
this.slots.set(p.messageId, slot);
|
|
7262
|
+
}
|
|
7263
|
+
const bodyKey = Array.from(
|
|
7264
|
+
p.body,
|
|
7265
|
+
(b) => b.toString(16).padStart(2, "0")
|
|
7266
|
+
).join("");
|
|
7267
|
+
const existing = slot.bodies.get(p.pageId);
|
|
7268
|
+
if (existing !== void 0) {
|
|
7269
|
+
if (existing === bodyKey) {
|
|
7270
|
+
this.stats.duplicatePages++;
|
|
7271
|
+
return null;
|
|
7272
|
+
}
|
|
7273
|
+
this.stats.resets++;
|
|
7274
|
+
slot.pages = [];
|
|
7275
|
+
slot.bodies.clear();
|
|
7276
|
+
slot.firstTow = tow;
|
|
7277
|
+
}
|
|
7278
|
+
slot.bodies.set(p.pageId, bodyKey);
|
|
7279
|
+
slot.pages.push({ pageId: p.pageId, octets: p.body });
|
|
7280
|
+
if (slot.pages.length < slot.messageSize) return null;
|
|
7281
|
+
const payload = rs255DecodeErasures(slot.pages, slot.messageSize);
|
|
7282
|
+
if (!payload) return null;
|
|
7283
|
+
this.slots.delete(p.messageId);
|
|
7284
|
+
this.lastMessageId = p.messageId;
|
|
7285
|
+
const msg = parseHasMt1(
|
|
7286
|
+
payload,
|
|
7287
|
+
{
|
|
7288
|
+
status: slot.status,
|
|
7289
|
+
messageId: p.messageId,
|
|
7290
|
+
messageSize: slot.messageSize
|
|
7291
|
+
},
|
|
7292
|
+
void 0
|
|
7293
|
+
);
|
|
7294
|
+
const resolved = msg.parseError === "mask-unavailable" && this.maskCache.has(msg.maskId) ? parseHasMt1(
|
|
7295
|
+
payload,
|
|
7296
|
+
{
|
|
7297
|
+
status: slot.status,
|
|
7298
|
+
messageId: p.messageId,
|
|
7299
|
+
messageSize: slot.messageSize
|
|
7300
|
+
},
|
|
7301
|
+
this.maskCache.get(msg.maskId)
|
|
7302
|
+
) : msg;
|
|
7303
|
+
if (resolved.flags.mask && resolved.masks)
|
|
7304
|
+
this.maskCache.set(resolved.maskId, resolved.masks);
|
|
7305
|
+
if (tow !== void 0) resolved.tow = tow;
|
|
7306
|
+
this.stats.messages++;
|
|
7307
|
+
if (resolved.parseError !== null) this.stats.parseErrors++;
|
|
7308
|
+
return resolved;
|
|
7309
|
+
}
|
|
7310
|
+
};
|
|
7311
|
+
|
|
7312
|
+
// src/sbf/rawnav-has.ts
|
|
7313
|
+
function parseSbfHas(data) {
|
|
7314
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
7315
|
+
const assembler = new HasAssembler();
|
|
7316
|
+
const messages = [];
|
|
7317
|
+
let pagesSeen = 0;
|
|
7318
|
+
let pagesBadCrc = 0;
|
|
7319
|
+
scanSbfFrames(data, view, (id, b, len) => {
|
|
7320
|
+
if (id !== 4024 || len < 84) return;
|
|
7321
|
+
pagesSeen++;
|
|
7322
|
+
const page = new Uint8Array(64);
|
|
7323
|
+
for (let k = 0; k < 16; k++) {
|
|
7324
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
7325
|
+
page[4 * k] = w >>> 24;
|
|
7326
|
+
page[4 * k + 1] = w >>> 16 & 255;
|
|
7327
|
+
page[4 * k + 2] = w >>> 8 & 255;
|
|
7328
|
+
page[4 * k + 3] = w & 255;
|
|
7329
|
+
}
|
|
7330
|
+
if (!hasPageCrcOk(page)) {
|
|
7331
|
+
pagesBadCrc++;
|
|
7332
|
+
return;
|
|
7333
|
+
}
|
|
7334
|
+
const tow = view.getUint32(b + 8, true) / 1e3;
|
|
7335
|
+
const msg = assembler.push(page, tow);
|
|
7336
|
+
if (msg) messages.push({ ...msg, tow, wnc: view.getUint16(b + 12, true) });
|
|
7337
|
+
});
|
|
7338
|
+
return {
|
|
7339
|
+
messages,
|
|
7340
|
+
pagesSeen,
|
|
7341
|
+
pagesBadCrc,
|
|
7342
|
+
pagesDummy: assembler.stats.dummyPages,
|
|
7343
|
+
pagesHas: assembler.stats.pages
|
|
7344
|
+
};
|
|
7345
|
+
}
|
|
7346
|
+
|
|
5930
7347
|
// src/sbf/index.ts
|
|
5931
7348
|
var CLIGHT = 299792458;
|
|
5932
|
-
var
|
|
5933
|
-
var
|
|
7349
|
+
var GPS_EPOCH_MS9 = Date.UTC(1980, 0, 6);
|
|
7350
|
+
var MS_PER_WEEK6 = 7 * 864e5;
|
|
5934
7351
|
var M3_SYS = ["G", "R", "E", "C", "S", "J", "I"];
|
|
5935
7352
|
var M3_PR_BASE = [19e6, 19e6, 22e6, 2e7, 34e6, 34e6, 34e6];
|
|
5936
7353
|
var M3_INTERVALS = [
|
|
@@ -6029,23 +7446,23 @@ var MEAS2_SIG = [
|
|
|
6029
7446
|
["J", "1E"],
|
|
6030
7447
|
["J", "5P"]
|
|
6031
7448
|
];
|
|
6032
|
-
var
|
|
7449
|
+
var two3 = (n) => String(n).padStart(2, "0");
|
|
6033
7450
|
function m3Prn(navsys, svid) {
|
|
6034
7451
|
switch (navsys) {
|
|
6035
7452
|
case 0:
|
|
6036
|
-
return svid < 32 ? `G${
|
|
7453
|
+
return svid < 32 ? `G${two3(svid + 1)}` : null;
|
|
6037
7454
|
case 1:
|
|
6038
|
-
return svid < 27 ? `R${
|
|
7455
|
+
return svid < 27 ? `R${two3(svid + 1)}` : null;
|
|
6039
7456
|
case 2:
|
|
6040
|
-
return svid < 36 ? `E${
|
|
7457
|
+
return svid < 36 ? `E${two3(svid + 1)}` : null;
|
|
6041
7458
|
case 3:
|
|
6042
|
-
return svid < 50 ? `C${
|
|
7459
|
+
return svid < 50 ? `C${two3(svid + 1)}` : null;
|
|
6043
7460
|
case 4:
|
|
6044
|
-
return svid <= 38 ? `S${
|
|
7461
|
+
return svid <= 38 ? `S${two3(svid + 20)}` : null;
|
|
6045
7462
|
case 5:
|
|
6046
|
-
return svid < 10 ? `J${
|
|
7463
|
+
return svid < 10 ? `J${two3(svid + 1)}` : null;
|
|
6047
7464
|
case 6:
|
|
6048
|
-
return svid < 14 ? `I${
|
|
7465
|
+
return svid < 14 ? `I${two3(svid + 1)}` : null;
|
|
6049
7466
|
default:
|
|
6050
7467
|
return null;
|
|
6051
7468
|
}
|
|
@@ -6583,7 +8000,7 @@ function parseSbfMeas(data) {
|
|
|
6583
8000
|
const tow = view.getUint32(i + 8, true);
|
|
6584
8001
|
const wnc = view.getUint16(i + 12, true);
|
|
6585
8002
|
if (tow !== 4294967295 && wnc !== 65535) {
|
|
6586
|
-
ensureEpoch(
|
|
8003
|
+
ensureEpoch(GPS_EPOCH_MS9 + wnc * MS_PER_WEEK6 + tow);
|
|
6587
8004
|
if (id === 4109) decodeMeas3Ranges(i, tow);
|
|
6588
8005
|
else if (id === 4110) decodeMeas3CN0(i, len);
|
|
6589
8006
|
else if (id === 4111) decodeMeas3Doppler(i, len);
|
|
@@ -6641,24 +8058,25 @@ function* oem4Frames(data, view, stats) {
|
|
|
6641
8058
|
|
|
6642
8059
|
// src/novatel/nav.ts
|
|
6643
8060
|
var ID_IONUTC = 8;
|
|
8061
|
+
var ID_RAWCNAVFRAME = 1066;
|
|
6644
8062
|
var ID_RAWEPHEM = 41;
|
|
6645
8063
|
var ID_GLOEPHEMERIS = 723;
|
|
6646
8064
|
var ID_GALEPHEMERIS = 1122;
|
|
6647
8065
|
var ID_QZSSEPHEMERIS = 1336;
|
|
6648
8066
|
var ID_GPSEPHEM = 7;
|
|
6649
8067
|
var ID_BDSEPHEMERIS = 1696;
|
|
6650
|
-
var
|
|
6651
|
-
var
|
|
6652
|
-
var
|
|
6653
|
-
var
|
|
6654
|
-
var
|
|
6655
|
-
var gpsMs2 = (week, sec) =>
|
|
6656
|
-
var
|
|
8068
|
+
var GPS_EPOCH_MS10 = Date.UTC(1980, 0, 6);
|
|
8069
|
+
var BDT_EPOCH_MS3 = Date.UTC(2006, 0, 1);
|
|
8070
|
+
var SEC_PER_WEEK8 = 7 * 86400;
|
|
8071
|
+
var SEC_PER_DAY2 = 86400;
|
|
8072
|
+
var MS_PER_WEEK7 = SEC_PER_WEEK8 * 1e3;
|
|
8073
|
+
var gpsMs2 = (week, sec) => GPS_EPOCH_MS10 + week * MS_PER_WEEK7 + sec * 1e3;
|
|
8074
|
+
var sowOf3 = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK8;
|
|
6657
8075
|
function nearWeekMs(refMs, sow) {
|
|
6658
|
-
const refWeek = Math.floor((refMs -
|
|
8076
|
+
const refWeek = Math.floor((refMs - GPS_EPOCH_MS10) / MS_PER_WEEK7);
|
|
6659
8077
|
let ms = gpsMs2(refWeek, sow);
|
|
6660
|
-
if (ms < refMs -
|
|
6661
|
-
else if (ms > refMs +
|
|
8078
|
+
if (ms < refMs - MS_PER_WEEK7 / 2) ms += MS_PER_WEEK7;
|
|
8079
|
+
else if (ms > refMs + MS_PER_WEEK7 / 2) ms -= MS_PER_WEEK7;
|
|
6662
8080
|
return ms;
|
|
6663
8081
|
}
|
|
6664
8082
|
function decodeRawEphem(data, view, p) {
|
|
@@ -6679,12 +8097,12 @@ function decodeGloEphemeris(view, p) {
|
|
|
6679
8097
|
const toff = view.getUint32(p + 12, true);
|
|
6680
8098
|
const health = view.getUint32(p + 24, true) < 4 ? 0 : 1;
|
|
6681
8099
|
let tof = view.getUint32(p + 124, true) - toff;
|
|
6682
|
-
tof += Math.floor(tow /
|
|
6683
|
-
if (tof < tow - 43200) tof +=
|
|
6684
|
-
else if (tof > tow + 43200) tof -=
|
|
6685
|
-
const toeGpsMs =
|
|
6686
|
-
const tofGpsMs =
|
|
6687
|
-
const tofUtcSec = (getUtcDate(new Date(tofGpsMs)).getTime() -
|
|
8100
|
+
tof += Math.floor(tow / SEC_PER_DAY2) * SEC_PER_DAY2;
|
|
8101
|
+
if (tof < tow - 43200) tof += SEC_PER_DAY2;
|
|
8102
|
+
else if (tof > tow + 43200) tof -= SEC_PER_DAY2;
|
|
8103
|
+
const toeGpsMs = GPS_EPOCH_MS10 + (week * SEC_PER_WEEK8 + tow) * 1e3;
|
|
8104
|
+
const tofGpsMs = GPS_EPOCH_MS10 + (week * SEC_PER_WEEK8 + tof) * 1e3;
|
|
8105
|
+
const tofUtcSec = (getUtcDate(new Date(tofGpsMs)).getTime() - GPS_EPOCH_MS10) / 1e3;
|
|
6688
8106
|
return {
|
|
6689
8107
|
system: "R",
|
|
6690
8108
|
prn: `R${String(slot).padStart(2, "0")}`,
|
|
@@ -6692,7 +8110,7 @@ function decodeGloEphemeris(view, p) {
|
|
|
6692
8110
|
tauN: -view.getFloat64(p + 100, true),
|
|
6693
8111
|
// RINEX stores −τ_n
|
|
6694
8112
|
gammaN: view.getFloat64(p + 116, true),
|
|
6695
|
-
messageFrameTime: (tofUtcSec %
|
|
8113
|
+
messageFrameTime: (tofUtcSec % SEC_PER_WEEK8 + SEC_PER_WEEK8) % SEC_PER_WEEK8,
|
|
6696
8114
|
x: view.getFloat64(p + 28, true) / 1e3,
|
|
6697
8115
|
y: view.getFloat64(p + 36, true) / 1e3,
|
|
6698
8116
|
z: view.getFloat64(p + 44, true) / 1e3,
|
|
@@ -6727,7 +8145,7 @@ function decodeGalEphemeris(view, p, headerMs) {
|
|
|
6727
8145
|
eph: {
|
|
6728
8146
|
system: "E",
|
|
6729
8147
|
prn: `E${String(prn).padStart(2, "0")}`,
|
|
6730
|
-
toc:
|
|
8148
|
+
toc: sowOf3(tocDate.getTime()),
|
|
6731
8149
|
tocDate,
|
|
6732
8150
|
af0: view.getFloat64(c + 4, true),
|
|
6733
8151
|
af1: view.getFloat64(c + 12, true),
|
|
@@ -6749,7 +8167,7 @@ function decodeGalEphemeris(view, p, headerMs) {
|
|
|
6749
8167
|
omega: view.getFloat64(p + 60, true),
|
|
6750
8168
|
omegaDot: view.getFloat64(p + 140, true),
|
|
6751
8169
|
idot: view.getFloat64(p + 124, true),
|
|
6752
|
-
week: Math.floor((toeMs -
|
|
8170
|
+
week: Math.floor((toeMs - GPS_EPOCH_MS10) / MS_PER_WEEK7),
|
|
6753
8171
|
// RINEX Galileo SVH bit layout (E1B DVS/HS in bits 0-2, E5a in
|
|
6754
8172
|
// 3-5, E5b in 6-8) — same packing as RTKLIB.
|
|
6755
8173
|
svHealth: svhE5b << 7 | dvsE5b << 6 | svhE5a << 4 | dvsE5a << 3 | svhE1b << 1 | dvsE1b,
|
|
@@ -6766,11 +8184,11 @@ function decodeBdsEphemeris2(view, p) {
|
|
|
6766
8184
|
const tgd1 = view.getFloat64(p + 20, true);
|
|
6767
8185
|
const tocs = view.getUint32(p + 40, true);
|
|
6768
8186
|
const toes = view.getUint32(p + 72, true);
|
|
6769
|
-
const tocDate = new Date(
|
|
8187
|
+
const tocDate = new Date(BDT_EPOCH_MS3 + week * MS_PER_WEEK7 + tocs * 1e3);
|
|
6770
8188
|
return {
|
|
6771
8189
|
system: "C",
|
|
6772
8190
|
prn: `C${String(prn).padStart(2, "0")}`,
|
|
6773
|
-
toc:
|
|
8191
|
+
toc: sowOf3(tocDate.getTime()),
|
|
6774
8192
|
tocDate,
|
|
6775
8193
|
af0: view.getFloat64(p + 44, true),
|
|
6776
8194
|
af1: view.getFloat64(p + 52, true),
|
|
@@ -6814,7 +8232,7 @@ function decodeGpsQzssEphemeris(view, p, sys) {
|
|
|
6814
8232
|
return {
|
|
6815
8233
|
system: sys,
|
|
6816
8234
|
prn: `${sys}${String(sys === "J" ? prn - 192 : prn).padStart(2, "0")}`,
|
|
6817
|
-
toc:
|
|
8235
|
+
toc: sowOf3(tocDate.getTime()),
|
|
6818
8236
|
tocDate,
|
|
6819
8237
|
af0: view.getFloat64(p + 180, true),
|
|
6820
8238
|
af1: view.getFloat64(p + 188, true),
|
|
@@ -6847,6 +8265,9 @@ function parseNovatelNav(data) {
|
|
|
6847
8265
|
const ephemerides = [];
|
|
6848
8266
|
const ionoCorrections = {};
|
|
6849
8267
|
let leapSeconds = null;
|
|
8268
|
+
const cnav = [];
|
|
8269
|
+
const cnavAssembler = new CnavAssembler();
|
|
8270
|
+
let cnavBadCrc = 0;
|
|
6850
8271
|
const lastKep = /* @__PURE__ */ new Map();
|
|
6851
8272
|
const lastGlo = /* @__PURE__ */ new Map();
|
|
6852
8273
|
const pushKepler = (key, eph) => {
|
|
@@ -6877,6 +8298,14 @@ function parseNovatelNav(data) {
|
|
|
6877
8298
|
} else if (frame.id === ID_QZSSEPHEMERIS && frame.msgLen >= 204) {
|
|
6878
8299
|
const eph = decodeGpsQzssEphemeris(view, frame.payload, "J");
|
|
6879
8300
|
if (eph) pushKepler(eph.prn, eph);
|
|
8301
|
+
} else if (frame.id === ID_RAWCNAVFRAME && frame.msgLen >= 50) {
|
|
8302
|
+
const msg = data.subarray(frame.payload + 12, frame.payload + 50);
|
|
8303
|
+
if (!cnavCrcOk(msg)) {
|
|
8304
|
+
cnavBadCrc++;
|
|
8305
|
+
} else {
|
|
8306
|
+
const eph = cnavAssembler.push(msg);
|
|
8307
|
+
if (eph) cnav.push(eph);
|
|
8308
|
+
}
|
|
6880
8309
|
} else if (frame.id === ID_IONUTC && frame.msgLen >= 108) {
|
|
6881
8310
|
const p = frame.payload;
|
|
6882
8311
|
const alpha = [];
|
|
@@ -6899,12 +8328,19 @@ function parseNovatelNav(data) {
|
|
|
6899
8328
|
ephemerides.push(eph);
|
|
6900
8329
|
}
|
|
6901
8330
|
}
|
|
6902
|
-
return {
|
|
8331
|
+
return {
|
|
8332
|
+
ephemerides,
|
|
8333
|
+
ionoCorrections,
|
|
8334
|
+
leapSeconds,
|
|
8335
|
+
cnav,
|
|
8336
|
+
cnavBadCrc,
|
|
8337
|
+
badCrc: stats.badCrc
|
|
8338
|
+
};
|
|
6903
8339
|
}
|
|
6904
8340
|
|
|
6905
8341
|
// src/novatel/index.ts
|
|
6906
|
-
var
|
|
6907
|
-
var
|
|
8342
|
+
var GPS_EPOCH_MS11 = Date.UTC(1980, 0, 6);
|
|
8343
|
+
var MS_PER_WEEK8 = 7 * 864e5;
|
|
6908
8344
|
var HDR = 28;
|
|
6909
8345
|
var ID_RANGE = 43;
|
|
6910
8346
|
var ID_RANGECMP = 140;
|
|
@@ -7073,7 +8509,7 @@ function parseNovatelRange(data) {
|
|
|
7073
8509
|
if (!codes.includes(code)) codes.push(code);
|
|
7074
8510
|
}
|
|
7075
8511
|
epochs.push({
|
|
7076
|
-
timeMs:
|
|
8512
|
+
timeMs: GPS_EPOCH_MS11 + week * MS_PER_WEEK8 + towMs,
|
|
7077
8513
|
meas
|
|
7078
8514
|
});
|
|
7079
8515
|
}
|
|
@@ -7125,7 +8561,7 @@ function parseNovatelRange(data) {
|
|
|
7125
8561
|
if (!codes.includes(code)) codes.push(code);
|
|
7126
8562
|
}
|
|
7127
8563
|
epochs.push({
|
|
7128
|
-
timeMs:
|
|
8564
|
+
timeMs: GPS_EPOCH_MS11 + week * MS_PER_WEEK8 + towMs,
|
|
7129
8565
|
meas
|
|
7130
8566
|
});
|
|
7131
8567
|
}
|
|
@@ -7135,10 +8571,184 @@ function parseNovatelRange(data) {
|
|
|
7135
8571
|
return { epochs, messageCounts, obsCodes, badCrc };
|
|
7136
8572
|
}
|
|
7137
8573
|
|
|
7138
|
-
// src/orbit/
|
|
8574
|
+
// src/orbit/almanac.ts
|
|
7139
8575
|
var GM_GPS = 3986005e8;
|
|
7140
8576
|
var GM_GAL = 3986004418e5;
|
|
7141
8577
|
var GM_BDS = 3986004418e5;
|
|
8578
|
+
var GPS_EPOCH_MS12 = Date.UTC(1980, 0, 6);
|
|
8579
|
+
var BDT_EPOCH_MS4 = Date.UTC(2006, 0, 1);
|
|
8580
|
+
var WEEK_MS = 6048e5;
|
|
8581
|
+
var BDT_MINUS_GPST_MS = 14e3;
|
|
8582
|
+
var BDS_GEO_PRNS = /* @__PURE__ */ new Set([1, 2, 3, 4, 5, 59, 60, 61, 62, 63]);
|
|
8583
|
+
function almanacEpochMs(alm) {
|
|
8584
|
+
if (alm.system === "C") {
|
|
8585
|
+
return BDT_EPOCH_MS4 + alm.weekAlm * WEEK_MS + alm.toaSec * 1e3 + BDT_MINUS_GPST_MS;
|
|
8586
|
+
}
|
|
8587
|
+
return GPS_EPOCH_MS12 + alm.weekAlm * WEEK_MS + alm.toaSec * 1e3;
|
|
8588
|
+
}
|
|
8589
|
+
function almanacSatPosition(alm, timeMs) {
|
|
8590
|
+
const GM = alm.system === "E" ? GM_GAL : alm.system === "C" ? GM_BDS : GM_GPS;
|
|
8591
|
+
const a = alm.sqrtA * alm.sqrtA;
|
|
8592
|
+
const n0 = Math.sqrt(GM / (a * a * a));
|
|
8593
|
+
const tk = (timeMs - almanacEpochMs(alm)) / 1e3;
|
|
8594
|
+
const Mk = alm.m0 + n0 * tk;
|
|
8595
|
+
let Ek = Mk;
|
|
8596
|
+
for (let i = 0; i < 12; i++) {
|
|
8597
|
+
const dE = (Mk - (Ek - alm.e * Math.sin(Ek))) / (1 - alm.e * Math.cos(Ek));
|
|
8598
|
+
Ek += dE;
|
|
8599
|
+
if (Math.abs(dE) < 1e-12) break;
|
|
8600
|
+
}
|
|
8601
|
+
const sinE = Math.sin(Ek);
|
|
8602
|
+
const cosE = Math.cos(Ek);
|
|
8603
|
+
const vk = Math.atan2(Math.sqrt(1 - alm.e * alm.e) * sinE, cosE - alm.e);
|
|
8604
|
+
const uk = vk + alm.omega;
|
|
8605
|
+
const rk = a * (1 - alm.e * cosE);
|
|
8606
|
+
const ik = alm.i0OrDeltaI;
|
|
8607
|
+
const xp = rk * Math.cos(uk);
|
|
8608
|
+
const yp = rk * Math.sin(uk);
|
|
8609
|
+
const clockBias = alm.af0 + alm.af1 * tk;
|
|
8610
|
+
const isGeo = alm.system === "C" && BDS_GEO_PRNS.has(Number(alm.prn.slice(1)));
|
|
8611
|
+
if (isGeo) {
|
|
8612
|
+
const omegak2 = alm.omega0 + alm.omegaDot * tk - OMEGA_E * alm.toaSec;
|
|
8613
|
+
const cosO2 = Math.cos(omegak2);
|
|
8614
|
+
const sinO2 = Math.sin(omegak2);
|
|
8615
|
+
const cosI2 = Math.cos(ik);
|
|
8616
|
+
const sinI2 = Math.sin(ik);
|
|
8617
|
+
const xg = xp * cosO2 - yp * cosI2 * sinO2;
|
|
8618
|
+
const yg = xp * sinO2 + yp * cosI2 * cosO2;
|
|
8619
|
+
const zg = yp * sinI2;
|
|
8620
|
+
const phi = OMEGA_E * tk;
|
|
8621
|
+
const cosPhi = Math.cos(phi);
|
|
8622
|
+
const sinPhi = Math.sin(phi);
|
|
8623
|
+
const COS5 = Math.cos(-5 * Math.PI / 180);
|
|
8624
|
+
const SIN5 = Math.sin(-5 * Math.PI / 180);
|
|
8625
|
+
return {
|
|
8626
|
+
prn: alm.prn,
|
|
8627
|
+
x: xg * cosPhi + yg * sinPhi * COS5 + zg * sinPhi * SIN5,
|
|
8628
|
+
y: -xg * sinPhi + yg * cosPhi * COS5 + zg * cosPhi * SIN5,
|
|
8629
|
+
z: -yg * SIN5 + zg * COS5,
|
|
8630
|
+
clockBias
|
|
8631
|
+
};
|
|
8632
|
+
}
|
|
8633
|
+
const omegak = alm.omega0 + (alm.omegaDot - OMEGA_E) * tk - OMEGA_E * alm.toaSec;
|
|
8634
|
+
const cosO = Math.cos(omegak);
|
|
8635
|
+
const sinO = Math.sin(omegak);
|
|
8636
|
+
const cosI = Math.cos(ik);
|
|
8637
|
+
const sinI = Math.sin(ik);
|
|
8638
|
+
return {
|
|
8639
|
+
prn: alm.prn,
|
|
8640
|
+
x: xp * cosO - yp * cosI * sinO,
|
|
8641
|
+
y: xp * sinO + yp * cosI * cosO,
|
|
8642
|
+
z: yp * sinI,
|
|
8643
|
+
clockBias
|
|
8644
|
+
};
|
|
8645
|
+
}
|
|
8646
|
+
|
|
8647
|
+
// src/orbit/almanac-glo.ts
|
|
8648
|
+
var C20 = -108263e-8;
|
|
8649
|
+
var J = -1.5 * C20;
|
|
8650
|
+
var AE = 6378.136;
|
|
8651
|
+
var MU = 398600.44;
|
|
8652
|
+
var OMEGA_Z = 7292115e-11;
|
|
8653
|
+
var I_MEAN = 63 * Math.PI / 180;
|
|
8654
|
+
var T_MEAN = 43200;
|
|
8655
|
+
var GLO_1996_UTC_MS = Date.UTC(1996, 0, 1) - 108e5;
|
|
8656
|
+
var DAY_MS = 864e5;
|
|
8657
|
+
var FOUR_YEARS_DAYS = 1461;
|
|
8658
|
+
function glonassAlmanacEpochMs(alm) {
|
|
8659
|
+
const utcMs = GLO_1996_UTC_MS + ((alm.n4 - 1) * FOUR_YEARS_DAYS + (alm.nDay - 1)) * DAY_MS + alm.tLambda * 1e3;
|
|
8660
|
+
return utcMs + getGpsLeap(new Date(utcMs)) * 1e3;
|
|
8661
|
+
}
|
|
8662
|
+
function c20Deltas(lam, tau, B, h, l, n, sinI, cosI) {
|
|
8663
|
+
const sin2i = sinI * sinI;
|
|
8664
|
+
const cos2i = cosI * cosI;
|
|
8665
|
+
const s1 = Math.sin(lam);
|
|
8666
|
+
const c1 = Math.cos(lam);
|
|
8667
|
+
const s2 = Math.sin(2 * lam);
|
|
8668
|
+
const c2 = Math.cos(2 * lam);
|
|
8669
|
+
const s3 = Math.sin(3 * lam);
|
|
8670
|
+
const c3 = Math.cos(3 * lam);
|
|
8671
|
+
const s4 = Math.sin(4 * lam);
|
|
8672
|
+
const c4 = Math.cos(4 * lam);
|
|
8673
|
+
const daOverA = 2 * B * (1 - 1.5 * sin2i) * (l * c1 + h * s1) + B * sin2i * (0.5 * h * s1 - 0.5 * l * c1 + c2 + 3.5 * l * c3 + 3.5 * h * s3);
|
|
8674
|
+
const dh = B * (1 - 1.5 * sin2i) * (l * n * tau + s1 + 1.5 * l * s2 - 1.5 * h * c2) - 0.25 * B * sin2i * (s1 - 7 / 3 * s3 + 5 * l * s2 - 8.5 * l * s4 + 8.5 * h * c4 + h * c2) + B * cos2i * (l * n * tau - 0.5 * l * s2);
|
|
8675
|
+
const dl = B * (1 - 1.5 * sin2i) * (-h * n * tau + c1 + 1.5 * l * c2 + 1.5 * h * s2) - 0.25 * B * sin2i * (-c1 - 7 / 3 * c3 - 5 * h * s2 - 8.5 * l * c4 - 8.5 * h * s4 + l * c2) + B * cos2i * (-h * n * tau + 0.5 * h * s2);
|
|
8676
|
+
const nodeBracket = n * tau + 3.5 * l * s1 - 2.5 * h * c1 - 0.5 * s2 - 7 / 6 * l * s3 + 7 / 6 * h * c3;
|
|
8677
|
+
const dOmega = -B * cosI * nodeBracket;
|
|
8678
|
+
const di = 0.5 * B * sinI * cosI * (-l * c1 + h * s1 + c2 + 7 / 3 * l * c3 + 7 / 3 * h * s3);
|
|
8679
|
+
const dLambda = 2 * B * (1 - 1.5 * sin2i) * (n * tau + 1.75 * l * s1 - 1.75 * h * c1) + 3 * B * sin2i * (-(7 / 24) * h * c1 - 7 / 24 * l * s1 - 49 / 72 * h * c3 + 49 / 72 * l * s3 + 0.25 * s2) + B * cos2i * nodeBracket;
|
|
8680
|
+
return { daOverA, dh, dl, dOmega, di, dLambda };
|
|
8681
|
+
}
|
|
8682
|
+
function glonassAlmanacPosition(alm, timeMs) {
|
|
8683
|
+
const i = I_MEAN + alm.deltaI;
|
|
8684
|
+
const sinI = Math.sin(i);
|
|
8685
|
+
const cosI = Math.cos(i);
|
|
8686
|
+
const sin2i = sinI * sinI;
|
|
8687
|
+
const e = alm.epsilon;
|
|
8688
|
+
const oneMinusE2 = 1 - e * e;
|
|
8689
|
+
const Tdr = T_MEAN + alm.deltaT;
|
|
8690
|
+
const n = 2 * Math.PI / Tdr;
|
|
8691
|
+
const cosW = Math.cos(alm.omega);
|
|
8692
|
+
let a = Math.cbrt((Tdr / (2 * Math.PI)) ** 2 * MU);
|
|
8693
|
+
for (let k = 0; k < 10; k++) {
|
|
8694
|
+
const p = a * oneMinusE2;
|
|
8695
|
+
const tOsc = Tdr / (1 + 1.5 * C20 * (AE / p) ** 2 * ((2 - 2.5 * sin2i) * (Math.pow(oneMinusE2, 1.5) / (1 + e * cosW) ** 2) + (1 + e * cosW) ** 3 / oneMinusE2));
|
|
8696
|
+
const aNext = Math.cbrt((tOsc / (2 * Math.PI)) ** 2 * MU);
|
|
8697
|
+
const converged = Math.abs(aNext - a) < 1e-3;
|
|
8698
|
+
a = aNext;
|
|
8699
|
+
if (converged) break;
|
|
8700
|
+
}
|
|
8701
|
+
const tStar = (timeMs - glonassAlmanacEpochMs(alm)) / 1e3;
|
|
8702
|
+
const W = Math.floor(tStar / Tdr);
|
|
8703
|
+
const nodeShift = Tdr * W + alm.deltaTDot * W * W;
|
|
8704
|
+
const omegaDot = 1.5 * C20 * n * (AE / a) ** 2 * cosI * oneMinusE2 ** -2;
|
|
8705
|
+
const lambdaK = alm.lambda + (omegaDot - OMEGA_Z) * nodeShift;
|
|
8706
|
+
const tau = tStar - nodeShift;
|
|
8707
|
+
const h = e * Math.sin(alm.omega);
|
|
8708
|
+
const l = e * cosW;
|
|
8709
|
+
const E0 = 2 * Math.atan(Math.sqrt((1 - e) / (1 + e)) * Math.tan(-alm.omega / 2));
|
|
8710
|
+
const M = E0 - e * Math.sin(E0);
|
|
8711
|
+
const B = J * (AE / a) ** 2;
|
|
8712
|
+
const d1 = c20Deltas(M + alm.omega, 0, B, h, l, n, sinI, cosI);
|
|
8713
|
+
const d2 = c20Deltas(M + alm.omega + n * tau, tau, B, h, l, n, sinI, cosI);
|
|
8714
|
+
const hi = h + (d2.dh - d1.dh);
|
|
8715
|
+
const li = l + (d2.dl - d1.dl);
|
|
8716
|
+
const epsI = Math.hypot(hi, li);
|
|
8717
|
+
const omegaI = epsI === 0 ? 0 : Math.atan2(hi, li);
|
|
8718
|
+
const aI = a + a * (d2.daOverA - d1.daOverA);
|
|
8719
|
+
const iI = i + (d2.di - d1.di);
|
|
8720
|
+
const omegaG = lambdaK + (d2.dOmega - d1.dOmega) - OMEGA_Z * tau;
|
|
8721
|
+
const lambdaStar = M + alm.omega + n * tau + (d2.dLambda - d1.dLambda);
|
|
8722
|
+
const Mi = lambdaStar - omegaI;
|
|
8723
|
+
let E = Mi;
|
|
8724
|
+
for (let k = 0; k < 30; k++) {
|
|
8725
|
+
const next = Mi + epsI * Math.sin(E);
|
|
8726
|
+
const converged = Math.abs(next - E) < 1e-12;
|
|
8727
|
+
E = next;
|
|
8728
|
+
if (converged) break;
|
|
8729
|
+
}
|
|
8730
|
+
const v = 2 * Math.atan(Math.sqrt((1 + epsI) / (1 - epsI)) * Math.tan(E / 2));
|
|
8731
|
+
const u = v + omegaI;
|
|
8732
|
+
const rKm = aI * (1 - epsI * Math.cos(E));
|
|
8733
|
+
const cosU = Math.cos(u);
|
|
8734
|
+
const sinU = Math.sin(u);
|
|
8735
|
+
const cosO = Math.cos(omegaG);
|
|
8736
|
+
const sinO = Math.sin(omegaG);
|
|
8737
|
+
const cosIi = Math.cos(iI);
|
|
8738
|
+
const sinIi = Math.sin(iI);
|
|
8739
|
+
return {
|
|
8740
|
+
prn: alm.prn,
|
|
8741
|
+
x: 1e3 * rKm * (cosU * cosO - sinU * sinO * cosIi),
|
|
8742
|
+
y: 1e3 * rKm * (cosU * sinO + sinU * cosO * cosIi),
|
|
8743
|
+
z: 1e3 * rKm * sinU * sinIi,
|
|
8744
|
+
clockBias: -alm.tau
|
|
8745
|
+
};
|
|
8746
|
+
}
|
|
8747
|
+
|
|
8748
|
+
// src/orbit/index.ts
|
|
8749
|
+
var GM_GPS2 = 3986005e8;
|
|
8750
|
+
var GM_GAL2 = 3986004418e5;
|
|
8751
|
+
var GM_BDS2 = 3986004418e5;
|
|
7142
8752
|
var GM_GLO = 39860044e7;
|
|
7143
8753
|
var BDS_GEO_MAX_INCLINATION_RAD = 0.1;
|
|
7144
8754
|
var BDS_GEO_MIN_SEMIMAJOR_AXIS_M = 4e7;
|
|
@@ -7146,9 +8756,9 @@ var AE_GLO = 6378136;
|
|
|
7146
8756
|
var J2_GLO = 108263e-8;
|
|
7147
8757
|
var TWO_PI = 2 * Math.PI;
|
|
7148
8758
|
function gmForSystem(sys) {
|
|
7149
|
-
if (sys === "E") return
|
|
7150
|
-
if (sys === "C") return
|
|
7151
|
-
return
|
|
8759
|
+
if (sys === "E") return GM_GAL2;
|
|
8760
|
+
if (sys === "C") return GM_BDS2;
|
|
8761
|
+
return GM_GPS2;
|
|
7152
8762
|
}
|
|
7153
8763
|
var geoVelocityPass = false;
|
|
7154
8764
|
function keplerPosition(eph, t) {
|
|
@@ -7484,10 +9094,10 @@ function selectBest(ephs, timeMs) {
|
|
|
7484
9094
|
}
|
|
7485
9095
|
return best;
|
|
7486
9096
|
}
|
|
7487
|
-
var
|
|
7488
|
-
var
|
|
9097
|
+
var GPS_EPOCH_MS13 = START_GPS_TIME.getTime();
|
|
9098
|
+
var MS_PER_WEEK9 = 7 * 864e5;
|
|
7489
9099
|
var BDS_EPOCH_MS = START_BDS_TIME.getTime();
|
|
7490
|
-
var GAL_EPOCH_MS =
|
|
9100
|
+
var GAL_EPOCH_MS = GPS_EPOCH_MS13 + 1024 * MS_PER_WEEK9;
|
|
7491
9101
|
function ephInfoToEphemeris(info) {
|
|
7492
9102
|
const sys = info.prn.charAt(0);
|
|
7493
9103
|
if (sys === "R") {
|
|
@@ -7538,11 +9148,11 @@ function ephInfoToEphemeris(info) {
|
|
|
7538
9148
|
} else if (sys === "E") {
|
|
7539
9149
|
epochMs = GAL_EPOCH_MS;
|
|
7540
9150
|
} else {
|
|
7541
|
-
epochMs =
|
|
7542
|
-
const weeksNow = (info.lastReceived -
|
|
9151
|
+
epochMs = GPS_EPOCH_MS13;
|
|
9152
|
+
const weeksNow = (info.lastReceived - GPS_EPOCH_MS13) / MS_PER_WEEK9;
|
|
7543
9153
|
week += 1024 * Math.round((weeksNow - week) / 1024);
|
|
7544
9154
|
}
|
|
7545
|
-
const tocDate = new Date(epochMs + week *
|
|
9155
|
+
const tocDate = new Date(epochMs + week * MS_PER_WEEK9 + tocSec * 1e3);
|
|
7546
9156
|
return {
|
|
7547
9157
|
system: sys,
|
|
7548
9158
|
prn: info.prn,
|
|
@@ -7968,7 +9578,7 @@ function klobucharDelay(coeffs, latRad, lonRad, azRad, elRad, gpsTowSec) {
|
|
|
7968
9578
|
}
|
|
7969
9579
|
|
|
7970
9580
|
// src/positioning/index.ts
|
|
7971
|
-
var
|
|
9581
|
+
var GM_GPS3 = 3986005e8;
|
|
7972
9582
|
var F_REL = -4442807633e-19;
|
|
7973
9583
|
function satClockCorrection(eph, tMs) {
|
|
7974
9584
|
if (eph.system === "R" || eph.system === "S") {
|
|
@@ -7979,7 +9589,7 @@ function satClockCorrection(eph, tMs) {
|
|
|
7979
9589
|
const dt = (tMs - k.tocDate.getTime()) / 1e3;
|
|
7980
9590
|
const poly = k.af0 + k.af1 * dt + k.af2 * dt * dt;
|
|
7981
9591
|
const a = k.sqrtA * k.sqrtA;
|
|
7982
|
-
const n = Math.sqrt(
|
|
9592
|
+
const n = Math.sqrt(GM_GPS3 / (a * a * a)) + k.deltaN;
|
|
7983
9593
|
const tk = dt;
|
|
7984
9594
|
const Mk = k.m0 + n * tk;
|
|
7985
9595
|
let Ek = Mk;
|
|
@@ -10523,6 +12133,8 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
10523
12133
|
WGS84_SEMI_MAJOR_AXIS,
|
|
10524
12134
|
WGS84_SEMI_MINOR_AXIS,
|
|
10525
12135
|
WarningAccumulator,
|
|
12136
|
+
almanacEpochMs,
|
|
12137
|
+
almanacSatPosition,
|
|
10526
12138
|
analyzeQuality,
|
|
10527
12139
|
applyHelmert,
|
|
10528
12140
|
applyIonoDcb,
|
|
@@ -10619,6 +12231,8 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
10619
12231
|
getWeekNumber,
|
|
10620
12232
|
getWeekOfYear,
|
|
10621
12233
|
gloFreq,
|
|
12234
|
+
glonassAlmanacEpochMs,
|
|
12235
|
+
glonassAlmanacPosition,
|
|
10622
12236
|
glonassPosition,
|
|
10623
12237
|
greatCircleMidpoint,
|
|
10624
12238
|
hdrLine,
|
|
@@ -10642,7 +12256,11 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
10642
12256
|
parseNovatelRange,
|
|
10643
12257
|
parseRinexStream,
|
|
10644
12258
|
parseSbfAlmanac,
|
|
12259
|
+
parseSbfBdsNav,
|
|
10645
12260
|
parseSbfCnav,
|
|
12261
|
+
parseSbfGalNav,
|
|
12262
|
+
parseSbfGloNav,
|
|
12263
|
+
parseSbfHas,
|
|
10646
12264
|
parseSbfIonoUtc,
|
|
10647
12265
|
parseSbfMeas,
|
|
10648
12266
|
parseSbfNav,
|