gnss-js 1.19.0 → 1.20.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/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,10 @@ __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,
227
234
  parseSbfIonoUtc: () => parseSbfIonoUtc,
228
235
  parseSbfMeas: () => parseSbfMeas,
229
236
  parseSbfNav: () => parseSbfNav,
@@ -5414,20 +5421,20 @@ var SIGNALS = {
5414
5421
  // GLONASS L1OF, L2OF
5415
5422
  };
5416
5423
  function prnFor(gnssId, svId) {
5417
- const two3 = (n) => String(n).padStart(2, "0");
5424
+ const two4 = (n) => String(n).padStart(2, "0");
5418
5425
  switch (gnssId) {
5419
5426
  case 0:
5420
- return svId >= 1 && svId <= 32 ? `G${two3(svId)}` : null;
5427
+ return svId >= 1 && svId <= 32 ? `G${two4(svId)}` : null;
5421
5428
  case 1:
5422
- return svId >= 120 && svId <= 158 ? `S${two3(svId - 100)}` : null;
5429
+ return svId >= 120 && svId <= 158 ? `S${two4(svId - 100)}` : null;
5423
5430
  case 2:
5424
- return svId >= 1 && svId <= 36 ? `E${two3(svId)}` : null;
5431
+ return svId >= 1 && svId <= 36 ? `E${two4(svId)}` : null;
5425
5432
  case 3:
5426
- return svId >= 1 && svId <= 63 ? `C${two3(svId)}` : null;
5433
+ return svId >= 1 && svId <= 63 ? `C${two4(svId)}` : null;
5427
5434
  case 5:
5428
- return svId >= 1 && svId <= 10 ? `J${two3(svId)}` : null;
5435
+ return svId >= 1 && svId <= 10 ? `J${two4(svId)}` : null;
5429
5436
  case 6:
5430
- return svId >= 1 && svId <= 32 ? `R${two3(svId)}` : null;
5437
+ return svId >= 1 && svId <= 32 ? `R${two4(svId)}` : null;
5431
5438
  default:
5432
5439
  return null;
5433
5440
  }
@@ -5927,10 +5934,896 @@ function parseSbfCnav(data) {
5927
5934
  return { ephemerides, badCrc, messages };
5928
5935
  }
5929
5936
 
5937
+ // src/navbits/gal.ts
5938
+ var GPS_EPOCH_MS6 = Date.UTC(1980, 0, 6);
5939
+ var SEC_PER_WEEK5 = 7 * 86400;
5940
+ var HALF_WEEK2 = 302400;
5941
+ var GST_GPS_WEEK_OFFSET = 1024;
5942
+ function galInavPageCrcOk(page) {
5943
+ if (page.length < 28) return false;
5944
+ return crc24q(page, 196) === getBitU(page, 196, 24);
5945
+ }
5946
+ function galFnavPageCrcOk(page) {
5947
+ if (page.length < 30) return false;
5948
+ return crc24q(page, 214) === getBitU(page, 214, 24);
5949
+ }
5950
+ function gpsDate2(week, sec) {
5951
+ return new Date(GPS_EPOCH_MS6 + (week * SEC_PER_WEEK5 + sec) * 1e3);
5952
+ }
5953
+ function weekOfToe(week, tow, toe) {
5954
+ if (toe - tow > HALF_WEEK2) return week - 1;
5955
+ if (toe - tow < -HALF_WEEK2) return week + 1;
5956
+ return week;
5957
+ }
5958
+ var two2 = (n) => String(n).padStart(2, "0");
5959
+ function decodeGalInavWords(words) {
5960
+ if (words.length < 96) return null;
5961
+ const b = words;
5962
+ let i = 128;
5963
+ const type1 = getBitU(b, i, 6);
5964
+ i += 6;
5965
+ const iodNav1 = getBitU(b, i, 10);
5966
+ i += 10;
5967
+ const toes = getBitU(b, i, 14) * 60;
5968
+ i += 14;
5969
+ const m0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
5970
+ i += 32;
5971
+ const e = getBitU(b, i, 32) * 2 ** -33;
5972
+ i += 32;
5973
+ const sqrtA = getBitU(b, i, 32) * 2 ** -19;
5974
+ i = 128 * 2;
5975
+ const type2 = getBitU(b, i, 6);
5976
+ i += 6;
5977
+ const iodNav2 = getBitU(b, i, 10);
5978
+ i += 10;
5979
+ const omega0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
5980
+ i += 32;
5981
+ const i0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
5982
+ i += 32;
5983
+ const omega = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
5984
+ i += 32;
5985
+ const idot = getBitS(b, i, 14) * 2 ** -43 * GPS_PI;
5986
+ i = 128 * 3;
5987
+ const type3 = getBitU(b, i, 6);
5988
+ i += 6;
5989
+ const iodNav3 = getBitU(b, i, 10);
5990
+ i += 10;
5991
+ const omegaDot = getBitS(b, i, 24) * 2 ** -43 * GPS_PI;
5992
+ i += 24;
5993
+ const deltaN = getBitS(b, i, 16) * 2 ** -43 * GPS_PI;
5994
+ i += 16;
5995
+ const cuc = getBitS(b, i, 16) * 2 ** -29;
5996
+ i += 16;
5997
+ const cus = getBitS(b, i, 16) * 2 ** -29;
5998
+ i += 16;
5999
+ const crc = getBitS(b, i, 16) * 2 ** -5;
6000
+ i += 16;
6001
+ const crs = getBitS(b, i, 16) * 2 ** -5;
6002
+ i = 128 * 4;
6003
+ const type4 = getBitU(b, i, 6);
6004
+ i += 6;
6005
+ const iodNav4 = getBitU(b, i, 10);
6006
+ i += 10;
6007
+ const svid = getBitU(b, i, 6);
6008
+ i += 6;
6009
+ const cic = getBitS(b, i, 16) * 2 ** -29;
6010
+ i += 16;
6011
+ const cis = getBitS(b, i, 16) * 2 ** -29;
6012
+ i += 16;
6013
+ const tocs = getBitU(b, i, 14) * 60;
6014
+ i += 14;
6015
+ const af0 = getBitS(b, i, 31) * 2 ** -34;
6016
+ i += 31;
6017
+ const af1 = getBitS(b, i, 21) * 2 ** -46;
6018
+ i += 21;
6019
+ const af2 = getBitS(b, i, 6) * 2 ** -59;
6020
+ i = 128 * 5;
6021
+ const type5 = getBitU(b, i, 6);
6022
+ i += 6 + 11 + 11 + 14 + 5;
6023
+ const bgdE5a = getBitS(b, i, 10) * 2 ** -32;
6024
+ i += 10;
6025
+ i += 10;
6026
+ const e5bHs = getBitU(b, i, 2);
6027
+ i += 2;
6028
+ const e1bHs = getBitU(b, i, 2);
6029
+ i += 2;
6030
+ const e5bDvs = getBitU(b, i, 1);
6031
+ i += 1;
6032
+ const e1bDvs = getBitU(b, i, 1);
6033
+ i += 1;
6034
+ const gstWeek = getBitU(b, i, 12);
6035
+ i += 12;
6036
+ const tow = getBitU(b, i, 20);
6037
+ if (type1 !== 1 || type2 !== 2 || type3 !== 3 || type4 !== 4 || type5 !== 5)
6038
+ return null;
6039
+ if (iodNav1 !== iodNav2 || iodNav1 !== iodNav3 || iodNav1 !== iodNav4)
6040
+ return null;
6041
+ if (svid < 1 || svid > 36) return null;
6042
+ const week = weekOfToe(gstWeek, tow, toes) + GST_GPS_WEEK_OFFSET;
6043
+ const tocDate = gpsDate2(week, tocs);
6044
+ return {
6045
+ system: "E",
6046
+ prn: `E${two2(svid)}`,
6047
+ toc: tocDate.getTime() / 1e3 % SEC_PER_WEEK5,
6048
+ tocDate,
6049
+ af0,
6050
+ af1,
6051
+ af2,
6052
+ iode: iodNav1,
6053
+ crs,
6054
+ deltaN,
6055
+ m0,
6056
+ cuc,
6057
+ e,
6058
+ cus,
6059
+ sqrtA,
6060
+ toe: toes,
6061
+ cic,
6062
+ omega0,
6063
+ cis,
6064
+ i0,
6065
+ crc,
6066
+ omega,
6067
+ omegaDot,
6068
+ idot,
6069
+ week,
6070
+ svHealth: e5bHs << 7 | e5bDvs << 6 | e1bHs << 1 | e1bDvs,
6071
+ tgd: bgdE5a
6072
+ };
6073
+ }
6074
+ function decodeGalFnavPages(pages) {
6075
+ if (pages.length < 124) return null;
6076
+ const b = pages;
6077
+ let i = 0;
6078
+ const type1 = getBitU(b, i, 6);
6079
+ i += 6;
6080
+ const svid = getBitU(b, i, 6);
6081
+ i += 6;
6082
+ const iodNav1 = getBitU(b, i, 10);
6083
+ i += 10;
6084
+ const tocs = getBitU(b, i, 14) * 60;
6085
+ i += 14;
6086
+ const af0 = getBitS(b, i, 31) * 2 ** -34;
6087
+ i += 31;
6088
+ const af1 = getBitS(b, i, 21) * 2 ** -46;
6089
+ i += 21;
6090
+ const af2 = getBitS(b, i, 6) * 2 ** -59;
6091
+ i += 6;
6092
+ i += 8 + 11 + 11 + 14 + 5;
6093
+ const bgdE5a = getBitS(b, i, 10) * 2 ** -32;
6094
+ i += 10;
6095
+ const e5aHs = getBitU(b, i, 2);
6096
+ i += 2;
6097
+ const gstWeek = getBitU(b, i, 12);
6098
+ i += 12;
6099
+ const tow = getBitU(b, i, 20);
6100
+ i += 20;
6101
+ const e5aDvs = getBitU(b, i, 1);
6102
+ i = 31 * 8;
6103
+ const type2 = getBitU(b, i, 6);
6104
+ i += 6;
6105
+ const iodNav2 = getBitU(b, i, 10);
6106
+ i += 10;
6107
+ const m0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
6108
+ i += 32;
6109
+ const omegaDot = getBitS(b, i, 24) * 2 ** -43 * GPS_PI;
6110
+ i += 24;
6111
+ const e = getBitU(b, i, 32) * 2 ** -33;
6112
+ i += 32;
6113
+ const sqrtA = getBitU(b, i, 32) * 2 ** -19;
6114
+ i += 32;
6115
+ const omega0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
6116
+ i += 32;
6117
+ const idot = getBitS(b, i, 14) * 2 ** -43 * GPS_PI;
6118
+ i = 62 * 8;
6119
+ const type3 = getBitU(b, i, 6);
6120
+ i += 6;
6121
+ const iodNav3 = getBitU(b, i, 10);
6122
+ i += 10;
6123
+ const i0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
6124
+ i += 32;
6125
+ const omega = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
6126
+ i += 32;
6127
+ const deltaN = getBitS(b, i, 16) * 2 ** -43 * GPS_PI;
6128
+ i += 16;
6129
+ const cuc = getBitS(b, i, 16) * 2 ** -29;
6130
+ i += 16;
6131
+ const cus = getBitS(b, i, 16) * 2 ** -29;
6132
+ i += 16;
6133
+ const crc = getBitS(b, i, 16) * 2 ** -5;
6134
+ i += 16;
6135
+ const crs = getBitS(b, i, 16) * 2 ** -5;
6136
+ i += 16;
6137
+ const toes = getBitU(b, i, 14) * 60;
6138
+ i = 93 * 8;
6139
+ const type4 = getBitU(b, i, 6);
6140
+ i += 6;
6141
+ const iodNav4 = getBitU(b, i, 10);
6142
+ i += 10;
6143
+ const cic = getBitS(b, i, 16) * 2 ** -29;
6144
+ i += 16;
6145
+ const cis = getBitS(b, i, 16) * 2 ** -29;
6146
+ if (type1 !== 1 || type2 !== 2 || type3 !== 3 || type4 !== 4) return null;
6147
+ if (iodNav1 !== iodNav2 || iodNav1 !== iodNav3 || iodNav1 !== iodNav4)
6148
+ return null;
6149
+ if (svid < 1 || svid > 36) return null;
6150
+ const week = weekOfToe(gstWeek, tow, toes) + GST_GPS_WEEK_OFFSET;
6151
+ const tocDate = gpsDate2(week, tocs);
6152
+ return {
6153
+ system: "E",
6154
+ prn: `E${two2(svid)}`,
6155
+ toc: tocDate.getTime() / 1e3 % SEC_PER_WEEK5,
6156
+ tocDate,
6157
+ af0,
6158
+ af1,
6159
+ af2,
6160
+ iode: iodNav1,
6161
+ crs,
6162
+ deltaN,
6163
+ m0,
6164
+ cuc,
6165
+ e,
6166
+ cus,
6167
+ sqrtA,
6168
+ toe: toes,
6169
+ cic,
6170
+ omega0,
6171
+ cis,
6172
+ i0,
6173
+ crc,
6174
+ omega,
6175
+ omegaDot,
6176
+ idot,
6177
+ week,
6178
+ svHealth: e5aHs << 4 | e5aDvs << 3,
6179
+ tgd: bgdE5a
6180
+ };
6181
+ }
6182
+ var dedupKey = (eph) => `${eph.iode}:${eph.toe}:${eph.tocDate.getTime()}`;
6183
+ var GalInavAssembler = class {
6184
+ sats = /* @__PURE__ */ new Map();
6185
+ /**
6186
+ * Push one I/NAV page pair for satellite `prn` (1-36): the 234-bit
6187
+ * even+odd concatenation, even part first with its 6 tail bits
6188
+ * removed, bit 0 = the even part's Even/Odd bit (≥ 17 bytes).
6189
+ * Returns the newly completed ephemeris, or null. Pages that are
6190
+ * not an even/odd nominal pair, alert pages and word types outside
6191
+ * 1-5 are ignored.
6192
+ */
6193
+ push(prn, page) {
6194
+ if (prn < 1 || prn > 36 || page.length < 17) return null;
6195
+ if (getBitU(page, 0, 1) !== 0 || getBitU(page, 114, 1) !== 1) return null;
6196
+ if (getBitU(page, 1, 1) === 1 || getBitU(page, 115, 1) === 1) return null;
6197
+ const type = getBitU(page, 2, 6);
6198
+ if (type < 1 || type > 5) return null;
6199
+ let sat = this.sats.get(prn);
6200
+ if (!sat) {
6201
+ sat = { words: new Uint8Array(96) };
6202
+ this.sats.set(prn, sat);
6203
+ }
6204
+ for (let k = 0; k < 14; k++)
6205
+ sat.words[type * 16 + k] = getBitU(page, 2 + 8 * k, 8);
6206
+ sat.words[type * 16 + 14] = getBitU(page, 116, 8);
6207
+ sat.words[type * 16 + 15] = getBitU(page, 124, 8);
6208
+ if (type !== 5) return null;
6209
+ const eph = decodeGalInavWords(sat.words);
6210
+ if (!eph || eph.prn !== `E${two2(prn)}`) return null;
6211
+ const key = dedupKey(eph);
6212
+ if (key === sat.lastKey) return null;
6213
+ sat.lastKey = key;
6214
+ return eph;
6215
+ }
6216
+ };
6217
+ var GalFnavAssembler = class {
6218
+ sats = /* @__PURE__ */ new Map();
6219
+ /**
6220
+ * Push one F/NAV page for satellite `prn` (1-36): 244 bits with the
6221
+ * sync field stripped, bit 0 = first page-type bit (≥ 31 bytes).
6222
+ * Returns the newly completed ephemeris, or null. Dummy pages
6223
+ * (type 63) and page types outside 1-4 are ignored.
6224
+ */
6225
+ push(prn, page) {
6226
+ if (prn < 1 || prn > 36 || page.length < 31) return null;
6227
+ const type = getBitU(page, 0, 6);
6228
+ if (type < 1 || type > 4) return null;
6229
+ let sat = this.sats.get(prn);
6230
+ if (!sat) {
6231
+ sat = { words: new Uint8Array(124) };
6232
+ this.sats.set(prn, sat);
6233
+ }
6234
+ sat.words.set(page.subarray(0, 31), (type - 1) * 31);
6235
+ if (type !== 4) return null;
6236
+ const eph = decodeGalFnavPages(sat.words);
6237
+ if (!eph || eph.prn !== `E${two2(prn)}`) return null;
6238
+ const key = dedupKey(eph);
6239
+ if (key === sat.lastKey) return null;
6240
+ sat.lastKey = key;
6241
+ return eph;
6242
+ }
6243
+ };
6244
+
6245
+ // src/sbf/rawnav-gal.ts
6246
+ var INAV_SOURCES = [17, 21, 22];
6247
+ var FNAV_SOURCES = [20, 22];
6248
+ function parseSbfGalNav(data) {
6249
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
6250
+ const ephemerides = [];
6251
+ const inav = new GalInavAssembler();
6252
+ const fnav = new GalFnavAssembler();
6253
+ let badCrc = 0;
6254
+ let messages = 0;
6255
+ scanSbfFrames(data, view, (id, b, len) => {
6256
+ if (id !== 4022 && id !== 4023 || len < 52) return;
6257
+ messages++;
6258
+ const prnStr = svidToPrn(data[b + 14]);
6259
+ if (!prnStr || prnStr[0] !== "E") return;
6260
+ const prn = parseInt(prnStr.slice(1), 10);
6261
+ const source = data[b + 17] & 31;
6262
+ const page = new Uint8Array(32);
6263
+ for (let k = 0; k < 8; k++) {
6264
+ const w = view.getUint32(b + 20 + 4 * k, true);
6265
+ page[4 * k] = w >>> 24;
6266
+ page[4 * k + 1] = w >>> 16 & 255;
6267
+ page[4 * k + 2] = w >>> 8 & 255;
6268
+ page[4 * k + 3] = w & 255;
6269
+ }
6270
+ let eph;
6271
+ let src;
6272
+ if (id === 4023) {
6273
+ src = "inav";
6274
+ if (!INAV_SOURCES.includes(source)) return;
6275
+ if (getBitU2(page, 0) !== 0 || getBitU2(page, 114) !== 1) return;
6276
+ if (!galInavPageCrcOk(page)) {
6277
+ badCrc++;
6278
+ return;
6279
+ }
6280
+ eph = inav.push(prn, page);
6281
+ } else {
6282
+ src = "fnav";
6283
+ if (!FNAV_SOURCES.includes(source)) return;
6284
+ if (isFnavDummy(page)) return;
6285
+ if (!galFnavPageCrcOk(page)) {
6286
+ badCrc++;
6287
+ return;
6288
+ }
6289
+ eph = fnav.push(prn, page);
6290
+ }
6291
+ if (eph) ephemerides.push({ ...eph, source: src });
6292
+ });
6293
+ return { ephemerides, badCrc, messages };
6294
+ }
6295
+ function getBitU2(buff, pos) {
6296
+ return buff[pos >> 3] >> 7 - (pos & 7) & 1;
6297
+ }
6298
+ function isFnavDummy(page) {
6299
+ return page[0] >> 2 === 63;
6300
+ }
6301
+
6302
+ // src/navbits/bds.ts
6303
+ var BDT_EPOCH_MS2 = Date.UTC(2006, 0, 1);
6304
+ var SEC_PER_WEEK6 = 7 * 86400;
6305
+ var MS_PER_WEEK4 = SEC_PER_WEEK6 * 1e3;
6306
+ var HALF_WEEK3 = 302400;
6307
+ var sowOf2 = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK6;
6308
+ var BDS_SUBFRAME_BYTES = 38;
6309
+ function getBitU22(b, p1, l1, p2, l2) {
6310
+ return getBitU(b, p1, l1) * 2 ** l2 + getBitU(b, p2, l2);
6311
+ }
6312
+ function getBitS2(b, p1, l1, p2, l2) {
6313
+ return getBitS(b, p1, l1) * 2 ** l2 + getBitU(b, p2, l2);
6314
+ }
6315
+ function getBitU3(b, p1, l1, p2, l2, p3, l3) {
6316
+ return getBitU(b, p1, l1) * 2 ** (l2 + l3) + getBitU(b, p2, l2) * 2 ** l3 + getBitU(b, p3, l3);
6317
+ }
6318
+ function getBitS3(b, p1, l1, p2, l2, p3, l3) {
6319
+ return getBitS(b, p1, l1) * 2 ** (l2 + l3) + getBitU(b, p2, l2) * 2 ** l3 + getBitU(b, p3, l3);
6320
+ }
6321
+ var mergeS = (hi, lo, n) => hi * 2 ** n + lo;
6322
+ function bchOk(cw) {
6323
+ for (let i = 14; i >= 4; i--) {
6324
+ if (cw & 1 << i) cw ^= 19 << i - 4;
6325
+ }
6326
+ return cw === 0;
6327
+ }
6328
+ function bdsSubframeParityOk(subframe) {
6329
+ if (subframe.length < BDS_SUBFRAME_BYTES) return false;
6330
+ if (!bchOk(getBitU(subframe, 15, 15))) return false;
6331
+ for (let w = 1; w < 10; w++) {
6332
+ const base = 30 * w;
6333
+ const cw1 = getBitU(subframe, base, 11) * 16 + getBitU(subframe, base + 22, 4);
6334
+ const cw2 = getBitU(subframe, base + 11, 11) * 16 + getBitU(subframe, base + 26, 4);
6335
+ if (!bchOk(cw1) || !bchOk(cw2)) return false;
6336
+ }
6337
+ return true;
6338
+ }
6339
+ function buildBdsEphemeris(prn, f) {
6340
+ let week = f.week;
6341
+ if (f.toes < f.sow - HALF_WEEK3) week++;
6342
+ else if (f.toes > f.sow + HALF_WEEK3) week--;
6343
+ const tocDate = new Date(BDT_EPOCH_MS2 + week * MS_PER_WEEK4 + f.tocSec * 1e3);
6344
+ return {
6345
+ system: "C",
6346
+ prn,
6347
+ toc: sowOf2(tocDate.getTime()),
6348
+ tocDate,
6349
+ af0: f.af0,
6350
+ af1: f.af1,
6351
+ af2: f.af2,
6352
+ // AODE is not in the ephemeris subframes; RTKLIB derives the RINEX
6353
+ // IODE/AODE slot from toc per the BDS ICD update schedule.
6354
+ iode: Math.floor(f.tocSec / 720) % 240,
6355
+ crs: f.crs,
6356
+ deltaN: f.deltaN,
6357
+ m0: f.m0,
6358
+ cuc: f.cuc,
6359
+ e: f.e,
6360
+ cus: f.cus,
6361
+ sqrtA: f.sqrtA,
6362
+ toe: f.toes,
6363
+ cic: f.cic,
6364
+ omega0: f.omega0,
6365
+ cis: f.cis,
6366
+ i0: f.i0,
6367
+ crc: f.crc,
6368
+ omega: f.omega,
6369
+ omegaDot: f.omegaDot,
6370
+ idot: f.idot,
6371
+ week,
6372
+ // RINEX BDS week field is the BDT week of toe
6373
+ svHealth: f.svh,
6374
+ // SatH1
6375
+ tgd: f.tgd1
6376
+ // TGD1 (B1) — RINEX slot
6377
+ };
6378
+ }
6379
+ function decodeBdsD1Frame(subframes, opts = {}) {
6380
+ if (subframes.length < 3 * BDS_SUBFRAME_BYTES) return null;
6381
+ const b = subframes;
6382
+ let i = 8 * 38 * 0;
6383
+ const frn1 = getBitU(b, i + 15, 3);
6384
+ const sow1 = getBitU22(b, i + 18, 8, i + 30, 12);
6385
+ const svh = getBitU(b, i + 42, 1);
6386
+ const week = getBitU(b, i + 60, 13);
6387
+ const tocSec = getBitU22(b, i + 73, 9, i + 90, 8) * 8;
6388
+ const tgd1 = getBitS(b, i + 98, 10) * 0.1 * 1e-9;
6389
+ const af2 = getBitS(b, i + 214, 11) * 2 ** -66;
6390
+ const af0 = getBitS2(b, i + 225, 7, i + 240, 17) * 2 ** -33;
6391
+ const af1 = getBitS2(b, i + 257, 5, i + 270, 17) * 2 ** -50;
6392
+ i = 8 * 38 * 1;
6393
+ const frn2 = getBitU(b, i + 15, 3);
6394
+ const sow2 = getBitU22(b, i + 18, 8, i + 30, 12);
6395
+ const deltaN = getBitS2(b, i + 42, 10, i + 60, 6) * 2 ** -43 * GPS_PI;
6396
+ const cuc = getBitS2(b, i + 66, 16, i + 90, 2) * 2 ** -31;
6397
+ const m0 = getBitS2(b, i + 92, 20, i + 120, 12) * 2 ** -31 * GPS_PI;
6398
+ const e = getBitU22(b, i + 132, 10, i + 150, 22) * 2 ** -33;
6399
+ const cus = getBitS(b, i + 180, 18) * 2 ** -31;
6400
+ const crc = getBitS2(b, i + 198, 4, i + 210, 14) * 2 ** -6;
6401
+ const crs = getBitS2(b, i + 224, 8, i + 240, 10) * 2 ** -6;
6402
+ const sqrtA = getBitU22(b, i + 250, 12, i + 270, 20) * 2 ** -19;
6403
+ const toe1 = getBitU(b, i + 290, 2);
6404
+ i = 8 * 38 * 2;
6405
+ const frn3 = getBitU(b, i + 15, 3);
6406
+ const sow3 = getBitU22(b, i + 18, 8, i + 30, 12);
6407
+ const toe2 = getBitU22(b, i + 42, 10, i + 60, 5);
6408
+ const i0 = getBitS2(b, i + 65, 17, i + 90, 15) * 2 ** -31 * GPS_PI;
6409
+ const cic = getBitS2(b, i + 105, 7, i + 120, 11) * 2 ** -31;
6410
+ const omegaDot = getBitS2(b, i + 131, 11, i + 150, 13) * 2 ** -43 * GPS_PI;
6411
+ const cis = getBitS2(b, i + 163, 9, i + 180, 9) * 2 ** -31;
6412
+ const idot = getBitS2(b, i + 189, 13, i + 210, 1) * 2 ** -43 * GPS_PI;
6413
+ const omega0 = getBitS2(b, i + 211, 21, i + 240, 11) * 2 ** -31 * GPS_PI;
6414
+ const omega = getBitS2(b, i + 251, 11, i + 270, 21) * 2 ** -31 * GPS_PI;
6415
+ const toes = (toe1 * 2 ** 15 + toe2) * 8;
6416
+ if (frn1 !== 1 || frn2 !== 2 || frn3 !== 3) return null;
6417
+ if (sow2 !== sow1 + 6 || sow3 !== sow2 + 6) return null;
6418
+ if (tocSec !== toes) return null;
6419
+ return buildBdsEphemeris(opts.prn ?? "C00", {
6420
+ week,
6421
+ sow: sow1,
6422
+ toes,
6423
+ tocSec,
6424
+ svh,
6425
+ tgd1,
6426
+ af0,
6427
+ af1,
6428
+ af2,
6429
+ crs,
6430
+ deltaN,
6431
+ m0,
6432
+ cuc,
6433
+ e,
6434
+ cus,
6435
+ sqrtA,
6436
+ cic,
6437
+ omega0,
6438
+ cis,
6439
+ i0,
6440
+ crc,
6441
+ omega,
6442
+ omegaDot,
6443
+ idot
6444
+ });
6445
+ }
6446
+ function decodeBdsD2Frame(pages, opts = {}) {
6447
+ if (pages.length < 10 * BDS_SUBFRAME_BYTES) return null;
6448
+ const b = pages;
6449
+ let i = 8 * 38 * 0;
6450
+ const pgn1 = getBitU(b, i + 42, 4);
6451
+ const sow1 = getBitU22(b, i + 18, 8, i + 30, 12);
6452
+ const svh = getBitU(b, i + 46, 1);
6453
+ const week = getBitU(b, i + 64, 13);
6454
+ const tocSec = getBitU22(b, i + 77, 5, i + 90, 12) * 8;
6455
+ const tgd1 = getBitS(b, i + 102, 10) * 0.1 * 1e-9;
6456
+ i = 8 * 38 * 2;
6457
+ const pgn3 = getBitU(b, i + 42, 4);
6458
+ const sow3 = getBitU22(b, i + 18, 8, i + 30, 12);
6459
+ const af0 = getBitS2(b, i + 100, 12, i + 120, 12) * 2 ** -33;
6460
+ const af1p3 = getBitS(b, i + 132, 4);
6461
+ i = 8 * 38 * 3;
6462
+ const pgn4 = getBitU(b, i + 42, 4);
6463
+ const sow4 = getBitU22(b, i + 18, 8, i + 30, 12);
6464
+ const af1p4 = getBitU22(b, i + 46, 6, i + 60, 12);
6465
+ const af2 = getBitS2(b, i + 72, 10, i + 90, 1) * 2 ** -66;
6466
+ const deltaN = getBitS(b, i + 96, 16) * 2 ** -43 * GPS_PI;
6467
+ const cucp4 = getBitS(b, i + 120, 14);
6468
+ i = 8 * 38 * 4;
6469
+ const pgn5 = getBitU(b, i + 42, 4);
6470
+ const sow5 = getBitU22(b, i + 18, 8, i + 30, 12);
6471
+ const cucp5 = getBitU(b, i + 46, 4);
6472
+ const m0 = getBitS3(b, i + 50, 2, i + 60, 22, i + 90, 8) * 2 ** -31 * GPS_PI;
6473
+ const cus = getBitS2(b, i + 98, 14, i + 120, 4) * 2 ** -31;
6474
+ const ep5 = getBitS(b, i + 124, 10);
6475
+ i = 8 * 38 * 5;
6476
+ const pgn6 = getBitU(b, i + 42, 4);
6477
+ const sow6 = getBitU22(b, i + 18, 8, i + 30, 12);
6478
+ const ep6 = getBitU22(b, i + 46, 6, i + 60, 16);
6479
+ const sqrtA = getBitU3(b, i + 76, 6, i + 90, 22, i + 120, 4) * 2 ** -19;
6480
+ const cicp6 = getBitS(b, i + 124, 10);
6481
+ i = 8 * 38 * 6;
6482
+ const pgn7 = getBitU(b, i + 42, 4);
6483
+ const sow7 = getBitU22(b, i + 18, 8, i + 30, 12);
6484
+ const cicp7 = getBitU22(b, i + 46, 6, i + 60, 2);
6485
+ const cis = getBitS(b, i + 62, 18) * 2 ** -31;
6486
+ const toes = getBitU22(b, i + 80, 2, i + 90, 15) * 8;
6487
+ const i0p7 = getBitS2(b, i + 105, 7, i + 120, 14);
6488
+ i = 8 * 38 * 7;
6489
+ const pgn8 = getBitU(b, i + 42, 4);
6490
+ const sow8 = getBitU22(b, i + 18, 8, i + 30, 12);
6491
+ const i0p8 = getBitU22(b, i + 46, 6, i + 60, 5);
6492
+ const crc = getBitS2(b, i + 65, 17, i + 90, 1) * 2 ** -6;
6493
+ const crs = getBitS(b, i + 91, 18) * 2 ** -6;
6494
+ const omegaDotP8 = getBitS2(b, i + 109, 3, i + 120, 16);
6495
+ i = 8 * 38 * 8;
6496
+ const pgn9 = getBitU(b, i + 42, 4);
6497
+ const sow9 = getBitU22(b, i + 18, 8, i + 30, 12);
6498
+ const omegaDotP9 = getBitU(b, i + 46, 5);
6499
+ const omega0 = getBitS3(b, i + 51, 1, i + 60, 22, i + 90, 9) * 2 ** -31 * GPS_PI;
6500
+ const omegaP9 = getBitS2(b, i + 99, 13, i + 120, 14);
6501
+ i = 8 * 38 * 9;
6502
+ const pgn10 = getBitU(b, i + 42, 4);
6503
+ const sow10 = getBitU22(b, i + 18, 8, i + 30, 12);
6504
+ const omegaP10 = getBitU(b, i + 46, 5);
6505
+ const idot = getBitS2(b, i + 51, 1, i + 60, 13) * 2 ** -43 * GPS_PI;
6506
+ if (pgn1 !== 1 || pgn3 !== 3 || pgn4 !== 4 || pgn5 !== 5 || pgn6 !== 6 || pgn7 !== 7 || pgn8 !== 8 || pgn9 !== 9 || pgn10 !== 10) {
6507
+ return null;
6508
+ }
6509
+ 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) {
6510
+ return null;
6511
+ }
6512
+ if (tocSec !== toes) return null;
6513
+ return buildBdsEphemeris(opts.prn ?? "C00", {
6514
+ week,
6515
+ sow: sow1,
6516
+ toes,
6517
+ tocSec,
6518
+ svh,
6519
+ tgd1,
6520
+ af0,
6521
+ af1: mergeS(af1p3, af1p4, 18) * 2 ** -50,
6522
+ af2,
6523
+ crs,
6524
+ deltaN,
6525
+ m0,
6526
+ cuc: mergeS(cucp4, cucp5, 4) * 2 ** -31,
6527
+ e: mergeS(ep5, ep6, 22) * 2 ** -33,
6528
+ cus,
6529
+ sqrtA,
6530
+ cic: mergeS(cicp6, cicp7, 8) * 2 ** -31,
6531
+ omega0,
6532
+ cis,
6533
+ i0: mergeS(i0p7, i0p8, 11) * 2 ** -31 * GPS_PI,
6534
+ crc,
6535
+ omega: mergeS(omegaP9, omegaP10, 5) * 2 ** -31 * GPS_PI,
6536
+ omegaDot: mergeS(omegaDotP8, omegaDotP9, 5) * 2 ** -43 * GPS_PI,
6537
+ idot
6538
+ });
6539
+ }
6540
+ function isBdsGeoPrn(prn) {
6541
+ return prn < 6 || prn > 58;
6542
+ }
6543
+ var BdsAssembler = class {
6544
+ sats = /* @__PURE__ */ new Map();
6545
+ /**
6546
+ * Push one 300-bit subframe (38+ bytes, bit 0 = first bit of the
6547
+ * preamble) for the satellite `prn` ("C06"). Returns the newly
6548
+ * completed ephemeris, or null.
6549
+ */
6550
+ push(prn, subframe) {
6551
+ if (subframe.length < BDS_SUBFRAME_BYTES) return null;
6552
+ const num = parseInt(prn.slice(1), 10);
6553
+ if (!Number.isFinite(num) || num < 1 || num > 63) return null;
6554
+ const id = getBitU(subframe, 15, 3);
6555
+ if (id < 1 || id > 5) return null;
6556
+ let sat = this.sats.get(prn);
6557
+ if (!sat) {
6558
+ sat = { buf: new Uint8Array(10 * BDS_SUBFRAME_BYTES) };
6559
+ this.sats.set(prn, sat);
6560
+ }
6561
+ let eph = null;
6562
+ if (!isBdsGeoPrn(num)) {
6563
+ sat.buf.set(subframe.subarray(0, BDS_SUBFRAME_BYTES), (id - 1) * 38);
6564
+ if (id === 3) eph = decodeBdsD1Frame(sat.buf, { prn });
6565
+ } else {
6566
+ if (id !== 1) return null;
6567
+ const pgn = getBitU(subframe, 42, 4);
6568
+ if (pgn < 1 || pgn > 10) return null;
6569
+ sat.buf.set(subframe.subarray(0, BDS_SUBFRAME_BYTES), (pgn - 1) * 38);
6570
+ if (pgn === 10) eph = decodeBdsD2Frame(sat.buf, { prn });
6571
+ }
6572
+ if (!eph) return null;
6573
+ const key = `${eph.week}:${eph.toe}`;
6574
+ if (key === sat.lastKey) return null;
6575
+ sat.lastKey = key;
6576
+ return eph;
6577
+ }
6578
+ };
6579
+
6580
+ // src/navbits/glo.ts
6581
+ var GPS_EPOCH_MS7 = Date.UTC(1980, 0, 6);
6582
+ var SEC_PER_WEEK7 = 7 * 86400;
6583
+ var SEC_PER_DAY = 86400;
6584
+ var GLO_STRING_BYTES = 10;
6585
+ function getBitG(b, pos, len) {
6586
+ const value = getBitU(b, pos + 1, len - 1);
6587
+ return getBitU(b, pos, 1) && value !== 0 ? -value : value;
6588
+ }
6589
+ var HAMMING_MASKS = [
6590
+ [85, 85, 90, 170, 170, 170, 181, 85, 106, 216, 8],
6591
+ [102, 102, 108, 204, 204, 204, 217, 153, 179, 104, 16],
6592
+ [135, 135, 143, 15, 15, 15, 30, 30, 60, 112, 32],
6593
+ [7, 248, 15, 240, 15, 240, 31, 224, 63, 128, 64],
6594
+ [248, 0, 15, 255, 240, 0, 31, 255, 192, 0, 128],
6595
+ [0, 0, 15, 255, 255, 255, 224, 0, 0, 1, 0],
6596
+ [255, 255, 240, 0, 0, 0, 0, 0, 0, 2, 0],
6597
+ [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 248]
6598
+ ];
6599
+ function testGloString(buff) {
6600
+ if (buff.length < 11) return false;
6601
+ let n = 0;
6602
+ let cs = 0;
6603
+ for (const mask of HAMMING_MASKS) {
6604
+ cs = 0;
6605
+ for (let j = 0; j < 11; j++) {
6606
+ let x = buff[j] & mask[j];
6607
+ x ^= x >> 4;
6608
+ x ^= x >> 2;
6609
+ x ^= x >> 1;
6610
+ cs ^= x & 1;
6611
+ }
6612
+ if (cs) n++;
6613
+ }
6614
+ return n === 0 || n === 2 && cs === 1;
6615
+ }
6616
+ function decodeGloStrings(strings, refDate, opts = {}) {
6617
+ if (strings.length < 4 * GLO_STRING_BYTES) return null;
6618
+ const b = strings;
6619
+ let i = 1;
6620
+ const frn1 = getBitU(b, i, 4);
6621
+ i += 4 + 2;
6622
+ i += 2;
6623
+ const tkH = getBitU(b, i, 5);
6624
+ i += 5;
6625
+ const tkM = getBitU(b, i, 6);
6626
+ i += 6;
6627
+ const tkS = getBitU(b, i, 1) * 30;
6628
+ i += 1;
6629
+ const xDot = getBitG(b, i, 24) * 2 ** -20;
6630
+ i += 24;
6631
+ const xAcc = getBitG(b, i, 5) * 2 ** -30;
6632
+ i += 5;
6633
+ const x = getBitG(b, i, 27) * 2 ** -11;
6634
+ i = 80 + 1;
6635
+ const frn2 = getBitU(b, i, 4);
6636
+ i += 4;
6637
+ const bn = getBitU(b, i, 1);
6638
+ i += 1 + 2;
6639
+ i += 1;
6640
+ const tb = getBitU(b, i, 7);
6641
+ i += 7 + 5;
6642
+ const yDot = getBitG(b, i, 24) * 2 ** -20;
6643
+ i += 24;
6644
+ const yAcc = getBitG(b, i, 5) * 2 ** -30;
6645
+ i += 5;
6646
+ const y = getBitG(b, i, 27) * 2 ** -11;
6647
+ i = 160 + 1;
6648
+ const frn3 = getBitU(b, i, 4);
6649
+ i += 4;
6650
+ i += 1;
6651
+ const gammaN = getBitG(b, i, 11) * 2 ** -40;
6652
+ i += 11 + 1;
6653
+ i += 2;
6654
+ i += 1;
6655
+ const zDot = getBitG(b, i, 24) * 2 ** -20;
6656
+ i += 24;
6657
+ const zAcc = getBitG(b, i, 5) * 2 ** -30;
6658
+ i += 5;
6659
+ const z = getBitG(b, i, 27) * 2 ** -11;
6660
+ i = 240 + 1;
6661
+ const frn4 = getBitU(b, i, 4);
6662
+ i += 4;
6663
+ const tauN = getBitG(b, i, 22) * 2 ** -30;
6664
+ i += 22;
6665
+ i += 5;
6666
+ i += 5;
6667
+ i += 14;
6668
+ i += 1;
6669
+ i += 4;
6670
+ i += 3;
6671
+ i += 11;
6672
+ const slot = getBitU(b, i, 5);
6673
+ if (frn1 !== 1 || frn2 !== 2 || frn3 !== 3 || frn4 !== 4) return null;
6674
+ if (slot < 1 || slot > 27) return null;
6675
+ const utcSec = (getUtcDate(refDate).getTime() - GPS_EPOCH_MS7) / 1e3;
6676
+ const week = Math.floor(utcSec / SEC_PER_WEEK7);
6677
+ let tow = utcSec - week * SEC_PER_WEEK7;
6678
+ const tod = tow % SEC_PER_DAY;
6679
+ tow -= tod;
6680
+ let tof = tkH * 3600 + tkM * 60 + tkS - 10800;
6681
+ if (tof < tod - 43200) tof += SEC_PER_DAY;
6682
+ else if (tof > tod + 43200) tof -= SEC_PER_DAY;
6683
+ let toe = tb * 900 - 10800;
6684
+ if (toe < tod - 43200) toe += SEC_PER_DAY;
6685
+ else if (toe > tod + 43200) toe -= SEC_PER_DAY;
6686
+ return {
6687
+ system: "R",
6688
+ prn: `R${String(slot).padStart(2, "0")}`,
6689
+ // RINEX GLONASS epochs are UTC: build the UTC toe Date directly.
6690
+ tocDate: new Date(GPS_EPOCH_MS7 + (week * SEC_PER_WEEK7 + tow + toe) * 1e3),
6691
+ tauN: -tauN,
6692
+ // RINEX stores −τn; the SIS carries τn (ICD sign)
6693
+ gammaN,
6694
+ // v3 message frame time: seconds of the UTC week (RTKLIB tof).
6695
+ messageFrameTime: ((tow + tof) % SEC_PER_WEEK7 + SEC_PER_WEEK7) % SEC_PER_WEEK7,
6696
+ x,
6697
+ xDot,
6698
+ xAcc,
6699
+ y,
6700
+ yDot,
6701
+ yAcc,
6702
+ z,
6703
+ zDot,
6704
+ zAcc,
6705
+ // MSB of the 3-bit Bn word — the unhealthy flag RINEX carries
6706
+ health: bn,
6707
+ freqNum: opts.freqNum ?? 0
6708
+ };
6709
+ }
6710
+ var GloStringAssembler = class {
6711
+ sats = /* @__PURE__ */ new Map();
6712
+ /**
6713
+ * Push one navigation string (10+ bytes, bit 0 = string bit 85) for
6714
+ * the satellite `prn` ("R09"), received at the GPS-scale `time`.
6715
+ * Returns the newly completed ephemeris, or null. The decoded
6716
+ * string-4 slot number must match `prn`, or nothing is emitted.
6717
+ */
6718
+ push(prn, str, time, freqNum = 0) {
6719
+ if (str.length < GLO_STRING_BYTES) return null;
6720
+ const m = getBitU(str, 1, 4);
6721
+ if (m < 1) return null;
6722
+ const sec = Math.floor(time.getTime() / 1e3);
6723
+ let sat = this.sats.get(prn);
6724
+ if (!sat) {
6725
+ sat = { buf: new Uint8Array(4 * GLO_STRING_BYTES), batchSec: sec };
6726
+ this.sats.set(prn, sat);
6727
+ } else if (Math.abs(sec - sat.batchSec) > 30) {
6728
+ sat.buf.fill(0);
6729
+ sat.batchSec = sec;
6730
+ }
6731
+ if (m > 4) return null;
6732
+ sat.buf.set(str.subarray(0, GLO_STRING_BYTES), (m - 1) * 10);
6733
+ if (m !== 4) return null;
6734
+ const eph = decodeGloStrings(sat.buf, time, { freqNum });
6735
+ if (!eph || eph.prn !== prn) return null;
6736
+ const key = `${eph.tocDate.getTime()}:${eph.health}`;
6737
+ if (key === sat.lastKey) return null;
6738
+ sat.lastKey = key;
6739
+ return eph;
6740
+ }
6741
+ };
6742
+
6743
+ // src/sbf/rawnav-bds.ts
6744
+ var GPS_EPOCH_MS8 = Date.UTC(1980, 0, 6);
6745
+ var MS_PER_WEEK5 = 7 * 86400 * 1e3;
6746
+ var TOW_DNU = 4294967295;
6747
+ var WNC_DNU = 65535;
6748
+ function parseSbfBdsNav(data) {
6749
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
6750
+ const ephemerides = [];
6751
+ const assembler = new BdsAssembler();
6752
+ let badCrc = 0;
6753
+ let messages = 0;
6754
+ scanSbfFrames(data, view, (id, b, len) => {
6755
+ if (id !== 4047 || len < 60) return;
6756
+ messages++;
6757
+ const prn = svidToPrn(view.getUint8(b + 14));
6758
+ if (!prn || prn[0] !== "C") return;
6759
+ const sf = new Uint8Array(38);
6760
+ for (let k = 0; k < 10; k++) {
6761
+ const w = view.getUint32(b + 20 + 4 * k, true);
6762
+ sf[4 * k] = w >>> 24;
6763
+ if (k < 9) {
6764
+ sf[4 * k + 1] = w >>> 16 & 255;
6765
+ sf[4 * k + 2] = w >>> 8 & 255;
6766
+ sf[4 * k + 3] = w & 255;
6767
+ } else {
6768
+ sf[37] = w >>> 16 & 240;
6769
+ }
6770
+ }
6771
+ if (!bdsSubframeParityOk(sf)) {
6772
+ badCrc++;
6773
+ return;
6774
+ }
6775
+ const eph = assembler.push(prn, sf);
6776
+ if (eph) ephemerides.push(eph);
6777
+ });
6778
+ return { ephemerides, badCrc, messages };
6779
+ }
6780
+ function parseSbfGloNav(data) {
6781
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
6782
+ const ephemerides = [];
6783
+ const assembler = new GloStringAssembler();
6784
+ let badCrc = 0;
6785
+ let messages = 0;
6786
+ scanSbfFrames(data, view, (id, b, len) => {
6787
+ if (id !== 4026 || len < 32) return;
6788
+ messages++;
6789
+ const prn = svidToPrn(view.getUint8(b + 14));
6790
+ if (!prn || prn[0] !== "R") return;
6791
+ const towMs = view.getUint32(b + 8, true);
6792
+ const wnc = view.getUint16(b + 12, true);
6793
+ if (towMs === TOW_DNU || wnc === WNC_DNU) return;
6794
+ const str = new Uint8Array(11);
6795
+ for (let k = 0; k < 3; k++) {
6796
+ const w = view.getUint32(b + 20 + 4 * k, true);
6797
+ str[4 * k] = w >>> 24;
6798
+ if (k < 2) {
6799
+ str[4 * k + 1] = w >>> 16 & 255;
6800
+ str[4 * k + 2] = w >>> 8 & 255;
6801
+ str[4 * k + 3] = w & 255;
6802
+ } else {
6803
+ str[9] = w >>> 16 & 255;
6804
+ str[10] = w >>> 8 & 248;
6805
+ }
6806
+ }
6807
+ if (!testGloString(str)) {
6808
+ badCrc++;
6809
+ return;
6810
+ }
6811
+ const eph = assembler.push(
6812
+ prn,
6813
+ str,
6814
+ new Date(GPS_EPOCH_MS8 + wnc * MS_PER_WEEK5 + towMs),
6815
+ view.getUint8(b + 18) - 8
6816
+ // FreqNr, offset by 8
6817
+ );
6818
+ if (eph) ephemerides.push(eph);
6819
+ });
6820
+ return { ephemerides, badCrc, messages };
6821
+ }
6822
+
5930
6823
  // src/sbf/index.ts
