@neilberkman/sidereon 0.9.0 → 0.9.1
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 +91 -100
- package/package.json +1 -1
- package/pkg/sidereon.d.ts +1295 -774
- package/pkg/sidereon.js +1039 -10
- package/pkg/sidereon_bg.wasm +0 -0
- package/pkg/sidereon_bg.wasm.d.ts +822 -760
- package/pkg-node/sidereon.d.ts +461 -2
- package/pkg-node/sidereon.js +1070 -10
- package/pkg-node/sidereon_bg.wasm +0 -0
- package/pkg-node/sidereon_bg.wasm.d.ts +822 -760
package/README.md
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
# sidereon
|
|
1
|
+
# @neilberkman/sidereon
|
|
2
2
|
|
|
3
|
-
GNSS and astrodynamics
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
(Vallado, Skyfield, IGS, IERS).
|
|
3
|
+
GNSS and astrodynamics in the browser and in Node: propagate satellites, predict
|
|
4
|
+
passes, solve precise positions (SPP / RTK / PPP), and convert between coordinate
|
|
5
|
+
frames and time scales. This is the JavaScript and TypeScript interface to the
|
|
6
|
+
sidereon engine.
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
The engine is written in Rust and compiled to WebAssembly, so a browser tab or a
|
|
9
|
+
Node process gets the same numbers the native builds produce, with no server
|
|
10
|
+
round-trip and no native add-on to install. Results are reference-validated: the
|
|
11
|
+
SGP4 propagator is a bit-exact port of Vallado's reference implementation, frames
|
|
12
|
+
and time are checked against Skyfield and IERS, and the positioning stack is
|
|
13
|
+
checked against IGS products.
|
|
13
14
|
|
|
14
15
|
## Install
|
|
15
16
|
|
|
@@ -17,145 +18,135 @@ server round-trip and no native add-on to install.
|
|
|
17
18
|
npm install @neilberkman/sidereon
|
|
18
19
|
```
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
points and they init differently:
|
|
21
|
+
The package is dual ESM/CJS and ships prebuilt wasm with bundled TypeScript
|
|
22
|
+
declarations. The two entry points initialize differently:
|
|
23
23
|
|
|
24
24
|
- **Browser / bundler (ESM):** import the default `init`, `await` it once, then
|
|
25
25
|
call the API. `init()` fetches the `.wasm` for you.
|
|
26
26
|
- **Node (CommonJS):** `require(...)` loads and initializes the wasm at require
|
|
27
|
-
time
|
|
27
|
+
time, so there is no init step and everything is ready synchronously.
|
|
28
28
|
|
|
29
|
-
##
|
|
29
|
+
## Example: propagate a TLE
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
Parse a two-line element set, run SGP4, and take look angles (azimuth, elevation,
|
|
32
|
+
range) from a ground station. No data files, no setup.
|
|
33
33
|
|
|
34
34
|
```js
|
|
35
35
|
import init, { Tle, GroundStation } from "@neilberkman/sidereon";
|
|
36
36
|
|
|
37
|
-
await init();
|
|
37
|
+
await init();
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"
|
|
42
|
-
"2 25544 51.6322 248.9966 0004278 238.4942 121.5629 15.49454046573359",
|
|
39
|
+
const tle = new Tle(
|
|
40
|
+
"1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 9009",
|
|
41
|
+
"2 25544 51.6400 208.8657 0002644 250.3037 109.7782 15.49560812999990",
|
|
43
42
|
);
|
|
43
|
+
const station = new GroundStation(51.5, -0.1, 10.0);
|
|
44
44
|
|
|
45
|
-
//
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const us = (ms) => BigInt(ms) * 1000n;
|
|
50
|
-
const now = Date.now();
|
|
51
|
-
|
|
52
|
-
// Every pass above 10° over the next 24 hours.
|
|
53
|
-
const passes = iss.findPasses(berkeley, us(now), us(now + 24 * 3600 * 1000), 10.0);
|
|
54
|
-
|
|
55
|
-
const at = (uus) => new Date(Number(uus / 1000n)).toISOString().slice(11, 16);
|
|
56
|
-
for (const p of passes) {
|
|
57
|
-
console.log(`${at(p.aosUnixUs)} UTC · ${(p.durationS / 60).toFixed(1)} min · peak ${p.maxElevationDeg.toFixed(0)}°`);
|
|
58
|
-
}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
```
|
|
62
|
-
08:30 UTC · 6.8 min · peak 88°
|
|
63
|
-
10:09 UTC · 4.3 min · peak 16°
|
|
64
|
-
13:25 UTC · 3.2 min · peak 13°
|
|
65
|
-
15:01 UTC · 6.6 min · peak 56°
|
|
66
|
-
16:39 UTC · 3.5 min · peak 14°
|
|
45
|
+
// Epochs are unix microseconds as BigInt64Array.
|
|
46
|
+
const t = BigInt(Date.UTC(2024, 0, 1, 12)) * 1000n;
|
|
47
|
+
const look = tle.lookAngles(station, new BigInt64Array([t]));
|
|
48
|
+
console.log(look.azimuthDeg[0], look.elevationDeg[0], look.rangeKm[0]);
|
|
67
49
|
```
|
|
68
50
|
|
|
69
51
|
`Tle` also gives you `propagate(epochs)` (TEME position/velocity over a
|
|
70
|
-
`BigInt64Array` of unix-microsecond epochs) and `
|
|
71
|
-
|
|
52
|
+
`BigInt64Array` of unix-microsecond epochs) and `findPasses(station, start, end,
|
|
53
|
+
minElevationDeg)` for visibility windows.
|
|
72
54
|
|
|
73
55
|
### Node (CommonJS)
|
|
74
56
|
|
|
75
|
-
`require` resolves to the Node build, which
|
|
76
|
-
init call, everything is ready synchronously:
|
|
57
|
+
`require` resolves to the Node build, which initializes the wasm at require time:
|
|
77
58
|
|
|
78
59
|
```js
|
|
79
60
|
const { Tle, GroundStation } = require("@neilberkman/sidereon");
|
|
80
61
|
|
|
81
|
-
const
|
|
82
|
-
const
|
|
62
|
+
const tle = new Tle(line1, line2);
|
|
63
|
+
const look = tle.lookAngles(new GroundStation(51.5, -0.1, 10.0), epochs);
|
|
83
64
|
```
|
|
84
65
|
|
|
85
|
-
|
|
86
|
-
needs the wasm bytes there — `await init({ module_or_path: await readFile(new
|
|
87
|
-
URL("...sidereon_bg.wasm", import.meta.url)) })`. If you're not sure, `require`
|
|
88
|
-
is the simplest path in Node.)
|
|
66
|
+
## Example: precise positioning
|
|
89
67
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
The positioning engine is the other half of the library: load a precise
|
|
93
|
-
ephemeris, hand it pseudoranges, and get a least-squares fix back.
|
|
68
|
+
Load a precise SP3 ephemeris, hand it pseudoranges, and get a least-squares fix
|
|
69
|
+
back.
|
|
94
70
|
|
|
95
71
|
```js
|
|
96
|
-
import { loadSp3 } from "@neilberkman/sidereon";
|
|
97
|
-
|
|
72
|
+
import init, { loadSp3 } from "@neilberkman/sidereon";
|
|
73
|
+
|
|
74
|
+
await init();
|
|
98
75
|
|
|
99
|
-
|
|
76
|
+
// SP3-c precise orbits, as bytes (read from a file, fetch, or string).
|
|
77
|
+
const sp3 = loadSp3(new TextEncoder().encode(sp3Text));
|
|
100
78
|
|
|
101
|
-
|
|
79
|
+
// GPS L1 pseudoranges (m) for the satellites in view at the epoch.
|
|
80
|
+
const solution = sp3.solveSpp({
|
|
102
81
|
observations: [
|
|
103
|
-
{ satelliteId: "
|
|
104
|
-
{ satelliteId: "
|
|
105
|
-
|
|
82
|
+
{ satelliteId: "G08", pseudorangeM: 23825519.8 },
|
|
83
|
+
{ satelliteId: "G10", pseudorangeM: 22717690.1 },
|
|
84
|
+
{ satelliteId: "G16", pseudorangeM: 20478653.4 },
|
|
85
|
+
{ satelliteId: "G18", pseudorangeM: 21768335.2 },
|
|
86
|
+
{ satelliteId: "G20", pseudorangeM: 21248327.7 },
|
|
87
|
+
{ satelliteId: "G21", pseudorangeM: 20808709.8 },
|
|
106
88
|
],
|
|
107
|
-
tRxJ2000S:
|
|
108
|
-
tRxSecondOfDayS:
|
|
109
|
-
dayOfYear: 176,
|
|
110
|
-
|
|
89
|
+
tRxJ2000S: 646272000.0,
|
|
90
|
+
tRxSecondOfDayS: 43200.0,
|
|
91
|
+
dayOfYear: 176.5,
|
|
92
|
+
initialGuess: [4.5e6, 0.5e6, 4.5e6, 0],
|
|
93
|
+
corrections: { ionosphere: false, troposphere: false },
|
|
111
94
|
withGeodetic: true,
|
|
112
95
|
});
|
|
113
96
|
|
|
114
|
-
console.log(
|
|
115
|
-
console.log(
|
|
116
|
-
console.log(fix.usedSats); // satellites that contributed
|
|
97
|
+
console.log(solution.positionM); // ECEF m ~ [4484128, 550582, 4487561]
|
|
98
|
+
console.log(solution.rxClockS); // receiver clock bias, seconds
|
|
117
99
|
```
|
|
118
100
|
|
|
119
101
|
`solveRtkFloat` / `solveRtkFixed` and `solvePppFloat` / `solvePppFixed` follow
|
|
120
|
-
the same shape
|
|
102
|
+
the same shape: an options object in, a result object with `Float64Array`
|
|
121
103
|
positions and scalar attributes out.
|
|
122
104
|
|
|
123
|
-
##
|
|
124
|
-
|
|
125
|
-
The wasm surface
|
|
126
|
-
|
|
127
|
-
- **
|
|
128
|
-
|
|
129
|
-
- **
|
|
130
|
-
|
|
131
|
-
- **
|
|
132
|
-
|
|
133
|
-
|
|
105
|
+
## Capabilities
|
|
106
|
+
|
|
107
|
+
The wasm surface mirrors the full breadth of the engine:
|
|
108
|
+
|
|
109
|
+
- **Orbit propagation:** SGP4 from TLE and OMM, numerical propagation, batch
|
|
110
|
+
constellation propagation, pass prediction, look angles, coverage.
|
|
111
|
+
- **GNSS positioning:** SPP, RTK (float/fixed), PPP (float/fixed), DGNSS, RAIM/FDE,
|
|
112
|
+
DOP, velocity.
|
|
113
|
+
- **Ephemeris and time:** broadcast ephemeris and SP3 (load/interpolate/merge),
|
|
114
|
+
JPL SPK (DAF/.bsp) kernels, scale-aware time (`Instant` with GMST/GAST and
|
|
115
|
+
resolved TT/UT1/TDB), Earth orientation parameters.
|
|
116
|
+
- **Geometry and events:** reference frames (TEME, GCRS, ITRS, geodetic, ECEF),
|
|
117
|
+
look angles, eclipse and shadow geometry, conjunction screening with collision
|
|
118
|
+
probability, initial orbit determination, orbital elements.
|
|
119
|
+
- **Atmosphere:** Klobuchar and NeQuick-G ionosphere, IONEX slant delay,
|
|
120
|
+
troposphere models.
|
|
121
|
+
- **RF link budget:** free-space path loss, EIRP, C/N0, antenna gain.
|
|
122
|
+
- **Format parsing and serialization:** TLE/OMM, CCSDS, RINEX, CRINEX (Hatanaka),
|
|
123
|
+
SP3, IONEX, ANTEX, RTCM.
|
|
134
124
|
|
|
135
125
|
The binding adds no modeling of its own: every result is exactly what the engine
|
|
136
|
-
computes. Failures surface as the JS exception you
|
|
137
|
-
rejections
|
|
138
|
-
for malformed input
|
|
139
|
-
live in the bundled TypeScript declarations (`sidereon.d.ts`),
|
|
140
|
-
plain-object request shapes in `@neilberkman/sidereon/types`.
|
|
126
|
+
computes. Failures surface as the JS exception you would expect (`Error` for
|
|
127
|
+
engine rejections such as parse failures, non-converging solves, and SGP4 error
|
|
128
|
+
codes; `TypeError` for malformed input; `RangeError` for out-of-domain numbers).
|
|
129
|
+
Full signatures live in the bundled TypeScript declarations (`sidereon.d.ts`),
|
|
130
|
+
with the plain-object request shapes in `@neilberkman/sidereon/types`.
|
|
141
131
|
|
|
142
132
|
A few conventions worth knowing: positions and state arrays cross as
|
|
143
133
|
`Float64Array` (multi-epoch arrays are flat row-major, `3 * epochCount`); SGP4
|
|
144
134
|
epoch grids are `BigInt64Array` of unix microseconds; SP3 query epochs are plain
|
|
145
135
|
numbers in seconds since J2000.
|
|
146
136
|
|
|
147
|
-
##
|
|
137
|
+
## Live demo
|
|
138
|
+
|
|
139
|
+
The interactive demo at [sidereon.dev](https://sidereon.dev) runs on this exact
|
|
140
|
+
package: every computation happens client-side in your browser via this wasm
|
|
141
|
+
build.
|
|
148
142
|
|
|
149
|
-
|
|
150
|
-
**Python**, **C**, **Elixir**, and **WebAssembly** — same numbers everywhere.
|
|
151
|
-
See the live demo and docs at [sidereon.dev](https://sidereon.dev).
|
|
143
|
+
## Links
|
|
152
144
|
|
|
153
|
-
|
|
145
|
+
- **Engine and core repo:** https://github.com/neilberkman/sidereon
|
|
146
|
+
- **Live demo:** https://sidereon.dev
|
|
147
|
+
- **Sibling interfaces:** sidereon-python (PyPI), sidereon-c, sidereon-ex (Hex).
|
|
148
|
+
One validated engine, the same numbers in every language.
|
|
154
149
|
|
|
155
|
-
|
|
156
|
-
bit-exact to it. Frames and time are checked against Skyfield and IERS; the
|
|
157
|
-
positioning stack is checked against IGS products. The published package ships
|
|
158
|
-
the prebuilt wasm, so there's nothing to compile to use it.
|
|
150
|
+
## License
|
|
159
151
|
|
|
160
|
-
|
|
161
|
-
build` for the `web` and `nodejs` targets). Tests: `npm test`.*
|
|
152
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neilberkman/sidereon",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "WebAssembly / JavaScript interface over the sidereon GNSS + astrodynamics engine: SP3 loading and multi-product merge, SPP / RTK (float + fixed) / PPP (float + fixed) positioning, IONEX slant delay, SGP4 and numerical orbit propagation, RINEX observation/navigation/clock parsing, CRINEX (Hatanaka) decoding, observable-domain math (carrier combinations, cycle slips, Hatch smoothing, weighting, velocity, GPS C/A signal), and the astro domain (scale-tagged time, frame transforms, Sun/Moon ephemerides, eclipse / body angles, DOP, passes / visibility, conjunction + collision probability, CDM / OMM / ANTEX parsing, RF link budget)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|