├── LICENSE
├── README.md
├── aws-s3
├── package.json
├── remove-wx-images.js
├── upload-upcoming-passes.js
└── upload-wx-images.js
├── configure.sh
├── receive_and_process_satellite.sh
├── schedule_all.sh
├── schedule_satellite.sh
└── website
├── index.html
├── logo.png
├── tle.js
└── wx-ground-station.js
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 nootropic design
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Automated Weather Satellite Ground Station
2 |
3 | This project allows you to create a fully automated ground station that will receive and decode NOAA weather satellite images and upload them to your own website served from an Amazon AWS S3 bucket. [See my example S3 site](http://nootropicdesign.wx.s3-website-us-west-2.amazonaws.com/).
4 | For full details of the project, see the [full project writeup on the Project Lab blog](https://nootropicdesign.com/projectlab/2019/11/08/weather-satellite-ground-station/).
5 |
6 | The scripting in this project is largely based on the excellent work by [Jim Haslett](https://www.youtube.com/user/JimHaslett) as described in his well-written Instructable, [Raspberry Pi NOAA Weather Satellite Receiver](https://www.instructables.com/id/Raspberry-Pi-NOAA-Weather-Satellite-Receiver/).
7 |
8 |
9 |
--------------------------------------------------------------------------------
/aws-s3/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aws-s3",
3 | "version": "1.0.0",
4 | "description": "scripts for manipulating and uploading wx images to S3 bucket",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "nootropic design",
10 | "license": "ISC",
11 | "dependencies": {
12 | "aws-sdk": "^2.539.0",
13 | "dateformat": "^3.0.3",
14 | "glob": "^7.1.4",
15 | "jimp": "^0.8.4",
16 | "uuid": "^3.3.3"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/aws-s3/remove-wx-images.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var AWS = require('aws-sdk');
3 | var uuid = require('uuid');
4 |
5 | var REGION = "";
6 | var BUCKET = "";
7 | var IMAGE_DIR = "images/";
8 |
9 | AWS.config.update({region: REGION});
10 | var s3 = new AWS.S3();
11 |
12 | var filebase = process.argv[2];
13 |
14 | console.log("Removing files " + filebase + "* from S3...");
15 |
16 | var files = [
17 | filebase + ".json",
18 | filebase + "-ZA.png",
19 | filebase + "-NO.png",
20 | filebase + "-MSA.png",
21 | filebase + "-MSAPRECIP.png",
22 | filebase + "-MCIR.png",
23 | filebase + "-THERM.png",
24 | "thumbs/" + filebase + "-ZA.png",
25 | "thumbs/" + filebase + "-NO.png",
26 | "thumbs/" + filebase + "-MSA.png",
27 | "thumbs/" + filebase + "-MSAPRECIP.png",
28 | "thumbs/" + filebase + "-MCIR.png",
29 | "thumbs/" + filebase + "-THERM.png"
30 | ];
31 |
32 | files.forEach(removeFile);
33 |
34 |
35 | function removeFile(filename) {
36 | var params = {
37 | Bucket: BUCKET,
38 | Key: IMAGE_DIR + filename,
39 | };
40 | s3.deleteObject(params, (err, data) => {
41 | if (err) {
42 | console.log(err)
43 | } else {
44 | console.log(" successfully removed " + filename);
45 | }
46 | });
47 | }
48 |
--------------------------------------------------------------------------------
/aws-s3/upload-upcoming-passes.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var path = require('path');
3 | var AWS = require('aws-sdk');
4 | var uuid = require('uuid');
5 |
6 | var REGION = "";
7 | var BUCKET = "";
8 | var IMAGE_DIR = "images/";
9 |
10 | AWS.config.update({region: REGION});
11 | var s3 = new AWS.S3();
12 |
13 | uploadUpcomingPasses(process.argv[2]);
14 |
15 | function uploadUpcomingPasses(filename) {
16 | var upcomingPassesFilename = "upcoming_passes.json";
17 | var lines = fs.readFileSync(filename).toString().split("\n");
18 | var count = 0;
19 | var all_passes = [];
20 | lines.forEach((line) => {
21 | if (line.trim().length > 0) {
22 | var fields = line.split(',');
23 | var pass_info = {
24 | start: new Date(0).setUTCSeconds(fields[0]),
25 | end: new Date(0).setUTCSeconds(fields[1]),
26 | elevation: fields[2],
27 | direction: fields[3],
28 | satellite: fields[4],
29 | tle1: fields[5],
30 | tle2: fields[6]
31 | };
32 | all_passes.push(pass_info);
33 | }
34 | if (++count == lines.length) {
35 | all_passes = all_passes.sort((a, b) => { return a.start-b.start });
36 | console.log("uploading upcoming pass info");
37 | var params = {
38 | ACL: "public-read",
39 | ContentType: "application/json",
40 | Bucket: BUCKET,
41 | Key: IMAGE_DIR + upcomingPassesFilename,
42 | Body: JSON.stringify(all_passes, null, 2)
43 | };
44 |
45 | s3.putObject(params, function(err, data) {
46 | if (err) {
47 | console.log(err)
48 | } else {
49 | console.log(" successfully uploaded " + upcomingPassesFilename);
50 | }
51 | });
52 | }
53 | })
54 | }
55 |
--------------------------------------------------------------------------------
/aws-s3/upload-wx-images.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var path = require('path');
3 | var glob = require("glob");
4 | var AWS = require('aws-sdk');
5 | var uuid = require('uuid');
6 | var Jimp = require('jimp');
7 | var dateFormat = require('dateformat');
8 |
9 | var REGION = "";
10 | var BUCKET = "";
11 | var LOCATION = "";
12 | var IMAGE_DIR = "images/";
13 |
14 | AWS.config.update({region: REGION});
15 | var s3 = new AWS.S3();
16 |
17 | var satellite = process.argv[2];
18 | var frequency = process.argv[3];
19 | var filebase = process.argv[4];
20 | var elevation = process.argv[5];
21 | var direction = process.argv[6];
22 | var duration = process.argv[7];
23 | var tle1 = process.argv[8];
24 | var tle2 = process.argv[9];
25 | var gain = process.argv[10];
26 | var chan_a = process.argv[11];
27 | var chan_b = process.argv[12];
28 |
29 | var basename = filebase.slice(filebase.lastIndexOf('/')+1);
30 | var dirname = filebase.slice(0, filebase.lastIndexOf('/')+1);
31 | var components = basename.split("-");
32 | var date = components[1];
33 | date = date.slice(0, 4) + '-' + date.slice(4, 6) + '-' + date.slice(6);
34 | var time = components[2];
35 | time = time.slice(0, 2) + ':' + time.slice(2, 4) + ':' + time.slice(4) + ' ' + dateFormat(new Date, "o");
36 |
37 |
38 | // example "Gain: 15.2"
39 | if (gain) {
40 | gain = gain.substring(gain.indexOf(": ") + 2)
41 | }
42 |
43 | // example "Channel A: 1 (visible)"
44 | if (chan_a) {
45 | chan_a = chan_a.substring(chan_a.indexOf(": ")+2);
46 | }
47 | // example "Channel B: 4 (thermal infrared)"
48 | if (chan_b) {
49 | chan_b = chan_b.substring(chan_b.indexOf(": ")+2);
50 | }
51 |
52 | console.log("Uploading files " + path.basename(filebase) + "* to S3...");
53 |
54 | var metadata = {
55 | satellite: satellite,
56 | date: date,
57 | time: time,
58 | elevation: elevation,
59 | direction: direction,
60 | duration: duration,
61 | imageKey: filebase.slice(filebase.lastIndexOf('/')+1),
62 | tle1: tle1,
63 | tle2: tle2,
64 | frequency: frequency,
65 | gain: gain,
66 | chan_a: chan_a,
67 | chan_b: chan_b,
68 | images: []
69 | };
70 |
71 | async function uploadImage(image, filename) {
72 | var w = image.bitmap.width;
73 | var h = image.bitmap.height;
74 | var enhancement;
75 | if (filename.endsWith("-ZA.png")) enhancement = "normal infrared";
76 | if (filename.endsWith("-NO.png")) enhancement = "color infrared";
77 | if (filename.endsWith("-MSA.png")) enhancement = "multispectral analysis";
78 | if (filename.endsWith("-MSAPRECIP.png")) enhancement = "multispectral precip";
79 | if (filename.endsWith("-MCIR.png")) enhancement = "map color infrared";
80 | if (filename.endsWith("-THERM.png")) enhancement = "thermal";
81 | var imageInfo = {
82 | filename: filename,
83 | width: w,
84 | height: h,
85 | thumbfilename: 'thumbs/' + filename,
86 | enhancement: enhancement
87 | };
88 |
89 |
90 | var font = await Jimp.loadFont(Jimp.FONT_SANS_16_WHITE);
91 | var newImage = await new Jimp(image.bitmap.width, image.bitmap.height+64, '#000000');
92 | newImage.composite(image, 0, 48);
93 | image = newImage;
94 | image.print(font, 5, 5, metadata.date + " " + metadata.time + " satellite: " + metadata.satellite +
95 | " elevation: " + metadata.elevation + '\xB0' + " enhancement: " + enhancement);
96 | image.print(font, 5, 25, LOCATION);
97 |
98 | image.getBuffer(Jimp.MIME_PNG, (err, buffer) => {
99 | var params = {
100 | ACL: "public-read",
101 | ContentType: "image/png",
102 | Bucket: BUCKET,
103 | Key: IMAGE_DIR + filename,
104 | Body: buffer
105 | };
106 | s3.putObject(params, (err, data) => {
107 | if (err) {
108 | console.log(err)
109 | } else {
110 | console.log(" successfully uploaded " + filename);
111 | }
112 | });
113 | });
114 |
115 | var thumb = image.clone();
116 | thumb.cover(260, 200);
117 | var thumbFilename = "thumbs/" + filename;
118 | thumb.getBuffer(Jimp.MIME_PNG, (err, buffer) => {
119 | var params = {
120 | ACL: "public-read",
121 | ContentType: "image/png",
122 | Bucket: BUCKET,
123 | Key: IMAGE_DIR + thumbFilename,
124 | Body: buffer
125 | };
126 | s3.putObject(params, (err, data) => {
127 | if (err) {
128 | console.log(err)
129 | } else {
130 | console.log(" successfully uploaded thumb " + filename);
131 | }
132 | });
133 | });
134 |
135 | return imageInfo;
136 | }
137 |
138 | function uploadMetadata(filebase) {
139 | var metadataFilename = filebase + ".json";
140 | console.log("uploading metadata " + JSON.stringify(metadata, null, 2));
141 | var params = {
142 | ACL: "public-read",
143 | Bucket: BUCKET,
144 | Key: IMAGE_DIR + metadataFilename,
145 | Body: JSON.stringify(metadata, null, 2)
146 | };
147 |
148 | s3.putObject(params, function(err, data) {
149 | if (err) {
150 | console.log(err)
151 | } else {
152 | console.log(" successfully uploaded metadata " + metadataFilename);
153 | }
154 | });
155 | }
156 |
157 |
158 | glob(filebase + "-[A-Z]*.png", {}, function (err, files) {
159 | var uploadPromises = [];
160 | files.forEach(function(filename) {
161 | var basename = path.basename(filename);
162 | Jimp.read(filename)
163 | .then(image => {
164 | uploadPromises.push(uploadImage(image, basename));
165 | if (uploadPromises.length == files.length) {
166 | Promise.all(uploadPromises).then((values) => {
167 | metadata.images = values;
168 | console.log("values: " + JSON.stringify(values, null, 2));
169 | uploadMetadata(path.basename(filebase));
170 | });
171 | }
172 | });
173 | });
174 | });
175 |
--------------------------------------------------------------------------------
/configure.sh:
--------------------------------------------------------------------------------
1 |
2 | # create directories
3 | if [ ! -d "audio" ]
4 | then
5 | mkdir audio
6 | fi
7 |
8 | if [ ! -d "images" ]
9 | then
10 | mkdir images
11 | fi
12 |
13 | if [ ! -d "logs" ]
14 | then
15 | mkdir logs
16 | fi
17 |
18 | currentDir=`echo $PWD`
19 | echo "configuring for" $currentDir
20 |
21 | sed -i "s|INSTALL_DIR|$currentDir|g" schedule_all.sh
22 | sed -i "s|INSTALL_DIR|$currentDir|g" schedule_satellite.sh
23 | sed -i "s|INSTALL_DIR|$currentDir|g" receive_and_process_satellite.sh
24 |
25 | chmod +x schedule_all.sh
26 | chmod +x schedule_satellite.sh
27 | chmod +x receive_and_process_satellite.sh
28 |
29 | cronjobcmd="$currentDir/schedule_all.sh"
30 | cronjob="0 0 * * * $cronjobcmd"
31 | ( crontab -l | grep -v -F "$cronjobcmd" ; echo "$cronjob" ) | crontab -
32 |
--------------------------------------------------------------------------------
/receive_and_process_satellite.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | SAT=$1
4 | FREQ=$2
5 | FILEKEY=$3
6 | TLE_FILE=$4
7 | START_TIME=$5
8 | DURATION=$6
9 | ELEVATION=$7
10 | DIRECTION=$8
11 |
12 | AUDIO_DIR=INSTALL_DIR/audio
13 | IMAGE_DIR=INSTALL_DIR/images
14 | LOG_DIR=INSTALL_DIR/logs
15 | MAP_FILE=${IMAGE_DIR}/${FILEKEY}-map.png
16 | AUDIO_FILE=${AUDIO_DIR}/${FILEKEY}.wav
17 | LOGFILE=${LOG_DIR}/${FILEKEY}.log
18 |
19 | echo $@ >> $LOGFILE
20 |
21 | #/usr/local/bin/rtl_biast -b 1 2>> $LOGFILE
22 | sudo timeout $DURATION rtl_fm -f ${FREQ}M -s 60k -g 45 -p 0 -E wav -E deemp -F 9 - 2>> $LOGFILE | sox -t wav - $AUDIO_FILE rate 11025
23 | #/usr/local/bin/rtl_biast -b 0 2>> $LOGFILE
24 |
25 | PassStart=`expr $START_TIME + 90`
26 |
27 | if [ -e $AUDIO_FILE ]
28 | then
29 | /usr/local/bin/wxmap -T "${SAT}" -H $TLE_FILE -p 0 -l 0 -o $PassStart ${MAP_FILE} >> $LOGFILE 2>&1
30 |
31 | /usr/local/bin/wxtoimg -m ${MAP_FILE} -e ZA $AUDIO_FILE ${IMAGE_DIR}/${FILEKEY}-ZA.png >> $LOGFILE 2>&1
32 |
33 | /usr/local/bin/wxtoimg -m ${MAP_FILE} -e NO $AUDIO_FILE ${IMAGE_DIR}/${FILEKEY}-NO.png >> $LOGFILE 2>&1
34 |
35 | /usr/local/bin/wxtoimg -m ${MAP_FILE} -e MSA $AUDIO_FILE ${IMAGE_DIR}/${FILEKEY}-MSA.png >> $LOGFILE 2>&1
36 |
37 | /usr/local/bin/wxtoimg -m ${MAP_FILE} -e MCIR $AUDIO_FILE ${IMAGE_DIR}/${FILEKEY}-MCIR.png >> $LOGFILE 2>&1
38 |
39 | /usr/local/bin/wxtoimg -m ${MAP_FILE} -e therm $AUDIO_FILE ${IMAGE_DIR}/${FILEKEY}-THERM.png >> $LOGFILE 2>&1
40 |
41 | TLE1=`grep "$SAT" $TLE_FILE -A 2 | tail -2 | head -1 | tr -d '\r'`
42 | TLE2=`grep "$SAT" $TLE_FILE -A 2 | tail -2 | tail -1 | tr -d '\r'`
43 | GAIN=`grep Gain $LOGFILE | head -1`
44 | CHAN_A=`grep "Channel A" $LOGFILE | head -1`
45 | CHAN_B=`grep "Channel B" $LOGFILE | head -1`
46 |
47 | echo "node INSTALL_DIR/aws-s3/upload-wx-images.js \"$SAT\" $FREQ ${IMAGE_DIR}/${FILEKEY} $ELEVATION $DIRECTION $DURATION \"${TLE1}\" \"${TLE2}\" \"$GAIN\" \"${CHAN_A}\" \"${CHAN_B}\"" >> $LOGFILE 2>&1
48 | node INSTALL_DIR/aws-s3/upload-wx-images.js "$SAT" $FREQ ${IMAGE_DIR}/${FILEKEY} $ELEVATION $DIRECTION $DURATION "${TLE1}" "${TLE2}" "$GAIN" "${CHAN_A}" "${CHAN_B}" >> $LOGFILE 2>&1
49 | fi
50 |
--------------------------------------------------------------------------------
/schedule_all.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Update Satellite Information
4 |
5 | wget -qr https://www.celestrak.com/NORAD/elements/weather.txt -O INSTALL_DIR/weather.txt
6 | grep "NOAA 15" INSTALL_DIR/weather.txt -A 2 > INSTALL_DIR/weather.tle
7 | grep "NOAA 18" INSTALL_DIR/weather.txt -A 2 >> INSTALL_DIR/weather.tle
8 | grep "NOAA 19" INSTALL_DIR/weather.txt -A 2 >> INSTALL_DIR/weather.tle
9 |
10 |
11 |
12 | #Remove all AT jobs
13 |
14 | for i in `atq | awk '{print $1}'`;do atrm $i;done
15 |
16 | rm -f INSTALL_DIR/upcoming_passes.txt
17 |
18 | #Schedule Satellite Passes:
19 |
20 | INSTALL_DIR/schedule_satellite.sh "NOAA 19" 137.1000
21 | INSTALL_DIR/schedule_satellite.sh "NOAA 18" 137.9125
22 | INSTALL_DIR/schedule_satellite.sh "NOAA 15" 137.6200
23 |
24 | node INSTALL_DIR/aws-s3/upload-upcoming-passes.js INSTALL_DIR/upcoming_passes.txt
25 |
--------------------------------------------------------------------------------
/schedule_satellite.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | SAT=$1
4 | FREQ=$2
5 | TLE_FILE=INSTALL_DIR/weather.tle
6 | PREDICTION_START=`/usr/bin/predict -t $TLE_FILE -p "$SAT" | head -1`
7 | PREDICTION_END=`/usr/bin/predict -t $TLE_FILE -p "$SAT" | tail -1`
8 |
9 | END_EPOCH=`echo $PREDICTION_END | cut -d " " -f 1`
10 | END_EPOCH_DATE=`date --date="TZ=\"UTC\" @${END_EPOCH}" +%D`
11 |
12 | MAXELEV=`/usr/bin/predict -t $TLE_FILE -p "${SAT}" | awk -v max=0 '{if($5>max){max=$5}}END{print max}'`
13 | START_LAT=`echo $PREDICTION_START | awk '{print $8}'`
14 | END_LAT=`echo $PREDICTION_END | awk '{print $8}'`
15 | if [ $START_LAT -gt $END_LAT ]
16 | then
17 | DIR="southbound"
18 | else
19 | DIR="northbound"
20 | fi
21 |
22 |
23 | while [ $END_EPOCH_DATE == `date +%D` ] || [ $END_EPOCH_DATE == `date --date="tomorrow" +%D` ]; do
24 |
25 | START_TIME=`echo $PREDICTION_START | cut -d " " -f 3-4`
26 | START_EPOCH=`echo $PREDICTION_START | cut -d " " -f 1`
27 |
28 | SECONDS_REMAINDER=`echo $START_TIME | cut -d " " -f 2 | cut -d ":" -f 3`
29 |
30 | JOB_START=`date --date="TZ=\"UTC\" $START_TIME" +"%H:%M %D"`
31 |
32 | # at jobs can only be started on minute boundaries, so add the
33 | # seconds remainder to the duration of the pass because the
34 | # recording job will start early
35 | PASS_DURATION=`expr $END_EPOCH - $START_EPOCH`
36 | JOB_TIMER=`expr $PASS_DURATION + $SECONDS_REMAINDER`
37 | OUTDATE=`date --date="TZ=\"UTC\" $START_TIME" +%Y%m%d-%H%M%S`
38 |
39 | if [ $MAXELEV -ge 20 ]
40 | then
41 | FILEKEY="${SAT//" "}-${OUTDATE}"
42 | COMMAND="INSTALL_DIR/receive_and_process_satellite.sh \"${SAT}\" $FREQ $FILEKEY $TLE_FILE $START_EPOCH $JOB_TIMER $MAXELEV $DIR"
43 | echo $COMMAND
44 | echo $COMMAND | at $JOB_START
45 |
46 | TLE1=`grep "$SAT" $TLE_FILE -A 2 | tail -2 | head -1 | tr -d '\r'`
47 | TLE2=`grep "$SAT" $TLE_FILE -A 2 | tail -2 | tail -1 | tr -d '\r'`
48 |
49 | echo ${START_EPOCH},${END_EPOCH},${MAXELEV},${DIR},${SAT},"${TLE1}","${TLE2}" >> INSTALL_DIR/upcoming_passes.txt
50 | fi
51 |
52 | nextpredict=`expr $END_EPOCH + 60`
53 |
54 | PREDICTION_START=`/usr/bin/predict -t $TLE_FILE -p "${SAT}" $nextpredict | head -1`
55 | PREDICTION_END=`/usr/bin/predict -t $TLE_FILE -p "${SAT}" $nextpredict | tail -1`
56 |
57 | MAXELEV=`/usr/bin/predict -t $TLE_FILE -p "${SAT}" $nextpredict | awk -v max=0 '{if($5>max){max=$5}}END{print max}'`
58 | START_LAT=`echo $PREDICTION_START | awk '{print $8}'`
59 | END_LAT=`echo $PREDICTION_END | awk '{print $8}'`
60 | if [ $START_LAT -gt $END_LAT ]
61 | then
62 | DIR="southbound"
63 | else
64 | DIR="northbound"
65 | fi
66 |
67 | END_EPOCH=`echo $PREDICTION_END | cut -d " " -f 1`
68 | END_EPOCH_DATE=`date --date="TZ=\"UTC\" @${END_EPOCH}" +%D`
69 |
70 | done
71 |
--------------------------------------------------------------------------------
/website/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | weather satellite ground station
5 |
6 |
7 |
10 |
13 |
14 |
15 |
16 |
17 |
38 |
39 |
40 |
41 |
42 |
43 |

44 |
weather satellite ground station
45 |
46 |
47 |
48 |
49 |
52 |
53 |
Recent captures:
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/website/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nootropicdesign/wx-ground-station/c5336f719024d9f43797a1cf4d0a8e2e2d8f5ec0/website/logo.png
--------------------------------------------------------------------------------
/website/tle.js:
--------------------------------------------------------------------------------
1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.TLEJS = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i= 0 ? 1 : -1;
77 | }
78 |
79 | rangeRate *= sign(rangeRate);
80 | var c = 299792.458; // Speed of light in km/s
81 |
82 | return 1 + rangeRate / c;
83 | }
84 | },{}],4:[function(require,module,exports){
85 | /*!
86 | * satellite-js v3.0.1
87 | * (c) 2013 Shashwat Kandadai and UCSC
88 | * https://github.com/shashwatak/satellite-js
89 | * License: MIT
90 | */
91 |
92 | "use strict";
93 |
94 | Object.defineProperty(exports, "__esModule", {
95 | value: true
96 | });
97 | exports.days2mdhms = days2mdhms;
98 | exports.jday = jday;
99 | exports.invjday = invjday;
100 |
101 | /* -----------------------------------------------------------------------------
102 | *
103 | * procedure days2mdhms
104 | *
105 | * this procedure converts the day of the year, days, to the equivalent month
106 | * day, hour, minute and second.
107 | *
108 | * algorithm : set up array for the number of days per month
109 | * find leap year - use 1900 because 2000 is a leap year
110 | * loop through a temp value while the value is < the days
111 | * perform int conversions to the correct day and month
112 | * convert remainder into h m s using type conversions
113 | *
114 | * author : david vallado 719-573-2600 1 mar 2001
115 | *
116 | * inputs description range / units
117 | * year - year 1900 .. 2100
118 | * days - julian day of the year 0.0 .. 366.0
119 | *
120 | * outputs :
121 | * mon - month 1 .. 12
122 | * day - day 1 .. 28,29,30,31
123 | * hr - hour 0 .. 23
124 | * min - minute 0 .. 59
125 | * sec - second 0.0 .. 59.999
126 | *
127 | * locals :
128 | * dayofyr - day of year
129 | * temp - temporary extended values
130 | * inttemp - temporary int value
131 | * i - index
132 | * lmonth[12] - int array containing the number of days per month
133 | *
134 | * coupling :
135 | * none.
136 | * --------------------------------------------------------------------------- */
137 | function days2mdhms(year, days) {
138 | var lmonth = [31, year % 4 === 0 ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
139 | var dayofyr = Math.floor(days); // ----------------- find month and day of month ----------------
140 |
141 | var i = 1;
142 | var inttemp = 0;
143 |
144 | while (dayofyr > inttemp + lmonth[i - 1] && i < 12) {
145 | inttemp += lmonth[i - 1];
146 | i += 1;
147 | }
148 |
149 | var mon = i;
150 | var day = dayofyr - inttemp; // ----------------- find hours minutes and seconds -------------
151 |
152 | var temp = (days - dayofyr) * 24.0;
153 | var hr = Math.floor(temp);
154 | temp = (temp - hr) * 60.0;
155 | var minute = Math.floor(temp);
156 | var sec = (temp - minute) * 60.0;
157 | return {
158 | mon: mon,
159 | day: day,
160 | hr: hr,
161 | minute: minute,
162 | sec: sec
163 | };
164 | }
165 | /* -----------------------------------------------------------------------------
166 | *
167 | * procedure jday
168 | *
169 | * this procedure finds the julian date given the year, month, day, and time.
170 | * the julian date is defined by each elapsed day since noon, jan 1, 4713 bc.
171 | *
172 | * algorithm : calculate the answer in one step for efficiency
173 | *
174 | * author : david vallado 719-573-2600 1 mar 2001
175 | *
176 | * inputs description range / units
177 | * year - year 1900 .. 2100
178 | * mon - month 1 .. 12
179 | * day - day 1 .. 28,29,30,31
180 | * hr - universal time hour 0 .. 23
181 | * min - universal time min 0 .. 59
182 | * sec - universal time sec 0.0 .. 59.999
183 | *
184 | * outputs :
185 | * jd - julian date days from 4713 bc
186 | *
187 | * locals :
188 | * none.
189 | *
190 | * coupling :
191 | * none.
192 | *
193 | * references :
194 | * vallado 2007, 189, alg 14, ex 3-14
195 | *
196 | * --------------------------------------------------------------------------- */
197 |
198 |
199 | function jdayInternal(year, mon, day, hr, minute, sec) {
200 | var msec = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : 0;
201 | return 367.0 * year - Math.floor(7 * (year + Math.floor((mon + 9) / 12.0)) * 0.25) + Math.floor(275 * mon / 9.0) + day + 1721013.5 + ((msec / 60000 + sec / 60.0 + minute) / 60.0 + hr) / 24.0 // ut in days
202 | // # - 0.5*sgn(100.0*year + mon - 190002.5) + 0.5;
203 | ;
204 | }
205 |
206 | function jday(year, mon, day, hr, minute, sec, msec) {
207 | if (year instanceof Date) {
208 | var date = year;
209 | return jdayInternal(date.getUTCFullYear(), date.getUTCMonth() + 1, // Note, this function requires months in range 1-12.
210 | date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), date.getUTCMilliseconds());
211 | }
212 |
213 | return jdayInternal(year, mon, day, hr, minute, sec, msec);
214 | }
215 | /* -----------------------------------------------------------------------------
216 | *
217 | * procedure invjday
218 | *
219 | * this procedure finds the year, month, day, hour, minute and second
220 | * given the julian date. tu can be ut1, tdt, tdb, etc.
221 | *
222 | * algorithm : set up starting values
223 | * find leap year - use 1900 because 2000 is a leap year
224 | * find the elapsed days through the year in a loop
225 | * call routine to find each individual value
226 | *
227 | * author : david vallado 719-573-2600 1 mar 2001
228 | *
229 | * inputs description range / units
230 | * jd - julian date days from 4713 bc
231 | *
232 | * outputs :
233 | * year - year 1900 .. 2100
234 | * mon - month 1 .. 12
235 | * day - day 1 .. 28,29,30,31
236 | * hr - hour 0 .. 23
237 | * min - minute 0 .. 59
238 | * sec - second 0.0 .. 59.999
239 | *
240 | * locals :
241 | * days - day of year plus fractional
242 | * portion of a day days
243 | * tu - julian centuries from 0 h
244 | * jan 0, 1900
245 | * temp - temporary double values
246 | * leapyrs - number of leap years from 1900
247 | *
248 | * coupling :
249 | * days2mdhms - finds month, day, hour, minute and second given days and year
250 | *
251 | * references :
252 | * vallado 2007, 208, alg 22, ex 3-13
253 | * --------------------------------------------------------------------------- */
254 |
255 |
256 | function invjday(jd, asArray) {
257 | // --------------- find year and days of the year -
258 | var temp = jd - 2415019.5;
259 | var tu = temp / 365.25;
260 | var year = 1900 + Math.floor(tu);
261 | var leapyrs = Math.floor((year - 1901) * 0.25); // optional nudge by 8.64x10-7 sec to get even outputs
262 |
263 | var days = temp - ((year - 1900) * 365.0 + leapyrs) + 0.00000000001; // ------------ check for case of beginning of a year -----------
264 |
265 | if (days < 1.0) {
266 | year -= 1;
267 | leapyrs = Math.floor((year - 1901) * 0.25);
268 | days = temp - ((year - 1900) * 365.0 + leapyrs);
269 | } // ----------------- find remaing data -------------------------
270 |
271 |
272 | var mdhms = days2mdhms(year, days);
273 | var mon = mdhms.mon,
274 | day = mdhms.day,
275 | hr = mdhms.hr,
276 | minute = mdhms.minute;
277 | var sec = mdhms.sec - 0.00000086400;
278 |
279 | if (asArray) {
280 | return [year, mon, day, hr, minute, Math.floor(sec)];
281 | }
282 |
283 | return new Date(Date.UTC(year, mon - 1, day, hr, minute, Math.floor(sec)));
284 | }
285 | },{}],5:[function(require,module,exports){
286 | /*!
287 | * satellite-js v3.0.1
288 | * (c) 2013 Shashwat Kandadai and UCSC
289 | * https://github.com/shashwatak/satellite-js
290 | * License: MIT
291 | */
292 |
293 | "use strict";
294 |
295 | Object.defineProperty(exports, "__esModule", {
296 | value: true
297 | });
298 | Object.defineProperty(exports, "jday", {
299 | enumerable: true,
300 | get: function get() {
301 | return _ext.jday;
302 | }
303 | });
304 | Object.defineProperty(exports, "invjday", {
305 | enumerable: true,
306 | get: function get() {
307 | return _ext.invjday;
308 | }
309 | });
310 | Object.defineProperty(exports, "twoline2satrec", {
311 | enumerable: true,
312 | get: function get() {
313 | return _io.default;
314 | }
315 | });
316 | Object.defineProperty(exports, "propagate", {
317 | enumerable: true,
318 | get: function get() {
319 | return _propagation.propagate;
320 | }
321 | });
322 | Object.defineProperty(exports, "sgp4", {
323 | enumerable: true,
324 | get: function get() {
325 | return _propagation.sgp4;
326 | }
327 | });
328 | Object.defineProperty(exports, "gstime", {
329 | enumerable: true,
330 | get: function get() {
331 | return _propagation.gstime;
332 | }
333 | });
334 | Object.defineProperty(exports, "dopplerFactor", {
335 | enumerable: true,
336 | get: function get() {
337 | return _dopplerFactor.default;
338 | }
339 | });
340 | Object.defineProperty(exports, "radiansToDegrees", {
341 | enumerable: true,
342 | get: function get() {
343 | return _transforms.radiansToDegrees;
344 | }
345 | });
346 | Object.defineProperty(exports, "degreesToRadians", {
347 | enumerable: true,
348 | get: function get() {
349 | return _transforms.degreesToRadians;
350 | }
351 | });
352 | Object.defineProperty(exports, "degreesLat", {
353 | enumerable: true,
354 | get: function get() {
355 | return _transforms.degreesLat;
356 | }
357 | });
358 | Object.defineProperty(exports, "degreesLong", {
359 | enumerable: true,
360 | get: function get() {
361 | return _transforms.degreesLong;
362 | }
363 | });
364 | Object.defineProperty(exports, "radiansLat", {
365 | enumerable: true,
366 | get: function get() {
367 | return _transforms.radiansLat;
368 | }
369 | });
370 | Object.defineProperty(exports, "radiansLong", {
371 | enumerable: true,
372 | get: function get() {
373 | return _transforms.radiansLong;
374 | }
375 | });
376 | Object.defineProperty(exports, "geodeticToEcf", {
377 | enumerable: true,
378 | get: function get() {
379 | return _transforms.geodeticToEcf;
380 | }
381 | });
382 | Object.defineProperty(exports, "eciToGeodetic", {
383 | enumerable: true,
384 | get: function get() {
385 | return _transforms.eciToGeodetic;
386 | }
387 | });
388 | Object.defineProperty(exports, "eciToEcf", {
389 | enumerable: true,
390 | get: function get() {
391 | return _transforms.eciToEcf;
392 | }
393 | });
394 | Object.defineProperty(exports, "ecfToEci", {
395 | enumerable: true,
396 | get: function get() {
397 | return _transforms.ecfToEci;
398 | }
399 | });
400 | Object.defineProperty(exports, "ecfToLookAngles", {
401 | enumerable: true,
402 | get: function get() {
403 | return _transforms.ecfToLookAngles;
404 | }
405 | });
406 | exports.constants = void 0;
407 |
408 | var constants = _interopRequireWildcard(require("./constants"));
409 |
410 | exports.constants = constants;
411 |
412 | var _ext = require("./ext");
413 |
414 | var _io = _interopRequireDefault(require("./io"));
415 |
416 | var _propagation = require("./propagation");
417 |
418 | var _dopplerFactor = _interopRequireDefault(require("./dopplerFactor"));
419 |
420 | var _transforms = require("./transforms");
421 |
422 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
423 |
424 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
425 | },{"./constants":2,"./dopplerFactor":3,"./ext":4,"./io":6,"./propagation":7,"./transforms":17}],6:[function(require,module,exports){
426 | /*!
427 | * satellite-js v3.0.1
428 | * (c) 2013 Shashwat Kandadai and UCSC
429 | * https://github.com/shashwatak/satellite-js
430 | * License: MIT
431 | */
432 |
433 | "use strict";
434 |
435 | Object.defineProperty(exports, "__esModule", {
436 | value: true
437 | });
438 | exports.default = twoline2satrec;
439 |
440 | var _constants = require("./constants");
441 |
442 | var _ext = require("./ext");
443 |
444 | var _sgp4init = _interopRequireDefault(require("./propagation/sgp4init"));
445 |
446 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
447 |
448 | /* -----------------------------------------------------------------------------
449 | *
450 | * function twoline2rv
451 | *
452 | * this function converts the two line element set character string data to
453 | * variables and initializes the sgp4 variables. several intermediate varaibles
454 | * and quantities are determined. note that the result is a structure so multiple
455 | * satellites can be processed simultaneously without having to reinitialize. the
456 | * verification mode is an important option that permits quick checks of any
457 | * changes to the underlying technical theory. this option works using a
458 | * modified tle file in which the start, stop, and delta time values are
459 | * included at the end of the second line of data. this only works with the
460 | * verification mode. the catalog mode simply propagates from -1440 to 1440 min
461 | * from epoch and is useful when performing entire catalog runs.
462 | *
463 | * author : david vallado 719-573-2600 1 mar 2001
464 | *
465 | * inputs :
466 | * longstr1 - first line of the tle
467 | * longstr2 - second line of the tle
468 | * typerun - type of run verification 'v', catalog 'c',
469 | * manual 'm'
470 | * typeinput - type of manual input mfe 'm', epoch 'e', dayofyr 'd'
471 | * opsmode - mode of operation afspc or improved 'a', 'i'
472 | * whichconst - which set of constants to use 72, 84
473 | *
474 | * outputs :
475 | * satrec - structure containing all the sgp4 satellite information
476 | *
477 | * coupling :
478 | * getgravconst-
479 | * days2mdhms - conversion of days to month, day, hour, minute, second
480 | * jday - convert day month year hour minute second into julian date
481 | * sgp4init - initialize the sgp4 variables
482 | *
483 | * references :
484 | * norad spacetrack report #3
485 | * vallado, crawford, hujsak, kelso 2006
486 | --------------------------------------------------------------------------- */
487 |
488 | /**
489 | * Return a Satellite imported from two lines of TLE data.
490 | *
491 | * Provide the two TLE lines as strings `longstr1` and `longstr2`,
492 | * and select which standard set of gravitational constants you want
493 | * by providing `gravity_constants`:
494 | *
495 | * `sgp4.propagation.wgs72` - Standard WGS 72 model
496 | * `sgp4.propagation.wgs84` - More recent WGS 84 model
497 | * `sgp4.propagation.wgs72old` - Legacy support for old SGP4 behavior
498 | *
499 | * Normally, computations are made using letious recent improvements
500 | * to the algorithm. If you want to turn some of these off and go
501 | * back into "afspc" mode, then set `afspc_mode` to `True`.
502 | */
503 | function twoline2satrec(longstr1, longstr2) {
504 | var opsmode = 'i';
505 | var xpdotp = 1440.0 / (2.0 * _constants.pi); // 229.1831180523293;
506 |
507 | var year = 0;
508 | var satrec = {};
509 | satrec.error = 0;
510 | satrec.satnum = longstr1.substring(2, 7);
511 | satrec.epochyr = parseInt(longstr1.substring(18, 20), 10);
512 | satrec.epochdays = parseFloat(longstr1.substring(20, 32));
513 | satrec.ndot = parseFloat(longstr1.substring(33, 43));
514 | satrec.nddot = parseFloat(".".concat(parseInt(longstr1.substring(44, 50), 10), "E").concat(longstr1.substring(50, 52)));
515 | satrec.bstar = parseFloat("".concat(longstr1.substring(53, 54), ".").concat(parseInt(longstr1.substring(54, 59), 10), "E").concat(longstr1.substring(59, 61))); // satrec.satnum = longstr2.substring(2, 7);
516 |
517 | satrec.inclo = parseFloat(longstr2.substring(8, 16));
518 | satrec.nodeo = parseFloat(longstr2.substring(17, 25));
519 | satrec.ecco = parseFloat(".".concat(longstr2.substring(26, 33)));
520 | satrec.argpo = parseFloat(longstr2.substring(34, 42));
521 | satrec.mo = parseFloat(longstr2.substring(43, 51));
522 | satrec.no = parseFloat(longstr2.substring(52, 63)); // ---- find no, ndot, nddot ----
523 |
524 | satrec.no /= xpdotp; // rad/min
525 | // satrec.nddot= satrec.nddot * Math.pow(10.0, nexp);
526 | // satrec.bstar= satrec.bstar * Math.pow(10.0, ibexp);
527 | // ---- convert to sgp4 units ----
528 |
529 | satrec.a = Math.pow(satrec.no * _constants.tumin, -2.0 / 3.0);
530 | satrec.ndot /= xpdotp * 1440.0; // ? * minperday
531 |
532 | satrec.nddot /= xpdotp * 1440.0 * 1440; // ---- find standard orbital elements ----
533 |
534 | satrec.inclo *= _constants.deg2rad;
535 | satrec.nodeo *= _constants.deg2rad;
536 | satrec.argpo *= _constants.deg2rad;
537 | satrec.mo *= _constants.deg2rad;
538 | satrec.alta = satrec.a * (1.0 + satrec.ecco) - 1.0;
539 | satrec.altp = satrec.a * (1.0 - satrec.ecco) - 1.0; // ----------------------------------------------------------------
540 | // find sgp4epoch time of element set
541 | // remember that sgp4 uses units of days from 0 jan 1950 (sgp4epoch)
542 | // and minutes from the epoch (time)
543 | // ----------------------------------------------------------------
544 | // ---------------- temp fix for years from 1957-2056 -------------------
545 | // --------- correct fix will occur when year is 4-digit in tle ---------
546 |
547 | if (satrec.epochyr < 57) {
548 | year = satrec.epochyr + 2000;
549 | } else {
550 | year = satrec.epochyr + 1900;
551 | }
552 |
553 | var mdhmsResult = (0, _ext.days2mdhms)(year, satrec.epochdays);
554 | var mon = mdhmsResult.mon,
555 | day = mdhmsResult.day,
556 | hr = mdhmsResult.hr,
557 | minute = mdhmsResult.minute,
558 | sec = mdhmsResult.sec;
559 | satrec.jdsatepoch = (0, _ext.jday)(year, mon, day, hr, minute, sec); // ---------------- initialize the orbit at sgp4epoch -------------------
560 |
561 | (0, _sgp4init.default)(satrec, {
562 | opsmode: opsmode,
563 | satn: satrec.satnum,
564 | epoch: satrec.jdsatepoch - 2433281.5,
565 | xbstar: satrec.bstar,
566 | xecco: satrec.ecco,
567 | xargpo: satrec.argpo,
568 | xinclo: satrec.inclo,
569 | xmo: satrec.mo,
570 | xno: satrec.no,
571 | xnodeo: satrec.nodeo
572 | });
573 | return satrec;
574 | }
575 | },{"./constants":2,"./ext":4,"./propagation/sgp4init":16}],7:[function(require,module,exports){
576 | /*!
577 | * satellite-js v3.0.1
578 | * (c) 2013 Shashwat Kandadai and UCSC
579 | * https://github.com/shashwatak/satellite-js
580 | * License: MIT
581 | */
582 |
583 | "use strict";
584 |
585 | Object.defineProperty(exports, "__esModule", {
586 | value: true
587 | });
588 | Object.defineProperty(exports, "propagate", {
589 | enumerable: true,
590 | get: function get() {
591 | return _propagate.default;
592 | }
593 | });
594 | Object.defineProperty(exports, "sgp4", {
595 | enumerable: true,
596 | get: function get() {
597 | return _sgp.default;
598 | }
599 | });
600 | Object.defineProperty(exports, "gstime", {
601 | enumerable: true,
602 | get: function get() {
603 | return _gstime.default;
604 | }
605 | });
606 |
607 | var _propagate = _interopRequireDefault(require("./propagation/propagate"));
608 |
609 | var _sgp = _interopRequireDefault(require("./propagation/sgp4"));
610 |
611 | var _gstime = _interopRequireDefault(require("./propagation/gstime"));
612 |
613 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
614 | },{"./propagation/gstime":12,"./propagation/propagate":14,"./propagation/sgp4":15}],8:[function(require,module,exports){
615 | /*!
616 | * satellite-js v3.0.1
617 | * (c) 2013 Shashwat Kandadai and UCSC
618 | * https://github.com/shashwatak/satellite-js
619 | * License: MIT
620 | */
621 |
622 | "use strict";
623 |
624 | Object.defineProperty(exports, "__esModule", {
625 | value: true
626 | });
627 | exports.default = dpper;
628 |
629 | var _constants = require("../constants");
630 |
631 | /* -----------------------------------------------------------------------------
632 | *
633 | * procedure dpper
634 | *
635 | * this procedure provides deep space long period periodic contributions
636 | * to the mean elements. by design, these periodics are zero at epoch.
637 | * this used to be dscom which included initialization, but it's really a
638 | * recurring function.
639 | *
640 | * author : david vallado 719-573-2600 28 jun 2005
641 | *
642 | * inputs :
643 | * e3 -
644 | * ee2 -
645 | * peo -
646 | * pgho -
647 | * pho -
648 | * pinco -
649 | * plo -
650 | * se2 , se3 , sgh2, sgh3, sgh4, sh2, sh3, si2, si3, sl2, sl3, sl4 -
651 | * t -
652 | * xh2, xh3, xi2, xi3, xl2, xl3, xl4 -
653 | * zmol -
654 | * zmos -
655 | * ep - eccentricity 0.0 - 1.0
656 | * inclo - inclination - needed for lyddane modification
657 | * nodep - right ascension of ascending node
658 | * argpp - argument of perigee
659 | * mp - mean anomaly
660 | *
661 | * outputs :
662 | * ep - eccentricity 0.0 - 1.0
663 | * inclp - inclination
664 | * nodep - right ascension of ascending node
665 | * argpp - argument of perigee
666 | * mp - mean anomaly
667 | *
668 | * locals :
669 | * alfdp -
670 | * betdp -
671 | * cosip , sinip , cosop , sinop ,
672 | * dalf -
673 | * dbet -
674 | * dls -
675 | * f2, f3 -
676 | * pe -
677 | * pgh -
678 | * ph -
679 | * pinc -
680 | * pl -
681 | * sel , ses , sghl , sghs , shl , shs , sil , sinzf , sis ,
682 | * sll , sls
683 | * xls -
684 | * xnoh -
685 | * zf -
686 | * zm -
687 | *
688 | * coupling :
689 | * none.
690 | *
691 | * references :
692 | * hoots, roehrich, norad spacetrack report #3 1980
693 | * hoots, norad spacetrack report #6 1986
694 | * hoots, schumacher and glover 2004
695 | * vallado, crawford, hujsak, kelso 2006
696 | ----------------------------------------------------------------------------*/
697 | function dpper(satrec, options) {
698 | var e3 = satrec.e3,
699 | ee2 = satrec.ee2,
700 | peo = satrec.peo,
701 | pgho = satrec.pgho,
702 | pho = satrec.pho,
703 | pinco = satrec.pinco,
704 | plo = satrec.plo,
705 | se2 = satrec.se2,
706 | se3 = satrec.se3,
707 | sgh2 = satrec.sgh2,
708 | sgh3 = satrec.sgh3,
709 | sgh4 = satrec.sgh4,
710 | sh2 = satrec.sh2,
711 | sh3 = satrec.sh3,
712 | si2 = satrec.si2,
713 | si3 = satrec.si3,
714 | sl2 = satrec.sl2,
715 | sl3 = satrec.sl3,
716 | sl4 = satrec.sl4,
717 | t = satrec.t,
718 | xgh2 = satrec.xgh2,
719 | xgh3 = satrec.xgh3,
720 | xgh4 = satrec.xgh4,
721 | xh2 = satrec.xh2,
722 | xh3 = satrec.xh3,
723 | xi2 = satrec.xi2,
724 | xi3 = satrec.xi3,
725 | xl2 = satrec.xl2,
726 | xl3 = satrec.xl3,
727 | xl4 = satrec.xl4,
728 | zmol = satrec.zmol,
729 | zmos = satrec.zmos;
730 | var init = options.init,
731 | opsmode = options.opsmode;
732 | var ep = options.ep,
733 | inclp = options.inclp,
734 | nodep = options.nodep,
735 | argpp = options.argpp,
736 | mp = options.mp; // Copy satellite attributes into local variables for convenience
737 | // and symmetry in writing formulae.
738 |
739 | var alfdp;
740 | var betdp;
741 | var cosip;
742 | var sinip;
743 | var cosop;
744 | var sinop;
745 | var dalf;
746 | var dbet;
747 | var dls;
748 | var f2;
749 | var f3;
750 | var pe;
751 | var pgh;
752 | var ph;
753 | var pinc;
754 | var pl;
755 | var sinzf;
756 | var xls;
757 | var xnoh;
758 | var zf;
759 | var zm; // ---------------------- constants -----------------------------
760 |
761 | var zns = 1.19459e-5;
762 | var zes = 0.01675;
763 | var znl = 1.5835218e-4;
764 | var zel = 0.05490; // --------------- calculate time varying periodics -----------
765 |
766 | zm = zmos + zns * t; // be sure that the initial call has time set to zero
767 |
768 | if (init === 'y') {
769 | zm = zmos;
770 | }
771 |
772 | zf = zm + 2.0 * zes * Math.sin(zm);
773 | sinzf = Math.sin(zf);
774 | f2 = 0.5 * sinzf * sinzf - 0.25;
775 | f3 = -0.5 * sinzf * Math.cos(zf);
776 | var ses = se2 * f2 + se3 * f3;
777 | var sis = si2 * f2 + si3 * f3;
778 | var sls = sl2 * f2 + sl3 * f3 + sl4 * sinzf;
779 | var sghs = sgh2 * f2 + sgh3 * f3 + sgh4 * sinzf;
780 | var shs = sh2 * f2 + sh3 * f3;
781 | zm = zmol + znl * t;
782 |
783 | if (init === 'y') {
784 | zm = zmol;
785 | }
786 |
787 | zf = zm + 2.0 * zel * Math.sin(zm);
788 | sinzf = Math.sin(zf);
789 | f2 = 0.5 * sinzf * sinzf - 0.25;
790 | f3 = -0.5 * sinzf * Math.cos(zf);
791 | var sel = ee2 * f2 + e3 * f3;
792 | var sil = xi2 * f2 + xi3 * f3;
793 | var sll = xl2 * f2 + xl3 * f3 + xl4 * sinzf;
794 | var sghl = xgh2 * f2 + xgh3 * f3 + xgh4 * sinzf;
795 | var shll = xh2 * f2 + xh3 * f3;
796 | pe = ses + sel;
797 | pinc = sis + sil;
798 | pl = sls + sll;
799 | pgh = sghs + sghl;
800 | ph = shs + shll;
801 |
802 | if (init === 'n') {
803 | pe -= peo;
804 | pinc -= pinco;
805 | pl -= plo;
806 | pgh -= pgho;
807 | ph -= pho;
808 | inclp += pinc;
809 | ep += pe;
810 | sinip = Math.sin(inclp);
811 | cosip = Math.cos(inclp);
812 | /* ----------------- apply periodics directly ------------ */
813 | // sgp4fix for lyddane choice
814 | // strn3 used original inclination - this is technically feasible
815 | // gsfc used perturbed inclination - also technically feasible
816 | // probably best to readjust the 0.2 limit value and limit discontinuity
817 | // 0.2 rad = 11.45916 deg
818 | // use next line for original strn3 approach and original inclination
819 | // if (inclo >= 0.2)
820 | // use next line for gsfc version and perturbed inclination
821 |
822 | if (inclp >= 0.2) {
823 | ph /= sinip;
824 | pgh -= cosip * ph;
825 | argpp += pgh;
826 | nodep += ph;
827 | mp += pl;
828 | } else {
829 | // ---- apply periodics with lyddane modification ----
830 | sinop = Math.sin(nodep);
831 | cosop = Math.cos(nodep);
832 | alfdp = sinip * sinop;
833 | betdp = sinip * cosop;
834 | dalf = ph * cosop + pinc * cosip * sinop;
835 | dbet = -ph * sinop + pinc * cosip * cosop;
836 | alfdp += dalf;
837 | betdp += dbet;
838 | nodep %= _constants.twoPi; // sgp4fix for afspc written intrinsic functions
839 | // nodep used without a trigonometric function ahead
840 |
841 | if (nodep < 0.0 && opsmode === 'a') {
842 | nodep += _constants.twoPi;
843 | }
844 |
845 | xls = mp + argpp + cosip * nodep;
846 | dls = pl + pgh - pinc * nodep * sinip;
847 | xls += dls;
848 | xnoh = nodep;
849 | nodep = Math.atan2(alfdp, betdp); // sgp4fix for afspc written intrinsic functions
850 | // nodep used without a trigonometric function ahead
851 |
852 | if (nodep < 0.0 && opsmode === 'a') {
853 | nodep += _constants.twoPi;
854 | }
855 |
856 | if (Math.abs(xnoh - nodep) > _constants.pi) {
857 | if (nodep < xnoh) {
858 | nodep += _constants.twoPi;
859 | } else {
860 | nodep -= _constants.twoPi;
861 | }
862 | }
863 |
864 | mp += pl;
865 | argpp = xls - mp - cosip * nodep;
866 | }
867 | }
868 |
869 | return {
870 | ep: ep,
871 | inclp: inclp,
872 | nodep: nodep,
873 | argpp: argpp,
874 | mp: mp
875 | };
876 | }
877 | },{"../constants":2}],9:[function(require,module,exports){
878 | /*!
879 | * satellite-js v3.0.1
880 | * (c) 2013 Shashwat Kandadai and UCSC
881 | * https://github.com/shashwatak/satellite-js
882 | * License: MIT
883 | */
884 |
885 | "use strict";
886 |
887 | Object.defineProperty(exports, "__esModule", {
888 | value: true
889 | });
890 | exports.default = dscom;
891 |
892 | var _constants = require("../constants");
893 |
894 | /*-----------------------------------------------------------------------------
895 | *
896 | * procedure dscom
897 | *
898 | * this procedure provides deep space common items used by both the secular
899 | * and periodics subroutines. input is provided as shown. this routine
900 | * used to be called dpper, but the functions inside weren't well organized.
901 | *
902 | * author : david vallado 719-573-2600 28 jun 2005
903 | *
904 | * inputs :
905 | * epoch -
906 | * ep - eccentricity
907 | * argpp - argument of perigee
908 | * tc -
909 | * inclp - inclination
910 | * nodep - right ascension of ascending node
911 | * np - mean motion
912 | *
913 | * outputs :
914 | * sinim , cosim , sinomm , cosomm , snodm , cnodm
915 | * day -
916 | * e3 -
917 | * ee2 -
918 | * em - eccentricity
919 | * emsq - eccentricity squared
920 | * gam -
921 | * peo -
922 | * pgho -
923 | * pho -
924 | * pinco -
925 | * plo -
926 | * rtemsq -
927 | * se2, se3 -
928 | * sgh2, sgh3, sgh4 -
929 | * sh2, sh3, si2, si3, sl2, sl3, sl4 -
930 | * s1, s2, s3, s4, s5, s6, s7 -
931 | * ss1, ss2, ss3, ss4, ss5, ss6, ss7, sz1, sz2, sz3 -
932 | * sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33 -
933 | * xgh2, xgh3, xgh4, xh2, xh3, xi2, xi3, xl2, xl3, xl4 -
934 | * nm - mean motion
935 | * z1, z2, z3, z11, z12, z13, z21, z22, z23, z31, z32, z33 -
936 | * zmol -
937 | * zmos -
938 | *
939 | * locals :
940 | * a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 -
941 | * betasq -
942 | * cc -
943 | * ctem, stem -
944 | * x1, x2, x3, x4, x5, x6, x7, x8 -
945 | * xnodce -
946 | * xnoi -
947 | * zcosg , zsing , zcosgl , zsingl , zcosh , zsinh , zcoshl , zsinhl ,
948 | * zcosi , zsini , zcosil , zsinil ,
949 | * zx -
950 | * zy -
951 | *
952 | * coupling :
953 | * none.
954 | *
955 | * references :
956 | * hoots, roehrich, norad spacetrack report #3 1980
957 | * hoots, norad spacetrack report #6 1986
958 | * hoots, schumacher and glover 2004
959 | * vallado, crawford, hujsak, kelso 2006
960 | ----------------------------------------------------------------------------*/
961 | function dscom(options) {
962 | var epoch = options.epoch,
963 | ep = options.ep,
964 | argpp = options.argpp,
965 | tc = options.tc,
966 | inclp = options.inclp,
967 | nodep = options.nodep,
968 | np = options.np;
969 | var a1;
970 | var a2;
971 | var a3;
972 | var a4;
973 | var a5;
974 | var a6;
975 | var a7;
976 | var a8;
977 | var a9;
978 | var a10;
979 | var cc;
980 | var x1;
981 | var x2;
982 | var x3;
983 | var x4;
984 | var x5;
985 | var x6;
986 | var x7;
987 | var x8;
988 | var zcosg;
989 | var zsing;
990 | var zcosh;
991 | var zsinh;
992 | var zcosi;
993 | var zsini;
994 | var ss1;
995 | var ss2;
996 | var ss3;
997 | var ss4;
998 | var ss5;
999 | var ss6;
1000 | var ss7;
1001 | var sz1;
1002 | var sz2;
1003 | var sz3;
1004 | var sz11;
1005 | var sz12;
1006 | var sz13;
1007 | var sz21;
1008 | var sz22;
1009 | var sz23;
1010 | var sz31;
1011 | var sz32;
1012 | var sz33;
1013 | var s1;
1014 | var s2;
1015 | var s3;
1016 | var s4;
1017 | var s5;
1018 | var s6;
1019 | var s7;
1020 | var z1;
1021 | var z2;
1022 | var z3;
1023 | var z11;
1024 | var z12;
1025 | var z13;
1026 | var z21;
1027 | var z22;
1028 | var z23;
1029 | var z31;
1030 | var z32;
1031 | var z33; // -------------------------- constants -------------------------
1032 |
1033 | var zes = 0.01675;
1034 | var zel = 0.05490;
1035 | var c1ss = 2.9864797e-6;
1036 | var c1l = 4.7968065e-7;
1037 | var zsinis = 0.39785416;
1038 | var zcosis = 0.91744867;
1039 | var zcosgs = 0.1945905;
1040 | var zsings = -0.98088458; // --------------------- local variables ------------------------
1041 |
1042 | var nm = np;
1043 | var em = ep;
1044 | var snodm = Math.sin(nodep);
1045 | var cnodm = Math.cos(nodep);
1046 | var sinomm = Math.sin(argpp);
1047 | var cosomm = Math.cos(argpp);
1048 | var sinim = Math.sin(inclp);
1049 | var cosim = Math.cos(inclp);
1050 | var emsq = em * em;
1051 | var betasq = 1.0 - emsq;
1052 | var rtemsq = Math.sqrt(betasq); // ----------------- initialize lunar solar terms ---------------
1053 |
1054 | var peo = 0.0;
1055 | var pinco = 0.0;
1056 | var plo = 0.0;
1057 | var pgho = 0.0;
1058 | var pho = 0.0;
1059 | var day = epoch + 18261.5 + tc / 1440.0;
1060 | var xnodce = (4.5236020 - 9.2422029e-4 * day) % _constants.twoPi;
1061 | var stem = Math.sin(xnodce);
1062 | var ctem = Math.cos(xnodce);
1063 | var zcosil = 0.91375164 - 0.03568096 * ctem;
1064 | var zsinil = Math.sqrt(1.0 - zcosil * zcosil);
1065 | var zsinhl = 0.089683511 * stem / zsinil;
1066 | var zcoshl = Math.sqrt(1.0 - zsinhl * zsinhl);
1067 | var gam = 5.8351514 + 0.0019443680 * day;
1068 | var zx = 0.39785416 * stem / zsinil;
1069 | var zy = zcoshl * ctem + 0.91744867 * zsinhl * stem;
1070 | zx = Math.atan2(zx, zy);
1071 | zx += gam - xnodce;
1072 | var zcosgl = Math.cos(zx);
1073 | var zsingl = Math.sin(zx); // ------------------------- do solar terms ---------------------
1074 |
1075 | zcosg = zcosgs;
1076 | zsing = zsings;
1077 | zcosi = zcosis;
1078 | zsini = zsinis;
1079 | zcosh = cnodm;
1080 | zsinh = snodm;
1081 | cc = c1ss;
1082 | var xnoi = 1.0 / nm;
1083 | var lsflg = 0;
1084 |
1085 | while (lsflg < 2) {
1086 | lsflg += 1;
1087 | a1 = zcosg * zcosh + zsing * zcosi * zsinh;
1088 | a3 = -zsing * zcosh + zcosg * zcosi * zsinh;
1089 | a7 = -zcosg * zsinh + zsing * zcosi * zcosh;
1090 | a8 = zsing * zsini;
1091 | a9 = zsing * zsinh + zcosg * zcosi * zcosh;
1092 | a10 = zcosg * zsini;
1093 | a2 = cosim * a7 + sinim * a8;
1094 | a4 = cosim * a9 + sinim * a10;
1095 | a5 = -sinim * a7 + cosim * a8;
1096 | a6 = -sinim * a9 + cosim * a10;
1097 | x1 = a1 * cosomm + a2 * sinomm;
1098 | x2 = a3 * cosomm + a4 * sinomm;
1099 | x3 = -a1 * sinomm + a2 * cosomm;
1100 | x4 = -a3 * sinomm + a4 * cosomm;
1101 | x5 = a5 * sinomm;
1102 | x6 = a6 * sinomm;
1103 | x7 = a5 * cosomm;
1104 | x8 = a6 * cosomm;
1105 | z31 = 12.0 * x1 * x1 - 3.0 * x3 * x3;
1106 | z32 = 24.0 * x1 * x2 - 6.0 * x3 * x4;
1107 | z33 = 12.0 * x2 * x2 - 3.0 * x4 * x4;
1108 | z1 = 3.0 * (a1 * a1 + a2 * a2) + z31 * emsq;
1109 | z2 = 6.0 * (a1 * a3 + a2 * a4) + z32 * emsq;
1110 | z3 = 3.0 * (a3 * a3 + a4 * a4) + z33 * emsq;
1111 | z11 = -6.0 * a1 * a5 + emsq * (-24.0 * x1 * x7 - 6.0 * x3 * x5);
1112 | z12 = -6.0 * (a1 * a6 + a3 * a5) + emsq * (-24.0 * (x2 * x7 + x1 * x8) + -6.0 * (x3 * x6 + x4 * x5));
1113 | z13 = -6.0 * a3 * a6 + emsq * (-24.0 * x2 * x8 - 6.0 * x4 * x6);
1114 | z21 = 6.0 * a2 * a5 + emsq * (24.0 * x1 * x5 - 6.0 * x3 * x7);
1115 | z22 = 6.0 * (a4 * a5 + a2 * a6) + emsq * (24.0 * (x2 * x5 + x1 * x6) - 6.0 * (x4 * x7 + x3 * x8));
1116 | z23 = 6.0 * a4 * a6 + emsq * (24.0 * x2 * x6 - 6.0 * x4 * x8);
1117 | z1 = z1 + z1 + betasq * z31;
1118 | z2 = z2 + z2 + betasq * z32;
1119 | z3 = z3 + z3 + betasq * z33;
1120 | s3 = cc * xnoi;
1121 | s2 = -0.5 * s3 / rtemsq;
1122 | s4 = s3 * rtemsq;
1123 | s1 = -15.0 * em * s4;
1124 | s5 = x1 * x3 + x2 * x4;
1125 | s6 = x2 * x3 + x1 * x4;
1126 | s7 = x2 * x4 - x1 * x3; // ----------------------- do lunar terms -------------------
1127 |
1128 | if (lsflg === 1) {
1129 | ss1 = s1;
1130 | ss2 = s2;
1131 | ss3 = s3;
1132 | ss4 = s4;
1133 | ss5 = s5;
1134 | ss6 = s6;
1135 | ss7 = s7;
1136 | sz1 = z1;
1137 | sz2 = z2;
1138 | sz3 = z3;
1139 | sz11 = z11;
1140 | sz12 = z12;
1141 | sz13 = z13;
1142 | sz21 = z21;
1143 | sz22 = z22;
1144 | sz23 = z23;
1145 | sz31 = z31;
1146 | sz32 = z32;
1147 | sz33 = z33;
1148 | zcosg = zcosgl;
1149 | zsing = zsingl;
1150 | zcosi = zcosil;
1151 | zsini = zsinil;
1152 | zcosh = zcoshl * cnodm + zsinhl * snodm;
1153 | zsinh = snodm * zcoshl - cnodm * zsinhl;
1154 | cc = c1l;
1155 | }
1156 | }
1157 |
1158 | var zmol = (4.7199672 + (0.22997150 * day - gam)) % _constants.twoPi;
1159 | var zmos = (6.2565837 + 0.017201977 * day) % _constants.twoPi; // ------------------------ do solar terms ----------------------
1160 |
1161 | var se2 = 2.0 * ss1 * ss6;
1162 | var se3 = 2.0 * ss1 * ss7;
1163 | var si2 = 2.0 * ss2 * sz12;
1164 | var si3 = 2.0 * ss2 * (sz13 - sz11);
1165 | var sl2 = -2.0 * ss3 * sz2;
1166 | var sl3 = -2.0 * ss3 * (sz3 - sz1);
1167 | var sl4 = -2.0 * ss3 * (-21.0 - 9.0 * emsq) * zes;
1168 | var sgh2 = 2.0 * ss4 * sz32;
1169 | var sgh3 = 2.0 * ss4 * (sz33 - sz31);
1170 | var sgh4 = -18.0 * ss4 * zes;
1171 | var sh2 = -2.0 * ss2 * sz22;
1172 | var sh3 = -2.0 * ss2 * (sz23 - sz21); // ------------------------ do lunar terms ----------------------
1173 |
1174 | var ee2 = 2.0 * s1 * s6;
1175 | var e3 = 2.0 * s1 * s7;
1176 | var xi2 = 2.0 * s2 * z12;
1177 | var xi3 = 2.0 * s2 * (z13 - z11);
1178 | var xl2 = -2.0 * s3 * z2;
1179 | var xl3 = -2.0 * s3 * (z3 - z1);
1180 | var xl4 = -2.0 * s3 * (-21.0 - 9.0 * emsq) * zel;
1181 | var xgh2 = 2.0 * s4 * z32;
1182 | var xgh3 = 2.0 * s4 * (z33 - z31);
1183 | var xgh4 = -18.0 * s4 * zel;
1184 | var xh2 = -2.0 * s2 * z22;
1185 | var xh3 = -2.0 * s2 * (z23 - z21);
1186 | return {
1187 | snodm: snodm,
1188 | cnodm: cnodm,
1189 | sinim: sinim,
1190 | cosim: cosim,
1191 | sinomm: sinomm,
1192 | cosomm: cosomm,
1193 | day: day,
1194 | e3: e3,
1195 | ee2: ee2,
1196 | em: em,
1197 | emsq: emsq,
1198 | gam: gam,
1199 | peo: peo,
1200 | pgho: pgho,
1201 | pho: pho,
1202 | pinco: pinco,
1203 | plo: plo,
1204 | rtemsq: rtemsq,
1205 | se2: se2,
1206 | se3: se3,
1207 | sgh2: sgh2,
1208 | sgh3: sgh3,
1209 | sgh4: sgh4,
1210 | sh2: sh2,
1211 | sh3: sh3,
1212 | si2: si2,
1213 | si3: si3,
1214 | sl2: sl2,
1215 | sl3: sl3,
1216 | sl4: sl4,
1217 | s1: s1,
1218 | s2: s2,
1219 | s3: s3,
1220 | s4: s4,
1221 | s5: s5,
1222 | s6: s6,
1223 | s7: s7,
1224 | ss1: ss1,
1225 | ss2: ss2,
1226 | ss3: ss3,
1227 | ss4: ss4,
1228 | ss5: ss5,
1229 | ss6: ss6,
1230 | ss7: ss7,
1231 | sz1: sz1,
1232 | sz2: sz2,
1233 | sz3: sz3,
1234 | sz11: sz11,
1235 | sz12: sz12,
1236 | sz13: sz13,
1237 | sz21: sz21,
1238 | sz22: sz22,
1239 | sz23: sz23,
1240 | sz31: sz31,
1241 | sz32: sz32,
1242 | sz33: sz33,
1243 | xgh2: xgh2,
1244 | xgh3: xgh3,
1245 | xgh4: xgh4,
1246 | xh2: xh2,
1247 | xh3: xh3,
1248 | xi2: xi2,
1249 | xi3: xi3,
1250 | xl2: xl2,
1251 | xl3: xl3,
1252 | xl4: xl4,
1253 | nm: nm,
1254 | z1: z1,
1255 | z2: z2,
1256 | z3: z3,
1257 | z11: z11,
1258 | z12: z12,
1259 | z13: z13,
1260 | z21: z21,
1261 | z22: z22,
1262 | z23: z23,
1263 | z31: z31,
1264 | z32: z32,
1265 | z33: z33,
1266 | zmol: zmol,
1267 | zmos: zmos
1268 | };
1269 | }
1270 | },{"../constants":2}],10:[function(require,module,exports){
1271 | /*!
1272 | * satellite-js v3.0.1
1273 | * (c) 2013 Shashwat Kandadai and UCSC
1274 | * https://github.com/shashwatak/satellite-js
1275 | * License: MIT
1276 | */
1277 |
1278 | "use strict";
1279 |
1280 | Object.defineProperty(exports, "__esModule", {
1281 | value: true
1282 | });
1283 | exports.default = dsinit;
1284 |
1285 | var _constants = require("../constants");
1286 |
1287 | /*-----------------------------------------------------------------------------
1288 | *
1289 | * procedure dsinit
1290 | *
1291 | * this procedure provides deep space contributions to mean motion dot due
1292 | * to geopotential resonance with half day and one day orbits.
1293 | *
1294 | * author : david vallado 719-573-2600 28 jun 2005
1295 | *
1296 | * inputs :
1297 | * cosim, sinim-
1298 | * emsq - eccentricity squared
1299 | * argpo - argument of perigee
1300 | * s1, s2, s3, s4, s5 -
1301 | * ss1, ss2, ss3, ss4, ss5 -
1302 | * sz1, sz3, sz11, sz13, sz21, sz23, sz31, sz33 -
1303 | * t - time
1304 | * tc -
1305 | * gsto - greenwich sidereal time rad
1306 | * mo - mean anomaly
1307 | * mdot - mean anomaly dot (rate)
1308 | * no - mean motion
1309 | * nodeo - right ascension of ascending node
1310 | * nodedot - right ascension of ascending node dot (rate)
1311 | * xpidot -
1312 | * z1, z3, z11, z13, z21, z23, z31, z33 -
1313 | * eccm - eccentricity
1314 | * argpm - argument of perigee
1315 | * inclm - inclination
1316 | * mm - mean anomaly
1317 | * xn - mean motion
1318 | * nodem - right ascension of ascending node
1319 | *
1320 | * outputs :
1321 | * em - eccentricity
1322 | * argpm - argument of perigee
1323 | * inclm - inclination
1324 | * mm - mean anomaly
1325 | * nm - mean motion
1326 | * nodem - right ascension of ascending node
1327 | * irez - flag for resonance 0-none, 1-one day, 2-half day
1328 | * atime -
1329 | * d2201, d2211, d3210, d3222, d4410, d4422, d5220, d5232, d5421, d5433 -
1330 | * dedt -
1331 | * didt -
1332 | * dmdt -
1333 | * dndt -
1334 | * dnodt -
1335 | * domdt -
1336 | * del1, del2, del3 -
1337 | * ses , sghl , sghs , sgs , shl , shs , sis , sls
1338 | * theta -
1339 | * xfact -
1340 | * xlamo -
1341 | * xli -
1342 | * xni
1343 | *
1344 | * locals :
1345 | * ainv2 -
1346 | * aonv -
1347 | * cosisq -
1348 | * eoc -
1349 | * f220, f221, f311, f321, f322, f330, f441, f442, f522, f523, f542, f543 -
1350 | * g200, g201, g211, g300, g310, g322, g410, g422, g520, g521, g532, g533 -
1351 | * sini2 -
1352 | * temp -
1353 | * temp1 -
1354 | * theta -
1355 | * xno2 -
1356 | *
1357 | * coupling :
1358 | * getgravconst
1359 | *
1360 | * references :
1361 | * hoots, roehrich, norad spacetrack report #3 1980
1362 | * hoots, norad spacetrack report #6 1986
1363 | * hoots, schumacher and glover 2004
1364 | * vallado, crawford, hujsak, kelso 2006
1365 | ----------------------------------------------------------------------------*/
1366 | function dsinit(options) {
1367 | var cosim = options.cosim,
1368 | argpo = options.argpo,
1369 | s1 = options.s1,
1370 | s2 = options.s2,
1371 | s3 = options.s3,
1372 | s4 = options.s4,
1373 | s5 = options.s5,
1374 | sinim = options.sinim,
1375 | ss1 = options.ss1,
1376 | ss2 = options.ss2,
1377 | ss3 = options.ss3,
1378 | ss4 = options.ss4,
1379 | ss5 = options.ss5,
1380 | sz1 = options.sz1,
1381 | sz3 = options.sz3,
1382 | sz11 = options.sz11,
1383 | sz13 = options.sz13,
1384 | sz21 = options.sz21,
1385 | sz23 = options.sz23,
1386 | sz31 = options.sz31,
1387 | sz33 = options.sz33,
1388 | t = options.t,
1389 | tc = options.tc,
1390 | gsto = options.gsto,
1391 | mo = options.mo,
1392 | mdot = options.mdot,
1393 | no = options.no,
1394 | nodeo = options.nodeo,
1395 | nodedot = options.nodedot,
1396 | xpidot = options.xpidot,
1397 | z1 = options.z1,
1398 | z3 = options.z3,
1399 | z11 = options.z11,
1400 | z13 = options.z13,
1401 | z21 = options.z21,
1402 | z23 = options.z23,
1403 | z31 = options.z31,
1404 | z33 = options.z33,
1405 | ecco = options.ecco,
1406 | eccsq = options.eccsq;
1407 | var emsq = options.emsq,
1408 | em = options.em,
1409 | argpm = options.argpm,
1410 | inclm = options.inclm,
1411 | mm = options.mm,
1412 | nm = options.nm,
1413 | nodem = options.nodem,
1414 | irez = options.irez,
1415 | atime = options.atime,
1416 | d2201 = options.d2201,
1417 | d2211 = options.d2211,
1418 | d3210 = options.d3210,
1419 | d3222 = options.d3222,
1420 | d4410 = options.d4410,
1421 | d4422 = options.d4422,
1422 | d5220 = options.d5220,
1423 | d5232 = options.d5232,
1424 | d5421 = options.d5421,
1425 | d5433 = options.d5433,
1426 | dedt = options.dedt,
1427 | didt = options.didt,
1428 | dmdt = options.dmdt,
1429 | dnodt = options.dnodt,
1430 | domdt = options.domdt,
1431 | del1 = options.del1,
1432 | del2 = options.del2,
1433 | del3 = options.del3,
1434 | xfact = options.xfact,
1435 | xlamo = options.xlamo,
1436 | xli = options.xli,
1437 | xni = options.xni;
1438 | var f220;
1439 | var f221;
1440 | var f311;
1441 | var f321;
1442 | var f322;
1443 | var f330;
1444 | var f441;
1445 | var f442;
1446 | var f522;
1447 | var f523;
1448 | var f542;
1449 | var f543;
1450 | var g200;
1451 | var g201;
1452 | var g211;
1453 | var g300;
1454 | var g310;
1455 | var g322;
1456 | var g410;
1457 | var g422;
1458 | var g520;
1459 | var g521;
1460 | var g532;
1461 | var g533;
1462 | var sini2;
1463 | var temp;
1464 | var temp1;
1465 | var xno2;
1466 | var ainv2;
1467 | var aonv;
1468 | var cosisq;
1469 | var eoc;
1470 | var q22 = 1.7891679e-6;
1471 | var q31 = 2.1460748e-6;
1472 | var q33 = 2.2123015e-7;
1473 | var root22 = 1.7891679e-6;
1474 | var root44 = 7.3636953e-9;
1475 | var root54 = 2.1765803e-9;
1476 | var rptim = 4.37526908801129966e-3; // equates to 7.29211514668855e-5 rad/sec
1477 |
1478 | var root32 = 3.7393792e-7;
1479 | var root52 = 1.1428639e-7;
1480 | var znl = 1.5835218e-4;
1481 | var zns = 1.19459e-5; // -------------------- deep space initialization ------------
1482 |
1483 | irez = 0;
1484 |
1485 | if (nm < 0.0052359877 && nm > 0.0034906585) {
1486 | irez = 1;
1487 | }
1488 |
1489 | if (nm >= 8.26e-3 && nm <= 9.24e-3 && em >= 0.5) {
1490 | irez = 2;
1491 | } // ------------------------ do solar terms -------------------
1492 |
1493 |
1494 | var ses = ss1 * zns * ss5;
1495 | var sis = ss2 * zns * (sz11 + sz13);
1496 | var sls = -zns * ss3 * (sz1 + sz3 - 14.0 - 6.0 * emsq);
1497 | var sghs = ss4 * zns * (sz31 + sz33 - 6.0);
1498 | var shs = -zns * ss2 * (sz21 + sz23); // sgp4fix for 180 deg incl
1499 |
1500 | if (inclm < 5.2359877e-2 || inclm > _constants.pi - 5.2359877e-2) {
1501 | shs = 0.0;
1502 | }
1503 |
1504 | if (sinim !== 0.0) {
1505 | shs /= sinim;
1506 | }
1507 |
1508 | var sgs = sghs - cosim * shs; // ------------------------- do lunar terms ------------------
1509 |
1510 | dedt = ses + s1 * znl * s5;
1511 | didt = sis + s2 * znl * (z11 + z13);
1512 | dmdt = sls - znl * s3 * (z1 + z3 - 14.0 - 6.0 * emsq);
1513 | var sghl = s4 * znl * (z31 + z33 - 6.0);
1514 | var shll = -znl * s2 * (z21 + z23); // sgp4fix for 180 deg incl
1515 |
1516 | if (inclm < 5.2359877e-2 || inclm > _constants.pi - 5.2359877e-2) {
1517 | shll = 0.0;
1518 | }
1519 |
1520 | domdt = sgs + sghl;
1521 | dnodt = shs;
1522 |
1523 | if (sinim !== 0.0) {
1524 | domdt -= cosim / sinim * shll;
1525 | dnodt += shll / sinim;
1526 | } // ----------- calculate deep space resonance effects --------
1527 |
1528 |
1529 | var dndt = 0.0;
1530 | var theta = (gsto + tc * rptim) % _constants.twoPi;
1531 | em += dedt * t;
1532 | inclm += didt * t;
1533 | argpm += domdt * t;
1534 | nodem += dnodt * t;
1535 | mm += dmdt * t; // sgp4fix for negative inclinations
1536 | // the following if statement should be commented out
1537 | // if (inclm < 0.0)
1538 | // {
1539 | // inclm = -inclm;
1540 | // argpm = argpm - pi;
1541 | // nodem = nodem + pi;
1542 | // }
1543 | // -------------- initialize the resonance terms -------------
1544 |
1545 | if (irez !== 0) {
1546 | aonv = Math.pow(nm / _constants.xke, _constants.x2o3); // ---------- geopotential resonance for 12 hour orbits ------
1547 |
1548 | if (irez === 2) {
1549 | cosisq = cosim * cosim;
1550 | var emo = em;
1551 | em = ecco;
1552 | var emsqo = emsq;
1553 | emsq = eccsq;
1554 | eoc = em * emsq;
1555 | g201 = -0.306 - (em - 0.64) * 0.440;
1556 |
1557 | if (em <= 0.65) {
1558 | g211 = 3.616 - 13.2470 * em + 16.2900 * emsq;
1559 | g310 = -19.302 + 117.3900 * em - 228.4190 * emsq + 156.5910 * eoc;
1560 | g322 = -18.9068 + 109.7927 * em - 214.6334 * emsq + 146.5816 * eoc;
1561 | g410 = -41.122 + 242.6940 * em - 471.0940 * emsq + 313.9530 * eoc;
1562 | g422 = -146.407 + 841.8800 * em - 1629.014 * emsq + 1083.4350 * eoc;
1563 | g520 = -532.114 + 3017.977 * em - 5740.032 * emsq + 3708.2760 * eoc;
1564 | } else {
1565 | g211 = -72.099 + 331.819 * em - 508.738 * emsq + 266.724 * eoc;
1566 | g310 = -346.844 + 1582.851 * em - 2415.925 * emsq + 1246.113 * eoc;
1567 | g322 = -342.585 + 1554.908 * em - 2366.899 * emsq + 1215.972 * eoc;
1568 | g410 = -1052.797 + 4758.686 * em - 7193.992 * emsq + 3651.957 * eoc;
1569 | g422 = -3581.690 + 16178.110 * em - 24462.770 * emsq + 12422.520 * eoc;
1570 |
1571 | if (em > 0.715) {
1572 | g520 = -5149.66 + 29936.92 * em - 54087.36 * emsq + 31324.56 * eoc;
1573 | } else {
1574 | g520 = 1464.74 - 4664.75 * em + 3763.64 * emsq;
1575 | }
1576 | }
1577 |
1578 | if (em < 0.7) {
1579 | g533 = -919.22770 + 4988.6100 * em - 9064.7700 * emsq + 5542.21 * eoc;
1580 | g521 = -822.71072 + 4568.6173 * em - 8491.4146 * emsq + 5337.524 * eoc;
1581 | g532 = -853.66600 + 4690.2500 * em - 8624.7700 * emsq + 5341.4 * eoc;
1582 | } else {
1583 | g533 = -37995.780 + 161616.52 * em - 229838.20 * emsq + 109377.94 * eoc;
1584 | g521 = -51752.104 + 218913.95 * em - 309468.16 * emsq + 146349.42 * eoc;
1585 | g532 = -40023.880 + 170470.89 * em - 242699.48 * emsq + 115605.82 * eoc;
1586 | }
1587 |
1588 | sini2 = sinim * sinim;
1589 | f220 = 0.75 * (1.0 + 2.0 * cosim + cosisq);
1590 | f221 = 1.5 * sini2;
1591 | f321 = 1.875 * sinim * (1.0 - 2.0 * cosim - 3.0 * cosisq);
1592 | f322 = -1.875 * sinim * (1.0 + 2.0 * cosim - 3.0 * cosisq);
1593 | f441 = 35.0 * sini2 * f220;
1594 | f442 = 39.3750 * sini2 * sini2;
1595 | f522 = 9.84375 * sinim * (sini2 * (1.0 - 2.0 * cosim - 5.0 * cosisq) + 0.33333333 * (-2.0 + 4.0 * cosim + 6.0 * cosisq));
1596 | f523 = sinim * (4.92187512 * sini2 * (-2.0 - 4.0 * cosim + 10.0 * cosisq) + 6.56250012 * (1.0 + 2.0 * cosim - 3.0 * cosisq));
1597 | f542 = 29.53125 * sinim * (2.0 - 8.0 * cosim + cosisq * (-12.0 + 8.0 * cosim + 10.0 * cosisq));
1598 | f543 = 29.53125 * sinim * (-2.0 - 8.0 * cosim + cosisq * (12.0 + 8.0 * cosim - 10.0 * cosisq));
1599 | xno2 = nm * nm;
1600 | ainv2 = aonv * aonv;
1601 | temp1 = 3.0 * xno2 * ainv2;
1602 | temp = temp1 * root22;
1603 | d2201 = temp * f220 * g201;
1604 | d2211 = temp * f221 * g211;
1605 | temp1 *= aonv;
1606 | temp = temp1 * root32;
1607 | d3210 = temp * f321 * g310;
1608 | d3222 = temp * f322 * g322;
1609 | temp1 *= aonv;
1610 | temp = 2.0 * temp1 * root44;
1611 | d4410 = temp * f441 * g410;
1612 | d4422 = temp * f442 * g422;
1613 | temp1 *= aonv;
1614 | temp = temp1 * root52;
1615 | d5220 = temp * f522 * g520;
1616 | d5232 = temp * f523 * g532;
1617 | temp = 2.0 * temp1 * root54;
1618 | d5421 = temp * f542 * g521;
1619 | d5433 = temp * f543 * g533;
1620 | xlamo = (mo + nodeo + nodeo - (theta + theta)) % _constants.twoPi;
1621 | xfact = mdot + dmdt + 2.0 * (nodedot + dnodt - rptim) - no;
1622 | em = emo;
1623 | emsq = emsqo;
1624 | } // ---------------- synchronous resonance terms --------------
1625 |
1626 |
1627 | if (irez === 1) {
1628 | g200 = 1.0 + emsq * (-2.5 + 0.8125 * emsq);
1629 | g310 = 1.0 + 2.0 * emsq;
1630 | g300 = 1.0 + emsq * (-6.0 + 6.60937 * emsq);
1631 | f220 = 0.75 * (1.0 + cosim) * (1.0 + cosim);
1632 | f311 = 0.9375 * sinim * sinim * (1.0 + 3.0 * cosim) - 0.75 * (1.0 + cosim);
1633 | f330 = 1.0 + cosim;
1634 | f330 *= 1.875 * f330 * f330;
1635 | del1 = 3.0 * nm * nm * aonv * aonv;
1636 | del2 = 2.0 * del1 * f220 * g200 * q22;
1637 | del3 = 3.0 * del1 * f330 * g300 * q33 * aonv;
1638 | del1 = del1 * f311 * g310 * q31 * aonv;
1639 | xlamo = (mo + nodeo + argpo - theta) % _constants.twoPi;
1640 | xfact = mdot + xpidot + dmdt + domdt + dnodt - (no + rptim);
1641 | } // ------------ for sgp4, initialize the integrator ----------
1642 |
1643 |
1644 | xli = xlamo;
1645 | xni = no;
1646 | atime = 0.0;
1647 | nm = no + dndt;
1648 | }
1649 |
1650 | return {
1651 | em: em,
1652 | argpm: argpm,
1653 | inclm: inclm,
1654 | mm: mm,
1655 | nm: nm,
1656 | nodem: nodem,
1657 | irez: irez,
1658 | atime: atime,
1659 | d2201: d2201,
1660 | d2211: d2211,
1661 | d3210: d3210,
1662 | d3222: d3222,
1663 | d4410: d4410,
1664 | d4422: d4422,
1665 | d5220: d5220,
1666 | d5232: d5232,
1667 | d5421: d5421,
1668 | d5433: d5433,
1669 | dedt: dedt,
1670 | didt: didt,
1671 | dmdt: dmdt,
1672 | dndt: dndt,
1673 | dnodt: dnodt,
1674 | domdt: domdt,
1675 | del1: del1,
1676 | del2: del2,
1677 | del3: del3,
1678 | xfact: xfact,
1679 | xlamo: xlamo,
1680 | xli: xli,
1681 | xni: xni
1682 | };
1683 | }
1684 | },{"../constants":2}],11:[function(require,module,exports){
1685 | /*!
1686 | * satellite-js v3.0.1
1687 | * (c) 2013 Shashwat Kandadai and UCSC
1688 | * https://github.com/shashwatak/satellite-js
1689 | * License: MIT
1690 | */
1691 |
1692 | "use strict";
1693 |
1694 | Object.defineProperty(exports, "__esModule", {
1695 | value: true
1696 | });
1697 | exports.default = dspace;
1698 |
1699 | var _constants = require("../constants");
1700 |
1701 | /*-----------------------------------------------------------------------------
1702 | *
1703 | * procedure dspace
1704 | *
1705 | * this procedure provides deep space contributions to mean elements for
1706 | * perturbing third body. these effects have been averaged over one
1707 | * revolution of the sun and moon. for earth resonance effects, the
1708 | * effects have been averaged over no revolutions of the satellite.
1709 | * (mean motion)
1710 | *
1711 | * author : david vallado 719-573-2600 28 jun 2005
1712 | *
1713 | * inputs :
1714 | * d2201, d2211, d3210, d3222, d4410, d4422, d5220, d5232, d5421, d5433 -
1715 | * dedt -
1716 | * del1, del2, del3 -
1717 | * didt -
1718 | * dmdt -
1719 | * dnodt -
1720 | * domdt -
1721 | * irez - flag for resonance 0-none, 1-one day, 2-half day
1722 | * argpo - argument of perigee
1723 | * argpdot - argument of perigee dot (rate)
1724 | * t - time
1725 | * tc -
1726 | * gsto - gst
1727 | * xfact -
1728 | * xlamo -
1729 | * no - mean motion
1730 | * atime -
1731 | * em - eccentricity
1732 | * ft -
1733 | * argpm - argument of perigee
1734 | * inclm - inclination
1735 | * xli -
1736 | * mm - mean anomaly
1737 | * xni - mean motion
1738 | * nodem - right ascension of ascending node
1739 | *
1740 | * outputs :
1741 | * atime -
1742 | * em - eccentricity
1743 | * argpm - argument of perigee
1744 | * inclm - inclination
1745 | * xli -
1746 | * mm - mean anomaly
1747 | * xni -
1748 | * nodem - right ascension of ascending node
1749 | * dndt -
1750 | * nm - mean motion
1751 | *
1752 | * locals :
1753 | * delt -
1754 | * ft -
1755 | * theta -
1756 | * x2li -
1757 | * x2omi -
1758 | * xl -
1759 | * xldot -
1760 | * xnddt -
1761 | * xndt -
1762 | * xomi -
1763 | *
1764 | * coupling :
1765 | * none -
1766 | *
1767 | * references :
1768 | * hoots, roehrich, norad spacetrack report #3 1980
1769 | * hoots, norad spacetrack report #6 1986
1770 | * hoots, schumacher and glover 2004
1771 | * vallado, crawford, hujsak, kelso 2006
1772 | ----------------------------------------------------------------------------*/
1773 | function dspace(options) {
1774 | var irez = options.irez,
1775 | d2201 = options.d2201,
1776 | d2211 = options.d2211,
1777 | d3210 = options.d3210,
1778 | d3222 = options.d3222,
1779 | d4410 = options.d4410,
1780 | d4422 = options.d4422,
1781 | d5220 = options.d5220,
1782 | d5232 = options.d5232,
1783 | d5421 = options.d5421,
1784 | d5433 = options.d5433,
1785 | dedt = options.dedt,
1786 | del1 = options.del1,
1787 | del2 = options.del2,
1788 | del3 = options.del3,
1789 | didt = options.didt,
1790 | dmdt = options.dmdt,
1791 | dnodt = options.dnodt,
1792 | domdt = options.domdt,
1793 | argpo = options.argpo,
1794 | argpdot = options.argpdot,
1795 | t = options.t,
1796 | tc = options.tc,
1797 | gsto = options.gsto,
1798 | xfact = options.xfact,
1799 | xlamo = options.xlamo,
1800 | no = options.no;
1801 | var atime = options.atime,
1802 | em = options.em,
1803 | argpm = options.argpm,
1804 | inclm = options.inclm,
1805 | xli = options.xli,
1806 | mm = options.mm,
1807 | xni = options.xni,
1808 | nodem = options.nodem,
1809 | nm = options.nm;
1810 | var fasx2 = 0.13130908;
1811 | var fasx4 = 2.8843198;
1812 | var fasx6 = 0.37448087;
1813 | var g22 = 5.7686396;
1814 | var g32 = 0.95240898;
1815 | var g44 = 1.8014998;
1816 | var g52 = 1.0508330;
1817 | var g54 = 4.4108898;
1818 | var rptim = 4.37526908801129966e-3; // equates to 7.29211514668855e-5 rad/sec
1819 |
1820 | var stepp = 720.0;
1821 | var stepn = -720.0;
1822 | var step2 = 259200.0;
1823 | var delt;
1824 | var x2li;
1825 | var x2omi;
1826 | var xl;
1827 | var xldot;
1828 | var xnddt;
1829 | var xndt;
1830 | var xomi;
1831 | var dndt = 0.0;
1832 | var ft = 0.0; // ----------- calculate deep space resonance effects -----------
1833 |
1834 | var theta = (gsto + tc * rptim) % _constants.twoPi;
1835 | em += dedt * t;
1836 | inclm += didt * t;
1837 | argpm += domdt * t;
1838 | nodem += dnodt * t;
1839 | mm += dmdt * t; // sgp4fix for negative inclinations
1840 | // the following if statement should be commented out
1841 | // if (inclm < 0.0)
1842 | // {
1843 | // inclm = -inclm;
1844 | // argpm = argpm - pi;
1845 | // nodem = nodem + pi;
1846 | // }
1847 |
1848 | /* - update resonances : numerical (euler-maclaurin) integration - */
1849 |
1850 | /* ------------------------- epoch restart ---------------------- */
1851 | // sgp4fix for propagator problems
1852 | // the following integration works for negative time steps and periods
1853 | // the specific changes are unknown because the original code was so convoluted
1854 | // sgp4fix take out atime = 0.0 and fix for faster operation
1855 |
1856 | if (irez !== 0) {
1857 | // sgp4fix streamline check
1858 | if (atime === 0.0 || t * atime <= 0.0 || Math.abs(t) < Math.abs(atime)) {
1859 | atime = 0.0;
1860 | xni = no;
1861 | xli = xlamo;
1862 | } // sgp4fix move check outside loop
1863 |
1864 |
1865 | if (t > 0.0) {
1866 | delt = stepp;
1867 | } else {
1868 | delt = stepn;
1869 | }
1870 |
1871 | var iretn = 381; // added for do loop
1872 |
1873 | while (iretn === 381) {
1874 | // ------------------- dot terms calculated -------------
1875 | // ----------- near - synchronous resonance terms -------
1876 | if (irez !== 2) {
1877 | xndt = del1 * Math.sin(xli - fasx2) + del2 * Math.sin(2.0 * (xli - fasx4)) + del3 * Math.sin(3.0 * (xli - fasx6));
1878 | xldot = xni + xfact;
1879 | xnddt = del1 * Math.cos(xli - fasx2) + 2.0 * del2 * Math.cos(2.0 * (xli - fasx4)) + 3.0 * del3 * Math.cos(3.0 * (xli - fasx6));
1880 | xnddt *= xldot;
1881 | } else {
1882 | // --------- near - half-day resonance terms --------
1883 | xomi = argpo + argpdot * atime;
1884 | x2omi = xomi + xomi;
1885 | x2li = xli + xli;
1886 | xndt = d2201 * Math.sin(x2omi + xli - g22) + d2211 * Math.sin(xli - g22) + d3210 * Math.sin(xomi + xli - g32) + d3222 * Math.sin(-xomi + xli - g32) + d4410 * Math.sin(x2omi + x2li - g44) + d4422 * Math.sin(x2li - g44) + d5220 * Math.sin(xomi + xli - g52) + d5232 * Math.sin(-xomi + xli - g52) + d5421 * Math.sin(xomi + x2li - g54) + d5433 * Math.sin(-xomi + x2li - g54);
1887 | xldot = xni + xfact;
1888 | xnddt = d2201 * Math.cos(x2omi + xli - g22) + d2211 * Math.cos(xli - g22) + d3210 * Math.cos(xomi + xli - g32) + d3222 * Math.cos(-xomi + xli - g32) + d5220 * Math.cos(xomi + xli - g52) + d5232 * Math.cos(-xomi + xli - g52) + 2.0 * d4410 * Math.cos(x2omi + x2li - g44) + d4422 * Math.cos(x2li - g44) + d5421 * Math.cos(xomi + x2li - g54) + d5433 * Math.cos(-xomi + x2li - g54);
1889 | xnddt *= xldot;
1890 | } // ----------------------- integrator -------------------
1891 | // sgp4fix move end checks to end of routine
1892 |
1893 |
1894 | if (Math.abs(t - atime) >= stepp) {
1895 | iretn = 381;
1896 | } else {
1897 | ft = t - atime;
1898 | iretn = 0;
1899 | }
1900 |
1901 | if (iretn === 381) {
1902 | xli += xldot * delt + xndt * step2;
1903 | xni += xndt * delt + xnddt * step2;
1904 | atime += delt;
1905 | }
1906 | }
1907 |
1908 | nm = xni + xndt * ft + xnddt * ft * ft * 0.5;
1909 | xl = xli + xldot * ft + xndt * ft * ft * 0.5;
1910 |
1911 | if (irez !== 1) {
1912 | mm = xl - 2.0 * nodem + 2.0 * theta;
1913 | dndt = nm - no;
1914 | } else {
1915 | mm = xl - nodem - argpm + theta;
1916 | dndt = nm - no;
1917 | }
1918 |
1919 | nm = no + dndt;
1920 | }
1921 |
1922 | return {
1923 | atime: atime,
1924 | em: em,
1925 | argpm: argpm,
1926 | inclm: inclm,
1927 | xli: xli,
1928 | mm: mm,
1929 | xni: xni,
1930 | nodem: nodem,
1931 | dndt: dndt,
1932 | nm: nm
1933 | };
1934 | }
1935 | },{"../constants":2}],12:[function(require,module,exports){
1936 | /*!
1937 | * satellite-js v3.0.1
1938 | * (c) 2013 Shashwat Kandadai and UCSC
1939 | * https://github.com/shashwatak/satellite-js
1940 | * License: MIT
1941 | */
1942 |
1943 | "use strict";
1944 |
1945 | Object.defineProperty(exports, "__esModule", {
1946 | value: true
1947 | });
1948 | exports.default = gstime;
1949 |
1950 | var _constants = require("../constants");
1951 |
1952 | var _ext = require("../ext");
1953 |
1954 | /* -----------------------------------------------------------------------------
1955 | *
1956 | * function gstime
1957 | *
1958 | * this function finds the greenwich sidereal time.
1959 | *
1960 | * author : david vallado 719-573-2600 1 mar 2001
1961 | *
1962 | * inputs description range / units
1963 | * jdut1 - julian date in ut1 days from 4713 bc
1964 | *
1965 | * outputs :
1966 | * gstime - greenwich sidereal time 0 to 2pi rad
1967 | *
1968 | * locals :
1969 | * temp - temporary variable for doubles rad
1970 | * tut1 - julian centuries from the
1971 | * jan 1, 2000 12 h epoch (ut1)
1972 | *
1973 | * coupling :
1974 | * none
1975 | *
1976 | * references :
1977 | * vallado 2004, 191, eq 3-45
1978 | * --------------------------------------------------------------------------- */
1979 | function gstimeInternal(jdut1) {
1980 | var tut1 = (jdut1 - 2451545.0) / 36525.0;
1981 | var temp = -6.2e-6 * tut1 * tut1 * tut1 + 0.093104 * tut1 * tut1 + (876600.0 * 3600 + 8640184.812866) * tut1 + 67310.54841; // # sec
1982 |
1983 | temp = temp * _constants.deg2rad / 240.0 % _constants.twoPi; // 360/86400 = 1/240, to deg, to rad
1984 | // ------------------------ check quadrants ---------------------
1985 |
1986 | if (temp < 0.0) {
1987 | temp += _constants.twoPi;
1988 | }
1989 |
1990 | return temp;
1991 | }
1992 |
1993 | function gstime() {
1994 | if ((arguments.length <= 0 ? undefined : arguments[0]) instanceof Date || arguments.length > 1) {
1995 | return gstimeInternal(_ext.jday.apply(void 0, arguments));
1996 | }
1997 |
1998 | return gstimeInternal.apply(void 0, arguments);
1999 | }
2000 | },{"../constants":2,"../ext":4}],13:[function(require,module,exports){
2001 | /*!
2002 | * satellite-js v3.0.1
2003 | * (c) 2013 Shashwat Kandadai and UCSC
2004 | * https://github.com/shashwatak/satellite-js
2005 | * License: MIT
2006 | */
2007 |
2008 | "use strict";
2009 |
2010 | Object.defineProperty(exports, "__esModule", {
2011 | value: true
2012 | });
2013 | exports.default = initl;
2014 |
2015 | var _constants = require("../constants");
2016 |
2017 | var _gstime = _interopRequireDefault(require("./gstime"));
2018 |
2019 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2020 |
2021 | /*-----------------------------------------------------------------------------
2022 | *
2023 | * procedure initl
2024 | *
2025 | * this procedure initializes the sgp4 propagator. all the initialization is
2026 | * consolidated here instead of having multiple loops inside other routines.
2027 | *
2028 | * author : david vallado 719-573-2600 28 jun 2005
2029 | *
2030 | * inputs :
2031 | * ecco - eccentricity 0.0 - 1.0
2032 | * epoch - epoch time in days from jan 0, 1950. 0 hr
2033 | * inclo - inclination of satellite
2034 | * no - mean motion of satellite
2035 | * satn - satellite number
2036 | *
2037 | * outputs :
2038 | * ainv - 1.0 / a
2039 | * ao - semi major axis
2040 | * con41 -
2041 | * con42 - 1.0 - 5.0 cos(i)
2042 | * cosio - cosine of inclination
2043 | * cosio2 - cosio squared
2044 | * eccsq - eccentricity squared
2045 | * method - flag for deep space 'd', 'n'
2046 | * omeosq - 1.0 - ecco * ecco
2047 | * posq - semi-parameter squared
2048 | * rp - radius of perigee
2049 | * rteosq - square root of (1.0 - ecco*ecco)
2050 | * sinio - sine of inclination
2051 | * gsto - gst at time of observation rad
2052 | * no - mean motion of satellite
2053 | *
2054 | * locals :
2055 | * ak -
2056 | * d1 -
2057 | * del -
2058 | * adel -
2059 | * po -
2060 | *
2061 | * coupling :
2062 | * getgravconst
2063 | * gstime - find greenwich sidereal time from the julian date
2064 | *
2065 | * references :
2066 | * hoots, roehrich, norad spacetrack report #3 1980
2067 | * hoots, norad spacetrack report #6 1986
2068 | * hoots, schumacher and glover 2004
2069 | * vallado, crawford, hujsak, kelso 2006
2070 | ----------------------------------------------------------------------------*/
2071 | function initl(options) {
2072 | var ecco = options.ecco,
2073 | epoch = options.epoch,
2074 | inclo = options.inclo,
2075 | opsmode = options.opsmode;
2076 | var no = options.no; // sgp4fix use old way of finding gst
2077 | // ----------------------- earth constants ---------------------
2078 | // sgp4fix identify constants and allow alternate values
2079 | // ------------- calculate auxillary epoch quantities ----------
2080 |
2081 | var eccsq = ecco * ecco;
2082 | var omeosq = 1.0 - eccsq;
2083 | var rteosq = Math.sqrt(omeosq);
2084 | var cosio = Math.cos(inclo);
2085 | var cosio2 = cosio * cosio; // ------------------ un-kozai the mean motion -----------------
2086 |
2087 | var ak = Math.pow(_constants.xke / no, _constants.x2o3);
2088 | var d1 = 0.75 * _constants.j2 * (3.0 * cosio2 - 1.0) / (rteosq * omeosq);
2089 | var delPrime = d1 / (ak * ak);
2090 | var adel = ak * (1.0 - delPrime * delPrime - delPrime * (1.0 / 3.0 + 134.0 * delPrime * delPrime / 81.0));
2091 | delPrime = d1 / (adel * adel);
2092 | no /= 1.0 + delPrime;
2093 | var ao = Math.pow(_constants.xke / no, _constants.x2o3);
2094 | var sinio = Math.sin(inclo);
2095 | var po = ao * omeosq;
2096 | var con42 = 1.0 - 5.0 * cosio2;
2097 | var con41 = -con42 - cosio2 - cosio2;
2098 | var ainv = 1.0 / ao;
2099 | var posq = po * po;
2100 | var rp = ao * (1.0 - ecco);
2101 | var method = 'n'; // sgp4fix modern approach to finding sidereal time
2102 |
2103 | var gsto;
2104 |
2105 | if (opsmode === 'a') {
2106 | // sgp4fix use old way of finding gst
2107 | // count integer number of days from 0 jan 1970
2108 | var ts70 = epoch - 7305.0;
2109 | var ds70 = Math.floor(ts70 + 1.0e-8);
2110 | var tfrac = ts70 - ds70; // find greenwich location at epoch
2111 |
2112 | var c1 = 1.72027916940703639e-2;
2113 | var thgr70 = 1.7321343856509374;
2114 | var fk5r = 5.07551419432269442e-15;
2115 | var c1p2p = c1 + _constants.twoPi;
2116 | gsto = (thgr70 + c1 * ds70 + c1p2p * tfrac + ts70 * ts70 * fk5r) % _constants.twoPi;
2117 |
2118 | if (gsto < 0.0) {
2119 | gsto += _constants.twoPi;
2120 | }
2121 | } else {
2122 | gsto = (0, _gstime.default)(epoch + 2433281.5);
2123 | }
2124 |
2125 | return {
2126 | no: no,
2127 | method: method,
2128 | ainv: ainv,
2129 | ao: ao,
2130 | con41: con41,
2131 | con42: con42,
2132 | cosio: cosio,
2133 | cosio2: cosio2,
2134 | eccsq: eccsq,
2135 | omeosq: omeosq,
2136 | posq: posq,
2137 | rp: rp,
2138 | rteosq: rteosq,
2139 | sinio: sinio,
2140 | gsto: gsto
2141 | };
2142 | }
2143 | },{"../constants":2,"./gstime":12}],14:[function(require,module,exports){
2144 | /*!
2145 | * satellite-js v3.0.1
2146 | * (c) 2013 Shashwat Kandadai and UCSC
2147 | * https://github.com/shashwatak/satellite-js
2148 | * License: MIT
2149 | */
2150 |
2151 | "use strict";
2152 |
2153 | Object.defineProperty(exports, "__esModule", {
2154 | value: true
2155 | });
2156 | exports.default = propagate;
2157 |
2158 | var _constants = require("../constants");
2159 |
2160 | var _ext = require("../ext");
2161 |
2162 | var _sgp = _interopRequireDefault(require("./sgp4"));
2163 |
2164 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2165 |
2166 | function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }
2167 |
2168 | function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); }
2169 |
2170 | function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); }
2171 |
2172 | function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }
2173 |
2174 | function propagate() {
2175 | for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
2176 | args[_key] = arguments[_key];
2177 | }
2178 |
2179 | // Return a position and velocity vector for a given date and time.
2180 | var satrec = args[0];
2181 | var date = Array.prototype.slice.call(args, 1);
2182 |
2183 | var j = _ext.jday.apply(void 0, _toConsumableArray(date));
2184 |
2185 | var m = (j - satrec.jdsatepoch) * _constants.minutesPerDay;
2186 | return (0, _sgp.default)(satrec, m);
2187 | }
2188 | },{"../constants":2,"../ext":4,"./sgp4":15}],15:[function(require,module,exports){
2189 | /*!
2190 | * satellite-js v3.0.1
2191 | * (c) 2013 Shashwat Kandadai and UCSC
2192 | * https://github.com/shashwatak/satellite-js
2193 | * License: MIT
2194 | */
2195 |
2196 | "use strict";
2197 |
2198 | Object.defineProperty(exports, "__esModule", {
2199 | value: true
2200 | });
2201 | exports.default = sgp4;
2202 |
2203 | var _constants = require("../constants");
2204 |
2205 | var _dpper = _interopRequireDefault(require("./dpper"));
2206 |
2207 | var _dspace = _interopRequireDefault(require("./dspace"));
2208 |
2209 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2210 |
2211 | /*----------------------------------------------------------------------------
2212 | *
2213 | * procedure sgp4
2214 | *
2215 | * this procedure is the sgp4 prediction model from space command. this is an
2216 | * updated and combined version of sgp4 and sdp4, which were originally
2217 | * published separately in spacetrack report //3. this version follows the
2218 | * methodology from the aiaa paper (2006) describing the history and
2219 | * development of the code.
2220 | *
2221 | * author : david vallado 719-573-2600 28 jun 2005
2222 | *
2223 | * inputs :
2224 | * satrec - initialised structure from sgp4init() call.
2225 | * tsince - time since epoch (minutes)
2226 | *
2227 | * outputs :
2228 | * r - position vector km
2229 | * v - velocity km/sec
2230 | * return code - non-zero on error.
2231 | * 1 - mean elements, ecc >= 1.0 or ecc < -0.001 or a < 0.95 er
2232 | * 2 - mean motion less than 0.0
2233 | * 3 - pert elements, ecc < 0.0 or ecc > 1.0
2234 | * 4 - semi-latus rectum < 0.0
2235 | * 5 - epoch elements are sub-orbital
2236 | * 6 - satellite has decayed
2237 | *
2238 | * locals :
2239 | * am -
2240 | * axnl, aynl -
2241 | * betal -
2242 | * cosim , sinim , cosomm , sinomm , cnod , snod , cos2u ,
2243 | * sin2u , coseo1 , sineo1 , cosi , sini , cosip , sinip ,
2244 | * cosisq , cossu , sinsu , cosu , sinu
2245 | * delm -
2246 | * delomg -
2247 | * dndt -
2248 | * eccm -
2249 | * emsq -
2250 | * ecose -
2251 | * el2 -
2252 | * eo1 -
2253 | * eccp -
2254 | * esine -
2255 | * argpm -
2256 | * argpp -
2257 | * omgadf -
2258 | * pl -
2259 | * r -
2260 | * rtemsq -
2261 | * rdotl -
2262 | * rl -
2263 | * rvdot -
2264 | * rvdotl -
2265 | * su -
2266 | * t2 , t3 , t4 , tc
2267 | * tem5, temp , temp1 , temp2 , tempa , tempe , templ
2268 | * u , ux , uy , uz , vx , vy , vz
2269 | * inclm - inclination
2270 | * mm - mean anomaly
2271 | * nm - mean motion
2272 | * nodem - right asc of ascending node
2273 | * xinc -
2274 | * xincp -
2275 | * xl -
2276 | * xlm -
2277 | * mp -
2278 | * xmdf -
2279 | * xmx -
2280 | * xmy -
2281 | * nodedf -
2282 | * xnode -
2283 | * nodep -
2284 | * np -
2285 | *
2286 | * coupling :
2287 | * getgravconst-
2288 | * dpper
2289 | * dspace
2290 | *
2291 | * references :
2292 | * hoots, roehrich, norad spacetrack report //3 1980
2293 | * hoots, norad spacetrack report //6 1986
2294 | * hoots, schumacher and glover 2004
2295 | * vallado, crawford, hujsak, kelso 2006
2296 | ----------------------------------------------------------------------------*/
2297 | function sgp4(satrec, tsince) {
2298 | /* eslint-disable no-param-reassign */
2299 | var coseo1;
2300 | var sineo1;
2301 | var cosip;
2302 | var sinip;
2303 | var cosisq;
2304 | var delm;
2305 | var delomg;
2306 | var eo1;
2307 | var argpm;
2308 | var argpp;
2309 | var su;
2310 | var t3;
2311 | var t4;
2312 | var tc;
2313 | var tem5;
2314 | var temp;
2315 | var tempa;
2316 | var tempe;
2317 | var templ;
2318 | var inclm;
2319 | var mm;
2320 | var nm;
2321 | var nodem;
2322 | var xincp;
2323 | var xlm;
2324 | var mp;
2325 | var nodep;
2326 | /* ------------------ set mathematical constants --------------- */
2327 | // sgp4fix divisor for divide by zero check on inclination
2328 | // the old check used 1.0 + cos(pi-1.0e-9), but then compared it to
2329 | // 1.5 e-12, so the threshold was changed to 1.5e-12 for consistency
2330 |
2331 | var temp4 = 1.5e-12; // --------------------- clear sgp4 error flag -----------------
2332 |
2333 | satrec.t = tsince;
2334 | satrec.error = 0; // ------- update for secular gravity and atmospheric drag -----
2335 |
2336 | var xmdf = satrec.mo + satrec.mdot * satrec.t;
2337 | var argpdf = satrec.argpo + satrec.argpdot * satrec.t;
2338 | var nodedf = satrec.nodeo + satrec.nodedot * satrec.t;
2339 | argpm = argpdf;
2340 | mm = xmdf;
2341 | var t2 = satrec.t * satrec.t;
2342 | nodem = nodedf + satrec.nodecf * t2;
2343 | tempa = 1.0 - satrec.cc1 * satrec.t;
2344 | tempe = satrec.bstar * satrec.cc4 * satrec.t;
2345 | templ = satrec.t2cof * t2;
2346 |
2347 | if (satrec.isimp !== 1) {
2348 | delomg = satrec.omgcof * satrec.t; // sgp4fix use mutliply for speed instead of pow
2349 |
2350 | var delmtemp = 1.0 + satrec.eta * Math.cos(xmdf);
2351 | delm = satrec.xmcof * (delmtemp * delmtemp * delmtemp - satrec.delmo);
2352 | temp = delomg + delm;
2353 | mm = xmdf + temp;
2354 | argpm = argpdf - temp;
2355 | t3 = t2 * satrec.t;
2356 | t4 = t3 * satrec.t;
2357 | tempa = tempa - satrec.d2 * t2 - satrec.d3 * t3 - satrec.d4 * t4;
2358 | tempe += satrec.bstar * satrec.cc5 * (Math.sin(mm) - satrec.sinmao);
2359 | templ = templ + satrec.t3cof * t3 + t4 * (satrec.t4cof + satrec.t * satrec.t5cof);
2360 | }
2361 |
2362 | nm = satrec.no;
2363 | var em = satrec.ecco;
2364 | inclm = satrec.inclo;
2365 |
2366 | if (satrec.method === 'd') {
2367 | tc = satrec.t;
2368 | var dspaceOptions = {
2369 | irez: satrec.irez,
2370 | d2201: satrec.d2201,
2371 | d2211: satrec.d2211,
2372 | d3210: satrec.d3210,
2373 | d3222: satrec.d3222,
2374 | d4410: satrec.d4410,
2375 | d4422: satrec.d4422,
2376 | d5220: satrec.d5220,
2377 | d5232: satrec.d5232,
2378 | d5421: satrec.d5421,
2379 | d5433: satrec.d5433,
2380 | dedt: satrec.dedt,
2381 | del1: satrec.del1,
2382 | del2: satrec.del2,
2383 | del3: satrec.del3,
2384 | didt: satrec.didt,
2385 | dmdt: satrec.dmdt,
2386 | dnodt: satrec.dnodt,
2387 | domdt: satrec.domdt,
2388 | argpo: satrec.argpo,
2389 | argpdot: satrec.argpdot,
2390 | t: satrec.t,
2391 | tc: tc,
2392 | gsto: satrec.gsto,
2393 | xfact: satrec.xfact,
2394 | xlamo: satrec.xlamo,
2395 | no: satrec.no,
2396 | atime: satrec.atime,
2397 | em: em,
2398 | argpm: argpm,
2399 | inclm: inclm,
2400 | xli: satrec.xli,
2401 | mm: mm,
2402 | xni: satrec.xni,
2403 | nodem: nodem,
2404 | nm: nm
2405 | };
2406 | var dspaceResult = (0, _dspace.default)(dspaceOptions);
2407 | em = dspaceResult.em;
2408 | argpm = dspaceResult.argpm;
2409 | inclm = dspaceResult.inclm;
2410 | mm = dspaceResult.mm;
2411 | nodem = dspaceResult.nodem;
2412 | nm = dspaceResult.nm;
2413 | }
2414 |
2415 | if (nm <= 0.0) {
2416 | // printf("// error nm %f\n", nm);
2417 | satrec.error = 2; // sgp4fix add return
2418 |
2419 | return [false, false];
2420 | }
2421 |
2422 | var am = Math.pow(_constants.xke / nm, _constants.x2o3) * tempa * tempa;
2423 | nm = _constants.xke / Math.pow(am, 1.5);
2424 | em -= tempe; // fix tolerance for error recognition
2425 | // sgp4fix am is fixed from the previous nm check
2426 |
2427 | if (em >= 1.0 || em < -0.001) {
2428 | // || (am < 0.95)
2429 | // printf("// error em %f\n", em);
2430 | satrec.error = 1; // sgp4fix to return if there is an error in eccentricity
2431 |
2432 | return [false, false];
2433 | } // sgp4fix fix tolerance to avoid a divide by zero
2434 |
2435 |
2436 | if (em < 1.0e-6) {
2437 | em = 1.0e-6;
2438 | }
2439 |
2440 | mm += satrec.no * templ;
2441 | xlm = mm + argpm + nodem;
2442 | nodem %= _constants.twoPi;
2443 | argpm %= _constants.twoPi;
2444 | xlm %= _constants.twoPi;
2445 | mm = (xlm - argpm - nodem) % _constants.twoPi; // ----------------- compute extra mean quantities -------------
2446 |
2447 | var sinim = Math.sin(inclm);
2448 | var cosim = Math.cos(inclm); // -------------------- add lunar-solar periodics --------------
2449 |
2450 | var ep = em;
2451 | xincp = inclm;
2452 | argpp = argpm;
2453 | nodep = nodem;
2454 | mp = mm;
2455 | sinip = sinim;
2456 | cosip = cosim;
2457 |
2458 | if (satrec.method === 'd') {
2459 | var dpperParameters = {
2460 | inclo: satrec.inclo,
2461 | init: 'n',
2462 | ep: ep,
2463 | inclp: xincp,
2464 | nodep: nodep,
2465 | argpp: argpp,
2466 | mp: mp,
2467 | opsmode: satrec.operationmode
2468 | };
2469 | var dpperResult = (0, _dpper.default)(satrec, dpperParameters);
2470 | ep = dpperResult.ep;
2471 | nodep = dpperResult.nodep;
2472 | argpp = dpperResult.argpp;
2473 | mp = dpperResult.mp;
2474 | xincp = dpperResult.inclp;
2475 |
2476 | if (xincp < 0.0) {
2477 | xincp = -xincp;
2478 | nodep += _constants.pi;
2479 | argpp -= _constants.pi;
2480 | }
2481 |
2482 | if (ep < 0.0 || ep > 1.0) {
2483 | // printf("// error ep %f\n", ep);
2484 | satrec.error = 3; // sgp4fix add return
2485 |
2486 | return [false, false];
2487 | }
2488 | } // -------------------- long period periodics ------------------
2489 |
2490 |
2491 | if (satrec.method === 'd') {
2492 | sinip = Math.sin(xincp);
2493 | cosip = Math.cos(xincp);
2494 | satrec.aycof = -0.5 * _constants.j3oj2 * sinip; // sgp4fix for divide by zero for xincp = 180 deg
2495 |
2496 | if (Math.abs(cosip + 1.0) > 1.5e-12) {
2497 | satrec.xlcof = -0.25 * _constants.j3oj2 * sinip * (3.0 + 5.0 * cosip) / (1.0 + cosip);
2498 | } else {
2499 | satrec.xlcof = -0.25 * _constants.j3oj2 * sinip * (3.0 + 5.0 * cosip) / temp4;
2500 | }
2501 | }
2502 |
2503 | var axnl = ep * Math.cos(argpp);
2504 | temp = 1.0 / (am * (1.0 - ep * ep));
2505 | var aynl = ep * Math.sin(argpp) + temp * satrec.aycof;
2506 | var xl = mp + argpp + nodep + temp * satrec.xlcof * axnl; // --------------------- solve kepler's equation ---------------
2507 |
2508 | var u = (xl - nodep) % _constants.twoPi;
2509 | eo1 = u;
2510 | tem5 = 9999.9;
2511 | var ktr = 1; // sgp4fix for kepler iteration
2512 | // the following iteration needs better limits on corrections
2513 |
2514 | while (Math.abs(tem5) >= 1.0e-12 && ktr <= 10) {
2515 | sineo1 = Math.sin(eo1);
2516 | coseo1 = Math.cos(eo1);
2517 | tem5 = 1.0 - coseo1 * axnl - sineo1 * aynl;
2518 | tem5 = (u - aynl * coseo1 + axnl * sineo1 - eo1) / tem5;
2519 |
2520 | if (Math.abs(tem5) >= 0.95) {
2521 | if (tem5 > 0.0) {
2522 | tem5 = 0.95;
2523 | } else {
2524 | tem5 = -0.95;
2525 | }
2526 | }
2527 |
2528 | eo1 += tem5;
2529 | ktr += 1;
2530 | } // ------------- short period preliminary quantities -----------
2531 |
2532 |
2533 | var ecose = axnl * coseo1 + aynl * sineo1;
2534 | var esine = axnl * sineo1 - aynl * coseo1;
2535 | var el2 = axnl * axnl + aynl * aynl;
2536 | var pl = am * (1.0 - el2);
2537 |
2538 | if (pl < 0.0) {
2539 | // printf("// error pl %f\n", pl);
2540 | satrec.error = 4; // sgp4fix add return
2541 |
2542 | return [false, false];
2543 | }
2544 |
2545 | var rl = am * (1.0 - ecose);
2546 | var rdotl = Math.sqrt(am) * esine / rl;
2547 | var rvdotl = Math.sqrt(pl) / rl;
2548 | var betal = Math.sqrt(1.0 - el2);
2549 | temp = esine / (1.0 + betal);
2550 | var sinu = am / rl * (sineo1 - aynl - axnl * temp);
2551 | var cosu = am / rl * (coseo1 - axnl + aynl * temp);
2552 | su = Math.atan2(sinu, cosu);
2553 | var sin2u = (cosu + cosu) * sinu;
2554 | var cos2u = 1.0 - 2.0 * sinu * sinu;
2555 | temp = 1.0 / pl;
2556 | var temp1 = 0.5 * _constants.j2 * temp;
2557 | var temp2 = temp1 * temp; // -------------- update for short period periodics ------------
2558 |
2559 | if (satrec.method === 'd') {
2560 | cosisq = cosip * cosip;
2561 | satrec.con41 = 3.0 * cosisq - 1.0;
2562 | satrec.x1mth2 = 1.0 - cosisq;
2563 | satrec.x7thm1 = 7.0 * cosisq - 1.0;
2564 | }
2565 |
2566 | var mrt = rl * (1.0 - 1.5 * temp2 * betal * satrec.con41) + 0.5 * temp1 * satrec.x1mth2 * cos2u; // sgp4fix for decaying satellites
2567 |
2568 | if (mrt < 1.0) {
2569 | // printf("// decay condition %11.6f \n",mrt);
2570 | satrec.error = 6;
2571 | return {
2572 | position: false,
2573 | velocity: false
2574 | };
2575 | }
2576 |
2577 | su -= 0.25 * temp2 * satrec.x7thm1 * sin2u;
2578 | var xnode = nodep + 1.5 * temp2 * cosip * sin2u;
2579 | var xinc = xincp + 1.5 * temp2 * cosip * sinip * cos2u;
2580 | var mvt = rdotl - nm * temp1 * satrec.x1mth2 * sin2u / _constants.xke;
2581 | var rvdot = rvdotl + nm * temp1 * (satrec.x1mth2 * cos2u + 1.5 * satrec.con41) / _constants.xke; // --------------------- orientation vectors -------------------
2582 |
2583 | var sinsu = Math.sin(su);
2584 | var cossu = Math.cos(su);
2585 | var snod = Math.sin(xnode);
2586 | var cnod = Math.cos(xnode);
2587 | var sini = Math.sin(xinc);
2588 | var cosi = Math.cos(xinc);
2589 | var xmx = -snod * cosi;
2590 | var xmy = cnod * cosi;
2591 | var ux = xmx * sinsu + cnod * cossu;
2592 | var uy = xmy * sinsu + snod * cossu;
2593 | var uz = sini * sinsu;
2594 | var vx = xmx * cossu - cnod * sinsu;
2595 | var vy = xmy * cossu - snod * sinsu;
2596 | var vz = sini * cossu; // --------- position and velocity (in km and km/sec) ----------
2597 |
2598 | var r = {
2599 | x: mrt * ux * _constants.earthRadius,
2600 | y: mrt * uy * _constants.earthRadius,
2601 | z: mrt * uz * _constants.earthRadius
2602 | };
2603 | var v = {
2604 | x: (mvt * ux + rvdot * vx) * _constants.vkmpersec,
2605 | y: (mvt * uy + rvdot * vy) * _constants.vkmpersec,
2606 | z: (mvt * uz + rvdot * vz) * _constants.vkmpersec
2607 | };
2608 | return {
2609 | position: r,
2610 | velocity: v
2611 | };
2612 | /* eslint-enable no-param-reassign */
2613 | }
2614 | },{"../constants":2,"./dpper":8,"./dspace":11}],16:[function(require,module,exports){
2615 | /*!
2616 | * satellite-js v3.0.1
2617 | * (c) 2013 Shashwat Kandadai and UCSC
2618 | * https://github.com/shashwatak/satellite-js
2619 | * License: MIT
2620 | */
2621 |
2622 | "use strict";
2623 |
2624 | Object.defineProperty(exports, "__esModule", {
2625 | value: true
2626 | });
2627 | exports.default = sgp4init;
2628 |
2629 | var _constants = require("../constants");
2630 |
2631 | var _dpper = _interopRequireDefault(require("./dpper"));
2632 |
2633 | var _dscom = _interopRequireDefault(require("./dscom"));
2634 |
2635 | var _dsinit = _interopRequireDefault(require("./dsinit"));
2636 |
2637 | var _initl = _interopRequireDefault(require("./initl"));
2638 |
2639 | var _sgp = _interopRequireDefault(require("./sgp4"));
2640 |
2641 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2642 |
2643 | /*-----------------------------------------------------------------------------
2644 | *
2645 | * procedure sgp4init
2646 | *
2647 | * this procedure initializes variables for sgp4.
2648 | *
2649 | * author : david vallado 719-573-2600 28 jun 2005
2650 | * author : david vallado 719-573-2600 28 jun 2005
2651 | *
2652 | * inputs :
2653 | * opsmode - mode of operation afspc or improved 'a', 'i'
2654 | * satn - satellite number
2655 | * bstar - sgp4 type drag coefficient kg/m2er
2656 | * ecco - eccentricity
2657 | * epoch - epoch time in days from jan 0, 1950. 0 hr
2658 | * argpo - argument of perigee (output if ds)
2659 | * inclo - inclination
2660 | * mo - mean anomaly (output if ds)
2661 | * no - mean motion
2662 | * nodeo - right ascension of ascending node
2663 | *
2664 | * outputs :
2665 | * rec - common values for subsequent calls
2666 | * return code - non-zero on error.
2667 | * 1 - mean elements, ecc >= 1.0 or ecc < -0.001 or a < 0.95 er
2668 | * 2 - mean motion less than 0.0
2669 | * 3 - pert elements, ecc < 0.0 or ecc > 1.0
2670 | * 4 - semi-latus rectum < 0.0
2671 | * 5 - epoch elements are sub-orbital
2672 | * 6 - satellite has decayed
2673 | *
2674 | * locals :
2675 | * cnodm , snodm , cosim , sinim , cosomm , sinomm
2676 | * cc1sq , cc2 , cc3
2677 | * coef , coef1
2678 | * cosio4 -
2679 | * day -
2680 | * dndt -
2681 | * em - eccentricity
2682 | * emsq - eccentricity squared
2683 | * eeta -
2684 | * etasq -
2685 | * gam -
2686 | * argpm - argument of perigee
2687 | * nodem -
2688 | * inclm - inclination
2689 | * mm - mean anomaly
2690 | * nm - mean motion
2691 | * perige - perigee
2692 | * pinvsq -
2693 | * psisq -
2694 | * qzms24 -
2695 | * rtemsq -
2696 | * s1, s2, s3, s4, s5, s6, s7 -
2697 | * sfour -
2698 | * ss1, ss2, ss3, ss4, ss5, ss6, ss7 -
2699 | * sz1, sz2, sz3
2700 | * sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33 -
2701 | * tc -
2702 | * temp -
2703 | * temp1, temp2, temp3 -
2704 | * tsi -
2705 | * xpidot -
2706 | * xhdot1 -
2707 | * z1, z2, z3 -
2708 | * z11, z12, z13, z21, z22, z23, z31, z32, z33 -
2709 | *
2710 | * coupling :
2711 | * getgravconst-
2712 | * initl -
2713 | * dscom -
2714 | * dpper -
2715 | * dsinit -
2716 | * sgp4 -
2717 | *
2718 | * references :
2719 | * hoots, roehrich, norad spacetrack report #3 1980
2720 | * hoots, norad spacetrack report #6 1986
2721 | * hoots, schumacher and glover 2004
2722 | * vallado, crawford, hujsak, kelso 2006
2723 | ----------------------------------------------------------------------------*/
2724 | function sgp4init(satrec, options) {
2725 | /* eslint-disable no-param-reassign */
2726 | var opsmode = options.opsmode,
2727 | satn = options.satn,
2728 | epoch = options.epoch,
2729 | xbstar = options.xbstar,
2730 | xecco = options.xecco,
2731 | xargpo = options.xargpo,
2732 | xinclo = options.xinclo,
2733 | xmo = options.xmo,
2734 | xno = options.xno,
2735 | xnodeo = options.xnodeo;
2736 | var cosim;
2737 | var sinim;
2738 | var cc1sq;
2739 | var cc2;
2740 | var cc3;
2741 | var coef;
2742 | var coef1;
2743 | var cosio4;
2744 | var em;
2745 | var emsq;
2746 | var eeta;
2747 | var etasq;
2748 | var argpm;
2749 | var nodem;
2750 | var inclm;
2751 | var mm;
2752 | var nm;
2753 | var perige;
2754 | var pinvsq;
2755 | var psisq;
2756 | var qzms24;
2757 | var s1;
2758 | var s2;
2759 | var s3;
2760 | var s4;
2761 | var s5;
2762 | var sfour;
2763 | var ss1;
2764 | var ss2;
2765 | var ss3;
2766 | var ss4;
2767 | var ss5;
2768 | var sz1;
2769 | var sz3;
2770 | var sz11;
2771 | var sz13;
2772 | var sz21;
2773 | var sz23;
2774 | var sz31;
2775 | var sz33;
2776 | var tc;
2777 | var temp;
2778 | var temp1;
2779 | var temp2;
2780 | var temp3;
2781 | var tsi;
2782 | var xpidot;
2783 | var xhdot1;
2784 | var z1;
2785 | var z3;
2786 | var z11;
2787 | var z13;
2788 | var z21;
2789 | var z23;
2790 | var z31;
2791 | var z33;
2792 | /* ------------------------ initialization --------------------- */
2793 | // sgp4fix divisor for divide by zero check on inclination
2794 | // the old check used 1.0 + Math.cos(pi-1.0e-9), but then compared it to
2795 | // 1.5 e-12, so the threshold was changed to 1.5e-12 for consistency
2796 |
2797 | var temp4 = 1.5e-12; // ----------- set all near earth variables to zero ------------
2798 |
2799 | satrec.isimp = 0;
2800 | satrec.method = 'n';
2801 | satrec.aycof = 0.0;
2802 | satrec.con41 = 0.0;
2803 | satrec.cc1 = 0.0;
2804 | satrec.cc4 = 0.0;
2805 | satrec.cc5 = 0.0;
2806 | satrec.d2 = 0.0;
2807 | satrec.d3 = 0.0;
2808 | satrec.d4 = 0.0;
2809 | satrec.delmo = 0.0;
2810 | satrec.eta = 0.0;
2811 | satrec.argpdot = 0.0;
2812 | satrec.omgcof = 0.0;
2813 | satrec.sinmao = 0.0;
2814 | satrec.t = 0.0;
2815 | satrec.t2cof = 0.0;
2816 | satrec.t3cof = 0.0;
2817 | satrec.t4cof = 0.0;
2818 | satrec.t5cof = 0.0;
2819 | satrec.x1mth2 = 0.0;
2820 | satrec.x7thm1 = 0.0;
2821 | satrec.mdot = 0.0;
2822 | satrec.nodedot = 0.0;
2823 | satrec.xlcof = 0.0;
2824 | satrec.xmcof = 0.0;
2825 | satrec.nodecf = 0.0; // ----------- set all deep space variables to zero ------------
2826 |
2827 | satrec.irez = 0;
2828 | satrec.d2201 = 0.0;
2829 | satrec.d2211 = 0.0;
2830 | satrec.d3210 = 0.0;
2831 | satrec.d3222 = 0.0;
2832 | satrec.d4410 = 0.0;
2833 | satrec.d4422 = 0.0;
2834 | satrec.d5220 = 0.0;
2835 | satrec.d5232 = 0.0;
2836 | satrec.d5421 = 0.0;
2837 | satrec.d5433 = 0.0;
2838 | satrec.dedt = 0.0;
2839 | satrec.del1 = 0.0;
2840 | satrec.del2 = 0.0;
2841 | satrec.del3 = 0.0;
2842 | satrec.didt = 0.0;
2843 | satrec.dmdt = 0.0;
2844 | satrec.dnodt = 0.0;
2845 | satrec.domdt = 0.0;
2846 | satrec.e3 = 0.0;
2847 | satrec.ee2 = 0.0;
2848 | satrec.peo = 0.0;
2849 | satrec.pgho = 0.0;
2850 | satrec.pho = 0.0;
2851 | satrec.pinco = 0.0;
2852 | satrec.plo = 0.0;
2853 | satrec.se2 = 0.0;
2854 | satrec.se3 = 0.0;
2855 | satrec.sgh2 = 0.0;
2856 | satrec.sgh3 = 0.0;
2857 | satrec.sgh4 = 0.0;
2858 | satrec.sh2 = 0.0;
2859 | satrec.sh3 = 0.0;
2860 | satrec.si2 = 0.0;
2861 | satrec.si3 = 0.0;
2862 | satrec.sl2 = 0.0;
2863 | satrec.sl3 = 0.0;
2864 | satrec.sl4 = 0.0;
2865 | satrec.gsto = 0.0;
2866 | satrec.xfact = 0.0;
2867 | satrec.xgh2 = 0.0;
2868 | satrec.xgh3 = 0.0;
2869 | satrec.xgh4 = 0.0;
2870 | satrec.xh2 = 0.0;
2871 | satrec.xh3 = 0.0;
2872 | satrec.xi2 = 0.0;
2873 | satrec.xi3 = 0.0;
2874 | satrec.xl2 = 0.0;
2875 | satrec.xl3 = 0.0;
2876 | satrec.xl4 = 0.0;
2877 | satrec.xlamo = 0.0;
2878 | satrec.zmol = 0.0;
2879 | satrec.zmos = 0.0;
2880 | satrec.atime = 0.0;
2881 | satrec.xli = 0.0;
2882 | satrec.xni = 0.0; // sgp4fix - note the following variables are also passed directly via satrec.
2883 | // it is possible to streamline the sgp4init call by deleting the "x"
2884 | // variables, but the user would need to set the satrec.* values first. we
2885 | // include the additional assignments in case twoline2rv is not used.
2886 |
2887 | satrec.bstar = xbstar;
2888 | satrec.ecco = xecco;
2889 | satrec.argpo = xargpo;
2890 | satrec.inclo = xinclo;
2891 | satrec.mo = xmo;
2892 | satrec.no = xno;
2893 | satrec.nodeo = xnodeo; // sgp4fix add opsmode
2894 |
2895 | satrec.operationmode = opsmode; // ------------------------ earth constants -----------------------
2896 | // sgp4fix identify constants and allow alternate values
2897 |
2898 | var ss = 78.0 / _constants.earthRadius + 1.0; // sgp4fix use multiply for speed instead of pow
2899 |
2900 | var qzms2ttemp = (120.0 - 78.0) / _constants.earthRadius;
2901 | var qzms2t = qzms2ttemp * qzms2ttemp * qzms2ttemp * qzms2ttemp;
2902 | satrec.init = 'y';
2903 | satrec.t = 0.0;
2904 | var initlOptions = {
2905 | satn: satn,
2906 | ecco: satrec.ecco,
2907 | epoch: epoch,
2908 | inclo: satrec.inclo,
2909 | no: satrec.no,
2910 | method: satrec.method,
2911 | opsmode: satrec.operationmode
2912 | };
2913 | var initlResult = (0, _initl.default)(initlOptions);
2914 | var ao = initlResult.ao,
2915 | con42 = initlResult.con42,
2916 | cosio = initlResult.cosio,
2917 | cosio2 = initlResult.cosio2,
2918 | eccsq = initlResult.eccsq,
2919 | omeosq = initlResult.omeosq,
2920 | posq = initlResult.posq,
2921 | rp = initlResult.rp,
2922 | rteosq = initlResult.rteosq,
2923 | sinio = initlResult.sinio;
2924 | satrec.no = initlResult.no;
2925 | satrec.con41 = initlResult.con41;
2926 | satrec.gsto = initlResult.gsto;
2927 | satrec.error = 0; // sgp4fix remove this check as it is unnecessary
2928 | // the mrt check in sgp4 handles decaying satellite cases even if the starting
2929 | // condition is below the surface of te earth
2930 | // if (rp < 1.0)
2931 | // {
2932 | // printf("// *** satn%d epoch elts sub-orbital ***\n", satn);
2933 | // satrec.error = 5;
2934 | // }
2935 |
2936 | if (omeosq >= 0.0 || satrec.no >= 0.0) {
2937 | satrec.isimp = 0;
2938 |
2939 | if (rp < 220.0 / _constants.earthRadius + 1.0) {
2940 | satrec.isimp = 1;
2941 | }
2942 |
2943 | sfour = ss;
2944 | qzms24 = qzms2t;
2945 | perige = (rp - 1.0) * _constants.earthRadius; // - for perigees below 156 km, s and qoms2t are altered -
2946 |
2947 | if (perige < 156.0) {
2948 | sfour = perige - 78.0;
2949 |
2950 | if (perige < 98.0) {
2951 | sfour = 20.0;
2952 | } // sgp4fix use multiply for speed instead of pow
2953 |
2954 |
2955 | var qzms24temp = (120.0 - sfour) / _constants.earthRadius;
2956 | qzms24 = qzms24temp * qzms24temp * qzms24temp * qzms24temp;
2957 | sfour = sfour / _constants.earthRadius + 1.0;
2958 | }
2959 |
2960 | pinvsq = 1.0 / posq;
2961 | tsi = 1.0 / (ao - sfour);
2962 | satrec.eta = ao * satrec.ecco * tsi;
2963 | etasq = satrec.eta * satrec.eta;
2964 | eeta = satrec.ecco * satrec.eta;
2965 | psisq = Math.abs(1.0 - etasq);
2966 | coef = qzms24 * Math.pow(tsi, 4.0);
2967 | coef1 = coef / Math.pow(psisq, 3.5);
2968 | cc2 = coef1 * satrec.no * (ao * (1.0 + 1.5 * etasq + eeta * (4.0 + etasq)) + 0.375 * _constants.j2 * tsi / psisq * satrec.con41 * (8.0 + 3.0 * etasq * (8.0 + etasq)));
2969 | satrec.cc1 = satrec.bstar * cc2;
2970 | cc3 = 0.0;
2971 |
2972 | if (satrec.ecco > 1.0e-4) {
2973 | cc3 = -2.0 * coef * tsi * _constants.j3oj2 * satrec.no * sinio / satrec.ecco;
2974 | }
2975 |
2976 | satrec.x1mth2 = 1.0 - cosio2;
2977 | satrec.cc4 = 2.0 * satrec.no * coef1 * ao * omeosq * (satrec.eta * (2.0 + 0.5 * etasq) + satrec.ecco * (0.5 + 2.0 * etasq) - _constants.j2 * tsi / (ao * psisq) * (-3.0 * satrec.con41 * (1.0 - 2.0 * eeta + etasq * (1.5 - 0.5 * eeta)) + 0.75 * satrec.x1mth2 * (2.0 * etasq - eeta * (1.0 + etasq)) * Math.cos(2.0 * satrec.argpo)));
2978 | satrec.cc5 = 2.0 * coef1 * ao * omeosq * (1.0 + 2.75 * (etasq + eeta) + eeta * etasq);
2979 | cosio4 = cosio2 * cosio2;
2980 | temp1 = 1.5 * _constants.j2 * pinvsq * satrec.no;
2981 | temp2 = 0.5 * temp1 * _constants.j2 * pinvsq;
2982 | temp3 = -0.46875 * _constants.j4 * pinvsq * pinvsq * satrec.no;
2983 | satrec.mdot = satrec.no + 0.5 * temp1 * rteosq * satrec.con41 + 0.0625 * temp2 * rteosq * (13.0 - 78.0 * cosio2 + 137.0 * cosio4);
2984 | satrec.argpdot = -0.5 * temp1 * con42 + 0.0625 * temp2 * (7.0 - 114.0 * cosio2 + 395.0 * cosio4) + temp3 * (3.0 - 36.0 * cosio2 + 49.0 * cosio4);
2985 | xhdot1 = -temp1 * cosio;
2986 | satrec.nodedot = xhdot1 + (0.5 * temp2 * (4.0 - 19.0 * cosio2) + 2.0 * temp3 * (3.0 - 7.0 * cosio2)) * cosio;
2987 | xpidot = satrec.argpdot + satrec.nodedot;
2988 | satrec.omgcof = satrec.bstar * cc3 * Math.cos(satrec.argpo);
2989 | satrec.xmcof = 0.0;
2990 |
2991 | if (satrec.ecco > 1.0e-4) {
2992 | satrec.xmcof = -_constants.x2o3 * coef * satrec.bstar / eeta;
2993 | }
2994 |
2995 | satrec.nodecf = 3.5 * omeosq * xhdot1 * satrec.cc1;
2996 | satrec.t2cof = 1.5 * satrec.cc1; // sgp4fix for divide by zero with xinco = 180 deg
2997 |
2998 | if (Math.abs(cosio + 1.0) > 1.5e-12) {
2999 | satrec.xlcof = -0.25 * _constants.j3oj2 * sinio * (3.0 + 5.0 * cosio) / (1.0 + cosio);
3000 | } else {
3001 | satrec.xlcof = -0.25 * _constants.j3oj2 * sinio * (3.0 + 5.0 * cosio) / temp4;
3002 | }
3003 |
3004 | satrec.aycof = -0.5 * _constants.j3oj2 * sinio; // sgp4fix use multiply for speed instead of pow
3005 |
3006 | var delmotemp = 1.0 + satrec.eta * Math.cos(satrec.mo);
3007 | satrec.delmo = delmotemp * delmotemp * delmotemp;
3008 | satrec.sinmao = Math.sin(satrec.mo);
3009 | satrec.x7thm1 = 7.0 * cosio2 - 1.0; // --------------- deep space initialization -------------
3010 |
3011 | if (2 * _constants.pi / satrec.no >= 225.0) {
3012 | satrec.method = 'd';
3013 | satrec.isimp = 1;
3014 | tc = 0.0;
3015 | inclm = satrec.inclo;
3016 | var dscomOptions = {
3017 | epoch: epoch,
3018 | ep: satrec.ecco,
3019 | argpp: satrec.argpo,
3020 | tc: tc,
3021 | inclp: satrec.inclo,
3022 | nodep: satrec.nodeo,
3023 | np: satrec.no,
3024 | e3: satrec.e3,
3025 | ee2: satrec.ee2,
3026 | peo: satrec.peo,
3027 | pgho: satrec.pgho,
3028 | pho: satrec.pho,
3029 | pinco: satrec.pinco,
3030 | plo: satrec.plo,
3031 | se2: satrec.se2,
3032 | se3: satrec.se3,
3033 | sgh2: satrec.sgh2,
3034 | sgh3: satrec.sgh3,
3035 | sgh4: satrec.sgh4,
3036 | sh2: satrec.sh2,
3037 | sh3: satrec.sh3,
3038 | si2: satrec.si2,
3039 | si3: satrec.si3,
3040 | sl2: satrec.sl2,
3041 | sl3: satrec.sl3,
3042 | sl4: satrec.sl4,
3043 | xgh2: satrec.xgh2,
3044 | xgh3: satrec.xgh3,
3045 | xgh4: satrec.xgh4,
3046 | xh2: satrec.xh2,
3047 | xh3: satrec.xh3,
3048 | xi2: satrec.xi2,
3049 | xi3: satrec.xi3,
3050 | xl2: satrec.xl2,
3051 | xl3: satrec.xl3,
3052 | xl4: satrec.xl4,
3053 | zmol: satrec.zmol,
3054 | zmos: satrec.zmos
3055 | };
3056 | var dscomResult = (0, _dscom.default)(dscomOptions);
3057 | satrec.e3 = dscomResult.e3;
3058 | satrec.ee2 = dscomResult.ee2;
3059 | satrec.peo = dscomResult.peo;
3060 | satrec.pgho = dscomResult.pgho;
3061 | satrec.pho = dscomResult.pho;
3062 | satrec.pinco = dscomResult.pinco;
3063 | satrec.plo = dscomResult.plo;
3064 | satrec.se2 = dscomResult.se2;
3065 | satrec.se3 = dscomResult.se3;
3066 | satrec.sgh2 = dscomResult.sgh2;
3067 | satrec.sgh3 = dscomResult.sgh3;
3068 | satrec.sgh4 = dscomResult.sgh4;
3069 | satrec.sh2 = dscomResult.sh2;
3070 | satrec.sh3 = dscomResult.sh3;
3071 | satrec.si2 = dscomResult.si2;
3072 | satrec.si3 = dscomResult.si3;
3073 | satrec.sl2 = dscomResult.sl2;
3074 | satrec.sl3 = dscomResult.sl3;
3075 | satrec.sl4 = dscomResult.sl4;
3076 | sinim = dscomResult.sinim;
3077 | cosim = dscomResult.cosim;
3078 | em = dscomResult.em;
3079 | emsq = dscomResult.emsq;
3080 | s1 = dscomResult.s1;
3081 | s2 = dscomResult.s2;
3082 | s3 = dscomResult.s3;
3083 | s4 = dscomResult.s4;
3084 | s5 = dscomResult.s5;
3085 | ss1 = dscomResult.ss1;
3086 | ss2 = dscomResult.ss2;
3087 | ss3 = dscomResult.ss3;
3088 | ss4 = dscomResult.ss4;
3089 | ss5 = dscomResult.ss5;
3090 | sz1 = dscomResult.sz1;
3091 | sz3 = dscomResult.sz3;
3092 | sz11 = dscomResult.sz11;
3093 | sz13 = dscomResult.sz13;
3094 | sz21 = dscomResult.sz21;
3095 | sz23 = dscomResult.sz23;
3096 | sz31 = dscomResult.sz31;
3097 | sz33 = dscomResult.sz33;
3098 | satrec.xgh2 = dscomResult.xgh2;
3099 | satrec.xgh3 = dscomResult.xgh3;
3100 | satrec.xgh4 = dscomResult.xgh4;
3101 | satrec.xh2 = dscomResult.xh2;
3102 | satrec.xh3 = dscomResult.xh3;
3103 | satrec.xi2 = dscomResult.xi2;
3104 | satrec.xi3 = dscomResult.xi3;
3105 | satrec.xl2 = dscomResult.xl2;
3106 | satrec.xl3 = dscomResult.xl3;
3107 | satrec.xl4 = dscomResult.xl4;
3108 | satrec.zmol = dscomResult.zmol;
3109 | satrec.zmos = dscomResult.zmos;
3110 | nm = dscomResult.nm;
3111 | z1 = dscomResult.z1;
3112 | z3 = dscomResult.z3;
3113 | z11 = dscomResult.z11;
3114 | z13 = dscomResult.z13;
3115 | z21 = dscomResult.z21;
3116 | z23 = dscomResult.z23;
3117 | z31 = dscomResult.z31;
3118 | z33 = dscomResult.z33;
3119 | var dpperOptions = {
3120 | inclo: inclm,
3121 | init: satrec.init,
3122 | ep: satrec.ecco,
3123 | inclp: satrec.inclo,
3124 | nodep: satrec.nodeo,
3125 | argpp: satrec.argpo,
3126 | mp: satrec.mo,
3127 | opsmode: satrec.operationmode
3128 | };
3129 | var dpperResult = (0, _dpper.default)(satrec, dpperOptions);
3130 | satrec.ecco = dpperResult.ep;
3131 | satrec.inclo = dpperResult.inclp;
3132 | satrec.nodeo = dpperResult.nodep;
3133 | satrec.argpo = dpperResult.argpp;
3134 | satrec.mo = dpperResult.mp;
3135 | argpm = 0.0;
3136 | nodem = 0.0;
3137 | mm = 0.0;
3138 | var dsinitOptions = {
3139 | cosim: cosim,
3140 | emsq: emsq,
3141 | argpo: satrec.argpo,
3142 | s1: s1,
3143 | s2: s2,
3144 | s3: s3,
3145 | s4: s4,
3146 | s5: s5,
3147 | sinim: sinim,
3148 | ss1: ss1,
3149 | ss2: ss2,
3150 | ss3: ss3,
3151 | ss4: ss4,
3152 | ss5: ss5,
3153 | sz1: sz1,
3154 | sz3: sz3,
3155 | sz11: sz11,
3156 | sz13: sz13,
3157 | sz21: sz21,
3158 | sz23: sz23,
3159 | sz31: sz31,
3160 | sz33: sz33,
3161 | t: satrec.t,
3162 | tc: tc,
3163 | gsto: satrec.gsto,
3164 | mo: satrec.mo,
3165 | mdot: satrec.mdot,
3166 | no: satrec.no,
3167 | nodeo: satrec.nodeo,
3168 | nodedot: satrec.nodedot,
3169 | xpidot: xpidot,
3170 | z1: z1,
3171 | z3: z3,
3172 | z11: z11,
3173 | z13: z13,
3174 | z21: z21,
3175 | z23: z23,
3176 | z31: z31,
3177 | z33: z33,
3178 | ecco: satrec.ecco,
3179 | eccsq: eccsq,
3180 | em: em,
3181 | argpm: argpm,
3182 | inclm: inclm,
3183 | mm: mm,
3184 | nm: nm,
3185 | nodem: nodem,
3186 | irez: satrec.irez,
3187 | atime: satrec.atime,
3188 | d2201: satrec.d2201,
3189 | d2211: satrec.d2211,
3190 | d3210: satrec.d3210,
3191 | d3222: satrec.d3222,
3192 | d4410: satrec.d4410,
3193 | d4422: satrec.d4422,
3194 | d5220: satrec.d5220,
3195 | d5232: satrec.d5232,
3196 | d5421: satrec.d5421,
3197 | d5433: satrec.d5433,
3198 | dedt: satrec.dedt,
3199 | didt: satrec.didt,
3200 | dmdt: satrec.dmdt,
3201 | dnodt: satrec.dnodt,
3202 | domdt: satrec.domdt,
3203 | del1: satrec.del1,
3204 | del2: satrec.del2,
3205 | del3: satrec.del3,
3206 | xfact: satrec.xfact,
3207 | xlamo: satrec.xlamo,
3208 | xli: satrec.xli,
3209 | xni: satrec.xni
3210 | };
3211 | var dsinitResult = (0, _dsinit.default)(dsinitOptions);
3212 | satrec.irez = dsinitResult.irez;
3213 | satrec.atime = dsinitResult.atime;
3214 | satrec.d2201 = dsinitResult.d2201;
3215 | satrec.d2211 = dsinitResult.d2211;
3216 | satrec.d3210 = dsinitResult.d3210;
3217 | satrec.d3222 = dsinitResult.d3222;
3218 | satrec.d4410 = dsinitResult.d4410;
3219 | satrec.d4422 = dsinitResult.d4422;
3220 | satrec.d5220 = dsinitResult.d5220;
3221 | satrec.d5232 = dsinitResult.d5232;
3222 | satrec.d5421 = dsinitResult.d5421;
3223 | satrec.d5433 = dsinitResult.d5433;
3224 | satrec.dedt = dsinitResult.dedt;
3225 | satrec.didt = dsinitResult.didt;
3226 | satrec.dmdt = dsinitResult.dmdt;
3227 | satrec.dnodt = dsinitResult.dnodt;
3228 | satrec.domdt = dsinitResult.domdt;
3229 | satrec.del1 = dsinitResult.del1;
3230 | satrec.del2 = dsinitResult.del2;
3231 | satrec.del3 = dsinitResult.del3;
3232 | satrec.xfact = dsinitResult.xfact;
3233 | satrec.xlamo = dsinitResult.xlamo;
3234 | satrec.xli = dsinitResult.xli;
3235 | satrec.xni = dsinitResult.xni;
3236 | } // ----------- set variables if not deep space -----------
3237 |
3238 |
3239 | if (satrec.isimp !== 1) {
3240 | cc1sq = satrec.cc1 * satrec.cc1;
3241 | satrec.d2 = 4.0 * ao * tsi * cc1sq;
3242 | temp = satrec.d2 * tsi * satrec.cc1 / 3.0;
3243 | satrec.d3 = (17.0 * ao + sfour) * temp;
3244 | satrec.d4 = 0.5 * temp * ao * tsi * (221.0 * ao + 31.0 * sfour) * satrec.cc1;
3245 | satrec.t3cof = satrec.d2 + 2.0 * cc1sq;
3246 | satrec.t4cof = 0.25 * (3.0 * satrec.d3 + satrec.cc1 * (12.0 * satrec.d2 + 10.0 * cc1sq));
3247 | satrec.t5cof = 0.2 * (3.0 * satrec.d4 + 12.0 * satrec.cc1 * satrec.d3 + 6.0 * satrec.d2 * satrec.d2 + 15.0 * cc1sq * (2.0 * satrec.d2 + cc1sq));
3248 | }
3249 | /* finally propogate to zero epoch to initialize all others. */
3250 | // sgp4fix take out check to let satellites process until they are actually below earth surface
3251 | // if(satrec.error == 0)
3252 |
3253 | }
3254 |
3255 | (0, _sgp.default)(satrec, 0, 0);
3256 | satrec.init = 'n';
3257 | /* eslint-enable no-param-reassign */
3258 | }
3259 | },{"../constants":2,"./dpper":8,"./dscom":9,"./dsinit":10,"./initl":13,"./sgp4":15}],17:[function(require,module,exports){
3260 | /*!
3261 | * satellite-js v3.0.1
3262 | * (c) 2013 Shashwat Kandadai and UCSC
3263 | * https://github.com/shashwatak/satellite-js
3264 | * License: MIT
3265 | */
3266 |
3267 | "use strict";
3268 |
3269 | Object.defineProperty(exports, "__esModule", {
3270 | value: true
3271 | });
3272 | exports.radiansToDegrees = radiansToDegrees;
3273 | exports.degreesToRadians = degreesToRadians;
3274 | exports.degreesLat = degreesLat;
3275 | exports.degreesLong = degreesLong;
3276 | exports.radiansLat = radiansLat;
3277 | exports.radiansLong = radiansLong;
3278 | exports.geodeticToEcf = geodeticToEcf;
3279 | exports.eciToGeodetic = eciToGeodetic;
3280 | exports.ecfToEci = ecfToEci;
3281 | exports.eciToEcf = eciToEcf;
3282 | exports.ecfToLookAngles = ecfToLookAngles;
3283 |
3284 | var _constants = require("./constants");
3285 |
3286 | function radiansToDegrees(radians) {
3287 | return radians * _constants.rad2deg;
3288 | }
3289 |
3290 | function degreesToRadians(degrees) {
3291 | return degrees * _constants.deg2rad;
3292 | }
3293 |
3294 | function degreesLat(radians) {
3295 | if (radians < -_constants.pi / 2 || radians > _constants.pi / 2) {
3296 | throw new RangeError('Latitude radians must be in range [-pi/2; pi/2].');
3297 | }
3298 |
3299 | return radiansToDegrees(radians);
3300 | }
3301 |
3302 | function degreesLong(radians) {
3303 | if (radians < -_constants.pi || radians > _constants.pi) {
3304 | throw new RangeError('Longitude radians must be in range [-pi; pi].');
3305 | }
3306 |
3307 | return radiansToDegrees(radians);
3308 | }
3309 |
3310 | function radiansLat(degrees) {
3311 | if (degrees < -90 || degrees > 90) {
3312 | throw new RangeError('Latitude degrees must be in range [-90; 90].');
3313 | }
3314 |
3315 | return degreesToRadians(degrees);
3316 | }
3317 |
3318 | function radiansLong(degrees) {
3319 | if (degrees < -180 || degrees > 180) {
3320 | throw new RangeError('Longitude degrees must be in range [-180; 180].');
3321 | }
3322 |
3323 | return degreesToRadians(degrees);
3324 | }
3325 |
3326 | function geodeticToEcf(geodetic) {
3327 | var longitude = geodetic.longitude,
3328 | latitude = geodetic.latitude,
3329 | height = geodetic.height;
3330 | var a = 6378.137;
3331 | var b = 6356.7523142;
3332 | var f = (a - b) / a;
3333 | var e2 = 2 * f - f * f;
3334 | var normal = a / Math.sqrt(1 - e2 * (Math.sin(latitude) * Math.sin(latitude)));
3335 | var x = (normal + height) * Math.cos(latitude) * Math.cos(longitude);
3336 | var y = (normal + height) * Math.cos(latitude) * Math.sin(longitude);
3337 | var z = (normal * (1 - e2) + height) * Math.sin(latitude);
3338 | return {
3339 | x: x,
3340 | y: y,
3341 | z: z
3342 | };
3343 | }
3344 |
3345 | function eciToGeodetic(eci, gmst) {
3346 | // http://www.celestrak.com/columns/v02n03/
3347 | var a = 6378.137;
3348 | var b = 6356.7523142;
3349 | var R = Math.sqrt(eci.x * eci.x + eci.y * eci.y);
3350 | var f = (a - b) / a;
3351 | var e2 = 2 * f - f * f;
3352 | var longitude = Math.atan2(eci.y, eci.x) - gmst;
3353 |
3354 | while (longitude < -_constants.pi) {
3355 | longitude += _constants.twoPi;
3356 | }
3357 |
3358 | while (longitude > _constants.pi) {
3359 | longitude -= _constants.twoPi;
3360 | }
3361 |
3362 | var kmax = 20;
3363 | var k = 0;
3364 | var latitude = Math.atan2(eci.z, Math.sqrt(eci.x * eci.x + eci.y * eci.y));
3365 | var C;
3366 |
3367 | while (k < kmax) {
3368 | C = 1 / Math.sqrt(1 - e2 * (Math.sin(latitude) * Math.sin(latitude)));
3369 | latitude = Math.atan2(eci.z + a * C * e2 * Math.sin(latitude), R);
3370 | k += 1;
3371 | }
3372 |
3373 | var height = R / Math.cos(latitude) - a * C;
3374 | return {
3375 | longitude: longitude,
3376 | latitude: latitude,
3377 | height: height
3378 | };
3379 | }
3380 |
3381 | function ecfToEci(ecf, gmst) {
3382 | // ccar.colorado.edu/ASEN5070/handouts/coordsys.doc
3383 | //
3384 | // [X] [C -S 0][X]
3385 | // [Y] = [S C 0][Y]
3386 | // [Z]eci [0 0 1][Z]ecf
3387 | //
3388 | var X = ecf.x * Math.cos(gmst) - ecf.y * Math.sin(gmst);
3389 | var Y = ecf.x * Math.sin(gmst) + ecf.y * Math.cos(gmst);
3390 | var Z = ecf.z;
3391 | return {
3392 | x: X,
3393 | y: Y,
3394 | z: Z
3395 | };
3396 | }
3397 |
3398 | function eciToEcf(eci, gmst) {
3399 | // ccar.colorado.edu/ASEN5070/handouts/coordsys.doc
3400 | //
3401 | // [X] [C -S 0][X]
3402 | // [Y] = [S C 0][Y]
3403 | // [Z]eci [0 0 1][Z]ecf
3404 | //
3405 | //
3406 | // Inverse:
3407 | // [X] [C S 0][X]
3408 | // [Y] = [-S C 0][Y]
3409 | // [Z]ecf [0 0 1][Z]eci
3410 | var x = eci.x * Math.cos(gmst) + eci.y * Math.sin(gmst);
3411 | var y = eci.x * -Math.sin(gmst) + eci.y * Math.cos(gmst);
3412 | var z = eci.z;
3413 | return {
3414 | x: x,
3415 | y: y,
3416 | z: z
3417 | };
3418 | }
3419 |
3420 | function topocentric(observerGeodetic, satelliteEcf) {
3421 | // http://www.celestrak.com/columns/v02n02/
3422 | // TS Kelso's method, except I'm using ECF frame
3423 | // and he uses ECI.
3424 | var longitude = observerGeodetic.longitude,
3425 | latitude = observerGeodetic.latitude;
3426 | var observerEcf = geodeticToEcf(observerGeodetic);
3427 | var rx = satelliteEcf.x - observerEcf.x;
3428 | var ry = satelliteEcf.y - observerEcf.y;
3429 | var rz = satelliteEcf.z - observerEcf.z;
3430 | var topS = Math.sin(latitude) * Math.cos(longitude) * rx + Math.sin(latitude) * Math.sin(longitude) * ry - Math.cos(latitude) * rz;
3431 | var topE = -Math.sin(longitude) * rx + Math.cos(longitude) * ry;
3432 | var topZ = Math.cos(latitude) * Math.cos(longitude) * rx + Math.cos(latitude) * Math.sin(longitude) * ry + Math.sin(latitude) * rz;
3433 | return {
3434 | topS: topS,
3435 | topE: topE,
3436 | topZ: topZ
3437 | };
3438 | }
3439 | /**
3440 | * @param {Object} tc
3441 | * @param {Number} tc.topS Positive horizontal vector S due south.
3442 | * @param {Number} tc.topE Positive horizontal vector E due east.
3443 | * @param {Number} tc.topZ Vector Z normal to the surface of the earth (up).
3444 | * @returns {Object}
3445 | */
3446 |
3447 |
3448 | function topocentricToLookAngles(tc) {
3449 | var topS = tc.topS,
3450 | topE = tc.topE,
3451 | topZ = tc.topZ;
3452 | var rangeSat = Math.sqrt(topS * topS + topE * topE + topZ * topZ);
3453 | var El = Math.asin(topZ / rangeSat);
3454 |
3455 | var Az = Math.atan2(-topE, topS) + _constants.pi;
3456 |
3457 | return {
3458 | azimuth: Az,
3459 | elevation: El,
3460 | rangeSat: rangeSat // Range in km
3461 |
3462 | };
3463 | }
3464 |
3465 | function ecfToLookAngles(observerGeodetic, satelliteEcf) {
3466 | var topocentricCoords = topocentric(observerGeodetic, satelliteEcf);
3467 | return topocentricToLookAngles(topocentricCoords);
3468 | }
3469 | },{"./constants":2}],18:[function(require,module,exports){
3470 | const _MS_IN_A_DAY = 1000 * 60 * 60 * 24;
3471 |
3472 | // Data formats for TLE orbital elements.
3473 | const _DATA_TYPES = {
3474 | _INT: Symbol(),
3475 | _FLOAT: Symbol(),
3476 | _CHAR: Symbol(),
3477 | _DECIMAL_ASSUMED: Symbol(), // 12345 -> 0.12345
3478 | _DECIMAL_ASSUMED_E: Symbol() // 12345-2 -> 0.0012345
3479 | };
3480 |
3481 | const _ACCEPTABLE_TLE_INPUT_TYPES = {
3482 | _STRING: 'string',
3483 | _ARRAY: 'array',
3484 | _OBJECT: 'object'
3485 | };
3486 |
3487 | const _LEADING_ZERO_ASSUMED_PREFIX = '0.';
3488 |
3489 | module.exports = {
3490 | _MS_IN_A_DAY,
3491 | _DATA_TYPES,
3492 | _ACCEPTABLE_TLE_INPUT_TYPES,
3493 | _LEADING_ZERO_ASSUMED_PREFIX
3494 | };
3495 |
3496 | },{}],19:[function(require,module,exports){
3497 | const { _DATA_TYPES } = require('./constants');
3498 |
3499 | const line1 = {
3500 | /* TLE line number. Will always return 1 for valid TLEs. */
3501 | lineNumber1: {
3502 | start: 0,
3503 | length: 1,
3504 | type: _DATA_TYPES._INT
3505 | },
3506 |
3507 | /**
3508 | * NORAD satellite catalog number (Sputnik's rocket was 00001).
3509 | *
3510 | * Range: 0 to 99999
3511 | * Example: 25544
3512 | */
3513 | satelliteNumber: {
3514 | start: 2,
3515 | length: 5,
3516 | type: _DATA_TYPES._INT
3517 | },
3518 |
3519 | /**
3520 | * Satellite classification.
3521 | * 'U' = unclassified
3522 | * 'C' = classified
3523 | * 'S' = secret)
3524 | *
3525 | * Example: 'U'
3526 | */
3527 | classification: {
3528 | start: 7,
3529 | length: 1,
3530 | type: _DATA_TYPES._CHAR
3531 | },
3532 |
3533 | /**
3534 | * International Designator: Last 2 digits of launch year. 57 to 99 = 1900s, 00-56 = 2000s.
3535 | * See https://en.wikipedia.org/wiki/International_Designator
3536 | *
3537 | * Range: 00 to 99
3538 | * Example: 98
3539 | */
3540 | intDesignatorYear: {
3541 | start: 9,
3542 | length: 2,
3543 | type: _DATA_TYPES._INT
3544 | },
3545 |
3546 | /**
3547 | * International Designator: Launch number of the year.
3548 | * See https://en.wikipedia.org/wiki/International_Designator
3549 | *
3550 | * Range: 1 to 999
3551 | * Example: 67
3552 | */
3553 | intDesignatorLaunchNumber: {
3554 | start: 11,
3555 | length: 3,
3556 | type: _DATA_TYPES._INT
3557 | },
3558 |
3559 | /**
3560 | * International Designator: Piece of the launch.
3561 | * See https://en.wikipedia.org/wiki/International_Designator
3562 | *
3563 | * Range: A to ZZZ
3564 | * Example: 'A'
3565 | */
3566 | intDesignatorPieceOfLaunch: {
3567 | start: 14,
3568 | length: 3,
3569 | type: _DATA_TYPES._CHAR
3570 | },
3571 |
3572 | /**
3573 | * Year when the TLE was generated (TLE epoch), last two digits.
3574 | *
3575 | * Range: 00 to 99
3576 | * Example: 17
3577 | */
3578 | epochYear: {
3579 | start: 18,
3580 | length: 2,
3581 | type: _DATA_TYPES._INT
3582 | },
3583 |
3584 | /**
3585 | * Fractional day of the year when the TLE was generated (TLE epoch).
3586 | *
3587 | * Range: 1 to 365.99999999
3588 | * Example: 206.18396726
3589 | */
3590 | epochDay: {
3591 | start: 20,
3592 | length: 12,
3593 | type: _DATA_TYPES._FLOAT
3594 | },
3595 |
3596 | /**
3597 | * First Time Derivative of the Mean Motion divided by two. Defines how mean motion changes
3598 | * from day to day, so TLE propagators can still be used to make reasonable guesses when
3599 | * times are distant from the original TLE epoch.
3600 | *
3601 | * Units: Orbits / day ^ 2
3602 | * Example: 0.00001961
3603 | */
3604 | firstTimeDerivative: {
3605 | start: 33,
3606 | length: 11,
3607 | type: _DATA_TYPES._FLOAT
3608 | },
3609 |
3610 | /**
3611 | * Second Time Derivative of Mean Motion divided by six (decimal point assumed). Measures rate
3612 | * of change in the Mean Motion Dot so software can make reasonable guesses when times are
3613 | * distant from the original TLE epoch.
3614 | *
3615 | * Usually zero, unless the satellite is manuevering or in a decaying orbit.
3616 | *
3617 | * Units: Orbits / day ^ 3.
3618 | * Example: 0 ('00000-0' in the original TLE [= 0.00000 * 10 ^ 0])
3619 | */
3620 | secondTimeDerivative: {
3621 | start: 44,
3622 | length: 8,
3623 | type: _DATA_TYPES._DECIMAL_ASSUMED_E
3624 | },
3625 |
3626 | /**
3627 | * BSTAR drag term (decimal point assumed). Estimates the effects of
3628 | * atmospheric drag on the satellite's motion.
3629 | *
3630 | * Units: EarthRadii ^ -1
3631 | * Example: 0.000036771 ('36771-4' in the original TLE [= 0.36771 * 10 ^ -4])
3632 | */
3633 | bstarDrag: {
3634 | start: 53,
3635 | length: 8,
3636 | type: _DATA_TYPES._DECIMAL_ASSUMED_E
3637 | },
3638 |
3639 | /**
3640 | * Private value - used by Air Force Space Command to reference the orbit model used to
3641 | * generate the TLE. Will always be seen as zero externally (e.g. by "us", unless you are
3642 | * "them" - in which case, hello!).
3643 | *
3644 | * Example: 0
3645 | */
3646 | orbitModel: {
3647 | start: 62,
3648 | length: 1,
3649 | type: _DATA_TYPES._INT
3650 | },
3651 |
3652 | /**
3653 | * TLE element set number, incremented for each new TLE generated. 999 seems to mean the TLE
3654 | * has maxed out.
3655 | *
3656 | * Range: Technically 1 to 9999, though in practice the maximum number seems to be 999.
3657 | * Example: 999
3658 | */
3659 | tleSetNumber: {
3660 | start: 64,
3661 | length: 4,
3662 | type: _DATA_TYPES._INT
3663 | },
3664 |
3665 | /*
3666 | * TLE line 1 checksum (modulo 10), for verifying the integrity of this line of the TLE.
3667 | *
3668 | * Range: 0 to 9
3669 | * Example: 3
3670 | */
3671 | checksum1: {
3672 | start: 68,
3673 | length: 1,
3674 | type: _DATA_TYPES._INT
3675 | }
3676 | };
3677 |
3678 | const line2 = {
3679 | /* TLE line number. Will always return 2 for valid TLEs. */
3680 | lineNumber2: {
3681 | start: 0,
3682 | length: 1,
3683 | type: _DATA_TYPES._INT
3684 | },
3685 |
3686 | /**
3687 | * NORAD satellite catalog number (Sputnik's rocket was 00001). Should match the satellite
3688 | * number on line 1.
3689 | *
3690 | * Range: 0 to 99999
3691 | * Example: 25544
3692 | */
3693 | satelliteNumber2: {
3694 | start: 2,
3695 | length: 5,
3696 | type: _DATA_TYPES._INT
3697 | },
3698 |
3699 | /**
3700 | * Inclination relative to the Earth's equatorial plane in degrees. 0 to 90 degrees is a
3701 | * prograde orbit and 90 to 180 degrees is a retrograde orbit.
3702 | *
3703 | * Units: degrees
3704 | * Range: 0 to 180
3705 | * Example: 51.6400
3706 | */
3707 | inclination: {
3708 | start: 8,
3709 | length: 8,
3710 | type: _DATA_TYPES._FLOAT
3711 | },
3712 |
3713 | /**
3714 | * Right ascension of the ascending node in degrees. Essentially, this is the angle of the
3715 | * satellite as it crosses northward (ascending) across the Earth's equator (equatorial
3716 | * plane).
3717 | *
3718 | * Units: degrees
3719 | * Range: 0 to 359.9999
3720 | * Example: 208.9163
3721 | */
3722 | rightAscension: {
3723 | start: 17,
3724 | length: 8,
3725 | type: _DATA_TYPES._FLOAT
3726 | },
3727 |
3728 | /**
3729 | * Orbital eccentricity, decimal point assumed. All artifical Earth satellites have an
3730 | * eccentricity between 0 (perfect circle) and 1 (parabolic orbit).
3731 | *
3732 | * Range: 0 to 1
3733 | * Example: 0.0006317 (`0006317` in the original TLE)
3734 | */
3735 | eccentricity: {
3736 | start: 26,
3737 | length: 7,
3738 | type: _DATA_TYPES._DECIMAL_ASSUMED
3739 | },
3740 |
3741 | /**
3742 | * Argument of perigee. See https://en.wikipedia.org/wiki/Argument_of_perigee
3743 | * Units: degrees
3744 | * Range: 0 to 359.9999
3745 | * Example: 69.9862
3746 | */
3747 | perigee: {
3748 | start: 34,
3749 | length: 8,
3750 | type: _DATA_TYPES._FLOAT
3751 | },
3752 |
3753 | /**
3754 | * Mean anomaly. Indicates where the satellite was located within its orbit at the time of the
3755 | * TLE epoch.
3756 | * See https://en.wikipedia.org/wiki/Mean_Anomaly
3757 | *
3758 | * Units: degrees
3759 | * Range: 0 to 359.9999
3760 | * Example: 25.2906
3761 | */
3762 | meanAnomaly: {
3763 | start: 43,
3764 | length: 8,
3765 | type: _DATA_TYPES._FLOAT
3766 | },
3767 |
3768 | /**
3769 | * Revolutions around the Earth per day (mean motion).
3770 | * See https://en.wikipedia.org/wiki/Mean_Motion
3771 | *
3772 | * Range: 0 to 17 (theoretically)
3773 | * Example: 15.54225995
3774 | */
3775 | meanMotion: {
3776 | start: 52,
3777 | length: 11,
3778 | type: _DATA_TYPES._FLOAT
3779 | },
3780 |
3781 | /**
3782 | * Total satellite revolutions when this TLE was generated. This number seems to roll over
3783 | * (e.g. 99999 -> 0).
3784 | *
3785 | * Range: 0 to 99999
3786 | * Example: 6766
3787 | */
3788 | revNumberAtEpoch: {
3789 | start: 63,
3790 | length: 5,
3791 | type: _DATA_TYPES._INT
3792 | },
3793 |
3794 | /*
3795 | * TLE line 1 checksum (modulo 10), for verifying the integrity of this line of the TLE.
3796 | *
3797 | * Range: 0 to 9
3798 | * Example: 0
3799 | */
3800 | checksum2: {
3801 | start: 68,
3802 | length: 1,
3803 | type: _DATA_TYPES._INT
3804 | }
3805 | };
3806 |
3807 | /**
3808 | * Fixed locations of orbital element value strings as they have appeared going back to the
3809 | * punchcard days.
3810 | * See https://en.wikipedia.org/wiki/Two-line_element_set.
3811 | */
3812 | module.exports = {
3813 | line1,
3814 | line2
3815 | };
3816 |
3817 | },{"./constants":18}],20:[function(require,module,exports){
3818 | const SatelliteJS = require('satellite.js');
3819 | const {
3820 | _crossesAntemeridian,
3821 | _dayOfYearToTimeStamp,
3822 | _decimalAssumedEToFloat,
3823 | _degreesToRadians,
3824 | _radiansToDegrees,
3825 | _toCamelCase
3826 | } = require('./utils');
3827 | const tleLines = require('./line-defs');
3828 | const {
3829 | _ACCEPTABLE_TLE_INPUT_TYPES,
3830 | _DATA_TYPES,
3831 | _LEADING_ZERO_ASSUMED_PREFIX,
3832 | _MS_IN_A_DAY
3833 | } = require('./constants');
3834 |
3835 | // TODO: fix this ugliness
3836 | const satellitejs = (SatelliteJS.twoline2satrec) ? SatelliteJS : SatelliteJS.satellite;
3837 |
3838 | class TLEJS {
3839 | constructor() {
3840 | this.createAllTLEGetters(tleLines);
3841 |
3842 | // TODO: use Set to store cache vals.
3843 | this.cache = {
3844 | antemeridianCrossings: {}
3845 | };
3846 | }
3847 |
3848 | /**
3849 | * Parses a TLE from a string or array input. Both two and three-line variants are acceptable.
3850 | */
3851 | parseTLE(inputTLE) {
3852 | const fnName = 'parseTLE';
3853 |
3854 | // Check if already an instance of a TLE object.
3855 | if (typeof inputTLE === _ACCEPTABLE_TLE_INPUT_TYPES._OBJECT && inputTLE.arr) return inputTLE;
3856 | const tleStrLong = (Array.isArray(inputTLE)) ? inputTLE.join('') : inputTLE;
3857 | const tleStr = tleStrLong.substr && tleStrLong.substr(0, 30);
3858 | const cacheKey = `${fnName}-${tleStr}`;
3859 | if (this.cache[cacheKey]) return this.cache[cacheKey];
3860 |
3861 | const outputObj = {};
3862 | const tleType = (Array.isArray(inputTLE))
3863 | ? _ACCEPTABLE_TLE_INPUT_TYPES._ARRAY
3864 | : typeof inputTLE;
3865 | let tleArr = [];
3866 |
3867 | switch (tleType) {
3868 | case _ACCEPTABLE_TLE_INPUT_TYPES._ARRAY:
3869 | // Make a copy.
3870 | tleArr = inputTLE.concat();
3871 | break;
3872 |
3873 | case _ACCEPTABLE_TLE_INPUT_TYPES._STRING:
3874 | // Convert string to array.
3875 | tleArr = inputTLE.split('\n');
3876 | break;
3877 |
3878 | default:
3879 | throw new Error('TLE input is invalid');
3880 | }
3881 |
3882 | // Handle 2 and 3 line variants.
3883 | if (tleArr.length > 2) {
3884 | // 3-line TLE with satellite name as the first line.
3885 |
3886 | // Keep track of satellite name.
3887 | outputObj.name = tleArr[0];
3888 |
3889 | // Remove name from array.
3890 | tleArr.splice(0, 1);
3891 | } else {
3892 | // 2-line TLE with no satellite name.
3893 | outputObj.name = 'Unknown';
3894 | }
3895 |
3896 | // Trim spaces
3897 | tleArr = tleArr.map(line => line.trim());
3898 |
3899 | outputObj.arr = tleArr;
3900 |
3901 | this.cache[cacheKey] = outputObj;
3902 |
3903 | return outputObj;
3904 | }
3905 |
3906 | /**
3907 | * Determines if a TLE is valid, checking for the presence of line numbers and making sure
3908 | * the calculated checksum matches the expected checksum.
3909 | */
3910 | isValidTLE(tle) {
3911 | const fnName = 'isValidTLE';
3912 |
3913 | const parsedTLE = this.parseTLE(tle);
3914 | const tleStr = parsedTLE.arr.join('').substr(0, 30);
3915 | const cacheKey = `${fnName}-${tleStr}`;
3916 | if (this.cache[cacheKey]) return this.cache[cacheKey];
3917 |
3918 | let isValid = true;
3919 |
3920 | if (parsedTLE.arr.length !== 2) return false;
3921 |
3922 | // Check line numbers and checksums at the same time.
3923 | parsedTLE.arr.forEach((line, index) => {
3924 | // Noop if already invalid.
3925 | if (!isValid) return;
3926 |
3927 | const lineNumber = index + 1;
3928 |
3929 | // Check line number.
3930 | const parsedLineNumber = this[`getLineNumber${lineNumber}`](parsedTLE);
3931 | const lineNumberIsValid = parsedLineNumber === lineNumber;
3932 |
3933 | // Checksum.
3934 | const calculatedLineChecksum = this.tleLineChecksum(parsedTLE.arr[index]);
3935 | const parsedChecksum = this[`getChecksum${lineNumber}`](parsedTLE);
3936 | const checksumIsValid = parsedChecksum === calculatedLineChecksum;
3937 |
3938 | if (!lineNumberIsValid || !checksumIsValid) {
3939 | isValid = false;
3940 | }
3941 | });
3942 |
3943 | this.cache[cacheKey] = isValid;
3944 |
3945 | return isValid;
3946 | }
3947 |
3948 | /**
3949 | * Determines the checksum for a single line of a TLE.
3950 | *
3951 | * Checksum = modulo 10 of sum of all numbers (including line number) + 1 for each negative
3952 | * sign (-). Everything else is ignored.
3953 | */
3954 | tleLineChecksum(tleLineStr) {
3955 | const charArr = tleLineStr.split('');
3956 |
3957 | // Remove trailing checksum.
3958 | charArr.splice(charArr.length - 1, 1);
3959 |
3960 | if (charArr.length === 0) {
3961 | throw new Error('Character array empty!', tleLineStr);
3962 | }
3963 |
3964 | const checksum = charArr.reduce((sum, val) => {
3965 | const parsedVal = parseInt(val, 10);
3966 | const parsedSum = parseInt(sum, 10);
3967 |
3968 | if (Number.isInteger(parsedVal)) {
3969 | return parsedSum + parsedVal;
3970 | } else if (val === '-') {
3971 | return parsedSum + 1;
3972 | }
3973 |
3974 | return parsedSum;
3975 | });
3976 |
3977 | return checksum % 10;
3978 | }
3979 |
3980 | /**
3981 | * Creates simple getters for each line of a TLE.
3982 | */
3983 | createAllTLEGetters(lines) {
3984 | const boundCreateTLELineGetters = this.createTLELineGetters.bind(this, lines);
3985 | Object.keys(lines).forEach(boundCreateTLELineGetters);
3986 | }
3987 |
3988 | /**
3989 | * Creates simple getters for all values on a single line of a TLE.
3990 | */
3991 | createTLELineGetters(lines, line) {
3992 | const boundCreateTLEValGetter = this.createTLEValGetter.bind(this, line);
3993 | Object.keys(lines[line]).forEach(boundCreateTLEValGetter);
3994 | }
3995 |
3996 | /**
3997 | * Creates a simple getter for a single TLE value.
3998 | *
3999 | * TODO: proper ES6 getters?
4000 | */
4001 | createTLEValGetter(tleLine, prop) {
4002 | this[_toCamelCase(`get-${prop}`)] = (tle) => {
4003 | const parsedTLE = this.parseTLE(tle);
4004 |
4005 | const tleArr = parsedTLE.arr;
4006 | const line = (tleLine === 'line1') ? tleArr[0] : tleArr[1];
4007 | const start = tleLines[tleLine][prop].start;
4008 | const length = tleLines[tleLine][prop].length;
4009 |
4010 | const substr = line.substr(start, length);
4011 |
4012 | let output;
4013 | switch (tleLines[tleLine][prop].type) {
4014 | case _DATA_TYPES._INT:
4015 | output = parseInt(substr, 10);
4016 | break;
4017 |
4018 | case _DATA_TYPES._FLOAT:
4019 | output = parseFloat(substr);
4020 | break;
4021 |
4022 | case _DATA_TYPES._DECIMAL_ASSUMED:
4023 | output = parseFloat(`${_LEADING_ZERO_ASSUMED_PREFIX}${substr}`);
4024 | break;
4025 |
4026 | case _DATA_TYPES._DECIMAL_ASSUMED_E:
4027 | output = _decimalAssumedEToFloat(substr);
4028 | break;
4029 |
4030 | case _DATA_TYPES._CHAR:
4031 | default:
4032 | output = substr.trim();
4033 | break;
4034 | }
4035 |
4036 | return output;
4037 | };
4038 | }
4039 |
4040 | /**
4041 | * Determines the Unix timestamp (in ms) of a TLE epoch (the time a TLE was generated).
4042 | *
4043 | * Example:
4044 | * getEpochTimestamp(tleStr);
4045 | * -> 1500956694771
4046 | */
4047 | getEpochTimestamp(tle) {
4048 | const epochDay = this.getEpochDay(tle);
4049 | const epochYear = this.getEpochYear(tle);
4050 | return _dayOfYearToTimeStamp(epochDay, epochYear);
4051 | }
4052 |
4053 | /**
4054 | * Determines the name of a satellite, if present in the first line of a 3-line TLE. If not
4055 | * present, 'Unknown' is returned.
4056 | *
4057 | * Example:
4058 | * getSatelliteName(tleStr);
4059 | * -> 'ISS (ZARYA)'
4060 | */
4061 | getSatelliteName(tle) {
4062 | const parsedTLE = this.parseTLE(tle);
4063 | return parsedTLE.name;
4064 | }
4065 |
4066 | /**
4067 | * Determines satellite position and look angles from an earth observer.
4068 | *
4069 | * Example:
4070 | * const timestampMS = 1501039265000;
4071 | * const observer = {
4072 | * lat: 34.243889,
4073 | * lng: -116.911389,
4074 | * height: 0
4075 | * };
4076 | * const satInfo = tle.getSatelliteInfo(
4077 | * tleStr, // Satellite TLE string or array.
4078 | * timestampMS, // Timestamp (ms)
4079 | * observer.lat, // Observer latitude (degrees)
4080 | * observer.lng, // Observer longitude (degrees)
4081 | * observer.height // Observer elevation (km)
4082 | * );
4083 | *
4084 | * ->
4085 | * {
4086 | * // satellite compass heading from observer in degrees (0 = north, 180 = south)
4087 | * azimuth: 294.5780478624994,
4088 | *
4089 | * // satellite elevation from observer in degrees (90 is directly overhead)
4090 | * elevation: 81.63903620330046,
4091 | *
4092 | * // km distance from observer to spacecraft
4093 | * range: 406.60211015810074,
4094 | *
4095 | * // spacecraft altitude in km
4096 | * height: 402.9082788620108,
4097 |
4098 | * // spacecraft latitude in degrees
4099 | * lat: 34.45112876592785,
4100 |
4101 | * // spacecraft longitude in degrees
4102 | * lng: -117.46176597710809,
4103 | *
4104 | * // spacecraft velocity in km/s
4105 | * velocity: 7.675627442183371
4106 | * }
4107 | */
4108 | getSatelliteInfo(tle, timestamp, observerLat, observerLng, observerHeight) {
4109 | const fnName = 'getSatelliteInfo';
4110 |
4111 | const timestampCopy = timestamp || Date.now();
4112 |
4113 | const tleArr = (this.parseTLE(tle)).arr;
4114 | const tleStrShort = tleArr.join('').substr(0, 30);
4115 |
4116 | const defaultObserverPosition = {
4117 | lat: 36.9613422,
4118 | lng: -122.0308,
4119 | height: 0.370
4120 | };
4121 |
4122 | const obsLat = observerLat || defaultObserverPosition.lat;
4123 | const obsLng = observerLng || defaultObserverPosition.lng;
4124 | const obsHeight = observerHeight || defaultObserverPosition.height;
4125 |
4126 | // Memoization
4127 | const cacheKey = `${fnName}-${tleStrShort}-${timestampCopy}-${observerLat}-${observerLng}
4128 | -${observerHeight}`;
4129 | if (this.cache[cacheKey]) return this.cache[cacheKey];
4130 |
4131 | // Sanity check
4132 | if (!satellitejs) {
4133 | throw new Error('satellite.js not found');
4134 | }
4135 |
4136 | // Initialize a satellite record
4137 | const satrec = satellitejs.twoline2satrec(tleArr[0], tleArr[1]);
4138 |
4139 | const time = new Date(timestampCopy);
4140 |
4141 | // Propagate SGP4.
4142 | const positionAndVelocity = satellitejs.propagate(satrec, time);
4143 |
4144 | if (satellitejs.error) {
4145 | throw new Error('Error: problematic TLE with unexpected eccentricity');
4146 | }
4147 |
4148 | // The position_velocity result is a key-value pair of ECI coordinates.
4149 | // These are the base results from which all other coordinates are derived.
4150 | const positionEci = positionAndVelocity.position;
4151 | const velocityEci = positionAndVelocity.velocity;
4152 |
4153 | // Set the observer position (in radians).
4154 | const observerGd = {
4155 | latitude: _degreesToRadians(obsLat),
4156 | longitude: _degreesToRadians(obsLng),
4157 | height: obsHeight
4158 | };
4159 |
4160 | // Get GMST for some coordinate transforms.
4161 | // http://en.wikipedia.org/wiki/Sidereal_time#Definition
4162 | const gmst = satellitejs.gstime(time);
4163 |
4164 | // Get ECF, Geodetic, Look Angles, and Doppler Factor.
4165 | const positionEcf = satellitejs.eciToEcf(positionEci, gmst);
4166 | const positionGd = satellitejs.eciToGeodetic(positionEci, gmst);
4167 | const lookAngles = satellitejs.ecfToLookAngles(observerGd, positionEcf);
4168 |
4169 | const velocityKmS =
4170 | Math.sqrt(Math.pow(velocityEci.x, 2) +
4171 | Math.pow(velocityEci.y, 2) +
4172 | Math.pow(velocityEci.z, 2));
4173 |
4174 | // Azimuth: is simply the compass heading from the observer's position.
4175 | const azimuth = lookAngles.azimuth;
4176 |
4177 | // Geodetic coords are accessed via `longitude`, `latitude`, `height`.
4178 | const longitude = positionGd.longitude;
4179 | const latitude = positionGd.latitude;
4180 | const height = positionGd.height;
4181 |
4182 | const output = {
4183 | lng: satellitejs.degreesLong(longitude),
4184 | lat: satellitejs.degreesLat(latitude),
4185 | elevation: _radiansToDegrees(lookAngles.elevation),
4186 | azimuth: _radiansToDegrees(azimuth),
4187 | range: lookAngles.rangeSat,
4188 | height,
4189 | velocity: velocityKmS
4190 | };
4191 |
4192 | this.cache[cacheKey] = output;
4193 |
4194 | return output;
4195 | }
4196 |
4197 | /**
4198 | * Determines current satellite position, or position at optional timestamp if passed in.
4199 | */
4200 | getLatLon(tle, optionalTimestamp = Date.now()) {
4201 | const tleObj = this.parseTLE(tle);
4202 |
4203 | // Validation.
4204 | if (!this.isValidTLE(tleObj)) {
4205 | throw new Error('TLE could not be parsed:', tle);
4206 | }
4207 |
4208 | const satInfo = this.getSatelliteInfo(tleObj.arr, optionalTimestamp);
4209 | return {
4210 | lat: satInfo.lat,
4211 | lng: satInfo.lng
4212 | };
4213 | }
4214 |
4215 | /**
4216 | * Determines current satellite position, or position at optional timestamp if passed in.
4217 | */
4218 | getLatLonArr(tle, optionalTimestamp = Date.now()) {
4219 | const ll = this.getLatLon(tle, optionalTimestamp);
4220 | return [ll.lat, ll.lng];
4221 | }
4222 |
4223 | /**
4224 | * Determines the position of the satellite at the time the TLE was generated.
4225 | */
4226 | getLatLonAtEpoch(tle) {
4227 | return this.getLatLon(tle, this.getEpochTimestamp(tle));
4228 | }
4229 |
4230 | /**
4231 | * Determines the average orbit length of the satellite in minutes.
4232 | */
4233 | getAverageOrbitLengthMins(tle) {
4234 | const fnName = 'getAverageOrbitLengthMins';
4235 |
4236 | const tleStr = tle.join('').substr(0, 30);
4237 | const cacheKey = `${fnName}-${tleStr}`;
4238 | if (this.cache[cacheKey]) return this.cache[cacheKey];
4239 |
4240 | const meanMotionSeconds = (24 * 60) / this.getMeanMotion(tle);
4241 |
4242 | this.cache[cacheKey] = meanMotionSeconds;
4243 |
4244 | return meanMotionSeconds;
4245 | }
4246 |
4247 | /**
4248 | * Determines the Unix timestamp (in ms) of the the TLE epoch (when the TLE was generated).
4249 | */
4250 | getTLEEpochTimestamp(tle) {
4251 | const epochYear = this.getEpochYear(tle);
4252 | const epochDayOfYear = this.getEpochDay(tle);
4253 | const timestamp = _dayOfYearToTimeStamp(epochDayOfYear, epochYear);
4254 |
4255 | return timestamp;
4256 | }
4257 |
4258 | /**
4259 | * Determines if the last antemeridian crossing has been cached. If it has, the time (in ms)
4260 | * is returned, otherwise it returns false.
4261 | */
4262 | getCachedLastAntemeridianCrossingTimeMS(tle, timeMS) {
4263 | const orbitLengthMS = this.getAverageOrbitLengthMins(tle.arr) * 60 * 1000;
4264 |
4265 | const tleStr = tle.arr.join('').substr(0, 30);
4266 |
4267 | const cachedCrossingTimes = this.cache.antemeridianCrossings[tleStr];
4268 | if (!cachedCrossingTimes) return false;
4269 |
4270 | if (cachedCrossingTimes === -1) return cachedCrossingTimes;
4271 |
4272 | const cachedTime = cachedCrossingTimes.filter(val => {
4273 | if (typeof val === 'object' && val.tle === tle) return -1;
4274 |
4275 | const diff = timeMS - val;
4276 | const isDiffPositive = diff > 0;
4277 | const isWithinOrbit = isDiffPositive && diff < orbitLengthMS;
4278 | return isWithinOrbit;
4279 | });
4280 |
4281 | return cachedTime[0] || false;
4282 | }
4283 |
4284 | /**
4285 | * Determines the last time the satellite crossed the antemeridian. For mapping convenience
4286 | * and to avoid headaches, we want to avoid plotting ground tracks that cross the antemeridian.
4287 | */
4288 | getLastAntemeridianCrossingTimeMS(tle, timeMS) {
4289 | const parsedTLE = this.parseTLE(tle);
4290 |
4291 | const cachedVal = this.getCachedLastAntemeridianCrossingTimeMS(parsedTLE, timeMS);
4292 | if (cachedVal) return cachedVal;
4293 |
4294 | const time = timeMS || Date.now();
4295 |
4296 | let step = 1000 * 60 * 10;
4297 | let curLatLon = [];
4298 | let lastLatLon = [];
4299 | let curTimeMS = time;
4300 | let didCrossAntemeridian = false;
4301 | let tries = 0;
4302 | let isDone = false;
4303 | const maxTries = 1000;
4304 | while (!isDone) {
4305 | curLatLon = this.getLatLonArr(parsedTLE.arr, curTimeMS);
4306 |
4307 | didCrossAntemeridian = _crossesAntemeridian(lastLatLon[1], curLatLon[1]);
4308 | if (didCrossAntemeridian) {
4309 | // back up
4310 | curTimeMS += step;
4311 | step = (step > 20000) ? 20000 : step / 2;
4312 | } else {
4313 | curTimeMS -= step;
4314 | lastLatLon = curLatLon;
4315 | }
4316 |
4317 | isDone = step < 500 || tries >= maxTries;
4318 |
4319 | tries++;
4320 | }
4321 |
4322 | const couldNotFindCrossing = tries - 1 === maxTries;
4323 | const crossingTime = (couldNotFindCrossing) ? -1 : parseInt(curTimeMS, 10);
4324 |
4325 | const tleStr = parsedTLE.arr.join('').substr(0, 30);
4326 | if (!this.cache.antemeridianCrossings[tleStr]) this.cache.antemeridianCrossings[tleStr] = [];
4327 |
4328 | if (couldNotFindCrossing) {
4329 | this.cache.antemeridianCrossings[tleStr] = -1;
4330 | } else {
4331 | this.cache.antemeridianCrossings[tleStr].push(crossingTime);
4332 | }
4333 |
4334 | return crossingTime;
4335 | }
4336 |
4337 | /**
4338 | * Determines the average amount of milliseconds in one orbit.
4339 | */
4340 | getOrbitTimeMS(tle) {
4341 | return parseInt(_MS_IN_A_DAY / this.getMeanMotion(tle), 10);
4342 | }
4343 |
4344 | /**
4345 | * Calculates three orbit arrays of latitude/longitude pairs.
4346 | *
4347 | * Example:
4348 | * const threeOrbitsArr = tle.getGroundTrackLatLng(tleStr);
4349 | * ->
4350 | * [
4351 | * // previous orbit
4352 | * [
4353 | * [ 45.85524291891481, -179.93297540317567 ],
4354 | * ...
4355 | * ],
4356 | *
4357 | * // current orbit
4358 | * [
4359 | * [ 51.26165992503701, -179.9398612198045 ],
4360 | * ...
4361 | * ],
4362 | *
4363 | * // next orbit
4364 | * [
4365 | * [ 51.0273714070371, -179.9190165549038 ],
4366 | * ...
4367 | * ]
4368 | * ]
4369 | */
4370 | getGroundTrackLatLng(tle, stepMS, optionalTimeMS) {
4371 | const fnName = 'getGroundTrackLatLng';
4372 |
4373 | const timeMS = optionalTimeMS || Date.now();
4374 | const timeS = (timeMS / 1000).toFixed();
4375 |
4376 | const parsedTLE = this.parseTLE(tle);
4377 | const tleStrTrimmed = parsedTLE.arr[1].substr(0, 30);
4378 |
4379 | const orbitTimeMS = this.getOrbitTimeMS(tle);
4380 | const curOrbitStartMS = this.getLastAntemeridianCrossingTimeMS(parsedTLE, timeMS);
4381 |
4382 | const foundCrossing = curOrbitStartMS !== -1;
4383 |
4384 | let cacheKey;
4385 | if (foundCrossing) {
4386 | const curOrbitStartS = (curOrbitStartMS / 1000).toFixed();
4387 |
4388 | // Check for memoized values.
4389 | cacheKey = `${fnName}-${tleStrTrimmed}-${stepMS}-${curOrbitStartS}`;
4390 | if (this.cache[cacheKey]) return this.cache[cacheKey];
4391 | } else {
4392 | // Geosync or unusual orbit.
4393 |
4394 | cacheKey = `${fnName}-${tleStrTrimmed}-${stepMS}-${timeS}`;
4395 | if (this.cache[cacheKey]) return this.cache[cacheKey];
4396 |
4397 | this.cache[cacheKey] = [
4398 | this.getOrbitTrack(parsedTLE.arr, timeMS, 600000, 86400000)
4399 | ];
4400 |
4401 | return this.cache[cacheKey];
4402 | }
4403 |
4404 | const lastOrbitStartMS = this.getLastAntemeridianCrossingTimeMS(tle, curOrbitStartMS - 10000);
4405 | const nextOrbitStartMS = this.getLastAntemeridianCrossingTimeMS(
4406 | tle, curOrbitStartMS + orbitTimeMS + (1000 * 60 * 30));
4407 |
4408 | const orbitStartTimes = [
4409 | lastOrbitStartMS,
4410 | curOrbitStartMS,
4411 | nextOrbitStartMS
4412 | ];
4413 |
4414 | const orbitLatLons = orbitStartTimes.map(
4415 | orbitStartMS => this.getOrbitTrack(parsedTLE.arr, orbitStartMS, stepMS, false)
4416 | );
4417 |
4418 | this.cache[cacheKey] = orbitLatLons;
4419 |
4420 | return orbitLatLons;
4421 | }
4422 |
4423 | /**
4424 | * Generates an array of lat/lng pairs representing a ground track (orbit track), starting
4425 | * from startTimeMS and continuing until crossing the antemeridian, which is considered the end
4426 | * of the orbit for convenience.
4427 | */
4428 | getOrbitTrack(TLEArr, startTimeMS, stepMS, maxTimeMS = 6000000) {
4429 | const fnName = 'getOrbitTrack';
4430 |
4431 | if (!startTimeMS) return [];
4432 |
4433 | // Memoization.
4434 | const tleStr = TLEArr.join('');
4435 | const tleStrTrimmed = tleStr.substr(0, 30);
4436 | const startTime = (startTimeMS / 10000).toFixed();
4437 | const cacheKey = `${fnName}-${tleStrTrimmed}-${startTime}-${stepMS}`;
4438 | if (this.cache[cacheKey]) return this.cache[cacheKey];
4439 |
4440 | // default to 1 minute intervals
4441 | const defaultStepMS = 1000 * 60 * 1;
4442 | let stepMSCopy = stepMS || defaultStepMS;
4443 |
4444 | const latLons = [];
4445 | let curTimeMS = startTimeMS;
4446 | let lastLatLon = [];
4447 | let curLatLon = [];
4448 | let isDone = false;
4449 | let doesCrossAntemeridian = false;
4450 | while (!isDone) {
4451 | curLatLon = this.getLatLonArr(TLEArr, curTimeMS);
4452 |
4453 | doesCrossAntemeridian = _crossesAntemeridian(lastLatLon[1], curLatLon[1]);
4454 | if (doesCrossAntemeridian) {
4455 | if (stepMSCopy === 500) isDone = true;
4456 |
4457 | // Go back a bit.
4458 | curTimeMS -= stepMSCopy;
4459 | stepMSCopy = 500;
4460 | } else {
4461 | latLons.push(curLatLon);
4462 | curTimeMS += stepMSCopy;
4463 | lastLatLon = curLatLon;
4464 | }
4465 |
4466 | if (maxTimeMS && (curTimeMS - startTimeMS > maxTimeMS)) isDone = true;
4467 | }
4468 |
4469 | this.cache[cacheKey] = latLons;
4470 |
4471 | return latLons;
4472 | }
4473 |
4474 | /**
4475 | * Determes the compass bearing from the perspective of the satellite. Useful for 3D / pitched
4476 | * map perspectives.
4477 | *
4478 | * TODO: a bit buggy at extreme parts of orbits, where latitude hardly changes.
4479 | */
4480 | getSatBearing(tle, customTimeMS) {
4481 | const parsedTLE = this.parseTLE(tle);
4482 |
4483 | const timeMS = customTimeMS || Date.now();
4484 |
4485 | const latLon1 = this.getLatLonArr(parsedTLE.arr, timeMS);
4486 | const latLon2 = this.getLatLonArr(parsedTLE.arr, timeMS + 10000);
4487 |
4488 | const doesCrossAntemeridian = _crossesAntemeridian(latLon1[1], latLon2[1]);
4489 |
4490 | if (doesCrossAntemeridian) {
4491 | // TODO: fix
4492 | return {};
4493 | // return this.getSatBearing(tle, customTimeMS + 10000);
4494 | }
4495 |
4496 | const lat1 = _degreesToRadians(latLon1[0]);
4497 | const lat2 = _degreesToRadians(latLon2[0]);
4498 | const lon1 = _degreesToRadians(latLon1[1]);
4499 | const lon2 = _degreesToRadians(latLon2[1]);
4500 |
4501 | const NS = (lat1 >= lat2) ? 'S' : 'N';
4502 | const EW = (lon1 >= lon2) ? 'W' : 'E';
4503 |
4504 | const y = Math.sin(lon2 - lon1) * Math.cos(lat2);
4505 | const x = (Math.cos(lat1) * Math.sin(lat2)) -
4506 | (Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1));
4507 | const degrees = _radiansToDegrees(Math.atan2(y, x));
4508 |
4509 | return {
4510 | degrees,
4511 | compass: `${NS}${EW}`
4512 | };
4513 | }
4514 |
4515 | /**
4516 | * Determines a set of three orbit ground tracks. Similar to getGroundTrackLatLng, except
4517 | * points are returned in reversed order ([longitude, latitude]), which is handy for GeoJSON.
4518 | */
4519 | getGroundTrackLngLat(tle, stepMS, optionalTimeMS) {
4520 | const latLngArr = this.getGroundTrackLatLng(tle, stepMS, optionalTimeMS);
4521 | const lngLatArr = latLngArr.map(line => line.map(latLng => [latLng[1], latLng[0]]));
4522 |
4523 | return lngLatArr;
4524 | }
4525 | }
4526 |
4527 | module.exports = TLEJS;
4528 |
4529 | },{"./constants":18,"./line-defs":19,"./utils":21,"satellite.js":5}],21:[function(require,module,exports){
4530 | const { _MS_IN_A_DAY, _LEADING_ZERO_ASSUMED_PREFIX } = require('./constants');
4531 |
4532 | /**
4533 | * Determines if a number is positive.
4534 | */
4535 | const _isPositive = num => num >= 0;
4536 |
4537 | /**
4538 | * Determines the amount of digits in a number. Used for converting a TLE's "leading decimal
4539 | * assumed" notation.
4540 | *
4541 | * Example:
4542 | * getDigitCount(12345);
4543 | * -> 5
4544 | */
4545 | const _getDigitCount = (num) => {
4546 | const absVal = Math.abs(num);
4547 | return absVal.toString().length;
4548 | };
4549 |
4550 | /**
4551 | * Converts a TLE's "leading decimal assumed" notation to a float representation.
4552 | *
4553 | * Example:
4554 | * toLeadingDecimal(12345);
4555 | * -> 0.12345
4556 | */
4557 | const _toLeadingDecimal = (num) => {
4558 | const numDigits = _getDigitCount(num);
4559 | const zeroes = '0'.repeat(numDigits - 1);
4560 | return parseFloat(num * `${_LEADING_ZERO_ASSUMED_PREFIX}${zeroes}1`);
4561 | };
4562 |
4563 | /**
4564 | * Converts a TLE's "leading decimal assumed" notation with leading zeroes to a float
4565 | * representation.
4566 | *
4567 | * Example:
4568 | * decimalAssumedEToFloat('12345-4');
4569 | * -> 0.000012345
4570 | */
4571 | const _decimalAssumedEToFloat = (str) => {
4572 | const numWithAssumedLeadingDecimal = str.substr(0, str.length - 2);
4573 | const num = _toLeadingDecimal(numWithAssumedLeadingDecimal);
4574 | const leadingDecimalPoints = parseInt(str.substr(str.length - 2, 2), 10);
4575 | const float = num * Math.pow(10, leadingDecimalPoints);
4576 | return float.toPrecision(5);
4577 | };
4578 |
4579 | /**
4580 | * Converts a fractional day of the year to a timestamp. Used for parsing the TLE epoch.
4581 | */
4582 | const _dayOfYearToTimeStamp = (dayOfYear, year = (new Date()).getFullYear()) => {
4583 | const yearStart = new Date(`1/1/${year} 0:0:0 Z`);
4584 |
4585 | const yearStartMS = yearStart.getTime();
4586 |
4587 | return Math.floor(yearStartMS + ((dayOfYear - 1) * _MS_IN_A_DAY));
4588 | };
4589 |
4590 | /**
4591 | * Converts a string divided by spacer characters to camelCase representation.
4592 | *
4593 | * Examples:
4594 | * toCamelCase('foo-bar');
4595 | * -> 'fooBar'
4596 | * toCamelCase('foo bar', ' ');
4597 | * -> 'fooBar'
4598 | */
4599 | const _toCamelCase = (str, divider = '-') => {
4600 | const bits = str.split(divider);
4601 |
4602 | const output = [];
4603 |
4604 | output.push(bits[0]);
4605 |
4606 | for (let i = 1, len = bits.length; i < len; i++) {
4607 | output.push(bits[i].substr(0, 1).toUpperCase() + bits[i].substr(1, bits[i].length - 1));
4608 | }
4609 |
4610 | return output.join('');
4611 | };
4612 |
4613 | /**
4614 | * Converts radians (0 to 2π) to degrees (0 to 360).
4615 | */
4616 | const _radiansToDegrees = radians => radians * (180 / Math.PI);
4617 |
4618 | /**
4619 | * Converts degrees (0 to 360) to radians (0 to 2π).
4620 | */
4621 | const _degreesToRadians = degrees => degrees * (Math.PI / 180);
4622 |
4623 | /**
4624 | * Determines if a pair of longitude points crosses over the antemeridian, which is a
4625 | * pain point for mapping software.
4626 | */
4627 | const _crossesAntemeridian = (longitude1, longitude2) => {
4628 | if (!longitude1 || !longitude2) return false;
4629 |
4630 | const isLong1Positive = _isPositive(longitude1);
4631 | const isLong2Positive = _isPositive(longitude2);
4632 | const haveSameSigns = isLong1Positive === isLong2Positive;
4633 |
4634 | if (haveSameSigns) return false;
4635 |
4636 | // Signs don't match, so check if we're reasonably near the antemeridian (just to be sure it's
4637 | // not the prime meridian).
4638 | const isNearAntemeridian = Math.abs(longitude1) > 100;
4639 |
4640 | return isNearAntemeridian;
4641 | };
4642 |
4643 | module.exports = {
4644 | _isPositive,
4645 | _getDigitCount,
4646 | _toLeadingDecimal,
4647 | _decimalAssumedEToFloat,
4648 | _dayOfYearToTimeStamp,
4649 | _toCamelCase,
4650 | _radiansToDegrees,
4651 | _degreesToRadians,
4652 | _crossesAntemeridian
4653 | };
4654 |
4655 | },{"./constants":18}]},{},[1])(1)
4656 | });
4657 |
--------------------------------------------------------------------------------
/website/wx-ground-station.js:
--------------------------------------------------------------------------------
1 |
2 | //
3 | // Replace BUCKET_NAME with the bucket name.
4 | //
5 | var bucketName = '';
6 | // Replace this block of code with the sample code located at:
7 | // Cognito -- Manage Identity Pools -- [identity_pool_name] -- Sample Code -- JavaScript
8 | //
9 | // Initialize the Amazon Cognito credentials provider
10 | AWS.config.region = 'us-west-2'; // Region
11 | AWS.config.credentials = new AWS.CognitoIdentityCredentials({
12 | IdentityPoolId: ''
13 | });
14 |
15 | // Create a mapbox.com account and get access token
16 | const MAP_BOX_ACCESS_TOKEN = 'YOUR MAPBOX TOKEN';
17 | const GROUND_STATION_LAT = 45.0468;
18 | const GROUND_STATION_LON = -93.4747;
19 | const GROUND_STATION_NAME = 'my ground station';
20 | const MAX_CAPTURES = 20;
21 | const DIR_NAME = "images";
22 |
23 | // Create a new service object
24 | var s3 = new AWS.S3({
25 | apiVersion: '2006-03-01',
26 | params: {Bucket: bucketName}
27 | });
28 |
29 | var tlejs = new TLEJS();
30 | var lastPositionOfNextPass;
31 | var nextPass = null
32 |
33 | function getSatelliteLink(tles) {
34 | var satNum = tlejs.getSatelliteNumber(tles);
35 | return "https://www.n2yo.com/satellite/?s=" + satNum;
36 | }
37 |
38 |
39 | function load() {
40 | $('#location').html(GROUND_STATION_LAT + ', ' + GROUND_STATION_LON);
41 | getUpcomingPassInfo();
42 | getImageMetadata(DIR_NAME, function (err, metadata) {
43 | if (err) {
44 | $('#messages').html('Error getting image metadata: ' + err + '
');
45 | return;
46 | }
47 | $('#messages').html('');
48 |
49 | // show newest first
50 | var sortedMeta = metadata.sort(function (m1, m2) {
51 | var m1key = m1.date + "-" + m1.time;
52 | var m2key = m2.date + "-" + m2.time;
53 | return (m1key > m2key) ? -1 : 1;
54 | });
55 |
56 | var captureCount = 0;
57 |
58 | sortedMeta.forEach(function (m) {
59 | if (++captureCount > MAX_CAPTURES) return;
60 | if (m == null) return;
61 | var mapId = m.imageKey + '-gt';
62 | var satLink = '' + m.satellite + '';
63 | $('#previous_passes').append([
64 | //'
',
65 | '', m.date, ' ', m.time, '
',
66 | '',
67 | '
',
68 | '
',
69 | '
',
70 | '
satellite: ', satLink, '
',
71 | '
elevation: ', m.elevation, '°', '
',
72 | '
direction: ', m.direction, '
',
73 | '
downlink freq: ', m.frequency, ' MHz', '
',
74 | '
gain: ', m.gain, '
',
75 | '
channel A: ', m.chan_a, '
',
76 | '
channel B: ', m.chan_b, '
',
77 | '
',
78 | '
'].join(''));
79 | $('#previous_passes').append([
80 | '',
81 | '
',
82 | '
orbital elements:
',
83 | '
', m.tle1.replace(/ /g, " "), '
',
84 | '
', m.tle2.replace(/ /g, " "), '
',
85 | '
',
86 | '
'].join(''));
87 |
88 | var mapOptions = {
89 | zoomControl: false,
90 | attributionControl: false,
91 | scrollWheelZoom: false,
92 | touchZoom: false,
93 | doubleClickZoom: false,
94 | dragging: false
95 | };
96 | var groundTrackMap = L.map(mapId, mapOptions).setView([GROUND_STATION_LAT, GROUND_STATION_LON], 4);
97 |
98 | L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}', {
99 | attribution: '© Mapbox © OpenStreetMap Improve this map',
100 | tileSize: 512,
101 | maxZoom: 18,
102 | zoomOffset: -1,
103 | id: 'mapbox/streets-v11',
104 | accessToken: MAP_BOX_ACCESS_TOKEN
105 | }).addTo(groundTrackMap);
106 |
107 | var bounds = groundTrackMap.getBounds();
108 | var marker = L.marker([GROUND_STATION_LAT, GROUND_STATION_LON], {title: GROUND_STATION_NAME}).addTo(groundTrackMap);
109 |
110 | var t = m.time.split(' ').join('');
111 | var captureTime = new Date(m.date + 'T' + t).getTime();
112 | if (m.duration) {
113 | // get the current orbit at the middle of the pass duration so it is the correct orbit for the ground station location.
114 | captureTime += (m.duration/2) * 1000;
115 | }
116 |
117 | const orbits = tlejs.getGroundTrackLatLng(
118 | [m.tle1, m.tle2],
119 | 10000,
120 | captureTime
121 | );
122 | var orbit = orbits[1];
123 | var polyline = L.polyline(orbit, {color: 'red'}).addTo(groundTrackMap);
124 | const lat = 0;
125 | const lon = 1;
126 | const tickLength = 0.5;
127 | for(var i=0;i bounds.getSouth())) {
130 | // draw two ticks to indicate direction of orbit
131 | /*
132 |
133 | directionAngle: |
134 | +135deg /|\ -135deg
135 | |
136 | */
137 | var dlon = orbit[i+1][lon] - origin[lon];
138 | var dlat = orbit[i+1][lat] - origin[lat];
139 |
140 | // angle from point i and point i+1
141 | var directionAngle = Math.atan2(dlat,dlon);
142 |
143 | var tickAngle = directionAngle - (135 * (Math.PI/180))
144 | var tick = [tickLength * Math.sin(tickAngle), tickLength * Math.cos(tickAngle)];
145 | var tickPoints = [ [origin[lat], origin[lon]], [origin[lat]+tick[lat], origin[lon]+tick[lon]] ];
146 | L.polyline(tickPoints, {color: 'red'}).addTo(groundTrackMap);
147 |
148 | tickAngle = directionAngle + (135 * (Math.PI/180))
149 | tick = [tickLength * Math.sin(tickAngle), tickLength * Math.cos(tickAngle)];
150 | tickPoints = [ [origin[lat], origin[lon]], [origin[lat]+tick[lat], origin[lon]+tick[lon]] ];
151 | L.polyline(tickPoints, {color: 'red'}).addTo(groundTrackMap);
152 | }
153 | }
154 |
155 | m.images.forEach(function (i) {
156 | if (i.filename.endsWith("-ZA.png")) i.order = 1;
157 | if (i.filename.endsWith("-MCIR.png")) i.order = 2;
158 | if (i.filename.endsWith("-NO.png")) i.order = 3;
159 | if (i.filename.endsWith("-MSA.png")) i.order = 4;
160 | if (i.filename.endsWith("-MSAPRECIP.png")) i.order = 5;
161 | if (i.filename.endsWith("-THERM.png")) i.order = 6;
162 | });
163 | var images = m.images.sort(function (i1, i2) {
164 | return (i1.order < i2.order) ? -1 : 1;
165 | });
166 | var imageHtml = [
167 | ''
168 | ];
169 | images.forEach(function (i) {
170 | if (i.filename.endsWith('-MSAPRECIP.png')) {
171 | return;
172 | }
173 | if (m.chan_a == '3/3B (mid infrared)') {
174 | // Show MSA image if sensor 3 was used.
175 | if (i.filename.endsWith('-MSA.png')) {
176 | return;
177 | }
178 | }
179 | if (m.chan_a != '3/3B (mid infrared)') {
180 | // If no sensor 3 data, then show the thermal IR image.
181 | if (i.filename.endsWith('-THERM.png')) {
182 | return;
183 | }
184 | }
185 | var url = DIR_NAME + '/' + i.filename;
186 | var thumburl = DIR_NAME + '/' + i.thumbfilename;
187 | imageHtml.push([
188 | '
',
189 | '',
190 | '
',
191 | '',
192 | '',
193 | i.enhancement,
194 | '
',
195 | ''].join(''));
196 | });
197 | imageHtml.push('
');
198 | $('#previous_passes').append(imageHtml.join(''));
199 | });
200 | });
201 | }
202 |
203 |
204 | function getImageMetadata(DIR_NAME, cb) {
205 | var pattern = new RegExp(".+-[0-9]+[0-9]+\.json$");
206 | s3.listObjects({Prefix: DIR_NAME}, function(err, data) {
207 | if (err) {
208 | return cb('There was an error viewing the directory: ' + err.message);
209 | }
210 | if (data && data.Contents && (data.Contents.length == 0)) {
211 | return cb('directory not found');
212 | }
213 | var metadataFiles = data.Contents.filter(function (object) {
214 | return pattern.test(object.Key);
215 | });
216 |
217 | var promises = metadataFiles.map(function(md) {
218 | var params = {
219 | Bucket: bucketName,
220 | Key: md.Key
221 | };
222 | return s3.getObject(params).promise().then(function(data) {
223 | var s = JSON.parse(data.Body.toString());
224 | return s;
225 | });
226 | });
227 |
228 | Promise.all(promises).then(function(results) {
229 | cb(null, results);
230 | })
231 |
232 | });
233 | }
234 |
235 | function getUpcomingPassInfo() {
236 |
237 | $.get(DIR_NAME + "/upcoming_passes.json", function(data) {
238 | var now = new Date();
239 | var processingTime = 180000; // approx 3 minutes to process and upload images.
240 | for(var i=0;i now)) {
243 | nextPass = data[i];
244 | }
245 | }
246 | var satLink = '' + nextPass.satellite + '';
247 | var startDate = new Date(nextPass.start);
248 | var endDate = new Date(nextPass.end + processingTime);
249 | $("#upcoming_passes").append([
250 | '',
251 | '
next image capture: ',
252 | satLink,
253 | ' ',
254 | nextPass.direction,
255 | ' at ',
256 | nextPass.elevation,
257 | '° elevation',
258 | '
',
259 | 'capture begins at: ',
260 | ("0" + startDate.getHours()).slice(-2) + ":" + ("0" + startDate.getMinutes()).slice(-2),
261 | '
',
262 | 'imagery approx: ',
263 | ("0" + endDate.getHours()).slice(-2) + ":" + ("0" + endDate.getMinutes()).slice(-2),
264 | '
',
265 | ''].join('')
266 | );
267 |
268 | lastPositionOfNextPass = tlejs.getLatLon([nextPass.tle1, nextPass.tle2], new Date().getTime());
269 |
270 | mapboxgl.accessToken = MAP_BOX_ACCESS_TOKEN;
271 |
272 | var flyoverMap = new mapboxgl.Map({
273 | container: 'flyover_map',
274 | style: 'mapbox://styles/mapbox/satellite-streets-v10',
275 | center: [lastPositionOfNextPass.lng, lastPositionOfNextPass.lat],
276 | pitch: 60,
277 | bearing: 0,
278 | zoom: 3
279 | });
280 |
281 | var staticMap = new mapboxgl.Map({
282 | container: 'static_map',
283 | style: 'mapbox://styles/mapbox/streets-v11',
284 | center: [0, 0],
285 | zoom: 0
286 | });
287 |
288 | function getSatLocation() {
289 | var location = tlejs.getLatLon([nextPass.tle1, nextPass.tle2], new Date().getTime());
290 | return new mapboxgl.LngLat(location.lng, location.lat);
291 | }
292 |
293 | function getSatLocationPoint() {
294 | var l = getSatLocation();
295 | return {
296 | "type": "Point",
297 | "coordinates": [l.lng, l.lat]
298 | };
299 | }
300 |
301 | function getCurrentOrbit() {
302 | var orbits = tlejs.getGroundTrackLatLng(
303 | [nextPass.tle1, nextPass.tle2],
304 | 10000,
305 | new Date().getTime()
306 | );
307 | var currentOrbit = orbits[1]; // [lat, lng] ordering
308 | var r = [];
309 | // Convert to [lng, lat] ordering as required by MapBox APIs
310 | for(var i=0;i {
356 | var currentLocation = getSatLocation();
357 | var bearing = getBearing(currentLocation);
358 | flyoverMap.setCenter([currentLocation.lng, currentLocation.lat]);
359 | flyoverMap.setBearing(bearing);
360 | }, 500);
361 | });
362 |
363 |
364 |
365 | staticMap.on('load', function() {
366 | staticMap.addSource('satellite-location', {
367 | "type": "geojson",
368 | "data": getSatLocationPoint()
369 | });
370 |
371 | staticMap.addSource('current-orbit', {
372 | "type": "geojson",
373 | "data": getOrbitData()
374 | });
375 |
376 |
377 | staticMap.addLayer({
378 | 'id': 'orbit',
379 | 'type': 'line',
380 | 'source': 'current-orbit',
381 | 'layout': {
382 | 'line-cap': 'round',
383 | 'line-join': 'round'
384 | },
385 | 'paint': {
386 | 'line-color': '#eeee00',
387 | 'line-width': 5,
388 | 'line-opacity': .8
389 | }
390 | });
391 |
392 | staticMap.addLayer({
393 | "id": "ground-station",
394 | "type": "circle",
395 | "source": {
396 | "type": "geojson",
397 | "data": {
398 | "type": "Point",
399 | "coordinates": [GROUND_STATION_LON, GROUND_STATION_LAT]
400 | }
401 | },
402 | "paint": {
403 | "circle-radius": 10,
404 | "circle-color": "#ff0000"
405 | }
406 | });
407 |
408 | staticMap.addLayer({
409 | "id": "satellites",
410 | "source": "satellite-location",
411 | "type": "circle",
412 | "paint": {
413 | "circle-radius": 10,
414 | "circle-color": "#007cbf"
415 | }
416 | });
417 |
418 | staticMap.setZoom(0);
419 |
420 | setInterval(() => {
421 | staticMap.getSource('satellite-location').setData(getSatLocationPoint());
422 | }, 500);
423 |
424 | setInterval(() => {
425 | // set the current orbit every minute.
426 | staticMap.getSource('current-orbit').setData(getOrbitData());
427 | }, 60000);
428 |
429 |
430 | });
431 |
432 | });
433 | }
434 |
--------------------------------------------------------------------------------