5931
6824
  var CLIGHT = 299792458;
5932
- var GPS_EPOCH_MS6 = Date.UTC(1980, 0, 6);
5933
- var MS_PER_WEEK4 = 7 * 864e5;
6825
+ var GPS_EPOCH_MS9 = Date.UTC(1980, 0, 6);
6826
+ var MS_PER_WEEK6 = 7 * 864e5;
5934
6827
  var M3_SYS = ["G", "R", "E", "C", "S", "J", "I"];
5935
6828
  var M3_PR_BASE = [19e6, 19e6, 22e6, 2e7, 34e6, 34e6, 34e6];
5936
6829
  var M3_INTERVALS = [
@@ -6029,23 +6922,23 @@ var MEAS2_SIG = [
6029
6922
  ["J", "1E"],
6030
6923
  ["J", "5P"]
6031
6924
  ];
6032
- var two2 = (n) => String(n).padStart(2, "0");
6925
+ var two3 = (n) => String(n).padStart(2, "0");
6033
6926
  function m3Prn(navsys, svid) {
6034
6927
  switch (navsys) {
6035
6928
  case 0:
6036
- return svid < 32 ? `G${two2(svid + 1)}` : null;
6929
+ return svid < 32 ? `G${two3(svid + 1)}` : null;
6037
6930
  case 1:
6038
- return svid < 27 ? `R${two2(svid + 1)}` : null;
6931
+ return svid < 27 ? `R${two3(svid + 1)}` : null;
6039
6932
  case 2:
6040
- return svid < 36 ? `E${two2(svid + 1)}` : null;
6933
+ return svid < 36 ? `E${two3(svid + 1)}` : null;
6041
6934
  case 3:
6042
- return svid < 50 ? `C${two2(svid + 1)}` : null;
6935
+ return svid < 50 ? `C${two3(svid + 1)}` : null;
6043
6936
  case 4:
6044
- return svid <= 38 ? `S${two2(svid + 20)}` : null;
6937
+ return svid <= 38 ? `S${two3(svid + 20)}` : null;
6045
6938
  case 5:
6046
- return svid < 10 ? `J${two2(svid + 1)}` : null;
6939
+ return svid < 10 ? `J${two3(svid + 1)}` : null;
6047
6940
  case 6:
6048
- return svid < 14 ? `I${two2(svid + 1)}` : null;
6941
+ return svid < 14 ? `I${two3(svid + 1)}` : null;
6049
6942
  default:
6050
6943
  return null;
6051
6944
  }
@@ -6583,7 +7476,7 @@ function parseSbfMeas(data) {
6583
7476
  const tow = view.getUint32(i + 8, true);
6584
7477
  const wnc = view.getUint16(i + 12, true);
6585
7478
  if (tow !== 4294967295 && wnc !== 65535) {
6586
- ensureEpoch(GPS_EPOCH_MS6 + wnc * MS_PER_WEEK4 + tow);
7479
+ ensureEpoch(GPS_EPOCH_MS9 + wnc * MS_PER_WEEK6 + tow);
6587
7480
  if (id === 4109) decodeMeas3Ranges(i, tow);
6588
7481
  else if (id === 4110) decodeMeas3CN0(i, len);
6589
7482
  else if (id === 4111) decodeMeas3Doppler(i, len);
@@ -6641,24 +7534,25 @@ function* oem4Frames(data, view, stats) {
6641
7534
 
6642
7535
  // src/novatel/nav.ts
6643
7536
  var ID_IONUTC = 8;
7537
+ var ID_RAWCNAVFRAME = 1066;
6644
7538
  var ID_RAWEPHEM = 41;
6645
7539
  var ID_GLOEPHEMERIS = 723;
6646
7540
  var ID_GALEPHEMERIS = 1122;
6647
7541
  var ID_QZSSEPHEMERIS = 1336;
6648
7542
  var ID_GPSEPHEM = 7;
6649
7543
  var ID_BDSEPHEMERIS = 1696;
6650
- var GPS_EPOCH_MS7 = Date.UTC(1980, 0, 6);
6651
- var BDT_EPOCH_MS2 = Date.UTC(2006, 0, 1);
6652
- var SEC_PER_WEEK5 = 7 * 86400;
6653
- var SEC_PER_DAY = 86400;
6654
- var MS_PER_WEEK5 = SEC_PER_WEEK5 * 1e3;
6655
- var gpsMs2 = (week, sec) => GPS_EPOCH_MS7 + week * MS_PER_WEEK5 + sec * 1e3;
6656
- var sowOf2 = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK5;
7544
+ var GPS_EPOCH_MS10 = Date.UTC(1980, 0, 6);
7545
+ var BDT_EPOCH_MS3 = Date.UTC(2006, 0, 1);
7546
+ var SEC_PER_WEEK8 = 7 * 86400;
7547
+ var SEC_PER_DAY2 = 86400;
7548
+ var MS_PER_WEEK7 = SEC_PER_WEEK8 * 1e3;
7549
+ var gpsMs2 = (week, sec) => GPS_EPOCH_MS10 + week * MS_PER_WEEK7 + sec * 1e3;
7550
+ var sowOf3 = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK8;
6657
7551
  function nearWeekMs(refMs, sow) {
6658
- const refWeek = Math.floor((refMs - GPS_EPOCH_MS7) / MS_PER_WEEK5);
7552
+ const refWeek = Math.floor((refMs - GPS_EPOCH_MS10) / MS_PER_WEEK7);
6659
7553
  let ms = gpsMs2(refWeek, sow);
6660
- if (ms < refMs - MS_PER_WEEK5 / 2) ms += MS_PER_WEEK5;
6661
- else if (ms > refMs + MS_PER_WEEK5 / 2) ms -= MS_PER_WEEK5;
7554
+ if (ms < refMs - MS_PER_WEEK7 / 2) ms += MS_PER_WEEK7;
7555
+ else if (ms > refMs + MS_PER_WEEK7 / 2) ms -= MS_PER_WEEK7;
6662
7556
  return ms;
6663
7557
  }
6664
7558
  function decodeRawEphem(data, view, p) {
@@ -6679,12 +7573,12 @@ function decodeGloEphemeris(view, p) {
6679
7573
  const toff = view.getUint32(p + 12, true);
6680
7574
  const health = view.getUint32(p + 24, true) < 4 ? 0 : 1;
6681
7575
  let tof = view.getUint32(p + 124, true) - toff;
6682
- tof += Math.floor(tow / SEC_PER_DAY) * SEC_PER_DAY;
6683
- if (tof < tow - 43200) tof += SEC_PER_DAY;
6684
- else if (tof > tow + 43200) tof -= SEC_PER_DAY;
6685
- const toeGpsMs = GPS_EPOCH_MS7 + (week * SEC_PER_WEEK5 + tow) * 1e3;
6686
- const tofGpsMs = GPS_EPOCH_MS7 + (week * SEC_PER_WEEK5 + tof) * 1e3;
6687
- const tofUtcSec = (getUtcDate(new Date(tofGpsMs)).getTime() - GPS_EPOCH_MS7) / 1e3;
7576
+ tof += Math.floor(tow / SEC_PER_DAY2) * SEC_PER_DAY2;
7577
+ if (tof < tow - 43200) tof += SEC_PER_DAY2;
7578
+ else if (tof > tow + 43200) tof -= SEC_PER_DAY2;
7579
+ const toeGpsMs = GPS_EPOCH_MS10 + (week * SEC_PER_WEEK8 + tow) * 1e3;
7580
+ const tofGpsMs = GPS_EPOCH_MS10 + (week * SEC_PER_WEEK8 + tof) * 1e3;
7581
+ const tofUtcSec = (getUtcDate(new Date(tofGpsMs)).getTime() - GPS_EPOCH_MS10) / 1e3;
6688
7582
  return {
6689
7583
  system: "R",
6690
7584
  prn: `R${String(slot).padStart(2, "0")}`,
@@ -6692,7 +7586,7 @@ function decodeGloEphemeris(view, p) {
6692
7586
  tauN: -view.getFloat64(p + 100, true),
6693
7587
  // RINEX stores −τ_n
6694
7588
  gammaN: view.getFloat64(p + 116, true),
6695
- messageFrameTime: (tofUtcSec % SEC_PER_WEEK5 + SEC_PER_WEEK5) % SEC_PER_WEEK5,
7589
+ messageFrameTime: (tofUtcSec % SEC_PER_WEEK8 + SEC_PER_WEEK8) % SEC_PER_WEEK8,
6696
7590
  x: view.getFloat64(p + 28, true) / 1e3,
6697
7591
  y: view.getFloat64(p + 36, true) / 1e3,
6698
7592
  z: view.getFloat64(p + 44, true) / 1e3,
@@ -6727,7 +7621,7 @@ function decodeGalEphemeris(view, p, headerMs) {
6727
7621
  eph: {
6728
7622
  system: "E",
6729
7623
  prn: `E${String(prn).padStart(2, "0")}`,
6730
- toc: sowOf2(tocDate.getTime()),
7624
+ toc: sowOf3(tocDate.getTime()),
6731
7625
  tocDate,
6732
7626
  af0: view.getFloat64(c + 4, true),
6733
7627
  af1: view.getFloat64(c + 12, true),
@@ -6749,7 +7643,7 @@ function decodeGalEphemeris(view, p, headerMs) {
6749
7643
  omega: view.getFloat64(p + 60, true),
6750
7644
  omegaDot: view.getFloat64(p + 140, true),
6751
7645
  idot: view.getFloat64(p + 124, true),
6752
- week: Math.floor((toeMs - GPS_EPOCH_MS7) / MS_PER_WEEK5),
7646
+ week: Math.floor((toeMs - GPS_EPOCH_MS10) / MS_PER_WEEK7),
6753
7647
  // RINEX Galileo SVH bit layout (E1B DVS/HS in bits 0-2, E5a in
6754
7648
  // 3-5, E5b in 6-8) — same packing as RTKLIB.
6755
7649
  svHealth: svhE5b << 7 | dvsE5b << 6 | svhE5a << 4 | dvsE5a << 3 | svhE1b << 1 | dvsE1b,
@@ -6766,11 +7660,11 @@ function decodeBdsEphemeris2(view, p) {
6766
7660
  const tgd1 = view.getFloat64(p + 20, true);
6767
7661
  const tocs = view.getUint32(p + 40, true);
6768
7662
  const toes = view.getUint32(p + 72, true);
6769
- const tocDate = new Date(BDT_EPOCH_MS2 + week * MS_PER_WEEK5 + tocs * 1e3);
7663
+ const tocDate = new Date(BDT_EPOCH_MS3 + week * MS_PER_WEEK7 + tocs * 1e3);
6770
7664
  return {
6771
7665
  system: "C",
6772
7666
  prn: `C${String(prn).padStart(2, "0")}`,
6773
- toc: sowOf2(tocDate.getTime()),
7667
+ toc: sowOf3(tocDate.getTime()),
6774
7668
  tocDate,
6775
7669
  af0: view.getFloat64(p + 44, true),
6776
7670
  af1: view.getFloat64(p + 52, true),
@@ -6814,7 +7708,7 @@ function decodeGpsQzssEphemeris(view, p, sys) {
6814
7708
  return {
6815
7709
  system: sys,
6816
7710
  prn: `${sys}${String(sys === "J" ? prn - 192 : prn).padStart(2, "0")}`,
6817
- toc: sowOf2(tocDate.getTime()),
7711
+ toc: sowOf3(tocDate.getTime()),
6818
7712
  tocDate,
6819
7713
  af0: view.getFloat64(p + 180, true),
6820
7714
  af1: view.getFloat64(p + 188, true),
@@ -6847,6 +7741,9 @@ function parseNovatelNav(data) {
6847
7741
  const ephemerides = [];
6848
7742
  const ionoCorrections = {};
6849
7743
  let leapSeconds = null;
7744
+ const cnav = [];
7745
+ const cnavAssembler = new CnavAssembler();
7746
+ let cnavBadCrc = 0;
6850
7747
  const lastKep = /* @__PURE__ */ new Map();
6851
7748
  const lastGlo = /* @__PURE__ */ new Map();
6852
7749
  const pushKepler = (key, eph) => {
@@ -6877,6 +7774,14 @@ function parseNovatelNav(data) {
6877
7774
  } else if (frame.id === ID_QZSSEPHEMERIS && frame.msgLen >= 204) {
6878
7775
  const eph = decodeGpsQzssEphemeris(view, frame.payload, "J");
6879
7776
  if (eph) pushKepler(eph.prn, eph);
7777
+ } else if (frame.id === ID_RAWCNAVFRAME && frame.msgLen >= 50) {
7778
+ const msg = data.subarray(frame.payload + 12, frame.payload + 50);
7779
+ if (!cnavCrcOk(msg)) {
7780
+ cnavBadCrc++;
7781
+ } else {
7782
+ const eph = cnavAssembler.push(msg);
7783
+ if (eph) cnav.push(eph);
7784
+ }
6880
7785
  } else if (frame.id === ID_IONUTC && frame.msgLen >= 108) {
6881
7786
  const p = frame.payload;
6882
7787
  const alpha = [];
@@ -6899,12 +7804,19 @@ function parseNovatelNav(data) {
6899
7804
  ephemerides.push(eph);
6900
7805
  }
6901
7806
  }
6902
- return { ephemerides, ionoCorrections, leapSeconds, badCrc: stats.badCrc };
7807
+ return {
7808
+ ephemerides,
7809
+ ionoCorrections,
7810
+ leapSeconds,
7811
+ cnav,
7812
+ cnavBadCrc,
7813
+ badCrc: stats.badCrc
7814
+ };
6903
7815
  }
6904
7816
 
6905
7817
  // src/novatel/index.ts
6906
- var GPS_EPOCH_MS8 = Date.UTC(1980, 0, 6);
6907
- var MS_PER_WEEK6 = 7 * 864e5;
7818
+ var GPS_EPOCH_MS11 = Date.UTC(1980, 0, 6);
7819
+ var MS_PER_WEEK8 = 7 * 864e5;
6908
7820
  var HDR = 28;
6909
7821
  var ID_RANGE = 43;
6910
7822
  var ID_RANGECMP = 140;
@@ -7073,7 +7985,7 @@ function parseNovatelRange(data) {
7073
7985
  if (!codes.includes(code)) codes.push(code);
7074
7986
  }
7075
7987
  epochs.push({
7076
- timeMs: GPS_EPOCH_MS8 + week * MS_PER_WEEK6 + towMs,
7988
+ timeMs: GPS_EPOCH_MS11 + week * MS_PER_WEEK8 + towMs,
7077
7989
  meas
7078
7990
  });
7079
7991
  }
@@ -7125,7 +8037,7 @@ function parseNovatelRange(data) {
7125
8037
  if (!codes.includes(code)) codes.push(code);
7126
8038
  }
7127
8039
  epochs.push({
7128
- timeMs: GPS_EPOCH_MS8 + week * MS_PER_WEEK6 + towMs,
8040
+ timeMs: GPS_EPOCH_MS11 + week * MS_PER_WEEK8 + towMs,
7129
8041
  meas
7130
8042
  });
7131
8043
  }
@@ -7135,10 +8047,184 @@ function parseNovatelRange(data) {
7135
8047
  return { epochs, messageCounts, obsCodes, badCrc };
7136
8048
  }
7137
8049
 
7138
- // src/orbit/index.ts
8050
+ // src/orbit/almanac.ts
7139
8051
  var GM_GPS = 3986005e8;
7140
8052
  var GM_GAL = 3986004418e5;
7141
8053
  var GM_BDS = 3986004418e5;
8054
+ var GPS_EPOCH_MS12 = Date.UTC(1980, 0, 6);
8055
+ var BDT_EPOCH_MS4 = Date.UTC(2006, 0, 1);
8056
+ var WEEK_MS = 6048e5;
8057
+ var BDT_MINUS_GPST_MS = 14e3;
8058
+ var BDS_GEO_PRNS = /* @__PURE__ */ new Set([1, 2, 3, 4, 5, 59, 60, 61, 62, 63]);
8059
+ function almanacEpochMs(alm) {
8060
+ if (alm.system === "C") {
8061
+ return BDT_EPOCH_MS4 + alm.weekAlm * WEEK_MS + alm.toaSec * 1e3 + BDT_MINUS_GPST_MS;
8062
+ }
8063
+ return GPS_EPOCH_MS12 + alm.weekAlm * WEEK_MS + alm.toaSec * 1e3;
8064
+ }
8065
+ function almanacSatPosition(alm, timeMs) {
8066
+ const GM = alm.system === "E" ? GM_GAL : alm.system === "C" ? GM_BDS : GM_GPS;
8067
+ const a = alm.sqrtA * alm.sqrtA;
8068
+ const n0 = Math.sqrt(GM / (a * a * a));
8069
+ const tk = (timeMs - almanacEpochMs(alm)) / 1e3;
8070
+ const Mk = alm.m0 + n0 * tk;
8071
+ let Ek = Mk;
8072
+ for (let i = 0; i < 12; i++) {
8073
+ const dE = (Mk - (Ek - alm.e * Math.sin(Ek))) / (1 - alm.e * Math.cos(Ek));
8074
+ Ek += dE;
8075
+ if (Math.abs(dE) < 1e-12) break;
8076
+ }
8077
+ const sinE = Math.sin(Ek);
8078
+ const cosE = Math.cos(Ek);
8079
+ const vk = Math.atan2(Math.sqrt(1 - alm.e * alm.e) * sinE, cosE - alm.e);
8080
+ const uk = vk + alm.omega;
8081
+ const rk = a * (1 - alm.e * cosE);
8082
+ const ik = alm.i0OrDeltaI;
8083
+ const xp = rk * Math.cos(uk);
8084
+ const yp = rk * Math.sin(uk);
8085
+ const clockBias = alm.af0 + alm.af1 * tk;
8086
+ const isGeo = alm.system === "C" && BDS_GEO_PRNS.has(Number(alm.prn.slice(1)));
8087
+ if (isGeo) {
8088
+ const omegak2 = alm.omega0 + alm.omegaDot * tk - OMEGA_E * alm.toaSec;
8089
+ const cosO2 = Math.cos(omegak2);
8090
+ const sinO2 = Math.sin(omegak2);
8091
+ const cosI2 = Math.cos(ik);
8092
+ const sinI2 = Math.sin(ik);
8093
+ const xg = xp * cosO2 - yp * cosI2 * sinO2;
8094
+ const yg = xp * sinO2 + yp * cosI2 * cosO2;
8095
+ const zg = yp * sinI2;
8096
+ const phi = OMEGA_E * tk;
8097
+ const cosPhi = Math.cos(phi);
8098
+ const sinPhi = Math.sin(phi);
8099
+ const COS5 = Math.cos(-5 * Math.PI / 180);
8100
+ const SIN5 = Math.sin(-5 * Math.PI / 180);
8101
+ return {
8102
+ prn: alm.prn,
8103
+ x: xg * cosPhi + yg * sinPhi * COS5 + zg * sinPhi * SIN5,
8104
+ y: -xg * sinPhi + yg * cosPhi * COS5 + zg * cosPhi * SIN5,
8105
+ z: -yg * SIN5 + zg * COS5,
8106
+ clockBias
8107
+ };
8108
+ }
8109
+ const omegak = alm.omega0 + (alm.omegaDot - OMEGA_E) * tk - OMEGA_E * alm.toaSec;
8110
+ const cosO = Math.cos(omegak);
8111
+ const sinO = Math.sin(omegak);
8112
+ const cosI = Math.cos(ik);
8113
+ const sinI = Math.sin(ik);
8114
+ return {
8115
+ prn: alm.prn,
8116
+ x: xp * cosO - yp * cosI * sinO,
8117
+ y: xp * sinO + yp * cosI * cosO,
8118
+ z: yp * sinI,
8119
+ clockBias
8120
+ };
8121
+ }
8122
+
8123
+ // src/orbit/almanac-glo.ts
8124
+ var C20 = -108263e-8;
8125
+ var J = -1.5 * C20;
8126
+ var AE = 6378.136;
8127
+ var MU = 398600.44;
8128
+ var OMEGA_Z = 7292115e-11;
8129
+ var I_MEAN = 63 * Math.PI / 180;
8130
+ var T_MEAN = 43200;
8131
+ var GLO_1996_UTC_MS = Date.UTC(1996, 0, 1) - 108e5;
8132
+ var DAY_MS = 864e5;
8133
+ var FOUR_YEARS_DAYS = 1461;
8134
+ function glonassAlmanacEpochMs(alm) {
8135
+ const utcMs = GLO_1996_UTC_MS + ((alm.n4 - 1) * FOUR_YEARS_DAYS + (alm.nDay - 1)) * DAY_MS + alm.tLambda * 1e3;
8136
+ return utcMs + getGpsLeap(new Date(utcMs)) * 1e3;
8137
+ }
8138
+ function c20Deltas(lam, tau, B, h, l, n, sinI, cosI) {
8139
+ const sin2i = sinI * sinI;
8140
+ const cos2i = cosI * cosI;
8141
+ const s1 = Math.sin(lam);
8142
+ const c1 = Math.cos(lam);
8143
+ const s2 = Math.sin(2 * lam);
8144
+ const c2 = Math.cos(2 * lam);
8145
+ const s3 = Math.sin(3 * lam);
8146
+ const c3 = Math.cos(3 * lam);
8147
+ const s4 = Math.sin(4 * lam);
8148
+ const c4 = Math.cos(4 * lam);
8149
+ 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);
8150
+ 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);
8151
+ 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);
8152
+ const nodeBracket = n * tau + 3.5 * l * s1 - 2.5 * h * c1 - 0.5 * s2 - 7 / 6 * l * s3 + 7 / 6 * h * c3;
8153
+ const dOmega = -B * cosI * nodeBracket;
8154
+ const di = 0.5 * B * sinI * cosI * (-l * c1 + h * s1 + c2 + 7 / 3 * l * c3 + 7 / 3 * h * s3);
8155
+ 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;
8156
+ return { daOverA, dh, dl, dOmega, di, dLambda };
8157
+ }
8158
+ function glonassAlmanacPosition(alm, timeMs) {
8159
+ const i = I_MEAN + alm.deltaI;
8160
+ const sinI = Math.sin(i);
8161
+ const cosI = Math.cos(i);
8162
+ const sin2i = sinI * sinI;
8163
+ const e = alm.epsilon;
8164
+ const oneMinusE2 = 1 - e * e;
8165
+ const Tdr = T_MEAN + alm.deltaT;
8166
+ const n = 2 * Math.PI / Tdr;
8167
+ const cosW = Math.cos(alm.omega);
8168
+ let a = Math.cbrt((Tdr / (2 * Math.PI)) ** 2 * MU);
8169
+ for (let k = 0; k < 10; k++) {
8170
+ const p = a * oneMinusE2;
8171
+ 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));
8172
+ const aNext = Math.cbrt((tOsc / (2 * Math.PI)) ** 2 * MU);
8173
+ const converged = Math.abs(aNext - a) < 1e-3;
8174
+ a = aNext;
8175
+ if (converged) break;
8176
+ }
8177
+ const tStar = (timeMs - glonassAlmanacEpochMs(alm)) / 1e3;
8178
+ const W = Math.floor(tStar / Tdr);
8179
+ const nodeShift = Tdr * W + alm.deltaTDot * W * W;
8180
+ const omegaDot = 1.5 * C20 * n * (AE / a) ** 2 * cosI * oneMinusE2 ** -2;
8181
+ const lambdaK = alm.lambda + (omegaDot - OMEGA_Z) * nodeShift;
8182
+ const tau = tStar - nodeShift;
8183
+ const h = e * Math.sin(alm.omega);
8184
+ const l = e * cosW;
8185
+ const E0 = 2 * Math.atan(Math.sqrt((1 - e) / (1 + e)) * Math.tan(-alm.omega / 2));
8186
+ const M = E0 - e * Math.sin(E0);
8187
+ const B = J * (AE / a) ** 2;
8188
+ const d1 = c20Deltas(M + alm.omega, 0, B, h, l, n, sinI, cosI);
8189
+ const d2 = c20Deltas(M + alm.omega + n * tau, tau, B, h, l, n, sinI, cosI);
8190
+ const hi = h + (d2.dh - d1.dh);
8191
+ const li = l + (d2.dl - d1.dl);
8192
+ const epsI = Math.hypot(hi, li);
8193
+ const omegaI = epsI === 0 ? 0 : Math.atan2(hi, li);
8194
+ const aI = a + a * (d2.daOverA - d1.daOverA);
8195
+ const iI = i + (d2.di - d1.di);
8196
+ const omegaG = lambdaK + (d2.dOmega - d1.dOmega) - OMEGA_Z * tau;
8197
+ const lambdaStar = M + alm.omega + n * tau + (d2.dLambda - d1.dLambda);
8198
+ const Mi = lambdaStar - omegaI;
8199
+ let E = Mi;
8200
+ for (let k = 0; k < 30; k++) {
8201
+ const next = Mi + epsI * Math.sin(E);
8202
+ const converged = Math.abs(next - E) < 1e-12;
8203
+ E = next;
8204
+ if (converged) break;
8205
+ }
8206
+ const v = 2 * Math.atan(Math.sqrt((1 + epsI) / (1 - epsI)) * Math.tan(E / 2));
8207
+ const u = v + omegaI;
8208
+ const rKm = aI * (1 - epsI * Math.cos(E));
8209
+ const cosU = Math.cos(u);
8210
+ const sinU = Math.sin(u);
8211
+ const cosO = Math.cos(omegaG);
8212
+ const sinO = Math.sin(omegaG);
8213
+ const cosIi = Math.cos(iI);
8214
+ const sinIi = Math.sin(iI);
8215
+ return {
8216
+ prn: alm.prn,
8217
+ x: 1e3 * rKm * (cosU * cosO - sinU * sinO * cosIi),
8218
+ y: 1e3 * rKm * (cosU * sinO + sinU * cosO * cosIi),
8219
+ z: 1e3 * rKm * sinU * sinIi,
8220
+ clockBias: -alm.tau
8221
+ };
8222
+ }
8223
+
8224
+ // src/orbit/index.ts
8225
+ var GM_GPS2 = 3986005e8;
8226
+ var GM_GAL2 = 3986004418e5;
8227
+ var GM_BDS2 = 3986004418e5;
7142
8228
  var GM_GLO = 39860044e7;
7143
8229
  var BDS_GEO_MAX_INCLINATION_RAD = 0.1;
7144
8230
  var BDS_GEO_MIN_SEMIMAJOR_AXIS_M = 4e7;
@@ -7146,9 +8232,9 @@ var AE_GLO = 6378136;
7146
8232
  var J2_GLO = 108263e-8;
7147
8233
  var TWO_PI = 2 * Math.PI;
7148
8234
  function gmForSystem(sys) {
7149
- if (sys === "E") return GM_GAL;
7150
- if (sys === "C") return GM_BDS;
7151
- return GM_GPS;
8235
+ if (sys === "E") return GM_GAL2;
8236
+ if (sys === "C") return GM_BDS2;
8237
+ return GM_GPS2;
7152
8238
  }
7153
8239
  var geoVelocityPass = false;
7154
8240
  function keplerPosition(eph, t) {
@@ -7484,10 +8570,10 @@ function selectBest(ephs, timeMs) {
7484
8570
  }
7485
8571
  return best;
7486
8572
  }
7487
- var GPS_EPOCH_MS9 = START_GPS_TIME.getTime();
7488
- var MS_PER_WEEK7 = 7 * 864e5;
8573
+ var GPS_EPOCH_MS13 = START_GPS_TIME.getTime();
8574
+ var MS_PER_WEEK9 = 7 * 864e5;
7489
8575
  var BDS_EPOCH_MS = START_BDS_TIME.getTime();
7490
- var GAL_EPOCH_MS = GPS_EPOCH_MS9 + 1024 * MS_PER_WEEK7;
8576
+ var GAL_EPOCH_MS = GPS_EPOCH_MS13 + 1024 * MS_PER_WEEK9;
7491
8577
  function ephInfoToEphemeris(info) {
7492
8578
  const sys = info.prn.charAt(0);
7493
8579
  if (sys === "R") {
@@ -7538,11 +8624,11 @@ function ephInfoToEphemeris(info) {
7538
8624
  } else if (sys === "E") {
7539
8625
  epochMs = GAL_EPOCH_MS;
7540
8626
  } else {
7541
- epochMs = GPS_EPOCH_MS9;
7542
- const weeksNow = (info.lastReceived - GPS_EPOCH_MS9) / MS_PER_WEEK7;
8627
+ epochMs = GPS_EPOCH_MS13;
8628
+ const weeksNow = (info.lastReceived - GPS_EPOCH_MS13) / MS_PER_WEEK9;
7543
8629
  week += 1024 * Math.round((weeksNow - week) / 1024);
7544
8630
  }
7545
- const tocDate = new Date(epochMs + week * MS_PER_WEEK7 + tocSec * 1e3);
8631
+ const tocDate = new Date(epochMs + week * MS_PER_WEEK9 + tocSec * 1e3);
7546
8632
  return {
7547
8633
  system: sys,
7548
8634
  prn: info.prn,
@@ -7968,7 +9054,7 @@ function klobucharDelay(coeffs, latRad, lonRad, azRad, elRad, gpsTowSec) {
7968
9054
  }
7969
9055
 
7970
9056
  // src/positioning/index.ts
7971
- var GM_GPS2 = 3986005e8;
9057
+ var GM_GPS3 = 3986005e8;
7972
9058
  var F_REL = -4442807633e-19;
7973
9059
  function satClockCorrection(eph, tMs) {
7974
9060
  if (eph.system === "R" || eph.system === "S") {
@@ -7979,7 +9065,7 @@ function satClockCorrection(eph, tMs) {
7979
9065
  const dt = (tMs - k.tocDate.getTime()) / 1e3;
7980
9066
  const poly = k.af0 + k.af1 * dt + k.af2 * dt * dt;
7981
9067
  const a = k.sqrtA * k.sqrtA;
7982
- const n = Math.sqrt(GM_GPS2 / (a * a * a)) + k.deltaN;
9068
+ const n = Math.sqrt(GM_GPS3 / (a * a * a)) + k.deltaN;
7983
9069
  const tk = dt;
7984
9070
  const Mk = k.m0 + n * tk;
7985
9071
  let Ek = Mk;
@@ -10523,6 +11609,8 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
10523
11609
  WGS84_SEMI_MAJOR_AXIS,
10524
11610
  WGS84_SEMI_MINOR_AXIS,
10525
11611
  WarningAccumulator,
11612
+ almanacEpochMs,
11613
+ almanacSatPosition,
10526
11614
  analyzeQuality,
10527
11615
  applyHelmert,
10528
11616
  applyIonoDcb,
@@ -10619,6 +11707,8 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
10619
11707
  getWeekNumber,
10620
11708
  getWeekOfYear,
10621
11709
  gloFreq,
11710
+ glonassAlmanacEpochMs,
11711
+ glonassAlmanacPosition,
10622
11712
  glonassPosition,
10623
11713
  greatCircleMidpoint,
10624
11714
  hdrLine,
@@ -10642,7 +11732,10 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
10642
11732
  parseNovatelRange,
10643
11733
  parseRinexStream,
10644
11734
  parseSbfAlmanac,
11735
+ parseSbfBdsNav,
10645
11736
  parseSbfCnav,
11737
+ parseSbfGalNav,
11738
+ parseSbfGloNav,
10646
11739
  parseSbfIonoUtc,
10647
11740
  parseSbfMeas,
10648
11741
  parseSbfNav,