gnss-js 2.10.1 → 2.12.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/README.md +16 -1
- package/dist/analysis.cjs +24 -25
- package/dist/analysis.js +2 -2
- package/dist/{clk-DGVBGRzA.d.cts → bias-sinex-OGMw9xEZ.d.cts} +66 -1
- package/dist/{clk-DGVBGRzA.d.ts → bias-sinex-OGMw9xEZ.d.ts} +66 -1
- package/dist/binex.d.cts +1 -1
- package/dist/binex.d.ts +1 -1
- package/dist/{chunk-56HM5B6T.js → chunk-2DJ4XENO.js} +177 -9
- package/dist/{chunk-GH7MYXON.js → chunk-2KQMCJ5Z.js} +7 -5
- package/dist/chunk-E3Y6YKQM.js +65 -0
- package/dist/{chunk-3U5AX7PY.js → chunk-FEABDV5P.js} +24 -25
- package/dist/{chunk-WQX354KD.js → chunk-H3AKFD25.js} +1 -1
- package/dist/{chunk-YUW33VXK.js → chunk-HUXQABJI.js} +2 -0
- package/dist/{chunk-74IVYOQV.js → chunk-HWHD5E6V.js} +128 -78
- package/dist/{chunk-KUSUN7DP.js → chunk-MFCPYUEI.js} +1 -1
- package/dist/{chunk-3KSDL3CO.js → chunk-NIJ6WFQJ.js} +6 -321
- package/dist/chunk-NL2ORX75.js +319 -0
- package/dist/{chunk-K3GLUWZI.js → chunk-RWFJEVLJ.js} +590 -296
- package/dist/{chunk-SEYH4BEN.js → chunk-SZP4TLYR.js} +2 -2
- package/dist/chunk-TWGZTRBL.js +323 -0
- package/dist/index.cjs +1315 -460
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +20 -12
- package/dist/{nav-DImXUdbp.d.cts → nav-COp0Vmlw.d.cts} +83 -2
- package/dist/{nav-DImXUdbp.d.ts → nav-COp0Vmlw.d.ts} +83 -2
- package/dist/{nav-BYmYoh9A.d.cts → nav-CvZXmumD.d.cts} +1 -1
- package/dist/{nav-CN8rxL4h.d.ts → nav-D2DFlVpa.d.ts} +1 -1
- package/dist/novatel.d.cts +1 -1
- package/dist/novatel.d.ts +1 -1
- package/dist/novatel.js +3 -3
- package/dist/orbit.d.cts +2 -2
- package/dist/orbit.d.ts +2 -2
- package/dist/osnma.cjs +1336 -0
- package/dist/osnma.d.cts +273 -0
- package/dist/osnma.d.ts +273 -0
- package/dist/osnma.js +1216 -0
- package/dist/positioning.cjs +585 -291
- package/dist/positioning.d.cts +116 -6
- package/dist/positioning.d.ts +116 -6
- package/dist/positioning.js +3 -3
- package/dist/rinex.cjs +210 -36
- package/dist/rinex.d.cts +10 -55
- package/dist/rinex.d.ts +10 -55
- package/dist/rinex.js +6 -3
- package/dist/sbf.cjs +420 -24
- package/dist/sbf.d.cts +46 -5
- package/dist/sbf.d.ts +46 -5
- package/dist/sbf.js +12 -6
- package/dist/trimble.d.cts +1 -1
- package/dist/trimble.d.ts +1 -1
- package/dist/ubx.d.cts +1 -1
- package/dist/ubx.d.ts +1 -1
- package/dist/ubx.js +5 -4
- package/package.json +6 -1
package/dist/index.cjs
CHANGED
|
@@ -106,6 +106,7 @@ __export(src_exports, {
|
|
|
106
106
|
SYSTEM_NAMES: () => SYSTEM_NAMES,
|
|
107
107
|
SYSTEM_ORDER: () => SYSTEM_ORDER,
|
|
108
108
|
SYS_SHORT: () => SYS_SHORT,
|
|
109
|
+
SatOsbTable: () => SatOsbTable,
|
|
109
110
|
SbasProcessor: () => SbasProcessor,
|
|
110
111
|
Scale: () => Scale,
|
|
111
112
|
Sp3EphemerisSource: () => Sp3EphemerisSource,
|
|
@@ -288,6 +289,7 @@ __export(src_exports, {
|
|
|
288
289
|
parseNovatelRange: () => parseNovatelRange,
|
|
289
290
|
parseRinexStream: () => parseRinexStream,
|
|
290
291
|
parseSbfAlmanac: () => parseSbfAlmanac,
|
|
292
|
+
parseSbfBdsCnav: () => parseSbfBdsCnav,
|
|
291
293
|
parseSbfBdsNav: () => parseSbfBdsNav,
|
|
292
294
|
parseSbfCnav: () => parseSbfCnav,
|
|
293
295
|
parseSbfGalNav: () => parseSbfGalNav,
|
|
@@ -1373,20 +1375,14 @@ function geodeticToGeohash(lat, lon, precision = 8) {
|
|
|
1373
1375
|
// src/rinex/crx.ts
|
|
1374
1376
|
function crxRepair(old, diff) {
|
|
1375
1377
|
const chars = old.split("");
|
|
1376
|
-
|
|
1378
|
+
const n = Math.min(old.length, diff.length);
|
|
1379
|
+
for (let i = 0; i < n; i++) {
|
|
1377
1380
|
const dc = diff[i];
|
|
1378
|
-
if (dc === " ")
|
|
1379
|
-
|
|
1380
|
-
chars[i] = " ";
|
|
1381
|
-
} else {
|
|
1382
|
-
chars[i] = dc;
|
|
1383
|
-
}
|
|
1384
|
-
}
|
|
1385
|
-
if (diff.length > chars.length) {
|
|
1386
|
-
for (let i = chars.length; i < diff.length; i++) {
|
|
1387
|
-
chars[i] = diff[i] === "&" ? " " : diff[i];
|
|
1388
|
-
}
|
|
1381
|
+
if (dc === " ") continue;
|
|
1382
|
+
chars[i] = dc === "&" ? " " : dc;
|
|
1389
1383
|
}
|
|
1384
|
+
for (let i = old.length; i < diff.length; i++)
|
|
1385
|
+
chars[i] = diff[i] === "&" ? " " : diff[i];
|
|
1390
1386
|
return chars.join("");
|
|
1391
1387
|
}
|
|
1392
1388
|
function parseCrxDataLine(line, ntype) {
|
|
@@ -2084,6 +2080,15 @@ function readObsValue(line, index) {
|
|
|
2084
2080
|
const v = parseFloat(raw);
|
|
2085
2081
|
return isNaN(v) ? null : v;
|
|
2086
2082
|
}
|
|
2083
|
+
function normalizePrn(id) {
|
|
2084
|
+
let sys = id[0];
|
|
2085
|
+
let num = id.substring(1);
|
|
2086
|
+
if (sys === " " || /\d/.test(sys)) {
|
|
2087
|
+
num = id;
|
|
2088
|
+
sys = "G";
|
|
2089
|
+
}
|
|
2090
|
+
return sys + num.replace(/\s/g, "").padStart(2, "0");
|
|
2091
|
+
}
|
|
2087
2092
|
function parseEpochLine3(line) {
|
|
2088
2093
|
if (line[0] !== ">") return null;
|
|
2089
2094
|
const yr = parseInt(line.substring(2, 6));
|
|
@@ -2233,7 +2238,7 @@ async function parseRinexStream(file, onProgress, signal, onSatObs, workerMode)
|
|
|
2233
2238
|
function processSatLineV3(line) {
|
|
2234
2239
|
if (!header || line.length < 3) return;
|
|
2235
2240
|
const sys = line[0];
|
|
2236
|
-
const prn = line.substring(0, 3);
|
|
2241
|
+
const prn = normalizePrn(line.substring(0, 3));
|
|
2237
2242
|
trackSat(sys, prn);
|
|
2238
2243
|
const obsLine = line.substring(3);
|
|
2239
2244
|
const codes = header.obsTypes[sys] ?? [];
|
|
@@ -2258,10 +2263,8 @@ async function parseRinexStream(file, onProgress, signal, onSatObs, workerMode)
|
|
|
2258
2263
|
let v2ObsAccum = [];
|
|
2259
2264
|
function processSatLineV2(line) {
|
|
2260
2265
|
if (!header || v2SatIndex >= v2SatIds.length) return;
|
|
2261
|
-
const
|
|
2262
|
-
|
|
2263
|
-
if (sys === " " || /\d/.test(sys)) sys = "G";
|
|
2264
|
-
const prn = sys + satId.substring(1).padStart(2, "0");
|
|
2266
|
+
const prn = normalizePrn(v2SatIds[v2SatIndex]);
|
|
2267
|
+
const sys = prn[0];
|
|
2265
2268
|
if (v2CurrentSatLine === 0) {
|
|
2266
2269
|
trackSat(sys, prn);
|
|
2267
2270
|
if (onSatObs) v2ObsAccum = [];
|
|
@@ -2352,6 +2355,7 @@ async function parseRinexStream(file, onProgress, signal, onSatObs, workerMode)
|
|
|
2352
2355
|
} else {
|
|
2353
2356
|
epochLine = crxRepair(crxPrevEpochLine, line);
|
|
2354
2357
|
}
|
|
2358
|
+
epochLine = epochLine.replace(/ +$/, "");
|
|
2355
2359
|
if (isV3) {
|
|
2356
2360
|
if (epochLine[0] !== ">") return;
|
|
2357
2361
|
const info = parseEpochLine3(epochLine);
|
|
@@ -2369,10 +2373,11 @@ async function parseRinexStream(file, onProgress, signal, onSatObs, workerMode)
|
|
|
2369
2373
|
return;
|
|
2370
2374
|
}
|
|
2371
2375
|
resetEpochAccum(info);
|
|
2372
|
-
const satPart = epochLine.substring(41).replace(/\s+$/, "");
|
|
2373
2376
|
crxSatList = [];
|
|
2374
|
-
for (let
|
|
2375
|
-
crxSatList.push(
|
|
2377
|
+
for (let k = 0; k < info.numSats; k++) {
|
|
2378
|
+
crxSatList.push(
|
|
2379
|
+
normalizePrn(epochLine.substring(41 + 3 * k, 44 + 3 * k))
|
|
2380
|
+
);
|
|
2376
2381
|
}
|
|
2377
2382
|
crxSatIndex = 0;
|
|
2378
2383
|
crxPrevEpochLine = epochLine;
|
|
@@ -2393,11 +2398,7 @@ async function parseRinexStream(file, onProgress, signal, onSatObs, workerMode)
|
|
|
2393
2398
|
return;
|
|
2394
2399
|
}
|
|
2395
2400
|
resetEpochAccum(info);
|
|
2396
|
-
crxSatList = (info.satIds ?? []).map(
|
|
2397
|
-
let sys = id[0];
|
|
2398
|
-
if (sys === " " || /\d/.test(sys)) sys = "G";
|
|
2399
|
-
return sys + id.substring(1).padStart(2, "0");
|
|
2400
|
-
});
|
|
2401
|
+
crxSatList = (info.satIds ?? []).slice(0, info.numSats).map(normalizePrn);
|
|
2401
2402
|
crxSatIndex = 0;
|
|
2402
2403
|
crxPrevEpochLine = epochLine;
|
|
2403
2404
|
crxPhase = "clock";
|
|
@@ -3026,7 +3027,7 @@ var isc = (b, pos) => {
|
|
|
3026
3027
|
return raw === -4096 ? null : raw * 2 ** -35;
|
|
3027
3028
|
};
|
|
3028
3029
|
function decodeClock(b, msgType) {
|
|
3029
|
-
const
|
|
3030
|
+
const clock2 = {
|
|
3030
3031
|
msgType,
|
|
3031
3032
|
top: getBitU(b, 38, 11) * 300,
|
|
3032
3033
|
uraNed0: getBitS(b, 49, 5),
|
|
@@ -3038,26 +3039,26 @@ function decodeClock(b, msgType) {
|
|
|
3038
3039
|
af2: getBitS(b, 117, 10) * 2 ** -60
|
|
3039
3040
|
};
|
|
3040
3041
|
if (msgType === 30) {
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3042
|
+
clock2.tgd = isc(b, 127);
|
|
3043
|
+
clock2.iscL1ca = isc(b, 140);
|
|
3044
|
+
clock2.iscL2c = isc(b, 153);
|
|
3045
|
+
clock2.iscL5i5 = isc(b, 166);
|
|
3046
|
+
clock2.iscL5q5 = isc(b, 179);
|
|
3047
|
+
clock2.ionoAlpha = [
|
|
3047
3048
|
getBitS(b, 192, 8) * 2 ** -30,
|
|
3048
3049
|
getBitS(b, 200, 8) * 2 ** -27,
|
|
3049
3050
|
getBitS(b, 208, 8) * 2 ** -24,
|
|
3050
3051
|
getBitS(b, 216, 8) * 2 ** -24
|
|
3051
3052
|
];
|
|
3052
|
-
|
|
3053
|
+
clock2.ionoBeta = [
|
|
3053
3054
|
getBitS(b, 224, 8) * 2 ** 11,
|
|
3054
3055
|
getBitS(b, 232, 8) * 2 ** 14,
|
|
3055
3056
|
getBitS(b, 240, 8) * 2 ** 16,
|
|
3056
3057
|
getBitS(b, 248, 8) * 2 ** 16
|
|
3057
3058
|
];
|
|
3058
|
-
|
|
3059
|
+
clock2.wnOp = getBitU(b, 256, 8);
|
|
3059
3060
|
}
|
|
3060
|
-
return
|
|
3061
|
+
return clock2;
|
|
3061
3062
|
}
|
|
3062
3063
|
function resolveWeek(week, towSec, sec) {
|
|
3063
3064
|
if (sec < towSec - HALF_WEEK) return week + 1;
|
|
@@ -3095,10 +3096,10 @@ var CnavAssembler = class {
|
|
|
3095
3096
|
return this.tryEmit(prn, sat);
|
|
3096
3097
|
}
|
|
3097
3098
|
tryEmit(prn, sat) {
|
|
3098
|
-
const { t10, t11, clock, extras } = sat;
|
|
3099
|
-
if (!t10 || !t11 || !
|
|
3100
|
-
if (t10.toe !== t11.toe ||
|
|
3101
|
-
const key = `${t10.week}:${t10.toe}:${
|
|
3099
|
+
const { t10, t11, clock: clock2, extras } = sat;
|
|
3100
|
+
if (!t10 || !t11 || !clock2) return null;
|
|
3101
|
+
if (t10.toe !== t11.toe || clock2.toc !== t10.toe) return null;
|
|
3102
|
+
const key = `${t10.week}:${t10.toe}:${clock2.af0}:${clock2.af1}`;
|
|
3102
3103
|
if (key === sat.lastKey) return null;
|
|
3103
3104
|
sat.lastKey = key;
|
|
3104
3105
|
const weekToe = resolveWeek(t10.week, t10.tow, t10.toe);
|
|
@@ -3109,9 +3110,9 @@ var CnavAssembler = class {
|
|
|
3109
3110
|
week: t10.week,
|
|
3110
3111
|
health: t10.health,
|
|
3111
3112
|
uraEd: t10.uraEd,
|
|
3112
|
-
uraNed0:
|
|
3113
|
-
uraNed1:
|
|
3114
|
-
uraNed2:
|
|
3113
|
+
uraNed0: clock2.uraNed0,
|
|
3114
|
+
uraNed1: clock2.uraNed1,
|
|
3115
|
+
uraNed2: clock2.uraNed2,
|
|
3115
3116
|
top: t10.top,
|
|
3116
3117
|
toe: t10.toe,
|
|
3117
3118
|
toeDate: gpsDate(weekToe, t10.toe),
|
|
@@ -3134,12 +3135,12 @@ var CnavAssembler = class {
|
|
|
3134
3135
|
crc: t11.crc,
|
|
3135
3136
|
cus: t11.cus,
|
|
3136
3137
|
cuc: t11.cuc,
|
|
3137
|
-
toc:
|
|
3138
|
-
tocDate: gpsDate(weekToe,
|
|
3139
|
-
af0:
|
|
3140
|
-
af1:
|
|
3141
|
-
af2:
|
|
3142
|
-
clockMsgType:
|
|
3138
|
+
toc: clock2.toc,
|
|
3139
|
+
tocDate: gpsDate(weekToe, clock2.toc),
|
|
3140
|
+
af0: clock2.af0,
|
|
3141
|
+
af1: clock2.af1,
|
|
3142
|
+
af2: clock2.af2,
|
|
3143
|
+
clockMsgType: clock2.msgType,
|
|
3143
3144
|
tgd: extras?.tgd ?? null,
|
|
3144
3145
|
iscL1ca: extras?.iscL1ca ?? null,
|
|
3145
3146
|
iscL2c: extras?.iscL2c ?? null,
|
|
@@ -3155,6 +3156,304 @@ var CnavAssembler = class {
|
|
|
3155
3156
|
}
|
|
3156
3157
|
};
|
|
3157
3158
|
|
|
3159
|
+
// src/navbits/bds-cnav.ts
|
|
3160
|
+
var BDT_EPOCH_MS = Date.UTC(2006, 0, 1);
|
|
3161
|
+
var SEC_PER_WEEK3 = 7 * 86400;
|
|
3162
|
+
var HALF_WEEK2 = 302400;
|
|
3163
|
+
var BDS_CNAV_A_REF_MEO = 27906100;
|
|
3164
|
+
var BDS_CNAV_A_REF_IGSO_GEO = 42162200;
|
|
3165
|
+
function bdsCnavAref(satType) {
|
|
3166
|
+
return satType === 3 ? BDS_CNAV_A_REF_MEO : BDS_CNAV_A_REF_IGSO_GEO;
|
|
3167
|
+
}
|
|
3168
|
+
function ephI(b, p) {
|
|
3169
|
+
return {
|
|
3170
|
+
toe: getBitU(b, p, 11) * 300,
|
|
3171
|
+
satType: getBitU(b, p + 11, 2),
|
|
3172
|
+
deltaA: getBitS(b, p + 13, 26) * 2 ** -9,
|
|
3173
|
+
aDot: getBitS(b, p + 39, 25) * 2 ** -21,
|
|
3174
|
+
deltaN0: getBitS(b, p + 64, 17) * 2 ** -44 * GPS_PI,
|
|
3175
|
+
deltaN0Dot: getBitS(b, p + 81, 23) * 2 ** -57 * GPS_PI,
|
|
3176
|
+
m0: getBitS33(b, p + 104) * 2 ** -32 * GPS_PI,
|
|
3177
|
+
e: getBitU33(b, p + 137) * 2 ** -34,
|
|
3178
|
+
omega: getBitS33(b, p + 170) * 2 ** -32 * GPS_PI
|
|
3179
|
+
};
|
|
3180
|
+
}
|
|
3181
|
+
function ephII(b, p) {
|
|
3182
|
+
return {
|
|
3183
|
+
omega0: getBitS33(b, p) * 2 ** -32 * GPS_PI,
|
|
3184
|
+
i0: getBitS33(b, p + 33) * 2 ** -32 * GPS_PI,
|
|
3185
|
+
omegaDot: getBitS(b, p + 66, 19) * 2 ** -44 * GPS_PI,
|
|
3186
|
+
i0Dot: getBitS(b, p + 85, 15) * 2 ** -44 * GPS_PI,
|
|
3187
|
+
cis: getBitS(b, p + 100, 16) * 2 ** -30,
|
|
3188
|
+
cic: getBitS(b, p + 116, 16) * 2 ** -30,
|
|
3189
|
+
crs: getBitS(b, p + 132, 24) * 2 ** -8,
|
|
3190
|
+
crc: getBitS(b, p + 156, 24) * 2 ** -8,
|
|
3191
|
+
cus: getBitS(b, p + 180, 21) * 2 ** -30,
|
|
3192
|
+
cuc: getBitS(b, p + 201, 21) * 2 ** -30
|
|
3193
|
+
};
|
|
3194
|
+
}
|
|
3195
|
+
function clock(b, p) {
|
|
3196
|
+
return {
|
|
3197
|
+
toc: getBitU(b, p, 11) * 300,
|
|
3198
|
+
af0: getBitS(b, p + 11, 25) * 2 ** -34,
|
|
3199
|
+
af1: getBitS(b, p + 36, 22) * 2 ** -50,
|
|
3200
|
+
af2: getBitS(b, p + 58, 11) * 2 ** -66
|
|
3201
|
+
};
|
|
3202
|
+
}
|
|
3203
|
+
function sisaiOc(b, p) {
|
|
3204
|
+
return {
|
|
3205
|
+
top: getBitU(b, p, 11) * 300,
|
|
3206
|
+
ocb: getBitS(b, p + 11, 5),
|
|
3207
|
+
oc1: getBitS(b, p + 16, 3),
|
|
3208
|
+
oc2: getBitS(b, p + 19, 3)
|
|
3209
|
+
};
|
|
3210
|
+
}
|
|
3211
|
+
var delay = (b, p) => getBitS(b, p, 12) * 2 ** -34;
|
|
3212
|
+
function crcOk(msg, dataBits) {
|
|
3213
|
+
const need = Math.ceil((dataBits + 24) / 8);
|
|
3214
|
+
return msg.length >= need && crc24q(msg, dataBits) === getBitU(msg, dataBits, 24);
|
|
3215
|
+
}
|
|
3216
|
+
var bdsCnav1Sf2CrcOk = (sf2) => crcOk(sf2, 576);
|
|
3217
|
+
var bdsCnav1Sf3CrcOk = (sf3) => crcOk(sf3, 240);
|
|
3218
|
+
var bdsCnav2CrcOk = (msg) => crcOk(msg, 264);
|
|
3219
|
+
var bdsCnav3CrcOk = (msg) => crcOk(msg, 462);
|
|
3220
|
+
function resolveWeek2(week, towSec, sec) {
|
|
3221
|
+
if (sec < towSec - HALF_WEEK2) return week + 1;
|
|
3222
|
+
if (sec > towSec + HALF_WEEK2) return week - 1;
|
|
3223
|
+
return week;
|
|
3224
|
+
}
|
|
3225
|
+
function bdtDate(week, sec) {
|
|
3226
|
+
return new Date(BDT_EPOCH_MS + (week * SEC_PER_WEEK3 + sec) * 1e3);
|
|
3227
|
+
}
|
|
3228
|
+
var emptyStatus = () => ({
|
|
3229
|
+
top: null,
|
|
3230
|
+
sisaiOe: null,
|
|
3231
|
+
sisaiOcb: null,
|
|
3232
|
+
sisaiOc1: null,
|
|
3233
|
+
sisaiOc2: null,
|
|
3234
|
+
sismai: null,
|
|
3235
|
+
health: null,
|
|
3236
|
+
integrityFlags: null
|
|
3237
|
+
});
|
|
3238
|
+
function applyOc(s, oc) {
|
|
3239
|
+
s.top = oc.top;
|
|
3240
|
+
s.sisaiOcb = oc.ocb;
|
|
3241
|
+
s.sisaiOc1 = oc.oc1;
|
|
3242
|
+
s.sisaiOc2 = oc.oc2;
|
|
3243
|
+
}
|
|
3244
|
+
function build(message, prn, wn, tTm, e1, e22, c, d, s) {
|
|
3245
|
+
const week = resolveWeek2(wn, tTm, e1.toe);
|
|
3246
|
+
const weekToc = resolveWeek2(wn, tTm, c.toc);
|
|
3247
|
+
return {
|
|
3248
|
+
system: "C",
|
|
3249
|
+
prn,
|
|
3250
|
+
message,
|
|
3251
|
+
week,
|
|
3252
|
+
toe: e1.toe,
|
|
3253
|
+
toeDate: bdtDate(week, e1.toe),
|
|
3254
|
+
toc: c.toc,
|
|
3255
|
+
tocDate: bdtDate(weekToc, c.toc),
|
|
3256
|
+
satType: e1.satType,
|
|
3257
|
+
a: bdsCnavAref(e1.satType) + e1.deltaA,
|
|
3258
|
+
deltaA: e1.deltaA,
|
|
3259
|
+
aDot: e1.aDot,
|
|
3260
|
+
deltaN0: e1.deltaN0,
|
|
3261
|
+
deltaN0Dot: e1.deltaN0Dot,
|
|
3262
|
+
m0: e1.m0,
|
|
3263
|
+
e: e1.e,
|
|
3264
|
+
omega: e1.omega,
|
|
3265
|
+
...e22,
|
|
3266
|
+
af0: c.af0,
|
|
3267
|
+
af1: c.af1,
|
|
3268
|
+
af2: c.af2,
|
|
3269
|
+
...d,
|
|
3270
|
+
...s,
|
|
3271
|
+
tow: tTm
|
|
3272
|
+
};
|
|
3273
|
+
}
|
|
3274
|
+
var prnLabel = (prn) => `C${String(prn).padStart(2, "0")}`;
|
|
3275
|
+
var BdsCnav1Assembler = class {
|
|
3276
|
+
status = /* @__PURE__ */ new Map();
|
|
3277
|
+
lastKey = /* @__PURE__ */ new Map();
|
|
3278
|
+
/**
|
|
3279
|
+
* Push one frame's CRC-valid subframes (bit-0 aligned; pass null for
|
|
3280
|
+
* a subframe that failed its CRC) for satellite `prn` (1-63). `tTm`
|
|
3281
|
+
* is the frame's transmit time, s of the BDT week. Returns the newly
|
|
3282
|
+
* seen ephemeris, or null.
|
|
3283
|
+
*/
|
|
3284
|
+
push(prn, sf2, sf3, tTm) {
|
|
3285
|
+
let s = this.status.get(prn);
|
|
3286
|
+
if (!s) this.status.set(prn, s = emptyStatus());
|
|
3287
|
+
if (sf3) {
|
|
3288
|
+
const page = getBitU(sf3, 0, 6);
|
|
3289
|
+
if (page >= 1 && page <= 4) {
|
|
3290
|
+
s.health = getBitU(sf3, 6, 2);
|
|
3291
|
+
s.integrityFlags = getBitU(sf3, 8, 3);
|
|
3292
|
+
s.sismai = getBitU(sf3, 11, 4);
|
|
3293
|
+
if (page === 1) {
|
|
3294
|
+
s.sisaiOe = getBitU(sf3, 15, 5);
|
|
3295
|
+
applyOc(s, sisaiOc(sf3, 20));
|
|
3296
|
+
} else if (page === 3) s.sisaiOe = getBitU(sf3, 15, 5);
|
|
3297
|
+
else applyOc(s, sisaiOc(sf3, 15));
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
3300
|
+
if (!sf2) return null;
|
|
3301
|
+
const wn = getBitU(sf2, 0, 13);
|
|
3302
|
+
const iodc = getBitU(sf2, 21, 10);
|
|
3303
|
+
const iode = getBitU(sf2, 31, 8);
|
|
3304
|
+
const e1 = ephI(sf2, 39);
|
|
3305
|
+
const c = clock(sf2, 464);
|
|
3306
|
+
const key = `${wn}:${iodc}:${iode}:${e1.toe}:${c.toc}`;
|
|
3307
|
+
if (this.lastKey.get(prn) === key) return null;
|
|
3308
|
+
this.lastKey.set(prn, key);
|
|
3309
|
+
return build(
|
|
3310
|
+
"CNV1",
|
|
3311
|
+
prnLabel(prn),
|
|
3312
|
+
wn,
|
|
3313
|
+
tTm,
|
|
3314
|
+
e1,
|
|
3315
|
+
ephII(sf2, 242),
|
|
3316
|
+
c,
|
|
3317
|
+
{
|
|
3318
|
+
iode,
|
|
3319
|
+
iodc,
|
|
3320
|
+
tgdB1Cp: delay(sf2, 557),
|
|
3321
|
+
tgdB2ap: delay(sf2, 533),
|
|
3322
|
+
iscB1Cd: delay(sf2, 545),
|
|
3323
|
+
iscB2ad: null,
|
|
3324
|
+
tgdB2bI: null
|
|
3325
|
+
},
|
|
3326
|
+
{ ...s }
|
|
3327
|
+
);
|
|
3328
|
+
}
|
|
3329
|
+
};
|
|
3330
|
+
var BdsCnav2Assembler = class {
|
|
3331
|
+
sats = /* @__PURE__ */ new Map();
|
|
3332
|
+
/**
|
|
3333
|
+
* Push one CRC-valid 288-bit message (bit 0 = first PRN bit, the
|
|
3334
|
+
* preamble stripped). Returns the newly completed ephemeris, or null.
|
|
3335
|
+
*/
|
|
3336
|
+
push(msg) {
|
|
3337
|
+
const prn = getBitU(msg, 0, 6);
|
|
3338
|
+
const type = getBitU(msg, 6, 6);
|
|
3339
|
+
const sow = getBitU(msg, 12, 18) * 3;
|
|
3340
|
+
if (prn < 1) return null;
|
|
3341
|
+
let sat = this.sats.get(prn);
|
|
3342
|
+
if (!sat) this.sats.set(prn, sat = { status: emptyStatus() });
|
|
3343
|
+
const s = sat.status;
|
|
3344
|
+
if (type === 10) {
|
|
3345
|
+
sat.t10 = {
|
|
3346
|
+
wn: getBitU(msg, 30, 13),
|
|
3347
|
+
iode: getBitU(msg, 53, 8),
|
|
3348
|
+
e1: ephI(msg, 61),
|
|
3349
|
+
sow
|
|
3350
|
+
};
|
|
3351
|
+
s.integrityFlags = getBitU(msg, 43, 3) << 3 | getBitU(msg, 50, 3);
|
|
3352
|
+
s.sismai = getBitU(msg, 46, 4);
|
|
3353
|
+
if (sat.t11 && sat.t11.sow < sow) sat.t11 = void 0;
|
|
3354
|
+
} else if (type === 11 || type >= 30 && type <= 34 || type === 40) {
|
|
3355
|
+
s.health = getBitU(msg, 30, 2);
|
|
3356
|
+
s.integrityFlags = getBitU(msg, 32, 3) << 3 | getBitU(msg, 39, 3);
|
|
3357
|
+
s.sismai = getBitU(msg, 35, 4);
|
|
3358
|
+
if (type === 11) {
|
|
3359
|
+
if (!sat.t10 || sow <= sat.t10.sow) return null;
|
|
3360
|
+
sat.t11 = { e2: ephII(msg, 42), sow };
|
|
3361
|
+
} else if (type === 34) {
|
|
3362
|
+
applyOc(s, sisaiOc(msg, 42));
|
|
3363
|
+
sat.clock = { c: clock(msg, 64), iodc: getBitU(msg, 133, 10) };
|
|
3364
|
+
} else if (type === 40) {
|
|
3365
|
+
s.sisaiOe = getBitU(msg, 42, 5);
|
|
3366
|
+
applyOc(s, sisaiOc(msg, 47));
|
|
3367
|
+
return null;
|
|
3368
|
+
} else {
|
|
3369
|
+
sat.clock = { c: clock(msg, 42), iodc: getBitU(msg, 111, 10) };
|
|
3370
|
+
if (type === 30)
|
|
3371
|
+
sat.delays = {
|
|
3372
|
+
tgdB2ap: delay(msg, 121),
|
|
3373
|
+
iscB2ad: delay(msg, 133),
|
|
3374
|
+
tgdB1Cp: delay(msg, 219)
|
|
3375
|
+
};
|
|
3376
|
+
}
|
|
3377
|
+
} else return null;
|
|
3378
|
+
const { t10, t11, clock: ck } = sat;
|
|
3379
|
+
if (!t10 || !t11 || !ck || (ck.iodc & 255) !== t10.iode) return null;
|
|
3380
|
+
const key = `${t10.wn}:${ck.iodc}:${t10.iode}:${t10.e1.toe}:${ck.c.toc}`;
|
|
3381
|
+
if (sat.lastKey === key) return null;
|
|
3382
|
+
sat.lastKey = key;
|
|
3383
|
+
return build(
|
|
3384
|
+
"CNV2",
|
|
3385
|
+
prnLabel(prn),
|
|
3386
|
+
t10.wn,
|
|
3387
|
+
t10.sow,
|
|
3388
|
+
t10.e1,
|
|
3389
|
+
t11.e2,
|
|
3390
|
+
ck.c,
|
|
3391
|
+
{
|
|
3392
|
+
iode: t10.iode,
|
|
3393
|
+
iodc: ck.iodc,
|
|
3394
|
+
tgdB1Cp: sat.delays?.tgdB1Cp ?? null,
|
|
3395
|
+
tgdB2ap: sat.delays?.tgdB2ap ?? null,
|
|
3396
|
+
iscB1Cd: null,
|
|
3397
|
+
iscB2ad: sat.delays?.iscB2ad ?? null,
|
|
3398
|
+
tgdB2bI: null
|
|
3399
|
+
},
|
|
3400
|
+
{ ...s }
|
|
3401
|
+
);
|
|
3402
|
+
}
|
|
3403
|
+
};
|
|
3404
|
+
var BdsCnav3Assembler = class {
|
|
3405
|
+
sats = /* @__PURE__ */ new Map();
|
|
3406
|
+
/**
|
|
3407
|
+
* Push one CRC-valid 486-bit message (bit 0 = first MesType bit) from
|
|
3408
|
+
* satellite `prn`. Returns the newly completed ephemeris, or null.
|
|
3409
|
+
*/
|
|
3410
|
+
push(prn, msg) {
|
|
3411
|
+
const type = getBitU(msg, 0, 6);
|
|
3412
|
+
const sow = getBitU(msg, 6, 20);
|
|
3413
|
+
let sat = this.sats.get(prn);
|
|
3414
|
+
if (!sat) this.sats.set(prn, sat = { status: emptyStatus() });
|
|
3415
|
+
const s = sat.status;
|
|
3416
|
+
if (type === 10) {
|
|
3417
|
+
sat.t10 = { e1: ephI(msg, 30), e2: ephII(msg, 233), sow };
|
|
3418
|
+
s.integrityFlags = getBitU(msg, 455, 3);
|
|
3419
|
+
s.sismai = getBitU(msg, 458, 4);
|
|
3420
|
+
} else if (type === 30) {
|
|
3421
|
+
sat.t30 = {
|
|
3422
|
+
wn: getBitU(msg, 26, 13),
|
|
3423
|
+
c: clock(msg, 43),
|
|
3424
|
+
tgd: delay(msg, 112)
|
|
3425
|
+
};
|
|
3426
|
+
applyOc(s, sisaiOc(msg, 433));
|
|
3427
|
+
s.sisaiOe = getBitU(msg, 455, 5);
|
|
3428
|
+
s.health = getBitU(msg, 460, 2);
|
|
3429
|
+
} else return null;
|
|
3430
|
+
const { t10, t30 } = sat;
|
|
3431
|
+
if (!t10 || !t30 || t10.e1.toe !== t30.c.toc) return null;
|
|
3432
|
+
const key = `${t30.wn}:${t10.e1.toe}:${t30.c.af0}:${t10.e1.m0}`;
|
|
3433
|
+
if (sat.lastKey === key) return null;
|
|
3434
|
+
sat.lastKey = key;
|
|
3435
|
+
return build(
|
|
3436
|
+
"CNV3",
|
|
3437
|
+
prnLabel(prn),
|
|
3438
|
+
t30.wn,
|
|
3439
|
+
t10.sow,
|
|
3440
|
+
t10.e1,
|
|
3441
|
+
t10.e2,
|
|
3442
|
+
t30.c,
|
|
3443
|
+
{
|
|
3444
|
+
iode: null,
|
|
3445
|
+
iodc: null,
|
|
3446
|
+
tgdB1Cp: null,
|
|
3447
|
+
tgdB2ap: null,
|
|
3448
|
+
iscB1Cd: null,
|
|
3449
|
+
iscB2ad: null,
|
|
3450
|
+
tgdB2bI: t30.tgd
|
|
3451
|
+
},
|
|
3452
|
+
{ ...s }
|
|
3453
|
+
);
|
|
3454
|
+
}
|
|
3455
|
+
};
|
|
3456
|
+
|
|
3158
3457
|
// src/rinex/nav.ts
|
|
3159
3458
|
var DATA_LINES = {
|
|
3160
3459
|
G: 7,
|
|
@@ -3180,16 +3479,17 @@ var R4_MSG_LINES = {
|
|
|
3180
3479
|
// RINEX 4 adds orbit-4 (status flags) vs 3 in RINEX 3
|
|
3181
3480
|
// EPH type parsed into RinexCnavEphemeris for G/J (skipped otherwise)
|
|
3182
3481
|
CNAV: 9,
|
|
3183
|
-
//
|
|
3482
|
+
// BeiDou-3 B-CNAV, parsed into BdsCnavEphemeris
|
|
3184
3483
|
CNV1: 10,
|
|
3185
3484
|
CNV2: 10,
|
|
3186
3485
|
CNV3: 9,
|
|
3486
|
+
// EPH types we skip (different field layout)
|
|
3187
3487
|
L1NV: 8,
|
|
3188
3488
|
L1OC: 9,
|
|
3189
3489
|
L3OC: 9
|
|
3190
3490
|
};
|
|
3191
3491
|
var GPS_EPOCH_MS3 = Date.UTC(1980, 0, 6);
|
|
3192
|
-
var
|
|
3492
|
+
var SEC_PER_WEEK4 = 7 * 86400;
|
|
3193
3493
|
var QZSS_CNAV_A_REF = 42164200;
|
|
3194
3494
|
var SUPPORTED_EPH_MSGS = /* @__PURE__ */ new Set([
|
|
3195
3495
|
"LNAV",
|
|
@@ -3334,8 +3634,8 @@ function buildCnavEphemeris(sys, prn, date, epochVals, d) {
|
|
|
3334
3634
|
const num = (r, c) => d[r]?.[c] ?? 0;
|
|
3335
3635
|
const opt = (r, c) => d[r]?.[c] ?? null;
|
|
3336
3636
|
const t = (date.getTime() - GPS_EPOCH_MS3) / 1e3;
|
|
3337
|
-
const week = Math.floor(t /
|
|
3338
|
-
const toc = t - week *
|
|
3637
|
+
const week = Math.floor(t / SEC_PER_WEEK4);
|
|
3638
|
+
const toc = t - week * SEC_PER_WEEK4;
|
|
3339
3639
|
const sqrtA = num(1, 3);
|
|
3340
3640
|
const a = sqrtA * sqrtA;
|
|
3341
3641
|
const aRef = sys === "J" ? QZSS_CNAV_A_REF : CNAV_A_REF;
|
|
@@ -3392,6 +3692,68 @@ function buildCnavEphemeris(sys, prn, date, epochVals, d) {
|
|
|
3392
3692
|
tow: num(7, 0)
|
|
3393
3693
|
};
|
|
3394
3694
|
}
|
|
3695
|
+
var BDT_EPOCH_MS2 = Date.UTC(2006, 0, 1);
|
|
3696
|
+
function buildBdsCnavEphemeris(message, prn, date, epochVals, d) {
|
|
3697
|
+
const num = (r, c) => d[r]?.[c] ?? 0;
|
|
3698
|
+
const opt = (r, c) => d[r]?.[c] ?? null;
|
|
3699
|
+
const cnv3 = message === "CNV3";
|
|
3700
|
+
const t = (date.getTime() - BDT_EPOCH_MS2) / 1e3;
|
|
3701
|
+
const weekToc = Math.floor(t / SEC_PER_WEEK4);
|
|
3702
|
+
const toc = t - weekToc * SEC_PER_WEEK4;
|
|
3703
|
+
const toe = num(2, 0);
|
|
3704
|
+
const week = toe - toc > SEC_PER_WEEK4 / 2 ? weekToc - 1 : toc - toe > SEC_PER_WEEK4 / 2 ? weekToc + 1 : weekToc;
|
|
3705
|
+
const sqrtA = num(1, 3);
|
|
3706
|
+
const a = sqrtA * sqrtA;
|
|
3707
|
+
const satType = num(4, 2);
|
|
3708
|
+
return {
|
|
3709
|
+
system: "C",
|
|
3710
|
+
prn,
|
|
3711
|
+
message,
|
|
3712
|
+
week,
|
|
3713
|
+
toe,
|
|
3714
|
+
toeDate: new Date(BDT_EPOCH_MS2 + (week * SEC_PER_WEEK4 + toe) * 1e3),
|
|
3715
|
+
toc,
|
|
3716
|
+
tocDate: date,
|
|
3717
|
+
satType,
|
|
3718
|
+
a,
|
|
3719
|
+
deltaA: a - bdsCnavAref(satType),
|
|
3720
|
+
aDot: num(0, 0),
|
|
3721
|
+
deltaN0: num(0, 2),
|
|
3722
|
+
deltaN0Dot: num(4, 1),
|
|
3723
|
+
m0: num(0, 3),
|
|
3724
|
+
e: num(1, 1),
|
|
3725
|
+
omega: num(3, 2),
|
|
3726
|
+
omega0: num(2, 2),
|
|
3727
|
+
i0: num(3, 0),
|
|
3728
|
+
omegaDot: num(3, 3),
|
|
3729
|
+
i0Dot: num(4, 0),
|
|
3730
|
+
cis: num(2, 3),
|
|
3731
|
+
cic: num(2, 1),
|
|
3732
|
+
crs: num(0, 1),
|
|
3733
|
+
crc: num(3, 1),
|
|
3734
|
+
cus: num(1, 2),
|
|
3735
|
+
cuc: num(1, 0),
|
|
3736
|
+
af0: epochVals[0] ?? 0,
|
|
3737
|
+
af1: epochVals[1] ?? 0,
|
|
3738
|
+
af2: epochVals[2] ?? 0,
|
|
3739
|
+
iode: cnv3 ? null : opt(8, 3),
|
|
3740
|
+
iodc: cnv3 ? null : opt(7, 3),
|
|
3741
|
+
tgdB1Cp: cnv3 ? null : opt(6, 2),
|
|
3742
|
+
tgdB2ap: cnv3 ? null : opt(6, 3),
|
|
3743
|
+
iscB1Cd: cnv3 ? null : opt(6, 0),
|
|
3744
|
+
iscB2ad: cnv3 ? null : opt(6, 1),
|
|
3745
|
+
tgdB2bI: cnv3 ? opt(6, 3) : null,
|
|
3746
|
+
top: opt(4, 3),
|
|
3747
|
+
sisaiOe: opt(5, 0),
|
|
3748
|
+
sisaiOcb: opt(5, 1),
|
|
3749
|
+
sisaiOc1: opt(5, 2),
|
|
3750
|
+
sisaiOc2: opt(5, 3),
|
|
3751
|
+
sismai: cnv3 ? opt(6, 0) : opt(7, 0),
|
|
3752
|
+
health: cnv3 ? opt(6, 1) : opt(7, 1),
|
|
3753
|
+
integrityFlags: cnv3 ? opt(6, 2) : opt(7, 2),
|
|
3754
|
+
tow: cnv3 ? num(7, 0) : num(8, 0)
|
|
3755
|
+
};
|
|
3756
|
+
}
|
|
3395
3757
|
function parseNavFile(text) {
|
|
3396
3758
|
const lines = text.split("\n");
|
|
3397
3759
|
const header = {
|
|
@@ -3402,6 +3764,7 @@ function parseNavFile(text) {
|
|
|
3402
3764
|
};
|
|
3403
3765
|
const ephemerides = [];
|
|
3404
3766
|
const cnav = [];
|
|
3767
|
+
const bdsCnav = [];
|
|
3405
3768
|
let inHeader = true;
|
|
3406
3769
|
let i = 0;
|
|
3407
3770
|
while (i < lines.length) {
|
|
@@ -3470,7 +3833,8 @@ function parseNavFile(text) {
|
|
|
3470
3833
|
continue;
|
|
3471
3834
|
}
|
|
3472
3835
|
const isCnav = msgType === "CNAV" && (svSys === "G" || svSys === "J");
|
|
3473
|
-
|
|
3836
|
+
const isBdsCnav = svSys === "C" && (msgType === "CNV1" || msgType === "CNV2" || msgType === "CNV3");
|
|
3837
|
+
if (!SUPPORTED_EPH_MSGS.has(msgType) && !isCnav && !isBdsCnav) {
|
|
3474
3838
|
const totalLines = R4_MSG_LINES[msgType] ?? 2;
|
|
3475
3839
|
i += totalLines + 1;
|
|
3476
3840
|
continue;
|
|
@@ -3482,17 +3846,34 @@ function parseNavFile(text) {
|
|
|
3482
3846
|
const sys2 = epochLine.charAt(0);
|
|
3483
3847
|
const parsed = parseNavEpochV3(epochLine);
|
|
3484
3848
|
const prn2 = `${sys2}${parsed.prn.substring(1)}`;
|
|
3485
|
-
if (isCnav) {
|
|
3849
|
+
if (isCnav || isBdsCnav) {
|
|
3486
3850
|
const slotLines = [];
|
|
3487
3851
|
for (let j = 0; j < numDataLines2; j++) {
|
|
3488
3852
|
i++;
|
|
3489
3853
|
if (i >= lines.length) break;
|
|
3490
3854
|
slotLines.push(parseDataLineSlots(lines[i]));
|
|
3491
3855
|
}
|
|
3492
|
-
if (slotLines.length === numDataLines2
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3856
|
+
if (slotLines.length === numDataLines2) {
|
|
3857
|
+
if (isBdsCnav && sys2 === "C")
|
|
3858
|
+
bdsCnav.push(
|
|
3859
|
+
buildBdsCnavEphemeris(
|
|
3860
|
+
msgType,
|
|
3861
|
+
prn2,
|
|
3862
|
+
parsed.date,
|
|
3863
|
+
parsed.values,
|
|
3864
|
+
slotLines
|
|
3865
|
+
)
|
|
3866
|
+
);
|
|
3867
|
+
else if (sys2 === "G" || sys2 === "J")
|
|
3868
|
+
cnav.push(
|
|
3869
|
+
buildCnavEphemeris(
|
|
3870
|
+
sys2,
|
|
3871
|
+
prn2,
|
|
3872
|
+
parsed.date,
|
|
3873
|
+
parsed.values,
|
|
3874
|
+
slotLines
|
|
3875
|
+
)
|
|
3876
|
+
);
|
|
3496
3877
|
}
|
|
3497
3878
|
i++;
|
|
3498
3879
|
continue;
|
|
@@ -3570,7 +3951,12 @@ function parseNavFile(text) {
|
|
|
3570
3951
|
}
|
|
3571
3952
|
i++;
|
|
3572
3953
|
}
|
|
3573
|
-
return
|
|
3954
|
+
return {
|
|
3955
|
+
header,
|
|
3956
|
+
ephemerides,
|
|
3957
|
+
...cnav.length > 0 && { cnav },
|
|
3958
|
+
...bdsCnav.length > 0 && { bdsCnav }
|
|
3959
|
+
};
|
|
3574
3960
|
}
|
|
3575
3961
|
|
|
3576
3962
|
// src/rinex/nav-writer.ts
|
|
@@ -3766,6 +4152,30 @@ function cnavRecord(eph) {
|
|
|
3766
4152
|
orbitLine4([eph.tow, resolveWnOp(eph.week, eph.wnOp)])
|
|
3767
4153
|
].join("\n");
|
|
3768
4154
|
}
|
|
4155
|
+
function bdsCnavRecord(eph) {
|
|
4156
|
+
const lines = [
|
|
4157
|
+
epochLine4(eph.prn, eph.tocDate, [eph.af0, eph.af1, eph.af2]),
|
|
4158
|
+
orbitLine4([eph.aDot, eph.crs, eph.deltaN0, eph.m0]),
|
|
4159
|
+
orbitLine4([eph.cuc, eph.e, eph.cus, Math.sqrt(eph.a)]),
|
|
4160
|
+
orbitLine4([eph.toe, eph.cic, eph.omega0, eph.cis]),
|
|
4161
|
+
orbitLine4([eph.i0, eph.crc, eph.omega, eph.omegaDot]),
|
|
4162
|
+
orbitLine4([eph.i0Dot, eph.deltaN0Dot, eph.satType, eph.top]),
|
|
4163
|
+
orbitLine4([eph.sisaiOe, eph.sisaiOcb, eph.sisaiOc1, eph.sisaiOc2])
|
|
4164
|
+
];
|
|
4165
|
+
if (eph.message === "CNV3") {
|
|
4166
|
+
lines.push(
|
|
4167
|
+
orbitLine4([eph.sismai, eph.health, eph.integrityFlags, eph.tgdB2bI]),
|
|
4168
|
+
orbitLine4([eph.tow])
|
|
4169
|
+
);
|
|
4170
|
+
} else {
|
|
4171
|
+
lines.push(
|
|
4172
|
+
orbitLine4([eph.iscB1Cd, eph.iscB2ad, eph.tgdB1Cp, eph.tgdB2ap]),
|
|
4173
|
+
orbitLine4([eph.sismai, eph.health, eph.integrityFlags, eph.iodc]),
|
|
4174
|
+
orbitLine4([eph.tow, null, null, eph.iode])
|
|
4175
|
+
);
|
|
4176
|
+
}
|
|
4177
|
+
return lines.join("\n");
|
|
4178
|
+
}
|
|
3769
4179
|
var KLOBUCHAR_SOURCES = [
|
|
3770
4180
|
["GPSA", "GPSB", "G", "LNAV"],
|
|
3771
4181
|
["QZSA", "QZSB", "J", "LNAV"],
|
|
@@ -3843,6 +4253,15 @@ function writeRinexNav4(nav) {
|
|
|
3843
4253
|
` + cnavRecord(eph)
|
|
3844
4254
|
});
|
|
3845
4255
|
}
|
|
4256
|
+
for (const eph of nav.bdsCnav ?? []) {
|
|
4257
|
+
records.push({
|
|
4258
|
+
prn: eph.prn,
|
|
4259
|
+
time: eph.tocDate.getTime(),
|
|
4260
|
+
label: eph.message,
|
|
4261
|
+
body: `> EPH ${padL(eph.prn, 3)} ${eph.message}
|
|
4262
|
+
` + bdsCnavRecord(eph)
|
|
4263
|
+
});
|
|
4264
|
+
}
|
|
3846
4265
|
records.sort(
|
|
3847
4266
|
(a, b) => a.prn.localeCompare(b.prn) || a.time - b.time || a.label.localeCompare(b.label)
|
|
3848
4267
|
);
|
|
@@ -4189,6 +4608,50 @@ function findSatBias(bias, prn, obs1, obs2, tMs) {
|
|
|
4189
4608
|
}
|
|
4190
4609
|
return null;
|
|
4191
4610
|
}
|
|
4611
|
+
var SatOsbTable = class {
|
|
4612
|
+
byKey = /* @__PURE__ */ new Map();
|
|
4613
|
+
constructor(bias) {
|
|
4614
|
+
const recs = Array.isArray(bias) ? bias : bias.records;
|
|
4615
|
+
const groups = /* @__PURE__ */ new Map();
|
|
4616
|
+
for (const r of recs) {
|
|
4617
|
+
if (r.type !== "OSB" || !r.prn || r.station) continue;
|
|
4618
|
+
if (r.unit !== "ns") continue;
|
|
4619
|
+
const k = `${r.prn} ${r.obs1}`;
|
|
4620
|
+
let g = groups.get(k);
|
|
4621
|
+
if (!g) groups.set(k, g = []);
|
|
4622
|
+
g.push(r);
|
|
4623
|
+
}
|
|
4624
|
+
for (const [k, g] of groups) {
|
|
4625
|
+
g.sort((a, b) => a.startMs - b.startMs);
|
|
4626
|
+
this.byKey.set(k, {
|
|
4627
|
+
start: Float64Array.from(g, (r) => r.startMs),
|
|
4628
|
+
end: Float64Array.from(g, (r) => r.endMs),
|
|
4629
|
+
m: Float64Array.from(g, biasMetres)
|
|
4630
|
+
});
|
|
4631
|
+
}
|
|
4632
|
+
}
|
|
4633
|
+
/** Whether any phase (L…) OSB is present — i.e. the product supports AR. */
|
|
4634
|
+
get hasPhase() {
|
|
4635
|
+
for (const k of this.byKey.keys())
|
|
4636
|
+
if (k.split(" ")[1][0] === "L") return true;
|
|
4637
|
+
return false;
|
|
4638
|
+
}
|
|
4639
|
+
/** OSB (m) of `prn`'s observable `obs` (e.g. 'C1W', 'L2W') at `tMs`;
|
|
4640
|
+
* null when the product has none valid then. */
|
|
4641
|
+
get(prn, obs, tMs) {
|
|
4642
|
+
const e = this.byKey.get(`${prn} ${obs}`) ?? this.byKey.get(`${prn} ${obs.slice(0, 2)}X`);
|
|
4643
|
+
if (!e) return null;
|
|
4644
|
+
let lo = 0;
|
|
4645
|
+
let hi = e.start.length - 1;
|
|
4646
|
+
if (tMs < e.start[0]) return null;
|
|
4647
|
+
while (lo < hi) {
|
|
4648
|
+
const mid = lo + hi + 1 >> 1;
|
|
4649
|
+
if (e.start[mid] <= tMs) lo = mid;
|
|
4650
|
+
else hi = mid - 1;
|
|
4651
|
+
}
|
|
4652
|
+
return tMs <= e.end[lo] ? e.m[lo] : null;
|
|
4653
|
+
}
|
|
4654
|
+
};
|
|
4192
4655
|
|
|
4193
4656
|
// src/rinex/obs-writer-common.ts
|
|
4194
4657
|
function createGzipLineSink() {
|
|
@@ -6937,11 +7400,11 @@ function parseUbxCnav(data) {
|
|
|
6937
7400
|
}
|
|
6938
7401
|
|
|
6939
7402
|
// src/navbits/bds.ts
|
|
6940
|
-
var
|
|
6941
|
-
var
|
|
6942
|
-
var MS_PER_WEEK2 =
|
|
6943
|
-
var
|
|
6944
|
-
var sowOf = (dateMs) => dateMs / 1e3 %
|
|
7403
|
+
var BDT_EPOCH_MS3 = Date.UTC(2006, 0, 1);
|
|
7404
|
+
var SEC_PER_WEEK5 = 7 * 86400;
|
|
7405
|
+
var MS_PER_WEEK2 = SEC_PER_WEEK5 * 1e3;
|
|
7406
|
+
var HALF_WEEK3 = 302400;
|
|
7407
|
+
var sowOf = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK5;
|
|
6945
7408
|
var BDS_SUBFRAME_BYTES = 38;
|
|
6946
7409
|
function getBitU2(b, p1, l1, p2, l2) {
|
|
6947
7410
|
return getBitU(b, p1, l1) * 2 ** l2 + getBitU(b, p2, l2);
|
|
@@ -6975,9 +7438,9 @@ function bdsSubframeParityOk(subframe) {
|
|
|
6975
7438
|
}
|
|
6976
7439
|
function buildBdsEphemeris(prn, f) {
|
|
6977
7440
|
let week = f.week;
|
|
6978
|
-
if (f.toes < f.sow -
|
|
6979
|
-
else if (f.toes > f.sow +
|
|
6980
|
-
const tocDate = new Date(
|
|
7441
|
+
if (f.toes < f.sow - HALF_WEEK3) week++;
|
|
7442
|
+
else if (f.toes > f.sow + HALF_WEEK3) week--;
|
|
7443
|
+
const tocDate = new Date(BDT_EPOCH_MS3 + week * MS_PER_WEEK2 + f.tocSec * 1e3);
|
|
6981
7444
|
return {
|
|
6982
7445
|
system: "C",
|
|
6983
7446
|
prn,
|
|
@@ -7216,8 +7679,8 @@ var BdsAssembler = class {
|
|
|
7216
7679
|
|
|
7217
7680
|
// src/navbits/gal.ts
|
|
7218
7681
|
var GPS_EPOCH_MS5 = Date.UTC(1980, 0, 6);
|
|
7219
|
-
var
|
|
7220
|
-
var
|
|
7682
|
+
var SEC_PER_WEEK6 = 7 * 86400;
|
|
7683
|
+
var HALF_WEEK4 = 302400;
|
|
7221
7684
|
var GST_GPS_WEEK_OFFSET = 1024;
|
|
7222
7685
|
function galInavPageCrcOk(page) {
|
|
7223
7686
|
if (page.length < 28) return false;
|
|
@@ -7228,11 +7691,11 @@ function galFnavPageCrcOk(page) {
|
|
|
7228
7691
|
return crc24q(page, 214) === getBitU(page, 214, 24);
|
|
7229
7692
|
}
|
|
7230
7693
|
function gpsDate2(week, sec) {
|
|
7231
|
-
return new Date(GPS_EPOCH_MS5 + (week *
|
|
7694
|
+
return new Date(GPS_EPOCH_MS5 + (week * SEC_PER_WEEK6 + sec) * 1e3);
|
|
7232
7695
|
}
|
|
7233
7696
|
function weekOfToe(week, tow, toe) {
|
|
7234
|
-
if (toe - tow >
|
|
7235
|
-
if (toe - tow < -
|
|
7697
|
+
if (toe - tow > HALF_WEEK4) return week - 1;
|
|
7698
|
+
if (toe - tow < -HALF_WEEK4) return week + 1;
|
|
7236
7699
|
return week;
|
|
7237
7700
|
}
|
|
7238
7701
|
var two4 = (n) => String(n).padStart(2, "0");
|
|
@@ -7324,7 +7787,7 @@ function decodeGalInavWords(words) {
|
|
|
7324
7787
|
return {
|
|
7325
7788
|
system: "E",
|
|
7326
7789
|
prn: `E${two4(svid)}`,
|
|
7327
|
-
toc: tocDate.getTime() / 1e3 %
|
|
7790
|
+
toc: tocDate.getTime() / 1e3 % SEC_PER_WEEK6,
|
|
7328
7791
|
tocDate,
|
|
7329
7792
|
af0,
|
|
7330
7793
|
af1,
|
|
@@ -7432,7 +7895,7 @@ function decodeGalFnavPages(pages) {
|
|
|
7432
7895
|
return {
|
|
7433
7896
|
system: "E",
|
|
7434
7897
|
prn: `E${two4(svid)}`,
|
|
7435
|
-
toc: tocDate.getTime() / 1e3 %
|
|
7898
|
+
toc: tocDate.getTime() / 1e3 % SEC_PER_WEEK6,
|
|
7436
7899
|
tocDate,
|
|
7437
7900
|
af0,
|
|
7438
7901
|
af1,
|
|
@@ -7524,7 +7987,7 @@ var GalFnavAssembler = class {
|
|
|
7524
7987
|
|
|
7525
7988
|
// src/navbits/glo.ts
|
|
7526
7989
|
var GPS_EPOCH_MS6 = Date.UTC(1980, 0, 6);
|
|
7527
|
-
var
|
|
7990
|
+
var SEC_PER_WEEK7 = 7 * 86400;
|
|
7528
7991
|
var SEC_PER_DAY = 86400;
|
|
7529
7992
|
var GLO_STRING_BYTES = 10;
|
|
7530
7993
|
function getBitG(b, pos, len) {
|
|
@@ -7618,8 +8081,8 @@ function decodeGloStrings(strings, refDate, opts = {}) {
|
|
|
7618
8081
|
if (frn1 !== 1 || frn2 !== 2 || frn3 !== 3 || frn4 !== 4) return null;
|
|
7619
8082
|
if (slot < 1 || slot > 27) return null;
|
|
7620
8083
|
const utcSec = (getUtcDate(refDate).getTime() - GPS_EPOCH_MS6) / 1e3;
|
|
7621
|
-
const week = Math.floor(utcSec /
|
|
7622
|
-
let tow = utcSec - week *
|
|
8084
|
+
const week = Math.floor(utcSec / SEC_PER_WEEK7);
|
|
8085
|
+
let tow = utcSec - week * SEC_PER_WEEK7;
|
|
7623
8086
|
const tod = tow % SEC_PER_DAY;
|
|
7624
8087
|
tow -= tod;
|
|
7625
8088
|
let tof = tkH * 3600 + tkM * 60 + tkS - 10800;
|
|
@@ -7632,12 +8095,12 @@ function decodeGloStrings(strings, refDate, opts = {}) {
|
|
|
7632
8095
|
system: "R",
|
|
7633
8096
|
prn: `R${String(slot).padStart(2, "0")}`,
|
|
7634
8097
|
// RINEX GLONASS epochs are UTC: build the UTC toe Date directly.
|
|
7635
|
-
tocDate: new Date(GPS_EPOCH_MS6 + (week *
|
|
8098
|
+
tocDate: new Date(GPS_EPOCH_MS6 + (week * SEC_PER_WEEK7 + tow + toe) * 1e3),
|
|
7636
8099
|
tauN: -tauN,
|
|
7637
8100
|
// RINEX stores −τn; the SIS carries τn (ICD sign)
|
|
7638
8101
|
gammaN,
|
|
7639
8102
|
// v3 message frame time: seconds of the UTC week (RTKLIB tof).
|
|
7640
|
-
messageFrameTime: ((tow + tof) %
|
|
8103
|
+
messageFrameTime: ((tow + tof) % SEC_PER_WEEK7 + SEC_PER_WEEK7) % SEC_PER_WEEK7,
|
|
7641
8104
|
x,
|
|
7642
8105
|
xDot,
|
|
7643
8106
|
xAcc,
|
|
@@ -7730,7 +8193,7 @@ function decodeSbasGeoNav(msg, prn, week, tow) {
|
|
|
7730
8193
|
|
|
7731
8194
|
// src/ubx/rawnav.ts
|
|
7732
8195
|
var GPS_EPOCH_MS8 = Date.UTC(1980, 0, 6);
|
|
7733
|
-
var
|
|
8196
|
+
var SEC_PER_WEEK8 = 7 * 86400;
|
|
7734
8197
|
var two6 = (n) => String(n).padStart(2, "0");
|
|
7735
8198
|
function parseUbxRawNav(data, opts = {}) {
|
|
7736
8199
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
@@ -7752,7 +8215,7 @@ function parseUbxRawNav(data, opts = {}) {
|
|
|
7752
8215
|
if (week === 0 && opts.refWeek !== void 0) week = opts.refWeek;
|
|
7753
8216
|
if (week > 0) {
|
|
7754
8217
|
refDate = new Date(
|
|
7755
|
-
GPS_EPOCH_MS8 + (week *
|
|
8218
|
+
GPS_EPOCH_MS8 + (week * SEC_PER_WEEK8 + rcvTow) * 1e3
|
|
7756
8219
|
);
|
|
7757
8220
|
refWeek = week;
|
|
7758
8221
|
refTow = rcvTow;
|
|
@@ -8066,9 +8529,9 @@ function svidToPrn(svid) {
|
|
|
8066
8529
|
// src/sbf/nav.ts
|
|
8067
8530
|
var PI2 = Math.PI;
|
|
8068
8531
|
var GPS_EPOCH_MS11 = Date.UTC(1980, 0, 6);
|
|
8069
|
-
var
|
|
8070
|
-
var
|
|
8071
|
-
var MS_PER_WEEK5 =
|
|
8532
|
+
var BDT_EPOCH_MS4 = Date.UTC(2006, 0, 1);
|
|
8533
|
+
var SEC_PER_WEEK9 = 7 * 86400;
|
|
8534
|
+
var MS_PER_WEEK5 = SEC_PER_WEEK9 * 1e3;
|
|
8072
8535
|
var F4_DNU = -2e10;
|
|
8073
8536
|
var U4_DNU = 4294967295;
|
|
8074
8537
|
function adjustWeek(refWeek, wn, mod) {
|
|
@@ -8078,7 +8541,7 @@ function adjustWeek(refWeek, wn, mod) {
|
|
|
8078
8541
|
return refWeek - offset;
|
|
8079
8542
|
}
|
|
8080
8543
|
var gpsMs = (week, sec) => GPS_EPOCH_MS11 + week * MS_PER_WEEK5 + sec * 1e3;
|
|
8081
|
-
var sowOf2 = (dateMs) => dateMs / 1e3 %
|
|
8544
|
+
var sowOf2 = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK9;
|
|
8082
8545
|
function decodeGpsQzsNav(view, b, sys) {
|
|
8083
8546
|
const svid = view.getUint8(b + 14);
|
|
8084
8547
|
const prn = sys === "G" ? svid : svid - 180;
|
|
@@ -8181,7 +8644,7 @@ function decodeBdsNav(view, b) {
|
|
|
8181
8644
|
const toes = view.getUint32(b + 88, true);
|
|
8182
8645
|
const wnToc = adjustWeek(bdsWeekRef, view.getUint16(b + 136, true), 8192);
|
|
8183
8646
|
const wnToe = adjustWeek(bdsWeekRef, view.getUint16(b + 138, true), 8192);
|
|
8184
|
-
const tocDate = new Date(
|
|
8647
|
+
const tocDate = new Date(BDT_EPOCH_MS4 + wnToc * MS_PER_WEEK5 + tocs * 1e3);
|
|
8185
8648
|
return {
|
|
8186
8649
|
system: "C",
|
|
8187
8650
|
prn,
|
|
@@ -8227,7 +8690,7 @@ function decodeGloNav(view, b) {
|
|
|
8227
8690
|
const tocDate = new Date(toeGpsMs - leapMs);
|
|
8228
8691
|
const tofGpsMs = gpsMs(wnc, 0) + view.getUint32(b + 8, true);
|
|
8229
8692
|
const tofLeapMs = getGpsLeap(new Date(tofGpsMs)) * 1e3;
|
|
8230
|
-
const messageFrameTime = (tofGpsMs - tofLeapMs - GPS_EPOCH_MS11) / 1e3 %
|
|
8693
|
+
const messageFrameTime = (tofGpsMs - tofLeapMs - GPS_EPOCH_MS11) / 1e3 % SEC_PER_WEEK9;
|
|
8231
8694
|
return {
|
|
8232
8695
|
system: "R",
|
|
8233
8696
|
prn,
|
|
@@ -8550,7 +9013,7 @@ function parseSbfGpsNav(data) {
|
|
|
8550
9013
|
|
|
8551
9014
|
// src/navbits/navic.ts
|
|
8552
9015
|
var GPS_EPOCH_MS13 = Date.UTC(1980, 0, 6);
|
|
8553
|
-
var
|
|
9016
|
+
var SEC_PER_WEEK10 = 604800;
|
|
8554
9017
|
var DATA = 30;
|
|
8555
9018
|
function navicSubframeCrcOk(sf) {
|
|
8556
9019
|
return crc24q(sf, 262) === getBitU(sf, 262, 24);
|
|
@@ -8612,16 +9075,16 @@ function decodeNavicSubframes(sf1, sf2, opts = {}) {
|
|
|
8612
9075
|
j += 22;
|
|
8613
9076
|
const i0 = getBitS(sf2, j, 32) * 2 ** -31 * GPS_PI;
|
|
8614
9077
|
if (sqrtA <= 0 || e >= 1) return null;
|
|
8615
|
-
const week = opts.refWeek ?? Math.floor((Date.now() - GPS_EPOCH_MS13) / 1e3 /
|
|
9078
|
+
const week = opts.refWeek ?? Math.floor((Date.now() - GPS_EPOCH_MS13) / 1e3 / SEC_PER_WEEK10);
|
|
8616
9079
|
const prn = opts.prn ?? "I00";
|
|
8617
9080
|
const tocDate = new Date(
|
|
8618
|
-
GPS_EPOCH_MS13 + (week *
|
|
9081
|
+
GPS_EPOCH_MS13 + (week * SEC_PER_WEEK10 + tocSec) * 1e3
|
|
8619
9082
|
);
|
|
8620
9083
|
return {
|
|
8621
9084
|
system: "I",
|
|
8622
9085
|
prn,
|
|
8623
9086
|
tocDate,
|
|
8624
|
-
toc: tocDate.getTime() / 1e3 %
|
|
9087
|
+
toc: tocDate.getTime() / 1e3 % SEC_PER_WEEK10,
|
|
8625
9088
|
af0,
|
|
8626
9089
|
af1,
|
|
8627
9090
|
af2,
|
|
@@ -8896,6 +9359,80 @@ function parseSbfGloNav(data) {
|
|
|
8896
9359
|
return { ephemerides, badCrc, messages };
|
|
8897
9360
|
}
|
|
8898
9361
|
|
|
9362
|
+
// src/sbf/rawnav-bds-cnav.ts
|
|
9363
|
+
var GPS_BDT_OFFSET = 14;
|
|
9364
|
+
var B1C_FRAME_S = 18;
|
|
9365
|
+
var TOW_DNU2 = 4294967295;
|
|
9366
|
+
function newBdsCnavAssemblers() {
|
|
9367
|
+
return {
|
|
9368
|
+
b1c: new BdsCnav1Assembler(),
|
|
9369
|
+
b2a: new BdsCnav2Assembler(),
|
|
9370
|
+
b2b: new BdsCnav3Assembler()
|
|
9371
|
+
};
|
|
9372
|
+
}
|
|
9373
|
+
function navBits(view, wordsAt, start, nBits) {
|
|
9374
|
+
const out = new Uint8Array(Math.ceil(nBits / 8));
|
|
9375
|
+
for (let i = 0; i < nBits; i++) {
|
|
9376
|
+
const p = start + i;
|
|
9377
|
+
const w = view.getUint32(wordsAt + 4 * (p >>> 5), true);
|
|
9378
|
+
if (w >>> 31 - (p & 31) & 1) out[i >> 3] |= 128 >> (i & 7);
|
|
9379
|
+
}
|
|
9380
|
+
return out;
|
|
9381
|
+
}
|
|
9382
|
+
var MIN_LEN = { 4218: 248, 4219: 92, 4242: 144 };
|
|
9383
|
+
function feedBdsCnavBlock(view, b, id, len, asm) {
|
|
9384
|
+
if (len < (MIN_LEN[id] ?? Infinity)) return {};
|
|
9385
|
+
const prnStr = svidToPrn(view.getUint8(b + 14));
|
|
9386
|
+
if (!prnStr || prnStr[0] !== "C") return {};
|
|
9387
|
+
const prn = Number(prnStr.slice(1));
|
|
9388
|
+
const words = b + 20;
|
|
9389
|
+
if (id === 4218) {
|
|
9390
|
+
const towMs = view.getUint32(b + 8, true);
|
|
9391
|
+
if (towMs === TOW_DNU2) return {};
|
|
9392
|
+
const sf2 = navBits(view, words, 72, 600);
|
|
9393
|
+
const sf3 = navBits(view, words, 1272, 264);
|
|
9394
|
+
const sf2Ok = bdsCnav1Sf2CrcOk(sf2);
|
|
9395
|
+
const bdt = (towMs / 1e3 - GPS_BDT_OFFSET + 604800) % 604800;
|
|
9396
|
+
const tTm = (Math.floor(bdt) - B1C_FRAME_S + 604800) % 604800;
|
|
9397
|
+
const eph = asm.b1c.push(
|
|
9398
|
+
prn,
|
|
9399
|
+
sf2Ok ? sf2 : null,
|
|
9400
|
+
bdsCnav1Sf3CrcOk(sf3) ? sf3 : null,
|
|
9401
|
+
tTm
|
|
9402
|
+
);
|
|
9403
|
+
if (!sf2Ok) return { badCrc: true };
|
|
9404
|
+
return eph ? { eph } : {};
|
|
9405
|
+
}
|
|
9406
|
+
if (id === 4219) {
|
|
9407
|
+
const msg = navBits(view, words, 0, 288);
|
|
9408
|
+
if (!bdsCnav2CrcOk(msg)) return { badCrc: true };
|
|
9409
|
+
const eph = asm.b2a.push(msg);
|
|
9410
|
+
return eph ? { eph } : {};
|
|
9411
|
+
}
|
|
9412
|
+
if (id === 4242) {
|
|
9413
|
+
const msg = navBits(view, words, 12, 486);
|
|
9414
|
+
if (!bdsCnav3CrcOk(msg)) return { badCrc: true };
|
|
9415
|
+
const eph = asm.b2b.push(prn, msg);
|
|
9416
|
+
return eph ? { eph } : {};
|
|
9417
|
+
}
|
|
9418
|
+
return {};
|
|
9419
|
+
}
|
|
9420
|
+
function parseSbfBdsCnav(data) {
|
|
9421
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
9422
|
+
const asm = newBdsCnavAssemblers();
|
|
9423
|
+
const ephemerides = [];
|
|
9424
|
+
let badCrc = 0;
|
|
9425
|
+
let messages = 0;
|
|
9426
|
+
scanSbfFrames(data, view, (id, b, len) => {
|
|
9427
|
+
if (id !== 4218 && id !== 4219 && id !== 4242) return;
|
|
9428
|
+
messages++;
|
|
9429
|
+
const r = feedBdsCnavBlock(view, b, id, len, asm);
|
|
9430
|
+
if (r.eph) ephemerides.push(r.eph);
|
|
9431
|
+
else if (r.badCrc) badCrc++;
|
|
9432
|
+
});
|
|
9433
|
+
return { ephemerides, badCrc, messages };
|
|
9434
|
+
}
|
|
9435
|
+
|
|
8899
9436
|
// src/navbits/sbas-l5.ts
|
|
8900
9437
|
var SBAS_L5_PREAMBLE_UW = 6056250;
|
|
8901
9438
|
function isSbasL1Preamble(msg) {
|
|
@@ -9038,6 +9575,7 @@ function decodeSbfNavigation(data, opts = {}) {
|
|
|
9038
9575
|
const ephemerides = [];
|
|
9039
9576
|
const seen = /* @__PURE__ */ new Set();
|
|
9040
9577
|
const cnav = [];
|
|
9578
|
+
const bdsCnav = [];
|
|
9041
9579
|
const ionoCorrections = {};
|
|
9042
9580
|
let leapSeconds = null;
|
|
9043
9581
|
const counts = {
|
|
@@ -9047,6 +9585,7 @@ function decodeSbfNavigation(data, opts = {}) {
|
|
|
9047
9585
|
galRaw: 0,
|
|
9048
9586
|
gloRaw: 0,
|
|
9049
9587
|
bdsRaw: 0,
|
|
9588
|
+
bdsCnavRaw: 0,
|
|
9050
9589
|
sbasRaw: 0,
|
|
9051
9590
|
sbasL5Raw: 0,
|
|
9052
9591
|
navicRaw: 0,
|
|
@@ -9058,6 +9597,7 @@ function decodeSbfNavigation(data, opts = {}) {
|
|
|
9058
9597
|
const galAsm = newGalAssemblers();
|
|
9059
9598
|
const gloAsm = new GloStringAssembler();
|
|
9060
9599
|
const bdsAsm = new BdsAssembler();
|
|
9600
|
+
const bdsCnavAsm = newBdsCnavAssemblers();
|
|
9061
9601
|
const lnavAsm = new GpsLnavAssembler();
|
|
9062
9602
|
const navicAsm = new NavicAssembler();
|
|
9063
9603
|
const addEph = (e) => {
|
|
@@ -9164,6 +9704,17 @@ function decodeSbfNavigation(data, opts = {}) {
|
|
|
9164
9704
|
else if (r.badCrc) counts.badFrames++;
|
|
9165
9705
|
return;
|
|
9166
9706
|
}
|
|
9707
|
+
case 4218:
|
|
9708
|
+
// BDSRawB1C
|
|
9709
|
+
case 4219:
|
|
9710
|
+
// BDSRawB2a
|
|
9711
|
+
case 4242: {
|
|
9712
|
+
counts.bdsCnavRaw++;
|
|
9713
|
+
const r = feedBdsCnavBlock(view, b, id, len, bdsCnavAsm);
|
|
9714
|
+
if (r.eph) bdsCnav.push(r.eph);
|
|
9715
|
+
else if (r.badCrc) counts.badFrames++;
|
|
9716
|
+
return;
|
|
9717
|
+
}
|
|
9167
9718
|
case 4020: {
|
|
9168
9719
|
if (len < 52) return;
|
|
9169
9720
|
counts.sbasRaw++;
|
|
@@ -9220,7 +9771,15 @@ function decodeSbfNavigation(data, opts = {}) {
|
|
|
9220
9771
|
prns: [...dfmcPrns].sort(),
|
|
9221
9772
|
messages: Object.values(dfmcByType).reduce((a, v) => a + v, 0)
|
|
9222
9773
|
};
|
|
9223
|
-
return {
|
|
9774
|
+
return {
|
|
9775
|
+
ephemerides,
|
|
9776
|
+
cnav,
|
|
9777
|
+
bdsCnav,
|
|
9778
|
+
ionoCorrections,
|
|
9779
|
+
leapSeconds,
|
|
9780
|
+
dfmc,
|
|
9781
|
+
counts
|
|
9782
|
+
};
|
|
9224
9783
|
}
|
|
9225
9784
|
|
|
9226
9785
|
// src/navbits/rs255.ts
|
|
@@ -10470,12 +11029,12 @@ var ID_BDSEPHEMERIS = 1696;
|
|
|
10470
11029
|
var ID_RAWWAASFRAME = 287;
|
|
10471
11030
|
var ID_RAWSBASFRAME = 973;
|
|
10472
11031
|
var GPS_EPOCH_MS16 = Date.UTC(1980, 0, 6);
|
|
10473
|
-
var
|
|
10474
|
-
var
|
|
11032
|
+
var BDT_EPOCH_MS5 = Date.UTC(2006, 0, 1);
|
|
11033
|
+
var SEC_PER_WEEK11 = 7 * 86400;
|
|
10475
11034
|
var SEC_PER_DAY2 = 86400;
|
|
10476
|
-
var MS_PER_WEEK8 =
|
|
11035
|
+
var MS_PER_WEEK8 = SEC_PER_WEEK11 * 1e3;
|
|
10477
11036
|
var gpsMs2 = (week, sec) => GPS_EPOCH_MS16 + week * MS_PER_WEEK8 + sec * 1e3;
|
|
10478
|
-
var sowOf3 = (dateMs) => dateMs / 1e3 %
|
|
11037
|
+
var sowOf3 = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK11;
|
|
10479
11038
|
function nearWeekMs(refMs, sow) {
|
|
10480
11039
|
const refWeek = Math.floor((refMs - GPS_EPOCH_MS16) / MS_PER_WEEK8);
|
|
10481
11040
|
let ms = gpsMs2(refWeek, sow);
|
|
@@ -10504,8 +11063,8 @@ function decodeGloEphemeris(view, p) {
|
|
|
10504
11063
|
tof += Math.floor(tow / SEC_PER_DAY2) * SEC_PER_DAY2;
|
|
10505
11064
|
if (tof < tow - 43200) tof += SEC_PER_DAY2;
|
|
10506
11065
|
else if (tof > tow + 43200) tof -= SEC_PER_DAY2;
|
|
10507
|
-
const toeGpsMs = GPS_EPOCH_MS16 + (week *
|
|
10508
|
-
const tofGpsMs = GPS_EPOCH_MS16 + (week *
|
|
11066
|
+
const toeGpsMs = GPS_EPOCH_MS16 + (week * SEC_PER_WEEK11 + tow) * 1e3;
|
|
11067
|
+
const tofGpsMs = GPS_EPOCH_MS16 + (week * SEC_PER_WEEK11 + tof) * 1e3;
|
|
10509
11068
|
const tofUtcSec = (getUtcDate(new Date(tofGpsMs)).getTime() - GPS_EPOCH_MS16) / 1e3;
|
|
10510
11069
|
return {
|
|
10511
11070
|
system: "R",
|
|
@@ -10514,7 +11073,7 @@ function decodeGloEphemeris(view, p) {
|
|
|
10514
11073
|
tauN: -view.getFloat64(p + 100, true),
|
|
10515
11074
|
// RINEX stores −τ_n
|
|
10516
11075
|
gammaN: view.getFloat64(p + 116, true),
|
|
10517
|
-
messageFrameTime: (tofUtcSec %
|
|
11076
|
+
messageFrameTime: (tofUtcSec % SEC_PER_WEEK11 + SEC_PER_WEEK11) % SEC_PER_WEEK11,
|
|
10518
11077
|
x: view.getFloat64(p + 28, true) / 1e3,
|
|
10519
11078
|
y: view.getFloat64(p + 36, true) / 1e3,
|
|
10520
11079
|
z: view.getFloat64(p + 44, true) / 1e3,
|
|
@@ -10588,7 +11147,7 @@ function decodeBdsEphemeris2(view, p) {
|
|
|
10588
11147
|
const tgd1 = view.getFloat64(p + 20, true);
|
|
10589
11148
|
const tocs = view.getUint32(p + 40, true);
|
|
10590
11149
|
const toes = view.getUint32(p + 72, true);
|
|
10591
|
-
const tocDate = new Date(
|
|
11150
|
+
const tocDate = new Date(BDT_EPOCH_MS5 + week * MS_PER_WEEK8 + tocs * 1e3);
|
|
10592
11151
|
return {
|
|
10593
11152
|
system: "C",
|
|
10594
11153
|
prn: `C${String(prn).padStart(2, "0")}`,
|
|
@@ -10936,7 +11495,7 @@ function parseNovatelRange(data) {
|
|
|
10936
11495
|
const sigtype = stat >>> 21 & 31;
|
|
10937
11496
|
const plock = stat >>> 10 & 1;
|
|
10938
11497
|
const parity = stat >>> 11 & 1;
|
|
10939
|
-
const
|
|
11498
|
+
const clock2 = stat >>> 12 & 1;
|
|
10940
11499
|
const sig = SIGNALS2[satsys]?.[sigtype];
|
|
10941
11500
|
if (!sig) continue;
|
|
10942
11501
|
let [sysL, code] = sig;
|
|
@@ -10966,7 +11525,7 @@ function parseNovatelRange(data) {
|
|
|
10966
11525
|
meas.push({
|
|
10967
11526
|
prn: `${sysL}${String(prnNum).padStart(2, "0")}`,
|
|
10968
11527
|
code,
|
|
10969
|
-
pr:
|
|
11528
|
+
pr: clock2 ? psr : null,
|
|
10970
11529
|
cp: plock ? cp : null,
|
|
10971
11530
|
doppler: plock ? dop : null,
|
|
10972
11531
|
cn0,
|
|
@@ -10993,7 +11552,7 @@ function parseNovatelRange(data) {
|
|
|
10993
11552
|
const sigtype = stat >>> 21 & 31;
|
|
10994
11553
|
const plock = stat >>> 10 & 1;
|
|
10995
11554
|
const parity = stat >>> 11 & 1;
|
|
10996
|
-
const
|
|
11555
|
+
const clock2 = stat >>> 12 & 1;
|
|
10997
11556
|
const sig = SIGNALS2[satsys]?.[sigtype];
|
|
10998
11557
|
if (!sig) continue;
|
|
10999
11558
|
let [sysL, code] = sig;
|
|
@@ -11018,7 +11577,7 @@ function parseNovatelRange(data) {
|
|
|
11018
11577
|
meas.push({
|
|
11019
11578
|
prn,
|
|
11020
11579
|
code,
|
|
11021
|
-
pr:
|
|
11580
|
+
pr: clock2 ? psr : null,
|
|
11022
11581
|
cp: plock ? -adr : null,
|
|
11023
11582
|
doppler: plock ? dop : null,
|
|
11024
11583
|
cn0: snr,
|
|
@@ -11081,14 +11640,14 @@ function* trimbleFrames(data, stats) {
|
|
|
11081
11640
|
|
|
11082
11641
|
// src/trimble/nav.ts
|
|
11083
11642
|
var GPS_EPOCH_MS19 = Date.UTC(1980, 0, 6);
|
|
11084
|
-
var
|
|
11085
|
-
var
|
|
11086
|
-
var MS_PER_WEEK10 =
|
|
11643
|
+
var BDT_EPOCH_MS6 = Date.UTC(2006, 0, 1);
|
|
11644
|
+
var SEC_PER_WEEK12 = 7 * 86400;
|
|
11645
|
+
var MS_PER_WEEK10 = SEC_PER_WEEK12 * 1e3;
|
|
11087
11646
|
var GPS_PI2 = 3.1415926535898;
|
|
11088
11647
|
var BDS_WEEK_OFFSET = 1356;
|
|
11089
11648
|
var BDS_LEAP_SEC = 14;
|
|
11090
11649
|
var gpsMs3 = (week, sec) => GPS_EPOCH_MS19 + week * MS_PER_WEEK10 + sec * 1e3;
|
|
11091
|
-
var sowOf4 = (dateMs) => dateMs / 1e3 %
|
|
11650
|
+
var sowOf4 = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK12;
|
|
11092
11651
|
var SUB_GPS_EPHEMERIS = 1;
|
|
11093
11652
|
var SUB_ION_UTC = 3;
|
|
11094
11653
|
var SUB_GLO_EPHEMERIS = 9;
|
|
@@ -11169,7 +11728,7 @@ function decodeBdsEphemeris3(view, base) {
|
|
|
11169
11728
|
const tocSec = r.tocSec - BDS_LEAP_SEC;
|
|
11170
11729
|
const toeSec = r.toeSec - BDS_LEAP_SEC;
|
|
11171
11730
|
const tocDate = new Date(
|
|
11172
|
-
|
|
11731
|
+
BDT_EPOCH_MS6 + bdsWeek * MS_PER_WEEK10 + tocSec * 1e3
|
|
11173
11732
|
);
|
|
11174
11733
|
return {
|
|
11175
11734
|
system: "C",
|
|
@@ -11240,7 +11799,7 @@ function decodeGloEphemeris2(view, base) {
|
|
|
11240
11799
|
// RINEX stores −τn as the clock bias; the record carries τn (ICD sign).
|
|
11241
11800
|
tauN: -view.getFloat64(base + 113, false),
|
|
11242
11801
|
gammaN: view.getFloat64(base + 121, false),
|
|
11243
|
-
messageFrameTime: (tocMs - GPS_EPOCH_MS19) / 1e3 %
|
|
11802
|
+
messageFrameTime: (tocMs - GPS_EPOCH_MS19) / 1e3 % SEC_PER_WEEK12,
|
|
11244
11803
|
// State vector: metres / m·s⁻¹ / m·s⁻² → km / km·s⁻¹ / km·s⁻².
|
|
11245
11804
|
x: view.getFloat64(base + 33, false) / 1e3,
|
|
11246
11805
|
xDot: view.getFloat64(base + 41, false) / 1e3,
|
|
@@ -11692,12 +12251,12 @@ function* binexRecords(data, view, stats) {
|
|
|
11692
12251
|
// src/binex/nav.ts
|
|
11693
12252
|
var GPS_EPOCH_MS21 = Date.UTC(1980, 0, 6);
|
|
11694
12253
|
var GLO_DAY0_MS = Date.UTC(1980, 0, 1);
|
|
11695
|
-
var
|
|
11696
|
-
var
|
|
11697
|
-
var MS_PER_WEEK12 =
|
|
12254
|
+
var BDT_EPOCH_MS7 = Date.UTC(2006, 0, 1);
|
|
12255
|
+
var SEC_PER_WEEK13 = 7 * 86400;
|
|
12256
|
+
var MS_PER_WEEK12 = SEC_PER_WEEK13 * 1e3;
|
|
11698
12257
|
var SC2RAD = GPS_PI;
|
|
11699
12258
|
var gpsMs4 = (week, sec) => GPS_EPOCH_MS21 + week * MS_PER_WEEK12 + sec * 1e3;
|
|
11700
|
-
var sowOf5 = (dateMs) => (dateMs / 1e3 %
|
|
12259
|
+
var sowOf5 = (dateMs) => (dateMs / 1e3 % SEC_PER_WEEK13 + SEC_PER_WEEK13) % SEC_PER_WEEK13;
|
|
11701
12260
|
var two9 = (n) => String(n).padStart(2, "0");
|
|
11702
12261
|
var Reader = class {
|
|
11703
12262
|
constructor(view, start, le) {
|
|
@@ -11861,7 +12420,7 @@ function decodeBeidou(view, p, le) {
|
|
|
11861
12420
|
const iode = flag1 >> 6 & 31;
|
|
11862
12421
|
const svHealth = flag1 & 1;
|
|
11863
12422
|
const tgd = bdsTgd(flag2 >> 4);
|
|
11864
|
-
const tocDate = new Date(
|
|
12423
|
+
const tocDate = new Date(BDT_EPOCH_MS7 + week * MS_PER_WEEK12 + toes * 1e3);
|
|
11865
12424
|
return {
|
|
11866
12425
|
system: "C",
|
|
11867
12426
|
prn: `C${two9(prn)}`,
|
|
@@ -12389,13 +12948,13 @@ var GM_GPS = 3986005e8;
|
|
|
12389
12948
|
var GM_GAL = 3986004418e5;
|
|
12390
12949
|
var GM_BDS = 3986004418e5;
|
|
12391
12950
|
var GPS_EPOCH_MS23 = Date.UTC(1980, 0, 6);
|
|
12392
|
-
var
|
|
12951
|
+
var BDT_EPOCH_MS8 = Date.UTC(2006, 0, 1);
|
|
12393
12952
|
var WEEK_MS = 6048e5;
|
|
12394
12953
|
var BDT_MINUS_GPST_MS = 14e3;
|
|
12395
12954
|
var BDS_GEO_PRNS = /* @__PURE__ */ new Set([1, 2, 3, 4, 5, 59, 60, 61, 62, 63]);
|
|
12396
12955
|
function almanacEpochMs(alm) {
|
|
12397
12956
|
if (alm.system === "C") {
|
|
12398
|
-
return
|
|
12957
|
+
return BDT_EPOCH_MS8 + alm.weekAlm * WEEK_MS + alm.toaSec * 1e3 + BDT_MINUS_GPST_MS;
|
|
12399
12958
|
}
|
|
12400
12959
|
return GPS_EPOCH_MS23 + alm.weekAlm * WEEK_MS + alm.toaSec * 1e3;
|
|
12401
12960
|
}
|
|
@@ -12770,8 +13329,8 @@ function computeDop(satAzEls) {
|
|
|
12770
13329
|
for (const { az, el, prn } of sats) {
|
|
12771
13330
|
const cosEl = Math.cos(el);
|
|
12772
13331
|
const row = [cosEl * Math.sin(az), cosEl * Math.cos(az), Math.sin(el)];
|
|
12773
|
-
const
|
|
12774
|
-
for (const c of clocks) row.push(c ===
|
|
13332
|
+
const clock2 = dopClock(prn);
|
|
13333
|
+
for (const c of clocks) row.push(c === clock2 ? 1 : 0);
|
|
12775
13334
|
H3.push(row);
|
|
12776
13335
|
}
|
|
12777
13336
|
const HtH = Array.from({ length: m }, () => new Array(m).fill(0));
|
|
@@ -13575,6 +14134,12 @@ function solveZt(n, m, Z2, E) {
|
|
|
13575
14134
|
for (let cIdx = 0; cIdx < m; cIdx++) X[r + cIdx * n] = M[r * w + n + cIdx];
|
|
13576
14135
|
return X;
|
|
13577
14136
|
}
|
|
14137
|
+
function normCdf(x) {
|
|
14138
|
+
const z = Math.abs(x) / Math.SQRT2;
|
|
14139
|
+
const t = 1 / (1 + 0.3275911 * z);
|
|
14140
|
+
const erf = 1 - ((((1.061405429 * t - 1.453152027) * t + 1.421413741) * t - 0.284496736) * t + 0.254829592) * t * Math.exp(-z * z);
|
|
14141
|
+
return x >= 0 ? 0.5 * (1 + erf) : 0.5 * (1 - erf);
|
|
14142
|
+
}
|
|
13578
14143
|
function lambdaSearch(a, Q, n, m = 2) {
|
|
13579
14144
|
if (n <= 0 || m <= 0 || a.length < n || Q.length < n * n) return null;
|
|
13580
14145
|
const L = new Float64Array(n * n);
|
|
@@ -13601,7 +14166,10 @@ function lambdaSearch(a, Q, n, m = 2) {
|
|
|
13601
14166
|
candidates.push(v);
|
|
13602
14167
|
}
|
|
13603
14168
|
const ratio = m >= 2 && s[0] > 0 ? s[1] / s[0] : Infinity;
|
|
13604
|
-
|
|
14169
|
+
let successRate = 1;
|
|
14170
|
+
for (let i = 0; i < n; i++)
|
|
14171
|
+
successRate *= 2 * normCdf(1 / (2 * Math.sqrt(D[i]))) - 1;
|
|
14172
|
+
return { candidates, residuals: s, ratio, successRate };
|
|
13605
14173
|
}
|
|
13606
14174
|
function lambdaReduction(Q, n) {
|
|
13607
14175
|
if (n <= 0 || Q.length < n * n) return null;
|
|
@@ -13616,7 +14184,7 @@ function lambdaReduction(Q, n) {
|
|
|
13616
14184
|
|
|
13617
14185
|
// src/positioning/ppp-antenna.ts
|
|
13618
14186
|
function parseAntexTime(s) {
|
|
13619
|
-
const p = s.trim().split(
|
|
14187
|
+
const p = s.trim().split(/[\s:-]+/).map(Number);
|
|
13620
14188
|
if (p.length < 3 || p.some((v) => Number.isNaN(v))) return null;
|
|
13621
14189
|
return Date.UTC(
|
|
13622
14190
|
p[0],
|
|
@@ -13666,11 +14234,21 @@ function buildPppAntenna(antex) {
|
|
|
13666
14234
|
satOffset(prn, dateMs, band1, band2, f1, f2) {
|
|
13667
14235
|
const list = sats.get(prn);
|
|
13668
14236
|
if (!list) return null;
|
|
13669
|
-
|
|
13670
|
-
|
|
13671
|
-
|
|
13672
|
-
|
|
13673
|
-
|
|
14237
|
+
let entry;
|
|
14238
|
+
let bestDist = Infinity;
|
|
14239
|
+
for (const e of list) {
|
|
14240
|
+
const from = parseAntexTime(e.validFrom) ?? -Infinity;
|
|
14241
|
+
const until = parseAntexTime(e.validUntil) ?? Infinity;
|
|
14242
|
+
if (dateMs >= from && dateMs <= until) {
|
|
14243
|
+
entry = e;
|
|
14244
|
+
break;
|
|
14245
|
+
}
|
|
14246
|
+
const dist = dateMs < from ? from - dateMs : dateMs - until;
|
|
14247
|
+
if (dist < bestDist) {
|
|
14248
|
+
bestDist = dist;
|
|
14249
|
+
entry = e;
|
|
14250
|
+
}
|
|
14251
|
+
}
|
|
13674
14252
|
if (!entry) return null;
|
|
13675
14253
|
const a = freqOf(entry, band1);
|
|
13676
14254
|
const b = freqOf(entry, band2);
|
|
@@ -13678,10 +14256,14 @@ function buildPppAntenna(antex) {
|
|
|
13678
14256
|
return withZen(entry, combineIf(a, b, f1, f2));
|
|
13679
14257
|
},
|
|
13680
14258
|
rcvOffset(antType, band1, band2, f1, f2) {
|
|
13681
|
-
const entry = rcvs.get(antType);
|
|
14259
|
+
const entry = rcvs.get(antType) ?? rcvs.get(antType.substring(0, 16).padEnd(16, " ") + "NONE");
|
|
13682
14260
|
if (!entry) return null;
|
|
13683
|
-
|
|
13684
|
-
|
|
14261
|
+
let a = freqOf(entry, band1);
|
|
14262
|
+
let b = freqOf(entry, band2);
|
|
14263
|
+
if (!a || !b) {
|
|
14264
|
+
a = freqOf(entry, "G01");
|
|
14265
|
+
b = freqOf(entry, "G02");
|
|
14266
|
+
}
|
|
13685
14267
|
if (!a || !b) return null;
|
|
13686
14268
|
return withZen(entry, combineIf(a, b, f1, f2));
|
|
13687
14269
|
}
|
|
@@ -13757,13 +14339,13 @@ function phaseWindup(prn, losRcvToSat, satFrame, latRad, lonRad, state) {
|
|
|
13757
14339
|
kx[2] - k[2] * kdotx - kcrossY[2]
|
|
13758
14340
|
];
|
|
13759
14341
|
const north = enuToEcef([0, 1, 0], latRad, lonRad);
|
|
13760
|
-
const
|
|
14342
|
+
const west = enuToEcef([-1, 0, 0], latRad, lonRad);
|
|
13761
14343
|
const kdotn = dot(k, north);
|
|
13762
|
-
const
|
|
14344
|
+
const kcrossW = cross(k, west);
|
|
13763
14345
|
const dR = [
|
|
13764
|
-
north[0] - k[0] * kdotn +
|
|
13765
|
-
north[1] - k[1] * kdotn +
|
|
13766
|
-
north[2] - k[2] * kdotn +
|
|
14346
|
+
north[0] - k[0] * kdotn + kcrossW[0],
|
|
14347
|
+
north[1] - k[1] * kdotn + kcrossW[1],
|
|
14348
|
+
north[2] - k[2] * kdotn + kcrossW[2]
|
|
13767
14349
|
];
|
|
13768
14350
|
const nS = Math.hypot(dS[0], dS[1], dS[2]) || 1;
|
|
13769
14351
|
const nR = Math.hypot(dR[0], dR[1], dR[2]) || 1;
|
|
@@ -13890,9 +14472,11 @@ function buildGeometry(rover, base, basePos, ephemerides, timeMs, maskRad, tropo
|
|
|
13890
14472
|
let baseLatRad = 0;
|
|
13891
14473
|
let baseLonRad = 0;
|
|
13892
14474
|
if (antenna?.base) {
|
|
13893
|
-
|
|
13894
|
-
|
|
13895
|
-
|
|
14475
|
+
[baseLatRad, baseLonRad] = ecefToGeodetic(
|
|
14476
|
+
basePos[0],
|
|
14477
|
+
basePos[1],
|
|
14478
|
+
basePos[2]
|
|
14479
|
+
);
|
|
13896
14480
|
}
|
|
13897
14481
|
for (const [prn, mR] of rover) {
|
|
13898
14482
|
const sys = prn[0];
|
|
@@ -13988,12 +14572,12 @@ function roverTerms(g, x, y, z, troposphere) {
|
|
|
13988
14572
|
dTropo = tropoDelay(Math.max(elR, 0.05)) - g.tropoB;
|
|
13989
14573
|
}
|
|
13990
14574
|
if (g.offR) {
|
|
13991
|
-
const [
|
|
14575
|
+
const [latRad, lonRad] = ecefToGeodetic(x, y, z);
|
|
13992
14576
|
rho += rcvAntennaRangeM(
|
|
13993
14577
|
g.offR,
|
|
13994
14578
|
[-u[0], -u[1], -u[2]],
|
|
13995
|
-
|
|
13996
|
-
|
|
14579
|
+
latRad,
|
|
14580
|
+
lonRad,
|
|
13997
14581
|
elR,
|
|
13998
14582
|
g.roverDelta
|
|
13999
14583
|
);
|
|
@@ -14997,7 +15581,7 @@ var P2_31 = 2 ** -31;
|
|
|
14997
15581
|
var P2_39 = 2 ** -39;
|
|
14998
15582
|
var D2R = Math.PI / 180;
|
|
14999
15583
|
var R2D = 180 / Math.PI;
|
|
15000
|
-
var
|
|
15584
|
+
var SEC_PER_WEEK14 = 604800;
|
|
15001
15585
|
var MAXSBSAGEF = 30;
|
|
15002
15586
|
var MAXSBSAGEL = 360;
|
|
15003
15587
|
var MAXBAND = 10;
|
|
@@ -15145,7 +15729,7 @@ var igpband2 = [
|
|
|
15145
15729
|
[{ coord: 60, arr: x5, bits: 1, bite: 72 }, { coord: 65, arr: x6, bits: 73, bite: 108 }, { coord: 70, arr: x6, bits: 109, bite: 144 }, { coord: 75, arr: x6, bits: 145, bite: 180 }, { coord: 85, arr: x7, bits: 181, bite: 192 }],
|
|
15146
15730
|
[{ coord: -60, arr: x5, bits: 1, bite: 72 }, { coord: -65, arr: x6, bits: 73, bite: 108 }, { coord: -70, arr: x6, bits: 109, bite: 144 }, { coord: -75, arr: x6, bits: 145, bite: 180 }, { coord: -85, arr: x8, bits: 181, bite: 192 }]
|
|
15147
15731
|
];
|
|
15148
|
-
var gpsSeconds = (week, tow) => week *
|
|
15732
|
+
var gpsSeconds = (week, tow) => week * SEC_PER_WEEK14 + tow;
|
|
15149
15733
|
function maskPrn(i) {
|
|
15150
15734
|
if (i >= 1 && i <= 37) return `G${two11(i)}`;
|
|
15151
15735
|
if (i >= 38 && i <= 61) return `R${two11(i - 37)}`;
|
|
@@ -15525,8 +16109,8 @@ var SbasProcessor = class {
|
|
|
15525
16109
|
const j = block * 15 + i;
|
|
15526
16110
|
if (j >= b.igp.length) continue;
|
|
15527
16111
|
const give = getBitU(msg, 22 + i * 13 + 9, 4);
|
|
15528
|
-
const
|
|
15529
|
-
b.igp[j].delay =
|
|
16112
|
+
const delay2 = getBitU(msg, 22 + i * 13, 9);
|
|
16113
|
+
b.igp[j].delay = delay2 === 511 ? 0 : delay2 * 0.125;
|
|
15530
16114
|
b.igp[j].give = give + 1 >= 16 ? 0 : give + 1;
|
|
15531
16115
|
b.igp[j].t0s = t0s;
|
|
15532
16116
|
}
|
|
@@ -15692,19 +16276,19 @@ var SbasProcessor = class {
|
|
|
15692
16276
|
if (w[3] < 0) return null;
|
|
15693
16277
|
} else return null;
|
|
15694
16278
|
const now = gpsSeconds(week, tow);
|
|
15695
|
-
let
|
|
16279
|
+
let delay2 = 0;
|
|
15696
16280
|
let varVert = 0;
|
|
15697
16281
|
for (let i = 0; i < 4; i++) {
|
|
15698
16282
|
const g = pts[i];
|
|
15699
16283
|
if (!g) continue;
|
|
15700
|
-
|
|
16284
|
+
delay2 += w[i] * g.delay;
|
|
15701
16285
|
const sigGive = Math.sqrt(varicorr(g.give));
|
|
15702
16286
|
const d = this.degr;
|
|
15703
16287
|
const eiono = d ? sbasIonoDeg(d, now - g.t0s) : 0;
|
|
15704
16288
|
const sig2 = d?.rssIono ? sigGive * sigGive + eiono * eiono : (sigGive + eiono) ** 2;
|
|
15705
16289
|
varVert += w[i] * sig2;
|
|
15706
16290
|
}
|
|
15707
|
-
return { delayM:
|
|
16291
|
+
return { delayM: delay2 * fp, varM2: varVert * fp * fp };
|
|
15708
16292
|
}
|
|
15709
16293
|
/** Find the four IGPs bracketing a pierce point (RTKLIB `searchigp`). */
|
|
15710
16294
|
searchIgp(latP, lonP) {
|
|
@@ -15792,10 +16376,10 @@ function applyOrbitClock(eph, corr, timeMs) {
|
|
|
15792
16376
|
const clockM = corr.clockC0 + (corr.clockC1 ?? 0) * age + (corr.clockC2 ?? 0) * age * age + (corr.highRateClock ?? 0);
|
|
15793
16377
|
return { x, y, z, clockOffsetS: clockM / C_LIGHT };
|
|
15794
16378
|
}
|
|
15795
|
-
function hasToOrbitClock(orbit,
|
|
16379
|
+
function hasToOrbitClock(orbit, clock2, refTimeMs, validitySeconds) {
|
|
15796
16380
|
if (orbit.deltaRadial == null || orbit.deltaInTrack == null || orbit.deltaCrossTrack == null)
|
|
15797
16381
|
return null;
|
|
15798
|
-
const clockC0 =
|
|
16382
|
+
const clockC0 = clock2 && clock2.deltaClock != null && !clock2.notUsable ? clock2.deltaClock : 0;
|
|
15799
16383
|
return {
|
|
15800
16384
|
prn: orbit.prn,
|
|
15801
16385
|
iod: orbit.gnssIod,
|
|
@@ -15808,41 +16392,269 @@ function hasToOrbitClock(orbit, clock, refTimeMs, validitySeconds) {
|
|
|
15808
16392
|
};
|
|
15809
16393
|
}
|
|
15810
16394
|
|
|
15811
|
-
// src/positioning/ppp-
|
|
15812
|
-
|
|
15813
|
-
|
|
15814
|
-
|
|
15815
|
-
|
|
15816
|
-
|
|
15817
|
-
|
|
15818
|
-
|
|
15819
|
-
|
|
15820
|
-
|
|
15821
|
-
|
|
15822
|
-
0
|
|
15823
|
-
|
|
15824
|
-
0
|
|
15825
|
-
|
|
15826
|
-
|
|
15827
|
-
|
|
15828
|
-
|
|
15829
|
-
|
|
15830
|
-
|
|
15831
|
-
|
|
15832
|
-
];
|
|
15833
|
-
|
|
15834
|
-
|
|
15835
|
-
|
|
15836
|
-
|
|
15837
|
-
|
|
15838
|
-
|
|
15839
|
-
|
|
15840
|
-
|
|
15841
|
-
|
|
15842
|
-
|
|
15843
|
-
|
|
15844
|
-
|
|
15845
|
-
|
|
16395
|
+
// src/positioning/ppp-ar.ts
|
|
16396
|
+
function wlWavelength(f1, f2) {
|
|
16397
|
+
return C_LIGHT / (f1 - f2);
|
|
16398
|
+
}
|
|
16399
|
+
function nlWavelength(f1, f2) {
|
|
16400
|
+
return C_LIGHT / (f1 + f2);
|
|
16401
|
+
}
|
|
16402
|
+
function resolvePppAmbiguities(sats, Qaif, opts = {}) {
|
|
16403
|
+
const wlThreshold = opts.wlThreshold ?? 0.25;
|
|
16404
|
+
const ratioThreshold = opts.ratioThreshold ?? 3;
|
|
16405
|
+
const minPartial = opts.minPartial ?? 4;
|
|
16406
|
+
const minSuccess = opts.minSuccessRate ?? 0;
|
|
16407
|
+
const n = sats.length;
|
|
16408
|
+
const none = (rejectedWl2, ratio = 0) => ({
|
|
16409
|
+
fixed: false,
|
|
16410
|
+
ratio,
|
|
16411
|
+
refPrn: null,
|
|
16412
|
+
refPrns: [],
|
|
16413
|
+
sats: [],
|
|
16414
|
+
rejectedWl: rejectedWl2
|
|
16415
|
+
});
|
|
16416
|
+
const elev = (i) => sats[i].elevDeg ?? -1;
|
|
16417
|
+
const wlOf = (i) => sats[i].mwCyc - (sats[i].wlBiasCyc ?? 0);
|
|
16418
|
+
const refOfSys = /* @__PURE__ */ new Map();
|
|
16419
|
+
for (let i = 0; i < n; i++) {
|
|
16420
|
+
const sys = sats[i].prn[0];
|
|
16421
|
+
const r = refOfSys.get(sys);
|
|
16422
|
+
if (r === void 0 || elev(i) > elev(r)) refOfSys.set(sys, i);
|
|
16423
|
+
}
|
|
16424
|
+
const nWlOf = /* @__PURE__ */ new Map();
|
|
16425
|
+
const refIdx = /* @__PURE__ */ new Map();
|
|
16426
|
+
const rejectedWl = [];
|
|
16427
|
+
for (const r of refOfSys.values()) {
|
|
16428
|
+
nWlOf.set(r, Math.round(wlOf(r)));
|
|
16429
|
+
refIdx.set(r, r);
|
|
16430
|
+
}
|
|
16431
|
+
for (let i = 0; i < n; i++) {
|
|
16432
|
+
if (refIdx.has(i)) continue;
|
|
16433
|
+
const r = refOfSys.get(sats[i].prn[0]);
|
|
16434
|
+
const sdWl = wlOf(i) - wlOf(r);
|
|
16435
|
+
const k = Math.round(sdWl);
|
|
16436
|
+
if (Math.abs(sdWl - k) <= wlThreshold) {
|
|
16437
|
+
nWlOf.set(i, nWlOf.get(r) + k);
|
|
16438
|
+
refIdx.set(i, r);
|
|
16439
|
+
} else rejectedWl.push(sats[i].prn);
|
|
16440
|
+
}
|
|
16441
|
+
const lamNl = (i) => nlWavelength(sats[i].f1, sats[i].f2);
|
|
16442
|
+
const n1Float = (i) => {
|
|
16443
|
+
const s = sats[i];
|
|
16444
|
+
return s.aIF / lamNl(i) - s.f2 / (s.f1 - s.f2) * nWlOf.get(i) - (s.nlBiasCyc ?? 0);
|
|
16445
|
+
};
|
|
16446
|
+
const qN1 = (a, b) => Qaif[a * n + b] / (lamNl(a) * lamNl(b));
|
|
16447
|
+
let cand = [...refIdx.keys()].filter((i) => refIdx.get(i) !== i).sort((a, b) => elev(b) - elev(a));
|
|
16448
|
+
if (cand.length < 1) return none(rejectedWl);
|
|
16449
|
+
let best = null;
|
|
16450
|
+
let firstRatio = 0;
|
|
16451
|
+
for (; ; ) {
|
|
16452
|
+
const m = cand.length;
|
|
16453
|
+
const sd2 = new Float64Array(m);
|
|
16454
|
+
const Qsd = new Float64Array(m * m);
|
|
16455
|
+
for (let a = 0; a < m; a++) {
|
|
16456
|
+
const ia = cand[a];
|
|
16457
|
+
const ra = refIdx.get(ia);
|
|
16458
|
+
sd2[a] = n1Float(ia) - n1Float(ra);
|
|
16459
|
+
for (let b = 0; b < m; b++) {
|
|
16460
|
+
const ib = cand[b];
|
|
16461
|
+
const rb = refIdx.get(ib);
|
|
16462
|
+
Qsd[a * m + b] = qN1(ia, ib) - qN1(ia, rb) - qN1(ra, ib) + qN1(ra, rb);
|
|
16463
|
+
}
|
|
16464
|
+
}
|
|
16465
|
+
const res = lambdaSearch(sd2, Qsd, m, 2);
|
|
16466
|
+
const ratio = res ? Math.min(res.ratio, 999.9) : 0;
|
|
16467
|
+
if (best === null && firstRatio === 0) firstRatio = ratio;
|
|
16468
|
+
if (res && ratio >= ratioThreshold && res.successRate >= minSuccess) {
|
|
16469
|
+
best = { set: cand, ratio, fix: Float64Array.from(res.candidates[0]) };
|
|
16470
|
+
break;
|
|
16471
|
+
}
|
|
16472
|
+
if (m <= minPartial) break;
|
|
16473
|
+
cand = cand.slice(0, -1);
|
|
16474
|
+
}
|
|
16475
|
+
if (!best) return { ...none(rejectedWl, firstRatio), refPrn: null };
|
|
16476
|
+
const refN1 = /* @__PURE__ */ new Map();
|
|
16477
|
+
for (const r of refOfSys.values()) refN1.set(r, Math.round(n1Float(r)));
|
|
16478
|
+
const out = [];
|
|
16479
|
+
const emit = (i, n1) => {
|
|
16480
|
+
const s = sats[i];
|
|
16481
|
+
const l = lamNl(i);
|
|
16482
|
+
const nWl = nWlOf.get(i);
|
|
16483
|
+
out.push({
|
|
16484
|
+
prn: s.prn,
|
|
16485
|
+
nWl,
|
|
16486
|
+
n1,
|
|
16487
|
+
aIF: l * n1 + l * (s.f2 / (s.f1 - s.f2)) * nWl,
|
|
16488
|
+
ref: sats[refIdx.get(i)].prn
|
|
16489
|
+
});
|
|
16490
|
+
};
|
|
16491
|
+
const usedRefs = new Set(best.set.map((i) => refIdx.get(i)));
|
|
16492
|
+
for (const r of usedRefs) emit(r, refN1.get(r));
|
|
16493
|
+
best.set.forEach(
|
|
16494
|
+
(i, a) => emit(i, refN1.get(refIdx.get(i)) + Math.round(best.fix[a]))
|
|
16495
|
+
);
|
|
16496
|
+
const refPrns = [...usedRefs].map((r) => sats[r].prn);
|
|
16497
|
+
return {
|
|
16498
|
+
fixed: true,
|
|
16499
|
+
ratio: best.ratio,
|
|
16500
|
+
refPrn: refPrns[0] ?? null,
|
|
16501
|
+
refPrns,
|
|
16502
|
+
sats: out,
|
|
16503
|
+
rejectedWl
|
|
16504
|
+
};
|
|
16505
|
+
}
|
|
16506
|
+
function solveSpd(A, b) {
|
|
16507
|
+
const n = b.length;
|
|
16508
|
+
const L = Array.from({ length: n }, () => new Array(n).fill(0));
|
|
16509
|
+
for (let i = 0; i < n; i++) {
|
|
16510
|
+
for (let j = 0; j <= i; j++) {
|
|
16511
|
+
let s = A[i][j];
|
|
16512
|
+
for (let k = 0; k < j; k++) s -= L[i][k] * L[j][k];
|
|
16513
|
+
if (i === j) {
|
|
16514
|
+
if (s <= 0) return null;
|
|
16515
|
+
L[i][j] = Math.sqrt(s);
|
|
16516
|
+
} else {
|
|
16517
|
+
L[i][j] = s / L[j][j];
|
|
16518
|
+
}
|
|
16519
|
+
}
|
|
16520
|
+
}
|
|
16521
|
+
const y = new Array(n).fill(0);
|
|
16522
|
+
for (let i = 0; i < n; i++) {
|
|
16523
|
+
let s = b[i];
|
|
16524
|
+
for (let k = 0; k < i; k++) s -= L[i][k] * y[k];
|
|
16525
|
+
y[i] = s / L[i][i];
|
|
16526
|
+
}
|
|
16527
|
+
const x = new Array(n).fill(0);
|
|
16528
|
+
for (let i = n - 1; i >= 0; i--) {
|
|
16529
|
+
let s = y[i];
|
|
16530
|
+
for (let k = i + 1; k < n; k++) s -= L[k][i] * x[k];
|
|
16531
|
+
x[i] = s / L[i][i];
|
|
16532
|
+
}
|
|
16533
|
+
return x;
|
|
16534
|
+
}
|
|
16535
|
+
function fixPppPosition(state, fcb, opts = {}) {
|
|
16536
|
+
const floatPos = state.position;
|
|
16537
|
+
const noFix = {
|
|
16538
|
+
fixed: false,
|
|
16539
|
+
position: floatPos,
|
|
16540
|
+
floatPosition: floatPos,
|
|
16541
|
+
shift: [0, 0, 0],
|
|
16542
|
+
nFixed: 0,
|
|
16543
|
+
ratio: 0,
|
|
16544
|
+
refPrn: null
|
|
16545
|
+
};
|
|
16546
|
+
const amb = state.ambiguities;
|
|
16547
|
+
if (amb.length < 3) return noFix;
|
|
16548
|
+
const sats = amb.map((a) => ({
|
|
16549
|
+
prn: a.prn,
|
|
16550
|
+
aIF: a.aIF,
|
|
16551
|
+
mwCyc: a.mwCyc,
|
|
16552
|
+
f1: a.f1,
|
|
16553
|
+
f2: a.f2,
|
|
16554
|
+
wlBiasCyc: fcb.satWlFcb.get(a.prn) ?? 0,
|
|
16555
|
+
nlBiasCyc: fcb.satNlFcb.get(a.prn) ?? 0,
|
|
16556
|
+
elevDeg: a.elevDeg
|
|
16557
|
+
}));
|
|
16558
|
+
const n = sats.length;
|
|
16559
|
+
const Qaif = new Float64Array(n * n);
|
|
16560
|
+
for (let i = 0; i < n; i++)
|
|
16561
|
+
for (let j = 0; j < n; j++)
|
|
16562
|
+
Qaif[i * n + j] = state.covariance[amb[i].index][amb[j].index];
|
|
16563
|
+
const res = resolvePppAmbiguities(sats, Qaif, {
|
|
16564
|
+
...opts,
|
|
16565
|
+
minPartial: opts.minPartial ?? Math.max(4, opts.minFixed ?? 0)
|
|
16566
|
+
});
|
|
16567
|
+
if (!res.fixed || res.refPrn === null) {
|
|
16568
|
+
return { ...noFix, ratio: res.ratio, refPrn: res.refPrn };
|
|
16569
|
+
}
|
|
16570
|
+
const idxOfPrn = new Map(amb.map((a) => [a.prn, a.index]));
|
|
16571
|
+
const floatOfPrn = new Map(amb.map((a) => [a.prn, a.aIF]));
|
|
16572
|
+
const fixedOf = new Map(res.sats.map((s) => [s.prn, s.aIF]));
|
|
16573
|
+
const pairs = res.sats.filter(
|
|
16574
|
+
(s) => s.ref !== s.prn && idxOfPrn.has(s.prn) && idxOfPrn.has(s.ref)
|
|
16575
|
+
).map((s) => ({ prn: s.prn, ref: s.ref }));
|
|
16576
|
+
const m = pairs.length;
|
|
16577
|
+
if (m < Math.max(1, opts.minFixed ?? 1))
|
|
16578
|
+
return { ...noFix, ratio: res.ratio, refPrn: res.refPrn };
|
|
16579
|
+
const P = state.covariance;
|
|
16580
|
+
const ix = (prn) => idxOfPrn.get(prn);
|
|
16581
|
+
const qAA = (i, j) => P[ix(i)][ix(j)];
|
|
16582
|
+
const qXA = (r, i) => P[r][ix(i)];
|
|
16583
|
+
const Qzz = Array.from({ length: m }, () => new Array(m).fill(0));
|
|
16584
|
+
const z = new Array(m).fill(0);
|
|
16585
|
+
for (let a = 0; a < m; a++) {
|
|
16586
|
+
const { prn: ia, ref: ra } = pairs[a];
|
|
16587
|
+
z[a] = floatOfPrn.get(ia) - floatOfPrn.get(ra) - (fixedOf.get(ia) - fixedOf.get(ra));
|
|
16588
|
+
for (let b = 0; b < m; b++) {
|
|
16589
|
+
const { prn: ib, ref: rb } = pairs[b];
|
|
16590
|
+
Qzz[a][b] = qAA(ia, ib) - qAA(ia, rb) - qAA(ra, ib) + qAA(ra, rb);
|
|
16591
|
+
}
|
|
16592
|
+
}
|
|
16593
|
+
const Qxz = [0, 1, 2].map(
|
|
16594
|
+
(r) => pairs.map(({ prn, ref }) => qXA(r, prn) - qXA(r, ref))
|
|
16595
|
+
);
|
|
16596
|
+
const y = solveSpd(Qzz, z);
|
|
16597
|
+
if (!y) return { ...noFix, ratio: res.ratio, refPrn: res.refPrn };
|
|
16598
|
+
let chi2 = 0;
|
|
16599
|
+
for (let a = 0; a < m; a++) chi2 += z[a] * y[a];
|
|
16600
|
+
if (chi2 / m > (opts.maxChi2 ?? Infinity))
|
|
16601
|
+
return { ...noFix, ratio: res.ratio, refPrn: res.refPrn };
|
|
16602
|
+
const shift = [0, 0, 0];
|
|
16603
|
+
for (let r = 0; r < 3; r++) {
|
|
16604
|
+
let s = 0;
|
|
16605
|
+
for (let a = 0; a < m; a++) s += Qxz[r][a] * y[a];
|
|
16606
|
+
shift[r] = -s;
|
|
16607
|
+
}
|
|
16608
|
+
return {
|
|
16609
|
+
fixed: true,
|
|
16610
|
+
position: [
|
|
16611
|
+
floatPos[0] + shift[0],
|
|
16612
|
+
floatPos[1] + shift[1],
|
|
16613
|
+
floatPos[2] + shift[2]
|
|
16614
|
+
],
|
|
16615
|
+
floatPosition: floatPos,
|
|
16616
|
+
shift,
|
|
16617
|
+
nFixed: m,
|
|
16618
|
+
ratio: res.ratio,
|
|
16619
|
+
refPrn: res.refPrn
|
|
16620
|
+
};
|
|
16621
|
+
}
|
|
16622
|
+
|
|
16623
|
+
// src/positioning/ppp-tropo.ts
|
|
16624
|
+
var HYD_AVG_A = [
|
|
16625
|
+
0.0012769934,
|
|
16626
|
+
1268323e-9,
|
|
16627
|
+
0.0012465397,
|
|
16628
|
+
0.0012196049,
|
|
16629
|
+
0.0012045996
|
|
16630
|
+
];
|
|
16631
|
+
var HYD_AVG_B = [
|
|
16632
|
+
0.0029153695,
|
|
16633
|
+
0.0029152299,
|
|
16634
|
+
0.0029288445,
|
|
16635
|
+
0.0029022565,
|
|
16636
|
+
0.0029024912
|
|
16637
|
+
];
|
|
16638
|
+
var HYD_AVG_C = [
|
|
16639
|
+
0.062610505,
|
|
16640
|
+
0.062837393,
|
|
16641
|
+
0.063721774,
|
|
16642
|
+
0.063824265,
|
|
16643
|
+
0.064258455
|
|
16644
|
+
];
|
|
16645
|
+
var HYD_AMP_A = [0, 12709626e-12, 26523662e-12, 34000452e-12, 41202191e-12];
|
|
16646
|
+
var HYD_AMP_B = [0, 21414979e-12, 30160779e-12, 72562722e-12, 11723375e-11];
|
|
16647
|
+
var HYD_AMP_C = [0, 901284e-10, 43497037e-12, 84795348e-11, 0.0017037206];
|
|
16648
|
+
var HT_A = 253e-7;
|
|
16649
|
+
var HT_B = 549e-5;
|
|
16650
|
+
var HT_C = 114e-5;
|
|
16651
|
+
var WET_A = [
|
|
16652
|
+
58021897e-11,
|
|
16653
|
+
56794847e-11,
|
|
16654
|
+
58118019e-11,
|
|
16655
|
+
59727542e-11,
|
|
16656
|
+
61641693e-11
|
|
16657
|
+
];
|
|
15846
16658
|
var WET_B = [
|
|
15847
16659
|
0.0014275268,
|
|
15848
16660
|
0.0015138625,
|
|
@@ -16015,13 +16827,11 @@ function createPppCorrections(cfg) {
|
|
|
16015
16827
|
let rangeM = 0;
|
|
16016
16828
|
let phaseWindupM = 0;
|
|
16017
16829
|
const e = geom.los;
|
|
16018
|
-
const [
|
|
16830
|
+
const [latRad, lonRad] = ecefToGeodetic(
|
|
16019
16831
|
geom.rcvEcef[0],
|
|
16020
16832
|
geom.rcvEcef[1],
|
|
16021
16833
|
geom.rcvEcef[2]
|
|
16022
16834
|
);
|
|
16023
|
-
const latRad = latDeg * Math.PI / 180;
|
|
16024
|
-
const lonRad = lonDeg * Math.PI / 180;
|
|
16025
16835
|
const frame = ctx ? satBodyFrame(geom.satEcef, ctx.sun) : null;
|
|
16026
16836
|
if (useSat && frame && geom.band1 && geom.band2) {
|
|
16027
16837
|
const off = cfg.antenna.satOffset(
|
|
@@ -16079,6 +16889,10 @@ function createPppCorrections(cfg) {
|
|
|
16079
16889
|
}
|
|
16080
16890
|
|
|
16081
16891
|
// src/positioning/ppp.ts
|
|
16892
|
+
var NO_FCB = {
|
|
16893
|
+
satWlFcb: /* @__PURE__ */ new Map(),
|
|
16894
|
+
satNlFcb: /* @__PURE__ */ new Map()
|
|
16895
|
+
};
|
|
16082
16896
|
function matVec(P, h) {
|
|
16083
16897
|
const n = P.length;
|
|
16084
16898
|
const out = new Array(n).fill(0);
|
|
@@ -16090,6 +16904,34 @@ function matVec(P, h) {
|
|
|
16090
16904
|
}
|
|
16091
16905
|
return out;
|
|
16092
16906
|
}
|
|
16907
|
+
function tdLsq(qs) {
|
|
16908
|
+
const M = [0, 1, 2, 3].map(() => [0, 0, 0, 0, 0]);
|
|
16909
|
+
for (const q of qs) {
|
|
16910
|
+
const a = [-q.v.e[0], -q.v.e[1], -q.v.e[2], 1];
|
|
16911
|
+
for (let i = 0; i < 4; i++) {
|
|
16912
|
+
M[i][4] += a[i] * q.d;
|
|
16913
|
+
for (let j = 0; j < 4; j++) M[i][j] += a[i] * a[j];
|
|
16914
|
+
}
|
|
16915
|
+
}
|
|
16916
|
+
for (let c = 0; c < 4; c++) {
|
|
16917
|
+
let p = c;
|
|
16918
|
+
for (let r = c + 1; r < 4; r++)
|
|
16919
|
+
if (Math.abs(M[r][c]) > Math.abs(M[p][c])) p = r;
|
|
16920
|
+
if (Math.abs(M[p][c]) < 1e-9) return null;
|
|
16921
|
+
[M[c], M[p]] = [M[p], M[c]];
|
|
16922
|
+
for (let r = 0; r < 4; r++) {
|
|
16923
|
+
if (r === c) continue;
|
|
16924
|
+
const f = M[r][c] / M[c][c];
|
|
16925
|
+
for (let k = c; k < 5; k++) M[r][k] -= f * M[c][k];
|
|
16926
|
+
}
|
|
16927
|
+
}
|
|
16928
|
+
return [0, 1, 2, 3].map((i) => M[i][4] / M[i][i]);
|
|
16929
|
+
}
|
|
16930
|
+
function tdResidual(q, s) {
|
|
16931
|
+
return q.d - (-q.v.e[0] * s[0] - q.v.e[1] * s[1] - q.v.e[2] * s[2] + s[3]);
|
|
16932
|
+
}
|
|
16933
|
+
var TD_SLIP_M = 0.08;
|
|
16934
|
+
var CODE_GATE_M = 15;
|
|
16093
16935
|
function ekfUpdateScalar(x, P, h, innovation, r, rejectK = 0) {
|
|
16094
16936
|
const n = x.length;
|
|
16095
16937
|
const Ph = matVec(P, h);
|
|
@@ -16122,10 +16964,17 @@ function ifCoeffs(f1, f2) {
|
|
|
16122
16964
|
return { g, lambdaIf };
|
|
16123
16965
|
}
|
|
16124
16966
|
var Sp3EphemerisSource = class {
|
|
16125
|
-
constructor(sp3, clk) {
|
|
16967
|
+
constructor(sp3, clk, osb) {
|
|
16126
16968
|
this.sp3 = sp3;
|
|
16127
16969
|
this.clk = clk;
|
|
16970
|
+
this.osb = osb;
|
|
16971
|
+
if (osb) {
|
|
16972
|
+
this.codeBias = (prn, code, t) => osb.get(prn, "C" + code, t);
|
|
16973
|
+
this.phaseBias = (prn, code, t) => osb.get(prn, "L" + code, t);
|
|
16974
|
+
}
|
|
16128
16975
|
}
|
|
16976
|
+
codeBias;
|
|
16977
|
+
phaseBias;
|
|
16129
16978
|
satState(prn, tEmitMs) {
|
|
16130
16979
|
const p = sp3Position(this.sp3, prn, tEmitMs);
|
|
16131
16980
|
if (!p || p.clk == null) return null;
|
|
@@ -16143,6 +16992,21 @@ var Sp3EphemerisSource = class {
|
|
|
16143
16992
|
return { x: p.x, y: p.y, z: p.z, vx, vy, vz, clkS };
|
|
16144
16993
|
}
|
|
16145
16994
|
};
|
|
16995
|
+
function applySatBiases(source, o, tMs) {
|
|
16996
|
+
if (!source.codeBias && !source.phaseBias) return o;
|
|
16997
|
+
const b1 = source.codeBias?.(o.prn, o.code1 ?? "", tMs) ?? 0;
|
|
16998
|
+
const b2 = source.codeBias?.(o.prn, o.code2 ?? "", tMs) ?? 0;
|
|
16999
|
+
let l1 = o.l1;
|
|
17000
|
+
let l2 = o.l2;
|
|
17001
|
+
if (source.phaseBias) {
|
|
17002
|
+
const p1 = source.phaseBias(o.prn, o.phase1 ?? o.code1 ?? "", tMs);
|
|
17003
|
+
const p2 = source.phaseBias(o.prn, o.phase2 ?? o.code2 ?? "", tMs);
|
|
17004
|
+
if (p1 == null || p2 == null) return null;
|
|
17005
|
+
l1 -= p1 / (C_LIGHT / o.f1);
|
|
17006
|
+
l2 -= p2 / (C_LIGHT / o.f2);
|
|
17007
|
+
}
|
|
17008
|
+
return { ...o, c1: o.c1 - b1, c2: o.c2 - b2, l1, l2 };
|
|
17009
|
+
}
|
|
16146
17010
|
function sagnacRotate(x, y, z, travelS) {
|
|
16147
17011
|
const theta = OMEGA_E * travelS;
|
|
16148
17012
|
const c = Math.cos(theta);
|
|
@@ -16204,6 +17068,16 @@ var PppEngine = class {
|
|
|
16204
17068
|
arcs;
|
|
16205
17069
|
arcSnap;
|
|
16206
17070
|
mwState;
|
|
17071
|
+
/** Previous epoch's phase terms per satellite, for the time-differenced
|
|
17072
|
+
* (clock-free) cycle-slip test. */
|
|
17073
|
+
tdPrev;
|
|
17074
|
+
/** Consecutive gated-out phase updates per satellite. */
|
|
17075
|
+
phaseRejects;
|
|
17076
|
+
/** PPP-AR: the latest accepted fix (null: float). */
|
|
17077
|
+
lastFix;
|
|
17078
|
+
lastArMs;
|
|
17079
|
+
firstFixMs;
|
|
17080
|
+
fixedEpochs;
|
|
16207
17081
|
series;
|
|
16208
17082
|
ei = 0;
|
|
16209
17083
|
t0 = 0;
|
|
@@ -16239,6 +17113,12 @@ var PppEngine = class {
|
|
|
16239
17113
|
this.arcs = [];
|
|
16240
17114
|
this.arcSnap = /* @__PURE__ */ new Map();
|
|
16241
17115
|
this.mwState = /* @__PURE__ */ new Map();
|
|
17116
|
+
this.tdPrev = /* @__PURE__ */ new Map();
|
|
17117
|
+
this.phaseRejects = /* @__PURE__ */ new Map();
|
|
17118
|
+
this.lastFix = null;
|
|
17119
|
+
this.lastArMs = -Infinity;
|
|
17120
|
+
this.firstFixMs = null;
|
|
17121
|
+
this.fixedEpochs = 0;
|
|
16242
17122
|
this.series = [];
|
|
16243
17123
|
this.ei = 0;
|
|
16244
17124
|
this.t0 = 0;
|
|
@@ -16332,7 +17212,9 @@ var PppEngine = class {
|
|
|
16332
17212
|
lastSeen,
|
|
16333
17213
|
arcSnap,
|
|
16334
17214
|
mwState,
|
|
16335
|
-
series
|
|
17215
|
+
series,
|
|
17216
|
+
tdPrev,
|
|
17217
|
+
phaseRejects
|
|
16336
17218
|
} = this;
|
|
16337
17219
|
const flushArc = this.flushArc.bind(this);
|
|
16338
17220
|
const detectSlip = this.detectSlip.bind(this);
|
|
@@ -16354,13 +17236,15 @@ var PppEngine = class {
|
|
|
16354
17236
|
for (const ci of clkIdx.values()) P[ci][ci] = CLK_VAR;
|
|
16355
17237
|
P[IDX_ZWD][IDX_ZWD] += ztdQ * (ei > 0 ? 1 : 0);
|
|
16356
17238
|
const rcv = [x[IDX_X], x[IDX_Y], x[IDX_Z]];
|
|
16357
|
-
const [
|
|
16358
|
-
const latRad = latDeg * Math.PI / 180;
|
|
17239
|
+
const [latRad, , heightM] = ecefToGeodetic(rcv[0], rcv[1], rcv[2]);
|
|
16359
17240
|
const epochCtx = corrections?.epochContext?.(epoch.timeMs, rcv) ?? null;
|
|
16360
17241
|
const vis = [];
|
|
16361
17242
|
let epochZhd = 0;
|
|
16362
|
-
for (const
|
|
16363
|
-
if (
|
|
17243
|
+
for (const raw of epoch.obs) {
|
|
17244
|
+
if (raw.c1 === 0 || raw.c2 === 0 || raw.l1 === 0 || raw.l2 === 0)
|
|
17245
|
+
continue;
|
|
17246
|
+
const o = applySatBiases(source, raw, epoch.timeMs);
|
|
17247
|
+
if (!o) continue;
|
|
16364
17248
|
const slip = detectSlip(o, ei);
|
|
16365
17249
|
const sat = satStateAtEmission(source, o.prn, epoch.timeMs, rcv);
|
|
16366
17250
|
if (!sat) continue;
|
|
@@ -16382,9 +17266,7 @@ var PppEngine = class {
|
|
|
16382
17266
|
const lam1 = C_LIGHT / o.f1;
|
|
16383
17267
|
const lam2 = C_LIGHT / o.f2;
|
|
16384
17268
|
if (o.c1 === 0 || o.c2 === 0 || o.l1 === 0 || o.l2 === 0) continue;
|
|
16385
|
-
const
|
|
16386
|
-
const b2 = source.codeBias?.(o.prn, o.code2 ?? "", epoch.timeMs) ?? 0;
|
|
16387
|
-
const pIf = g * (o.c1 - b1) - (g - 1) * (o.c2 - b2);
|
|
17269
|
+
const pIf = g * o.c1 - (g - 1) * o.c2;
|
|
16388
17270
|
const lIf = g * (o.l1 * lam1) - (g - 1) * (o.l2 * lam2);
|
|
16389
17271
|
if (!Number.isFinite(pIf) || !Number.isFinite(lIf)) continue;
|
|
16390
17272
|
const trop = opts.troposphere ?? true ? niellMapping(elRad, latRad, heightM, epoch.timeMs) : { zhd: 0, mh: 0, mw: 0 };
|
|
@@ -16417,9 +17299,63 @@ var PppEngine = class {
|
|
|
16417
17299
|
windupM: corr.phaseWindupM,
|
|
16418
17300
|
slip,
|
|
16419
17301
|
f1: o.f1,
|
|
16420
|
-
f2: o.f2
|
|
17302
|
+
f2: o.f2,
|
|
17303
|
+
sat: [sat.state.x, sat.state.y, sat.state.z]
|
|
16421
17304
|
});
|
|
16422
17305
|
}
|
|
17306
|
+
{
|
|
17307
|
+
const dq = [];
|
|
17308
|
+
for (const v of vis) {
|
|
17309
|
+
const prev = tdPrev.get(v.prn);
|
|
17310
|
+
const model = -v.satClkM + v.tropoFixed + v.windupM;
|
|
17311
|
+
if (prev && prev.ei === ei - 1 && !v.slip) {
|
|
17312
|
+
const r0 = Math.hypot(
|
|
17313
|
+
prev.sat[0] - rcv[0],
|
|
17314
|
+
prev.sat[1] - rcv[1],
|
|
17315
|
+
prev.sat[2] - rcv[2]
|
|
17316
|
+
);
|
|
17317
|
+
dq.push({
|
|
17318
|
+
v,
|
|
17319
|
+
d: v.lIf - prev.lIf - (v.range - r0) - (model - prev.model)
|
|
17320
|
+
});
|
|
17321
|
+
}
|
|
17322
|
+
tdPrev.set(v.prn, { ei, lIf: v.lIf, sat: v.sat, model });
|
|
17323
|
+
}
|
|
17324
|
+
if (!kinematic) {
|
|
17325
|
+
if (dq.length >= 4) {
|
|
17326
|
+
const sorted = dq.map((q) => q.d).sort((a, b) => a - b);
|
|
17327
|
+
const med = sorted[Math.floor(sorted.length / 2)];
|
|
17328
|
+
for (const q of dq)
|
|
17329
|
+
if (Math.abs(q.d - med) > TD_SLIP_M) q.v.slip = true;
|
|
17330
|
+
}
|
|
17331
|
+
} else if (dq.length >= 6) {
|
|
17332
|
+
let use = dq;
|
|
17333
|
+
for (let iter = 0; iter < 6; iter++) {
|
|
17334
|
+
const sol = use.length >= 6 ? tdLsq(use) : null;
|
|
17335
|
+
if (!sol) {
|
|
17336
|
+
for (const q of dq) q.v.slip = true;
|
|
17337
|
+
break;
|
|
17338
|
+
}
|
|
17339
|
+
let worst = -1;
|
|
17340
|
+
let worstR = 0;
|
|
17341
|
+
use.forEach((q, k) => {
|
|
17342
|
+
const r = Math.abs(tdResidual(q, sol));
|
|
17343
|
+
if (r > worstR) {
|
|
17344
|
+
worstR = r;
|
|
17345
|
+
worst = k;
|
|
17346
|
+
}
|
|
17347
|
+
});
|
|
17348
|
+
if (worstR <= TD_SLIP_M || iter === 5) {
|
|
17349
|
+
for (const q of dq)
|
|
17350
|
+
if (Math.abs(tdResidual(q, sol)) > TD_SLIP_M) q.v.slip = true;
|
|
17351
|
+
break;
|
|
17352
|
+
}
|
|
17353
|
+
use = use.filter((_, k) => k !== worst);
|
|
17354
|
+
}
|
|
17355
|
+
} else {
|
|
17356
|
+
for (const q of dq) q.v.slip = true;
|
|
17357
|
+
}
|
|
17358
|
+
}
|
|
16423
17359
|
const zwd0 = x[IDX_ZWD];
|
|
16424
17360
|
const bySys = /* @__PURE__ */ new Map();
|
|
16425
17361
|
for (const v of vis) {
|
|
@@ -16429,6 +17365,20 @@ var PppEngine = class {
|
|
|
16429
17365
|
if (arr) arr.push(r);
|
|
16430
17366
|
else bySys.set(sys, [r]);
|
|
16431
17367
|
}
|
|
17368
|
+
const posSigma = Math.sqrt(
|
|
17369
|
+
P[IDX_X][IDX_X] + P[IDX_Y][IDX_Y] + P[IDX_Z][IDX_Z]
|
|
17370
|
+
);
|
|
17371
|
+
const codeGate = CODE_GATE_M + 3 * posSigma;
|
|
17372
|
+
const screened = /* @__PURE__ */ new Set();
|
|
17373
|
+
for (const [sys, res] of bySys) {
|
|
17374
|
+
if (res.length < 4) continue;
|
|
17375
|
+
const med = [...res].sort((a, b) => a - b)[Math.floor(res.length / 2)];
|
|
17376
|
+
for (const v of vis) {
|
|
17377
|
+
if (v.prn[0] !== sys) continue;
|
|
17378
|
+
const r = v.pIf - (v.range - v.satClkM + v.tropoFixed + zwd0 * v.mw);
|
|
17379
|
+
if (Math.abs(r - med) > codeGate) screened.add(v.prn);
|
|
17380
|
+
}
|
|
17381
|
+
}
|
|
16432
17382
|
for (const [sys, res] of bySys) {
|
|
16433
17383
|
const ci = clockOf(sys);
|
|
16434
17384
|
if (!clockSeeded.has(sys)) {
|
|
@@ -16439,9 +17389,11 @@ var PppEngine = class {
|
|
|
16439
17389
|
P[ci][ci] = CLK_VAR;
|
|
16440
17390
|
}
|
|
16441
17391
|
let nSats = 0;
|
|
16442
|
-
|
|
17392
|
+
const live = vis.filter((v) => !screened.has(v.prn));
|
|
17393
|
+
const rangeNow = (v) => v.range - (v.e[0] * (x[IDX_X] - rcv[0]) + v.e[1] * (x[IDX_Y] - rcv[1]) + v.e[2] * (x[IDX_Z] - rcv[2]));
|
|
17394
|
+
const prepAmbiguity = (v) => {
|
|
16443
17395
|
const ci = clockOf(v.prn[0]);
|
|
16444
|
-
const common = v
|
|
17396
|
+
const common = rangeNow(v) + x[ci] - v.satClkM + v.tropoFixed + zwd0 * v.mw;
|
|
16445
17397
|
if (v.slip) flushArc(v.prn);
|
|
16446
17398
|
let ai = ambIdx.get(v.prn);
|
|
16447
17399
|
if (ai === void 0 || v.slip) {
|
|
@@ -16458,67 +17410,91 @@ var PppEngine = class {
|
|
|
16458
17410
|
}
|
|
16459
17411
|
ambIdx.set(v.prn, ai);
|
|
16460
17412
|
}
|
|
16461
|
-
|
|
17413
|
+
return ai;
|
|
17414
|
+
};
|
|
17415
|
+
const codeUpdate = (v) => {
|
|
17416
|
+
const ci = clockOf(v.prn[0]);
|
|
17417
|
+
const common = rangeNow(v) + x[ci] - v.satClkM + v.tropoFixed + x[IDX_ZWD] * v.mw;
|
|
17418
|
+
const sinEl = Math.max(Math.sin(v.elRad), 0.1);
|
|
17419
|
+
const h = new Array(x.length).fill(0);
|
|
17420
|
+
h[IDX_X] = -v.e[0];
|
|
17421
|
+
h[IDX_Y] = -v.e[1];
|
|
17422
|
+
h[IDX_Z] = -v.e[2];
|
|
17423
|
+
h[ci] = 1;
|
|
17424
|
+
h[IDX_ZWD] = v.mw;
|
|
17425
|
+
const innov = v.pIf - common;
|
|
17426
|
+
if (Math.abs(innov) < 1e6)
|
|
17427
|
+
ekfUpdateScalar(x, P, h, innov, (codeSigma / sinEl) ** 2, 4);
|
|
17428
|
+
};
|
|
17429
|
+
const phaseUpdate = (v, ai) => {
|
|
17430
|
+
const ci = clockOf(v.prn[0]);
|
|
16462
17431
|
const sinEl = Math.max(Math.sin(v.elRad), 0.1);
|
|
16463
|
-
const rCode = (codeSigma / sinEl) ** 2;
|
|
16464
17432
|
const rPhase = (phaseSigma / sinEl) ** 2;
|
|
16465
|
-
|
|
16466
|
-
|
|
17433
|
+
const commonPh = rangeNow(v) + x[ci] - v.satClkM + v.tropoFixed + x[IDX_ZWD] * v.mw;
|
|
17434
|
+
const innov = v.lIf - (commonPh + v.windupM + x[ai]);
|
|
17435
|
+
const reinit = (phaseRejects.get(v.prn) ?? 0) >= 3;
|
|
17436
|
+
let used = false;
|
|
17437
|
+
if (!reinit) {
|
|
17438
|
+
const h = new Array(x.length).fill(0);
|
|
16467
17439
|
h[IDX_X] = -v.e[0];
|
|
16468
17440
|
h[IDX_Y] = -v.e[1];
|
|
16469
17441
|
h[IDX_Z] = -v.e[2];
|
|
16470
17442
|
h[ci] = 1;
|
|
16471
17443
|
h[IDX_ZWD] = v.mw;
|
|
16472
|
-
|
|
16473
|
-
|
|
17444
|
+
h[ai] = 1;
|
|
17445
|
+
used = ekfUpdateScalar(x, P, h, innov, rPhase, 4);
|
|
16474
17446
|
}
|
|
16475
|
-
{
|
|
16476
|
-
|
|
16477
|
-
|
|
16478
|
-
|
|
16479
|
-
|
|
16480
|
-
|
|
16481
|
-
for (let j = 0; j < P.length; j++) {
|
|
16482
|
-
P[ai][j] = 0;
|
|
16483
|
-
P[j][ai] = 0;
|
|
16484
|
-
}
|
|
16485
|
-
P[ai][ai] = 100 * 100;
|
|
16486
|
-
} else {
|
|
16487
|
-
const h = new Array(n).fill(0);
|
|
16488
|
-
h[IDX_X] = -v.e[0];
|
|
16489
|
-
h[IDX_Y] = -v.e[1];
|
|
16490
|
-
h[IDX_Z] = -v.e[2];
|
|
16491
|
-
h[ci] = 1;
|
|
16492
|
-
h[IDX_ZWD] = v.mw;
|
|
16493
|
-
h[ai] = 1;
|
|
16494
|
-
ekfUpdateScalar(x, P, h, innov, rPhase, 4);
|
|
16495
|
-
}
|
|
16496
|
-
}
|
|
16497
|
-
{
|
|
16498
|
-
const elevDeg = v.elRad * 180 / Math.PI;
|
|
16499
|
-
const mwMean = mwState.get(v.prn)?.mean ?? 0;
|
|
16500
|
-
const s = arcSnap.get(v.prn);
|
|
16501
|
-
if (s) {
|
|
16502
|
-
s.aIF = x[ai];
|
|
16503
|
-
s.mwCyc = mwMean;
|
|
16504
|
-
s.elevSum += elevDeg;
|
|
16505
|
-
s.nEpochs++;
|
|
16506
|
-
s.endMs = epoch.timeMs;
|
|
16507
|
-
} else {
|
|
16508
|
-
arcSnap.set(v.prn, {
|
|
16509
|
-
aIF: x[ai],
|
|
16510
|
-
mwCyc: mwMean,
|
|
16511
|
-
f1: v.f1,
|
|
16512
|
-
f2: v.f2,
|
|
16513
|
-
elevSum: elevDeg,
|
|
16514
|
-
nEpochs: 1,
|
|
16515
|
-
startMs: epoch.timeMs,
|
|
16516
|
-
endMs: epoch.timeMs
|
|
16517
|
-
});
|
|
17447
|
+
if (reinit) {
|
|
17448
|
+
flushArc(v.prn);
|
|
17449
|
+
x[ai] = v.lIf - (commonPh + v.windupM);
|
|
17450
|
+
for (let j = 0; j < P.length; j++) {
|
|
17451
|
+
P[ai][j] = 0;
|
|
17452
|
+
P[j][ai] = 0;
|
|
16518
17453
|
}
|
|
17454
|
+
P[ai][ai] = 100 * 100;
|
|
17455
|
+
phaseRejects.delete(v.prn);
|
|
17456
|
+
} else if (used) phaseRejects.delete(v.prn);
|
|
17457
|
+
else phaseRejects.set(v.prn, (phaseRejects.get(v.prn) ?? 0) + 1);
|
|
17458
|
+
};
|
|
17459
|
+
const snapshot = (v, ai) => {
|
|
17460
|
+
const elevDeg = v.elRad * 180 / Math.PI;
|
|
17461
|
+
const mwMean = mwState.get(v.prn)?.mean ?? 0;
|
|
17462
|
+
const s = arcSnap.get(v.prn);
|
|
17463
|
+
if (s) {
|
|
17464
|
+
s.aIF = x[ai];
|
|
17465
|
+
s.mwCyc = mwMean;
|
|
17466
|
+
s.elevSum += elevDeg;
|
|
17467
|
+
s.nEpochs++;
|
|
17468
|
+
s.endMs = epoch.timeMs;
|
|
17469
|
+
} else {
|
|
17470
|
+
arcSnap.set(v.prn, {
|
|
17471
|
+
aIF: x[ai],
|
|
17472
|
+
mwCyc: mwMean,
|
|
17473
|
+
f1: v.f1,
|
|
17474
|
+
f2: v.f2,
|
|
17475
|
+
elevSum: elevDeg,
|
|
17476
|
+
nEpochs: 1,
|
|
17477
|
+
startMs: epoch.timeMs,
|
|
17478
|
+
endMs: epoch.timeMs
|
|
17479
|
+
});
|
|
16519
17480
|
}
|
|
16520
17481
|
lastSeen.set(v.prn, ei);
|
|
16521
17482
|
nSats++;
|
|
17483
|
+
};
|
|
17484
|
+
if (kinematic) {
|
|
17485
|
+
for (const v of live) codeUpdate(v);
|
|
17486
|
+
for (const v of live) {
|
|
17487
|
+
const ai = prepAmbiguity(v);
|
|
17488
|
+
phaseUpdate(v, ai);
|
|
17489
|
+
snapshot(v, ai);
|
|
17490
|
+
}
|
|
17491
|
+
} else {
|
|
17492
|
+
for (const v of live) {
|
|
17493
|
+
const ai = prepAmbiguity(v);
|
|
17494
|
+
codeUpdate(v);
|
|
17495
|
+
phaseUpdate(v, ai);
|
|
17496
|
+
snapshot(v, ai);
|
|
17497
|
+
}
|
|
16522
17498
|
}
|
|
16523
17499
|
let sumPhaseResSq = 0;
|
|
16524
17500
|
let nPhaseRes = 0;
|
|
@@ -16529,7 +17505,7 @@ var PppEngine = class {
|
|
|
16529
17505
|
if (ai === void 0) continue;
|
|
16530
17506
|
const sys = v.prn[0];
|
|
16531
17507
|
const ci = clockOf(sys);
|
|
16532
|
-
const commonPh = v
|
|
17508
|
+
const commonPh = rangeNow(v) + x[ci] - v.satClkM + v.tropoFixed + x[IDX_ZWD] * v.mw;
|
|
16533
17509
|
const innov = v.lIf - (commonPh + v.windupM + x[ai]);
|
|
16534
17510
|
if (Math.abs(innov) >= 0.15) continue;
|
|
16535
17511
|
const arr = bySysRes.get(sys);
|
|
@@ -16553,6 +17529,8 @@ var PppEngine = class {
|
|
|
16553
17529
|
flushArc(prn);
|
|
16554
17530
|
}
|
|
16555
17531
|
}
|
|
17532
|
+
this.tryFix(epoch.timeMs, vis);
|
|
17533
|
+
if (this.lastFix) this.fixedEpochs++;
|
|
16556
17534
|
const pos = [x[IDX_X], x[IDX_Y], x[IDX_Z]];
|
|
16557
17535
|
let enu = null;
|
|
16558
17536
|
let error3d = null;
|
|
@@ -16588,12 +17566,75 @@ var PppEngine = class {
|
|
|
16588
17566
|
nSats,
|
|
16589
17567
|
ztdWet: x[IDX_ZWD],
|
|
16590
17568
|
ztdHydrostatic: epochZhd,
|
|
16591
|
-
phaseResRms: nPhaseRes > 0 ? Math.sqrt(sumPhaseResSq / nPhaseRes) : 0
|
|
17569
|
+
phaseResRms: nPhaseRes > 0 ? Math.sqrt(sumPhaseResSq / nPhaseRes) : 0,
|
|
17570
|
+
nFixed: this.lastFix?.nFixed ?? 0,
|
|
17571
|
+
fixedPosition: this.lastFix?.position ?? null
|
|
16592
17572
|
};
|
|
16593
17573
|
series.push(result);
|
|
16594
17574
|
this.ei = ei + 1;
|
|
16595
17575
|
return result;
|
|
16596
17576
|
}
|
|
17577
|
+
/**
|
|
17578
|
+
* PPP-AR. Every `everyS`, resolve the converged ambiguities of the
|
|
17579
|
+
* satellites in view (between satellites of one constellation) and, when
|
|
17580
|
+
* the fix passes the ratio, success-rate and χ² tests, condition the
|
|
17581
|
+
* float position on it ({@link fixPppPosition}). The float filter itself
|
|
17582
|
+
* is never constrained — a wrong fix can't contaminate later epochs, and
|
|
17583
|
+
* the next attempt starts clean. Between attempts the last fix carries
|
|
17584
|
+
* over (static) or is dropped (kinematic).
|
|
17585
|
+
*/
|
|
17586
|
+
tryFix(tMs, vis) {
|
|
17587
|
+
const ar = this.opts.ar;
|
|
17588
|
+
if (!ar || !this.source.phaseBias) return;
|
|
17589
|
+
const cfg = ar === true ? {} : ar;
|
|
17590
|
+
if (tMs - this.lastArMs < (cfg.everyS ?? 120) * 1e3) {
|
|
17591
|
+
if (this.kinematic) this.lastFix = null;
|
|
17592
|
+
return;
|
|
17593
|
+
}
|
|
17594
|
+
this.lastArMs = tMs;
|
|
17595
|
+
this.lastFix = null;
|
|
17596
|
+
const { x, P, ambIdx, arcSnap, mwState } = this;
|
|
17597
|
+
const minArcMs = (cfg.minArcS ?? 600) * 1e3;
|
|
17598
|
+
const ambiguities = [];
|
|
17599
|
+
for (const v of vis) {
|
|
17600
|
+
const index = ambIdx.get(v.prn);
|
|
17601
|
+
const snap = arcSnap.get(v.prn);
|
|
17602
|
+
const mw = mwState.get(v.prn);
|
|
17603
|
+
if (index === void 0 || !snap || !mw) continue;
|
|
17604
|
+
if (tMs - snap.startMs < minArcMs || snap.nEpochs < 20) continue;
|
|
17605
|
+
ambiguities.push({
|
|
17606
|
+
prn: v.prn,
|
|
17607
|
+
index,
|
|
17608
|
+
aIF: x[index],
|
|
17609
|
+
mwCyc: mw.mean,
|
|
17610
|
+
f1: v.f1,
|
|
17611
|
+
f2: v.f2,
|
|
17612
|
+
elevDeg: v.elRad * 180 / Math.PI
|
|
17613
|
+
});
|
|
17614
|
+
}
|
|
17615
|
+
const fx = fixPppPosition(
|
|
17616
|
+
{
|
|
17617
|
+
position: [x[IDX_X], x[IDX_Y], x[IDX_Z]],
|
|
17618
|
+
covariance: P,
|
|
17619
|
+
ambiguities
|
|
17620
|
+
},
|
|
17621
|
+
NO_FCB,
|
|
17622
|
+
{
|
|
17623
|
+
ratioThreshold: cfg.ratio ?? 3,
|
|
17624
|
+
wlThreshold: cfg.wlThreshold ?? 0.15,
|
|
17625
|
+
minSuccessRate: cfg.successRate ?? 0.999,
|
|
17626
|
+
minFixed: cfg.minFixed ?? 5,
|
|
17627
|
+
maxChi2: cfg.maxChi2 ?? 20
|
|
17628
|
+
}
|
|
17629
|
+
);
|
|
17630
|
+
if (!fx.fixed) return;
|
|
17631
|
+
this.lastFix = {
|
|
17632
|
+
position: fx.position,
|
|
17633
|
+
nFixed: fx.nFixed,
|
|
17634
|
+
ratio: fx.ratio
|
|
17635
|
+
};
|
|
17636
|
+
this.firstFixMs ??= tMs;
|
|
17637
|
+
}
|
|
16597
17638
|
/** Finalise the session: capture the AR state, flush open arcs, assemble. */
|
|
16598
17639
|
solution() {
|
|
16599
17640
|
const { opts, x, P, ambIdx, arcSnap, mwState, arcs, series, truth } = this;
|
|
@@ -16626,7 +17667,12 @@ var PppEngine = class {
|
|
|
16626
17667
|
x[IDX_Y],
|
|
16627
17668
|
x[IDX_Z]
|
|
16628
17669
|
];
|
|
16629
|
-
const
|
|
17670
|
+
const geo = ecefToGeodetic(finalPos[0], finalPos[1], finalPos[2]);
|
|
17671
|
+
const llh = [
|
|
17672
|
+
geo[0] * 180 / Math.PI,
|
|
17673
|
+
geo[1] * 180 / Math.PI,
|
|
17674
|
+
geo[2]
|
|
17675
|
+
];
|
|
16630
17676
|
const finalError3d = truth ? Math.hypot(
|
|
16631
17677
|
finalPos[0] - truth[0],
|
|
16632
17678
|
finalPos[1] - truth[1],
|
|
@@ -16642,218 +17688,25 @@ var PppEngine = class {
|
|
|
16642
17688
|
convergenceSec: this.convergenceSec,
|
|
16643
17689
|
finalError3d,
|
|
16644
17690
|
arcs,
|
|
16645
|
-
finalState
|
|
17691
|
+
finalState,
|
|
17692
|
+
...opts.ar && this.source.phaseBias ? {
|
|
17693
|
+
ar: {
|
|
17694
|
+
firstFixSec: this.firstFixMs === null || !series.length ? null : (this.firstFixMs - series[0].timeMs) / 1e3,
|
|
17695
|
+
nFixedEnd: this.lastFix?.nFixed ?? 0,
|
|
17696
|
+
position: this.lastFix?.position ?? null,
|
|
17697
|
+
fixedEpochShare: series.length ? this.fixedEpochs / series.length : 0
|
|
17698
|
+
}
|
|
17699
|
+
} : {}
|
|
16646
17700
|
};
|
|
16647
17701
|
}
|
|
16648
17702
|
};
|
|
16649
17703
|
function solvePpp(epochs, sp3OrSource, opts) {
|
|
16650
|
-
const source = "satState" in sp3OrSource ? sp3OrSource : new Sp3EphemerisSource(sp3OrSource, opts.clk);
|
|
17704
|
+
const source = "satState" in sp3OrSource ? sp3OrSource : new Sp3EphemerisSource(sp3OrSource, opts.clk, opts.osb);
|
|
16651
17705
|
const eng = new PppEngine(opts, source);
|
|
16652
17706
|
for (const epoch of epochs) eng.process(epoch);
|
|
16653
17707
|
return eng.solution();
|
|
16654
17708
|
}
|
|
16655
17709
|
|
|
16656
|
-
// src/positioning/ppp-ar.ts
|
|
16657
|
-
function wlWavelength(f1, f2) {
|
|
16658
|
-
return C_LIGHT / (f1 - f2);
|
|
16659
|
-
}
|
|
16660
|
-
function nlWavelength(f1, f2) {
|
|
16661
|
-
return C_LIGHT / (f1 + f2);
|
|
16662
|
-
}
|
|
16663
|
-
function resolvePppAmbiguities(sats, Qaif, opts = {}) {
|
|
16664
|
-
const wlThreshold = opts.wlThreshold ?? 0.25;
|
|
16665
|
-
const ratioThreshold = opts.ratioThreshold ?? 3;
|
|
16666
|
-
const kept = [];
|
|
16667
|
-
const nWl = [];
|
|
16668
|
-
const rejectedWl = [];
|
|
16669
|
-
for (let i = 0; i < sats.length; i++) {
|
|
16670
|
-
const s = sats[i];
|
|
16671
|
-
const wlFloat = s.mwCyc - (s.wlBiasCyc ?? 0);
|
|
16672
|
-
const r = Math.round(wlFloat);
|
|
16673
|
-
if (Math.abs(wlFloat - r) <= wlThreshold) {
|
|
16674
|
-
kept.push(i);
|
|
16675
|
-
nWl.push(r);
|
|
16676
|
-
} else {
|
|
16677
|
-
rejectedWl.push(s.prn);
|
|
16678
|
-
}
|
|
16679
|
-
}
|
|
16680
|
-
if (kept.length < 2) {
|
|
16681
|
-
return {
|
|
16682
|
-
fixed: false,
|
|
16683
|
-
ratio: 0,
|
|
16684
|
-
refPrn: null,
|
|
16685
|
-
sats: [],
|
|
16686
|
-
rejectedWl
|
|
16687
|
-
};
|
|
16688
|
-
}
|
|
16689
|
-
const n1Float = [];
|
|
16690
|
-
const lamNl = [];
|
|
16691
|
-
for (let k = 0; k < kept.length; k++) {
|
|
16692
|
-
const s = sats[kept[k]];
|
|
16693
|
-
const lNl = nlWavelength(s.f1, s.f2);
|
|
16694
|
-
lamNl.push(lNl);
|
|
16695
|
-
const n1 = s.aIF / lNl - s.f2 / (s.f1 - s.f2) * nWl[k] - (s.nlBiasCyc ?? 0);
|
|
16696
|
-
n1Float.push(n1);
|
|
16697
|
-
}
|
|
16698
|
-
let ref = 0;
|
|
16699
|
-
for (let k = 1; k < kept.length; k++) {
|
|
16700
|
-
const e = sats[kept[k]].elevDeg ?? -1;
|
|
16701
|
-
if (e > (sats[kept[ref]].elevDeg ?? -1)) ref = k;
|
|
16702
|
-
}
|
|
16703
|
-
const m = kept.length - 1;
|
|
16704
|
-
const sd2 = new Float64Array(m);
|
|
16705
|
-
const Qsd = new Float64Array(m * m);
|
|
16706
|
-
const others = [];
|
|
16707
|
-
for (let k = 0; k < kept.length; k++) if (k !== ref) others.push(k);
|
|
16708
|
-
const n = sats.length;
|
|
16709
|
-
const qN1 = (ka, kb) => Qaif[kept[ka] * n + kept[kb]] / (lamNl[ka] * lamNl[kb]);
|
|
16710
|
-
for (let a = 0; a < m; a++) {
|
|
16711
|
-
const ka = others[a];
|
|
16712
|
-
sd2[a] = n1Float[ka] - n1Float[ref];
|
|
16713
|
-
for (let b = 0; b < m; b++) {
|
|
16714
|
-
const kb = others[b];
|
|
16715
|
-
Qsd[a * m + b] = qN1(ka, kb) - qN1(ka, ref) - qN1(ref, kb) + qN1(ref, ref);
|
|
16716
|
-
}
|
|
16717
|
-
}
|
|
16718
|
-
const res = lambdaSearch(sd2, Qsd, m, 2);
|
|
16719
|
-
const ratio = res ? Math.min(res.ratio, 999.9) : 0;
|
|
16720
|
-
const fixed = !!res && ratio >= ratioThreshold;
|
|
16721
|
-
const refN1 = Math.round(n1Float[ref]);
|
|
16722
|
-
const sdFix = res?.candidates[0];
|
|
16723
|
-
const outSats = [];
|
|
16724
|
-
for (let k = 0; k < kept.length; k++) {
|
|
16725
|
-
const s = sats[kept[k]];
|
|
16726
|
-
let n1;
|
|
16727
|
-
if (k === ref) {
|
|
16728
|
-
n1 = refN1;
|
|
16729
|
-
} else {
|
|
16730
|
-
const a = others.indexOf(k);
|
|
16731
|
-
n1 = fixed && sdFix ? refN1 + Math.round(sdFix[a]) : Math.round(n1Float[k]);
|
|
16732
|
-
}
|
|
16733
|
-
const lNl = lamNl[k];
|
|
16734
|
-
const aIF = lNl * n1 + lNl * (s.f2 / (s.f1 - s.f2)) * nWl[k];
|
|
16735
|
-
outSats.push({ prn: s.prn, nWl: nWl[k], n1, aIF });
|
|
16736
|
-
}
|
|
16737
|
-
return {
|
|
16738
|
-
fixed,
|
|
16739
|
-
ratio,
|
|
16740
|
-
refPrn: sats[kept[ref]].prn,
|
|
16741
|
-
sats: outSats,
|
|
16742
|
-
rejectedWl
|
|
16743
|
-
};
|
|
16744
|
-
}
|
|
16745
|
-
function solveSpd(A, b) {
|
|
16746
|
-
const n = b.length;
|
|
16747
|
-
const L = Array.from({ length: n }, () => new Array(n).fill(0));
|
|
16748
|
-
for (let i = 0; i < n; i++) {
|
|
16749
|
-
for (let j = 0; j <= i; j++) {
|
|
16750
|
-
let s = A[i][j];
|
|
16751
|
-
for (let k = 0; k < j; k++) s -= L[i][k] * L[j][k];
|
|
16752
|
-
if (i === j) {
|
|
16753
|
-
if (s <= 0) return null;
|
|
16754
|
-
L[i][j] = Math.sqrt(s);
|
|
16755
|
-
} else {
|
|
16756
|
-
L[i][j] = s / L[j][j];
|
|
16757
|
-
}
|
|
16758
|
-
}
|
|
16759
|
-
}
|
|
16760
|
-
const y = new Array(n).fill(0);
|
|
16761
|
-
for (let i = 0; i < n; i++) {
|
|
16762
|
-
let s = b[i];
|
|
16763
|
-
for (let k = 0; k < i; k++) s -= L[i][k] * y[k];
|
|
16764
|
-
y[i] = s / L[i][i];
|
|
16765
|
-
}
|
|
16766
|
-
const x = new Array(n).fill(0);
|
|
16767
|
-
for (let i = n - 1; i >= 0; i--) {
|
|
16768
|
-
let s = y[i];
|
|
16769
|
-
for (let k = i + 1; k < n; k++) s -= L[k][i] * x[k];
|
|
16770
|
-
x[i] = s / L[i][i];
|
|
16771
|
-
}
|
|
16772
|
-
return x;
|
|
16773
|
-
}
|
|
16774
|
-
function fixPppPosition(state, fcb, opts = {}) {
|
|
16775
|
-
const floatPos = state.position;
|
|
16776
|
-
const noFix = {
|
|
16777
|
-
fixed: false,
|
|
16778
|
-
position: floatPos,
|
|
16779
|
-
floatPosition: floatPos,
|
|
16780
|
-
shift: [0, 0, 0],
|
|
16781
|
-
nFixed: 0,
|
|
16782
|
-
ratio: 0,
|
|
16783
|
-
refPrn: null
|
|
16784
|
-
};
|
|
16785
|
-
const amb = state.ambiguities;
|
|
16786
|
-
if (amb.length < 3) return noFix;
|
|
16787
|
-
const sats = amb.map((a) => ({
|
|
16788
|
-
prn: a.prn,
|
|
16789
|
-
aIF: a.aIF,
|
|
16790
|
-
mwCyc: a.mwCyc,
|
|
16791
|
-
f1: a.f1,
|
|
16792
|
-
f2: a.f2,
|
|
16793
|
-
wlBiasCyc: fcb.satWlFcb.get(a.prn) ?? 0,
|
|
16794
|
-
nlBiasCyc: fcb.satNlFcb.get(a.prn) ?? 0,
|
|
16795
|
-
elevDeg: a.elevDeg
|
|
16796
|
-
}));
|
|
16797
|
-
const n = sats.length;
|
|
16798
|
-
const Qaif = new Float64Array(n * n);
|
|
16799
|
-
for (let i = 0; i < n; i++)
|
|
16800
|
-
for (let j = 0; j < n; j++)
|
|
16801
|
-
Qaif[i * n + j] = state.covariance[amb[i].index][amb[j].index];
|
|
16802
|
-
const res = resolvePppAmbiguities(sats, Qaif, opts);
|
|
16803
|
-
if (!res.fixed || res.refPrn === null) {
|
|
16804
|
-
return { ...noFix, ratio: res.ratio, refPrn: res.refPrn };
|
|
16805
|
-
}
|
|
16806
|
-
const idxOfPrn = new Map(amb.map((a) => [a.prn, a.index]));
|
|
16807
|
-
const floatOfPrn = new Map(amb.map((a) => [a.prn, a.aIF]));
|
|
16808
|
-
const kept = res.sats.filter((s) => idxOfPrn.has(s.prn));
|
|
16809
|
-
const refPos = kept.findIndex((s) => s.prn === res.refPrn);
|
|
16810
|
-
if (refPos < 0 || kept.length < 2) {
|
|
16811
|
-
return { ...noFix, ratio: res.ratio, refPrn: res.refPrn };
|
|
16812
|
-
}
|
|
16813
|
-
const ambIdx = kept.map((s) => idxOfPrn.get(s.prn));
|
|
16814
|
-
const aFloat = kept.map((s) => floatOfPrn.get(s.prn));
|
|
16815
|
-
const aFixed = kept.map((s) => s.aIF);
|
|
16816
|
-
const others = kept.map((_, i) => i).filter((i) => i !== refPos);
|
|
16817
|
-
const m = others.length;
|
|
16818
|
-
const P = state.covariance;
|
|
16819
|
-
const qAA = (i, j) => P[ambIdx[i]][ambIdx[j]];
|
|
16820
|
-
const qXA = (r, i) => P[r][ambIdx[i]];
|
|
16821
|
-
const Qzz = Array.from({ length: m }, () => new Array(m).fill(0));
|
|
16822
|
-
const z = new Array(m).fill(0);
|
|
16823
|
-
for (let a = 0; a < m; a++) {
|
|
16824
|
-
const ia = others[a];
|
|
16825
|
-
z[a] = aFloat[ia] - aFloat[refPos] - (aFixed[ia] - aFixed[refPos]);
|
|
16826
|
-
for (let b = 0; b < m; b++) {
|
|
16827
|
-
const ib = others[b];
|
|
16828
|
-
Qzz[a][b] = qAA(ia, ib) - qAA(ia, refPos) - qAA(refPos, ib) + qAA(refPos, refPos);
|
|
16829
|
-
}
|
|
16830
|
-
}
|
|
16831
|
-
const Qxz = [0, 1, 2].map(
|
|
16832
|
-
(r) => others.map((ia) => qXA(r, ia) - qXA(r, refPos))
|
|
16833
|
-
);
|
|
16834
|
-
const y = solveSpd(Qzz, z);
|
|
16835
|
-
if (!y) return { ...noFix, ratio: res.ratio, refPrn: res.refPrn };
|
|
16836
|
-
const shift = [0, 0, 0];
|
|
16837
|
-
for (let r = 0; r < 3; r++) {
|
|
16838
|
-
let s = 0;
|
|
16839
|
-
for (let a = 0; a < m; a++) s += Qxz[r][a] * y[a];
|
|
16840
|
-
shift[r] = -s;
|
|
16841
|
-
}
|
|
16842
|
-
return {
|
|
16843
|
-
fixed: true,
|
|
16844
|
-
position: [
|
|
16845
|
-
floatPos[0] + shift[0],
|
|
16846
|
-
floatPos[1] + shift[1],
|
|
16847
|
-
floatPos[2] + shift[2]
|
|
16848
|
-
],
|
|
16849
|
-
floatPosition: floatPos,
|
|
16850
|
-
shift,
|
|
16851
|
-
nFixed: m,
|
|
16852
|
-
ratio: res.ratio,
|
|
16853
|
-
refPrn: res.refPrn
|
|
16854
|
-
};
|
|
16855
|
-
}
|
|
16856
|
-
|
|
16857
17710
|
// src/positioning/ppp-fcb.ts
|
|
16858
17711
|
function extractWidelaneArcs(station, epochs, opts = {}) {
|
|
16859
17712
|
const slipCyc = opts.slipCyc ?? 4;
|
|
@@ -17171,7 +18024,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
17171
18024
|
let x9 = 0;
|
|
17172
18025
|
let y2 = 0;
|
|
17173
18026
|
let z2 = 0;
|
|
17174
|
-
const
|
|
18027
|
+
const clock3 = new Map(systems.map((s) => [s, 0]));
|
|
17175
18028
|
const residuals2 = {};
|
|
17176
18029
|
let iterations2 = 0;
|
|
17177
18030
|
let converged2 = false;
|
|
@@ -17191,7 +18044,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
17191
18044
|
const psr = pseudoranges.get(prn);
|
|
17192
18045
|
const eph = ephemerides.get(prn);
|
|
17193
18046
|
const sys = prn[0];
|
|
17194
|
-
const clk =
|
|
18047
|
+
const clk = clock3.get(sys);
|
|
17195
18048
|
const tTx = timeMs - psr / C_LIGHT * 1e3;
|
|
17196
18049
|
const dtsClock = satClockCorrection(eph, tTx);
|
|
17197
18050
|
const sat = computeSatPosition(eph, tTx - dtsClock * 1e3);
|
|
@@ -17283,13 +18136,13 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
17283
18136
|
y2 += dx[1];
|
|
17284
18137
|
z2 += dx[2];
|
|
17285
18138
|
for (const s of systems)
|
|
17286
|
-
|
|
18139
|
+
clock3.set(s, clock3.get(s) + dx[sysIndex.get(s)]);
|
|
17287
18140
|
if (Math.hypot(dx[0], dx[1], dx[2]) < convergenceM) {
|
|
17288
18141
|
converged2 = true;
|
|
17289
18142
|
break;
|
|
17290
18143
|
}
|
|
17291
18144
|
}
|
|
17292
|
-
return { x: x9, y: y2, z: z2, clock:
|
|
18145
|
+
return { x: x9, y: y2, z: z2, clock: clock3, residuals: residuals2, iterations: iterations2, converged: converged2 };
|
|
17293
18146
|
};
|
|
17294
18147
|
const REJECT_THRESHOLD_M = 50;
|
|
17295
18148
|
let candidates = all;
|
|
@@ -17314,7 +18167,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
17314
18167
|
candidates = remaining;
|
|
17315
18168
|
}
|
|
17316
18169
|
if (!inner) return null;
|
|
17317
|
-
const { x, y, z, clock, residuals, iterations, converged } = inner;
|
|
18170
|
+
const { x, y, z, clock: clock2, residuals, iterations, converged } = inner;
|
|
17318
18171
|
const used = [];
|
|
17319
18172
|
const azels = [];
|
|
17320
18173
|
const [rxLat, rxLon, rxHgt] = ecefToGeodetic(x, y, z);
|
|
@@ -17354,7 +18207,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
17354
18207
|
const pl = sbas ? sbasProtectionLevels(sbasRows) : null;
|
|
17355
18208
|
return {
|
|
17356
18209
|
position: [x, y, z],
|
|
17357
|
-
clockBias: Object.fromEntries(
|
|
18210
|
+
clockBias: Object.fromEntries(clock2),
|
|
17358
18211
|
usedSatellites: used,
|
|
17359
18212
|
rejectedSatellites: rejected,
|
|
17360
18213
|
residuals,
|
|
@@ -19713,6 +20566,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
19713
20566
|
SYSTEM_NAMES,
|
|
19714
20567
|
SYSTEM_ORDER,
|
|
19715
20568
|
SYS_SHORT,
|
|
20569
|
+
SatOsbTable,
|
|
19716
20570
|
SbasProcessor,
|
|
19717
20571
|
Scale,
|
|
19718
20572
|
Sp3EphemerisSource,
|
|
@@ -19895,6 +20749,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
19895
20749
|
parseNovatelRange,
|
|
19896
20750
|
parseRinexStream,
|
|
19897
20751
|
parseSbfAlmanac,
|
|
20752
|
+
parseSbfBdsCnav,
|
|
19898
20753
|
parseSbfBdsNav,
|
|
19899
20754
|
parseSbfCnav,
|
|
19900
20755
|
parseSbfGalNav,
|