Commit 12302e70 authored by Christopher Reis's avatar Christopher Reis

Initial Commit

parent c8033378
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="lib" path="C:/Users/Christopher/Development/commons-logging-1.2/commons-logging-1.2.jar"/>
<classpathentry kind="lib" path="C:/Users/Christopher/Development/commons-lang-1.0.jar"/>
<classpathentry kind="lib" path="C:/Users/Christopher/Development/worldwind-2.0.0/worldwind.jar" sourcepath="C:/Users/Christopher/Development/worldwind-2.0.0/src">
<attributes>
<attribute name="javadoc_location" value="file:/C:/Users/Christopher/Development/worldwind-2.0.0/doc/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Users/Christopher/Development/worldwind-2.0.0/worldwindx.jar" sourcepath="C:/Users/Christopher/Development/worldwind-2.0.0/src"/>
<classpathentry kind="output" path="bin"/>
</classpath>
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Satellite</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.8
GPS BIIA-10 (PRN 32)
1 20959U 90103A 15269.04530958 -.00000012 00000-0 00000+0 0 9998
2 20959 54.2520 190.1599 0113066 6.3332 353.8164 2.00562097181868
GPS BIIA-23 (PRN 04)
1 22877U 93068A 15269.45673109 .00000048 00000-0 00000+0 0 9991
2 22877 53.8947 124.4699 0116901 62.6647 290.7571 2.00565876160599
GPS BIIA-24 (PRN 10)
1 23027U 94016A 15269.32112950 -.00000010 00000-0 00000+0 0 9991
2 23027 54.4487 60.9596 0100853 7.1892 348.1763 2.00566855157885
GPS BIIR-2 (PRN 13)
1 24876U 97035A 15269.11865657 .00000015 00000-0 00000+0 0 9998
2 24876 55.7631 251.9503 0044833 120.2510 67.7218 2.00562286133193
GPS BIIR-3 (PRN 11)
1 25933U 99055A 15269.46949601 .00000039 00000-0 00000+0 0 9993
2 25933 51.2373 105.3079 0160236 83.5295 278.3783 2.00568266117013
GPS BIIR-4 (PRN 20)
1 26360U 00025A 15269.43785088 -.00000007 00000-0 00000+0 0 9997
2 26360 53.0688 181.1543 0047003 69.5227 15.1571 2.00566007112704
GPS BIIR-5 (PRN 28)
1 26407U 00040A 15269.44381009 -.00000071 00000-0 00000+0 0 9993
2 26407 56.6839 9.6887 0199858 265.0841 102.7131 2.00561013111389
GPS BIIR-6 (PRN 14)
1 26605U 00071A 15269.25736054 .00000011 00000-0 00000+0 0 9993
2 26605 55.3326 249.9152 0086765 248.5059 279.1881 2.00565181108971
GPS BIIR-7 (PRN 18)
1 26690U 01004A 15269.54360140 -.00000008 00000-0 00000+0 0 9992
2 26690 52.9994 184.1384 0165788 249.3778 216.6594 2.00567512107387
GPS BIIR-8 (PRN 16)
1 27663U 03005A 15269.27710764 -.00000070 00000-0 00000+0 0 9996
2 27663 56.7613 9.3957 0080162 16.8632 353.5989 2.00569326 92747
GPS BIIR-9 (PRN 21)
1 27704U 03010A 15269.24067076 .00000047 00000-0 00000+0 0 9999
2 27704 53.5523 124.3993 0227623 252.6662 53.4906 2.00553830 91549
GPS BIIR-10 (PRN 22)
1 28129U 03058A 15269.21301227 -.00000010 00000-0 00000+0 0 9990
2 28129 52.8750 184.2064 0082094 243.7572 309.7820 2.00561982 86241
GPS BIIR-11 (PRN 19)
1 28190U 04009A 15269.41991616 .00000011 00000-0 00000+0 0 9994
2 28190 55.6275 70.9272 0112369 36.3879 319.6106 2.00392298 84426
GPS BIIR-12 (PRN 23)
1 28361U 04023A 15269.45562346 .00000004 00000-0 00000+0 0 9990
2 28361 54.2951 245.6631 0105230 210.5015 356.9411 2.00548934 82509
GPS BIIR-13 (PRN 02)
1 28474U 04045A 15268.50152568 .00000046 00000-0 00000-0 0 9992
2 28474 53.9468 123.6429 0149667 232.6782 4.1474 2.00567803 79852
GPS BIIRM-1 (PRN 17)
1 28874U 05038A 15269.06841200 .00000009 00000-0 00000+0 0 9997
2 28874 55.7956 68.1190 0106285 245.4297 144.5677 2.00575366 73264
GPS BIIRM-2 (PRN 31)
1 29486U 06042A 15269.08864984 -.00000007 00000-0 00000+0 0 9998
2 29486 55.8027 307.4370 0082577 328.7371 359.7438 2.00572537 65979
GPS BIIRM-3 (PRN 12)
1 29601U 06052A 15269.10632894 -.00000070 00000-0 00000+0 0 9994
2 29601 56.7305 8.3300 0053602 35.1844 346.0325 2.00572178 64893
GPS BIIRM-4 (PRN 15)
1 32260U 07047A 15269.18494997 .00000002 00000-0 00000+0 0 9996
2 32260 53.4258 242.5767 0073939 21.6921 189.7857 2.00557605 58274
GPS BIIRM-5 (PRN 29)
1 32384U 07062A 15269.13956852 .00000010 00000-0 00000+0 0 9997
2 32384 55.8462 68.6592 0009973 321.3935 349.4251 2.00561661 57009
GPS BIIRM-6 (PRN 07)
1 32711U 08012A 15269.30358917 -.00000008 00000-0 00000+0 0 9992
2 32711 55.5235 306.9540 0090373 206.5076 153.0968 2.00560984 55215
GPS BIIRM-8 (PRN 05)
1 35752U 09043A 15268.57723749 -.00000012 00000-0 00000-0 0 9998
2 35752 54.2259 185.0825 0043111 21.4940 203.0615 2.00566073 44789
GPS BIIF-1 (PRN 25)
1 36585U 10022A 15268.57015994 -.00000071 00000-0 00000+0 0 9992
2 36585 56.0667 5.5990 0044830 40.6059 281.8786 2.00569735 39021
GPS BIIF-2 (PRN 01)
1 37753U 11036A 15269.50839363 .00000051 00000-0 00000+0 0 9991
2 37753 55.1690 125.9064 0046142 24.7932 341.5786 2.00565009 30716
GPS BIIF-3 (PRN 24)
1 38833U 12053A 15268.99065042 -.00000006 00000-0 00000+0 0 9999
2 38833 54.5589 304.5054 0033824 13.4913 346.6672 2.00565483 21780
GPS BIIF-4 (PRN 27)
1 39166U 13023A 15269.34471794 .00000001 00000-0 10000-3 0 9991
2 39166 55.5042 65.3298 0025818 14.0462 346.0439 2.00560688 17318
GPS BIIF-5 (PRN 30)
1 39533U 14008A 15269.34542518 -.00000014 00000-0 00000+0 0 9996
2 39533 54.7084 309.6805 0017260 186.9281 173.1181 2.00561224 11685
GPS BIIF-6 (PRN 06)
1 39741U 14026A 15269.12928822 .00000051 00000-0 00000+0 0 9999
2 39741 55.1607 125.4357 0002341 229.4318 130.6452 2.00578995 9966
GPS BIIF-7 (PRN 09)
1 40105U 14045A 15269.21607097 .00000007 00000-0 00000+0 0 9995
2 40105 54.8093 245.2405 0003552 193.2034 166.7722 2.00556010 8413
GPS BIIF-8 (PRN 03)
1 40294U 14068A 15269.08576717 -.00000009 00000-0 00000+0 0 9991
2 40294 54.9610 185.5548 0007478 225.6828 134.2787 2.00571253 6633
GPS BIIF-9 (PRN 26)
1 40534U 15013A 15269.22411217 -.00000073 00000-0 00000+0 0 9999
2 40534 55.0406 5.3040 0001259 322.2203 37.7917 2.00568795 3695
GPS BIIF-10 (PRN 08)
1 40730U 15033A 15268.88935377 .00000003 00000-0 00000+0 0 9990
2 40730 55.0412 65.3058 0015914 258.7905 101.0510 2.00575741 1444
NOAA 1 [-]
1 04793U 70106A 15269.22184748 -.00000034 00000-0 71569-4 0 9996
2 04793 101.8990 323.9675 0032004 29.1728 14.2461 12.53973449 50196
NOAA 2 [-]
1 06235U 72082A 15269.49560619 -.00000035 00000-0 58986-4 0 9997
2 06235 101.5821 236.5542 0004064 121.7621 348.9123 12.53073872964576
NOAA 3 [-]
1 06920U 73086A 15269.49830588 -.00000034 00000-0 74765-4 0 9990
2 06920 101.8437 242.3213 0006334 172.2699 299.0599 12.40353491896471
NOAA 4 [-]
1 07529U 74089A 15269.50725728 -.00000039 00000-0 32428-4 0 9996
2 07529 101.5447 242.3468 0008829 158.6121 311.0402 12.53108302869163
NOAA 5 [-]
1 09057U 76077A 15269.54801728 -.00000029 00000-0 10568-3 0 9991
2 09057 101.7664 262.7119 0010034 26.5616 87.1377 12.37771359770103
TIROS N [P]
1 11060U 78096A 15269.55667835 .00000058 00000-0 50485-4 0 9995
2 11060 98.9826 304.2196 0010122 342.6747 17.4081 14.18066971123747
NOAA 6 [P]
1 11416U 79057A 15269.52985816 .00000156 00000-0 72515-4 0 9994
2 11416 98.5179 254.2471 0009561 316.2979 43.7448 14.33245552889871
NOAA 7 [-]
1 12553U 81059A 15269.55520623 -.00000002 00000-0 21410-4 0 9995
2 12553 98.9637 231.8890 0010517 244.8180 225.3216 14.17157192770151
NOAA 8 [-]
1 13923U 83022A 15269.47119625 .00000086 00000-0 51348-4 0 9990
2 13923 98.4707 265.5246 0014669 210.7362 149.2962 14.28455898691982
NOAA 9 [P]
1 15427U 84123A 15269.45275907 .00000041 00000-0 42834-4 0 9999
2 15427 98.7262 212.4340 0014278 322.8511 147.1277 14.15905372589250
NOAA 10 [-]
1 16969U 86073A 15269.54812954 .00000052 00000-0 38175-4 0 9991
2 16969 98.4838 286.1476 0011546 331.3445 180.1784 14.27921956510570
NOAA 11 [-]
1 19531U 88089A 15269.31125383 .00000009 00000-0 26445-4 0 9995
2 19531 98.6373 339.5960 0012000 48.5960 311.6243 14.15163211393669
NOAA 12 [-]
1 21263U 91032A 15269.50691727 .00000029 00000-0 30553-4 0 9990
2 21263 98.6233 294.8739 0013008 323.5019 198.0046 14.25777830267001
NOAA 13 [-]
1 22739U 93050A 15269.24158186 .00000024 00000-0 35783-4 0 9994
2 22739 98.6526 331.5613 0009866 166.6292 234.3773 14.12620513140508
NOAA 14 [-]
1 23455U 94089A 15269.45164953 -.00000009 00000-0 17875-4 0 9991
2 23455 98.7469 348.7949 0010091 146.6569 271.0540 14.14053117 69849
NOAA 15 [B]
1 25338U 98030A 15269.50110354 .00000083 00000-0 53858-4 0 9997
2 25338 98.7777 268.2305 0009680 230.9244 129.1075 14.25662700903270
NOAA 16 [-]
1 26536U 00055A 15269.48842723 .00000017 00000-0 33351-4 0 9990
2 26536 98.9328 335.3213 0009652 309.7496 50.2825 14.13109186773961
NOAA 17 [-]
1 27453U 02032A 15269.47784998 .00000016 00000-0 24415-4 0 9994
2 27453 98.3506 250.5101 0010531 243.7231 116.2868 14.24900055689083
NOAA 18 [B]
1 28654U 05018A 15269.51876032 .00000056 00000-0 55935-4 0 9996
2 28654 99.1911 264.6679 0014976 39.8046 320.4221 14.12235327533379
NOAA 19 [+]
1 33591U 09005A 15269.49988593 .00000149 00000-0 10603-3 0 9990
2 33591 99.0003 219.6711 0012986 243.4080 116.5761 14.11980612341781
NPP [+]
1 37849U 11061A 15269.45783714 .00000074 00000-0 55620-4 0 9995
2 37849 98.6909 207.0139 0001560 114.6322 353.1198 14.19556415202743
/**
predict4java: An SDP4 / SGP4 library for satellite orbit predictions
Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
This class is a Java port of one of the core elements of
the Predict program, Copyright John A. Magliacane,
KD2BD 1991-2003: http://www.qsl.net/kd2bd/predict.html
Dr. T.S. Kelso is the author of the SGP4/SDP4 orbital models,
originally written in Fortran and Pascal, and released into the
public domain through his website (http://www.celestrak.com/).
Neoklis Kyriazis, 5B4AZ, later re-wrote Dr. Kelso's code in C,
and released it under the GNU GPL in 2002.
PREDICT's core is based on 5B4AZ's code translation efforts.
Author: David A. B. Johnson, G4DPZ <dave@g4dpz.me.uk>
Comments, questions and bugreports should be submitted via
http://sourceforge.net/projects/websat/
More details can be found at the project home page:
http://websat.sourceforge.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, visit http://www.fsf.org/
*/
package predict4java;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicReference;
/**
* Not thread safe!
*/
public abstract class AbstractSatellite implements Satellite {
private static final double MINS_PER_DAY = 1.44E3;
private static final double PI_OVER_TWO = Math.PI / 2.0;
private static final double SECS_PER_DAY = 8.6400E4;
private static final double FLATTENING_FACTOR = 3.35281066474748E-3;
protected static final double CK4 = 6.209887E-7;
protected static final double EARTH_GRAVITATIONAL_CONSTANT = 3.986008E5;
protected static final double S = 1.012229;
protected static final double QOMS2T = 1.880279E-09;
protected static final double EARTH_ROTATIONS_PER_SIDERIAL_DAY = 1.00273790934;
protected static final double EARTH_ROTATIONS_RADIANS_PER_SIDERIAL_DAY = EARTH_ROTATIONS_PER_SIDERIAL_DAY
* TWO_PI;
protected static final double RHO = 1.5696615E-1;
protected static final double MFACTOR = 7.292115E-5;
protected static final double SOLAR_RADIUS_KM = 6.96000E5;
protected static final double ASTRONOMICAL_UNIT = 1.49597870691E8;
protected static final double SPEED_OF_LIGHT = 2.99792458E8;
protected static final double PERIGEE_156_KM = 156.0;
/* WGS 84 Earth radius km */
protected static final double EARTH_RADIUS = 6.378137E3;
/* Solar radius - km (IAU 76) */
protected static final double SOLAR_RADIUS = 6.96000E5;
private double s4;
private double qoms24;
private double perigee;
private final TLE tle;
private double eclipseDepth;
/**
* Position vector of the satellite. Used to store the position for later
* calculations.
*/
private final Vector4 position = new Vector4();
/**
* Velocity vector of the satellite. Used to store the velocity for later
* calculations.
*/
private final Vector4 velocity = new Vector4();
/** Date/time at which the position and velocity were calculated */
private double julUTC;
/** Satellite position. Used to store the SatPos for later calculations. */
private SatPos satPos;
/** The time at which we do all the calculations. */
static final TimeZone TZ = TimeZone.getTimeZone("UTC:UTC");
private final double julEpoch;
public AbstractSatellite(final TLE tle) {
this.tle = tle;
julEpoch = AbstractSatellite.juliandDateOfEpoch(tle.getEpoch());
}
@Override
public final synchronized TLE getTLE() {
return tle;
}
/**
* Calculates the Julian Day of the Year.
*
* The function Julian_Date_of_Year calculates the Julian Date of Day 0.0 of
* {year}. This function is used to calculate the Julian Date of any date by
* using Julian_Date_of_Year, DOY, and Fraction_of_Day.
*
* Astronomical Formulae for Calculators, Jean Meeus, pages 23-25. Calculate
* Julian Date of 0.0 Jan aYear
*
* @param theYear
* the year
* @return the Julian day number
*/
protected static double julianDateOfYear(final double theYear) {
final double aYear = theYear - 1;
long i = (long) Math.floor(aYear / 100);
final long a = i;
i = a / 4;
final long b = 2 - a + i;
i = (long) Math.floor(365.25 * aYear);
i += 30.6001 * 14;
return i + 1720994.5 + b;
}
/**
* The function Julian_Date_of_Epoch returns the Julian Date of an epoch
* specified in the format used in the NORAD two-line element sets. It has
* been modified to support dates beyond the year 1999 assuming that
* two-digit years in the range 00-56 correspond to 2000-2056. Until the
* two-line element set format is changed, it is only valid for dates
* through 2056 December 31.
*
* @param epoch
* the Epoch
* @return The Julian date of the Epoch
*/
static double juliandDateOfEpoch(final double epoch) {
/* Modification to support Y2K */
/* Valid 1957 through 2056 */
double year = Math.floor(epoch * 1E-3);
final double day = (epoch * 1E-3 - year) * 1000.0;
if (year < 57) {
year = year + 2000;
} else {
year = year + 1900;
}
return AbstractSatellite.julianDateOfYear(year) + day;
}
/**
* Read the system clock and return the number of days since 31Dec79
* 00:00:00 UTC (daynum 0).
*
* @param date
* the date we wan to get the offset for
* @return the number of days offset
*/
private static double calcCurrentDaynum(final Date date) {
final long now = date.getTime();
final Calendar sgp4Epoch = Calendar.getInstance(TZ);
sgp4Epoch.clear();
sgp4Epoch.set(1979, 11, 31, 0, 0, 0);
final long then = sgp4Epoch.getTimeInMillis();
final long millis = now - then;
return millis / 1000.0 / 60.0 / 60.0 / 24.0;
}
/**
* Returns the square of a double.
*
* @param arg
* the value for which to get the double
* @return the arg squared
*/
protected static double sqr(final double arg) {
return arg * arg;
}
/**
* Calculates scalar magnitude of a vector4 argument.
*
* @param v
* the vector were measuring
*
*/
protected static void magnitude(final Vector4 v) {
v.setW(Math.sqrt(AbstractSatellite.sqr(v.getX())
+ AbstractSatellite.sqr(v.getY())
+ AbstractSatellite.sqr(v.getZ())));
}
/**
* Multiplies the vector v1 by the scalar k.
*
* @param k
* the multiplier
* @param v
* the vector
*/
private static void scaleVector(final double k, final Vector4 v) {
v.multiply(k);
AbstractSatellite.magnitude(v);
}
/**
* Gets the modulus of a double value.
*
* @param arg1
* the value to be tested
* @param arg2
* the divisor
* @return the remainder
*/
static double modulus(final double arg1, final double arg2) {
/* Returns arg1 mod arg2 */
double returnValue = arg1;
final int i = (int) Math.floor(returnValue / arg2);
returnValue -= i * arg2;
if (returnValue < 0.0) {
returnValue += arg2;
}
return returnValue;
}
private static double frac(final double arg) {
/* Returns fractional part of double argument */
return arg - Math.floor(arg);
}
private static double thetaGJD(final double theJD) {
/* Reference: The 1992 Astronomical Almanac, page B6. */
final double ut = AbstractSatellite.frac(theJD + 0.5);
final double aJD = theJD - ut;
final double tu = (aJD - 2451545.0) / 36525.0;
double gmst = 24110.54841 + tu
* (8640184.812866 + tu * (0.093104 - tu * 6.2E-6));
gmst = AbstractSatellite.modulus(gmst + SECS_PER_DAY
* EARTH_ROTATIONS_PER_SIDERIAL_DAY * ut, SECS_PER_DAY);
return TWO_PI * gmst / SECS_PER_DAY;
}
/**
* Calculates the dot product of two vectors.
*
* @param v1
* vector 1
* @param v2
* vector 2
* @return the dot product
*/
private static double dot(final Vector4 v1, final Vector4 v2) {
return v1.getX() * v2.getX() + v1.getY() * v2.getY() + v1.getZ()
* v2.getZ();
}
/**
* Calculates the modulus of 2 * PI.
*
* @param testValue
* the value under test
* @return the modulus
*/
protected static double mod2PI(final double testValue) {
/* Returns mod 2PI of argument */
double retVal = testValue;
final int i = (int) (retVal / TWO_PI);
retVal -= i * TWO_PI;
if (retVal < 0.0) {
retVal += TWO_PI;
}
return retVal;
}
/**
* Calculate the geodetic position of an object given its ECI position pos
* and time. It is intended to be used to determine the ground track of a
* satellite. The calculations assume the earth to be an oblate spheroid as
* defined in WGS '72.
*
* Reference: The 1992 Astronomical Almanac, page K12.
*
* @param time
* the time
*/
private void calculateLatLonAlt(final double time) {
calculateLatLonAlt(time, satPos, position);
}
private void calculateLatLonAlt(final double time, SatPos satPos,
Vector4 position) {
satPos.setTheta(Math.atan2(position.getY(), position.getX()));
satPos.setLongitude(AbstractSatellite.mod2PI(satPos.getTheta()
- AbstractSatellite.thetaGJD(time)));
final double r = Math.sqrt(AbstractSatellite.sqr(position.getX())
+ AbstractSatellite.sqr(position.getY()));
final double e2 = FLATTENING_FACTOR * (2.0 - FLATTENING_FACTOR);
satPos.setLatitude(Math.atan2(position.getZ(), r));
double phi;
double c;
int i = 0;
boolean converged = false;
do {
phi = satPos.getLatitude();
c = invert(Math.sqrt(1.0 - e2 * sqr(Math.sin(phi))));
satPos.setLatitude(Math.atan2(position.getZ() + EARTH_RADIUS_KM * c
* e2 * Math.sin(phi), r));
converged = Math.abs(satPos.getLatitude() - phi) < EPSILON;
} while (i++ < 10 && !converged);
satPos.setAltitude(r / Math.cos(satPos.getLatitude()) - EARTH_RADIUS_KM
* c);
double temp = satPos.getLatitude();
if (temp > PI_OVER_TWO) {
temp -= TWO_PI;
satPos.setLatitude(temp);
}
}
/**
* Converts the satellite'S position and velocity vectors from normalized
* values to km and km/sec.
*
* @param pos
* the position
* @param vel
* the velocity
*/
private static void convertSatState(final Vector4 pos, final Vector4 vel) {
/* Converts the satellite'S position and velocity */
/* vectors from normalized values to km and km/sec */
AbstractSatellite.scaleVector(EARTH_RADIUS_KM, pos);
AbstractSatellite.scaleVector(EARTH_RADIUS_KM * MINS_PER_DAY
/ SECS_PER_DAY, vel);
}
@Override
public synchronized SatPos getPosition(final GroundStationPosition gsPos,
final Date date) {
/* This is the stuff we need to do repetitively while tracking. */
satPos = new SatPos();
julUTC = AbstractSatellite.calcCurrentDaynum(date) + 2444238.5;
/* Convert satellite'S epoch time to Julian */
/* and calculate time since epoch in minutes */
final double tsince = (julUTC - julEpoch) * MINS_PER_DAY;
calculateSDP4orSGP4(tsince);
/* Scale position and velocity vectors to km and km/sec */
AbstractSatellite.convertSatState(position, velocity);
/* Calculate velocity of satellite */
AbstractSatellite.magnitude(velocity);
final Vector4 squintVector = new Vector4();
//
// /** All angles in rads. Distance in km. Velocity in km/S **/
// /* Calculate satellite Azi, Ele, Range and Range-rate */
calculateObs(julUTC, position, velocity, gsPos, squintVector);
//
/* Calculate satellite Lat North, Lon East and Alt. */
calculateLatLonAlt(julUTC);
satPos.setTime(date);
satPos.setEclipsed(isEclipsed());
satPos.setEclipseDepth(eclipseDepth);
return satPos;
}
private void calculateSDP4orSGP4(final double tsince) {
if (tle.isDeepspace()) {
((DeepSpaceSatellite) this).calculateSDP4(tsince);
} else {
((LEOSatellite) this).calculateSGP4(tsince);
}
}
/**
* Calculate_User_PosVel() passes the user'S observer position and the time
* of interest and returns the ECI position and velocity of the observer.
* The velocity calculation assumes the observer position is stationary
* relative to the earth'S surface.
*
* Reference: The 1992 Astronomical Almanac, page K11.
*
* @param time
* the time
* @param gsPos
* the ground station position
* @param obsPos
* the position of the observer
* @param obsVel
* the velocity of the observer
*/
private static void calculateUserPosVel(final double time,
final GroundStationPosition gsPos,
AtomicReference<Double> gsPosTheta, final Vector4 obsPos,
final Vector4 obsVel) {
gsPosTheta.set(AbstractSatellite.mod2PI(AbstractSatellite
.thetaGJD(time) + DEG2RAD * gsPos.getLongitude()));
final double c = AbstractSatellite
.invert(Math.sqrt(1.0
+ FLATTENING_FACTOR
* (FLATTENING_FACTOR - 2)
* AbstractSatellite.sqr(Math.sin(DEG2RAD
* gsPos.getLatitude()))));
final double sq = AbstractSatellite.sqr(1.0 - FLATTENING_FACTOR) * c;
final double achcp = (EARTH_RADIUS_KM * c + (gsPos.getHeightAMSL() / 1000.0))
* Math.cos(DEG2RAD * gsPos.getLatitude());
obsPos.setXYZ(achcp * Math.cos(gsPosTheta.get()),
achcp * Math.sin(gsPosTheta.get()),
(EARTH_RADIUS_KM * sq + (gsPos.getHeightAMSL() / 1000.0))
* Math.sin(DEG2RAD * gsPos.getLatitude()));
obsVel.setXYZ(-MFACTOR * obsPos.getY(), MFACTOR * obsPos.getX(), 0);
AbstractSatellite.magnitude(obsPos);
AbstractSatellite.magnitude(obsVel);
}
/**
* The procedures Calculate_Obs and Calculate_RADec calculate thetopocentric
* coordinates of the object with ECI position, {pos}, and velocity, {vel},
* from location {geodetic} at {time}. The {obs_set} returned for
* Calculate_Obs consists of azimuth, elevation, range, and range rate (in
* that order) with units of radians, radians, kilometers, and
* kilometers/second, respectively. The WGS '72 geoid is used and the effect
* of atmospheric refraction (under standard temperature and pressure) is
* incorporated into the elevation calculation; the effect of atmospheric
* refraction on range and range rate has not yet been quantified.
*
* The {obs_set} for Calculate_RADec consists of right ascension and
* declination (in that order) in radians. Again, calculations are based
* ontopocentric position using the WGS '72 geoid and incorporating
* atmospheric refraction.
*
* @param julianUTC
* Julian date of UTC
* @param positionVector
* the position vector
* @param velocityVector
* the velocity vector
* @param gsPos
* the ground tstation position
* @param squintVector
* the squint vector
* @param satellitePosition
* the satellite position
*
*/
private void calculateObs(final double julianUTC,
final Vector4 positionVector, final Vector4 velocityVector,
final GroundStationPosition gsPos, final Vector4 squintVector) {
final Vector4 obsPos = new Vector4();
final Vector4 obsVel = new Vector4();
final Vector4 range = new Vector4();
final Vector4 rgvel = new Vector4();
AtomicReference<Double> gsPosTheta = new AtomicReference<Double>();
AbstractSatellite.calculateUserPosVel(julianUTC, gsPos, gsPosTheta,
obsPos, obsVel);
range.setXYZ(positionVector.getX() - obsPos.getX(),
positionVector.getY() - obsPos.getY(), positionVector.getZ()
- obsPos.getZ());
/* Save these values globally for calculating squint angles later... */
squintVector.setXYZ(range.getX(), range.getY(), range.getZ());
rgvel.setXYZ(velocityVector.getX() - obsVel.getX(),
velocityVector.getY() - obsVel.getY(), velocityVector.getZ()
- obsVel.getZ());
AbstractSatellite.magnitude(range);
final double sinLat = Math.sin(DEG2RAD * gsPos.getLatitude());
final double cosLat = Math.cos(DEG2RAD * gsPos.getLatitude());
final double sinTheta = Math.sin(gsPosTheta.get());
final double cosTheta = Math.cos(gsPosTheta.get());
final double topS = sinLat * cosTheta * range.getX() + sinLat
* sinTheta * range.getY() - cosLat * range.getZ();
final double topE = -sinTheta * range.getX() + cosTheta * range.getY();
final double topZ = cosLat * cosTheta * range.getX() + cosLat
* sinTheta * range.getY() + sinLat * range.getZ();
double azim = Math.atan(-topE / topS);
if (topS > 0.0) {
azim = azim + Math.PI;
}
if (azim < 0.0) {
azim = azim + TWO_PI;
}
satPos.setAzimuth(azim);
satPos.setElevation(Math.asin(topZ / range.getW()));
satPos.setRange(range.getW());
satPos.setRangeRate(AbstractSatellite.dot(range, rgvel) / range.getW());
final int sector = (int) (satPos.getAzimuth() / TWO_PI * 360.0 / 10.0);
double elevation = (satPos.getElevation() / Satellite.TWO_PI) * 360.0;
if (elevation > 90) {
elevation = 180 - elevation;
}
satPos.setAboveHorizon((elevation - gsPos.getHorizonElevations()[sector]) > EPSILON);
}
@Override
public boolean willBeSeen(final GroundStationPosition qth) {
if (tle.getMeanmo() < 1e-8) {
return false;
} else {
double lin = tle.getIncl();
if (lin >= 90.0) {
lin = 180.0 - lin;
}
final double sma = 331.25 * Math.exp(Math.log(1440.0 / tle
.getMeanmo()) * (2.0 / 3.0));
final double apogee = sma * (1.0 + tle.getEccn()) - EARTH_RADIUS_KM;
return (Math.acos(EARTH_RADIUS_KM / (apogee + EARTH_RADIUS_KM)) + (lin * DEG2RAD)) > Math
.abs(qth.getLatitude() * DEG2RAD);
}
}
/**
* @return the s4
*/
protected double getS4() {
return s4;
}
/**
* @return the qoms24
*/
protected double getQoms24() {
return qoms24;
}
/**
* Checks and adjusts the calculation if the perigee is less tan 156KM.
*/
private void checkPerigee() {
s4 = S;
qoms24 = QOMS2T;
if (perigee < PERIGEE_156_KM) {
if (perigee <= 98.0) {
s4 = 20.0;
} else {
s4 = perigee - 78.0;
}
qoms24 = Math.pow((120 - s4) / EARTH_RADIUS_KM, 4);
s4 = s4 / EARTH_RADIUS_KM + 1.0;
}
}
/**
* Sets perigee and checks and adjusts the calculation if the perigee is
* less tan 156KM.
*
* @param perigee
* the perigee to set
*/
protected void setPerigee(final double perigee) {
this.perigee = perigee;
checkPerigee();
}
static class Vector4 {
/** the w part of the vector. ` */
private double w;
/** the x part of the vector. ` */
private double x;
/** the y part of the vector. ` */
private double y;
/** the z part of the vector. ` */
private double z;
/** default constructor. */
Vector4() {
this.w = 0.0;
this.x = 0.0;
this.y = 0.0;
this.z = 0.0;
}
/**
* @param w
* the w value
* @param x
* the x value
* @param y
* the y value
* @param z
* the z value
*/
Vector4(final double w, final double x, final double y, final double z) {
this.w = w;
this.x = x;
this.y = y;
this.z = z;
}
/**
* Gets the string representation of the object.
*
* @return the string representation of the object
*/
@Override
public final String toString() {
return "w: " + w + ", x: " + x + ", y: " + y + ", z: " + z;
}
/**
* @return the w
*/
public final double getW() {
return w;
}
/**
* @param w
* the w to set
*/
public final void setW(final double w) {
this.w = w;
}
/**
* @return the x
*/
public final double getX() {
return x;
}
/**
* @param x
* the x to set
*/
public final void setX(final double x) {
this.x = x;
}
/**
* @return the y
*/
public final double getY() {
return y;
}
/**
* @param y
* the y to set
*/
public final void setY(final double y) {
this.y = y;
}
/**
* @return the z
*/
public final double getZ() {
return z;
}
/**
* @param z
* the z to set
*/
public final void setZ(final double z) {
this.z = z;
}
public final void multiply(final double multiplier) {
this.x *= multiplier;
this.y *= multiplier;
this.z *= multiplier;
}
public final void setXYZ(final double xValue, final double yValue,
final double zValue) {
this.x = xValue;
this.y = yValue;
this.z = zValue;
}
public Vector4 subtract(final Vector4 vector) {
return new Vector4(this.w - vector.w, this.x - vector.x, this.y
- vector.y, this.z - vector.z);
}
public static final Vector4 scalarMultiply(final Vector4 vector,
final double multiplier) {
return new Vector4(vector.w * Math.abs(multiplier), vector.x
* multiplier, vector.y * multiplier, vector.z * multiplier);
}
/**
* Calculates the angle between vectors v1 and v2.
*/
public static final double angle(final Vector4 v1, final Vector4 v2) {
AbstractSatellite.magnitude(v1);
AbstractSatellite.magnitude(v2);
return Math.acos(AbstractSatellite.dot(v1, v2) / (v1.w * v2.w));
}
/**
* Subtracts vector v2 from v1.
*/
public static final Vector4 subtract(final Vector4 v1, final Vector4 v2) {
final Vector4 v3 = new Vector4();
v3.x = v1.x - v2.x;
v3.y = v1.y - v2.y;
v3.z = v1.z - v2.z;
AbstractSatellite.magnitude(v3);
return v3;
}
}
/**
* Solves Keplers' Equation.
*
* @param temp
* an array of temporary values we pass around as part of the
* orbit calculation.
* @param axn
* @param ayn
* @param capu
*/
protected static void converge(final double[] temp, final double axn,
final double ayn, final double capu) {
boolean converged = false;
int i = 0;
do {
temp[7] = Math.sin(temp[2]);
temp[8] = Math.cos(temp[2]);
temp[3] = axn * temp[7];
temp[4] = ayn * temp[8];
temp[5] = axn * temp[8];
temp[6] = ayn * temp[7];
final double epw = (capu - temp[4] + temp[3] - temp[2])
/ (1.0 - temp[5] - temp[6]) + temp[2];
if (Math.abs(epw - temp[2]) <= EPSILON) {
converged = true;
} else {
temp[2] = epw;
}
} while (i++ < 10 && !converged);
}
@Override
public synchronized void calculateSatelliteVectors(final Date date) {
// Re-initialize, object can contain data from previous calculations
satPos = new SatPos();
// Date/time for which the satellite position and velocity are
// calculated
julUTC = AbstractSatellite.calcCurrentDaynum(date) + 2444238.5;
// Calculate time since epoch in minutes
final double tsince = (julUTC - julEpoch) * MINS_PER_DAY;
// Calculations of satellite position, no ground stations involved here
// yet
calculateSDP4orSGP4(tsince);
// Scale position and velocity vectors to km and km/s
AbstractSatellite.convertSatState(position, velocity);
// Calculate the magnitude of the velocity of satellite
AbstractSatellite.magnitude(velocity);
satPos.setEclipsed(isEclipsed());
satPos.setEclipseDepth(eclipseDepth);
satPos.setTime(date);
}
@Override
public synchronized SatPos calculateSatelliteGroundTrack() {
calculateLatLonAlt(julUTC);
return this.satPos;
}
@Override
public synchronized SatPos calculateSatPosForGroundStation(
final GroundStationPosition gsPos) {
final Vector4 squintVector = new Vector4();
// All angles in rads. Distance in km. Velocity in km/s
// Calculate satellite Azi, Ele, Range and Range-rate
calculateObs(julUTC, position, velocity, gsPos, squintVector);
return this.satPos;
}
/**
* Determines if the satellite is in sunlight.
*/
private boolean isEclipsed() {
final Vector4 sunVector = calculateSunVector();
/* Calculates stellite's eclipse status and depth */
/* Determine partial eclipse */
final double sdEarth = Math.asin(EARTH_RADIUS / position.w);
final Vector4 rho = Vector4.subtract(sunVector, position);
final double sdSun = Math.asin(SOLAR_RADIUS / rho.w);
final Vector4 earth = Vector4.scalarMultiply(position, -1);
final double delta = Vector4.angle(sunVector, earth);
eclipseDepth = sdEarth - sdSun - delta;
if (sdEarth < sdSun) {
return false;
} else {
return eclipseDepth >= 0;
}
}
private Vector4 calculateSunVector() {
final double mjd = julUTC - 2415020.0;
final double year = 1900 + mjd / 365.25;
final double solTime = (mjd + deltaEt(year) / SECS_PER_DAY) / 36525.0;
final double m = radians(AbstractSatellite.modulus(
358.47583
+ AbstractSatellite.modulus(35999.04975 * solTime,
360.0) - (0.000150 + 0.0000033 * solTime)
* AbstractSatellite.sqr(solTime), 360.0));
final double l = radians(AbstractSatellite.modulus(279.69668
+ AbstractSatellite.modulus(36000.76892 * solTime, 360.0)
+ 0.0003025 * AbstractSatellite.sqr(solTime), 360.0));
final double e = 0.01675104 - (0.0000418 + 0.000000126 * solTime)
* solTime;
final double c = radians((1.919460 - (0.004789 + 0.000014 * solTime)
* solTime)
* Math.sin(m)
+ (0.020094 - 0.000100 * solTime)
* Math.sin(2 * m) + 0.000293 * Math.sin(3 * m));
final double o = radians(AbstractSatellite.modulus(
259.18 - 1934.142 * solTime, 360.0));
final double lsa = AbstractSatellite.modulus(l + c
- radians(0.00569 - 0.00479 * Math.sin(o)), TWO_PI);
final double nu = AbstractSatellite.modulus(m + c, TWO_PI);
double r = 1.0000002 * (1.0 - AbstractSatellite.sqr(e))
/ (1.0 + e * Math.cos(nu));
final double eps = radians(23.452294
- (0.0130125 + (0.00000164 - 0.000000503 * solTime) * solTime)
* solTime + 0.00256 * Math.cos(o));
r = ASTRONOMICAL_UNIT * r;
return new Vector4(r, r * Math.cos(lsa), r * Math.sin(lsa)
* Math.cos(eps), r * Math.sin(lsa) * Math.sin(eps));
}
/**
* The function Delta_ET has been added to allow calculations on the
* position of the sun. It provides the difference between UT (approximately
* the same as UTC) and ET (now referred to as TDT) This function is based
* on a least squares fit of data from 1950 to 1991 and will need to be
* updated periodically.
*
* Values determined using data from 1950-1991 in the 1990 Astronomical
* Almanac. See DELTA_ET.WQ1 for details.
*/
private double deltaEt(final double year) {
return 26.465 + 0.747622 * (year - 1950) + 1.886913
* Math.sin(TWO_PI * (year - 1975) / 33);
}
/**
* Returns angle in radians from argument in degrees.
*/
private double radians(final double degrees) {
return degrees * DEG2RAD;
}
protected void calculatePhase(final double xlt, final double xnode,
final double omgadf) {
/* Phase in radians */
double phaseValue = xlt - xnode - omgadf + TWO_PI;
if (phaseValue < 0.0) {
phaseValue += TWO_PI;
}
satPos.setPhase(AbstractSatellite.mod2PI(phaseValue));
}
protected void calculatePositionAndVelocity(final double rk,
final double uk, final double xnodek, final double xinck,
final double rdotk, final double rfdotk) {
/* Orientation vectors */
final double sinuk = Math.sin(uk);
final double cosuk = Math.cos(uk);
final double sinik = Math.sin(xinck);
final double cosik = Math.cos(xinck);
final double sinnok = Math.sin(xnodek);
final double cosnok = Math.cos(xnodek);
final double xmx = -sinnok * cosik;
final double xmy = cosnok * cosik;
final double ux = xmx * sinuk + cosnok * cosuk;
final double uy = xmy * sinuk + sinnok * cosuk;
final double uz = sinik * sinuk;
final double vx = xmx * cosuk - cosnok * sinuk;
final double vy = xmy * cosuk - sinnok * sinuk;
final double vz = sinik * cosuk;
/* Position and velocity */
position.setXYZ(ux, uy, uz);
position.multiply(rk);
velocity.setX(rdotk * ux + rfdotk * vx);
velocity.setY(rdotk * uy + rfdotk * vy);
velocity.setZ(rdotk * uz + rfdotk * vz);
}
protected static double invert(final double value) {
return 1.0 / value;
}
/**
* @return the eclipseDepth
*/
public final double getEclipseDepth() {
return eclipseDepth;
}
}
/**
predict4java: An SDP4 / SGP4 library for satellite orbit predictions
Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
This class is a Java port of one of the core elements of
the Predict program, Copyright John A. Magliacane,
KD2BD 1991-2003: http://www.qsl.net/kd2bd/predict.html
Dr. T.S. Kelso is the author of the SGP4/SDP4 orbital models,
originally written in Fortran and Pascal, and released into the
public domain through his website (http://www.celestrak.com/).
Neoklis Kyriazis, 5B4AZ, later re-wrote Dr. Kelso's code in C,
and released it under the GNU GPL in 2002.
PREDICT's core is based on 5B4AZ's code translation efforts.
Author: David A. B. Johnson, G4DPZ <dave@g4dpz.me.uk>
Comments, questions and bugreports should be submitted via
http://sourceforge.net/projects/websat/
More details can be found at the project home page:
http://websat.sourceforge.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, visit http://www.fsf.org/
*/
package predict4java;
/**
* DeepSpaceSatellite.
*
* @author g4dpz
*
*/
public class DeepSpaceSatellite extends AbstractSatellite {
private final double c1;
private final double c4;
private final double x1mth2;
private final double x3thm1;
private final double xlcof;
private final double xnodcf;
private final double t2cof;
private final double aycof;
private final double x7thm1;
private final DeepSpaceValueObject dsv;
private final DeepSpaceCalculator deep;
/**
* DeepSpaceSatellite Constructor.
*
* @param tle
* the three line elements
*/
public DeepSpaceSatellite(final TLE tle) {
super(tle);
this.dsv = new DeepSpaceValueObject();
// ////////////////////////////
// initSDP4
// ////////////////////////////
/* Recover original mean motion (xnodp) and */
/* semimajor axis (aodp) from input elements. */
// recoverMeanMotionAndSemiMajorAxis
final double a1 = Math.pow(XKE / getTLE().getXno(), TWO_THIRDS);
dsv.cosio = Math.cos(getTLE().getXincl());
dsv.theta2 = dsv.cosio * dsv.cosio;
x3thm1 = 3.0 * dsv.theta2 - 1;
dsv.eosq = getTLE().getEo() * getTLE().getEo();
dsv.betao2 = 1.0 - dsv.eosq;
dsv.betao = Math.sqrt(dsv.betao2);
final double del1 = 1.5 * CK2 * x3thm1
/ (a1 * a1 * dsv.betao * dsv.betao2);
final double ao = a1
* (1.0 - del1
* (0.5 * TWO_THIRDS + del1 * (1.0 + 134 / 81 * del1)));
final double delo = 1.5 * CK2 * x3thm1
/ (ao * ao * dsv.betao * dsv.betao2);
dsv.xnodp = getTLE().getXno() / (1.0 + delo);
dsv.aodp = ao / (1.0 - delo);
/* For perigee below 156 km, the values */
/* of S and QOMS2T are altered. */
setPerigee((dsv.aodp * (1.0 - getTLE().getEo()) - 1.0)
* EARTH_RADIUS_KM);
final double pinvsq = AbstractSatellite.invert(dsv.aodp * dsv.aodp
* dsv.betao2 * dsv.betao2);
dsv.sing = Math.sin(getTLE().getOmegao());
dsv.cosg = Math.cos(getTLE().getOmegao());
final double tsi = AbstractSatellite.invert(dsv.aodp - getS4());
final double eta = dsv.aodp * getTLE().getEo() * tsi;
final double etasq = eta * eta;
final double eeta = getTLE().getEo() * eta;
final double psisq = Math.abs(1.0 - etasq);
final double coef = getQoms24() * Math.pow(tsi, 4);
final double coef1 = coef / Math.pow(psisq, 3.5);
final double c2 = coef1
* dsv.xnodp
* (dsv.aodp * (1.0 + 1.5 * etasq + eeta * (4.0 + etasq)) + 0.75
* CK2 * tsi / psisq * x3thm1
* (8.0 + 3.0 * etasq * (8.0 + etasq)));
c1 = getTLE().getBstar() * c2;
dsv.sinio = Math.sin(getTLE().getXincl());
final double a3ovk2 = -J3_HARMONIC / CK2;
x1mth2 = 1.0 - dsv.theta2;
c4 = 2
* dsv.xnodp
* coef1
* dsv.aodp
* dsv.betao2
* (eta * (2.0 + 0.5 * etasq) + getTLE().getEo()
* (0.5 + 2 * etasq) - 2
* CK2
* tsi
/ (dsv.aodp * psisq)
* (-3 * x3thm1
* (1.0 - 2 * eeta + etasq * (1.5 - 0.5 * eeta)) + 0.75
* x1mth2
* (2.0 * etasq - eeta * (1.0 + etasq))
* Math.cos(2.0 * getTLE().getOmegao())));
final double theta4 = dsv.theta2 * dsv.theta2;
double temp1 = 3.0 * CK2 * pinvsq * dsv.xnodp;
double temp2 = temp1 * CK2 * pinvsq;
double temp3 = 1.25 * CK4 * pinvsq * pinvsq * dsv.xnodp;
dsv.xmdot = dsv.xnodp + 0.5 * temp1 * dsv.betao * x3thm1 + 0.0625
* temp2 * dsv.betao * (13 - 78 * dsv.theta2 + 137 * theta4);
final double x1m5th = 1.0 - 5 * dsv.theta2;
dsv.omgdot = -0.5 * temp1 * x1m5th + 0.0625 * temp2
* (7.0 - 114 * dsv.theta2 + 395 * theta4) + temp3
* (3.0 - 36 * dsv.theta2 + 49 * theta4);
final double xhdot1 = -temp1 * dsv.cosio;
dsv.xnodot = xhdot1
+ (0.5 * temp2 * (4.0 - 19 * dsv.theta2) + 2 * temp3
* (3.0 - 7 * dsv.theta2)) * dsv.cosio;
xnodcf = 3.5 * dsv.betao2 * xhdot1 * c1;
t2cof = 1.5 * c1;
xlcof = 0.125 * a3ovk2 * dsv.sinio * (3.0 + 5 * dsv.cosio)
/ (1.0 + dsv.cosio);
aycof = 0.25 * a3ovk2 * dsv.sinio;
x7thm1 = 7.0 * dsv.theta2 - 1;
/* initialize Deep() */
this.deep = new DeepSpaceCalculator(tle, dsv);
}
/**
* This function is used to calculate the position and velocity of
* deep-space (period > 225 minutes) satellites. tsince is time since epoch
* in minutes, tle is a pointer to a tle_t structure with Keplerian orbital
* elements and pos and vel are vector_t structures returning ECI satellite
* position and velocity. Use Convert_Sat_State() to convert to km and km/S.
*
* @param tsince
* time since the epoch
* @param position
* the position
* @param velocity
* the velocity
* @param satPos
* the position of the satellite
*/
protected void calculateSDP4(final double tsince) {
synchronized (this) {
final double[] temp = new double[12];
final double xmdf = getTLE().getXmo() + dsv.xmdot * tsince;
final double tsq = tsince * tsince;
final double templ = t2cof * tsq;
dsv.xll = xmdf + dsv.xnodp * templ;
dsv.omgadf = getTLE().getOmegao() + dsv.omgdot * tsince;
final double xnoddf = getTLE().getXnodeo() + dsv.xnodot * tsince;
dsv.xnode = xnoddf + xnodcf * tsq;
final double tempa = 1.0 - c1 * tsince;
final double tempe = getTLE().getBstar() * c4 * tsince;
dsv.xn = dsv.xnodp;
dsv.t = tsince;
deep.dpsec(getTLE());
final double a = Math.pow(XKE / dsv.xn, TWO_THIRDS) * tempa * tempa;
dsv.em = dsv.em - tempe;
deep.dpper();
final double xl = dsv.xll + dsv.omgadf + dsv.xnode;
final double beta = Math.sqrt(1.0 - dsv.em * dsv.em);
dsv.xn = XKE / Math.pow(a, 1.5);
/* Long period periodics */
final double axn = dsv.em * Math.cos(dsv.omgadf);
temp[0] = AbstractSatellite.invert(a * beta * beta);
final double xll = temp[0] * xlcof * axn;
final double aynl = temp[0] * aycof;
final double xlt = xl + xll;
final double ayn = dsv.em * Math.sin(dsv.omgadf) + aynl;
/* Solve Kepler'S Equation */
final double capu = AbstractSatellite.mod2PI(xlt - dsv.xnode);
temp[2] = capu;
AbstractSatellite.converge(temp, axn, ayn, capu);
calculatePositionAndVelocity(temp, a, axn, ayn);
calculatePhase(xlt, dsv.xnode, dsv.omgadf);
}
}
private void calculatePositionAndVelocity(final double[] temp,
final double a, final double axn, final double ayn) {
final double ecose = temp[5] + temp[6];
final double esine = temp[3] - temp[4];
final double elsq = axn * axn + ayn * ayn;
temp[0] = 1.0 - elsq;
final double pl = a * temp[0];
temp[9] = a * (1.0 - ecose);
temp[1] = AbstractSatellite.invert(temp[9]);
temp[10] = XKE * Math.sqrt(a) * esine * temp[1];
temp[11] = XKE * Math.sqrt(pl) * temp[1];
temp[2] = a * temp[1];
final double betal = Math.sqrt(temp[0]);
temp[3] = AbstractSatellite.invert(1.0 + betal);
final double cosu = temp[2] * (temp[8] - axn + ayn * esine * temp[3]);
final double sinu = temp[2] * (temp[7] - ayn - axn * esine * temp[3]);
final double u = Math.atan2(sinu, cosu);
final double sin2u = 2.0 * sinu * cosu;
final double cos2u = 2.0 * cosu * cosu - 1;
temp[0] = AbstractSatellite.invert(pl);
temp[1] = CK2 * temp[0];
temp[2] = temp[1] * temp[0];
/* Update for short periodics */
final double rk = temp[9] * (1.0 - 1.5 * temp[2] * betal * x3thm1)
+ 0.5 * temp[1] * x1mth2 * cos2u;
final double uk = u - 0.25 * temp[2] * x7thm1 * sin2u;
final double xnodek = dsv.xnode + 1.5 * temp[2] * dsv.cosio * sin2u;
final double xinck = dsv.xinc + 1.5 * temp[2] * dsv.cosio * dsv.sinio
* cos2u;
final double rdotk = temp[10] - dsv.xn * temp[1] * x1mth2 * sin2u;
final double rfdotk = temp[11] + dsv.xn * temp[1]
* (x1mth2 * cos2u + 1.5 * x3thm1);
super.calculatePositionAndVelocity(rk, uk, xnodek, xinck, rdotk, rfdotk);
}
final static class DeepSpaceCalculator {
/* This function is used by SDP4 to add lunar and solar */
/* perturbation effects to deep-space orbit objects. */
static final double ZSINIS = 3.9785416E-1;
static final double ZSINGS = -9.8088458E-1;
static final double ZNS = 1.19459E-5;
static final double C1SS = 2.9864797E-6;
static final double ZES = 1.675E-2;
static final double ZNL = 1.5835218E-4;
static final double C1L = 4.7968065E-7;
static final double ZEL = 5.490E-2;
static final double ROOT22 = 1.7891679E-6;
static final double ROOT32 = 3.7393792E-7;
static final double ROOT44 = 7.3636953E-9;
static final double ROOT52 = 1.1428639E-7;
static final double ROOT54 = 2.1765803E-9;
static final double THDT = 4.3752691E-3;
static final double Q22 = 1.7891679E-6;
static final double Q31 = 2.1460748E-6;
static final double Q33 = 2.2123015E-7;
static final double G22 = 5.7686396;
static final double G32 = 9.5240898E-1;
static final double G44 = 1.8014998;
static final double G52 = 1.0508330;
static final double G54 = 4.4108898;
private final double thgr;
private final double xnq;
private final double xqncl;
private final double omegaq;
private final double zmol;
private final double zmos;
// many fields below cannot be final because they are iteratively
// refined
private double savtsn;
private double ee2;
private double e3;
private double xi2;
private double xl2;
private double xl3;
private double xl4;
private double xgh2;
private double xgh3;
private double xgh4;
private double xh2;
private double xh3;
private double sse;
private double ssi;
private double ssg;
private double xi3;
private double se2;
private double si2;
private double sl2;
private double sgh2;
private double sh2;
private double se3;
private double si3;
private double sl3;
private double sgh3;
private double sh3;
private double sl4;
private double sgh4;
private double ssl;
private double ssh;
private double d3210;
private double d3222;
private double d4410;
private double d4422;
private double d5220;
private double d5232;
private double d5421;
private double d5433;
private double del1;
private double del2;
private double del3;
private double fasx2;
private double fasx4;
private double fasx6;
private double xlamo;
private double xfact;
private double xni;
private double atime;
private double stepp;
private double stepn;
private double step2;
private double preep;
private double pl;
private double sghs;
private double xli;
private double d2201;
private double d2211;
private double sghl;
private double sh1;
private double pinc;
private double pe;
private double shs;
private double zsingl;
private double zcosgl;
private double zsinhl;
private double zcoshl;
private double zsinil;
private double zcosil;
private double a1;
private double a2;
private double a3;
private double a4;
private double a5;
private double a6;
private double a7;
private double a8;
private double a9;
private double a10;
private double ainv2;
private double alfdp;
private double aqnv;
private double sgh;
private double sini2;
private double sinis;
private double sinok;
private double sh;
private double si;
private double sil;
private double day;
private double betdp;
private double dalf;
private double bfact;
private double c;
private double cc;
private double cosis;
private double cosok;
private double cosq;
private double ctem;
private double f322;
private double zx;
private double zy;
private double dbet;
private double dls;
private double eoc;
private double eq;
private double f2;
private double f220;
private double f221;
private double f3;
private double f311;
private double f321;
private double xnoh;
private double f330;
private double f441;
private double f442;
private double f522;
private double f523;
private double f542;
private double f543;
private double g200;
private double g201;
private double g211;
private double pgh;
private double ph;
private double s1;
private double s2;
private double s3;
private double s4;
private double s5;
private double s6;
private double s7;
private double se;
private double sel;
private double ses;
private double xls;
private double g300;
private double g310;
private double g322;
private double g410;
private double g422;
private double g520;
private double g521;
private double g532;
private double g533;
private double gam;
private double sinq;
private double sinzf;
private double sis;
private double sl;
private double sll;
private double sls;
private double stem;
private double temp;
private double temp1;
private double x1;
private double x2;
private double x2li;
private double x2omi;
private double x3;
private double x4;
private double x5;
private double x6;
private double x7;
private double x8;
private double xl;
private double xldot;
private double xmao;
private double xnddt;
private double xndot;
private double xno2;
private double xnodce;
private double xnoi;
private double xomi;
private double xpidot;
private double z1;
private double z11;
private double z12;
private double z13;
private double z2;
private double z21;
private double z22;
private double z23;
private double z3;
private double z31;
private double z32;
private double z33;
private double ze;
private double zf;
private double zm;
private double zn;
private double zsing;
private double zsinh;
private double zsini;
private double zcosg;
private double zcosh;
private double zcosi;
private double delt;
private double ft;
private boolean resonance;
private boolean synchronous;
private boolean doLoop;
private boolean epochRestart;
private DeepSpaceValueObject dsv;
private DeepSpaceCalculator(TLE tle, DeepSpaceValueObject dsv) {
this.dsv = dsv;
thgr = thetaG(tle.getRefepoch());
eq = tle.getEo();
xnq = dsv.xnodp;
aqnv = AbstractSatellite.invert(dsv.aodp);
xqncl = tle.getXincl();
xmao = tle.getXmo();
xpidot = dsv.omgdot + dsv.xnodot;
sinq = Math.sin(tle.getXnodeo());
cosq = Math.cos(tle.getXnodeo());
omegaq = tle.getOmegao();
/* Initialize lunar solar terms */
/* Days since 1900 Jan 0.5 */
day = dsv.ds50 + 18261.5;
if (Math.abs(day - preep) > 1.0E-6) {
preep = day;
xnodce = 4.5236020 - 9.2422029E-4 * day;
stem = Math.sin(xnodce);
ctem = Math.cos(xnodce);
zcosil = 0.91375164 - 0.03568096 * ctem;
zsinil = Math.sqrt(1.0 - zcosil * zcosil);
zsinhl = 0.089683511 * stem / zsinil;
zcoshl = Math.sqrt(1.0 - zsinhl * zsinhl);
c = 4.7199672 + 0.22997150 * day;
gam = 5.8351514 + 0.0019443680 * day;
zmol = AbstractSatellite.mod2PI(c - gam);
zx = 0.39785416 * stem / zsinil;
zy = zcoshl * ctem + 0.91744867 * zsinhl * stem;
zx = Math.atan2(zx, zy);
zx = gam + zx - xnodce;
zcosgl = Math.cos(zx);
zsingl = Math.sin(zx);
zmos = AbstractSatellite.mod2PI(6.2565837 + 0.017201977 * day);
} else {
zmol = 0;
zmos = 0;
}
/* Do solar terms */
doSolarTerms();
/* Geopotential resonance initialization for 12 hour orbits */
resonance = false;
synchronous = false;
if (!((xnq < 0.0052359877) && (xnq > 0.0034906585))) {
if ((xnq < 0.00826) || (xnq > 0.00924)) {
return;
}
if (eq < 0.5) {
return;
}
// calculateResonance
resonance = true;
eoc = eq * dsv.eosq;
g201 = -0.306 - (eq - 0.64) * 0.440;
if (eq <= 0.65) {
g211 = 3.616 - 13.247 * eq + 16.290 * dsv.eosq;
g310 = -19.302 + 117.390 * eq - 228.419 * dsv.eosq
+ 156.591 * eoc;
g322 = -18.9068 + 109.7927 * eq - 214.6334 * dsv.eosq
+ 146.5816 * eoc;
g410 = -41.122 + 242.694 * eq - 471.094 * dsv.eosq
+ 313.953 * eoc;
g422 = -146.407 + 841.880 * eq - 1629.014 * dsv.eosq
+ 1083.435 * eoc;
g520 = -532.114 + 3017.977 * eq - 5740 * dsv.eosq
+ 3708.276 * eoc;
} else {
g211 = -72.099 + 331.819 * eq - 508.738 * dsv.eosq
+ 266.724 * eoc;
g310 = -346.844 + 1582.851 * eq - 2415.925 * dsv.eosq
+ 1246.113 * eoc;
g322 = -342.585 + 1554.908 * eq - 2366.899 * dsv.eosq
+ 1215.972 * eoc;
g410 = -1052.797 + 4758.686 * eq - 7193.992 * dsv.eosq
+ 3651.957 * eoc;
g422 = -3581.69 + 16178.11 * eq - 24462.77 * dsv.eosq
+ 12422.52 * eoc;
if (eq <= 0.715) {
g520 = 1464.74 - 4664.75 * eq + 3763.64 * dsv.eosq;
} else {
g520 = -5149.66 + 29936.92 * eq - 54087.36 * dsv.eosq
+ 31324.56 * eoc;
}
}
if (eq < 0.7) {
g533 = -919.2277 + 4988.61 * eq - 9064.77 * dsv.eosq
+ 5542.21 * eoc;
g521 = -822.71072 + 4568.6173 * eq - 8491.4146 * dsv.eosq
+ 5337.524 * eoc;
g532 = -853.666 + 4690.25 * eq - 8624.77 * dsv.eosq
+ 5341.4 * eoc;
} else {
g533 = -37995.78 + 161616.52 * eq - 229838.2 * dsv.eosq
+ 109377.94 * eoc;
g521 = -51752.104 + 218913.95 * eq - 309468.16 * dsv.eosq
+ 146349.42 * eoc;
g532 = -40023.88 + 170470.89 * eq - 242699.48 * dsv.eosq
+ 115605.82 * eoc;
}
sini2 = dsv.sinio * dsv.sinio;
f220 = 0.75 * (1.0 + 2 * dsv.cosio + dsv.theta2);
f221 = 1.5 * sini2;
f321 = 1.875 * dsv.sinio
* (1.0 - 2 * dsv.cosio - 3.0 * dsv.theta2);
f322 = -1.875 * dsv.sinio
* (1.0 + 2 * dsv.cosio - 3.0 * dsv.theta2);
f441 = 35 * sini2 * f220;
f442 = 39.3750 * sini2 * sini2;
f522 = 9.84375
* dsv.sinio
* (sini2 * (1.0 - 2 * dsv.cosio - 5 * dsv.theta2) + 0.33333333 * (-2
+ 4 * dsv.cosio + 6 * dsv.theta2));
f523 = dsv.sinio
* (4.92187512 * sini2
* (-2 - 4 * dsv.cosio + 10 * dsv.theta2) + 6.56250012 * (1.0 + 2 * dsv.cosio - 3.0 * dsv.theta2));
f542 = 29.53125
* dsv.sinio
* (2.0 - 8 * dsv.cosio + dsv.theta2
* (-12 + 8 * dsv.cosio + 10 * dsv.theta2));
f543 = 29.53125
* dsv.sinio
* (-2 - 8 * dsv.cosio + dsv.theta2
* (12 + 8 * dsv.cosio - 10 * dsv.theta2));
xno2 = xnq * xnq;
ainv2 = aqnv * aqnv;
temp1 = 3.0 * xno2 * ainv2;
temp = temp1 * ROOT22;
d2201 = temp * f220 * g201;
d2211 = temp * f221 * g211;
temp1 = temp1 * aqnv;
temp = temp1 * ROOT32;
d3210 = temp * f321 * g310;
d3222 = temp * f322 * g322;
temp1 = temp1 * aqnv;
temp = 2.0 * temp1 * ROOT44;
d4410 = temp * f441 * g410;
d4422 = temp * f442 * g422;
temp1 = temp1 * aqnv;
temp = temp1 * ROOT52;
d5220 = temp * f522 * g520;
d5232 = temp * f523 * g532;
temp = 2.0 * temp1 * ROOT54;
d5421 = temp * f542 * g521;
d5433 = temp * f543 * g533;
xlamo = xmao + tle.getXnodeo() + tle.getXnodeo() - thgr - thgr;
bfact = dsv.xmdot + dsv.xnodot + dsv.xnodot - THDT - THDT;
bfact = bfact + ssl + ssh + ssh;
} else {
// initSynchronousResonanceTerms
resonance = true;
synchronous = true;
g200 = 1.0 + dsv.eosq * (-2.5 + 0.8125 * dsv.eosq);
g310 = 1.0 + 2 * dsv.eosq;
g300 = 1.0 + dsv.eosq * (-6 + 6.60937 * dsv.eosq);
f220 = 0.75 * (1.0 + dsv.cosio) * (1.0 + dsv.cosio);
f311 = 0.9375 * dsv.sinio * dsv.sinio * (1.0 + 3.0 * dsv.cosio)
- 0.75 * (1.0 + dsv.cosio);
f330 = 1.0 + dsv.cosio;
f330 = 1.875 * f330 * f330 * f330;
del1 = 3.0 * xnq * xnq * aqnv * aqnv;
del2 = 2.0 * del1 * f220 * g200 * Q22;
del3 = 3.0 * del1 * f330 * g300 * Q33 * aqnv;
del1 = del1 * f311 * g310 * Q31 * aqnv;
fasx2 = 0.13130908;
fasx4 = 2.8843198;
fasx6 = 0.37448087;
xlamo = xmao + tle.getXnodeo() + tle.getOmegao() - thgr;
bfact = dsv.xmdot + xpidot - THDT;
bfact = bfact + ssl + ssg + ssh;
}
xfact = bfact - xnq;
/* Initialize integrator */
xli = xlamo;
xni = xnq;
atime = 0;
stepp = 720;
stepn = -720;
step2 = 259200;
}
private void doSolarTerms() {
savtsn = 1E20;
zcosg = 1.945905E-1;
zsing = ZSINGS;
zcosi = 9.1744867E-1;
zsini = ZSINIS;
zcosh = cosq;
zsinh = sinq;
cc = C1SS;
zn = ZNS;
ze = ZES;
xnoi = AbstractSatellite.invert(xnq);
/* Solar terms done again after Lunar terms are done */
calculateSolarTerms();
/* Do lunar terms */
calculateLunarTerms();
calculateSolarTerms();
sse = sse + se;
ssi = ssi + si;
ssl = ssl + sl;
ssg = ssg + sgh - dsv.cosio / dsv.sinio * sh;
ssh = ssh + sh / dsv.sinio;
}
/**
*
*/
private void calculateLunarTerms() {
sse = se;
ssi = si;
ssl = sl;
ssh = sh / dsv.sinio;
ssg = sgh - dsv.cosio * ssh;
se2 = ee2;
si2 = xi2;
sl2 = xl2;
sgh2 = xgh2;
sh2 = xh2;
se3 = e3;
si3 = xi3;
sl3 = xl3;
sgh3 = xgh3;
sh3 = xh3;
sl4 = xl4;
sgh4 = xgh4;
zcosg = zcosgl;
zsing = zsingl;
zcosi = zcosil;
zsini = zsinil;
zcosh = zcoshl * cosq + zsinhl * sinq;
zsinh = sinq * zcoshl - cosq * zsinhl;
zn = ZNL;
cc = C1L;
ze = ZEL;
}
/**
*
*/
private void calculateSolarTerms() {
a1 = zcosg * zcosh + zsing * zcosi * zsinh;
a3 = -zsing * zcosh + zcosg * zcosi * zsinh;
a7 = -zcosg * zsinh + zsing * zcosi * zcosh;
a8 = zsing * zsini;
a9 = zsing * zsinh + zcosg * zcosi * zcosh;
a10 = zcosg * zsini;
a2 = dsv.cosio * a7 + dsv.sinio * a8;
a4 = dsv.cosio * a9 + dsv.sinio * a10;
a5 = -dsv.sinio * a7 + dsv.cosio * a8;
a6 = -dsv.sinio * a9 + dsv.cosio * a10;
x1 = a1 * dsv.cosg + a2 * dsv.sing;
x2 = a3 * dsv.cosg + a4 * dsv.sing;
x3 = -a1 * dsv.sing + a2 * dsv.cosg;
x4 = -a3 * dsv.sing + a4 * dsv.cosg;
x5 = a5 * dsv.sing;
x6 = a6 * dsv.sing;
x7 = a5 * dsv.cosg;
x8 = a6 * dsv.cosg;
z31 = 12 * x1 * x1 - 3.0 * x3 * x3;
z32 = 24 * x1 * x2 - 6 * x3 * x4;
z33 = 12 * x2 * x2 - 3.0 * x4 * x4;
z1 = 3.0 * (a1 * a1 + a2 * a2) + z31 * dsv.eosq;
z2 = 6.0 * (a1 * a3 + a2 * a4) + z32 * dsv.eosq;
z3 = 3.0 * (a3 * a3 + a4 * a4) + z33 * dsv.eosq;
z11 = -6 * a1 * a5 + dsv.eosq * (-24 * x1 * x7 - 6 * x3 * x5);
z12 = -6 * (a1 * a6 + a3 * a5) + dsv.eosq
* (-24 * (x2 * x7 + x1 * x8) - 6 * (x3 * x6 + x4 * x5));
z13 = -6 * a3 * a6 + dsv.eosq * (-24 * x2 * x8 - 6 * x4 * x6);
z21 = 6.0 * a2 * a5 + dsv.eosq * (24 * x1 * x5 - 6 * x3 * x7);
z22 = 6.0 * (a4 * a5 + a2 * a6) + dsv.eosq
* (24 * (x2 * x5 + x1 * x6) - 6 * (x4 * x7 + x3 * x8));
z23 = 6.0 * a4 * a6 + dsv.eosq * (24 * x2 * x6 - 6 * x4 * x8);
z1 = z1 + z1 + dsv.betao2 * z31;
z2 = z2 + z2 + dsv.betao2 * z32;
z3 = z3 + z3 + dsv.betao2 * z33;
s3 = cc * xnoi;
s2 = -0.5 * s3 / dsv.betao;
s4 = s3 * dsv.betao;
s1 = -15 * eq * s4;
s5 = x1 * x3 + x2 * x4;
s6 = x2 * x3 + x1 * x4;
s7 = x2 * x4 - x1 * x3;
se = s1 * zn * s5;
si = s2 * zn * (z11 + z13);
sl = -zn * s3 * (z1 + z3 - 14 - 6 * dsv.eosq);
sgh = s4 * zn * (z31 + z33 - 6);
sh = -zn * s2 * (z21 + z23);
if (xqncl < 5.2359877E-2) {
sh = 0;
}
ee2 = 2.0 * s1 * s6;
e3 = 2.0 * s1 * s7;
xi2 = 2.0 * s2 * z12;
xi3 = 2.0 * s2 * (z13 - z11);
xl2 = -2 * s3 * z2;
xl3 = -2 * s3 * (z3 - z1);
xl4 = -2 * s3 * (-21 - 9 * dsv.eosq) * ze;
xgh2 = 2.0 * s4 * z32;
xgh3 = 2.0 * s4 * (z33 - z31);
xgh4 = -18 * s4 * ze;
xh2 = -2 * s2 * z22;
xh3 = -2 * s2 * (z23 - z21);
}
/**
* Entrance for deep space secular effects.
*
* @param tle
* the three line elements
* @param dsv
* the deep space values
*/
private void dpsec(final TLE tle) {
dsv.xll = dsv.xll + ssl * dsv.t;
dsv.omgadf = dsv.omgadf + ssg * dsv.t;
dsv.xnode = dsv.xnode + ssh * dsv.t;
dsv.em = tle.getEo() + sse * dsv.t;
dsv.xinc = tle.getXincl() + ssi * dsv.t;
if (dsv.xinc < 0) {
dsv.xinc = -dsv.xinc;
dsv.xnode = dsv.xnode + Math.PI;
dsv.omgadf = dsv.omgadf - Math.PI;
}
if (!resonance) {
return;
}
do {
processEpochRestartLoop();
} while (doLoop && epochRestart);
dsv.xn = xni + xndot * ft + xnddt * ft * ft * 0.5;
xl = xli + xldot * ft + xndot * ft * ft * 0.5;
temp = -dsv.xnode + thgr + dsv.t * THDT;
if (synchronous) {
dsv.xll = xl - dsv.omgadf + temp;
} else {
dsv.xll = xl + temp + temp;
}
}
/**
*
*/
private void processEpochRestartLoop() {
if ((atime == 0) || ((dsv.t >= 0) && (atime < 0))
|| ((dsv.t < 0) && (atime >= 0))) {
/* Epoch restart */
calclateDelt();
atime = 0;
xni = xnq;
xli = xlamo;
} else if (Math.abs(dsv.t) >= Math.abs(atime)) {
calclateDelt();
}
processNotEpochRestartLoop();
}
private void calclateDelt() {
if (dsv.t < 0) {
delt = stepn;
} else {
delt = stepp;
}
}
/**
*
*/
private void processNotEpochRestartLoop() {
do {
if (Math.abs(dsv.t - atime) >= stepp) {
doLoop = true;
epochRestart = false;
} else {
ft = dsv.t - atime;
doLoop = false;
}
if (Math.abs(dsv.t) < Math.abs(atime)) {
if (dsv.t >= 0) {
delt = stepn;
} else {
delt = stepp;
}
doLoop |= epochRestart;
}
/* Dot terms calculated */
if (synchronous) {
xndot = del1 * Math.sin(xli - fasx2) + del2
* Math.sin(2.0 * (xli - fasx4)) + del3
* Math.sin(3.0 * (xli - fasx6));
xnddt = del1 * Math.cos(xli - fasx2) + 2 * del2
* Math.cos(2.0 * (xli - fasx4)) + 3.0 * del3
* Math.cos(3.0 * (xli - fasx6));
} else {
xomi = omegaq + dsv.omgdot * atime;
x2omi = xomi + xomi;
x2li = xli + xli;
xndot = 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);
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
* (d4410 * Math.cos(x2omi + x2li - G44) + d4422
* Math.cos(x2li - G44) + d5421
* Math.cos(xomi + x2li - G54) + d5433
* Math.cos(-xomi + x2li - G54));
}
xldot = xni + xfact;
xnddt = xnddt * xldot;
if (doLoop) {
xli = xli + xldot * delt + xndot * step2;
xni = xni + xndot * delt + xnddt * step2;
atime = atime + delt;
}
} while (doLoop && !epochRestart);
}
/**
* Entrance for lunar-solar periodics.
*
* @param tle
* the three line elements
* @param dsv
* the deep space values
*/
private void dpper() {
sinis = Math.sin(dsv.xinc);
cosis = Math.cos(dsv.xinc);
if (Math.abs(savtsn - dsv.t) >= 30) {
savtsn = dsv.t;
zm = zmos + ZNS * dsv.t;
zf = zm + 2 * ZES * Math.sin(zm);
sinzf = Math.sin(zf);
f2 = 0.5 * sinzf * sinzf - 0.25;
f3 = -0.5 * sinzf * Math.cos(zf);
ses = se2 * f2 + se3 * f3;
sis = si2 * f2 + si3 * f3;
sls = sl2 * f2 + sl3 * f3 + sl4 * sinzf;
sghs = sgh2 * f2 + sgh3 * f3 + sgh4 * sinzf;
shs = sh2 * f2 + sh3 * f3;
zm = zmol + ZNL * dsv.t;
zf = zm + 2 * ZEL * Math.sin(zm);
sinzf = Math.sin(zf);
f2 = 0.5 * sinzf * sinzf - 0.25;
f3 = -0.5 * sinzf * Math.cos(zf);
sel = ee2 * f2 + e3 * f3;
sil = xi2 * f2 + xi3 * f3;
sll = xl2 * f2 + xl3 * f3 + xl4 * sinzf;
sghl = xgh2 * f2 + xgh3 * f3 + xgh4 * sinzf;
sh1 = xh2 * f2 + xh3 * f3;
pe = ses + sel;
pinc = sis + sil;
pl = sls + sll;
}
pgh = sghs + sghl;
ph = shs + sh1;
dsv.xinc = dsv.xinc + pinc;
dsv.em = dsv.em + pe;
if (xqncl >= 0.2) {
/* Apply periodics directly */
ph = ph / dsv.sinio;
pgh = pgh - dsv.cosio * ph;
dsv.omgadf = dsv.omgadf + pgh;
dsv.xnode = dsv.xnode + ph;
dsv.xll = dsv.xll + pl;
}
else {
applyPeriodics();
/* This is a patch to Lyddane modification */
/* suggested by Rob Matson. */
if (Math.abs(xnoh - dsv.xnode) > Math.PI) {
if (dsv.xnode < xnoh) {
dsv.xnode += TWO_PI;
} else {
dsv.xnode -= TWO_PI;
}
}
dsv.xll = dsv.xll + pl;
dsv.omgadf = xls - dsv.xll - Math.cos(dsv.xinc) * dsv.xnode;
}
}
/**
* Apply periodics with Lyddane modification.
*
* @param dsv
* the space values
*/
private void applyPeriodics() {
sinok = Math.sin(dsv.xnode);
cosok = Math.cos(dsv.xnode);
alfdp = sinis * sinok;
betdp = sinis * cosok;
dalf = ph * cosok + pinc * cosis * sinok;
dbet = -ph * sinok + pinc * cosis * cosok;
alfdp = alfdp + dalf;
betdp = betdp + dbet;
dsv.xnode = AbstractSatellite.mod2PI(dsv.xnode);
xls = dsv.xll + dsv.omgadf + cosis * dsv.xnode;
dls = pl + pgh - pinc * dsv.xnode * sinis;
xls = xls + dls;
xnoh = dsv.xnode;
dsv.xnode = Math.atan2(alfdp, betdp);
}
/**
* The function ThetaG calculates the Greenwich Mean Sidereal Time for
* an epoch specified in the format used in the NORAD two-line element
* sets. It has now been adapted for dates beyond the year 1999, as
* described above. The function ThetaG_JD provides the same calculation
* except that it is based on an input in the form of a Julian Date.
*
* Reference: The 1992 Astronomical Almanac, page B6.
*
* @param epoch
* the epach
* @param dsv
* the deep space values
* @return the Greenwich Mean Sidereal Time
*/
private double thetaG(final double epoch) {
/* Modification to support Y2K */
/* Valid 1957 through 2056 */
double year = Math.floor(epoch * 1E-3);
double dayOfYear = (epoch * 1E-3 - year) * 1000.0;
if (year < 57) {
year = year + 2000;
} else {
year = year + 1900;
}
final double dayFloor = Math.floor(dayOfYear);
final double dayFraction = dayOfYear - dayFloor;
dayOfYear = dayFloor;
final double jd = AbstractSatellite.julianDateOfYear(year)
+ dayOfYear;
dsv.ds50 = jd - 2433281.5 + dayFraction;
return AbstractSatellite
.mod2PI(6.3003880987 * dsv.ds50 + 1.72944494);
}
}
private static final class DeepSpaceValueObject {
private double eosq;
private double sinio;
private double cosio;
private double betao;
private double aodp;
private double theta2;
private double sing;
private double cosg;
private double betao2;
private double xmdot;
private double omgdot;
private double xnodot;
private double xnodp;
/* Used by dpsec and dpper parts of Deep() */
private double xll;
private double omgadf;
private double xnode;
private double em;
private double xinc;
private double xn;
private double t;
/* Used by thetg and Deep() */
private double ds50;
/**
* Default constructor.
*/
private DeepSpaceValueObject() {
}
}
}
/**
predict4java: An SDP4 / SGP4 library for satellite orbit predictions
Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
This class is a Java port of one of the core elements of
the Predict program, Copyright John A. Magliacane,
KD2BD 1991-2003: http://www.qsl.net/kd2bd/predict.html
Dr. T.S. Kelso is the author of the SGP4/SDP4 orbital models,
originally written in Fortran and Pascal, and released into the
public domain through his website (http://www.celestrak.com/).
Neoklis Kyriazis, 5B4AZ, later re-wrote Dr. Kelso's code in C,
and released it under the GNU GPL in 2002.
PREDICT's core is based on 5B4AZ's code translation efforts.
Author: David A. B. Johnson, G4DPZ <dave@g4dpz.me.uk>
Comments, questions and bugreports should be submitted via
http://sourceforge.net/projects/websat/
More details can be found at the project home page:
http://websat.sourceforge.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, visit http://www.fsf.org/
*/
package predict4java;
/**
* The location of the Satellite Ground Station. Instances of this class are
* immutable and thus thread safe.
*
* @author g4dpz
*/
public class GroundStationPosition {
private double latitude;
private double longitude;
private double heightAMSL;
private final int[] horizonElevations = new int[36];
private final String name;
/**
* @param latitude
* the latitue of the ground station in degrees, North: positive
* @param longitude
* the longitude of the ground station in degrees, East: positive
* @param heightAMSL
* the height of te ground station above mean sea level, in
* metres
*/
public GroundStationPosition(final double latitude, final double longitude,
final double heightAMSL) {
this.latitude = latitude;
this.longitude = longitude;
this.heightAMSL = heightAMSL;
this.name = "";
}
/**
* @param latitude
* the latitue of the ground station in degrees, North: positive
* @param longitude
* the longitude of the ground station in degrees, East: positive
* @param heightAMSL
* the height of te ground station above mean sea level, in
* metres
*/
public GroundStationPosition(final double latitude, final double longitude,
final double heightAMSL, String name) {
this.latitude = latitude;
this.longitude = longitude;
this.heightAMSL = heightAMSL;
this.name = name;
}
/**
* @return latitude
*/
public double getLatitude() {
return latitude;
}
/**
* @return longitude
*/
public double getLongitude() {
return longitude;
}
/**
* @return elevation
*/
public double getHeightAMSL() {
return heightAMSL;
}
/**
* Returns a copy of the horizon elevations.
*
* @return the horizonElevations
*/
public final int[] getHorizonElevations() {
final int[] horizonElevationsCopy = new int[horizonElevations.length];
System.arraycopy(horizonElevationsCopy, 0, horizonElevations, 0,
horizonElevations.length);
return horizonElevationsCopy;
}
public String getName() {
return name;
}
}
/**
predict4java: An SDP4 / SGP4 library for satellite orbit predictions
Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
This class is a Java port of one of the core elements of
the Predict program, Copyright John A. Magliacane,
KD2BD 1991-2003: http://www.qsl.net/kd2bd/predict.html
Dr. T.S. Kelso is the author of the SGP4/SDP4 orbital models,
originally written in Fortran and Pascal, and released into the
public domain through his website (http://www.celestrak.com/).
Neoklis Kyriazis, 5B4AZ, later re-wrote Dr. Kelso's code in C,
and released it under the GNU GPL in 2002.
PREDICT's core is based on 5B4AZ's code translation efforts.
Author: David A. B. Johnson, G4DPZ <dave@g4dpz.me.uk>
Comments, questions and bugreports should be submitted via
http://sourceforge.net/projects/websat/
More details can be found at the project home page:
http://websat.sourceforge.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, visit http://www.fsf.org/
*/
package predict4java;
/**
*
* @author g4dpz
*
*/
public class LEOSatellite extends AbstractSatellite {
private final double aodp;
private final double aycof;
private final double c1;
private final double c4;
private final double c5;
private final double cosio;
private final double d2;
private final double d3;
private final double d4;
private final double delmo;
private final double omgcof;
private final double eta;
private final double omgdot;
private final double sinio;
private final double xnodp;
private final double sinmo;
private final double t2cof;
private final double t3cof;
private final double t4cof;
private final double t5cof;
private final double x1mth2;
private final double x3thm1;
private final double x7thm1;
private final double xmcof;
private final double xmdot;
private final double xnodcf;
private final double xnodot;
private final double xlcof;
private final boolean sgp4Simple;
/**
* Creates a Low Earth Orbit Satellite.
*
* @param tle
* the three line elements
*/
public LEOSatellite(final TLE tle) {
super(tle);
/* Recover original mean motion (xnodp) and */
/* semimajor axis (aodp) from input elements. */
final double a1 = Math.pow(XKE / getTLE().getXno(), TWO_THIRDS);
cosio = Math.cos(getTLE().getXincl());
final double theta2 = AbstractSatellite.sqr(cosio);
x3thm1 = 3.0 * theta2 - 1.0;
final double eo = getTLE().getEo();
final double eosq = AbstractSatellite.sqr(eo);
final double betao2 = 1.0 - eosq;
final double betao = Math.sqrt(betao2);
final double del1 = 1.5 * CK2 * x3thm1
/ (AbstractSatellite.sqr(a1) * betao * betao2);
final double ao = a1
* (1.0 - del1
* (0.5 * TWO_THIRDS + del1
* (1.0 + 134.0 / 81.0 * del1)));
final double delo = 1.5 * CK2 * x3thm1
/ (AbstractSatellite.sqr(ao) * betao * betao2);
xnodp = getTLE().getXno() / (1.0 + delo);
aodp = ao / (1.0 - delo);
/* For perigee less than 220 kilometers, the "simple" */
/* flag is set and the equations are truncated to linear */
/* variation in sqrt a and quadratic variation in mean */
/* anomaly. Also, the c3 term, the delta omega term, and */
/* the delta m term are dropped. */
sgp4Simple = (aodp * (1.0 - eo)) < (220 / EARTH_RADIUS_KM + 1.0);
/* For perigees below 156 km, the */
/* values of S and QOMS2T are altered. */
setPerigee((aodp * (1.0 - eo) - 1.0) * EARTH_RADIUS_KM);
final double pinvsq = AbstractSatellite.invert(AbstractSatellite
.sqr(aodp) * AbstractSatellite.sqr(betao2));
final double tsi = AbstractSatellite.invert(aodp - getS4());
eta = aodp * eo * tsi;
final double etasq = eta * eta;
final double eeta = eo * eta;
final double psisq = Math.abs(1.0 - etasq);
final double coef = getQoms24() * Math.pow(tsi, 4);
final double coef1 = coef / Math.pow(psisq, 3.5);
final double bstar = getTLE().getBstar();
final double c2 = coef1
* xnodp
* (aodp * (1.0 + 1.5 * etasq + eeta * (4.0 + etasq)) + 0.75
* CK2 * tsi / psisq * x3thm1
* (8.0 + 3.0 * etasq * (8.0 + etasq)));
c1 = bstar * c2;
sinio = Math.sin(getTLE().getXincl());
final double a3ovk2 = -J3_HARMONIC / CK2;
final double c3 = coef * tsi * a3ovk2 * xnodp * sinio / eo;
x1mth2 = 1.0 - theta2;
final double omegao = getTLE().getOmegao();
c4 = 2
* xnodp
* coef1
* aodp
* betao2
* (eta * (2.0 + 0.5 * etasq) + eo * (0.5 + 2 * etasq) - 2
* CK2
* tsi
/ (aodp * psisq)
* (-3 * x3thm1
* (1.0 - 2 * eeta + etasq * (1.5 - 0.5 * eeta)) + 0.75
* x1mth2
* (2.0 * etasq - eeta * (1.0 + etasq))
* Math.cos(2.0 * omegao)));
c5 = 2.0 * coef1 * aodp * betao2
* (1.0 + 2.75 * (etasq + eeta) + eeta * etasq);
final double theta4 = AbstractSatellite.sqr(theta2);
final double temp1 = 3.0 * CK2 * pinvsq * xnodp;
final double temp2 = temp1 * CK2 * pinvsq;
final double temp3 = 1.25 * CK4 * pinvsq * pinvsq * xnodp;
xmdot = xnodp + 0.5 * temp1 * betao * x3thm1 + 0.0625 * temp2 * betao
* (13.0 - 78.0 * theta2 + 137.0 * theta4);
final double x1m5th = 1.0 - 5.0 * theta2;
omgdot = -0.5 * temp1 * x1m5th + 0.0625 * temp2
* (7.0 - 114.0 * theta2 + 395.0 * theta4) + temp3
* (3.0 - 36.0 * theta2 + 49.0 * theta4);
final double xhdot1 = -temp1 * cosio;
xnodot = xhdot1
+ (0.5 * temp2 * (4.0 - 19.0 * theta2) + 2.0 * temp3
* (3.0 - 7.0 * theta2)) * cosio;
omgcof = bstar * c3 * Math.cos(omegao);
xmcof = -TWO_THIRDS * coef * bstar / eeta;
xnodcf = 3.5 * betao2 * xhdot1 * c1;
t2cof = 1.5 * c1;
xlcof = 0.125 * a3ovk2 * sinio * (3.0 + 5 * cosio) / (1.0 + cosio);
aycof = 0.25 * a3ovk2 * sinio;
final double xmo = getTLE().getXmo();
delmo = Math.pow(1.0 + eta * Math.cos(xmo), 3);
sinmo = Math.sin(xmo);
x7thm1 = 7.0 * theta2 - 1;
if (!sgp4Simple) {
final double c1sq = AbstractSatellite.sqr(c1);
d2 = 4.0 * aodp * tsi * c1sq;
final double temp = d2 * tsi * c1 / 3.0;
d3 = (17 * aodp + getS4()) * temp;
d4 = 0.5 * temp * aodp * tsi * (221 * aodp + 31 * getS4()) * c1;
t3cof = d2 + 2 * c1sq;
t4cof = 0.25 * (3.0 * d3 + c1 * (12 * d2 + 10 * c1sq));
t5cof = 0.2 * (3.0 * d4 + 12 * c1 * d3 + 6 * d2 * d2 + 15 * c1sq
* (2.0 * d2 + c1sq));
} else {
d2 = 0;
d3 = 0;
d4 = 0;
t3cof = 0;
t4cof = 0;
t5cof = 0;
}
}
protected void calculateSGP4(final double tsince) {
synchronized (this) {
final double[] temp = new double[9];
/* Update for secular gravity and atmospheric drag. */
final double xmdf = getTLE().getXmo() + xmdot * tsince;
final double omgadf = getTLE().getOmegao() + omgdot * tsince;
final double xnoddf = getTLE().getXnodeo() + xnodot * tsince;
double omega = omgadf;
double xmp = xmdf;
final double tsq = AbstractSatellite.sqr(tsince);
final double xnode = xnoddf + xnodcf * tsq;
final double bstar = getTLE().getBstar();
double tempa = 1.0 - c1 * tsince;
double tempe = bstar * c4 * tsince;
double templ = t2cof * tsq;
if (!sgp4Simple) {
final double delomg = omgcof * tsince;
final double delm = xmcof
* (Math.pow(1.0 + eta * Math.cos(xmdf), 3) - delmo);
temp[0] = delomg + delm;
xmp = xmdf + temp[0];
omega = omgadf - temp[0];
final double tcube = tsq * tsince;
final double tfour = tsince * tcube;
tempa = tempa - d2 * tsq - d3 * tcube - d4 * tfour;
tempe = tempe + bstar * c5 * (Math.sin(xmp) - sinmo);
templ = templ + t3cof * tcube + tfour
* (t4cof + tsince * t5cof);
}
final double a = aodp * Math.pow(tempa, 2);
final double eo = getTLE().getEo();
final double e = eo - tempe;
final double xl = xmp + omega + xnode + xnodp * templ;
final double beta = Math.sqrt(1.0 - e * e);
final double xn = XKE / Math.pow(a, 1.5);
/* Long period periodics */
final double axn = e * Math.cos(omega);
temp[0] = AbstractSatellite.invert(a * AbstractSatellite.sqr(beta));
final double xll = temp[0] * xlcof * axn;
final double aynl = temp[0] * aycof;
final double xlt = xl + xll;
final double ayn = e * Math.sin(omega) + aynl;
/* Solve Kepler'S Equation */
final double capu = AbstractSatellite.mod2PI(xlt - xnode);
temp[2] = capu;
AbstractSatellite.converge(temp, axn, ayn, capu);
calculatePositionAndVelocity(temp, xnode, a, xn, axn, ayn);
calculatePhase(xlt, xnode, omgadf);
}
}
private void calculatePositionAndVelocity(final double[] temp,
final double xnode, final double a, final double xn,
final double axn, final double ayn) {
final double ecose = temp[5] + temp[6];
final double esine = temp[3] - temp[4];
final double elsq = AbstractSatellite.sqr(axn)
+ AbstractSatellite.sqr(ayn);
temp[0] = 1.0 - elsq;
final double pl = a * temp[0];
final double r = a * (1.0 - ecose);
temp[1] = AbstractSatellite.invert(r);
final double rdot = XKE * Math.sqrt(a) * esine * temp[1];
final double rfdot = XKE * Math.sqrt(pl) * temp[1];
temp[2] = a * temp[1];
final double betal = Math.sqrt(temp[0]);
temp[3] = AbstractSatellite.invert(1.0 + betal);
final double cosu = temp[2] * (temp[8] - axn + ayn * esine * temp[3]);
final double sinu = temp[2] * (temp[7] - ayn - axn * esine * temp[3]);
final double u = Math.atan2(sinu, cosu);
final double sin2u = 2.0 * sinu * cosu;
final double cos2u = 2.0 * cosu * cosu - 1;
temp[0] = AbstractSatellite.invert(pl);
temp[1] = CK2 * temp[0];
temp[2] = temp[1] * temp[0];
/* Update for short periodics */
final double rk = r * (1.0 - 1.5 * temp[2] * betal * x3thm1) + 0.5
* temp[1] * x1mth2 * cos2u;
final double uk = u - 0.25 * temp[2] * x7thm1 * sin2u;
final double xnodek = xnode + 1.5 * temp[2] * cosio * sin2u;
final double xinck = getTLE().getXincl() + 1.5 * temp[2] * cosio
* sinio * cos2u;
final double rdotk = rdot - xn * temp[1] * x1mth2 * sin2u;
final double rfdotk = rfdot + xn * temp[1]
* (x1mth2 * cos2u + 1.5 * x3thm1);
super.calculatePositionAndVelocity(rk, uk, xnodek, xinck, rdotk, rfdotk);
}
}
/**
predict4java: An SDP4 / SGP4 library for satellite orbit predictions
Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
This class is a Java port of one of the core elements of
the Predict program, Copyright John A. Magliacane,
KD2BD 1991-2003: http://www.qsl.net/kd2bd/predict.html
Dr. T.S. Kelso is the author of the SGP4/SDP4 orbital models,
originally written in Fortran and Pascal, and released into the
public domain through his website (http://www.celestrak.com/).
Neoklis Kyriazis, 5B4AZ, later re-wrote Dr. Kelso's code in C,
and released it under the GNU GPL in 2002.
PREDICT's core is based on 5B4AZ's code translation efforts.
Author: David A. B. Johnson, G4DPZ <dave@g4dpz.me.uk>
Comments, questions and bugreports should be submitted via
http://sourceforge.net/projects/websat/
More details can be found at the project home page:
http://websat.sourceforge.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, visit http://www.fsf.org/
*/
package predict4java;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Class which provides Pass Prediction.
*
* @author David A. B. Johnson, g4dpz
*
*/
public class PassPredictor {
private static final String UTC = "UTC";
private static final String SOUTH = "south";
private static final String NORTH = "north";
private static final double SPEED_OF_LIGHT = 2.99792458E8;
private static final double TWOPI = Math.PI * 2.0;
private static final String DEADSPOT_NONE = "none";
/** The time at which we do all the calculations. */
static final TimeZone TZ = TimeZone.getTimeZone(UTC);
private static Log log = LogFactory.getLog(PassPredictor.class);
private final TLE tle;
private final GroundStationPosition qth;
private final Satellite sat;
private int iterationCount;
/**
* Constructor.
*
* @param tle
* the Three Line Elements
* @param qth
* the ground station position
* @throws IllegalArgumentException
* bad argument passed in
* @throws SatNotFoundException
*/
public PassPredictor(final TLE theTLE, final GroundStationPosition theQTH)
throws IllegalArgumentException, SatNotFoundException {
if (null == theTLE) {
throw new IllegalArgumentException("TLE has not been set");
}
if (null == theQTH) {
throw new IllegalArgumentException("QTH has not been set");
}
this.tle = theTLE;
this.qth = theQTH;
sat = SatelliteFactory.createSatellite(tle);
if (null == sat) {
throw new SatNotFoundException("Satellite has not been created");
} else if (!sat.willBeSeen(qth)) {
throw new SatNotFoundException(
"Satellite will never appear above the horizon");
}
}
/**
* Gets the downlink frequency corrected for doppler.
*
* @param freq
* the original frequency in Hz
* @return the doppler corrected frequency in Hz
* @throws InvalidTleException
* bad TLE passed in
* @throws SatNotFoundException
*/
public Long getDownlinkFreq(final Long freq, final Date date)
throws SatNotFoundException {
// get the current position
final Calendar cal = Calendar.getInstance(TZ);
cal.clear();
cal.setTimeInMillis(date.getTime());
final SatPos satPos = getSatPos(cal.getTime());
final double rangeRate = satPos.getRangeRate();
return (long) ((double) freq * (SPEED_OF_LIGHT - rangeRate * 1000.0) / SPEED_OF_LIGHT);
}
public SatPos getSatPos(final Date time) throws SatNotFoundException {
this.iterationCount++;
return sat.getPosition(qth, time);
}
public Long getUplinkFreq(final Long freq, final Date date)
throws SatNotFoundException {
final Calendar cal = Calendar.getInstance(TZ);
cal.clear();
cal.setTimeInMillis(date.getTime());
final SatPos satPos = getSatPos(cal.getTime());
final double rangeRate = satPos.getRangeRate();
return (long) ((double) freq * (SPEED_OF_LIGHT + rangeRate * 1000.0) / SPEED_OF_LIGHT);
}
public SatPassTime nextSatPass(final Date date) throws SatNotFoundException {
return nextSatPass(date, false);
}
public SatPassTime nextSatPass(final Date date, final boolean windBack)
throws SatNotFoundException {
int aosAzimuth = 0;
int losAzimuth = 0;
double maxElevation = 0;
double elevation = 0;
String polePassed = DEADSPOT_NONE;
// get the current position
final Calendar cal = Calendar.getInstance(TZ);
cal.clear();
cal.setTimeInMillis(date.getTime());
// wind back time 1/4 of an orbit
if (windBack) {
double meanMotion = tle.getMeanmo();
cal.add(Calendar.MINUTE, (int) (-24.0 * 60.0 / meanMotion / 4.0));
}
SatPos satPos = getSatPos(cal.getTime());
SatPos prevPos = satPos;
// test for the elevation being above the horizon
if (satPos.getElevation() > 0.0) {
// move time forward in 30 second intervals until the sat goes below
// the horizon
do {
satPos = getPosition(cal, 60);
} while (satPos.getElevation() > 0.0);
// move time forward 3/4 orbit
cal.add(Calendar.MINUTE, threeQuarterOrbitMinutes());
}
Date tca = null;
// now find the next time it comes above the horizon
do {
satPos = getPosition(cal, 60);
final Date now = cal.getTime();
elevation = satPos.getElevation();
if (elevation > maxElevation) {
maxElevation = elevation;
tca = now;
}
} while (satPos.getElevation() < 0.0);
// refine it to 5 seconds
cal.add(Calendar.SECOND, -60);
do {
satPos = getPosition(cal, 5);
final Date now = cal.getTime();
elevation = satPos.getElevation();
if (elevation > maxElevation) {
maxElevation = elevation;
tca = now;
}
prevPos = satPos;
} while (satPos.getElevation() < 0.0);
final Date startDate = satPos.getTime();
aosAzimuth = (int) ((satPos.getAzimuth() / (2.0 * Math.PI)) * 360.0);
// now find when it goes below
do {
satPos = getPosition(cal, 30);
final Date now = cal.getTime();
final String currPolePassed = getPolePassed(prevPos, satPos);
if (!currPolePassed.equals(DEADSPOT_NONE)) {
polePassed = currPolePassed;
}
log.debug("Current pole passed: " + polePassed);
elevation = satPos.getElevation();
if (elevation > maxElevation) {
maxElevation = elevation;
tca = now;
}
prevPos = satPos;
} while (satPos.getElevation() > 0.0);
// refine it to 5 seconds
cal.add(Calendar.SECOND, -30);
do {
satPos = getPosition(cal, 5);
final Date now = cal.getTime();
elevation = satPos.getElevation();
if (elevation > maxElevation) {
maxElevation = elevation;
tca = now;
}
} while (satPos.getElevation() > 0.0);
final Date endDate = satPos.getTime();
losAzimuth = (int) ((satPos.getAzimuth() / (2.0 * Math.PI)) * 360.0);
return new SatPassTime(startDate, endDate, tca, polePassed, aosAzimuth,
losAzimuth, (maxElevation / (2.0 * Math.PI)) * 360.0);
}
/**
* @param cal
* @param offSet
* @return
* @throws InvalidTleException
* @throws SatNotFoundException
*/
private SatPos getPosition(final Calendar cal, final int offSet)
throws SatNotFoundException {
SatPos satPos;
cal.add(Calendar.SECOND, offSet);
satPos = getSatPos(cal.getTime());
return satPos;
}
/**
* Gets a list of SatPassTime
*
* @param start
* Date
*
* newTLE = true; validateData();
* @param end
* Date
* @param firstAosLimit
* in hours
* @return List<SatPassTime>
* @throws SatNotFoundException
* @throws InvalidTleException
*/
public List<SatPassTime> getPasses(final Date start, final int hoursAhead,
final boolean windBack) throws SatNotFoundException {
this.iterationCount = 0;
boolean windBackTime = windBack;
final List<SatPassTime> passes = new ArrayList<SatPassTime>();
Date trackStartDate = start;
final Date trackEndDate = new Date(start.getTime()
+ (hoursAhead * 60L * 60L * 1000L));
Date lastAOS;
int count = 0;
do {
if (count > 0) {
windBackTime = false;
}
final SatPassTime pass = nextSatPass(trackStartDate, windBackTime);
lastAOS = pass.getStartTime();
passes.add(pass);
trackStartDate = new Date(pass.getEndTime().getTime()
+ (threeQuarterOrbitMinutes() * 60L * 1000L));
count++;
} while (lastAOS.compareTo(trackEndDate) < 0);
return passes;
}
/**
* Returns the iterationCount. @VisibleForTesting
*
* @return the iterationCount
*/
final int getIterationCount() {
return iterationCount;
}
/**
* @return time in mS for 3/4 of an orbit
*/
private int threeQuarterOrbitMinutes() {
return (int) (24.0 * 60.0 / tle.getMeanmo() * 0.75);
}
private String getPolePassed(final SatPos prevPos, final SatPos satPos) {
String polePassed = DEADSPOT_NONE;
final double az1 = prevPos.getAzimuth() / TWOPI * 360.0;
final double az2 = satPos.getAzimuth() / TWOPI * 360.0;
if (az1 > az2) {
// we may be moving from 350 or greateer thru north
if (az1 > 350 && az2 < 10) {
polePassed = NORTH;
} else {
// we may be moving from 190 or greateer thru south
if (az1 > 180 && az2 < 180) {
polePassed = SOUTH;
}
}
} else {
// we may be moving from 10 or less through north
if (az1 < 10 && az2 > 350) {
polePassed = NORTH;
} else {
// we may be moving from 170 or more through south
if (az1 < 180 && az2 > 180) {
polePassed = SOUTH;
}
}
}
return polePassed;
}
/**
* Calculates positions of satellite for a given point in time, time range
* and step increment.
*
* @param referenceDate
* @param incrementSeconds
* @param minutesBefore
* @param minutesAfter
* @return list of SatPos
* @throws SatNotFoundException
* @throws InvalidTleException
*/
public List<SatPos> getPositions(final Date referenceDate,
final int incrementSeconds, final int minutesBefore,
final int minutesAfter) throws SatNotFoundException {
Date trackDate = new Date(referenceDate.getTime()
- (minutesBefore * 60L * 1000L));
final Date endDateDate = new Date(referenceDate.getTime()
+ (minutesAfter * 60L * 1000L));
final List<SatPos> positions = new ArrayList<SatPos>();
while (trackDate.before(endDateDate)) {
positions.add(getSatPos(trackDate));
trackDate = new Date(trackDate.getTime()
+ (incrementSeconds * 1000));
}
return positions;
}
}
package predict4java;
/**
* Immutable class created to avoid returning ugly 2d arrays of lat long points
* from api methods.
*
* @author Dave Moten
*
*/
public class Position {
private final double lat;
private final double lon;
public Position(double lat, double lon) {
super();
this.lat = lat;
this.lon = lon;
}
public double getLat() {
return lat;
}
public double getLon() {
return lon;
}
@Override
public String toString() {
return "Position [lat=" + lat + ", lon=" + lon + "]";
}
}
/**
predict4java: An SDP4 / SGP4 library for satellite orbit predictions
Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
This class is a Java port of one of the core elements of
the Predict program, Copyright John A. Magliacane,
KD2BD 1991-2003: http://www.qsl.net/kd2bd/predict.html
Dr. T.S. Kelso is the author of the SGP4/SDP4 orbital models,
originally written in Fortran and Pascal, and released into the
public domain through his website (http://www.celestrak.com/).
Neoklis Kyriazis, 5B4AZ, later re-wrote Dr. Kelso's code in C,
and released it under the GNU GPL in 2002.
PREDICT's core is based on 5B4AZ's code translation efforts.
Author: David A. B. Johnson, G4DPZ <dave@g4dpz.me.uk>
Comments, questions and bugreports should be submitted via
http://sourceforge.net/projects/websat/
More details can be found at the project home page:
http://websat.sourceforge.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, visit http://www.fsf.org/
*/
package predict4java;
/**
* @author David A. B. Johnson, g4dpz
*/
public class SatNotFoundException extends Exception {
private static final long serialVersionUID = 3389434245667560642L;
/**
* @param message
*/
public SatNotFoundException(final String message) {
super(message);
}
}
/**
predict4java: An SDP4 / SGP4 library for satellite orbit predictions
Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
This class is a Java port of one of the core elements of
the Predict program, Copyright John A. Magliacane,
KD2BD 1991-2003: http://www.qsl.net/kd2bd/predict.html
Dr. T.S. Kelso is the author of the SGP4/SDP4 orbital models,
originally written in Fortran and Pascal, and released into the
public domain through his website (http://www.celestrak.com/).
Neoklis Kyriazis, 5B4AZ, later re-wrote Dr. Kelso's code in C,
and released it under the GNU GPL in 2002.
PREDICT's core is based on 5B4AZ's code translation efforts.
Author: David A. B. Johnson, G4DPZ <dave@g4dpz.me.uk>
Comments, questions and bugreports should be submitted via
http://sourceforge.net/projects/websat/
More details can be found at the project home page:
http://websat.sourceforge.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, visit http://www.fsf.org/
*/
package predict4java;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class SatPassTime {
private final Date startTime;
private final Date endTime;
private final Date tca;
private final String polePassed;
private final int aos;
private final int los;
private final double maxEl;
private static final String NEW_LINE = "\n";
private static final String DEG_NL = " deg.\n";
private static final SimpleDateFormat TIME_FORMAT;
private static final SimpleDateFormat DATE_FORMAT;
static {
TIME_FORMAT = new SimpleDateFormat("h:mm a");
TIME_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
DATE_FORMAT = new SimpleDateFormat("MMMMMM d, yyyy");
DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
}
public SatPassTime(final Date startTime, final Date endTime,
final String polePassed, final int aos, final int los,
final double maxEl) {
this(startTime, endTime, new Date(
(startTime.getTime() + endTime.getTime()) / 2), polePassed,
aos, los, maxEl);
}
public SatPassTime(final Date startTime, final Date endTime,
final Date tca, final String polePassed, final int aosAzimuth,
final int losAzimuth, final double maxEl) {
this.startTime = new Date(startTime.getTime());
this.endTime = new Date(endTime.getTime());
this.polePassed = polePassed;
this.aos = aosAzimuth;
this.los = losAzimuth;
this.maxEl = maxEl;
this.tca = new Date(tca.getTime());
}
public final Date getStartTime() {
return new Date(startTime.getTime());
}
public final Date getEndTime() {
return new Date(endTime.getTime());
}
public final Date getTCA() {
return new Date(tca.getTime());
}
public final String getPolePassed() {
return polePassed;
}
/**
* @return the aos azimuth
*/
public final int getAosAzimuth() {
return aos;
}
/**
* @return the los azimuth
*/
public final int getLosAzimuth() {
return los;
}
/**
* @return the maxEl
*/
public final double getMaxEl() {
return maxEl;
}
private synchronized static String formatDate(Date date) {
return DATE_FORMAT.format(date);
}
private synchronized static String formatTime(Date date) {
return TIME_FORMAT.format(date);
}
/**
* Returns a string representing the contents of the object.
*/
@Override
public String toString() {
final double duration = (endTime.getTime() - startTime.getTime()) / 60000.0;
return "Date: " + formatDate(startTime) + NEW_LINE
+ "Start Time: "
+ formatTime(startTime)
+ NEW_LINE
+
// "End Time: " + mTimeFormatter.format(endDate_time) + "\n" +
String.format("Duration: %4.1f min.%n", duration)
+ "AOS Azimuth: " + aos + DEG_NL
+ String.format("Max Elevation: %4.1f deg.%n", maxEl)
+ "LOS Azimuth: " + los + " deg.";
}
}
/**
predict4java: An SDP4 / SGP4 library for satellite orbit predictions
Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
This class is a Java port of one of the core elements of
the Predict program, Copyright John A. Magliacane,
KD2BD 1991-2003: http://www.qsl.net/kd2bd/predict.html
Dr. T.S. Kelso is the author of the SGP4/SDP4 orbital models,
originally written in Fortran and Pascal, and released into the
public domain through his website (http://www.celestrak.com/).
Neoklis Kyriazis, 5B4AZ, later re-wrote Dr. Kelso's code in C,
and released it under the GNU GPL in 2002.
PREDICT's core is based on 5B4AZ's code translation efforts.
Author: David A. B. Johnson, G4DPZ <dave@g4dpz.me.uk>
Comments, questions and bugreports should be submitted via
http://sourceforge.net/projects/websat/
More details can be found at the project home page:
http://websat.sourceforge.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, visit http://www.fsf.org/
*/
package predict4java;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
*
* @author g4dpz
*
*/
public class SatPos {
private static final String NL = "\n";
private static final String DEG_CR = " deg.\n";
/* WGS 84 Earth radius km */
private static final double EARTH_RADIUS_KM = 6.378137E3;
private static final double R0 = 6378.16;
// the internal representation will be in radians
private double azimuth;
private double elevation;
private double latitude;
private double longitude;
private Date time;
private double range;
private double rangeRate;
private double phase;
private double altitude;
private double theta;
private double eclipseDepth;
private boolean eclipsed;
private boolean aboveHorizon;
/**
* Default constructor.
*/
public SatPos() {
}
/**
* Constructs a Satellite Position.
*
* @param azimuth
* the Azimuth
* @param elevation
* the Elevation
* @param theTime
* the Time
*/
public SatPos(final double azimuth, final double elevation,
final Date theTime) {
this.azimuth = azimuth;
this.elevation = elevation;
this.time = new Date(theTime.getTime());
}
/**
* @return the azimuth
*/
public double getAzimuth() {
return azimuth;
}
/**
* @return the elevation
*/
public double getElevation() {
return elevation;
}
/**
* @return time for the SatPos
*/
public Date getTime() {
return new Date(time.getTime());
}
/**
* @return the range
*/
public final double getRange() {
return range;
}
/**
* @param range
* the range to set
*/
public final void setRange(final double range) {
this.range = range;
}
/**
* @return the rangeRate
*/
public final double getRangeRate() {
return rangeRate;
}
/**
* @param rangeRate
* the rangeRate to set
*/
public final void setRangeRate(final double rangeRate) {
this.rangeRate = rangeRate;
}
/**
* @return the phase
*/
public final double getPhase() {
return phase;
}
/**
* @param phase
* the phase to set
*/
public final void setPhase(final double phase) {
this.phase = phase;
}
/**
* @return the latitude
*/
public final double getLatitude() {
return latitude;
}
/**
* @param latitude
* the latitude to set
*/
public final void setLatitude(final double latitude) {
this.latitude = latitude;
}
/**
* @return the longitude
*/
public final double getLongitude() {
return longitude;
}
/**
* @param longitude
* the longitude to set
*/
public final void setLongitude(final double longitude) {
this.longitude = longitude;
}
/**
* @return the altitude in km
*/
public final double getAltitude() {
return altitude;
}
/**
* @param altitude
* the altitude to set
*/
public final void setAltitude(final double altitude) {
this.altitude = altitude;
}
/**
* @return the theta
*/
public final double getTheta() {
return theta;
}
/**
* @param theta
* the theta to set
*/
public final void setTheta(final double theta) {
this.theta = theta;
}
/**
* @param azimuth
* the azimuth to set
*/
public final void setAzimuth(final double azimuth) {
this.azimuth = azimuth;
}
/**
* @param elevation
* the elevation to set
*/
public final void setElevation(final double elevation) {
this.elevation = elevation;
}
/**
* @param time
* the time to set
*/
public final void setTime(final Date time) {
this.time = new Date(time.getTime());
}
/**
* @return the aboveHorizon
*/
public final boolean isAboveHorizon() {
return aboveHorizon;
}
/**
* @param aboveHorizon
* the aboveHorizon to set
*/
public final void setAboveHorizon(final boolean aboveHorizon) {
this.aboveHorizon = aboveHorizon;
}
/**
* @return the eclipseDepth
*/
protected final double getEclipseDepth() {
return eclipseDepth;
}
/**
* @param eclipseDepth
* the eclipseDepth to set
*/
protected final void setEclipseDepth(final double eclipseDepth) {
this.eclipseDepth = eclipseDepth;
}
/**
* @return the eclipsed
*/
protected final boolean isEclipsed() {
return eclipsed;
}
/**
* @param eclipsed
* the eclipsed to set
*/
protected final void setEclipsed(final boolean eclipsed) {
this.eclipsed = eclipsed;
}
/**
* @return a pretty printed version of the Satellite Position
*/
@Override
public String toString() {
return "Azimuth: " + azimuth / (Math.PI * 2.0) * 360 + DEG_CR
+ "Elevation: " + elevation / (Math.PI * 2.0) * 360 + DEG_CR
+ "Latitude: " + latitude / (Math.PI * 2.0) * 360 + DEG_CR
+ "Longitude: " + longitude / (Math.PI * 2.0) * 360 + DEG_CR
+ "Date: " + time + NL + "Range: " + range
+ " km.\n" + "Range rate: " + rangeRate + " m/S.\n"
+ "Phase: " + phase + " /(256)\n" + "Altitude: "
+ altitude + " km\n" + "Theta: " + theta + " rad/sec\n"
+ "Eclipsed: " + eclipsed + NL + "Eclipse depth:"
+ eclipseDepth + " radians\n";
}
public String toShortString() {
String returnString = "";
final NumberFormat numberFormat = NumberFormat.getNumberInstance();
numberFormat.setMaximumFractionDigits(0);
returnString = returnString + "Elevation: "
+ numberFormat.format(elevation / (Math.PI * 2.0) * 360)
+ DEG_CR + "Azimuth: "
+ numberFormat.format(azimuth / (Math.PI * 2.0) * 360) + DEG_CR;
numberFormat.setMaximumFractionDigits(2);
returnString = returnString + "Latitude: "
+ numberFormat.format(latitude / (Math.PI * 2.0) * 360)
+ DEG_CR + "Longitude: "
+ numberFormat.format(longitude / (Math.PI * 2.0) * 360)
+ DEG_CR;
numberFormat.setMaximumFractionDigits(0);
returnString = returnString + "Range: " + numberFormat.format(range)
+ " Km";
return returnString;
}
/**
* Calculates the footprint range circle using the given increment. TODO
* where is first point, give heading.
*
* @param incrementDegrees
* @return
*/
public final List<Position> getRangeCircle(double incrementDegrees) {
return calculateRangeCirclePoints(this, incrementDegrees);
}
/**
* Calculates the footprint range circle using an increment of 1.0 degrees.
*
* @param pos
* @return a list of {@link Position}
*/
public final List<Position> getRangeCircle() {
return getRangeCircle(1.0);
}
/**
* Calculates the footprint range circle using the given increment.
*
* @param pos
* @return a list of {@link Position}
*/
private static List<Position> calculateRangeCirclePoints(final SatPos pos,
double incrementDegrees) {
final double radiusKm = pos.getRangeCircleRadiusKm();
final double latitude = pos.latitude;
final double longitude = pos.longitude;
final double beta = radiusKm / R0;
List<Position> result = new ArrayList<Position>();
for (int azi = 0; azi < 360; azi += incrementDegrees) {
final double azimuth = (azi / 360.0) * 2.0 * Math.PI;
double rangelat = Math.asin(Math.sin(latitude) * Math.cos(beta)
+ Math.cos(azimuth) * Math.sin(beta) * Math.cos(latitude));
final double num = Math.cos(beta)
- (Math.sin(latitude) * Math.sin(rangelat));
final double den = Math.cos(latitude) * Math.cos(rangelat);
double rangelong;
if (azi == 0 && (beta > ((Math.PI / 2.0) - latitude))) {
rangelong = longitude + Math.PI;
} else if (azi == 180 && (beta > ((Math.PI / 2.0) - latitude))) {
rangelong = longitude + Math.PI;
} else if (Math.abs(num / den) > 1.0) {
rangelong = longitude;
} else {
if ((180 - azi) >= 0) {
rangelong = longitude - Math.acos(num / den);
} else {
rangelong = longitude + Math.acos(num / den);
}
}
while (rangelong < 0.0) {
rangelong += Math.PI * 2.0;
}
while (rangelong > Math.PI * 2.0) {
rangelong -= Math.PI * 2.0;
}
rangelat = (rangelat / (2.0 * Math.PI)) * 360.0;
rangelong = (rangelong / (2.0 * Math.PI)) * 360.0;
// if (rangelong < 180.0) {
// rangelong = -rangelong;
// }
// else if (rangelong > 180.0) {
// rangelong = 360.0 - rangelong;
// }
//
// if (rangelat < 90.0) {
// rangelat = -rangelat;
// }
// else if (rangelat > 90.0) {
// rangelat = 180.0 - rangelat;
// }
result.add(new Position(rangelat, rangelong));
}
return result;
}
public double getRangeCircleRadiusKm() {
return 0.5 * (12756.33 * Math.acos(EARTH_RADIUS_KM
/ (EARTH_RADIUS_KM + altitude)));
}
}
/**
predict4java: An SDP4 / SGP4 library for satellite orbit predictions
Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
This class is a Java port of one of the core elements of
the Predict program, Copyright John A. Magliacane,
KD2BD 1991-2003: http://www.qsl.net/kd2bd/predict.html
Dr. T.S. Kelso is the author of the SGP4/SDP4 orbital models,
originally written in Fortran and Pascal, and released into the
public domain through his website (http://www.celestrak.com/).
Neoklis Kyriazis, 5B4AZ, later re-wrote Dr. Kelso's code in C,
and released it under the GNU GPL in 2002.
PREDICT's core is based on 5B4AZ's code translation efforts.
Author: David A. B. Johnson, G4DPZ <dave@g4dpz.me.uk>
Comments, questions and bugreports should be submitted via
http://sourceforge.net/projects/websat/
More details can be found at the project home page:
http://websat.sourceforge.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, visit http://www.fsf.org/
*/
package predict4java;
import java.util.Date;
public interface Satellite {
double DEG2RAD = 1.745329251994330E-2;
double TWO_PI = Math.PI * 2.0;
double EPSILON = 1.0E-12;
double TWO_THIRDS = 2.0 / 3.0;
double EARTH_RADIUS_KM = 6.378137E3;
double XKE = 7.43669161E-2;
double CK2 = 5.413079E-4;
/** J2 Harmonic (WGS '72). */
double J2_HARMONIC = 1.0826158E-3;
/** J3 Harmonic (WGS '72). */
double J3_HARMONIC = -2.53881E-6;
/** J4 Harmonic (WGS '72). */
double J4_HARMONIC = -1.65597E-6;
/**
* This function returns true if the satellite can ever rise above the
* horizon of the ground station.
*
* @param qth
* the ground station position
* @return boolean whether or not the satellite will be seen
*/
boolean willBeSeen(GroundStationPosition qth);
/**
* Calculates the position and velocity vectors of the satellite. When
* observations for many ground stations have to be made for one satellite,
* this method can be used together with the
* calculateSatPosForGroundStation(..) method. This gives a performance
* improvement relative to using the all-in-one method getPosition(..).
*
* @param date
* The date for the calculation the position and velocity vectors
* of the satellite.
*/
void calculateSatelliteVectors(Date time);
/**
* Calculates the ground track (sub satellite point) of the satellite, for
* the already determined position of the satellite.
*
* @return satPos The SatPos object in which the ground track of the
* satellite is stored.
*/
SatPos calculateSatelliteGroundTrack();
/**
* Calculates the position of the satellite from the perspective of a ground
* station. The position and velocity of the satellite must have been
* determined before (by calculateSatelliteVectors(..)). The ground track
* (sub satellite point) is not calculated, this should be done by
* calculateSatelliteGroundTrack(..).
*
* @param gsPos
* The position of the ground station to perform the calculations
* for.
* @return satPos The SatPos object where the position of the satellite is
* stored, as seen from a ground station.
*/
SatPos calculateSatPosForGroundStation(GroundStationPosition gsPos);
/**
* Returns the currently assigned TLE for the satellite.
*
* @return
*/
TLE getTLE();
/**
* Get the position of the satellite.
*
* @param gsPos
* the ground station position
* @param satPos
* the position of the satellite
* @param date
* the date
*/
SatPos getPosition(GroundStationPosition qth, Date time);
}
/**
predict4java: An SDP4 / SGP4 library for satellite orbit predictions
Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
This class is a Java port of one of the core elements of
the Predict program, Copyright John A. Magliacane,
KD2BD 1991-2003: http://www.qsl.net/kd2bd/predict.html
Dr. T.S. Kelso is the author of the SGP4/SDP4 orbital models,
originally written in Fortran and Pascal, and released into the
public domain through his website (http://www.celestrak.com/).
Neoklis Kyriazis, 5B4AZ, later re-wrote Dr. Kelso's code in C,
and released it under the GNU GPL in 2002.
PREDICT's core is based on 5B4AZ's code translation efforts.
Author: David A. B. Johnson, G4DPZ <dave@g4dpz.me.uk>
Comments, questions and bugreports should be submitted via
http://sourceforge.net/projects/websat/
More details can be found at the project home page:
http://websat.sourceforge.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, visit http://www.fsf.org/
*/
package predict4java;
/**
* The factory which creates a LEO or Deep Space Satellite.
*
* @author G4DPZ
*
*/
public final class SatelliteFactory {
/**
* Default constructor is private so cannot be instantiated.
*/
private SatelliteFactory() {
}
/**
* Creates a <code>Satellite</code> from a <code>TLE</code>.
*
* @param tle
* The 'Three Line Elements'
* @return <code>Satellite</code>
* @throws IllegalArgumentException
* when the given TLE is null or the data is incorrect
*/
public static synchronized Satellite createSatellite(final TLE tle)
throws IllegalArgumentException {
if (null == tle) {
throw new IllegalArgumentException("TLE was null");
}
Satellite satellite = null;
if (tle.isDeepspace()) {
satellite = new DeepSpaceSatellite(tle);
} else {
satellite = new LEOSatellite(tle);
}
return satellite;
}
}
/**
predict4java: An SDP4 / SGP4 library for satellite orbit predictions
Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
This class is a Java port of one of the core elements of
the Predict program, Copyright John A. Magliacane,
KD2BD 1991-2003: http://www.qsl.net/kd2bd/predict.html
Dr. T.S. Kelso is the author of the SGP4/SDP4 orbital models,
originally written in Fortran and Pascal, and released into the
public domain through his website (http://www.celestrak.com/).
Neoklis Kyriazis, 5B4AZ, later re-wrote Dr. Kelso's code in C,
and released it under the GNU GPL in 2002.
PREDICT's core is based on 5B4AZ's code translation efforts.
Author: David A. B. Johnson, G4DPZ <dave@g4dpz.me.uk>
Comments, questions and bugreports should be submitted via
http://sourceforge.net/projects/websat/
More details can be found at the project home page:
http://websat.sourceforge.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, visit http://www.fsf.org/
*/
package predict4java;
import org.apache.commons.lang.*;
import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
/**
* TLE representation to aid SGP4 calculations. Instances of this class are
* immutable and thus thread safe.
*/
public class TLE implements Serializable {
private static final long serialVersionUID = 716922882884628016L;
private static final int THREELINES = 3;
private static final double DEG2RAD = 1.745329251994330E-2;
private static final double TWO_PI = Math.PI * 2.0;
private static final double MINS_PERDAY = 1.44E3;
private static final double XKE = 7.43669161E-2;
private static final double TWO_THIRDS = 2.0 / 3.0;
private static final double CK2 = 5.413079E-4;
private final int catnum;
private final String name;
private final int setnum;
private final int year;
private final double refepoch;
private final double incl;
private final double raan;
private final double eccn;
private final double argper;
private final double meanan;
private final double meanmo;
private final double drag;
private final double nddot6;
private final double bstar;
private final int orbitnum;
private final double epoch;
private final double xndt2o;
private final double xincl;
private final double xnodeo;
private final double eo;
private final double omegao;
private final double xmo;
private final double xno;
private final boolean deepspace;
// Constructors
/**
* Copy constructor.
*
* @param tle
*/
public TLE(final TLE tle) {
this.catnum = tle.catnum;
this.name = tle.name;
this.setnum = tle.setnum;
this.year = tle.year;
this.refepoch = tle.refepoch;
this.incl = tle.incl;
this.raan = tle.raan;
this.eccn = tle.eccn;
this.argper = tle.argper;
this.meanan = tle.meanan;
this.meanmo = tle.meanmo;
this.drag = tle.drag;
this.nddot6 = tle.nddot6;
this.bstar = tle.bstar;
this.orbitnum = tle.orbitnum;
this.epoch = tle.epoch;
this.xndt2o = tle.xndt2o;
this.xincl = tle.xincl;
this.xnodeo = tle.xnodeo;
this.eo = tle.eo;
this.omegao = tle.omegao;
this.xmo = tle.xmo;
this.xno = tle.xno;
this.deepspace = tle.deepspace;
}
/**
* Constructor.
*
* @param tle the three line elements
* @throws IllegalArgumentException here was something wrong with the TLE
*/
public TLE(final String[] tle) throws IllegalArgumentException {
{
if (null == tle) {
throw new IllegalArgumentException("TLE was null");
}
if (tle.length != THREELINES) {
throw new IllegalArgumentException("TLE had " + tle.length
+ " elements");
}
int lineCount = 0;
for (final String line : tle) {
testArguments(lineCount, line);
lineCount++;
}
catnum = Integer
.parseInt(StringUtils.strip(tle[1].substring(2, 7)));
name = tle[0].trim();
setnum = Integer.parseInt(StringUtils.strip(tle[1]
.substring(64, 68)));
year = Integer
.parseInt(StringUtils.strip(tle[1].substring(18, 20)));
refepoch = Double.parseDouble(tle[1].substring(20, 32));
incl = Double.parseDouble(tle[2].substring(8, 16));
raan = Double.parseDouble(tle[2].substring(17, 25));
eccn = 1.0e-07 * Double.parseDouble(tle[2].substring(26, 33));
argper = Double.parseDouble(tle[2].substring(34, 42));
meanan = Double.parseDouble(tle[2].substring(43, 51));
meanmo = Double.parseDouble(tle[2].substring(52, 63));
drag = Double.parseDouble(tle[1].substring(33, 43));
double tempnum = 1.0e-5 * Double.parseDouble(tle[1].substring(44,
50));
nddot6 = tempnum
/ Math.pow(10.0,
Double.parseDouble(tle[1].substring(51, 52)));
tempnum = 1.0e-5 * Double.parseDouble(tle[1].substring(53, 59));
bstar = tempnum
/ Math.pow(10.0,
Double.parseDouble(tle[1].substring(60, 61)));
orbitnum = Integer.parseInt(StringUtils.strip(tle[2].substring(63,
68)));
/* reassign the values to thse which get used in calculations */
epoch = (1000.0 * getYear()) + getRefepoch();
double temp = incl;
temp *= DEG2RAD;
xincl = temp;
temp = raan;
temp *= DEG2RAD;
xnodeo = temp;
eo = eccn;
temp = argper;
temp *= DEG2RAD;
omegao = temp;
temp = meanan;
temp *= DEG2RAD;
xmo = temp;
}
/* Preprocess tle set */
{
double temp;
temp = TWO_PI / MINS_PERDAY / MINS_PERDAY;
xno = meanmo * temp * MINS_PERDAY;
xndt2o = drag * temp;
double dd1 = XKE / xno;
final double a1 = Math.pow(dd1, TWO_THIRDS);
final double r1 = Math.cos(xincl);
dd1 = 1.0 - eo * eo;
temp = CK2 * 1.5f * (r1 * r1 * 3.0 - 1.0) / Math.pow(dd1, 1.5);
final double del1 = temp / (a1 * a1);
final double ao = a1
* (1.0 - del1
* (TWO_THIRDS * .5 + del1
* (del1 * 1.654320987654321 + 1.0)));
final double delo = temp / (ao * ao);
final double xnodp = xno / (delo + 1.0);
/* Select a deep-space/near-earth ephemeris */
deepspace = TWO_PI / xnodp / MINS_PERDAY >= 0.15625;
}
}
/**
* @param lineCount the current line
* @param line the line under test
* @throws IllegalArgumentException there was a problem with the data
*/
private void testArguments(final int lineCount, final String line)
throws IllegalArgumentException {
if (null == line) {
throw new IllegalArgumentException(createIllegalArgumentMessage(
lineCount, "was null"));
}
if (0 == line.length()) {
throw new IllegalArgumentException(createIllegalArgumentMessage(
lineCount, "was zero length"));
}
}
/**
* @return the catalog number
*/
public int getCatnum() {
return this.catnum;
}
/**
* @return the name
*/
public String getName() {
return this.name;
}
/**
* @return the element set number
*/
public int getSetnum() {
return this.setnum;
}
/**
* @return the year part of the date of the elements
*/
public int getYear() {
return this.year;
}
/**
* @return the reference epoch of the elements
*/
public double getRefepoch() {
return this.refepoch;
}
/**
* @return the inclination of the satellite orbit
*/
public double getIncl() {
return this.incl;
}
/**
* @return the Right Ascention of the Acending Node of the orbit
*/
public double getRaan() {
return this.raan;
}
/**
* @return the Eccentricity of the orbit
*/
public double getEccn() {
return this.eccn;
}
/**
* @return the Argument of Perigee of the orbit
*/
public double getArgper() {
return this.argper;
}
/**
* @return the Mean Anomoly of the orbit
*/
public double getMeanan() {
return this.meanan;
}
/**
* @return the Mean Motion of the satellite
*/
public double getMeanmo() {
return this.meanmo;
}
/**
* @return the Drag factor
*/
public double getDrag() {
return this.drag;
}
/**
* @return Nddot6
*/
public double getNddot6() {
return this.nddot6;
}
/**
* @return Bstar
*/
public double getBstar() {
return this.bstar;
}
/**
* @return Orbitnum
*/
public int getOrbitnum() {
return this.orbitnum;
}
/**
* @return Deepspace
*/
public boolean isDeepspace() {
return deepspace;
}
/**
* @return Eo
*/
public double getEo() {
return eo;
}
/**
* @return Epoch
*/
public double getEpoch() {
return epoch;
}
/**
* @return Omegao
*/
public double getOmegao() {
return omegao;
}
/**
* @return Xincl
*/
public double getXincl() {
return xincl;
}
/**
* @return Xmo
*/
public double getXmo() {
return xmo;
}
/**
* @return Xndt2o
*/
public synchronized double getXndt2o() {
return xndt2o;
}
/**
* @return Xno
*/
public synchronized double getXno() {
return xno;
}
/**
* @return Xnodeo
*/
public double getXnodeo() {
return xnodeo;
}
/**
* @param lineCount the line count
* @param problem the problem
* @return the description
*/
private String createIllegalArgumentMessage(final int lineCount,
final String problem) {
return "TLE line[" + lineCount + "] " + problem;
}
public static List<TLE> importSat(final InputStream fileIS)
throws IOException {
final List<TLE> importedSats = new ArrayList<TLE>();
final BufferedReader buf = new BufferedReader(new InputStreamReader(
fileIS, Charset.forName("UTF-8")));
String readString;
int j = 0;
final String[] lines = new String[3];
while ((readString = buf.readLine()) != null) {
switch (j) {
case 0:
case 1:
lines[j] = readString;
j++;
break;
case 2:
lines[j] = readString;
j = 0;
importedSats.add(new TLE(lines));
break;
default:
break;
}
}
return importedSats;
}
@Override
public String toString() {
return name;
}
}
package satellite;
import gov.nasa.worldwind.View;
import gov.nasa.worldwind.WorldWind;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.geom.LatLon;
import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.layers.RenderableLayer;
import gov.nasa.worldwind.render.*;
import gov.nasa.worldwind.util.WWUtil;
import gov.nasa.worldwindx.examples.ApplicationTemplate;
import java.awt.Color;
import java.util.ArrayList;
/**
* Example of {@link Path} usage. A Path is a line or curve between positions. The path may follow terrain, and may be
* turned into a curtain by extruding the path to the ground.
*
* @author tag
* @version $Id: Paths.java 1171 2013-02-11 21:45:02Z dcollins $
*/
public class Paths extends ApplicationTemplate
{
static RenderableLayer layer = new RenderableLayer();
static ArrayList<satPosition> aSatellite = new ArrayList<satPosition>();
public static void setOrbit(ArrayList<satPosition> sat){
aSatellite = sat;
// Create and set an attribute bundle.
ShapeAttributes attrs = new BasicShapeAttributes();
attrs.setOutlineMaterial(new Material(WWUtil.makeRandomColor(null)));
attrs.setOutlineWidth(2d);
ArrayList<Position> pathPositions = new ArrayList<Position>();
for(int i=0;i<aSatellite.size(); i++){
pathPositions.add(Position.fromDegrees(aSatellite.get(i).getLat(), aSatellite.get(i).getLon(), aSatellite.get(i).getAlt()*1000));
}
Path path = new Path(pathPositions);
path.setAttributes(attrs);
path.setVisible(true);
path.setAltitudeMode(WorldWind.RELATIVE_TO_GROUND);
path.setPathType(AVKey.GREAT_CIRCLE);
layer.addRenderable(path);
attrs = new BasicShapeAttributes();
attrs.setOutlineMaterial(new Material(WWUtil.makeRandomColor(null)));
attrs.setInteriorMaterial(new Material(WWUtil.makeRandomColor(null)));
attrs.setOutlineWidth(2);
path.setAttributes(attrs);
//layer.addRenderable(path);
//this.getLayerPanel().update(this.getWwd());
}
public static void setPosition(ArrayList<satPosition> aSatellite, String name){
PointPlacemark pp = new PointPlacemark(Position.fromDegrees(aSatellite.get(0).getLat(),aSatellite.get(0).getLon(),aSatellite.get(0).getAlt()*1000));;
pp.setLabelText(name);
pp.setValue(AVKey.DISPLAY_NAME, "Label, Semi-transparent, Audio icon");
pp.setLineEnabled(false);
pp.setAltitudeMode(WorldWind.RELATIVE_TO_GROUND);
PointPlacemarkAttributes attrsP = new PointPlacemarkAttributes();
attrsP.setImageAddress("satellite.png");
//attrsP.setImageColor(new Color(1f, 1f, 1f, 0.6f));
attrsP.setScale(0.1);
attrsP.setImageOffset(new Offset(175d,175d,AVKey.PIXELS, AVKey.PIXELS));
pp.setAttributes(attrsP);
layer.addRenderable(pp);
}
public static class AppFrame extends ApplicationTemplate.AppFrame
{
public AppFrame()
{
super(true, true, false);
// Add the layer to the model.
insertBeforeCompass(getWwd(), layer);
// Update layer panel
this.getLayerPanel().update(this.getWwd());
// //goto coord
// LatLon latlon = LatLon.fromDegrees(aSatellite.get(1).getLat(),aSatellite.get(1).getLon());
// System.out.println(latlon + " " + aSatellite.get(1).getAlt());
// View view = this.getWwd().getView();
// //double distance = view.getCenterPoint().distanceTo3(view.getEyePoint());
// view.goTo(new Position(latlon, 0.0), 0.0);
}
}
// public static void main(String[] args)
// {
// ApplicationTemplate.start("World Wind Paths", AppFrame.class);
// }
}
package satellite;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import predict4java.*;
public class SatelliteDB {
ArrayList<Satellite> satelliteDB = new ArrayList<Satellite>();
boolean databaseSet = false;
GroundStationPosition groundstation;
final static GroundStationPosition ALBUQUERQUE = new GroundStationPosition(35.0873191, -106.6376107, 5500, "Albuquerque");
final static GroundStationPosition STORMLAKE = new GroundStationPosition(42.6436, 95.2019, 1440,"Storm Lake");
public boolean downloadTLE(String in_url, String file){
URL url;
try {
url = new URL(in_url);
} catch (MalformedURLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
return false;
}
PrintWriter writer = null;
try {
writer = new PrintWriter(file, "UTF-8");
URLConnection yc = url.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(yc.getInputStream()));
String inputLine;
System.out.println("Data from: " + url);
while ((inputLine = in.readLine()) != null){
//System.out.println(inputLine);
writer.println(inputLine);
}
in.close();
writer.close();
return true;
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
System.err.println("Unsupported Encoding...");
e.printStackTrace();
return false;
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
public void TLEReader(String file){
//TODO
FileReader in = null;
try {
in = new FileReader(file);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
BufferedReader br = new BufferedReader(in);
String line;
try {
while((line = br.readLine()) != null) {
// if(line.startsWith("1") || line.startsWith("2")){
// System.out.println("Uhhhh this shouldn't happen");
// }else{
// System.out.println(line);
// }
String[] TLEs = {line,br.readLine(),br.readLine()};
TLE data = new TLE(TLEs);
satelliteDB.add(SatelliteFactory.createSatellite(data));
// System.out.println(line);
// System.out.println(br.readLine());
// System.out.println(br.readLine());
}
} catch (IllegalArgumentException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void setGroundstation(GroundStationPosition gPos){
groundstation = gPos;
}
public void getSatellites_GPS(){
downloadTLE("https://celestrak.com/NORAD/elements/gps-ops.txt","gps.txt");
TLEReader("gps.txt");
databaseSet = true;
}
public void getSatellites_Stations(){
downloadTLE("https://celestrak.com/NORAD/elements/stations.txt","stations.txt");
TLEReader("stations.txt");
databaseSet = true;
}
public void getSatellites_NOAA(){
downloadTLE("https://celestrak.com/NORAD/elements/noaa.txt","noaa.txt");
TLEReader("noaa.txt");
databaseSet = true;
}
public int getSatIndex(String sat){
for(int i=0;i<satelliteDB.size();i++){
if(sat.equals(satelliteDB.get(i).getTLE().getName())){
return i;
}
}
return -1;
}
public int getSize(){
return satelliteDB.size();
}
public Satellite getSat(int selectedSatellite) {
return satelliteDB.get(selectedSatellite);
}
public boolean satExist(String string){
int selectedSatellite = this.getSatIndex(string);
if(selectedSatellite>=0){
//System.out.println(this.getSat(selectedSatellite).getTLE().getName() + " Exists!");
return true;
}else{
//System.out.println("Satellite does not exisit");
return false;
}
}
public static void main(String[] args) throws InterruptedException {
SatelliteDB gpsSats = new SatelliteDB();
gpsSats.getSatellites_GPS();
gpsSats.setGroundstation(ALBUQUERQUE);
SatelliteDB stationSats = new SatelliteDB();
stationSats.getSatellites_Stations();
stationSats.setGroundstation(STORMLAKE);
SatelliteDB noaaSats = new SatelliteDB();
noaaSats.getSatellites_NOAA();
noaaSats.setGroundstation(ALBUQUERQUE);
//Date now = new Date();
System.out.println(gpsSats.satExist("ISS (ZARYA)"));
System.out.println(stationSats.satExist("ISS (ZARYA)"));
// int selectedSat = stationSats.getSatIndex("ISS (ZARYA)");
// Satellite trackedSat = stationSats.getSat(selectedSat);
ArrayList<satPosition> orbit;
for(int i = 0; i<noaaSats.getSize(); i++){
orbit = satOrbit.getDoubleOrbit(noaaSats.getSat(i));
//Paths.setOrbit(orbit);
Paths.setPosition(orbit, noaaSats.getSat(i).getTLE().getName());
}
for(int i = 0; i<gpsSats.getSize(); i++){
orbit = satOrbit.getDoubleOrbit(gpsSats.getSat(i));
//Paths.setOrbit(orbit);
Paths.setPosition(orbit, gpsSats.getSat(i).getTLE().getName());
}
//WorldWind App
Paths.start("World Wind Paths - Test", Paths.AppFrame.class);
}
}
package satellite;
import predict4java.*;
import java.util.ArrayList;
import java.util.Date;
import satellite.satPosition;
public class satOrbit {
public static ArrayList<satPosition> getDayOrbit(Satellite trackedSat){
ArrayList<satPosition> dayOrbit = new ArrayList<satPosition>();
Date now = new Date();
long timeNow = now.getTime();
for(int i = 0; i<8640;i++){ //10s of seconds in a day
Date increment = new Date(timeNow + i*10000);
trackedSat.calculateSatelliteVectors(increment);
dayOrbit.add(new satPosition(
trackedSat.calculateSatelliteGroundTrack().getLatitude(),
trackedSat.calculateSatelliteGroundTrack().getLongitude(),
trackedSat.calculateSatelliteGroundTrack().getAltitude(),
trackedSat.calculateSatelliteGroundTrack().getTime()));
}
System.out.println("Calculated 24hr Orbit for: " + trackedSat.getTLE().getName());
return dayOrbit;
}
public static ArrayList<satPosition> getSingleOrbit(Satellite trackedSat){
//Array to store orbit
ArrayList<satPosition> singleOrbit = new ArrayList<satPosition>();
Date now = new Date();
long timeNow = now.getTime();
trackedSat.calculateSatelliteVectors(now);
//Iterate through one orbit
double meanMotion = trackedSat.getTLE().getMeanmo();
double period = 8460/meanMotion;
for(int i = 0;i<period;i++){ //Seconds in a day
Date increment = new Date(timeNow + i * 10000);
trackedSat.calculateSatelliteVectors(increment);
singleOrbit.add(new satPosition(
trackedSat.calculateSatelliteGroundTrack().getLatitude(),
trackedSat.calculateSatelliteGroundTrack().getLongitude(),
trackedSat.calculateSatelliteGroundTrack().getAltitude(),
trackedSat.calculateSatelliteGroundTrack().getTime()));
}
System.out.println("Calculated Single Orbit for: " + trackedSat.getTLE().getName());
return singleOrbit;
}
public static ArrayList<satPosition> getDoubleOrbit(Satellite trackedSat){
//Array to store orbit
ArrayList<satPosition> doubleOrbit = new ArrayList<satPosition>();
Date now = new Date();
long timeNow = now.getTime();
trackedSat.calculateSatelliteVectors(now);
//Iterate through two orbits
double meanMotion = trackedSat.getTLE().getMeanmo();
double period = 8460/meanMotion;
for(int i = 0;i<period*2;i++){ //Seconds in a day
Date increment = new Date(timeNow + i * 10000);
trackedSat.calculateSatelliteVectors(increment);
doubleOrbit.add(new satPosition(
trackedSat.calculateSatelliteGroundTrack().getLatitude(),
trackedSat.calculateSatelliteGroundTrack().getLongitude(),
trackedSat.calculateSatelliteGroundTrack().getAltitude(),
trackedSat.calculateSatelliteGroundTrack().getTime()));
}
System.out.println("Calculated Double Orbit for: " + trackedSat.getTLE().getName());
return doubleOrbit;
}
public static ArrayList<satPosition> getTripleOrbit(Satellite trackedSat){
//Array to store orbit
ArrayList<satPosition> tripleOrbit = new ArrayList<satPosition>();
Date now = new Date();
long timeNow = now.getTime();
trackedSat.calculateSatelliteVectors(now);
//Iterate through two orbits
double meanMotion = trackedSat.getTLE().getMeanmo();
double period = 8460/meanMotion;
for(int i = 0;i<period*3;i++){ //Seconds in a day
Date increment = new Date(timeNow + i * 10000);
trackedSat.calculateSatelliteVectors(increment);
tripleOrbit.add(new satPosition(
trackedSat.calculateSatelliteGroundTrack().getLatitude(),
trackedSat.calculateSatelliteGroundTrack().getLongitude(),
trackedSat.calculateSatelliteGroundTrack().getAltitude(),
trackedSat.calculateSatelliteGroundTrack().getTime()));
}
System.out.println("Calculated Triple Orbit for: " + trackedSat.getTLE().getName());
return tripleOrbit;
}
}
package satellite;
import java.util.Date;
public class satPosition{
private final double lat;
private final double lon;
private final double alt;
private final Date time;
public satPosition(double lat, double lon, double alt, Date time) {
super();
this.lat = lat;
this.lon = lon;
this.alt = alt;
this.time = time;
}
public double getLat() {
return lat / (Math.PI * 2.0) * 360;
}
public double getLon() {
return lon / (Math.PI * 2.0) * 360;
}
public double getAlt() {
return alt;
}
public Date getTime() {
return time;
}
@Override
public String toString() {
double degLat = lat / (Math.PI * 2.0) * 360;
double degLon = lon / (Math.PI * 2.0) * 360;
return "Position [lat=" + degLat + ", lon=" + degLon + ", alt = " + alt + ", time= " + time +"]";
}
}
ISS (ZARYA)
1 25544U 98067A 15269.94241877 .00005768 00000-0 94169-4 0 9994
2 25544 51.6459 296.0663 0005307 325.3476 107.7064 15.54165765963872
TIANGONG 1
1 37820U 11053A 15269.72495600 .00021283 00000-0 21272-3 0 9999
2 37820 42.7663 27.4666 0014379 2.0270 142.2882 15.65042323229210
SPINSAT
1 40314U 98067FL 15269.49907340 .00016259 00000-0 17471-3 0 9997
2 40314 51.6399 290.2307 0005737 112.0903 248.0702 15.63909165 98508
FLOCK 1B-27
1 40422U 98067FN 15269.45995081 .00280907 41787-4 72750-3 0 9997
2 40422 51.6312 272.2073 0010168 85.7646 36.3934 15.94508247 42107
FLOCK 1B-21
1 40427U 98067FQ 15269.83261839 .00273002 39922-4 72334-3 0 9995
2 40427 51.6258 270.3149 0005660 80.6703 341.2716 15.94155665 42190
FLOCK 1B-22
1 40428U 98067FR 15269.86227266 .00799185 32164-3 12825-2 0 9998
2 40428 51.6261 270.4810 0007641 48.4062 23.2138 16.02948163 42190
FLOCK 1D-1
1 40451U 98067FU 15269.84494433 .00367340 67498-4 74326-3 0 9992
2 40451 51.6275 269.6030 0008193 77.1526 349.2217 15.98973182 42183
FLOCK 1D-2
1 40452U 98067FV 15269.53880203 .00066263 00000-0 43970-3 0 9996
2 40452 51.6402 283.4036 0006541 108.0244 29.6819 15.74825078 41979
FLOCK 1B-6
1 40454U 98067FX 15269.86126287 .00285757 42209-4 80637-3 0 9992
2 40454 51.6311 272.7965 0007488 80.4521 344.0757 15.92934090 42133
GEARRS-1
1 40456U 98067FZ 15269.41814346 .00143825 00000-0 57078-3 0 9996
2 40456 51.6380 277.6171 0007970 73.3159 286.8720 15.85720511 42044
FLOCK 1B-12
1 40460U 98067GD 15269.72785140 .02266994 54065-2 23068-2 0 9992
2 40460 51.6357 274.3028 0005361 92.3705 267.7302 16.11489783 42124
PROGRESS-M 28M
1 40713U 15031A 15268.21313216 .00005785 00000-0 94507-4 0 9990
2 40713 51.6463 304.6860 0005196 319.3549 152.0018 15.54144244 13087
FLOCK 1E-2
1 40722U 98067GE 15269.54812459 .00026049 00000-0 31579-3 0 9995
2 40722 51.6436 296.3091 0003075 133.3834 0.1579 15.60448472 11647
FLOCK 1E-1
1 40723U 98067GF 15269.56415023 .00025793 00000-0 32224-3 0 9997
2 40723 51.6436 296.4117 0003415 167.1728 327.6820 15.59660390 11596
FLOCK 1E-4
1 40724U 98067GG 15269.51614576 .00024812 00000-0 31311-3 0 9994
2 40724 51.6457 296.8080 0004406 83.8866 67.3058 15.59415236 11588
FLOCK 1E-3
1 40725U 98067GH 15269.53091366 .00029165 00000-0 34694-3 0 9996
2 40725 51.6437 296.2096 0006469 69.5768 53.7469 15.60861764 11567
FLOCK 1E-7
1 40726U 98067GJ 15269.57329762 .00020848 00000-0 26246-3 0 9998
2 40726 51.6424 296.4740 0003151 171.7202 324.8711 15.59597753 11447
FLOCK 1E-8
1 40727U 98067GK 15269.37586769 .00020414 00000-0 25732-3 0 9997
2 40727 51.6435 297.4805 0002188 154.3872 303.7304 15.59580942 11404
FLOCK 1E-5
1 40728U 98067GL 15269.37146089 .00027660 00000-0 34463-3 0 9996
2 40728 51.6430 297.4542 0004305 136.5716 320.6611 15.59687988 11418
FLOCK 1E-6
1 40729U 98067GM 15269.56708968 .00020840 00000-0 25927-3 0 9996
2 40729 51.6436 296.4258 0004058 124.8618 12.6644 15.59908801 11452
FLOCK 1E-9
1 40736U 98067GN 15269.57985853 .00019657 00000-0 25140-3 0 9996
2 40736 51.6460 296.5790 0000871 168.8594 299.8356 15.59224633 11429
FLOCK 1E-10
1 40737U 98067GP 15269.58325230 .00025550 00000-0 32224-3 0 9995
2 40737 51.6453 296.5297 0001459 127.2544 11.2403 15.59419409 11438
FLOCK 1E-11
1 40738U 98067GQ 15269.53951983 .00023305 00000-0 27710-3 0 9991
2 40738 51.6414 296.1927 0004473 105.2841 56.2152 15.61020560 11256
FLOCK 1E-12
1 40739U 98067GR 15269.51718744 .00020057 00000-0 25469-3 0 9996
2 40739 51.6440 296.8146 0004527 129.2951 21.2508 15.59393391 11253
FLOCK 1E-13
1 40740U 98067GS 15269.51196156 .00021914 00000-0 27460-3 0 9991
2 40740 51.6448 296.7836 0001849 173.6209 337.9978 15.59689272 11233
FLOCK 1E-14
1 40741U 98067GT 15269.51031750 .00021635 00000-0 27023-3 0 9995
2 40741 51.6442 296.7732 0001753 154.0753 357.2694 15.59782281 11227
ARKYD-3R
1 40742U 98067GU 15269.55414866 .00073414 00000-0 76701-3 0 9992
2 40742 51.6450 295.6017 0003020 21.7732 111.5349 15.63803454 11248
CENTENNIAL 1
1 40743U 98067GV 15269.59283797 .00050690 00000-0 57018-3 0 9995
2 40743 51.6449 295.8440 0001510 20.1492 122.4764 15.62069574 11245
SOYUZ-TMA 17M
1 40744U 15035A 15268.21313216 .00005785 00000-0 94507-4 0 9998
2 40744 51.6463 304.6860 0005196 319.3549 152.0018 15.54144244 10011
HTV-5 (KOUNOTORI 5)
1 40873U 15038A 15268.21313216 .00005785 00000-0 94507-4 0 9994
2 40873 51.6463 304.6860 0005196 319.3549 152.0018 15.54144244 5726
SOYUZ-TMA 18M
1 40885U 15043A 15268.21313216 .00005785 00000-0 94507-4 0 9993
2 40885 51.6463 304.6860 0005196 319.3549 152.0018 15.54144244 3592
SERPENS
1 40897U 98067GX 15269.53773286 .00037218 00000-0 53957-3 0 9995
2 40897 51.6464 298.0185 0008537 342.6507 17.4202 15.55441570 1294
S-CUBE
1 40898U 98067GY 15268.96073225 .00020141 00000-0 30034-3 0 9996
2 40898 51.6453 300.9125 0008528 323.8770 36.1693 15.55029871 1202
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment