Skip to content

Commit

Permalink
refactor: ♻️ combine Tle classes and improve documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
thkruz committed Jan 11, 2024
1 parent 64116c8 commit b5b506a
Show file tree
Hide file tree
Showing 17 changed files with 1,081 additions and 850 deletions.
4 changes: 2 additions & 2 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
/dist
/lib
/src/sgp4/asc
/examples/commonjs/satellite-js-migration.js
/examples/mjs/satellite-js-migration.mjs
71 changes: 71 additions & 0 deletions examples/commonjs/satellite-js-migration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
const { Satellite, Sgp4, GroundPosition, calcGmst } = require('../../lib/ootk-core');

// Sample TLE
const tle1 = '1 25544U 98067A 19156.50900463 .00003075 00000-0 59442-4 0 9992';
const tle2 = '2 25544 51.6433 59.2583 0008217 16.4489 347.6017 15.51174618173442';

// Initialize a Satellite Object
const satellite = new Satellite({
tle1,
tle2,
});

// You can still propagate a satellite using time since epoch (in minutes), but it's not recommended.
const timeSinceTleEpochMinutes = 10;
let positionAndVelocity = Sgp4.propagate(satellite.satrec, timeSinceTleEpochMinutes);

// Use a Date object instead
positionAndVelocity = satellite.eci(new Date(2024, 0, 1));
// Or use the current time
positionAndVelocity = satellite.eci();

// The position_velocity result is a key-value pair of ECI coordinates.
// These are the base results from which all other coordinates are derived.
const positionEci = positionAndVelocity.position;
const velocityEci = positionAndVelocity.velocity;

// Set the Observer at 122.03 West by 36.96 North, in DEGREES (because who likes working in radians?)
const observer = new GroundPosition({
lon: -122.0308,
lat: 36.9613422,
alt: 0.37,
});

// You can still calculate GMST if you want to, but unlike satellite.js it's not required.
const { gmst, j } = calcGmst(new Date());

// You can get ECF, Geodetic, Look Angles, and Doppler Factor.
const positionEcf = satellite.ecf();
const observerEcf = observer.ecf();
const positionGd = satellite.lla();
const lookAngles = satellite.rae(observer);
// This never worked in satellite.js, but it does now!
const dopplerFactor = satellite.dopplerFactor(observer);

// The coordinates are all stored in strongly typed key-value pairs.
// ECI and ECF are accessed by `x`, `y`, `z` properties.
const position = satellite.eci().position;
const satelliteX = position.x;
const satelliteY = position.y;
const satelliteZ = position.z;

// Look Angles may be accessed by `azimuth`, `elevation`, `range` properties.
const azimuth = lookAngles.azimuth; // Radians
const azimuthDegrees = lookAngles.azimuthDegrees; // Degrees
const elevation = lookAngles.elevation; // Radians
const elevationDegrees = lookAngles.elevationDegrees; // Degrees
const rangeSat = lookAngles.range; // Kilometers
const rangeRate = lookAngles.rangeRate; // Kilometers/Second

// Geodetic coords are accessed via `longitude`, `latitude`, `height`.
const longitude = positionGd.lon; // longitude is in degrees
const latitude = positionGd.lat; // latitude is in degrees
const height = positionGd.alt; // height is in kilometers

// Convert the degrees to radians if you want.
const longitudeRad = longitude * DEG2RAD;
const latitudeRad = latitude * DEG2RAD;

// There is no need to use the units seen in TypeScript examples.
// const longitudeRad = (longitude * DEG2RAD) as Radians;
// const latitudeRad = (latitude * DEG2RAD) as Radians;
12 changes: 0 additions & 12 deletions examples/commonjs/satellite.js

This file was deleted.

71 changes: 71 additions & 0 deletions examples/mjs/satellite-js-migration.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { calcGmst, GroundPosition, Satellite, Sgp4 } from '../../lib/ootk-core';

// Sample TLE
const tle1 = '1 25544U 98067A 19156.50900463 .00003075 00000-0 59442-4 0 9992';
const tle2 = '2 25544 51.6433 59.2583 0008217 16.4489 347.6017 15.51174618173442';

// Initialize a Satellite Object
const satellite = new Satellite({
tle1,
tle2,
});

// You can still propagate a satellite using time since epoch (in minutes), but it's not recommended.
const timeSinceTleEpochMinutes = 10;
let positionAndVelocity = Sgp4.propagate(satellite.satrec, timeSinceTleEpochMinutes);

// Use a Date object instead
positionAndVelocity = satellite.eci(new Date(2024, 0, 1));
// Or use the current time
positionAndVelocity = satellite.eci();

// The position_velocity result is a key-value pair of ECI coordinates.
// These are the base results from which all other coordinates are derived.
const positionEci = positionAndVelocity.position;
const velocityEci = positionAndVelocity.velocity;

// Set the Observer at 122.03 West by 36.96 North, in DEGREES (because who likes working in radians?)
const observer = new GroundPosition({
lon: -122.0308,
lat: 36.9613422,
alt: 0.37,
});

// You can still calculate GMST if you want to, but unlike satellite.js it's not required.
const { gmst, j } = calcGmst(new Date());

// You can get ECF, Geodetic, Look Angles, and Doppler Factor.
const positionEcf = satellite.ecf();
const observerEcf = observer.ecf();
const positionGd = satellite.lla();
const lookAngles = satellite.rae(observer);
// This never worked in satellite.js, but it does now!
const dopplerFactor = satellite.dopplerFactor(observer);

// The coordinates are all stored in strongly typed key-value pairs.
// ECI and ECF are accessed by `x`, `y`, `z` properties.
const position = satellite.eci().position;
const satelliteX = position.x;
const satelliteY = position.y;
const satelliteZ = position.z;

// Look Angles may be accessed by `azimuth`, `elevation`, `range` properties.
const azimuth = lookAngles.azimuth; // Radians
const azimuthDegrees = lookAngles.azimuthDegrees; // Degrees
const elevation = lookAngles.elevation; // Radians
const elevationDegrees = lookAngles.elevationDegrees; // Degrees
const rangeSat = lookAngles.range; // Kilometers
const rangeRate = lookAngles.rangeRate; // Kilometers/Second

// Geodetic coords are accessed via `longitude`, `latitude`, `height`.
const longitude = positionGd.lon; // longitude is in degrees
const latitude = positionGd.lat; // latitude is in degrees
const height = positionGd.alt; // height is in kilometers

// Convert the degrees to radians if you want.
const longitudeRad = longitude * DEG2RAD;
const latitudeRad = latitude * DEG2RAD;

// There is no need to use the units seen in TypeScript examples.
// const longitudeRad = (longitude * DEG2RAD) as Radians;
// const latitudeRad = (latitude * DEG2RAD) as Radians;
12 changes: 0 additions & 12 deletions examples/mjs/satellite.mjs

This file was deleted.

6 changes: 4 additions & 2 deletions examples/typescript/satellite-js-migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,10 @@ const satelliteY = position.y; // to prevent you from accidentally
const satelliteZ = position.z; // mixing Meters with Kilometers.

// Look Angles may be accessed by `azimuth`, `elevation`, `range` properties.
const azimuth = lookAngles.azimuth; // Typed as Degrees
const elevation = lookAngles.elevation; // Typed as Degrees
const azimuth = lookAngles.azimuth; // Typed as Radians
const azimuthDegress = lookAngles.azimuthDegrees; // Typed as Degrees
const elevation = lookAngles.elevation; // Typed as Radains
const elevationDegrees = lookAngles.elevationDegrees; // Typed as Degrees
const rangeSat = lookAngles.range; // Typed as Kilometers

// Geodetic coords are accessed via `longitude`, `latitude`, `height`.
Expand Down
87 changes: 87 additions & 0 deletions examples/typescript/tle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/* eslint-disable multiline-comment-style */
/* eslint-disable no-console */
/* eslint-disable @typescript-eslint/no-unused-vars */

import { Tle, TleLine1, TleLine2 } from '../../lib/ootk-core';

// Sample TLE
const tle1 = '1 25544U 98067A 19156.50900463 .00003075 00000-0 59442-4 0 9992' as TleLine1;
const tle2 = '2 25544 51.6433 59.2583 0008217 16.4489 347.6017 15.51174618173442' as TleLine2;

// Getting the inclination is as easy as passing the second line to the inclination function
const inc = Tle.inclination(tle2);

/**
* TypeScript asserts that you can't call this on a TleLine2, so you don't need
* to memorize which functions are for which line.
*
* const bstar = Tle.getBstar(tle2);
*/

const bstarGood = Tle.bstar(tle1);

// You can get all parameters from a TLE line with the parseLine1 or parseLine2 functions
const {
satNum,
classification,
intlDes,
epochYear,
epochDay,
meanMoDev1,
meanMoDev2,
bstar,
ephemerisType,
elsetNum,
checksum1,
} = Tle.parseLine1(tle1);

// You can get the most common parameters from a TLE with the parse function
const tle = Tle.parse(tle1, tle2);
// {
// satNum: 25544,
// intlDes: '98067A',
// epochYear: 19,
// epochDay: 156.50900463,
// meanMoDev1: 0.00003075,
// meanMoDev2: 0,
// bstar: 0.000059442,
// inclination: 51.6433,
// raan: 59.2583,
// eccentricity: 0.0008217,
// argOfPerigee: 16.4489,
// meanAnomaly: 347.6017,
// meanMotion: 15.51174618,
// period: 92.83287537651032
// }

// Or get everything with the parseAll function
const tleAll = Tle.parseAll(tle1, tle2);
// {
// lineNumber1: 1,
// satNum: 25544,
// satNumRaw: '25544',
// classification: 'U',
// intlDes: '98067A',
// intlDesYear: 98,
// intlDesLaunchNum: 67,
// intlDesLaunchPiece: 'A',
// epochYear: 19,
// epochYearFull: 2019,
// epochDay: 156.50900463,
// meanMoDev1: 0.00003075,
// meanMoDev2: 0,
// bstar: 0.000059442,
// ephemerisType: 0,
// elsetNum: 999,
// checksum1: 2,
// lineNumber2: 2,
// inclination: 51.6433,
// raan: 59.2583,
// eccentricity: 0.0008217,
// argOfPerigee: 16.4489,
// meanAnomaly: 347.6017,
// meanMotion: 15.51174618,
// revNum: 17344,
// checksum2: 2,
// period: 92.83287537651032
// }
57 changes: 3 additions & 54 deletions src/coordinate/FormatTle.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Satellite } from 'src/objects';
import { Satellite } from '../objects';

Check failure on line 1 in src/coordinate/FormatTle.ts

View workflow job for this annotation

GitHub Actions / build

Cannot find module './Tle' or its corresponding type declarations.
import { Tle } from './Tle';

export type StringifiedNumber = `${number}.${number}`;

Expand Down Expand Up @@ -36,7 +37,7 @@ export abstract class FormatTle {

static createTle(tleParams: TleParams): { tle1: string; tle2: string } {
const { inc, meanmo, rasc, argPe, meana, ecen, epochyr, epochday, intl } = tleParams;
const scc = FormatTle.convert6DigitToA5(tleParams.scc);
const scc = Tle.convert6DigitToA5(tleParams.scc);
const epochYrStr = epochyr.padStart(2, '0');
const epochdayStr = parseFloat(epochday).toFixed(8).padStart(12, '0');
const incStr = FormatTle.inclination(inc);
Expand Down Expand Up @@ -143,56 +144,4 @@ export abstract class FormatTle {

return `${str.substring(0, index)}${chr}${str.substring(index + 1)}`;
}

/**
* Converts a 6 digit SCC number to a 5 digit SCC alpha 5 number
*/
static convert6DigitToA5(sccNum: string): string {
// Only applies to 6 digit numbers
if (sccNum.length < 6) {
return sccNum;
}

if (RegExp(/[A-Z]/iu, 'u').test(sccNum[0])) {
return sccNum;
}

// Extract the trailing 4 digits
const rest = sccNum.slice(2, 6);

/*
* Convert the first two digit numbers into a Letter. Skip I and O as they look too similar to 1 and 0
* A=10, B=11, C=12, D=13, E=14, F=15, G=16, H=17, J=18, K=19, L=20, M=21, N=22, P=23, Q=24, R=25, S=26,
* T=27, U=28, V=29, W=30, X=31, Y=32, Z=33
*/
let first = parseInt(`${sccNum[0]}${sccNum[1]}`);
const iPlus = first >= 18 ? 1 : 0;
const tPlus = first >= 24 ? 1 : 0;

first = first + iPlus + tPlus;

return `${String.fromCharCode(first + 55)}${rest}`;
}

static convertA5to6Digit(sccNum: string): string {
if (RegExp(/[A-Z]/iu, 'u').test(sccNum[0])) {
// Extract the trailing 4 digits
const rest = sccNum.slice(1, 5);

/*
* Convert the first letter to a two digit number. Skip I and O as they look too similar to 1 and 0
* A=10, B=11, C=12, D=13, E=14, F=15, G=16, H=17, J=18, K=19, L=20, M=21, N=22, P=23, Q=24, R=25, S=26,
* T=27, U=28, V=29, W=30, X=31, Y=32, Z=33
*/
let first = sccNum[0].toUpperCase().charCodeAt(0) - 55;
const iPlus = first >= 18 ? 1 : 0;
const tPlus = first >= 24 ? 1 : 0;

first = first - iPlus - tPlus;

return `${first}${rest}`;
}

return sccNum;
}
}
Loading

0 comments on commit b5b506a

Please sign in to comment.