Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added function json2satrec in io.js #122

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
1 change: 1 addition & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ export const j3 = -0.00000253881;
export const j4 = -0.00000165597;
export const j3oj2 = j3 / j2;
export const x2o3 = 2.0 / 3.0;
export const xpdotp = 1440.0 / (2.0 * pi); // 229.1831180523293;
8 changes: 7 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as constants from './constants';

import { jday, invjday } from './ext';
import twoline2satrec from './io';
import { twoline2satrec, json2satrec} from './io';
import { propagate, sgp4, gstime } from './propagation';

import dopplerFactor from './dopplerFactor';
Expand All @@ -20,13 +20,16 @@ import {
ecfToLookAngles,
} from './transforms';

import { sunPos } from './sun';

export {
constants,

// Propagation
propagate,
sgp4,
twoline2satrec,
json2satrec,

gstime,
jday,
Expand All @@ -46,4 +49,7 @@ export {
eciToEcf,
ecfToEci,
ecfToLookAngles,

// Sun Position
sunPos,
};
3 changes: 2 additions & 1 deletion src/indexUmd.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as constants from './constants';

import { jday, invjday } from './ext';
import twoline2satrec from './io';
import { twoline2satrec, json2satrec} from './io';
import { propagate, sgp4, gstime } from './propagation';

import dopplerFactor from './dopplerFactor';
Expand All @@ -27,6 +27,7 @@ export default {
propagate,
sgp4,
twoline2satrec,
json2satrec,

gstime,
jday,
Expand Down
97 changes: 93 additions & 4 deletions src/io.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { pi, deg2rad } from './constants';
import { deg2rad, xpdotp } from './constants';

import { jday, days2mdhms } from './ext';

import sgp4init from './propagation/sgp4init';

/* -----------------------------------------------------------------------------
*
* function twoline2rv
* function twoline2satrec
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why you are updating the name? Did you update the comments above too?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because classically, rv stands for satellite state vector: [rx, ry, rz, vx, vy, vz]. This represents the position and velocity in the x,y and z directions. But this function actually returns a satrec object.

This is not the same as a satellite state vector. A satrec object is a dictionary containing all the sgp4 satellite information [sgp4io.cpp].

I have not modified any other comments above. I figured that the old way on naming the function was not in-line with its modern interpretation of the term rv and satrec.

*
* this function converts the two line element set character string data to
* variables and initializes the sgp4 variables. several intermediate varaibles
Expand Down Expand Up @@ -59,9 +59,8 @@ import sgp4init from './propagation/sgp4init';
* to the algorithm. If you want to turn some of these off and go
* back into "afspc" mode, then set `afspc_mode` to `True`.
*/
export default function twoline2satrec(longstr1, longstr2) {
export function twoline2satrec(longstr1, longstr2) {
const opsmode = 'i';
const xpdotp = 1440.0 / (2.0 * pi); // 229.1831180523293;
let year = 0;

const satrec = {};
Expand Down Expand Up @@ -146,3 +145,93 @@ export default function twoline2satrec(longstr1, longstr2) {

return satrec;
}

/* -----------------------------------------------------------------------------
*
* function json2satrec
*
* this function converts the OMM json data to variables and initializes the sgp4
* variables. several intermediate varaibles and quantities are determined. note
* that the result is a structure so multiple satellites can be processed
* simultaneously without having to reinitialize. the verification mode is an
* important option that permits quick checks of any changes to the underlying
* technical theory. this option works using a modified tle file in which the
* start, stop, and delta time values are included at the end of the second line
* of data. this only works with the verification mode. the catalog mode simply
* propagates from -1440 to 1440 min from epoch and is useful when performing
* entire catalog runs.
*
* author : Hariharan Vitaladevuni 18 Aug 2023
* Theodore Kruczek 19 Aug 2023
*
* inputs :
* jsonobj - OMM json data
* opsmode - mode of operation afspc or improved 'a', 'i'. Default: 'i'.
*
* outputs :
* satrec - structure containing all the sgp4 satellite information
*
* coupling :
* days2mdhms - conversion of days to month, day, hour, minute, second
* jday - convert day month year hour minute second into julian date
* sgp4init - initialize the sgp4 variables
*
* warning : the epoch date in OMM format is more accurate than TLE format!
* this will result in extremely close, but different
* position/velocity values. Depending on your use case, it may
* be better to use twoline2satrec, but for the average user this
* will provide comparable results.
*
* references :
* https://celestrak.org/NORAD/documentation/gp-data-formats.php
--------------------------------------------------------------------------- */
export function json2satrec(jsonobj, opsmode = 'i') {
const satrec = {};
satrec.error = 0;

satrec.satnum = jsonobj.NORAD_CAT_ID.toString().padStart(5, '0');

const epoch = new Date(jsonobj.EPOCH + 'Z');
const year = epoch.getUTCFullYear();

satrec.epochyr = Number(year.toString().slice(-2));
satrec.epochdays =
(epoch - new Date(Date.UTC(year, 0, 1, 0, 0, 0))) / (86400 * 1000) + 1;

satrec.ndot = jsonobj.MEAN_MOTION_DOT;
satrec.nddot = jsonobj.MEAN_MOTION_DDOT;
satrec.bstar = jsonobj.BSTAR;

satrec.inclo = jsonobj.INCLINATION * deg2rad;
satrec.nodeo = jsonobj.RA_OF_ASC_NODE * deg2rad;
satrec.ecco = jsonobj.ECCENTRICITY;
satrec.argpo = jsonobj.ARG_OF_PERICENTER * deg2rad;
satrec.mo = jsonobj.MEAN_ANOMALY * deg2rad;
satrec.no = jsonobj.MEAN_MOTION / xpdotp;

// ----------------------------------------------------------------
// find sgp4epoch time of element set
// remember that sgp4 uses units of days from 0 jan 1950 (sgp4epoch)
// and minutes from the epoch (time)
// ----------------------------------------------------------------
const mdhmsResult = days2mdhms(year, satrec.epochdays);

const { mon, day, hr, minute, sec } = mdhmsResult;
satrec.jdsatepoch = jday(year, mon, day, hr, minute, sec);

// ---------------- initialize the orbit at sgp4epoch -------------------
sgp4init(satrec, {
opsmode,
satn: satrec.satnum,
epoch: satrec.jdsatepoch - 2433281.5,
xbstar: satrec.bstar,
xecco: satrec.ecco,
xargpo: satrec.argpo,
xinclo: satrec.inclo,
xmo: satrec.mo,
xno: satrec.no,
xnodeo: satrec.nodeo,
});

return satrec;
}
145 changes: 145 additions & 0 deletions src/sun.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import { deg2rad, twoPi } from './constants';

////////////////////////////////////////////////////////////////////////////////////
/* Line by Line MATLAB-to-Javascript conversion of "sun.mat" from Vallado package */
////////////////////////////////////////////////////////////////////////////////////
/* -----------------------------------------------------------------------------
*
* function sunPos
*
* this function calculates the geocentric equatorial position vector
* the sun given the julian date. this is the low precision formula and
* is valid for years from 1950 to 2050. accuaracy of apparent coordinates
* is 0.01 degrees. notice many of the calculations are performed in
* degrees, and are not changed until later. this is due to the fact that
* the almanac uses degrees exclusively in their formulations.
*
* author : david vallado 719-573-2600 1 mar 2001
*
* inputs description range / units
* jd - julian date days from 4713 bc
*
* outputs :
* rsun - ijk position vector of the sun au
* rtasc - right ascension rad
* decl - declination rad
*
* coupling :
* -
*
* references :
* VALLADO, DAVID A. (2022) ‘Computer software in MATLAB’, in Fundamentals of astrodynamics and applications. 5th edn.
* Computer software in MATLAB: http://celestrak.org/software/vallado-sw.php
* --------------------------------------------------------------------------- */

export function sunPos(jd) {

// ------------------------- implementation -----------------
// ------------------- initialize values --------------------
const tut1 = ( jd - 2451545.0 ) / 36525.0;

const meanlong = (280.460 + 36000.77 * tut1) % 360.0; //deg

const ttdb = tut1; // is this declaration required instead of replacing `ttdb` with `tut1`

if (meananomaly < 0.0 ) {
const meananomaly = twoPi + ((357.5277233 + 35999.05034 * ttdb) * deg2rad) % twoPi; //rad;
} else {
const meananomaly = ((357.5277233 + 35999.05034 * ttdb) * deg2rad) % twoPi; //rad;
}

const eclplong_raw = ((meanlong + 1.914666471 * Math.sin(meananomaly) + 0.019994643 * Math.sin(2.0 * meananomaly)) % 360.0) * deg2rad; //rad

const obliquity = (23.439291 - 0.0130042 * ttdb) * deg2rad; //rad

// --------- find magnitude of sun vector, and it's components ------
const magr = 1.000140612 - 0.016708617 * Math.cos( meananomaly ) - 0.000139589 * Math.cos( 2.0 * meananomaly ); // in au's

const rsun = [
magr*Math.cos(eclplong_raw),
magr*Math.cos(obliquity)*Math.sin(eclplong_raw),
magr*Math.sin(obliquity)*Math.sin(eclplong_raw)
];

const rtasc_raw = Math.atan( Math.cos(obliquity) * Math.tan(eclplong_raw) );

// --- check that rtasc is in the same quadrant as eclplong_raw ----
if ( eclplong_raw < 0.0 ) {
const eclplong = eclplong_raw + twoPi; // make sure it's in 0 to 2pi range
} else {
const eclplong = eclplong_raw;
}

if ( Math.abs( eclplong_raw - rtasc_raw ) > pi*0.5 ) {
const rtasc = rtasc_raw + 0.5 *pi*Math.round( (eclplong_raw - rtasc_raw)/(0.5 *pi));
} else {
const rtasc = rtasc_raw;
}

const decl = Math.asin( Math.sin(obliquity) * Math.sin(eclplong_raw) );

return {rsun, rtasc, decl}
}


/* Original MATLAB code for Sun position from Vallado package (sun.mat) */
/*
function [rsun,rtasc,decl] = sun ( jd );

twopi = 2.0*pi;
deg2rad = pi/180.0;
show = 'n';

% ------------------------- implementation -----------------
% ------------------- initialize values --------------------
tut1= ( jd - 2451545.0 )/ 36525.0;

if show == 'y'
fprintf(1,'tut1 %14.9f \n',tut1);
end

meanlong= 280.460 + 36000.77*tut1;
meanlong= rem( meanlong,360.0 ); %deg

ttdb= tut1;
meananomaly= 357.5277233 + 35999.05034 *ttdb;
meananomaly= rem( meananomaly*deg2rad,twopi ); %rad
if ( meananomaly < 0.0 )
meananomaly= twopi + meananomaly;
end

eclplong_raw= meanlong + 1.914666471 *sin(meananomaly) ...
+ 0.019994643 *sin(2.0 *meananomaly); %deg
eclplong_raw= rem( eclplong_raw,360.0 ); %deg

obliquity= 23.439291 - 0.0130042 *ttdb; %deg

eclplong_raw = eclplong_raw *deg2rad;
obliquity= obliquity *deg2rad;

% --------- find magnitude of sun vector, ) components ------
magr= 1.000140612 - 0.016708617 *cos( meananomaly ) ...
- 0.000139589 *cos( 2.0 *meananomaly ); % in au's

rsun(1)= magr*cos( eclplong_raw );
rsun(2)= magr*cos(obliquity)*sin(eclplong_raw);
rsun(3)= magr*sin(obliquity)*sin(eclplong_raw);

if show == 'y'
fprintf(1,'meanlon %11.6f meanan %11.6f eclplon %11.6f obli %11.6f \n', ...
meanlong,meananomaly/deg2rad,eclplong_raw/deg2rad,obliquity/deg2rad);
fprintf(1,'rs %11.9f %11.9f %11.9f \n',rsun);
fprintf(1,'magr %14.7f \n',magr);
end

rtasc= atan( cos(obliquity)*tan(eclplong_raw) );

% --- check that rtasc is in the same quadrant as eclplong_raw ----
if ( eclplong_raw < 0.0 )
eclplong_raw= eclplong_raw + twopi; % make sure it's in 0 to 2pi range
end
if ( abs( eclplong_raw-rtasc ) > pi*0.5 )
rtasc= rtasc + 0.5 *pi*round( (eclplong_raw-rtasc)/(0.5 *pi));
end
decl = asin( sin(obliquity)*sin(eclplong_raw) );
*/
2 changes: 1 addition & 1 deletion test/ext.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import compareVectors from './compareVectors';

import { jday, invjday } from '../src/ext';
import twoline2satrec from '../src/io';
import { twoline2satrec } from '../src/io';
import { propagate, gstime } from '../src/propagation';

describe('Julian date / time', () => {
Expand Down
3 changes: 2 additions & 1 deletion test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
} from '../src/constants';

import { jday, invjday } from '../src/ext';
import twoline2satrec from '../src/io';
import { twoline2satrec, json2satrec } from '../src/io';
import { propagate, sgp4, gstime } from '../src/propagation';

import dopplerFactor from '../src/dopplerFactor';
Expand Down Expand Up @@ -74,6 +74,7 @@ function checkTransforms(transforms) {
function checkExports(namespace) {
it('constants', () => checkConstants(namespace.constants));
it('twoline2satrec', () => expect(namespace.twoline2satrec).toEqual(twoline2satrec));
it('json2satrec', () => expect(namespace.json2satrec).toEqual(json2satrec));
it('propagate', () => expect(namespace.propagate).toEqual(propagate));
it('sgp4', () => expect(namespace.sgp4).toEqual(sgp4));
it('gstime', () => expect(namespace.gstime).toEqual(gstime));
Expand Down
34 changes: 34 additions & 0 deletions test/io-edge.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[
{
"tleLine1": "1 00001U 57001B 21005.53831292 -.00000083 00000-0 -11575-3 0 9996",
"tleLine2": "2 00001 34.2508 325.6936 1846988 181.8107 177.4919 00.00000000227203",
"description": "Mean motion is zero and that is not allowed.",
"results": [{
"error": 2
}]
},
{
"tleLine1": "1 00002U 57001B 21005.53831292 -.00000083 00000-0 -11575-3 0 9996",
"tleLine2": "2 00002 34.2508 325.6936 1846988 181.8107 177.4919 00.00000001227203",
"description": "Eccentricity is way too high because mean motion is nearly zero.",
"results": [{
"error": 3
}]
},
{
"tleLine1": "1 00004U 57001B 21005.53831292 -.00000083 00000-0 -11575-3 0 9996",
"tleLine2": "2 00004 34.2508 325.6936 9999999 181.8107 177.4919 10.84863720227203",
"description": "Eccentricity is way too high.",
"results": [{
"error": 4
}]
},
{
"tleLine1": "1 00006U 57001B 21005.53831292 -.00000083 00000-0 -11575-3 0 9996",
"tleLine2": "2 00005 34.2508 325.6936 1846988 181.8107 177.4919 25.84863720227203",
"description": "Satellite should be decayed already.",
"results": [{
"error": 6
}]
}
]
Loading