@saber-usa/node-common 1.7.36 → 1.7.38

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.
Files changed (3) hide show
  1. package/package.json +8 -7
  2. package/src/astro.js +54 -18
  3. package/src/udl.js +28 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saber-usa/node-common",
3
- "version": "1.7.36",
3
+ "version": "1.7.38",
4
4
  "description": "Common node functions for Saber",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -23,13 +23,13 @@
23
23
  "author": "Saber USA",
24
24
  "license": "ISC",
25
25
  "dependencies": {
26
- "@aws-sdk/client-s3": "^3.1092.0",
26
+ "@aws-sdk/client-s3": "^3.1119.0",
27
27
  "date-fns": "^4.4.0",
28
28
  "lodash": "4.18.1",
29
29
  "mathjs": "^15.2.0",
30
30
  "pious-squid": "^2.3.0",
31
31
  "plotly": "^1.0.6",
32
- "satellite.js": "^7.0.1",
32
+ "satellite.js": "^7.1.0",
33
33
  "solar-calculator": "^0.3.0",
34
34
  "three": "^0.185.1",
35
35
  "winston": "3.19.0"
@@ -41,16 +41,17 @@
41
41
  "@jest/globals": "^30.4.1",
42
42
  "@sonar/scan": "^5.0.0",
43
43
  "cross-env": "^10.1.0",
44
- "eslint": "^10.7.0",
45
- "eslint-plugin-jest": "^29.15.5",
46
- "globals": "^17.7.0",
44
+ "eslint": "^10.9.1",
45
+ "eslint-plugin-jest": "^29.16.2",
46
+ "globals": "^17.11.0",
47
47
  "jest": "^30.4.2",
48
48
  "jest-diff": "^30.4.1",
49
49
  "nodemon": "3.1.14"
50
50
  },
51
51
  "overrides": {
52
52
  "braces": "3.0.3",
53
- "brace-expansion": "2.1.2",
53
+ "brace-expansion": "2.1.4",
54
+ "js-yaml": "3.15.2",
54
55
  "lodash": "4.18.1"
55
56
  }
56
57
  }
package/src/astro.js CHANGED
@@ -40,6 +40,7 @@ import {DEG2RAD,
40
40
  REGIMES,
41
41
  GRAV_CONST,
42
42
  EARTH_MASS,
43
+ MU,
43
44
  WGS72_EARTH_EQUATORIAL_RADIUS_KM,
44
45
  WGS84_EARTH_EQUATORIAL_RADIUS_KM,
45
46
  MILLIS_PER_DAY,
@@ -49,6 +50,7 @@ import TLEValidator from "./tle/TLEValidator.js";
49
50
  import MultiLineTLEValidator from "./tle/MultiLineTLEValidator.js";
50
51
  import {TLE_ERRORS} from "./tle/tleErrors.js";
51
52
  import {TleParseUtils} from "./tle/TleParseUtils.js";
53
+ import {OrbitUtils} from "./OrbitUtils.js";
52
54
 
53
55
  // Solar Terminator
54
56
  // Returns sun latitude and longitude as -180/180
@@ -310,8 +312,34 @@ const getLonAndDrift = (line1, line2, datetime) => {
310
312
  };
311
313
 
312
314
  /**
313
- * Given eccentricity, inclination, meanmotion, and period
314
- * Calculates & returns type of orbit to include LEO, MEO, HEO, GEO Drifter, GEO Inclined,GEO Stationary, and undetermined if applicable
315
+ * Orbital period in minutes from semi-major axis and gravitational parameter.
316
+ * @param {number} aKm Semi-major axis (km)
317
+ * @param {number} muKm3s2 Standard gravitational parameter (km³/s²)
318
+ * @return {number|null} Period in minutes, or null if a ≤ 0
319
+ */
320
+ const orbitalPeriodMinutes = (aKm, muKm3s2) => {
321
+ const periodSec = OrbitUtils.getPeriod(aKm, muKm3s2);
322
+ return periodSec === null ? null : periodSec / 60;
323
+ };
324
+
325
+ /**
326
+ * Mean motion in revolutions per day from semi-major axis and gravitational parameter.
327
+ * @param {number} aKm Semi-major axis (km)
328
+ * @param {number} muKm3s2 Standard gravitational parameter (km³/s²)
329
+ * @return {number} Mean motion in rev/day
330
+ */
331
+ const orbitalMeanMotionRevPerDay = (aKm, muKm3s2) => {
332
+ const nRadS = OrbitUtils.getMeanMotion(aKm, muKm3s2);
333
+ return nRadS * 86400 / (2 * Math.PI);
334
+ };
335
+
336
+ /**
337
+ * Classify orbit regime using JCO v1.0.0 primary period/eccentricity cuts
338
+ * (Orbit_Class_Definitions_v1.0.0_11Jun2024.csv). Evaluation order matters:
339
+ * HEO first, then GEO family (1300–1800 min), MEO, LEO, else Undetermined.
340
+ *
341
+ * Documentation available at: https://unifieddatalibrary.com/scs/download?id=/CommunityData/JCO_DOK/JCO_JSON_Requirements/Orbit_Class_Definitions_v1.0.0_11Jun2024.xlsx
342
+ *
315
343
  * @param {Object} orbit Object with keys eccentricity, inclination (deg), meanmotion (rev/day) and period (min)
316
344
  * @return {number} the regime index
317
345
  */
@@ -320,34 +348,43 @@ const calcRegime = (orbit) => {
320
348
  return REGIMES.Undetermined;
321
349
  }
322
350
 
323
- const {eccentricity, inclination, meanmotion, period}
351
+ const {eccentricity: e, inclination: i, meanmotion: n, period: T}
324
352
  = lowerCaseObjectKeys(orbit);
325
353
 
326
- if (!isDefined(meanmotion) && (!isDefined(period) || !isDefined(eccentricity))) {
354
+ if (!isDefined(e)) {
327
355
  return REGIMES.Undetermined;
328
356
  }
329
357
 
330
- if (meanmotion >= 0.99 && meanmotion <= 1.01 && inclination <= 0.01) {
331
- return REGIMES.GeoStationary;
358
+ if (e >= 0.25) {
359
+ return REGIMES.Heo;
332
360
  }
333
361
 
334
- if (meanmotion >= 0.99 && meanmotion <= 1.01 && inclination > 0.01) {
335
- return REGIMES.GeoInclined;
362
+ if (!isDefined(T) || T <= 0) {
363
+ return REGIMES.Undetermined;
336
364
  }
337
365
 
338
- if (meanmotion >= 0.94 && meanmotion <= 1.06) {
366
+ if (T > 1300 && T < 1800) {
367
+ if (!isDefined(n) || !isDefined(i)) {
368
+ return REGIMES.Undetermined;
369
+ }
370
+ if (n >= 0.99 && n <= 1.01 && i <= 0.01) {
371
+ return REGIMES.GeoStationary;
372
+ }
373
+ if (n >= 0.99 && n <= 1.01 && i > 0.01) {
374
+ return REGIMES.GeoInclined;
375
+ }
339
376
  return REGIMES.GeoDrifter;
340
377
  }
341
378
 
342
- if (period >= 600 && period <= 800 && eccentricity < 0.25) {
379
+ if (T > 600 && T < 900) {
343
380
  return REGIMES.Meo;
344
381
  }
345
382
 
346
- if (meanmotion > 11.25 && eccentricity < 0.25) {
383
+ if (T <= 225) {
347
384
  return REGIMES.Leo;
348
385
  }
349
386
 
350
- return eccentricity > 0.25 ? REGIMES.Heo : REGIMES.Undetermined;
387
+ return REGIMES.Undetermined;
351
388
  };
352
389
 
353
390
  /**
@@ -1748,11 +1785,9 @@ const cartesianToElsetElements = (pv, epoch) => {
1748
1785
  ArgOfPerigee: kepl.w,
1749
1786
  };
1750
1787
 
1751
- // Mean motion in radians per second
1752
- const mu = 3.986004418e14; // (m^3)/(s^2) WGS-84 Earth Mu
1753
- const meanMotion = Math.sqrt(mu/Math.pow((elset.SemiMajorAxis*1000), 3));
1754
-
1755
- elset.MeanMotion = meanMotion / (2*Math.PI) * 60 * 60 * 24; // rads/s to revs per day
1788
+ const muKm3s2 = MU / 1e9;
1789
+ elset.MeanMotion = orbitalMeanMotionRevPerDay(elset.SemiMajorAxis, muKm3s2);
1790
+ elset.Period = orbitalPeriodMinutes(elset.SemiMajorAxis, muKm3s2);
1756
1791
 
1757
1792
  const trueAnomaly = kepl.f;
1758
1793
 
@@ -1763,7 +1798,6 @@ const cartesianToElsetElements = (pv, epoch) => {
1763
1798
  // Compute Mean Anomaly from Eccentric Anomaly and Eccentricity
1764
1799
  elset.MeanAnomaly = (E - (elset.Eccentricity)*Math.sin(E)) * RAD2DEG;
1765
1800
 
1766
- elset.Period = 2*Math.PI/meanMotion / 60; // period in minutes
1767
1801
  elset.Apogee = elset.SemiMajorAxis * (1 + elset.Eccentricity); // km
1768
1802
  elset.Perigee = elset.SemiMajorAxis * (1 - elset.Eccentricity); // km
1769
1803
 
@@ -3590,6 +3624,8 @@ export {
3590
3624
  } from "satellite.js";
3591
3625
  export {
3592
3626
  calcRegime,
3627
+ orbitalPeriodMinutes,
3628
+ orbitalMeanMotionRevPerDay,
3593
3629
  altToRegime,
3594
3630
  cartesianToRIC,
3595
3631
  angleBetween3DCoords,
package/src/udl.js CHANGED
@@ -5,11 +5,14 @@ import {
5
5
  getElsetUdlFromTle,
6
6
  getLonAndDrift,
7
7
  getRaanPrecession,
8
+ orbitalMeanMotionRevPerDay,
9
+ orbitalPeriodMinutes,
8
10
  raDecToAzEl,
9
11
  azElToRaDec,
10
12
  raDecToGeodetic,
11
13
  estimateSlantRange,
12
14
  } from "./astro.js";
15
+ import {REGIMES, MU} from "./constants.js";
13
16
  import {lowerCaseObjectKeys, jsonArrayOrNull} from "./transform.js";
14
17
  import {isDefined} from "./utils.js";
15
18
  import _ from "lodash";
@@ -327,6 +330,28 @@ const getSVSatno = (udlRow) => {
327
330
  return null;
328
331
  };
329
332
 
333
+ const computeStateRegimeFromKeplerians = (keplerians) => {
334
+ const {a, e, i} = keplerians;
335
+ if (!isDefined(a) || a <= 0 || !isDefined(e) || e >= 1) {
336
+ return REGIMES.Undetermined;
337
+ }
338
+
339
+ const muKm3s2 = MU / 1e9;
340
+ const period = orbitalPeriodMinutes(a, muKm3s2);
341
+ const meanmotion = orbitalMeanMotionRevPerDay(a, muKm3s2);
342
+
343
+ if (period === null) {
344
+ return REGIMES.Undetermined;
345
+ }
346
+
347
+ return calcRegime({
348
+ eccentricity: e,
349
+ inclination: i,
350
+ meanmotion,
351
+ period,
352
+ });
353
+ };
354
+
330
355
  const udlToNpsState = (udlRow) => {
331
356
  const Xpos = _.get(udlRow, "xpos", null); // kilometers
332
357
  const Ypos = _.get(udlRow, "ypos", null);
@@ -351,6 +376,8 @@ const udlToNpsState = (udlRow) => {
351
376
  keplerians = cartesianToKeplerian(pos, vel);
352
377
  }
353
378
 
379
+ const regime = computeStateRegimeFromKeplerians(keplerians);
380
+
354
381
  const npsState = lowerCaseObjectKeys({
355
382
  satno: getSVSatno(udlRow),
356
383
  Epoch: fixDate(_.get(udlRow, "epoch", null)),
@@ -388,7 +415,7 @@ const udlToNpsState = (udlRow) => {
388
415
  Longitude: null,
389
416
  LonDriftDegreesPerDay: null,
390
417
  RaanPrecessionDegreesPerDay: null,
391
- Regime: 1,
418
+ Regime: regime,
392
419
  });
393
420
  return npsState;
394
421
  };