├── .gitignore
├── .travis.yml
├── README.md
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── github
│ │ └── amsacode
│ │ └── predict4java
│ │ ├── AbstractSatellite.java
│ │ ├── DeepSpaceSatellite.java
│ │ ├── GroundStationPosition.java
│ │ ├── LEOSatellite.java
│ │ ├── PassPredictor.java
│ │ ├── Position.java
│ │ ├── SatNotFoundException.java
│ │ ├── SatPassTime.java
│ │ ├── SatPos.java
│ │ ├── Satellite.java
│ │ ├── SatelliteFactory.java
│ │ └── TLE.java
└── resources
│ └── META-INF
│ └── gpl-2.0.txt
└── test
├── java
└── com
│ └── github
│ └── amsacode
│ └── predict4java
│ ├── AbstractSatelliteTest.java
│ ├── AbstractSatelliteTestBase.java
│ ├── DeepSpaceSatelliteTest.java
│ ├── GroundStationPositionTest.java
│ ├── IlluminationTest.java
│ ├── LEOSatelliteTest.java
│ ├── PassPredictorTest.java
│ ├── SatNotFoundExceptionTest.java
│ ├── SatPassTimeTest.java
│ ├── SatPosTest.java
│ ├── SatelliteFactoryTest.java
│ ├── TLETest.java
│ ├── TestingUtil.java
│ └── Vector4Test.java
└── resources
├── LEO.txt
└── log4j.properties
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 | .settings
3 | .project
4 | .classpath
5 | .idea
6 | *.iml
7 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: java
3 | jdk:
4 | - openjdk8
5 | - openjdk10
6 | - openjdk11
7 |
8 | after_success:
9 | - src/deploy/deploy.sh
10 | - bash <(curl -s https://codecov.io/bash)
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | predict4java
2 | ============
3 |
4 | [](https://maven-badges.herokuapp.com/maven-central/com.github.davidmoten/predict4java)
5 | [](https://codecov.io/gh/davidmoten/predict4java)
6 |
7 | *predict4java* provides real-time satellite tracking and orbital prediction information.
8 |
9 | Status: *deployed to Maven Central*
10 |
11 | mavenized fork of http://code.google.com/p/predict4java/
12 |
13 | Quoting from above site:
14 |
15 | *This is a Java port of the core elements of the Open Source (GPL v2) Predict program, Copyright John A. Magliacane, KD2BD 1991-2003:*
16 |
17 | http://www.qsl.net/kd2bd/predict.html
18 |
19 | *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:*
20 |
21 | http://www.celestrak.com/
22 |
23 | *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.*
24 |
25 | *The Author of the pre-mavenized version is: David A. B. Johnson, G4DPZ*
26 |
27 | Continuous integration with Jenkins for this project is [here](https://xuml-tools.ci.cloudbees.com/).
28 |
29 | Project reports including Javadocs are [here](https://xuml-tools.ci.cloudbees.com/job/predict4java%20site/site/project-reports.html).
30 |
31 | Notes
32 | ----------
33 |
34 | During the mavenizing process the following minor changes to the original project were made:
35 | * TestUtil dependency is not available in a maven repository so commented out the calls to that library in SatPosTest and SatPassTimeTest.
36 | * checkstyle configuration is included in the source but is not referenced yet by the maven checkstyle plugin
37 |
38 | More enhancements to the original codebase have been performed since the original mavenization and are indicated in the commit history.
39 |
40 | Getting started
41 | ------------------
42 | Add this dependency to your pom.xml:
43 |
44 | ```xml
45 |
46 | com.github.davidmoten
47 | predict4java
48 | VERSION_HERE
49 |
50 | ```
51 |
52 | Build instructions
53 | -------------------
54 |
55 | cd
56 | git clone http://github.com/davidmoten/predict4java.git
57 | cd predict4java
58 | mvn clean install
59 |
60 | View site reports
61 | ------------------
62 | The generated maven site includes these reports:
63 | * Cobertura coverage
64 | * Checkstyle
65 | * PMD
66 | * CPD
67 | * FindBugs
68 | * JDepend
69 | * JavaNCSS
70 | * Tag List
71 | * Javadocs
72 |
73 | To generate:
74 |
75 | mvn clean site
76 |
77 | Then open *target/site/index.html* in a browser
78 |
79 |
80 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 |
4 | com.github.davidmoten
5 | sonatype-parent
6 | 0.1
7 |
8 | com.github.davidmoten
9 | predict4java
10 | 1.3.2-SNAPSHOT
11 | ${project.artifactId}
12 | predict4java provides real-time satellite tracking and orbital prediction information
13 |
14 | 3.0.1
15 |
16 |
17 | UTF-8
18 | 1.6
19 | 2.10
20 | 3.1.12
21 | 3.1.0
22 | 2.7.1
23 | 2.0-beta-2
24 | 2.0
25 | 2.3
26 | 2.4
27 | 3.7.1
28 | scm:git:https://github.com/davidmoten/predict4java.git
29 |
30 |
31 |
32 |
33 | GNU General Public License (GPL) version 2.0
34 | http://www.gnu.org/licenses/gpl-2.0.html
35 |
36 |
37 |
38 |
39 | ${scm.url}
40 | ${scm.url}
41 | ${scm.url}
42 | HEAD
43 |
44 |
45 |
46 |
47 | commons-lang
48 | commons-lang
49 | 2.6
50 |
51 |
52 | commons-logging
53 | commons-logging
54 | 1.2
55 |
56 |
57 |
58 | com.github.davidmoten
59 | guava-mini
60 | 0.1.2
61 |
62 |
63 | joda-time
64 | joda-time
65 | 2.10.1
66 | test
67 |
68 |
69 | org.assertj
70 | assertj-core
71 | 1.7.1
72 | test
73 |
74 |
75 |
76 | junit
77 | junit
78 | 4.13.1
79 | test
80 |
81 |
82 |
83 |
84 |
85 | org.apache.maven.plugins
86 | maven-compiler-plugin
87 | 3.8.1
88 |
89 | true
90 | true
91 | ${compiler.source.version}
92 | ${compiler.source.version}
93 |
94 |
95 |
96 | org.jacoco
97 | jacoco-maven-plugin
98 | 0.8.3
99 |
100 |
101 |
102 | prepare-agent
103 |
104 |
105 |
106 | report
107 | test
108 |
109 | report
110 |
111 |
112 |
113 |
114 |
115 |
116 | org.apache.maven.plugins
117 | maven-surefire-plugin
118 | 2.12
119 |
120 | -Duser.language=en
121 |
122 |
123 |
124 |
125 | maven-site-plugin
126 | ${m3.site.version}
127 |
128 |
129 | attach-descriptor
130 |
131 | attach-descriptor
132 |
133 |
134 |
135 |
136 |
137 | org.apache.maven.plugins
138 | maven-javadoc-plugin
139 | ${javadoc.version}
140 |
141 |
142 | -Xdoclint:none
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
153 |
154 | org.apache.maven.plugins
155 | maven-jxr-plugin
156 | ${jxr.version}
157 |
158 |
159 | org.apache.maven.plugins
160 | maven-checkstyle-plugin
161 | ${checkstyle.version}
162 |
163 |
164 | true
165 |
166 |
167 |
168 | org.apache.maven.plugins
169 | maven-pmd-plugin
170 | ${pmd.version}
171 |
172 | ${compiler.source.version}
173 |
174 |
175 |
176 | com.github.spotbugs
177 | spotbugs-maven-plugin
178 | ${spotbugs.version}
179 |
180 |
181 | org.codehaus.mojo
182 | jdepend-maven-plugin
183 | ${jdepend.version}
184 |
185 |
186 | org.codehaus.mojo
187 | taglist-maven-plugin
188 | ${taglist.version}
189 |
190 |
191 | org.apache.maven.plugins
192 | maven-javadoc-plugin
193 | ${javadoc.version}
194 |
195 |
196 | -Xdoclint:none
197 |
198 |
199 |
200 |
201 | org.apache.maven.plugins
202 | maven-project-info-reports-plugin
203 | 3.0.0
204 |
205 |
206 |
207 |
208 |
209 |
--------------------------------------------------------------------------------
/src/main/java/com/github/amsacode/predict4java/AbstractSatellite.java:
--------------------------------------------------------------------------------
1 | /**
2 | predict4java: An SDP4 / SGP4 library for satellite orbit predictions
3 |
4 | Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
5 |
6 | This class is a Java port of one of the core elements of
7 | the Predict program, Copyright John A. Magliacane,
8 | KD2BD 1991-2003: http://www.qsl.net/kd2bd/predict.html
9 |
10 | Dr. T.S. Kelso is the author of the SGP4/SDP4 orbital models,
11 | originally written in Fortran and Pascal, and released into the
12 | public domain through his website (http://www.celestrak.com/).
13 | Neoklis Kyriazis, 5B4AZ, later re-wrote Dr. Kelso's code in C,
14 | and released it under the GNU GPL in 2002.
15 | PREDICT's core is based on 5B4AZ's code translation efforts.
16 |
17 | Author: David A. B. Johnson, G4DPZ
18 |
19 | Comments, questions and bugreports should be submitted via
20 | http://sourceforge.net/projects/websat/
21 | More details can be found at the project home page:
22 |
23 | http://websat.sourceforge.net
24 |
25 | This program is free software; you can redistribute it and/or modify
26 | it under the terms of the GNU General Public License as published by
27 | the Free Software Foundation; either version 2 of the License, or
28 | (at your option) any later version.
29 |
30 | This program is distributed in the hope that it will be useful,
31 | but WITHOUT ANY WARRANTY; without even the implied warranty of
32 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 | GNU General Public License for more details.
34 |
35 | You should have received a copy of the GNU General Public License
36 | along with this program; if not, visit http://www.fsf.org/
37 | */
38 | package com.github.amsacode.predict4java;
39 |
40 | import java.util.Calendar;
41 | import java.util.Date;
42 | import java.util.TimeZone;
43 | import java.util.concurrent.atomic.AtomicReference;
44 |
45 | /**
46 | * Not thread safe!
47 | */
48 | public abstract class AbstractSatellite implements Satellite {
49 |
50 | private static final double MINS_PER_DAY = 1.44E3;
51 | private static final double PI_OVER_TWO = Math.PI / 2.0;
52 | private static final double SECS_PER_DAY = 8.6400E4;
53 | private static final double FLATTENING_FACTOR = 3.35281066474748E-3;
54 |
55 | protected static final double CK4 = 6.209887E-7;
56 | protected static final double EARTH_GRAVITATIONAL_CONSTANT = 3.986008E5;
57 | protected static final double S = 1.012229;
58 | protected static final double QOMS2T = 1.880279E-09;
59 | protected static final double EARTH_ROTATIONS_PER_SIDERIAL_DAY = 1.00273790934;
60 | protected static final double EARTH_ROTATIONS_RADIANS_PER_SIDERIAL_DAY = EARTH_ROTATIONS_PER_SIDERIAL_DAY
61 | * TWO_PI;
62 | protected static final double RHO = 1.5696615E-1;
63 | protected static final double MFACTOR = 7.292115E-5;
64 | protected static final double SOLAR_RADIUS_KM = 6.96000E5;
65 | protected static final double ASTRONOMICAL_UNIT = 1.49597870691E8;
66 |
67 | protected static final double SPEED_OF_LIGHT = 2.99792458E8;
68 |
69 | protected static final double PERIGEE_156_KM = 156.0;
70 |
71 | /* WGS 84 Earth radius km */
72 | protected static final double EARTH_RADIUS = 6.378137E3;
73 |
74 | /* Solar radius - km (IAU 76) */
75 | protected static final double SOLAR_RADIUS = 6.96000E5;
76 |
77 | private double s4;
78 | private double qoms24;
79 | private double perigee;
80 |
81 | private final TLE tle;
82 |
83 | private double eclipseDepth;
84 |
85 | /**
86 | * Position vector of the satellite. Used to store the position for later
87 | * calculations.
88 | */
89 | private final Vector4 position = new Vector4();
90 | /**
91 | * Velocity vector of the satellite. Used to store the velocity for later
92 | * calculations.
93 | */
94 | private final Vector4 velocity = new Vector4();
95 | /** Date/time at which the position and velocity were calculated */
96 | private double julUTC;
97 | /** Satellite position. Used to store the SatPos for later calculations. */
98 | private SatPos satPos;
99 |
100 | /** The time at which we do all the calculations. */
101 | static final TimeZone TZ = TimeZone.getTimeZone("UTC:UTC");
102 |
103 | private final double julEpoch;
104 |
105 | public AbstractSatellite(final TLE tle) {
106 | this.tle = tle;
107 | julEpoch = AbstractSatellite.juliandDateOfEpoch(tle.getEpoch());
108 | }
109 |
110 | @Override
111 | public final synchronized TLE getTLE() {
112 | return tle;
113 | }
114 |
115 | /**
116 | * Calculates the Julian Day of the Year.
117 | *
118 | * The function Julian_Date_of_Year calculates the Julian Date of Day 0.0 of
119 | * {year}. This function is used to calculate the Julian Date of any date by
120 | * using Julian_Date_of_Year, DOY, and Fraction_of_Day.
121 | *
122 | * Astronomical Formulae for Calculators, Jean Meeus, pages 23-25. Calculate
123 | * Julian Date of 0.0 Jan aYear
124 | *
125 | * @param theYear
126 | * the year
127 | * @return the Julian day number
128 | */
129 | protected static double julianDateOfYear(final double theYear) {
130 |
131 | final double aYear = theYear - 1;
132 | long i = (long) Math.floor(aYear / 100);
133 | final long a = i;
134 | i = a / 4;
135 | final long b = 2 - a + i;
136 | i = (long) Math.floor(365.25 * aYear);
137 | i += 30.6001 * 14;
138 |
139 | return i + 1720994.5 + b;
140 | }
141 |
142 | /**
143 | * The function Julian_Date_of_Epoch returns the Julian Date of an epoch
144 | * specified in the format used in the NORAD two-line element sets. It has
145 | * been modified to support dates beyond the year 1999 assuming that
146 | * two-digit years in the range 00-56 correspond to 2000-2056. Until the
147 | * two-line element set format is changed, it is only valid for dates
148 | * through 2056 December 31.
149 | *
150 | * @param epoch
151 | * the Epoch
152 | * @return The Julian date of the Epoch
153 | */
154 | static double juliandDateOfEpoch(final double epoch) {
155 |
156 | /* Modification to support Y2K */
157 | /* Valid 1957 through 2056 */
158 | double year = Math.floor(epoch * 1E-3);
159 | final double day = (epoch * 1E-3 - year) * 1000.0;
160 |
161 | if (year < 57) {
162 | year = year + 2000;
163 | } else {
164 | year = year + 1900;
165 | }
166 |
167 | return AbstractSatellite.julianDateOfYear(year) + day;
168 | }
169 |
170 | /**
171 | * Read the system clock and return the number of days since 31Dec79
172 | * 00:00:00 UTC (daynum 0).
173 | *
174 | * @param date
175 | * the date we wan to get the offset for
176 | * @return the number of days offset
177 | */
178 | private static double calcCurrentDaynum(final Date date) {
179 |
180 | final long now = date.getTime();
181 |
182 | final Calendar sgp4Epoch = Calendar.getInstance(TZ);
183 | sgp4Epoch.clear();
184 | sgp4Epoch.set(1979, 11, 31, 0, 0, 0);
185 | final long then = sgp4Epoch.getTimeInMillis();
186 | final long millis = now - then;
187 | return millis / 1000.0 / 60.0 / 60.0 / 24.0;
188 | }
189 |
190 | /**
191 | * Returns the square of a double.
192 | *
193 | * @param arg
194 | * the value for which to get the double
195 | * @return the arg squared
196 | */
197 | protected static double sqr(final double arg) {
198 |
199 | return arg * arg;
200 | }
201 |
202 | /**
203 | * Calculates scalar magnitude of a vector4 argument.
204 | *
205 | * @param v
206 | * the vector were measuring
207 | *
208 | */
209 | protected static void magnitude(final Vector4 v) {
210 | v.setW(Math.sqrt(AbstractSatellite.sqr(v.getX())
211 | + AbstractSatellite.sqr(v.getY())
212 | + AbstractSatellite.sqr(v.getZ())));
213 | }
214 |
215 | /**
216 | * Multiplies the vector v1 by the scalar k.
217 | *
218 | * @param k
219 | * the multiplier
220 | * @param v
221 | * the vector
222 | */
223 | private static void scaleVector(final double k, final Vector4 v) {
224 | v.multiply(k);
225 | AbstractSatellite.magnitude(v);
226 | }
227 |
228 | /**
229 | * Gets the modulus of a double value.
230 | *
231 | * @param arg1
232 | * the value to be tested
233 | * @param arg2
234 | * the divisor
235 | * @return the remainder
236 | */
237 | static double modulus(final double arg1, final double arg2) {
238 | /* Returns arg1 mod arg2 */
239 |
240 | double returnValue = arg1;
241 |
242 | final int i = (int) Math.floor(returnValue / arg2);
243 | returnValue -= i * arg2;
244 |
245 | if (returnValue < 0.0) {
246 | returnValue += arg2;
247 | }
248 |
249 | return returnValue;
250 | }
251 |
252 | private static double frac(final double arg) {
253 | /* Returns fractional part of double argument */
254 | return arg - Math.floor(arg);
255 | }
256 |
257 | private static double thetaGJD(final double theJD) {
258 | /* Reference: The 1992 Astronomical Almanac, page B6. */
259 |
260 | final double ut = AbstractSatellite.frac(theJD + 0.5);
261 | final double aJD = theJD - ut;
262 | final double tu = (aJD - 2451545.0) / 36525.0;
263 | double gmst = 24110.54841 + tu
264 | * (8640184.812866 + tu * (0.093104 - tu * 6.2E-6));
265 | gmst = AbstractSatellite.modulus(gmst + SECS_PER_DAY
266 | * EARTH_ROTATIONS_PER_SIDERIAL_DAY * ut, SECS_PER_DAY);
267 |
268 | return TWO_PI * gmst / SECS_PER_DAY;
269 | }
270 |
271 | /**
272 | * Calculates the dot product of two vectors.
273 | *
274 | * @param v1
275 | * vector 1
276 | * @param v2
277 | * vector 2
278 | * @return the dot product
279 | */
280 | private static double dot(final Vector4 v1, final Vector4 v2) {
281 | return v1.getX() * v2.getX() + v1.getY() * v2.getY() + v1.getZ()
282 | * v2.getZ();
283 | }
284 |
285 | /**
286 | * Calculates the modulus of 2 * PI.
287 | *
288 | * @param testValue
289 | * the value under test
290 | * @return the modulus
291 | */
292 | protected static double mod2PI(final double testValue) {
293 | /* Returns mod 2PI of argument */
294 |
295 | double retVal = testValue;
296 | final int i = (int) (retVal / TWO_PI);
297 | retVal -= i * TWO_PI;
298 |
299 | if (retVal < 0.0) {
300 | retVal += TWO_PI;
301 | }
302 |
303 | return retVal;
304 | }
305 |
306 | /**
307 | * Calculate the geodetic position of an object given its ECI position pos
308 | * and time. It is intended to be used to determine the ground track of a
309 | * satellite. The calculations assume the earth to be an oblate spheroid as
310 | * defined in WGS '72.
311 | *
312 | * Reference: The 1992 Astronomical Almanac, page K12.
313 | *
314 | * @param time
315 | * the time
316 | */
317 | private void calculateLatLonAlt(final double time) {
318 |
319 | calculateLatLonAlt(time, satPos, position);
320 | }
321 |
322 | private void calculateLatLonAlt(final double time, SatPos satPos,
323 | Vector4 position) {
324 | satPos.setTheta(Math.atan2(position.getY(), position.getX()));
325 | satPos.setLongitude(AbstractSatellite.mod2PI(satPos.getTheta()
326 | - AbstractSatellite.thetaGJD(time)));
327 | final double r = Math.sqrt(AbstractSatellite.sqr(position.getX())
328 | + AbstractSatellite.sqr(position.getY()));
329 | final double e2 = FLATTENING_FACTOR * (2.0 - FLATTENING_FACTOR);
330 | satPos.setLatitude(Math.atan2(position.getZ(), r));
331 |
332 | double phi;
333 | double c;
334 | int i = 0;
335 | boolean converged = false;
336 |
337 | do {
338 | phi = satPos.getLatitude();
339 | c = invert(Math.sqrt(1.0 - e2 * sqr(Math.sin(phi))));
340 | satPos.setLatitude(Math.atan2(position.getZ() + EARTH_RADIUS_KM * c
341 | * e2 * Math.sin(phi), r));
342 |
343 | converged = Math.abs(satPos.getLatitude() - phi) < EPSILON;
344 |
345 | } while (i++ < 10 && !converged);
346 |
347 | satPos.setAltitude(r / Math.cos(satPos.getLatitude()) - EARTH_RADIUS_KM
348 | * c);
349 |
350 | double temp = satPos.getLatitude();
351 |
352 | if (temp > PI_OVER_TWO) {
353 | temp -= TWO_PI;
354 | satPos.setLatitude(temp);
355 | }
356 | }
357 |
358 | /**
359 | * Converts the satellite'S position and velocity vectors from normalized
360 | * values to km and km/sec.
361 | *
362 | * @param pos
363 | * the position
364 | * @param vel
365 | * the velocity
366 | */
367 | private static void convertSatState(final Vector4 pos, final Vector4 vel) {
368 | /* Converts the satellite'S position and velocity */
369 | /* vectors from normalized values to km and km/sec */
370 | AbstractSatellite.scaleVector(EARTH_RADIUS_KM, pos);
371 | AbstractSatellite.scaleVector(EARTH_RADIUS_KM * MINS_PER_DAY
372 | / SECS_PER_DAY, vel);
373 | }
374 |
375 | @Override
376 | public synchronized SatPos getPosition(final GroundStationPosition gsPos,
377 | final Date date) {
378 |
379 | /* This is the stuff we need to do repetitively while tracking. */
380 | satPos = new SatPos();
381 |
382 | julUTC = AbstractSatellite.calcCurrentDaynum(date) + 2444238.5;
383 |
384 | /* Convert satellite'S epoch time to Julian */
385 | /* and calculate time since epoch in minutes */
386 |
387 | final double tsince = (julUTC - julEpoch) * MINS_PER_DAY;
388 |
389 | calculateSDP4orSGP4(tsince);
390 |
391 | /* Scale position and velocity vectors to km and km/sec */
392 | AbstractSatellite.convertSatState(position, velocity);
393 |
394 | /* Calculate velocity of satellite */
395 |
396 | AbstractSatellite.magnitude(velocity);
397 |
398 | final Vector4 squintVector = new Vector4();
399 |
400 | //
401 | // /** All angles in rads. Distance in km. Velocity in km/S **/
402 | // /* Calculate satellite Azi, Ele, Range and Range-rate */
403 | calculateObs(julUTC, position, velocity, gsPos, squintVector);
404 | //
405 | /* Calculate satellite Lat North, Lon East and Alt. */
406 |
407 | calculateLatLonAlt(julUTC);
408 |
409 | satPos.setTime(date);
410 |
411 | satPos.setEclipsed(isEclipsed());
412 | satPos.setEclipseDepth(eclipseDepth);
413 |
414 | return satPos;
415 | }
416 |
417 | private void calculateSDP4orSGP4(final double tsince) {
418 | if (tle.isDeepspace()) {
419 | ((DeepSpaceSatellite) this).calculateSDP4(tsince);
420 | } else {
421 | ((LEOSatellite) this).calculateSGP4(tsince);
422 | }
423 | }
424 |
425 | /**
426 | * Calculate_User_PosVel() passes the user'S observer position and the time
427 | * of interest and returns the ECI position and velocity of the observer.
428 | * The velocity calculation assumes the observer position is stationary
429 | * relative to the earth'S surface.
430 | *
431 | * Reference: The 1992 Astronomical Almanac, page K11.
432 | *
433 | * @param time
434 | * the time
435 | * @param gsPos
436 | * the ground station position
437 | * @param obsPos
438 | * the position of the observer
439 | * @param obsVel
440 | * the velocity of the observer
441 | */
442 | private static void calculateUserPosVel(final double time,
443 | final GroundStationPosition gsPos,
444 | AtomicReference gsPosTheta, final Vector4 obsPos,
445 | final Vector4 obsVel) {
446 |
447 | gsPosTheta.set(AbstractSatellite.mod2PI(AbstractSatellite
448 | .thetaGJD(time) + DEG2RAD * gsPos.getLongitude()));
449 | final double c = AbstractSatellite
450 | .invert(Math.sqrt(1.0
451 | + FLATTENING_FACTOR
452 | * (FLATTENING_FACTOR - 2)
453 | * AbstractSatellite.sqr(Math.sin(DEG2RAD
454 | * gsPos.getLatitude()))));
455 | final double sq = AbstractSatellite.sqr(1.0 - FLATTENING_FACTOR) * c;
456 | final double achcp = (EARTH_RADIUS_KM * c + (gsPos.getHeightAMSL() / 1000.0))
457 | * Math.cos(DEG2RAD * gsPos.getLatitude());
458 | obsPos.setXYZ(achcp * Math.cos(gsPosTheta.get()),
459 | achcp * Math.sin(gsPosTheta.get()),
460 | (EARTH_RADIUS_KM * sq + (gsPos.getHeightAMSL() / 1000.0))
461 | * Math.sin(DEG2RAD * gsPos.getLatitude()));
462 | obsVel.setXYZ(-MFACTOR * obsPos.getY(), MFACTOR * obsPos.getX(), 0);
463 | AbstractSatellite.magnitude(obsPos);
464 | AbstractSatellite.magnitude(obsVel);
465 | }
466 |
467 | /**
468 | * The procedures Calculate_Obs and Calculate_RADec calculate thetopocentric
469 | * coordinates of the object with ECI position, {pos}, and velocity, {vel},
470 | * from location {geodetic} at {time}. The {obs_set} returned for
471 | * Calculate_Obs consists of azimuth, elevation, range, and range rate (in
472 | * that order) with units of radians, radians, kilometers, and
473 | * kilometers/second, respectively. The WGS '72 geoid is used and the effect
474 | * of atmospheric refraction (under standard temperature and pressure) is
475 | * incorporated into the elevation calculation; the effect of atmospheric
476 | * refraction on range and range rate has not yet been quantified.
477 | *
478 | * The {obs_set} for Calculate_RADec consists of right ascension and
479 | * declination (in that order) in radians. Again, calculations are based
480 | * ontopocentric position using the WGS '72 geoid and incorporating
481 | * atmospheric refraction.
482 | *
483 | * @param julianUTC
484 | * Julian date of UTC
485 | * @param positionVector
486 | * the position vector
487 | * @param velocityVector
488 | * the velocity vector
489 | * @param gsPos
490 | * the ground tstation position
491 | * @param squintVector
492 | * the squint vector
493 | * @param satellitePosition
494 | * the satellite position
495 | *
496 | */
497 | private void calculateObs(final double julianUTC,
498 | final Vector4 positionVector, final Vector4 velocityVector,
499 | final GroundStationPosition gsPos, final Vector4 squintVector) {
500 |
501 | final Vector4 obsPos = new Vector4();
502 | final Vector4 obsVel = new Vector4();
503 | final Vector4 range = new Vector4();
504 | final Vector4 rgvel = new Vector4();
505 |
506 | AtomicReference gsPosTheta = new AtomicReference();
507 | AbstractSatellite.calculateUserPosVel(julianUTC, gsPos, gsPosTheta,
508 | obsPos, obsVel);
509 |
510 | range.setXYZ(positionVector.getX() - obsPos.getX(),
511 | positionVector.getY() - obsPos.getY(), positionVector.getZ()
512 | - obsPos.getZ());
513 |
514 | /* Save these values globally for calculating squint angles later... */
515 |
516 | squintVector.setXYZ(range.getX(), range.getY(), range.getZ());
517 |
518 | rgvel.setXYZ(velocityVector.getX() - obsVel.getX(),
519 | velocityVector.getY() - obsVel.getY(), velocityVector.getZ()
520 | - obsVel.getZ());
521 |
522 | AbstractSatellite.magnitude(range);
523 |
524 | final double sinLat = Math.sin(DEG2RAD * gsPos.getLatitude());
525 | final double cosLat = Math.cos(DEG2RAD * gsPos.getLatitude());
526 | final double sinTheta = Math.sin(gsPosTheta.get());
527 | final double cosTheta = Math.cos(gsPosTheta.get());
528 | final double topS = sinLat * cosTheta * range.getX() + sinLat
529 | * sinTheta * range.getY() - cosLat * range.getZ();
530 | final double topE = -sinTheta * range.getX() + cosTheta * range.getY();
531 | final double topZ = cosLat * cosTheta * range.getX() + cosLat
532 | * sinTheta * range.getY() + sinLat * range.getZ();
533 | double azim = Math.atan(-topE / topS);
534 |
535 | if (topS > 0.0) {
536 | azim = azim + Math.PI;
537 | }
538 |
539 | if (azim < 0.0) {
540 | azim = azim + TWO_PI;
541 | }
542 |
543 | satPos.setAzimuth(azim);
544 | satPos.setElevation(Math.asin(topZ / range.getW()));
545 | satPos.setRange(range.getW());
546 | satPos.setRangeRate(AbstractSatellite.dot(range, rgvel) / range.getW());
547 |
548 | final int sector = (int) (satPos.getAzimuth() / TWO_PI * 360.0 / 10.0);
549 |
550 | double elevation = (satPos.getElevation() / Satellite.TWO_PI) * 360.0;
551 |
552 | if (elevation > 90) {
553 | elevation = 180 - elevation;
554 | }
555 |
556 | satPos.setAboveHorizon((elevation - gsPos.getHorizonElevation(sector)) > EPSILON);
557 | }
558 |
559 | @Override
560 | public boolean willBeSeen(final GroundStationPosition qth) {
561 |
562 | if (tle.getMeanmo() < 1e-8) {
563 | return false;
564 | } else {
565 | double lin = tle.getIncl();
566 |
567 | if (lin >= 90.0) {
568 | lin = 180.0 - lin;
569 | }
570 |
571 | final double sma = 331.25 * Math.exp(Math.log(1440.0 / tle
572 | .getMeanmo()) * (2.0 / 3.0));
573 | final double apogee = sma * (1.0 + tle.getEccn()) - EARTH_RADIUS_KM;
574 |
575 | return (Math.acos(EARTH_RADIUS_KM / (apogee + EARTH_RADIUS_KM)) + (lin * DEG2RAD)) > Math
576 | .abs(qth.getLatitude() * DEG2RAD);
577 | }
578 |
579 | }
580 |
581 | /**
582 | * @return the s4
583 | */
584 | protected double getS4() {
585 | return s4;
586 | }
587 |
588 | /**
589 | * @return the qoms24
590 | */
591 | protected double getQoms24() {
592 | return qoms24;
593 | }
594 |
595 | /**
596 | * Checks and adjusts the calculation if the perigee is less tan 156KM.
597 | */
598 | private void checkPerigee() {
599 | s4 = S;
600 | qoms24 = QOMS2T;
601 |
602 | if (perigee < PERIGEE_156_KM) {
603 | if (perigee <= 98.0) {
604 | s4 = 20.0;
605 | } else {
606 | s4 = perigee - 78.0;
607 | }
608 |
609 | qoms24 = Math.pow((120 - s4) / EARTH_RADIUS_KM, 4);
610 | s4 = s4 / EARTH_RADIUS_KM + 1.0;
611 | }
612 | }
613 |
614 | /**
615 | * Sets perigee and checks and adjusts the calculation if the perigee is
616 | * less tan 156KM.
617 | *
618 | * @param perigee
619 | * the perigee to set
620 | */
621 | protected void setPerigee(final double perigee) {
622 | this.perigee = perigee;
623 | checkPerigee();
624 | }
625 |
626 | static class Vector4 {
627 |
628 | /** the w part of the vector. ` */
629 | private double w;
630 | /** the x part of the vector. ` */
631 | private double x;
632 | /** the y part of the vector. ` */
633 | private double y;
634 | /** the z part of the vector. ` */
635 | private double z;
636 |
637 | /** default constructor. */
638 | Vector4() {
639 | this.w = 0.0;
640 | this.x = 0.0;
641 | this.y = 0.0;
642 | this.z = 0.0;
643 | }
644 |
645 | /**
646 | * @param w
647 | * the w value
648 | * @param x
649 | * the x value
650 | * @param y
651 | * the y value
652 | * @param z
653 | * the z value
654 | */
655 | Vector4(final double w, final double x, final double y, final double z) {
656 | this.w = w;
657 | this.x = x;
658 | this.y = y;
659 | this.z = z;
660 | }
661 |
662 | /**
663 | * Gets the string representation of the object.
664 | *
665 | * @return the string representation of the object
666 | */
667 | @Override
668 | public final String toString() {
669 | return "w: " + w + ", x: " + x + ", y: " + y + ", z: " + z;
670 | }
671 |
672 | /**
673 | * @return the w
674 | */
675 | public final double getW() {
676 | return w;
677 | }
678 |
679 | /**
680 | * @param w
681 | * the w to set
682 | */
683 | public final void setW(final double w) {
684 | this.w = w;
685 | }
686 |
687 | /**
688 | * @return the x
689 | */
690 | public final double getX() {
691 | return x;
692 | }
693 |
694 | /**
695 | * @param x
696 | * the x to set
697 | */
698 | public final void setX(final double x) {
699 | this.x = x;
700 | }
701 |
702 | /**
703 | * @return the y
704 | */
705 | public final double getY() {
706 | return y;
707 | }
708 |
709 | /**
710 | * @param y
711 | * the y to set
712 | */
713 | public final void setY(final double y) {
714 | this.y = y;
715 | }
716 |
717 | /**
718 | * @return the z
719 | */
720 | public final double getZ() {
721 | return z;
722 | }
723 |
724 | /**
725 | * @param z
726 | * the z to set
727 | */
728 | public final void setZ(final double z) {
729 | this.z = z;
730 | }
731 |
732 | public final void multiply(final double multiplier) {
733 | this.x *= multiplier;
734 | this.y *= multiplier;
735 | this.z *= multiplier;
736 | }
737 |
738 | public final void setXYZ(final double xValue, final double yValue,
739 | final double zValue) {
740 | this.x = xValue;
741 | this.y = yValue;
742 | this.z = zValue;
743 | }
744 |
745 | public Vector4 subtract(final Vector4 vector) {
746 | return new Vector4(this.w - vector.w, this.x - vector.x, this.y
747 | - vector.y, this.z - vector.z);
748 | }
749 |
750 | public static final Vector4 scalarMultiply(final Vector4 vector,
751 | final double multiplier) {
752 |
753 | return new Vector4(vector.w * Math.abs(multiplier), vector.x
754 | * multiplier, vector.y * multiplier, vector.z * multiplier);
755 | }
756 |
757 | /**
758 | * Calculates the angle between vectors v1 and v2.
759 | */
760 | public static final double angle(final Vector4 v1, final Vector4 v2) {
761 | AbstractSatellite.magnitude(v1);
762 | AbstractSatellite.magnitude(v2);
763 | return Math.acos(AbstractSatellite.dot(v1, v2) / (v1.w * v2.w));
764 | }
765 |
766 | /**
767 | * Subtracts vector v2 from v1.
768 | */
769 | public static final Vector4 subtract(final Vector4 v1, final Vector4 v2) {
770 |
771 | final Vector4 v3 = new Vector4();
772 | v3.x = v1.x - v2.x;
773 | v3.y = v1.y - v2.y;
774 | v3.z = v1.z - v2.z;
775 | AbstractSatellite.magnitude(v3);
776 | return v3;
777 | }
778 | }
779 |
780 | /**
781 | * Solves Keplers' Equation.
782 | *
783 | * @param temp
784 | * an array of temporary values we pass around as part of the
785 | * orbit calculation.
786 | * @param axn
787 | * @param ayn
788 | * @param capu
789 | */
790 | protected static void converge(final double[] temp, final double axn,
791 | final double ayn, final double capu) {
792 |
793 | boolean converged = false;
794 | int i = 0;
795 |
796 | do {
797 | temp[7] = Math.sin(temp[2]);
798 | temp[8] = Math.cos(temp[2]);
799 | temp[3] = axn * temp[7];
800 | temp[4] = ayn * temp[8];
801 | temp[5] = axn * temp[8];
802 | temp[6] = ayn * temp[7];
803 | final double epw = (capu - temp[4] + temp[3] - temp[2])
804 | / (1.0 - temp[5] - temp[6]) + temp[2];
805 |
806 | if (Math.abs(epw - temp[2]) <= EPSILON) {
807 | converged = true;
808 | } else {
809 | temp[2] = epw;
810 | }
811 |
812 | } while (i++ < 10 && !converged);
813 | }
814 |
815 | @Override
816 | public synchronized void calculateSatelliteVectors(final Date date) {
817 | // Re-initialize, object can contain data from previous calculations
818 | satPos = new SatPos();
819 |
820 | // Date/time for which the satellite position and velocity are
821 | // calculated
822 | julUTC = AbstractSatellite.calcCurrentDaynum(date) + 2444238.5;
823 |
824 | // Calculate time since epoch in minutes
825 |
826 | final double tsince = (julUTC - julEpoch) * MINS_PER_DAY;
827 |
828 | // Calculations of satellite position, no ground stations involved here
829 | // yet
830 | calculateSDP4orSGP4(tsince);
831 |
832 | // Scale position and velocity vectors to km and km/s
833 | AbstractSatellite.convertSatState(position, velocity);
834 |
835 | // Calculate the magnitude of the velocity of satellite
836 | AbstractSatellite.magnitude(velocity);
837 |
838 | satPos.setEclipsed(isEclipsed());
839 | satPos.setEclipseDepth(eclipseDepth);
840 |
841 | satPos.setTime(date);
842 | }
843 |
844 | @Override
845 | public synchronized SatPos calculateSatelliteGroundTrack() {
846 | calculateLatLonAlt(julUTC);
847 |
848 | return this.satPos;
849 | }
850 |
851 | @Override
852 | public synchronized SatPos calculateSatPosForGroundStation(
853 | final GroundStationPosition gsPos) {
854 | final Vector4 squintVector = new Vector4();
855 | // All angles in rads. Distance in km. Velocity in km/s
856 | // Calculate satellite Azi, Ele, Range and Range-rate
857 | calculateObs(julUTC, position, velocity, gsPos, squintVector);
858 |
859 | return this.satPos;
860 | }
861 |
862 | /**
863 | * Determines if the satellite is in sunlight.
864 | */
865 | private boolean isEclipsed() {
866 |
867 | final Vector4 sunVector = calculateSunVector();
868 |
869 | /* Calculates stellite's eclipse status and depth */
870 |
871 | /* Determine partial eclipse */
872 |
873 | final double sdEarth = Math.asin(EARTH_RADIUS / position.w);
874 | final Vector4 rho = Vector4.subtract(sunVector, position);
875 | final double sdSun = Math.asin(SOLAR_RADIUS / rho.w);
876 | final Vector4 earth = Vector4.scalarMultiply(position, -1);
877 | final double delta = Vector4.angle(sunVector, earth);
878 | eclipseDepth = sdEarth - sdSun - delta;
879 |
880 | if (sdEarth < sdSun) {
881 | return false;
882 | } else {
883 | return eclipseDepth >= 0;
884 | }
885 | }
886 |
887 | private Vector4 calculateSunVector() {
888 |
889 | final double mjd = julUTC - 2415020.0;
890 | final double year = 1900 + mjd / 365.25;
891 | final double solTime = (mjd + deltaEt(year) / SECS_PER_DAY) / 36525.0;
892 |
893 | final double m = radians(AbstractSatellite.modulus(
894 | 358.47583
895 | + AbstractSatellite.modulus(35999.04975 * solTime,
896 | 360.0) - (0.000150 + 0.0000033 * solTime)
897 | * AbstractSatellite.sqr(solTime), 360.0));
898 | final double l = radians(AbstractSatellite.modulus(279.69668
899 | + AbstractSatellite.modulus(36000.76892 * solTime, 360.0)
900 | + 0.0003025 * AbstractSatellite.sqr(solTime), 360.0));
901 | final double e = 0.01675104 - (0.0000418 + 0.000000126 * solTime)
902 | * solTime;
903 | final double c = radians((1.919460 - (0.004789 + 0.000014 * solTime)
904 | * solTime)
905 | * Math.sin(m)
906 | + (0.020094 - 0.000100 * solTime)
907 | * Math.sin(2 * m) + 0.000293 * Math.sin(3 * m));
908 | final double o = radians(AbstractSatellite.modulus(
909 | 259.18 - 1934.142 * solTime, 360.0));
910 | final double lsa = AbstractSatellite.modulus(l + c
911 | - radians(0.00569 - 0.00479 * Math.sin(o)), TWO_PI);
912 | final double nu = AbstractSatellite.modulus(m + c, TWO_PI);
913 | double r = 1.0000002 * (1.0 - AbstractSatellite.sqr(e))
914 | / (1.0 + e * Math.cos(nu));
915 | final double eps = radians(23.452294
916 | - (0.0130125 + (0.00000164 - 0.000000503 * solTime) * solTime)
917 | * solTime + 0.00256 * Math.cos(o));
918 | r = ASTRONOMICAL_UNIT * r;
919 |
920 | return new Vector4(r, r * Math.cos(lsa), r * Math.sin(lsa)
921 | * Math.cos(eps), r * Math.sin(lsa) * Math.sin(eps));
922 | }
923 |
924 | /**
925 | * The function Delta_ET has been added to allow calculations on the
926 | * position of the sun. It provides the difference between UT (approximately
927 | * the same as UTC) and ET (now referred to as TDT) This function is based
928 | * on a least squares fit of data from 1950 to 1991 and will need to be
929 | * updated periodically.
930 | *
931 | * Values determined using data from 1950-1991 in the 1990 Astronomical
932 | * Almanac. See DELTA_ET.WQ1 for details.
933 | */
934 | private double deltaEt(final double year) {
935 |
936 | return 26.465 + 0.747622 * (year - 1950) + 1.886913
937 | * Math.sin(TWO_PI * (year - 1975) / 33);
938 | }
939 |
940 | /**
941 | * Returns angle in radians from argument in degrees.
942 | */
943 | private double radians(final double degrees) {
944 | return degrees * DEG2RAD;
945 | }
946 |
947 | protected void calculatePhase(final double xlt, final double xnode,
948 | final double omgadf) {
949 | /* Phase in radians */
950 | double phaseValue = xlt - xnode - omgadf + TWO_PI;
951 |
952 | if (phaseValue < 0.0) {
953 | phaseValue += TWO_PI;
954 | }
955 |
956 | satPos.setPhase(AbstractSatellite.mod2PI(phaseValue));
957 | }
958 |
959 | protected void calculatePositionAndVelocity(final double rk,
960 | final double uk, final double xnodek, final double xinck,
961 | final double rdotk, final double rfdotk) {
962 | /* Orientation vectors */
963 | final double sinuk = Math.sin(uk);
964 | final double cosuk = Math.cos(uk);
965 | final double sinik = Math.sin(xinck);
966 | final double cosik = Math.cos(xinck);
967 | final double sinnok = Math.sin(xnodek);
968 | final double cosnok = Math.cos(xnodek);
969 | final double xmx = -sinnok * cosik;
970 | final double xmy = cosnok * cosik;
971 | final double ux = xmx * sinuk + cosnok * cosuk;
972 | final double uy = xmy * sinuk + sinnok * cosuk;
973 | final double uz = sinik * sinuk;
974 | final double vx = xmx * cosuk - cosnok * sinuk;
975 | final double vy = xmy * cosuk - sinnok * sinuk;
976 | final double vz = sinik * cosuk;
977 |
978 | /* Position and velocity */
979 | position.setXYZ(ux, uy, uz);
980 | position.multiply(rk);
981 | velocity.setX(rdotk * ux + rfdotk * vx);
982 | velocity.setY(rdotk * uy + rfdotk * vy);
983 | velocity.setZ(rdotk * uz + rfdotk * vz);
984 | }
985 |
986 | protected static double invert(final double value) {
987 | return 1.0 / value;
988 | }
989 |
990 | /**
991 | * @return the eclipseDepth
992 | */
993 | public final double getEclipseDepth() {
994 | return eclipseDepth;
995 | }
996 | }
997 |
--------------------------------------------------------------------------------
/src/main/java/com/github/amsacode/predict4java/GroundStationPosition.java:
--------------------------------------------------------------------------------
1 | /**
2 | predict4java: An SDP4 / SGP4 library for satellite orbit predictions
3 |
4 | Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
5 |
6 | This class is a Java port of one of the core elements of
7 | the Predict program, Copyright John A. Magliacane,
8 | KD2BD 1991-2003: http://www.qsl.net/kd2bd/predict.html
9 |
10 | Dr. T.S. Kelso is the author of the SGP4/SDP4 orbital models,
11 | originally written in Fortran and Pascal, and released into the
12 | public domain through his website (http://www.celestrak.com/).
13 | Neoklis Kyriazis, 5B4AZ, later re-wrote Dr. Kelso's code in C,
14 | and released it under the GNU GPL in 2002.
15 | PREDICT's core is based on 5B4AZ's code translation efforts.
16 |
17 | Author: David A. B. Johnson, G4DPZ
18 |
19 | Comments, questions and bugreports should be submitted via
20 | http://sourceforge.net/projects/websat/
21 | More details can be found at the project home page:
22 |
23 | http://websat.sourceforge.net
24 |
25 | This program is free software; you can redistribute it and/or modify
26 | it under the terms of the GNU General Public License as published by
27 | the Free Software Foundation; either version 2 of the License, or
28 | (at your option) any later version.
29 |
30 | This program is distributed in the hope that it will be useful,
31 | but WITHOUT ANY WARRANTY; without even the implied warranty of
32 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 | GNU General Public License for more details.
34 |
35 | You should have received a copy of the GNU General Public License
36 | along with this program; if not, visit http://www.fsf.org/
37 | */
38 | package com.github.amsacode.predict4java;
39 |
40 | import java.util.Arrays;
41 |
42 | import com.github.davidmoten.guavamini.Preconditions;
43 |
44 | /**
45 | * The location of the Satellite Ground Station. Instances of this class are
46 | * immutable and thus thread safe.
47 | *
48 | * @author g4dpz
49 | */
50 | public class GroundStationPosition {
51 | private static final int NUM_SECTORS = 36; //each sector is 10 degrees
52 |
53 | private final double latitude;
54 | private final double longitude;
55 | private final double heightAMSL;
56 | private final int[] horizonElevations;
57 | private final String name;
58 |
59 | /**
60 | * @param latitude
61 | * the latitude of the ground station in degrees, North: positive
62 | * @param longitude
63 | * the longitude of the ground station in degrees, East: positive
64 | * @param heightAMSL
65 | * the height of the ground station above mean sea level, in metres
66 | * @param name
67 | * the name of the ground station. If null passed then an empty
68 | * string is used for the name
69 | * @param horizonElevations
70 | * the elevations of the horizon in degrees from the ground station
71 | * by 10 degree sectors. If null is passed then 0 is assumed for all
72 | * sectors.
73 | */
74 | public GroundStationPosition(final double latitude, final double longitude, final double heightAMSL, String name,
75 | int[] horizonElevations) {
76 | Preconditions.checkArgument(horizonElevations == null || horizonElevations.length == NUM_SECTORS,
77 | "horizonElevations array must have length 36 corresponding to 10 degree sectors");
78 | this.latitude = latitude;
79 | this.longitude = longitude;
80 | this.heightAMSL = heightAMSL;
81 | this.name = name == null ? "" : name;
82 | // Note that a copy of horizon elevations is made to honour the thread-safety
83 | // claim of this class
84 | this.horizonElevations = horizonElevations == null ? new int[NUM_SECTORS]
85 | : Arrays.copyOf(horizonElevations, horizonElevations.length);
86 | }
87 |
88 | /**
89 | * @param latitude
90 | * the latitude of the ground station in degrees, North: positive
91 | * @param longitude
92 | * the longitude of the ground station in degrees, East: positive
93 | * @param heightAMSL
94 | * the height of the ground station above mean sea level, in
95 | * metres
96 | */
97 | public GroundStationPosition(final double latitude, final double longitude,
98 | final double heightAMSL) {
99 | this(latitude, longitude, heightAMSL, null, null);
100 | }
101 |
102 | /**
103 | * @param latitude
104 | * the latitude of the ground station in degrees, North: positive
105 | * @param longitude
106 | * the longitude of the ground station in degrees, East: positive
107 | * @param heightAMSL
108 | * the height of the ground station above mean sea level, in metres
109 | * @param name
110 | * the name of the ground station. If null passed then an empty
111 | * string is used for the name
112 | */
113 | public GroundStationPosition(final double latitude, final double longitude, final double heightAMSL, String name) {
114 | this(latitude, longitude, heightAMSL, name, null);
115 | }
116 |
117 |
118 | /**
119 | * @return latitude
120 | */
121 | public double getLatitude() {
122 | return latitude;
123 | }
124 |
125 | /**
126 | * @return longitude
127 | */
128 | public double getLongitude() {
129 | return longitude;
130 | }
131 |
132 | /**
133 | * @return elevation
134 | */
135 | public double getHeightAMSL() {
136 | return heightAMSL;
137 | }
138 |
139 | /**
140 | * Returns the horizon elevation in degrees by 10 degree sector.
141 | *
142 | * @return the horizonElevation in degrees.
143 | */
144 | public final int getHorizonElevation(int sector) {
145 | return horizonElevations[sector];
146 | }
147 |
148 | public String getName() {
149 | return name;
150 | }
151 |
152 | }
153 |
--------------------------------------------------------------------------------
/src/main/java/com/github/amsacode/predict4java/LEOSatellite.java:
--------------------------------------------------------------------------------
1 | /**
2 | predict4java: An SDP4 / SGP4 library for satellite orbit predictions
3 |
4 | Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
5 |
6 | This class is a Java port of one of the core elements of
7 | the Predict program, Copyright John A. Magliacane,
8 | KD2BD 1991-2003: http://www.qsl.net/kd2bd/predict.html
9 |
10 | Dr. T.S. Kelso is the author of the SGP4/SDP4 orbital models,
11 | originally written in Fortran and Pascal, and released into the
12 | public domain through his website (http://www.celestrak.com/).
13 | Neoklis Kyriazis, 5B4AZ, later re-wrote Dr. Kelso's code in C,
14 | and released it under the GNU GPL in 2002.
15 | PREDICT's core is based on 5B4AZ's code translation efforts.
16 |
17 | Author: David A. B. Johnson, G4DPZ
18 |
19 | Comments, questions and bugreports should be submitted via
20 | http://sourceforge.net/projects/websat/
21 | More details can be found at the project home page:
22 |
23 | http://websat.sourceforge.net
24 |
25 | This program is free software; you can redistribute it and/or modify
26 | it under the terms of the GNU General Public License as published by
27 | the Free Software Foundation; either version 2 of the License, or
28 | (at your option) any later version.
29 |
30 | This program is distributed in the hope that it will be useful,
31 | but WITHOUT ANY WARRANTY; without even the implied warranty of
32 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 | GNU General Public License for more details.
34 |
35 | You should have received a copy of the GNU General Public License
36 | along with this program; if not, visit http://www.fsf.org/
37 | */
38 | package com.github.amsacode.predict4java;
39 |
40 | /**
41 | *
42 | * @author g4dpz
43 | *
44 | */
45 | public class LEOSatellite extends AbstractSatellite {
46 |
47 | private final double aodp;
48 | private final double aycof;
49 | private final double c1;
50 | private final double c4;
51 | private final double c5;
52 | private final double cosio;
53 | private final double d2;
54 | private final double d3;
55 | private final double d4;
56 | private final double delmo;
57 | private final double omgcof;
58 | private final double eta;
59 | private final double omgdot;
60 | private final double sinio;
61 | private final double xnodp;
62 | private final double sinmo;
63 | private final double t2cof;
64 | private final double t3cof;
65 | private final double t4cof;
66 | private final double t5cof;
67 | private final double x1mth2;
68 | private final double x3thm1;
69 | private final double x7thm1;
70 | private final double xmcof;
71 | private final double xmdot;
72 | private final double xnodcf;
73 | private final double xnodot;
74 | private final double xlcof;
75 |
76 | private final boolean sgp4Simple;
77 |
78 | /**
79 | * Creates a Low Earth Orbit Satellite.
80 | *
81 | * @param tle
82 | * the three line elements
83 | */
84 | public LEOSatellite(final TLE tle) {
85 | super(tle);
86 |
87 | /* Recover original mean motion (xnodp) and */
88 | /* semimajor axis (aodp) from input elements. */
89 |
90 | final double a1 = Math.pow(XKE / getTLE().getXno(), TWO_THIRDS);
91 | cosio = Math.cos(getTLE().getXincl());
92 | final double theta2 = AbstractSatellite.sqr(cosio);
93 | x3thm1 = 3.0 * theta2 - 1.0;
94 | final double eo = getTLE().getEo();
95 | final double eosq = AbstractSatellite.sqr(eo);
96 | final double betao2 = 1.0 - eosq;
97 | final double betao = Math.sqrt(betao2);
98 | final double del1 = 1.5 * CK2 * x3thm1
99 | / (AbstractSatellite.sqr(a1) * betao * betao2);
100 | final double ao = a1
101 | * (1.0 - del1
102 | * (0.5 * TWO_THIRDS + del1
103 | * (1.0 + 134.0 / 81.0 * del1)));
104 | final double delo = 1.5 * CK2 * x3thm1
105 | / (AbstractSatellite.sqr(ao) * betao * betao2);
106 | xnodp = getTLE().getXno() / (1.0 + delo);
107 | aodp = ao / (1.0 - delo);
108 |
109 | /* For perigee less than 220 kilometers, the "simple" */
110 | /* flag is set and the equations are truncated to linear */
111 | /* variation in sqrt a and quadratic variation in mean */
112 | /* anomaly. Also, the c3 term, the delta omega term, and */
113 | /* the delta m term are dropped. */
114 |
115 | sgp4Simple = (aodp * (1.0 - eo)) < (220 / EARTH_RADIUS_KM + 1.0);
116 |
117 | /* For perigees below 156 km, the */
118 | /* values of S and QOMS2T are altered. */
119 | setPerigee((aodp * (1.0 - eo) - 1.0) * EARTH_RADIUS_KM);
120 |
121 | final double pinvsq = AbstractSatellite.invert(AbstractSatellite
122 | .sqr(aodp) * AbstractSatellite.sqr(betao2));
123 | final double tsi = AbstractSatellite.invert(aodp - getS4());
124 | eta = aodp * eo * tsi;
125 | final double etasq = eta * eta;
126 | final double eeta = eo * eta;
127 | final double psisq = Math.abs(1.0 - etasq);
128 | final double coef = getQoms24() * Math.pow(tsi, 4);
129 | final double coef1 = coef / Math.pow(psisq, 3.5);
130 | final double bstar = getTLE().getBstar();
131 | final double c2 = coef1
132 | * xnodp
133 | * (aodp * (1.0 + 1.5 * etasq + eeta * (4.0 + etasq)) + 0.75
134 | * CK2 * tsi / psisq * x3thm1
135 | * (8.0 + 3.0 * etasq * (8.0 + etasq)));
136 | c1 = bstar * c2;
137 | sinio = Math.sin(getTLE().getXincl());
138 | final double a3ovk2 = -J3_HARMONIC / CK2;
139 | final double c3 = coef * tsi * a3ovk2 * xnodp * sinio / eo;
140 | x1mth2 = 1.0 - theta2;
141 |
142 | final double omegao = getTLE().getOmegao();
143 |
144 | c4 = 2
145 | * xnodp
146 | * coef1
147 | * aodp
148 | * betao2
149 | * (eta * (2.0 + 0.5 * etasq) + eo * (0.5 + 2 * etasq) - 2
150 | * CK2
151 | * tsi
152 | / (aodp * psisq)
153 | * (-3 * x3thm1
154 | * (1.0 - 2 * eeta + etasq * (1.5 - 0.5 * eeta)) + 0.75
155 | * x1mth2
156 | * (2.0 * etasq - eeta * (1.0 + etasq))
157 | * Math.cos(2.0 * omegao)));
158 |
159 | c5 = 2.0 * coef1 * aodp * betao2
160 | * (1.0 + 2.75 * (etasq + eeta) + eeta * etasq);
161 |
162 | final double theta4 = AbstractSatellite.sqr(theta2);
163 | final double temp1 = 3.0 * CK2 * pinvsq * xnodp;
164 | final double temp2 = temp1 * CK2 * pinvsq;
165 | final double temp3 = 1.25 * CK4 * pinvsq * pinvsq * xnodp;
166 | xmdot = xnodp + 0.5 * temp1 * betao * x3thm1 + 0.0625 * temp2 * betao
167 | * (13.0 - 78.0 * theta2 + 137.0 * theta4);
168 | final double x1m5th = 1.0 - 5.0 * theta2;
169 | omgdot = -0.5 * temp1 * x1m5th + 0.0625 * temp2
170 | * (7.0 - 114.0 * theta2 + 395.0 * theta4) + temp3
171 | * (3.0 - 36.0 * theta2 + 49.0 * theta4);
172 | final double xhdot1 = -temp1 * cosio;
173 | xnodot = xhdot1
174 | + (0.5 * temp2 * (4.0 - 19.0 * theta2) + 2.0 * temp3
175 | * (3.0 - 7.0 * theta2)) * cosio;
176 | omgcof = bstar * c3 * Math.cos(omegao);
177 | xmcof = -TWO_THIRDS * coef * bstar / eeta;
178 | xnodcf = 3.5 * betao2 * xhdot1 * c1;
179 | t2cof = 1.5 * c1;
180 | xlcof = 0.125 * a3ovk2 * sinio * (3.0 + 5 * cosio) / (1.0 + cosio);
181 | aycof = 0.25 * a3ovk2 * sinio;
182 | final double xmo = getTLE().getXmo();
183 | delmo = Math.pow(1.0 + eta * Math.cos(xmo), 3);
184 | sinmo = Math.sin(xmo);
185 | x7thm1 = 7.0 * theta2 - 1;
186 |
187 | if (!sgp4Simple) {
188 | final double c1sq = AbstractSatellite.sqr(c1);
189 | d2 = 4.0 * aodp * tsi * c1sq;
190 | final double temp = d2 * tsi * c1 / 3.0;
191 | d3 = (17 * aodp + getS4()) * temp;
192 | d4 = 0.5 * temp * aodp * tsi * (221 * aodp + 31 * getS4()) * c1;
193 | t3cof = d2 + 2 * c1sq;
194 | t4cof = 0.25 * (3.0 * d3 + c1 * (12 * d2 + 10 * c1sq));
195 | t5cof = 0.2 * (3.0 * d4 + 12 * c1 * d3 + 6 * d2 * d2 + 15 * c1sq
196 | * (2.0 * d2 + c1sq));
197 | } else {
198 | d2 = 0;
199 | d3 = 0;
200 | d4 = 0;
201 | t3cof = 0;
202 | t4cof = 0;
203 | t5cof = 0;
204 | }
205 | }
206 |
207 | protected void calculateSGP4(final double tsince) {
208 |
209 | synchronized (this) {
210 |
211 | final double[] temp = new double[9];
212 |
213 | /* Update for secular gravity and atmospheric drag. */
214 | final double xmdf = getTLE().getXmo() + xmdot * tsince;
215 | final double omgadf = getTLE().getOmegao() + omgdot * tsince;
216 | final double xnoddf = getTLE().getXnodeo() + xnodot * tsince;
217 | double omega = omgadf;
218 | double xmp = xmdf;
219 | final double tsq = AbstractSatellite.sqr(tsince);
220 | final double xnode = xnoddf + xnodcf * tsq;
221 | final double bstar = getTLE().getBstar();
222 | double tempa = 1.0 - c1 * tsince;
223 | double tempe = bstar * c4 * tsince;
224 | double templ = t2cof * tsq;
225 |
226 | if (!sgp4Simple) {
227 | final double delomg = omgcof * tsince;
228 | final double delm = xmcof
229 | * (Math.pow(1.0 + eta * Math.cos(xmdf), 3) - delmo);
230 | temp[0] = delomg + delm;
231 | xmp = xmdf + temp[0];
232 | omega = omgadf - temp[0];
233 | final double tcube = tsq * tsince;
234 | final double tfour = tsince * tcube;
235 | tempa = tempa - d2 * tsq - d3 * tcube - d4 * tfour;
236 | tempe = tempe + bstar * c5 * (Math.sin(xmp) - sinmo);
237 | templ = templ + t3cof * tcube + tfour
238 | * (t4cof + tsince * t5cof);
239 | }
240 |
241 | final double a = aodp * Math.pow(tempa, 2);
242 | final double eo = getTLE().getEo();
243 | final double e = eo - tempe;
244 | final double xl = xmp + omega + xnode + xnodp * templ;
245 | final double beta = Math.sqrt(1.0 - e * e);
246 | final double xn = XKE / Math.pow(a, 1.5);
247 |
248 | /* Long period periodics */
249 | final double axn = e * Math.cos(omega);
250 | temp[0] = AbstractSatellite.invert(a * AbstractSatellite.sqr(beta));
251 | final double xll = temp[0] * xlcof * axn;
252 | final double aynl = temp[0] * aycof;
253 | final double xlt = xl + xll;
254 | final double ayn = e * Math.sin(omega) + aynl;
255 |
256 | /* Solve Kepler'S Equation */
257 | final double capu = AbstractSatellite.mod2PI(xlt - xnode);
258 | temp[2] = capu;
259 |
260 | AbstractSatellite.converge(temp, axn, ayn, capu);
261 |
262 | calculatePositionAndVelocity(temp, xnode, a, xn, axn, ayn);
263 |
264 | calculatePhase(xlt, xnode, omgadf);
265 | }
266 | }
267 |
268 | private void calculatePositionAndVelocity(final double[] temp,
269 | final double xnode, final double a, final double xn,
270 | final double axn, final double ayn) {
271 | final double ecose = temp[5] + temp[6];
272 | final double esine = temp[3] - temp[4];
273 | final double elsq = AbstractSatellite.sqr(axn)
274 | + AbstractSatellite.sqr(ayn);
275 | temp[0] = 1.0 - elsq;
276 | final double pl = a * temp[0];
277 | final double r = a * (1.0 - ecose);
278 | temp[1] = AbstractSatellite.invert(r);
279 | final double rdot = XKE * Math.sqrt(a) * esine * temp[1];
280 | final double rfdot = XKE * Math.sqrt(pl) * temp[1];
281 | temp[2] = a * temp[1];
282 | final double betal = Math.sqrt(temp[0]);
283 | temp[3] = AbstractSatellite.invert(1.0 + betal);
284 | final double cosu = temp[2] * (temp[8] - axn + ayn * esine * temp[3]);
285 | final double sinu = temp[2] * (temp[7] - ayn - axn * esine * temp[3]);
286 | final double u = Math.atan2(sinu, cosu);
287 | final double sin2u = 2.0 * sinu * cosu;
288 | final double cos2u = 2.0 * cosu * cosu - 1;
289 | temp[0] = AbstractSatellite.invert(pl);
290 | temp[1] = CK2 * temp[0];
291 | temp[2] = temp[1] * temp[0];
292 |
293 | /* Update for short periodics */
294 | final double rk = r * (1.0 - 1.5 * temp[2] * betal * x3thm1) + 0.5
295 | * temp[1] * x1mth2 * cos2u;
296 | final double uk = u - 0.25 * temp[2] * x7thm1 * sin2u;
297 | final double xnodek = xnode + 1.5 * temp[2] * cosio * sin2u;
298 | final double xinck = getTLE().getXincl() + 1.5 * temp[2] * cosio
299 | * sinio * cos2u;
300 | final double rdotk = rdot - xn * temp[1] * x1mth2 * sin2u;
301 | final double rfdotk = rfdot + xn * temp[1]
302 | * (x1mth2 * cos2u + 1.5 * x3thm1);
303 |
304 | super.calculatePositionAndVelocity(rk, uk, xnodek, xinck, rdotk, rfdotk);
305 | }
306 |
307 | }
308 |
--------------------------------------------------------------------------------
/src/main/java/com/github/amsacode/predict4java/PassPredictor.java:
--------------------------------------------------------------------------------
1 | /**
2 | predict4java: An SDP4 / SGP4 library for satellite orbit predictions
3 |
4 | Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
5 |
6 | This class is a Java port of one of the core elements of
7 | the Predict program, Copyright John A. Magliacane,
8 | KD2BD 1991-2003: http://www.qsl.net/kd2bd/predict.html
9 |
10 | Dr. T.S. Kelso is the author of the SGP4/SDP4 orbital models,
11 | originally written in Fortran and Pascal, and released into the
12 | public domain through his website (http://www.celestrak.com/).
13 | Neoklis Kyriazis, 5B4AZ, later re-wrote Dr. Kelso's code in C,
14 | and released it under the GNU GPL in 2002.
15 | PREDICT's core is based on 5B4AZ's code translation efforts.
16 |
17 | Author: David A. B. Johnson, G4DPZ
18 |
19 | Comments, questions and bugreports should be submitted via
20 | http://sourceforge.net/projects/websat/
21 | More details can be found at the project home page:
22 |
23 | http://websat.sourceforge.net
24 |
25 | This program is free software; you can redistribute it and/or modify
26 | it under the terms of the GNU General Public License as published by
27 | the Free Software Foundation; either version 2 of the License, or
28 | (at your option) any later version.
29 |
30 | This program is distributed in the hope that it will be useful,
31 | but WITHOUT ANY WARRANTY; without even the implied warranty of
32 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 | GNU General Public License for more details.
34 |
35 | You should have received a copy of the GNU General Public License
36 | along with this program; if not, visit http://www.fsf.org/
37 | */
38 | package com.github.amsacode.predict4java;
39 |
40 | import java.util.ArrayList;
41 | import java.util.Calendar;
42 | import java.util.Date;
43 | import java.util.List;
44 | import java.util.TimeZone;
45 |
46 | import org.apache.commons.logging.Log;
47 | import org.apache.commons.logging.LogFactory;
48 |
49 | /**
50 | * Class which provides Pass Prediction.
51 | *
52 | * @author David A. B. Johnson, g4dpz
53 | *
54 | */
55 | public class PassPredictor {
56 |
57 | private static final String UTC = "UTC";
58 | private static final String SOUTH = "south";
59 | private static final String NORTH = "north";
60 | private static final double SPEED_OF_LIGHT = 2.99792458E8;
61 | private static final double TWOPI = Math.PI * 2.0;
62 |
63 | private static final String DEADSPOT_NONE = "none";
64 |
65 | /** The time at which we do all the calculations. */
66 | static final TimeZone TZ = TimeZone.getTimeZone(UTC);
67 |
68 | private static Log log = LogFactory.getLog(PassPredictor.class);
69 |
70 | private final TLE tle;
71 | private final GroundStationPosition qth;
72 | private final Satellite sat;
73 |
74 | private int iterationCount;
75 |
76 | /**
77 | * Constructor.
78 | *
79 | * @param tle
80 | * the Three Line Elements
81 | * @param qth
82 | * the ground station position
83 | * @throws IllegalArgumentException
84 | * bad argument passed in
85 | * @throws SatNotFoundException
86 | */
87 | public PassPredictor(final TLE theTLE, final GroundStationPosition theQTH)
88 | throws IllegalArgumentException, SatNotFoundException {
89 |
90 | if (null == theTLE) {
91 | throw new IllegalArgumentException("TLE has not been set");
92 | }
93 |
94 | if (null == theQTH) {
95 | throw new IllegalArgumentException("QTH has not been set");
96 | }
97 |
98 | this.tle = theTLE;
99 | this.qth = theQTH;
100 |
101 | sat = SatelliteFactory.createSatellite(tle);
102 |
103 | if (null == sat) {
104 | throw new SatNotFoundException("Satellite has not been created");
105 | } else if (!sat.willBeSeen(qth)) {
106 | throw new SatNotFoundException(
107 | "Satellite will never appear above the horizon");
108 | }
109 |
110 | }
111 |
112 | /**
113 | * Gets the downlink frequency corrected for doppler.
114 | *
115 | * @param freq
116 | * the original frequency in Hz
117 | * @return the doppler corrected frequency in Hz
118 | * @throws InvalidTleException
119 | * bad TLE passed in
120 | * @throws SatNotFoundException
121 | */
122 | public Long getDownlinkFreq(final Long freq, final Date date)
123 | throws SatNotFoundException {
124 | // get the current position
125 | final Calendar cal = Calendar.getInstance(TZ);
126 | cal.clear();
127 | cal.setTimeInMillis(date.getTime());
128 | final SatPos satPos = getSatPos(cal.getTime());
129 | final double rangeRate = satPos.getRangeRate();
130 | return (long) ((double) freq * (SPEED_OF_LIGHT - rangeRate * 1000.0) / SPEED_OF_LIGHT);
131 | }
132 |
133 | public SatPos getSatPos(final Date time) throws SatNotFoundException {
134 | this.iterationCount++;
135 | return sat.getPosition(qth, time);
136 | }
137 |
138 | public Long getUplinkFreq(final Long freq, final Date date)
139 | throws SatNotFoundException {
140 | final Calendar cal = Calendar.getInstance(TZ);
141 | cal.clear();
142 | cal.setTimeInMillis(date.getTime());
143 | final SatPos satPos = getSatPos(cal.getTime());
144 | final double rangeRate = satPos.getRangeRate();
145 | return (long) ((double) freq * (SPEED_OF_LIGHT + rangeRate * 1000.0) / SPEED_OF_LIGHT);
146 | }
147 |
148 | public SatPassTime nextSatPass(final Date date) throws SatNotFoundException {
149 | return nextSatPass(date, false);
150 | }
151 |
152 | public SatPassTime nextSatPass(final Date date, final boolean windBack)
153 | throws SatNotFoundException {
154 |
155 | int aosAzimuth = 0;
156 | int losAzimuth = 0;
157 | double maxElevation = 0;
158 | double elevation = 0;
159 |
160 | String polePassed = DEADSPOT_NONE;
161 |
162 | // get the current position
163 | final Calendar cal = Calendar.getInstance(TZ);
164 | cal.clear();
165 | cal.setTimeInMillis(date.getTime());
166 |
167 | // wind back time 1/4 of an orbit
168 | if (windBack) {
169 | double meanMotion = tle.getMeanmo();
170 | cal.add(Calendar.MINUTE, (int) (-24.0 * 60.0 / meanMotion / 4.0));
171 | }
172 |
173 | SatPos satPos = getSatPos(cal.getTime());
174 | SatPos prevPos = satPos;
175 |
176 | // test for the elevation being above the horizon
177 | if (satPos.getElevation() > 0.0) {
178 |
179 | // move time forward in 30 second intervals until the sat goes below
180 | // the horizon
181 | do {
182 | satPos = getPosition(cal, 60);
183 | } while (satPos.getElevation() > 0.0);
184 |
185 | // move time forward 3/4 orbit
186 | cal.add(Calendar.MINUTE, threeQuarterOrbitMinutes());
187 | }
188 |
189 | Date tca = null;
190 |
191 | // now find the next time it comes above the horizon
192 | do {
193 | satPos = getPosition(cal, 60);
194 | final Date now = cal.getTime();
195 | elevation = satPos.getElevation();
196 | if (elevation > maxElevation) {
197 | maxElevation = elevation;
198 | tca = now;
199 | }
200 | } while (satPos.getElevation() < 0.0);
201 |
202 | // refine it to 5 seconds
203 | cal.add(Calendar.SECOND, -60);
204 | do {
205 | satPos = getPosition(cal, 5);
206 | final Date now = cal.getTime();
207 | elevation = satPos.getElevation();
208 | if (elevation > maxElevation) {
209 | maxElevation = elevation;
210 | tca = now;
211 | }
212 | prevPos = satPos;
213 | } while (satPos.getElevation() < 0.0);
214 |
215 | final Date startDate = satPos.getTime();
216 |
217 | aosAzimuth = (int) ((satPos.getAzimuth() / (2.0 * Math.PI)) * 360.0);
218 |
219 | // now find when it goes below
220 | do {
221 | satPos = getPosition(cal, 30);
222 | final Date now = cal.getTime();
223 | final String currPolePassed = getPolePassed(prevPos, satPos);
224 | if (!currPolePassed.equals(DEADSPOT_NONE)) {
225 | polePassed = currPolePassed;
226 | }
227 | log.debug("Current pole passed: " + polePassed);
228 | elevation = satPos.getElevation();
229 | if (elevation > maxElevation) {
230 | maxElevation = elevation;
231 | tca = now;
232 | }
233 | prevPos = satPos;
234 | } while (satPos.getElevation() > 0.0);
235 |
236 | // refine it to 5 seconds
237 | cal.add(Calendar.SECOND, -30);
238 | do {
239 | satPos = getPosition(cal, 5);
240 | final Date now = cal.getTime();
241 | elevation = satPos.getElevation();
242 | if (elevation > maxElevation) {
243 | maxElevation = elevation;
244 | tca = now;
245 | }
246 | } while (satPos.getElevation() > 0.0);
247 |
248 | final Date endDate = satPos.getTime();
249 | losAzimuth = (int) ((satPos.getAzimuth() / (2.0 * Math.PI)) * 360.0);
250 |
251 | return new SatPassTime(startDate, endDate, tca, polePassed, aosAzimuth,
252 | losAzimuth, (maxElevation / (2.0 * Math.PI)) * 360.0);
253 |
254 | }
255 |
256 | /**
257 | * @param cal
258 | * @param offSet
259 | * @return
260 | * @throws InvalidTleException
261 | * @throws SatNotFoundException
262 | */
263 | private SatPos getPosition(final Calendar cal, final int offSet)
264 | throws SatNotFoundException {
265 | SatPos satPos;
266 | cal.add(Calendar.SECOND, offSet);
267 | satPos = getSatPos(cal.getTime());
268 | return satPos;
269 | }
270 |
271 | /**
272 | * Gets a list of SatPassTime
273 | *
274 | * @param start
275 | * Date
276 | *
277 | * newTLE = true; validateData();
278 | * @param end
279 | * Date
280 | * @param firstAosLimit
281 | * in hours
282 | * @return List
283 | * @throws SatNotFoundException
284 | * @throws InvalidTleException
285 | */
286 | public List getPasses(final Date start, final int hoursAhead,
287 | final boolean windBack) throws SatNotFoundException {
288 |
289 | this.iterationCount = 0;
290 |
291 | boolean windBackTime = windBack;
292 |
293 | final List passes = new ArrayList();
294 |
295 | Date trackStartDate = start;
296 | final Date trackEndDate = new Date(start.getTime()
297 | + (hoursAhead * 60L * 60L * 1000L));
298 |
299 | Date lastAOS;
300 |
301 | int count = 0;
302 |
303 | do {
304 | if (count > 0) {
305 | windBackTime = false;
306 | }
307 | final SatPassTime pass = nextSatPass(trackStartDate, windBackTime);
308 | lastAOS = pass.getStartTime();
309 | passes.add(pass);
310 | trackStartDate = new Date(pass.getEndTime().getTime()
311 | + (threeQuarterOrbitMinutes() * 60L * 1000L));
312 | count++;
313 | } while (lastAOS.compareTo(trackEndDate) < 0);
314 |
315 | return passes;
316 | }
317 |
318 | /**
319 | * Returns the iterationCount. @VisibleForTesting
320 | *
321 | * @return the iterationCount
322 | */
323 | final int getIterationCount() {
324 | return iterationCount;
325 | }
326 |
327 | /**
328 | * @return time in mS for 3/4 of an orbit
329 | */
330 | private int threeQuarterOrbitMinutes() {
331 | return (int) (24.0 * 60.0 / tle.getMeanmo() * 0.75);
332 | }
333 |
334 | private String getPolePassed(final SatPos prevPos, final SatPos satPos) {
335 | String polePassed = DEADSPOT_NONE;
336 |
337 | final double az1 = prevPos.getAzimuth() / TWOPI * 360.0;
338 | final double az2 = satPos.getAzimuth() / TWOPI * 360.0;
339 |
340 | if (az1 > az2) {
341 | // we may be moving from 350 or greateer thru north
342 | if (az1 > 350 && az2 < 10) {
343 | polePassed = NORTH;
344 | } else {
345 | // we may be moving from 190 or greateer thru south
346 | if (az1 > 180 && az2 < 180) {
347 | polePassed = SOUTH;
348 | }
349 | }
350 | } else {
351 | // we may be moving from 10 or less through north
352 | if (az1 < 10 && az2 > 350) {
353 | polePassed = NORTH;
354 | } else {
355 | // we may be moving from 170 or more through south
356 | if (az1 < 180 && az2 > 180) {
357 | polePassed = SOUTH;
358 | }
359 | }
360 | }
361 |
362 | return polePassed;
363 | }
364 |
365 | /**
366 | * Calculates positions of satellite for a given point in time, time range
367 | * and step increment.
368 | *
369 | * @param referenceDate
370 | * @param incrementSeconds
371 | * @param minutesBefore
372 | * @param minutesAfter
373 | * @return list of SatPos
374 | * @throws SatNotFoundException
375 | * @throws InvalidTleException
376 | */
377 | public List getPositions(final Date referenceDate,
378 | final int incrementSeconds, final int minutesBefore,
379 | final int minutesAfter) throws SatNotFoundException {
380 |
381 | Date trackDate = new Date(referenceDate.getTime()
382 | - (minutesBefore * 60L * 1000L));
383 | final Date endDateDate = new Date(referenceDate.getTime()
384 | + (minutesAfter * 60L * 1000L));
385 |
386 | final List positions = new ArrayList();
387 |
388 | while (trackDate.before(endDateDate)) {
389 |
390 | positions.add(getSatPos(trackDate));
391 |
392 | trackDate = new Date(trackDate.getTime()
393 | + (incrementSeconds * 1000));
394 | }
395 |
396 | return positions;
397 | }
398 | }
399 |
--------------------------------------------------------------------------------
/src/main/java/com/github/amsacode/predict4java/Position.java:
--------------------------------------------------------------------------------
1 | package com.github.amsacode.predict4java;
2 |
3 | /**
4 | * Immutable class created to avoid returning ugly 2d arrays of lat long points
5 | * from api methods.
6 | *
7 | * @author Dave Moten
8 | *
9 | */
10 | public class Position {
11 |
12 | private final double lat;
13 | private final double lon;
14 |
15 | public Position(double lat, double lon) {
16 | super();
17 | this.lat = lat;
18 | this.lon = lon;
19 | }
20 |
21 | public double getLat() {
22 | return lat;
23 | }
24 |
25 | public double getLon() {
26 | return lon;
27 | }
28 |
29 | @Override
30 | public String toString() {
31 | return "Position [lat=" + lat + ", lon=" + lon + "]";
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/github/amsacode/predict4java/SatNotFoundException.java:
--------------------------------------------------------------------------------
1 | /**
2 | predict4java: An SDP4 / SGP4 library for satellite orbit predictions
3 |
4 | Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
5 |
6 | This class is a Java port of one of the core elements of
7 | the Predict program, Copyright John A. Magliacane,
8 | KD2BD 1991-2003: http://www.qsl.net/kd2bd/predict.html
9 |
10 | Dr. T.S. Kelso is the author of the SGP4/SDP4 orbital models,
11 | originally written in Fortran and Pascal, and released into the
12 | public domain through his website (http://www.celestrak.com/).
13 | Neoklis Kyriazis, 5B4AZ, later re-wrote Dr. Kelso's code in C,
14 | and released it under the GNU GPL in 2002.
15 | PREDICT's core is based on 5B4AZ's code translation efforts.
16 |
17 | Author: David A. B. Johnson, G4DPZ
18 |
19 | Comments, questions and bugreports should be submitted via
20 | http://sourceforge.net/projects/websat/
21 | More details can be found at the project home page:
22 |
23 | http://websat.sourceforge.net
24 |
25 | This program is free software; you can redistribute it and/or modify
26 | it under the terms of the GNU General Public License as published by
27 | the Free Software Foundation; either version 2 of the License, or
28 | (at your option) any later version.
29 |
30 | This program is distributed in the hope that it will be useful,
31 | but WITHOUT ANY WARRANTY; without even the implied warranty of
32 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 | GNU General Public License for more details.
34 |
35 | You should have received a copy of the GNU General Public License
36 | along with this program; if not, visit http://www.fsf.org/
37 | */
38 | package com.github.amsacode.predict4java;
39 |
40 | /**
41 | * @author David A. B. Johnson, g4dpz
42 | */
43 | public class SatNotFoundException extends Exception {
44 |
45 | private static final long serialVersionUID = 3389434245667560642L;
46 |
47 | /**
48 | * @param message
49 | */
50 | public SatNotFoundException(final String message) {
51 | super(message);
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/github/amsacode/predict4java/SatPassTime.java:
--------------------------------------------------------------------------------
1 | /**
2 | predict4java: An SDP4 / SGP4 library for satellite orbit predictions
3 |
4 | Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
5 |
6 | This class is a Java port of one of the core elements of
7 | the Predict program, Copyright John A. Magliacane,
8 | KD2BD 1991-2003: http://www.qsl.net/kd2bd/predict.html
9 |
10 | Dr. T.S. Kelso is the author of the SGP4/SDP4 orbital models,
11 | originally written in Fortran and Pascal, and released into the
12 | public domain through his website (http://www.celestrak.com/).
13 | Neoklis Kyriazis, 5B4AZ, later re-wrote Dr. Kelso's code in C,
14 | and released it under the GNU GPL in 2002.
15 | PREDICT's core is based on 5B4AZ's code translation efforts.
16 |
17 | Author: David A. B. Johnson, G4DPZ
18 |
19 | Comments, questions and bugreports should be submitted via
20 | http://sourceforge.net/projects/websat/
21 | More details can be found at the project home page:
22 |
23 | http://websat.sourceforge.net
24 |
25 | This program is free software; you can redistribute it and/or modify
26 | it under the terms of the GNU General Public License as published by
27 | the Free Software Foundation; either version 2 of the License, or
28 | (at your option) any later version.
29 |
30 | This program is distributed in the hope that it will be useful,
31 | but WITHOUT ANY WARRANTY; without even the implied warranty of
32 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 | GNU General Public License for more details.
34 |
35 | You should have received a copy of the GNU General Public License
36 | along with this program; if not, visit http://www.fsf.org/
37 | */
38 | package com.github.amsacode.predict4java;
39 |
40 | import java.text.SimpleDateFormat;
41 | import java.util.Date;
42 | import java.util.TimeZone;
43 |
44 | public class SatPassTime {
45 |
46 | private final Date startTime;
47 | private final Date endTime;
48 | private final Date tca;
49 | private final String polePassed;
50 | private final int aos;
51 | private final int los;
52 | private final double maxEl;
53 |
54 | private static final String NEW_LINE = "\n";
55 | private static final String DEG_NL = " deg.\n";
56 |
57 | private static final SimpleDateFormat TIME_FORMAT;
58 | private static final SimpleDateFormat DATE_FORMAT;
59 | static {
60 | TIME_FORMAT = new SimpleDateFormat("h:mm a");
61 | TIME_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
62 | DATE_FORMAT = new SimpleDateFormat("MMMMMM d, yyyy");
63 | DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
64 | }
65 |
66 | public SatPassTime(final Date startTime, final Date endTime,
67 | final String polePassed, final int aos, final int los,
68 | final double maxEl) {
69 | this(startTime, endTime, new Date(
70 | (startTime.getTime() + endTime.getTime()) / 2), polePassed,
71 | aos, los, maxEl);
72 | }
73 |
74 | public SatPassTime(final Date startTime, final Date endTime,
75 | final Date tca, final String polePassed, final int aosAzimuth,
76 | final int losAzimuth, final double maxEl) {
77 | this.startTime = new Date(startTime.getTime());
78 | this.endTime = new Date(endTime.getTime());
79 | this.polePassed = polePassed;
80 | this.aos = aosAzimuth;
81 | this.los = losAzimuth;
82 | this.maxEl = maxEl;
83 | this.tca = new Date(tca.getTime());
84 | }
85 |
86 | public final Date getStartTime() {
87 | return new Date(startTime.getTime());
88 | }
89 |
90 | public final Date getEndTime() {
91 | return new Date(endTime.getTime());
92 | }
93 |
94 | public final Date getTCA() {
95 | return new Date(tca.getTime());
96 | }
97 |
98 | public final String getPolePassed() {
99 | return polePassed;
100 | }
101 |
102 | /**
103 | * @return the aos azimuth
104 | */
105 | public final int getAosAzimuth() {
106 | return aos;
107 | }
108 |
109 | /**
110 | * @return the los azimuth
111 | */
112 | public final int getLosAzimuth() {
113 | return los;
114 | }
115 |
116 | /**
117 | * @return the maxEl
118 | */
119 | public final double getMaxEl() {
120 | return maxEl;
121 | }
122 |
123 | private synchronized static String formatDate(Date date) {
124 | return DATE_FORMAT.format(date);
125 | }
126 |
127 | private synchronized static String formatTime(Date date) {
128 | return TIME_FORMAT.format(date);
129 | }
130 |
131 | /**
132 | * Returns a string representing the contents of the object.
133 | */
134 | @Override
135 | public String toString() {
136 |
137 | final double duration = (endTime.getTime() - startTime.getTime()) / 60000.0;
138 |
139 | return "Date: " + formatDate(startTime) + NEW_LINE
140 | + "Start Time: "
141 | + formatTime(startTime)
142 | + NEW_LINE
143 | +
144 | // "End Time: " + mTimeFormatter.format(endDate_time) + "\n" +
145 | String.format("Duration: %4.1f min.%n", duration)
146 | + "AOS Azimuth: " + aos + DEG_NL
147 | + String.format("Max Elevation: %4.1f deg.%n", maxEl)
148 | + "LOS Azimuth: " + los + " deg.";
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/src/main/java/com/github/amsacode/predict4java/SatPos.java:
--------------------------------------------------------------------------------
1 | /**
2 | predict4java: An SDP4 / SGP4 library for satellite orbit predictions
3 |
4 | Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
5 |
6 | This class is a Java port of one of the core elements of
7 | the Predict program, Copyright John A. Magliacane,
8 | KD2BD 1991-2003: http://www.qsl.net/kd2bd/predict.html
9 |
10 | Dr. T.S. Kelso is the author of the SGP4/SDP4 orbital models,
11 | originally written in Fortran and Pascal, and released into the
12 | public domain through his website (http://www.celestrak.com/).
13 | Neoklis Kyriazis, 5B4AZ, later re-wrote Dr. Kelso's code in C,
14 | and released it under the GNU GPL in 2002.
15 | PREDICT's core is based on 5B4AZ's code translation efforts.
16 |
17 | Author: David A. B. Johnson, G4DPZ
18 |
19 | Comments, questions and bugreports should be submitted via
20 | http://sourceforge.net/projects/websat/
21 | More details can be found at the project home page:
22 |
23 | http://websat.sourceforge.net
24 |
25 | This program is free software; you can redistribute it and/or modify
26 | it under the terms of the GNU General Public License as published by
27 | the Free Software Foundation; either version 2 of the License, or
28 | (at your option) any later version.
29 |
30 | This program is distributed in the hope that it will be useful,
31 | but WITHOUT ANY WARRANTY; without even the implied warranty of
32 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 | GNU General Public License for more details.
34 |
35 | You should have received a copy of the GNU General Public License
36 | along with this program; if not, visit http://www.fsf.org/
37 | */
38 | package com.github.amsacode.predict4java;
39 |
40 | import java.text.NumberFormat;
41 | import java.util.ArrayList;
42 | import java.util.Date;
43 | import java.util.List;
44 |
45 | /**
46 | *
47 | * @author g4dpz
48 | *
49 | */
50 | public class SatPos {
51 | private static final String NL = "\n";
52 | private static final String DEG_CR = " deg.\n";
53 |
54 | /* WGS 84 Earth radius km */
55 | private static final double EARTH_RADIUS_KM = 6.378137E3;
56 | private static final double R0 = 6378.16;
57 |
58 | // the internal representation will be in radians
59 | private double azimuth;
60 | private double elevation;
61 | private double latitude;
62 | private double longitude;
63 |
64 | private Date time;
65 | private double range;
66 | private double rangeRate;
67 | private double phase;
68 | private double altitude;
69 | private double theta;
70 |
71 | private double eclipseDepth;
72 | private boolean eclipsed;
73 |
74 | private boolean aboveHorizon;
75 |
76 | /**
77 | * Default constructor.
78 | */
79 | public SatPos() {
80 |
81 | }
82 |
83 | /**
84 | * Constructs a Satellite Position.
85 | *
86 | * @param azimuth
87 | * the Azimuth
88 | * @param elevation
89 | * the Elevation
90 | * @param theTime
91 | * the Time
92 | */
93 | public SatPos(final double azimuth, final double elevation,
94 | final Date theTime) {
95 | this.azimuth = azimuth;
96 | this.elevation = elevation;
97 | this.time = new Date(theTime.getTime());
98 | }
99 |
100 | /**
101 | * @return the azimuth
102 | */
103 | public double getAzimuth() {
104 | return azimuth;
105 | }
106 |
107 | /**
108 | * @return the elevation
109 | */
110 | public double getElevation() {
111 | return elevation;
112 | }
113 |
114 | /**
115 | * @return time for the SatPos
116 | */
117 | public Date getTime() {
118 | return new Date(time.getTime());
119 | }
120 |
121 | /**
122 | * @return the range
123 | */
124 | public final double getRange() {
125 | return range;
126 | }
127 |
128 | /**
129 | * @param range
130 | * the range to set
131 | */
132 | public final void setRange(final double range) {
133 | this.range = range;
134 | }
135 |
136 | /**
137 | * @return the rangeRate
138 | */
139 | public final double getRangeRate() {
140 | return rangeRate;
141 | }
142 |
143 | /**
144 | * @param rangeRate
145 | * the rangeRate to set
146 | */
147 | public final void setRangeRate(final double rangeRate) {
148 | this.rangeRate = rangeRate;
149 | }
150 |
151 | /**
152 | * @return the phase
153 | */
154 | public final double getPhase() {
155 | return phase;
156 | }
157 |
158 | /**
159 | * @param phase
160 | * the phase to set
161 | */
162 | public final void setPhase(final double phase) {
163 | this.phase = phase;
164 | }
165 |
166 | /**
167 | * @return the latitude
168 | */
169 | public final double getLatitude() {
170 | return latitude;
171 | }
172 |
173 | /**
174 | * @param latitude
175 | * the latitude to set
176 | */
177 | public final void setLatitude(final double latitude) {
178 | this.latitude = latitude;
179 | }
180 |
181 | /**
182 | * @return the longitude
183 | */
184 | public final double getLongitude() {
185 | return longitude;
186 | }
187 |
188 | /**
189 | * @param longitude
190 | * the longitude to set
191 | */
192 | public final void setLongitude(final double longitude) {
193 | this.longitude = longitude;
194 | }
195 |
196 | /**
197 | * @return the altitude in km
198 | */
199 | public final double getAltitude() {
200 | return altitude;
201 | }
202 |
203 | /**
204 | * @param altitude
205 | * the altitude to set
206 | */
207 | public final void setAltitude(final double altitude) {
208 | this.altitude = altitude;
209 | }
210 |
211 | /**
212 | * @return the theta
213 | */
214 | public final double getTheta() {
215 | return theta;
216 | }
217 |
218 | /**
219 | * @param theta
220 | * the theta to set
221 | */
222 | public final void setTheta(final double theta) {
223 | this.theta = theta;
224 | }
225 |
226 | /**
227 | * @param azimuth
228 | * the azimuth to set
229 | */
230 | public final void setAzimuth(final double azimuth) {
231 | this.azimuth = azimuth;
232 | }
233 |
234 | /**
235 | * @param elevation
236 | * the elevation to set
237 | */
238 | public final void setElevation(final double elevation) {
239 | this.elevation = elevation;
240 | }
241 |
242 | /**
243 | * @param time
244 | * the time to set
245 | */
246 | public final void setTime(final Date time) {
247 | this.time = new Date(time.getTime());
248 | }
249 |
250 | /**
251 | * @return the aboveHorizon
252 | */
253 | public final boolean isAboveHorizon() {
254 | return aboveHorizon;
255 | }
256 |
257 | /**
258 | * @param aboveHorizon
259 | * the aboveHorizon to set
260 | */
261 | public final void setAboveHorizon(final boolean aboveHorizon) {
262 | this.aboveHorizon = aboveHorizon;
263 | }
264 |
265 | /**
266 | * @return the eclipseDepth
267 | */
268 | protected final double getEclipseDepth() {
269 | return eclipseDepth;
270 | }
271 |
272 | /**
273 | * @param eclipseDepth
274 | * the eclipseDepth to set
275 | */
276 | protected final void setEclipseDepth(final double eclipseDepth) {
277 | this.eclipseDepth = eclipseDepth;
278 | }
279 |
280 | /**
281 | * @return the eclipsed
282 | */
283 | protected final boolean isEclipsed() {
284 | return eclipsed;
285 | }
286 |
287 | /**
288 | * @param eclipsed
289 | * the eclipsed to set
290 | */
291 | protected final void setEclipsed(final boolean eclipsed) {
292 | this.eclipsed = eclipsed;
293 | }
294 |
295 | /**
296 | * @return a pretty printed version of the Satellite Position
297 | */
298 | @Override
299 | public String toString() {
300 | return "Azimuth: " + azimuth / (Math.PI * 2.0) * 360 + DEG_CR
301 | + "Elevation: " + elevation / (Math.PI * 2.0) * 360 + DEG_CR
302 | + "Latitude: " + latitude / (Math.PI * 2.0) * 360 + DEG_CR
303 | + "Longitude: " + longitude / (Math.PI * 2.0) * 360 + DEG_CR
304 |
305 | + "Date: " + time + NL + "Range: " + range
306 | + " km.\n" + "Range rate: " + rangeRate + " m/S.\n"
307 | + "Phase: " + phase + " /(256)\n" + "Altitude: "
308 | + altitude + " km\n" + "Theta: " + theta + " rad/sec\n"
309 | + "Eclipsed: " + eclipsed + NL + "Eclipse depth:"
310 | + eclipseDepth + " radians\n";
311 | }
312 |
313 | public String toShortString() {
314 | String returnString = "";
315 |
316 | final NumberFormat numberFormat = NumberFormat.getNumberInstance();
317 |
318 | numberFormat.setMaximumFractionDigits(0);
319 | returnString = returnString + "Elevation: "
320 | + numberFormat.format(elevation / (Math.PI * 2.0) * 360)
321 | + DEG_CR + "Azimuth: "
322 | + numberFormat.format(azimuth / (Math.PI * 2.0) * 360) + DEG_CR;
323 |
324 | numberFormat.setMaximumFractionDigits(2);
325 | returnString = returnString + "Latitude: "
326 | + numberFormat.format(latitude / (Math.PI * 2.0) * 360)
327 | + DEG_CR + "Longitude: "
328 | + numberFormat.format(longitude / (Math.PI * 2.0) * 360)
329 | + DEG_CR;
330 |
331 | numberFormat.setMaximumFractionDigits(0);
332 | returnString = returnString + "Range: " + numberFormat.format(range)
333 | + " Km";
334 |
335 | return returnString;
336 |
337 | }
338 |
339 | /**
340 | * Calculates the footprint range circle using the given increment. TODO
341 | * where is first point, give heading.
342 | *
343 | * @param incrementDegrees
344 | * @return
345 | */
346 | public final List getRangeCircle(double incrementDegrees) {
347 |
348 | return calculateRangeCirclePoints(this, incrementDegrees);
349 |
350 | }
351 |
352 | /**
353 | * Calculates the footprint range circle using an increment of 1.0 degrees.
354 | *
355 | * @param pos
356 | * @return a list of {@link Position}
357 | */
358 | public final List getRangeCircle() {
359 | return getRangeCircle(1.0);
360 | }
361 |
362 | /**
363 | * Calculates the footprint range circle using the given increment.
364 | *
365 | * @param pos
366 | * @return a list of {@link Position}
367 | */
368 | private static List calculateRangeCirclePoints(final SatPos pos,
369 | double incrementDegrees) {
370 |
371 | final double radiusKm = pos.getRangeCircleRadiusKm();
372 |
373 | final double latitude = pos.latitude;
374 | final double longitude = pos.longitude;
375 | final double beta = radiusKm / R0;
376 | List result = new ArrayList();
377 | for (int azi = 0; azi < 360; azi += incrementDegrees) {
378 | final double azimuth = (azi / 360.0) * 2.0 * Math.PI;
379 | double rangelat = Math.asin(Math.sin(latitude) * Math.cos(beta)
380 | + Math.cos(azimuth) * Math.sin(beta) * Math.cos(latitude));
381 | final double num = Math.cos(beta)
382 | - (Math.sin(latitude) * Math.sin(rangelat));
383 | final double den = Math.cos(latitude) * Math.cos(rangelat);
384 | double rangelong;
385 |
386 | if (azi == 0 && (beta > ((Math.PI / 2.0) - latitude))) {
387 | rangelong = longitude + Math.PI;
388 | } else if (azi == 180 && (beta > ((Math.PI / 2.0) - latitude))) {
389 | rangelong = longitude + Math.PI;
390 | } else if (Math.abs(num / den) > 1.0) {
391 | rangelong = longitude;
392 | } else {
393 | if ((180 - azi) >= 0) {
394 | rangelong = longitude - Math.acos(num / den);
395 | } else {
396 | rangelong = longitude + Math.acos(num / den);
397 | }
398 | }
399 |
400 | while (rangelong < 0.0) {
401 | rangelong += Math.PI * 2.0;
402 | }
403 |
404 | while (rangelong > Math.PI * 2.0) {
405 | rangelong -= Math.PI * 2.0;
406 | }
407 |
408 | rangelat = (rangelat / (2.0 * Math.PI)) * 360.0;
409 | rangelong = (rangelong / (2.0 * Math.PI)) * 360.0;
410 |
411 | // if (rangelong < 180.0) {
412 | // rangelong = -rangelong;
413 | // }
414 | // else if (rangelong > 180.0) {
415 | // rangelong = 360.0 - rangelong;
416 | // }
417 | //
418 | // if (rangelat < 90.0) {
419 | // rangelat = -rangelat;
420 | // }
421 | // else if (rangelat > 90.0) {
422 | // rangelat = 180.0 - rangelat;
423 | // }
424 |
425 | result.add(new Position(rangelat, rangelong));
426 |
427 | }
428 |
429 | return result;
430 | }
431 |
432 | public double getRangeCircleRadiusKm() {
433 | return 0.5 * (12756.33 * Math.acos(EARTH_RADIUS_KM
434 | / (EARTH_RADIUS_KM + altitude)));
435 | }
436 |
437 | }
438 |
--------------------------------------------------------------------------------
/src/main/java/com/github/amsacode/predict4java/Satellite.java:
--------------------------------------------------------------------------------
1 | /**
2 | predict4java: An SDP4 / SGP4 library for satellite orbit predictions
3 |
4 | Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
5 |
6 | This class is a Java port of one of the core elements of
7 | the Predict program, Copyright John A. Magliacane,
8 | KD2BD 1991-2003: http://www.qsl.net/kd2bd/predict.html
9 |
10 | Dr. T.S. Kelso is the author of the SGP4/SDP4 orbital models,
11 | originally written in Fortran and Pascal, and released into the
12 | public domain through his website (http://www.celestrak.com/).
13 | Neoklis Kyriazis, 5B4AZ, later re-wrote Dr. Kelso's code in C,
14 | and released it under the GNU GPL in 2002.
15 | PREDICT's core is based on 5B4AZ's code translation efforts.
16 |
17 | Author: David A. B. Johnson, G4DPZ
18 |
19 | Comments, questions and bugreports should be submitted via
20 | http://sourceforge.net/projects/websat/
21 | More details can be found at the project home page:
22 |
23 | http://websat.sourceforge.net
24 |
25 | This program is free software; you can redistribute it and/or modify
26 | it under the terms of the GNU General Public License as published by
27 | the Free Software Foundation; either version 2 of the License, or
28 | (at your option) any later version.
29 |
30 | This program is distributed in the hope that it will be useful,
31 | but WITHOUT ANY WARRANTY; without even the implied warranty of
32 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 | GNU General Public License for more details.
34 |
35 | You should have received a copy of the GNU General Public License
36 | along with this program; if not, visit http://www.fsf.org/
37 | */
38 | package com.github.amsacode.predict4java;
39 |
40 | import java.util.Date;
41 |
42 | public interface Satellite {
43 |
44 | double DEG2RAD = 1.745329251994330E-2;
45 | double TWO_PI = Math.PI * 2.0;
46 | double EPSILON = 1.0E-12;
47 | double TWO_THIRDS = 2.0 / 3.0;
48 | double EARTH_RADIUS_KM = 6.378137E3;
49 | double XKE = 7.43669161E-2;
50 | double CK2 = 5.413079E-4;
51 | /** J2 Harmonic (WGS '72). */
52 | double J2_HARMONIC = 1.0826158E-3;
53 | /** J3 Harmonic (WGS '72). */
54 | double J3_HARMONIC = -2.53881E-6;
55 | /** J4 Harmonic (WGS '72). */
56 | double J4_HARMONIC = -1.65597E-6;
57 |
58 | /**
59 | * This function returns true if the satellite can ever rise above the
60 | * horizon of the ground station.
61 | *
62 | * @param qth
63 | * the ground station position
64 | * @return boolean whether or not the satellite will be seen
65 | */
66 | boolean willBeSeen(GroundStationPosition qth);
67 |
68 | /**
69 | * Calculates the position and velocity vectors of the satellite. When
70 | * observations for many ground stations have to be made for one satellite,
71 | * this method can be used together with the
72 | * calculateSatPosForGroundStation(..) method. This gives a performance
73 | * improvement relative to using the all-in-one method getPosition(..).
74 | *
75 | * @param date
76 | * The date for the calculation the position and velocity vectors
77 | * of the satellite.
78 | */
79 | void calculateSatelliteVectors(Date time);
80 |
81 | /**
82 | * Calculates the ground track (sub satellite point) of the satellite, for
83 | * the already determined position of the satellite.
84 | *
85 | * @return satPos The SatPos object in which the ground track of the
86 | * satellite is stored.
87 | */
88 | SatPos calculateSatelliteGroundTrack();
89 |
90 | /**
91 | * Calculates the position of the satellite from the perspective of a ground
92 | * station. The position and velocity of the satellite must have been
93 | * determined before (by calculateSatelliteVectors(..)). The ground track
94 | * (sub satellite point) is not calculated, this should be done by
95 | * calculateSatelliteGroundTrack(..).
96 | *
97 | * @param gsPos
98 | * The position of the ground station to perform the calculations
99 | * for.
100 | * @return satPos The SatPos object where the position of the satellite is
101 | * stored, as seen from a ground station.
102 | */
103 | SatPos calculateSatPosForGroundStation(GroundStationPosition gsPos);
104 |
105 | /**
106 | * Returns the currently assigned TLE for the satellite.
107 | *
108 | * @return
109 | */
110 | TLE getTLE();
111 |
112 | /**
113 | * Get the position of the satellite.
114 | *
115 | * @param gsPos
116 | * the ground station position
117 | * @param satPos
118 | * the position of the satellite
119 | * @param date
120 | * the date
121 | */
122 | SatPos getPosition(GroundStationPosition qth, Date time);
123 | }
124 |
--------------------------------------------------------------------------------
/src/main/java/com/github/amsacode/predict4java/SatelliteFactory.java:
--------------------------------------------------------------------------------
1 | /**
2 | predict4java: An SDP4 / SGP4 library for satellite orbit predictions
3 |
4 | Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
5 |
6 | This class is a Java port of one of the core elements of
7 | the Predict program, Copyright John A. Magliacane,
8 | KD2BD 1991-2003: http://www.qsl.net/kd2bd/predict.html
9 |
10 | Dr. T.S. Kelso is the author of the SGP4/SDP4 orbital models,
11 | originally written in Fortran and Pascal, and released into the
12 | public domain through his website (http://www.celestrak.com/).
13 | Neoklis Kyriazis, 5B4AZ, later re-wrote Dr. Kelso's code in C,
14 | and released it under the GNU GPL in 2002.
15 | PREDICT's core is based on 5B4AZ's code translation efforts.
16 |
17 | Author: David A. B. Johnson, G4DPZ
18 |
19 | Comments, questions and bugreports should be submitted via
20 | http://sourceforge.net/projects/websat/
21 | More details can be found at the project home page:
22 |
23 | http://websat.sourceforge.net
24 |
25 | This program is free software; you can redistribute it and/or modify
26 | it under the terms of the GNU General Public License as published by
27 | the Free Software Foundation; either version 2 of the License, or
28 | (at your option) any later version.
29 |
30 | This program is distributed in the hope that it will be useful,
31 | but WITHOUT ANY WARRANTY; without even the implied warranty of
32 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 | GNU General Public License for more details.
34 |
35 | You should have received a copy of the GNU General Public License
36 | along with this program; if not, visit http://www.fsf.org/
37 | */
38 | package com.github.amsacode.predict4java;
39 |
40 | /**
41 | * The factory which creates a LEO or Deep Space Satellite.
42 | *
43 | * @author G4DPZ
44 | *
45 | */
46 | public final class SatelliteFactory {
47 |
48 | /**
49 | * Default constructor is private so cannot be instantiated.
50 | */
51 | private SatelliteFactory() {
52 |
53 | }
54 |
55 | /**
56 | * Creates a Satellite from a TLE.
57 | *
58 | * @param tle
59 | * The 'Three Line Elements'
60 | * @return Satellite
61 | * @throws IllegalArgumentException
62 | * when the given TLE is null or the data is incorrect
63 | */
64 | public static synchronized Satellite createSatellite(final TLE tle)
65 | throws IllegalArgumentException {
66 |
67 | if (null == tle) {
68 | throw new IllegalArgumentException("TLE was null");
69 | }
70 |
71 | Satellite satellite = null;
72 |
73 | if (tle.isDeepspace()) {
74 | satellite = new DeepSpaceSatellite(tle);
75 | } else {
76 | satellite = new LEOSatellite(tle);
77 | }
78 | return satellite;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/java/com/github/amsacode/predict4java/TLE.java:
--------------------------------------------------------------------------------
1 | /**
2 | predict4java: An SDP4 / SGP4 library for satellite orbit predictions
3 |
4 | Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
5 |
6 | This class is a Java port of one of the core elements of
7 | the Predict program, Copyright John A. Magliacane,
8 | KD2BD 1991-2003: http://www.qsl.net/kd2bd/predict.html
9 |
10 | Dr. T.S. Kelso is the author of the SGP4/SDP4 orbital models,
11 | originally written in Fortran and Pascal, and released into the
12 | public domain through his website (http://www.celestrak.com/).
13 | Neoklis Kyriazis, 5B4AZ, later re-wrote Dr. Kelso's code in C,
14 | and released it under the GNU GPL in 2002.
15 | PREDICT's core is based on 5B4AZ's code translation efforts.
16 |
17 | Author: David A. B. Johnson, G4DPZ
18 |
19 | Comments, questions and bugreports should be submitted via
20 | http://sourceforge.net/projects/websat/
21 | More details can be found at the project home page:
22 |
23 | http://websat.sourceforge.net
24 |
25 | This program is free software; you can redistribute it and/or modify
26 | it under the terms of the GNU General Public License as published by
27 | the Free Software Foundation; either version 2 of the License, or
28 | (at your option) any later version.
29 |
30 | This program is distributed in the hope that it will be useful,
31 | but WITHOUT ANY WARRANTY; without even the implied warranty of
32 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 | GNU General Public License for more details.
34 |
35 | You should have received a copy of the GNU General Public License
36 | along with this program; if not, visit http://www.fsf.org/
37 | */
38 | package com.github.amsacode.predict4java;
39 |
40 | import java.io.BufferedReader;
41 | import java.io.IOException;
42 | import java.io.InputStream;
43 | import java.io.InputStreamReader;
44 | import java.io.Serializable;
45 | import java.nio.charset.Charset;
46 | import java.util.ArrayList;
47 | import java.util.List;
48 |
49 | import org.apache.commons.lang.StringUtils;
50 |
51 | /**
52 | * TLE representation to aid SGP4 calculations. Instances of this class are
53 | * immutable and thus thread safe.
54 | */
55 | public class TLE implements Serializable {
56 |
57 | private static final long serialVersionUID = 716922882884628016L;
58 |
59 | private static final int THREELINES = 3;
60 | private static final double DEG2RAD = 1.745329251994330E-2;
61 | private static final double TWO_PI = Math.PI * 2.0;
62 | private static final double MINS_PERDAY = 1.44E3;
63 | private static final double XKE = 7.43669161E-2;
64 | private static final double TWO_THIRDS = 2.0 / 3.0;
65 | private static final double CK2 = 5.413079E-4;
66 |
67 | private final int catnum;
68 | private final String name;
69 | private final int setnum;
70 | private final int year;
71 | private final double refepoch;
72 | private final double incl;
73 | private final double raan;
74 | private final double eccn;
75 | private final double argper;
76 | private final double meanan;
77 | private final double meanmo;
78 | private final double drag;
79 | private final double nddot6;
80 | private final double bstar;
81 | private final int orbitnum;
82 | private final double epoch;
83 | private final double xndt2o;
84 | private final double xincl;
85 | private final double xnodeo;
86 | private final double eo;
87 | private final double omegao;
88 | private final double xmo;
89 | private final double xno;
90 | private final boolean deepspace;
91 |
92 | // Constructors
93 |
94 | /**
95 | * Copy constructor.
96 | *
97 | * @param tle
98 | */
99 | public TLE(final TLE tle) {
100 | this.catnum = tle.catnum;
101 | this.name = tle.name;
102 | this.setnum = tle.setnum;
103 | this.year = tle.year;
104 | this.refepoch = tle.refepoch;
105 | this.incl = tle.incl;
106 | this.raan = tle.raan;
107 | this.eccn = tle.eccn;
108 | this.argper = tle.argper;
109 | this.meanan = tle.meanan;
110 | this.meanmo = tle.meanmo;
111 | this.drag = tle.drag;
112 | this.nddot6 = tle.nddot6;
113 | this.bstar = tle.bstar;
114 | this.orbitnum = tle.orbitnum;
115 | this.epoch = tle.epoch;
116 | this.xndt2o = tle.xndt2o;
117 | this.xincl = tle.xincl;
118 | this.xnodeo = tle.xnodeo;
119 | this.eo = tle.eo;
120 | this.omegao = tle.omegao;
121 | this.xmo = tle.xmo;
122 | this.xno = tle.xno;
123 | this.deepspace = tle.deepspace;
124 | }
125 |
126 | /**
127 | * Constructor.
128 | *
129 | * @param tle the three line elements
130 | * @throws IllegalArgumentException here was something wrong with the TLE
131 | */
132 | public TLE(final String[] tle) throws IllegalArgumentException {
133 | {
134 | if (null == tle) {
135 | throw new IllegalArgumentException("TLE was null");
136 | }
137 |
138 | if (tle.length != THREELINES) {
139 | throw new IllegalArgumentException("TLE had " + tle.length
140 | + " elements");
141 | }
142 |
143 | int lineCount = 0;
144 |
145 | for (final String line : tle) {
146 |
147 | testArguments(lineCount, line);
148 |
149 | lineCount++;
150 | }
151 |
152 | catnum = Integer
153 | .parseInt(StringUtils.strip(tle[1].substring(2, 7)));
154 | name = tle[0].trim();
155 | setnum = Integer.parseInt(StringUtils.strip(tle[1]
156 | .substring(64, 68)));
157 | year = Integer
158 | .parseInt(StringUtils.strip(tle[1].substring(18, 20)));
159 | refepoch = Double.parseDouble(tle[1].substring(20, 32));
160 | incl = Double.parseDouble(tle[2].substring(8, 16));
161 | raan = Double.parseDouble(tle[2].substring(17, 25));
162 | eccn = 1.0e-07 * Double.parseDouble(tle[2].substring(26, 33));
163 | argper = Double.parseDouble(tle[2].substring(34, 42));
164 | meanan = Double.parseDouble(tle[2].substring(43, 51));
165 | meanmo = Double.parseDouble(tle[2].substring(52, 63));
166 | drag = Double.parseDouble(tle[1].substring(33, 43));
167 |
168 | double tempnum = 1.0e-5 * Double.parseDouble(tle[1].substring(44,
169 | 50));
170 | nddot6 = tempnum
171 | / Math.pow(10.0,
172 | Double.parseDouble(tle[1].substring(51, 52)));
173 |
174 | tempnum = 1.0e-5 * Double.parseDouble(tle[1].substring(53, 59));
175 |
176 | bstar = tempnum
177 | / Math.pow(10.0,
178 | Double.parseDouble(tle[1].substring(60, 61)));
179 |
180 | orbitnum = Integer.parseInt(StringUtils.strip(tle[2].substring(63,
181 | 68)));
182 |
183 | /* reassign the values to thse which get used in calculations */
184 | epoch = (1000.0 * getYear()) + getRefepoch();
185 |
186 | double temp = incl;
187 | temp *= DEG2RAD;
188 | xincl = temp;
189 |
190 | temp = raan;
191 | temp *= DEG2RAD;
192 | xnodeo = temp;
193 |
194 | eo = eccn;
195 |
196 | temp = argper;
197 | temp *= DEG2RAD;
198 | omegao = temp;
199 |
200 | temp = meanan;
201 | temp *= DEG2RAD;
202 | xmo = temp;
203 |
204 | }
205 |
206 | /* Preprocess tle set */
207 | {
208 | double temp;
209 | temp = TWO_PI / MINS_PERDAY / MINS_PERDAY;
210 | xno = meanmo * temp * MINS_PERDAY;
211 | xndt2o = drag * temp;
212 |
213 | double dd1 = XKE / xno;
214 | final double a1 = Math.pow(dd1, TWO_THIRDS);
215 | final double r1 = Math.cos(xincl);
216 | dd1 = 1.0 - eo * eo;
217 | temp = CK2 * 1.5f * (r1 * r1 * 3.0 - 1.0) / Math.pow(dd1, 1.5);
218 | final double del1 = temp / (a1 * a1);
219 | final double ao = a1
220 | * (1.0 - del1
221 | * (TWO_THIRDS * .5 + del1
222 | * (del1 * 1.654320987654321 + 1.0)));
223 | final double delo = temp / (ao * ao);
224 | final double xnodp = xno / (delo + 1.0);
225 |
226 | /* Select a deep-space/near-earth ephemeris */
227 |
228 | deepspace = TWO_PI / xnodp / MINS_PERDAY >= 0.15625;
229 | }
230 |
231 | }
232 |
233 | /**
234 | * @param lineCount the current line
235 | * @param line the line under test
236 | * @throws IllegalArgumentException there was a problem with the data
237 | */
238 | private void testArguments(final int lineCount, final String line)
239 | throws IllegalArgumentException {
240 | if (null == line) {
241 | throw new IllegalArgumentException(createIllegalArgumentMessage(
242 | lineCount, "was null"));
243 | }
244 |
245 | if (0 == line.length()) {
246 | throw new IllegalArgumentException(createIllegalArgumentMessage(
247 | lineCount, "was zero length"));
248 | }
249 | }
250 |
251 | /**
252 | * @return the catalog number
253 | */
254 | public int getCatnum() {
255 | return this.catnum;
256 | }
257 |
258 | /**
259 | * @return the name
260 | */
261 | public String getName() {
262 | return this.name;
263 | }
264 |
265 | /**
266 | * @return the element set number
267 | */
268 | public int getSetnum() {
269 | return this.setnum;
270 | }
271 |
272 | /**
273 | * @return the year part of the date of the elements
274 | */
275 | public int getYear() {
276 | return this.year;
277 | }
278 |
279 | /**
280 | * @return the reference epoch of the elements
281 | */
282 | public double getRefepoch() {
283 | return this.refepoch;
284 | }
285 |
286 | /**
287 | * @return the inclination of the satellite orbit
288 | */
289 | public double getIncl() {
290 | return this.incl;
291 | }
292 |
293 | /**
294 | * @return the Right Ascention of the Acending Node of the orbit
295 | */
296 | public double getRaan() {
297 | return this.raan;
298 | }
299 |
300 | /**
301 | * @return the Eccentricity of the orbit
302 | */
303 | public double getEccn() {
304 | return this.eccn;
305 | }
306 |
307 | /**
308 | * @return the Argument of Perigee of the orbit
309 | */
310 | public double getArgper() {
311 | return this.argper;
312 | }
313 |
314 | /**
315 | * @return the Mean Anomoly of the orbit
316 | */
317 | public double getMeanan() {
318 | return this.meanan;
319 | }
320 |
321 | /**
322 | * @return the Mean Motion of the satellite
323 | */
324 | public double getMeanmo() {
325 | return this.meanmo;
326 | }
327 |
328 | /**
329 | * @return the Drag factor
330 | */
331 | public double getDrag() {
332 | return this.drag;
333 | }
334 |
335 | /**
336 | * @return Nddot6
337 | */
338 | public double getNddot6() {
339 | return this.nddot6;
340 | }
341 |
342 | /**
343 | * @return Bstar
344 | */
345 | public double getBstar() {
346 | return this.bstar;
347 | }
348 |
349 | /**
350 | * @return Orbitnum
351 | */
352 | public int getOrbitnum() {
353 | return this.orbitnum;
354 | }
355 |
356 | /**
357 | * @return Deepspace
358 | */
359 | public boolean isDeepspace() {
360 | return deepspace;
361 | }
362 |
363 | /**
364 | * @return Eo
365 | */
366 | public double getEo() {
367 | return eo;
368 | }
369 |
370 | /**
371 | * @return Epoch
372 | */
373 | public double getEpoch() {
374 | return epoch;
375 | }
376 |
377 | /**
378 | * @return Omegao
379 | */
380 | public double getOmegao() {
381 | return omegao;
382 | }
383 |
384 | /**
385 | * @return Xincl
386 | */
387 | public double getXincl() {
388 | return xincl;
389 | }
390 |
391 | /**
392 | * @return Xmo
393 | */
394 | public double getXmo() {
395 | return xmo;
396 | }
397 |
398 | /**
399 | * @return Xndt2o
400 | */
401 | public synchronized double getXndt2o() {
402 | return xndt2o;
403 | }
404 |
405 | /**
406 | * @return Xno
407 | */
408 | public synchronized double getXno() {
409 | return xno;
410 | }
411 |
412 | /**
413 | * @return Xnodeo
414 | */
415 | public double getXnodeo() {
416 | return xnodeo;
417 | }
418 |
419 | /**
420 | * @param lineCount the line count
421 | * @param problem the problem
422 | * @return the description
423 | */
424 | private String createIllegalArgumentMessage(final int lineCount,
425 | final String problem) {
426 | return "TLE line[" + lineCount + "] " + problem;
427 | }
428 |
429 | public static List importSat(final InputStream fileIS)
430 | throws IOException {
431 | final List importedSats = new ArrayList();
432 |
433 | final BufferedReader buf = new BufferedReader(new InputStreamReader(
434 | fileIS, Charset.forName("UTF-8")));
435 | String readString;
436 |
437 | int j = 0;
438 |
439 | final String[] lines = new String[3];
440 |
441 | while ((readString = buf.readLine()) != null) {
442 |
443 | switch (j) {
444 | case 0:
445 | case 1:
446 | lines[j] = readString;
447 | j++;
448 | break;
449 | case 2:
450 | lines[j] = readString;
451 | j = 0;
452 | importedSats.add(new TLE(lines));
453 | break;
454 | default:
455 | break;
456 | }
457 | }
458 |
459 | return importedSats;
460 | }
461 |
462 | @Override
463 | public String toString() {
464 | return name;
465 | }
466 |
467 | }
468 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/gpl-2.0.txt:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 |
294 | Copyright (C)
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | , 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
--------------------------------------------------------------------------------
/src/test/java/com/github/amsacode/predict4java/AbstractSatelliteTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | predict4java: An SDP4 / SGP4 library for satellite orbit predictions
3 |
4 | Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
5 |
6 | Author: David A. B. Johnson, G4DPZ
7 |
8 | Comments, questions and bug reports should be submitted via
9 | http://sourceforge.net/projects/websat/
10 | More details can be found at the project home page:
11 |
12 | http://websat.sourceforge.net
13 |
14 | This program is free software; you can redistribute it and/or modify
15 | it under the terms of the GNU General Public License as published by
16 | the Free Software Foundation; either version 2 of the License, or
17 | (at your option) any later version.
18 |
19 | This program is distributed in the hope that it will be useful,
20 | but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | GNU General Public License for more details.
23 |
24 | You should have received a copy of the GNU General Public License
25 | along with this program; if not, visit http://www.fsf.org/
26 | */
27 | package com.github.amsacode.predict4java;
28 |
29 | import static org.assertj.core.api.Assertions.assertThat;
30 |
31 | import org.assertj.core.data.Offset;
32 | import org.junit.Test;
33 |
34 | public final class AbstractSatelliteTest {
35 |
36 | private static final Offset PRECISION = Offset.offset(0.00001);
37 |
38 | @Test
39 | public void testJulianDateFromEpochConversionGivenYearIn20thCentury() {
40 | assertThat(AbstractSatellite.juliandDateOfEpoch(90000)).isEqualTo(AbstractSatellite.julianDateOfYear(1990), PRECISION);
41 | }
42 |
43 | @Test
44 | public void testModulusGivenNegativeFirstArg() {
45 | assertThat(AbstractSatellite.modulus(-10.6, 10)).isEqualTo(9.4, PRECISION);
46 | }
47 |
48 | @Test
49 | public void testModulusGivenNegativeSecondArg() {
50 | // weird behaviour for modulus if you ask me
51 | assertThat(AbstractSatellite.modulus(23, -10)).isEqualTo(-17.0, PRECISION);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/test/java/com/github/amsacode/predict4java/AbstractSatelliteTestBase.java:
--------------------------------------------------------------------------------
1 | /**
2 | predict4java: An SDP4 / SGP4 library for satellite orbit predictions
3 |
4 | Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
5 |
6 | Author: David A. B. Johnson, G4DPZ
7 |
8 | Comments, questions and bug reports should be submitted via
9 | http://sourceforge.net/projects/websat/
10 | More details can be found at the project home page:
11 |
12 | http://websat.sourceforge.net
13 |
14 | This program is free software; you can redistribute it and/or modify
15 | it under the terms of the GNU General Public License as published by
16 | the Free Software Foundation; either version 2 of the License, or
17 | (at your option) any later version.
18 |
19 | This program is distributed in the hope that it will be useful,
20 | but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | GNU General Public License for more details.
23 |
24 | You should have received a copy of the GNU General Public License
25 | along with this program; if not, visit http://www.fsf.org/
26 | */
27 | package com.github.amsacode.predict4java;
28 |
29 | import java.text.SimpleDateFormat;
30 | import java.util.TimeZone;
31 |
32 | /**
33 | * @author David A. B. Johnson, g4dpz
34 | *
35 | */
36 | public abstract class AbstractSatelliteTestBase {
37 |
38 | protected AbstractSatelliteTestBase() {
39 |
40 | }
41 |
42 | static final GroundStationPosition GROUND_STATION = new GroundStationPosition(
43 | 52.4670, -2.022, 200);
44 |
45 | protected static final SimpleDateFormat TZ_FORMAT;
46 | static {
47 | TZ_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
48 | TZ_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
49 | }
50 |
51 | /** The time at which we do all the calculations. */
52 | static final TimeZone TZ = TimeZone.getTimeZone("UTC:UTC");
53 |
54 | /** Seconds per day. */
55 | static final long SECONDS_PER_DAY = 24 * 60 * 60;
56 |
57 | protected static final String[] LEO_TLE = {
58 | "AO-51 [+]",
59 | "1 28375U 04025K 09105.66391970 .00000003 00000-0 13761-4 0 3643",
60 | "2 28375 098.0551 118.9086 0084159 315.8041 043.6444 14.40638450251959" };
61 |
62 | protected static final String[] DEEP_SPACE_TLE = {
63 | "AO-40",
64 | "1 26609U 00072B 09105.66069202 -.00000356 00000-0 10000-3 0 2169",
65 | "2 26609 009.1977 023.4368 7962000 194.9139 106.0662 01.25584647 38840" };
66 |
67 | protected static final String[] GEOSYNC_TLE = {
68 | "EUTELSAT 2-F1",
69 | "1 20777U 90079B 09356.31446792 .00000081 00000-0 10000-3 0 9721",
70 | "2 20777 9.6834 57.1012 0004598 207.1414 152.7950 0.99346230 50950" };
71 |
72 | protected static final String[] MOLNIYA_TLE = {
73 | "MOLNIYA 1-80",
74 | "1 21118U 91012A 09357.87605320 .00001593 00000-0 10000-3 0 7339",
75 | "2 21118 61.8585 240.5458 7236516 255.2789 21.0579 2.00792202138149" };
76 |
77 | protected static final String[] WEATHER_TLE = {
78 | "TIROS N [P]",
79 | "1 11060U 78096A 09359.84164805 -.00000019 00000-0 13276-4 0 3673",
80 | "2 11060 98.9548 331.5509 0010393 187.3222 172.7804 14.17491792826101" };
81 |
82 | protected static final String[] DE_ORBIT_TLE = {
83 | "COSMOS 2421 DEB",
84 | "1 33139U 06026MX 09359.84164805 .10408321 74078-5 34039-2 0 6397",
85 | "2 33139 064.8768 254.5588 0010700 285.2081 074.8503 16.45000000 91112" };
86 |
87 | protected static final String LATITUDE = "52.4670";
88 | protected static final String LONGITUDE = "-2.022";
89 | protected static final int HEIGHT_AMSL = 200;
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/src/test/java/com/github/amsacode/predict4java/DeepSpaceSatelliteTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | predict4java: An SDP4 / SGP4 library for satellite orbit predictions
3 |
4 | Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
5 |
6 | Author: David A. B. Johnson, G4DPZ
7 |
8 | Comments, questions and bug reports should be submitted via
9 | http://sourceforge.net/projects/websat/
10 | More details can be found at the project home page:
11 |
12 | http://websat.sourceforge.net
13 |
14 | This program is free software; you can redistribute it and/or modify
15 | it under the terms of the GNU General Public License as published by
16 | the Free Software Foundation; either version 2 of the License, or
17 | (at your option) any later version.
18 |
19 | This program is distributed in the hope that it will be useful,
20 | but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | GNU General Public License for more details.
23 |
24 | You should have received a copy of the GNU General Public License
25 | along with this program; if not, visit http://www.fsf.org/
26 | */
27 | package com.github.amsacode.predict4java;
28 |
29 | import static org.assertj.core.api.Assertions.assertThat;
30 |
31 | import org.joda.time.DateTime;
32 | import org.junit.Before;
33 | import org.junit.Test;
34 |
35 | /**
36 | * @author David A. B. Johnson, g4dpz
37 | *
38 | */
39 | public final class DeepSpaceSatelliteTest extends AbstractSatelliteTestBase {
40 |
41 | private static final String DATE_2009_12_26T00_00_00Z = "2009-12-26T00:00:00Z";
42 | private static final String FORMAT_9_3F = "%9.3f";
43 | private static final String FORMAT_10_7F = "%10.7f";
44 | private static final String FORMAT_9_7F = "%9.7f";
45 | private DateTime timeNow;
46 |
47 | /**
48 | * @throws java.lang.Exception
49 | */
50 | @Before
51 | public void setUp() throws Exception {
52 | timeNow = new DateTime("2009-04-17T10:10:52Z");
53 | }
54 |
55 | @Test
56 | public void testDeepSpaceSatellite() {
57 | final TLE tle = new TLE(DEEP_SPACE_TLE);
58 | assertThat(tle.isDeepspace()).isTrue();
59 |
60 | final Satellite satellite = SatelliteFactory.createSatellite(tle);
61 |
62 | final SatPos satellitePosition = satellite.getPosition(GROUND_STATION,
63 | timeNow.toDate());
64 |
65 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getAzimuth())).isEqualTo("2.2579325");
66 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getElevation())).isEqualTo("0.4144053");
67 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getLongitude())).isEqualTo("0.7091175");
68 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getLatitude())).isEqualTo("0.0442970");
69 | assertThat(String.format(FORMAT_10_7F, satellitePosition.getAltitude())).isEqualTo("58847.2042542");
70 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getPhase())).isEqualTo("3.2039351");
71 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getRange())).isEqualTo("62390.2433539");
72 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getRangeRate())).isEqualTo("-0.2187132");
73 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getTheta())).isEqualTo("0.6810134");
74 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getEclipseDepth())).isEqualTo("-2.7759541");
75 | assertThat(satellitePosition.isEclipsed()).isFalse();
76 | assertThat(satellite.willBeSeen(GROUND_STATION)).isTrue();
77 | assertThat(satellitePosition.isAboveHorizon()).isTrue();
78 |
79 | }
80 |
81 |
82 | @Test
83 | public void testToStringMethod() {
84 | final TLE tle = new TLE(DEEP_SPACE_TLE);
85 | final Satellite satellite = SatelliteFactory.createSatellite(tle);
86 | final SatPos satellitePosition = satellite.getPosition(GROUND_STATION,
87 | timeNow.toDate());
88 | assertThat(satellitePosition.toString()).isNotNull();
89 | }
90 |
91 | @Test
92 | public void testToShortStringMethod() {
93 | final TLE tle = new TLE(DEEP_SPACE_TLE);
94 | final Satellite satellite = SatelliteFactory.createSatellite(tle);
95 | final SatPos satellitePosition = satellite.getPosition(GROUND_STATION,
96 | timeNow.toDate());
97 | assertThat(satellitePosition.toShortString()).isNotNull();
98 | }
99 |
100 | @Test
101 | public void testGeoSynchSatellite() {
102 | timeNow = new DateTime(DATE_2009_12_26T00_00_00Z);
103 |
104 | final TLE tle = new TLE(GEOSYNC_TLE);
105 |
106 | assertThat(tle.isDeepspace()).isTrue();
107 |
108 | final Satellite satellite = SatelliteFactory.createSatellite(tle);
109 |
110 | final SatPos satellitePosition = satellite.getPosition(GROUND_STATION,
111 | timeNow.toDate());
112 |
113 | assertThat(tle.isDeepspace()).isTrue();
114 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getAzimuth())).isEqualTo("5.7530820");
115 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getElevation())).isEqualTo("-0.8368869");
116 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getLongitude())).isEqualTo("3.4946919");
117 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getLatitude())).isEqualTo("-0.1440008");
118 | assertThat(String.format(FORMAT_10_7F, satellitePosition.getAltitude())).isEqualTo("36031.8182912");
119 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getPhase())).isEqualTo("0.5377382");
120 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getRange())).isEqualTo("46934.3153284");
121 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getRangeRate())).isEqualTo("0.0271561");
122 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getTheta())).isEqualTo("-1.1369975");
123 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getEclipseDepth())).isEqualTo("-2.5674344");
124 | assertThat(satellitePosition.isEclipsed()).isFalse();
125 | assertThat(satellite.willBeSeen(GROUND_STATION)).isTrue();
126 | }
127 |
128 | @Test
129 | public void testMolniyaSatellite() {
130 | timeNow = new DateTime(DATE_2009_12_26T00_00_00Z);
131 |
132 | final TLE tle = new TLE(MOLNIYA_TLE);
133 |
134 | final Satellite satellite = SatelliteFactory.createSatellite(tle);
135 |
136 | final SatPos satellitePosition = satellite.getPosition(GROUND_STATION,
137 | timeNow.toDate());
138 |
139 | assertThat(tle.isDeepspace()).isTrue();
140 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getAzimuth())).isEqualTo("6.2095948");
141 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getElevation())).isEqualTo("0.0572862");
142 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getLongitude())).isEqualTo("3.2171857");
143 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getLatitude())).isEqualTo("0.8635892");
144 | assertThat(String.format(FORMAT_9_3F, satellitePosition.getAltitude())).isEqualTo("35280.747");
145 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getPhase())).isEqualTo("2.0315668");
146 | assertThat(String.format(FORMAT_9_3F, satellitePosition.getRange())).isEqualTo("40814.880");
147 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getRangeRate())).isEqualTo("0.9164450");
148 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getTheta())).isEqualTo("-1.4145037");
149 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getEclipseDepth())).isEqualTo("-1.7199331");
150 | assertThat(satellitePosition.isEclipsed()).isFalse();
151 | assertThat(satellite.willBeSeen(GROUND_STATION)).isTrue();
152 | }
153 |
154 | }
155 |
--------------------------------------------------------------------------------
/src/test/java/com/github/amsacode/predict4java/GroundStationPositionTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | predict4java: An SDP4 / SGP4 library for satellite orbit predictions
3 |
4 | Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
5 |
6 | Author: David A. B. Johnson, G4DPZ
7 |
8 | Comments, questions and bug reports should be submitted via
9 | http://sourceforge.net/projects/websat/
10 | More details can be found at the project home page:
11 |
12 | http://websat.sourceforge.net
13 |
14 | This program is free software; you can redistribute it and/or modify
15 | it under the terms of the GNU General Public License as published by
16 | the Free Software Foundation; either version 2 of the License, or
17 | (at your option) any later version.
18 |
19 | This program is distributed in the hope that it will be useful,
20 | but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | GNU General Public License for more details.
23 |
24 | You should have received a copy of the GNU General Public License
25 | along with this program; if not, visit http://www.fsf.org/
26 | */
27 | package com.github.amsacode.predict4java;
28 |
29 | import static org.assertj.core.api.Assertions.assertThat;
30 |
31 | import org.assertj.core.data.Offset;
32 | import org.junit.Test;
33 |
34 | /**
35 | * @author David A. B. Johnson, g4dpz
36 | */
37 | public final class GroundStationPositionTest {
38 |
39 | private static final double HEIGHT_AMSL = 3.0;
40 | private static final double LONGITUDE = 2.0;
41 | private static final double LATITUDE = 1.0;
42 | private static final Offset PRECISION = Offset.offset(0.00001);
43 |
44 | @Test
45 | public void testConstructionUsingAttributes() {
46 |
47 | final GroundStationPosition groundStationPosition = new GroundStationPosition(
48 | LATITUDE, LONGITUDE, HEIGHT_AMSL);
49 | assertThat(Math.abs(LATITUDE - groundStationPosition.getLatitude()) < 0.000001).isTrue();
50 | assertThat(Math.abs(LONGITUDE - groundStationPosition.getLongitude()) < 0.000001).isTrue();
51 | assertThat(Math
52 | .abs(HEIGHT_AMSL - groundStationPosition.getHeightAMSL()) < 0.000001).isTrue();
53 |
54 | }
55 |
56 | @Test
57 | public void testConstructor() {
58 | GroundStationPosition g = new GroundStationPosition(10, 11, 12, "boo");
59 | assertThat(g.getLatitude()).isEqualTo(10.0, PRECISION);
60 | assertThat(g.getLongitude()).isEqualTo(11.0, PRECISION);
61 | assertThat(g.getHeightAMSL()).isEqualTo(12.0, PRECISION);
62 | assertThat(g.getName()).isEqualTo("boo");
63 | }
64 |
65 | @Test
66 | public void testConstructorWithHorizonElevations() {
67 | int[] horizonElevations = new int[36];
68 | horizonElevations[0]=12;
69 | horizonElevations[1]=14;
70 | horizonElevations[35]=16;
71 | GroundStationPosition g = new GroundStationPosition(10, 11, 12, "boo", horizonElevations);
72 | assertThat(g.getLatitude()).isEqualTo(10.0, PRECISION);
73 | assertThat(g.getLongitude()).isEqualTo(11.0, PRECISION);
74 | assertThat(g.getHeightAMSL()).isEqualTo(12.0, PRECISION);
75 | assertThat(g.getName()).isEqualTo("boo");
76 | assertThat(g.getHorizonElevation(0)).isEqualTo(12);
77 | assertThat(g.getHorizonElevation(1)).isEqualTo(14);
78 | assertThat(g.getHorizonElevation(35)).isEqualTo(16);
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/test/java/com/github/amsacode/predict4java/IlluminationTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | predict4java: An SDP4 / SGP4 library for satellite orbit predictions
3 |
4 | Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
5 |
6 | Author: David A. B. Johnson, G4DPZ
7 |
8 | Comments, questions and bug reports should be submitted via
9 | http://sourceforge.net/projects/websat/
10 | More details can be found at the project home page:
11 |
12 | http://websat.sourceforge.net
13 |
14 | This program is free software; you can redistribute it and/or modify
15 | it under the terms of the GNU General Public License as published by
16 | the Free Software Foundation; either version 2 of the License, or
17 | (at your option) any later version.
18 |
19 | This program is distributed in the hope that it will be useful,
20 | but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | GNU General Public License for more details.
23 |
24 | You should have received a copy of the GNU General Public License
25 | along with this program; if not, visit http://www.fsf.org/
26 | */
27 | package com.github.amsacode.predict4java;
28 |
29 | import org.joda.time.DateTime;
30 | import org.junit.Assert;
31 | import org.junit.Test;
32 |
33 | public class IlluminationTest extends AbstractSatelliteTestBase {
34 |
35 | @Test
36 | public void testCalculateSunVector() {
37 |
38 | final TLE tle = new TLE(LEO_TLE);
39 |
40 | Assert.assertFalse(tle.isDeepspace());
41 |
42 | final Satellite satellite = SatelliteFactory.createSatellite(tle);
43 |
44 | DateTime timeNow = new DateTime("2009-06-01T00:00:00Z");
45 |
46 | for (int day = 0; day < 30; day++) {
47 | final SatPos satPos = satellite.getPosition(GROUND_STATION,
48 | timeNow.toDate());
49 |
50 | switch (day) {
51 | case 4:
52 | case 9:
53 | case 14:
54 | case 19:
55 | case 24:
56 | case 29:
57 | Assert.assertTrue("Satellite should have been eclipsed on day "
58 | + day, satPos.isEclipsed());
59 | break;
60 | default:
61 | Assert.assertFalse(
62 | "Satellite should not have been eclipsed on day " + day,
63 | satPos.isEclipsed());
64 | break;
65 | }
66 | timeNow = timeNow.plusDays(1);
67 | }
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/src/test/java/com/github/amsacode/predict4java/LEOSatelliteTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | predict4java: An SDP4 / SGP4 library for satellite orbit predictions
3 |
4 | Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
5 |
6 | Author: David A. B. Johnson, G4DPZ
7 |
8 | Comments, questions and bug reports should be submitted via
9 | http://sourceforge.net/projects/websat/
10 | More details can be found at the project home page:
11 |
12 | http://websat.sourceforge.net
13 |
14 | This program is free software; you can redistribute it and/or modify
15 | it under the terms of the GNU General Public License as published by
16 | the Free Software Foundation; either version 2 of the License, or
17 | (at your option) any later version.
18 |
19 | This program is distributed in the hope that it will be useful,
20 | but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | GNU General Public License for more details.
23 |
24 | You should have received a copy of the GNU General Public License
25 | along with this program; if not, visit http://www.fsf.org/
26 | */
27 | package com.github.amsacode.predict4java;
28 |
29 | import static org.assertj.core.api.Assertions.assertThat;
30 |
31 | import java.util.List;
32 |
33 | import org.joda.time.DateTime;
34 | import org.junit.Test;
35 |
36 | /**
37 | * @author David A. B. Johnson, g4dpz
38 | *
39 | */
40 | public final class LEOSatelliteTest extends AbstractSatelliteTestBase {
41 |
42 | private static final String ECLIPSE_DEPTH = "-0.2353420";
43 |
44 | private static final String THETA_VALUE = "-1.8011516";
45 |
46 | private static final String RANGE_RATE_VALUE = "-3.0094317";
47 |
48 | private static final String RANGE_VALUE = "5433";
49 |
50 | private static final String PHASE_VALUE = "4.5526109";
51 |
52 | private static final String ALTITUDE_VALUE = "848.4319560";
53 |
54 | private static final String LATITUDE_VALUE = "1.4098576";
55 |
56 | private static final String LONGITUDE_VALUE = "2.8305378";
57 |
58 | private static final String ELEVATION_VALUE = "-0.2617647";
59 |
60 | private static final String AZIMUTH_VALUE = "0.0602822";
61 |
62 | private static final String FORMAT_4_0F = "%4.0f";
63 |
64 | private static final String FORMAT_10_7F = "%10.7f";
65 |
66 | private static final String FORMAT_9_7F = "%9.7f";
67 |
68 | private static final String BASE_TIME = "2009-12-26T00:00:00Z";
69 |
70 | private DateTime timeNow;
71 |
72 | /**
73 | * Test method for
74 | * {@link com.github.amsacode.predict4java.LEOSatellite#LEOSatellite(com.github.amsacode.predict4java.TLE)}
75 | * .
76 | */
77 | @Test
78 | public void testLEOSatellite() {
79 | timeNow = new DateTime("2009-04-17T06:57:32Z");
80 |
81 | final TLE tle = new TLE(LEO_TLE);
82 |
83 | assertThat(tle.isDeepspace()).isFalse();
84 |
85 | final Satellite satellite = SatelliteFactory.createSatellite(tle);
86 |
87 | final SatPos satellitePosition = satellite.getPosition(GROUND_STATION,
88 | timeNow.toDate());
89 |
90 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getAzimuth())).isEqualTo("3.2421950");
91 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getElevation())).isEqualTo("0.1511580");
92 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getLongitude())).isEqualTo("6.2069835");
93 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getLatitude())).isEqualTo("0.5648232");
94 | assertThat(String.format(FORMAT_10_7F, satellitePosition.getAltitude())).isEqualTo("818.1375014");
95 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getPhase())).isEqualTo("3.4337605");
96 | assertThat(String.format(FORMAT_4_0F, satellitePosition.getRange())).isEqualTo("2506");
97 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getRangeRate())).isEqualTo("6.4832408");
98 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getTheta())).isEqualTo("-0.9501914");
99 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getEclipseDepth())).isEqualTo("-0.7307717");
100 | assertThat(satellitePosition.isEclipsed()).isFalse();
101 | assertThat(satellite.willBeSeen(GROUND_STATION)).isTrue();
102 |
103 | List rangeCircle = satellitePosition.getRangeCircle();
104 | assertThat(String.format("%6.1f %6.1f", rangeCircle
105 | .get(0).getLat(), rangeCircle.get(0).getLon())).isEqualTo(" 59.9 355.6");
106 | assertThat(String.format("%6.1f %6.1f", rangeCircle
107 | .get(89).getLat(), rangeCircle.get(89).getLon())).isEqualTo(" 28.8 323.7");
108 | assertThat(String.format("%6.1f %6.1f", rangeCircle
109 | .get(179).getLat(), rangeCircle.get(179).getLon())).isEqualTo(" 4.8 355.2");
110 | assertThat(String.format("%6.1f %6.1f", rangeCircle
111 | .get(269).getLat(), rangeCircle.get(269).getLon())).isEqualTo(" 27.9 27.2");
112 | }
113 |
114 | @Test
115 | public void testWeatherSatellite() {
116 | timeNow = new DateTime(BASE_TIME);
117 |
118 | final TLE tle = new TLE(WEATHER_TLE);
119 |
120 | assertThat(tle.isDeepspace()).isFalse();
121 |
122 | final Satellite satellite = SatelliteFactory.createSatellite(tle);
123 |
124 | final SatPos satellitePosition = satellite.getPosition(GROUND_STATION,
125 | timeNow.toDate());
126 |
127 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getAzimuth())).isEqualTo(AZIMUTH_VALUE);
128 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getElevation())).isEqualTo(ELEVATION_VALUE);
129 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getLongitude())).isEqualTo(LONGITUDE_VALUE);
130 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getLatitude())).isEqualTo(LATITUDE_VALUE);
131 | assertThat(String.format(FORMAT_10_7F, satellitePosition.getAltitude())).isEqualTo(ALTITUDE_VALUE);
132 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getPhase())).isEqualTo(PHASE_VALUE);
133 | assertThat(String.format(FORMAT_4_0F,
134 | Math.floor(satellitePosition.getRange()))).isEqualTo(RANGE_VALUE);
135 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getRangeRate())).isEqualTo(RANGE_RATE_VALUE);
136 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getTheta())).isEqualTo(THETA_VALUE);
137 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getEclipseDepth())).isEqualTo(ECLIPSE_DEPTH);
138 | assertThat(satellitePosition.isEclipsed()).isFalse();
139 | assertThat(satellite.willBeSeen(GROUND_STATION)).isTrue();
140 |
141 | }
142 |
143 | @Test
144 | public void testIvoAlgorithm() {
145 | timeNow = new DateTime(BASE_TIME);
146 |
147 | final TLE tle = new TLE(WEATHER_TLE);
148 |
149 | assertThat(tle.isDeepspace()).isFalse();
150 |
151 | final Satellite satellite = SatelliteFactory.createSatellite(tle);
152 |
153 | satellite.calculateSatelliteVectors(timeNow.toDate());
154 |
155 | SatPos satellitePosition = satellite.calculateSatelliteGroundTrack();
156 |
157 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getLongitude())).isEqualTo(LONGITUDE_VALUE);
158 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getLatitude())).isEqualTo(LATITUDE_VALUE);
159 | assertThat(String.format(FORMAT_10_7F, satellitePosition.getAltitude())).isEqualTo(ALTITUDE_VALUE);
160 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getPhase())).isEqualTo(PHASE_VALUE);
161 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getTheta())).isEqualTo(THETA_VALUE);
162 | assertThat(satellite.willBeSeen(GROUND_STATION)).isTrue();
163 |
164 | satellitePosition = satellite
165 | .calculateSatPosForGroundStation(GROUND_STATION);
166 |
167 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getAzimuth())).isEqualTo(AZIMUTH_VALUE);
168 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getElevation())).isEqualTo(ELEVATION_VALUE);
169 | assertThat(String.format(FORMAT_4_0F,
170 | Math.floor(satellitePosition.getRange()))).isEqualTo(RANGE_VALUE);
171 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getRangeRate())).isEqualTo(RANGE_RATE_VALUE);
172 | assertThat(String.format(FORMAT_9_7F, satellitePosition.getEclipseDepth())).isEqualTo(ECLIPSE_DEPTH);
173 | assertThat(satellitePosition.isEclipsed()).isFalse();
174 |
175 | }
176 |
177 | @Test
178 | public void testDeOrbitSatellite() {
179 | timeNow = new DateTime(BASE_TIME);
180 |
181 | final TLE tle = new TLE(DE_ORBIT_TLE);
182 |
183 | assertThat(tle.isDeepspace()).isFalse();
184 |
185 | final Satellite satellite = SatelliteFactory.createSatellite(tle);
186 |
187 | satellite.calculateSatelliteVectors(timeNow.toDate());
188 |
189 | final SatPos satellitePosition = satellite
190 | .calculateSatelliteGroundTrack();
191 |
192 | assertThat(String.format(FORMAT_10_7F, satellitePosition.getAltitude())).isEqualTo("57.2854215");
193 |
194 | }
195 |
196 | }
197 |
--------------------------------------------------------------------------------
/src/test/java/com/github/amsacode/predict4java/PassPredictorTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | predict4java: An SDP4 / SGP4 library for satellite orbit predictions
3 |
4 | Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
5 |
6 | Author: David A. B. Johnson, G4DPZ
7 |
8 | Comments, questions and bug reports should be submitted via
9 | http://sourceforge.net/projects/websat/
10 | More details can be found at the project home page:
11 |
12 | http://websat.sourceforge.net
13 |
14 | This program is free software; you can redistribute it and/or modify
15 | it under the terms of the GNU General Public License as published by
16 | the Free Software Foundation; either version 2 of the License, or
17 | (at your option) any later version.
18 |
19 | This program is distributed in the hope that it will be useful,
20 | but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | GNU General Public License for more details.
23 |
24 | You should have received a copy of the GNU General Public License
25 | along with this program; if not, visit http://www.fsf.org/
26 | */
27 | package com.github.amsacode.predict4java;
28 |
29 | import static org.assertj.core.api.Assertions.assertThat;
30 | import static org.junit.Assert.assertEquals;
31 |
32 | import java.util.List;
33 |
34 | import org.joda.time.DateTime;
35 | import org.junit.Test;
36 |
37 | /**
38 | * @author David A. B. Johnson, g4dpz
39 | */
40 | public final class PassPredictorTest extends AbstractSatelliteTestBase {
41 |
42 | private static final String DATE_2009_01_05T04_30_00Z = "2009-01-05T04:30:00Z";
43 | private static final String DATE_2009_01_05T04_32_15_0000 = "2009-01-05T04:32:15+0000";
44 | private static final String DATE_2009_01_05T04_28_10_0000 = "2009-01-05T04:28:10+0000";
45 | private static final String DATE_2009_01_05T07_00_00Z = "2009-01-05T07:00:00Z";
46 | private static final String NORTH = "north";
47 | private static final String STRING_PAIR = "%s, %s";
48 | private static final String NONE = "none";
49 |
50 | @Test(expected = IllegalArgumentException.class)
51 | public void cannot_accept_two_null_parameters_in_constructor() throws SatNotFoundException {
52 | new PassPredictor(null, null);
53 | }
54 |
55 | @Test(expected = IllegalArgumentException.class)
56 | public void cannot_accept_one_null_parameters_in_constructor() throws SatNotFoundException {
57 | new PassPredictor(new TLE(LEO_TLE), null);
58 | }
59 |
60 | /**
61 | * Test method for {@link com.github.amsacode.predict4java.PassPredictor#nextSatPass()}
62 | */
63 | @Test
64 | public void testNextSatPass() throws SatNotFoundException {
65 | final TLE tle = new TLE(LEO_TLE);
66 | assertThat(tle.isDeepspace()).isFalse();
67 | final PassPredictor passPredictor = new PassPredictor(tle,
68 | GROUND_STATION);
69 | final DateTime cal = new DateTime("2009-01-05T00:00:00Z");
70 | SatPassTime passTime = passPredictor.nextSatPass(cal.toDate());
71 | assertThat(TZ_FORMAT.format(passTime.getStartTime())).isEqualTo(DATE_2009_01_05T04_28_10_0000);
72 | assertThat(TZ_FORMAT.format(passTime.getEndTime())).isEqualTo(DATE_2009_01_05T04_32_15_0000);
73 | assertThat(TZ_FORMAT.format(passTime.getTCA())).isEqualTo("2009-01-05T04:30:10+0000");
74 | assertThat(passTime.getPolePassed()).isEqualTo(NONE);
75 | assertThat(passTime.getAosAzimuth()).isEqualTo(52);
76 | assertThat(passTime.getLosAzimuth()).isEqualTo(84);
77 | assertThat(String.format("%3.1f", passTime.getMaxEl())).isEqualTo("0.9");
78 | assertThat(passPredictor.getDownlinkFreq(436800000L,
79 | passTime.getStartTime())).isEqualTo(Long.valueOf(436802379L));
80 | assertThat(passPredictor.getUplinkFreq(145800000L,
81 | passTime.getEndTime())).isEqualTo(Long.valueOf(145800719L));
82 |
83 | passTime = passPredictor.nextSatPass(passTime.getStartTime());
84 | assertThat(TZ_FORMAT.format(passTime.getStartTime())).isEqualTo("2009-01-05T06:04:00+0000");
85 | assertThat(TZ_FORMAT.format(passTime.getEndTime())).isEqualTo("2009-01-05T06:18:00+0000");
86 | assertThat(passTime.getPolePassed()).isEqualTo(NONE);
87 | assertThat(passTime.getAosAzimuth()).isEqualTo(22);
88 | assertThat(passTime.getLosAzimuth()).isEqualTo(158);
89 | assertEquals(24.42, passTime.getMaxEl(), 0.02);
90 |
91 | passTime = passPredictor.nextSatPass(passTime.getStartTime());
92 | assertThat(TZ_FORMAT.format(passTime.getStartTime())).isEqualTo("2009-01-05T07:42:45+0000");
93 | assertThat(TZ_FORMAT.format(passTime.getEndTime())).isEqualTo("2009-01-05T07:57:50+0000");
94 | assertThat(passTime.getPolePassed()).isEqualTo(NORTH);
95 | assertThat(passTime.getAosAzimuth()).isEqualTo(11);
96 | assertThat(passTime.getLosAzimuth()).isEqualTo(207);
97 | assertThat(String.format("%5.2f", passTime.getMaxEl())).isEqualTo("62.19");
98 |
99 | passTime = passPredictor.nextSatPass(passTime.getStartTime());
100 | assertThat(TZ_FORMAT.format(passTime.getStartTime())).isEqualTo("2009-01-05T09:22:05+0000");
101 | assertThat(TZ_FORMAT.format(passTime.getEndTime())).isEqualTo("2009-01-05T09:34:20+0000");
102 | assertThat(passTime.getPolePassed()).isEqualTo(NORTH);
103 | assertThat(passTime.getAosAzimuth()).isEqualTo(4);
104 | assertThat(passTime.getLosAzimuth()).isEqualTo(256);
105 | assertEquals(14.3, passTime.getMaxEl(), 0.02);
106 |
107 | passTime = passPredictor.nextSatPass(passTime.getStartTime());
108 | assertThat(TZ_FORMAT.format(passTime.getStartTime())).isEqualTo("2009-01-05T11:02:05+0000");
109 | assertThat(TZ_FORMAT.format(passTime.getEndTime())).isEqualTo("2009-01-05T11:07:35+0000");
110 | assertThat(passTime.getPolePassed()).isEqualTo(NONE);
111 | assertThat(passTime.getAosAzimuth()).isEqualTo(355);
112 | assertThat(passTime.getLosAzimuth()).isEqualTo(312);
113 | assertEquals(1.8, passTime.getMaxEl(), 0.05);
114 | }
115 |
116 | /**
117 | * Test method for {@link com.github.amsacode.predict4java.PassPredictor#nextSatPass()}
118 | * .
119 | */
120 | @Test
121 | public void testNextSatPassWithWindBack() throws SatNotFoundException {
122 | final TLE tle = new TLE(LEO_TLE);
123 | assertThat(tle.isDeepspace()).isFalse();
124 |
125 | final PassPredictor passPredictor = new PassPredictor(tle,
126 | GROUND_STATION);
127 | final DateTime cal = new DateTime(DATE_2009_01_05T04_30_00Z);
128 | final SatPassTime passTime = passPredictor.nextSatPass(
129 | cal.toDate(), true);
130 | assertThat(TZ_FORMAT.format(passTime.getStartTime())).isEqualTo(DATE_2009_01_05T04_28_10_0000);
131 | assertThat(TZ_FORMAT.format(passTime.getEndTime())).isEqualTo(DATE_2009_01_05T04_32_15_0000);
132 | assertThat(passTime.getPolePassed()).isEqualTo(NONE);
133 | assertThat(passTime.getAosAzimuth()).isEqualTo(52);
134 | assertThat(passTime.getLosAzimuth()).isEqualTo(84);
135 | assertEquals(0.9, passTime.getMaxEl(), 0.05);
136 | assertThat(passPredictor.getDownlinkFreq(436800000L,
137 | passTime.getStartTime())).isEqualTo(Long.valueOf(436802379L));
138 | assertThat(passPredictor.getUplinkFreq(145800000L,
139 | passTime.getEndTime())).isEqualTo(Long.valueOf(145800719L));
140 | }
141 |
142 | @Test
143 | public void correctToStringResult() throws SatNotFoundException {
144 | final TLE tle = new TLE(LEO_TLE);
145 | assertThat(tle.isDeepspace()).isFalse();
146 |
147 | final PassPredictor passPredictor = new PassPredictor(tle,
148 | GROUND_STATION);
149 | final DateTime cal = new DateTime(DATE_2009_01_05T04_30_00Z);
150 | final SatPassTime passTime = passPredictor.nextSatPass(
151 | cal.toDate(), true);
152 |
153 | assertThat(passTime.toString()).isEqualTo("Date: January 5, 2009\n" + "Start Time: 4:28 AM\n"
154 | + "Duration: 4.1 min.\n" + "AOS Azimuth: 52 deg.\n"
155 | + "Max Elevation: 0.9 deg.\n" + "LOS Azimuth: 84 deg.");
156 | }
157 |
158 | /**
159 | * test to determine if the antenna would track through a pole during a pass
160 | */
161 | @Test
162 | public void poleIsPassed() throws SatNotFoundException {
163 | final TLE tle = new TLE(LEO_TLE);
164 | assertThat(tle.isDeepspace()).isFalse();
165 |
166 | final PassPredictor passPredictor = new PassPredictor(tle,
167 | GROUND_STATION);
168 | DateTime cal = new DateTime(DATE_2009_01_05T07_00_00Z);
169 |
170 | boolean northFound = false;
171 | boolean southFound = false;
172 |
173 | for (int minute = 0; minute < 60 * 24 * 7; minute++) {
174 | final long startTime = cal.toDate().getTime();
175 | if (northFound && southFound) {
176 | break;
177 | }
178 | final SatPassTime passTime = passPredictor.nextSatPass(cal
179 | .toDate());
180 | final long endTime = passTime.getEndTime().getTime();
181 | final String polePassed = passTime.getPolePassed();
182 | if (!polePassed.equals(NONE)) {
183 | if (!northFound && polePassed.equals(NORTH)) {
184 | assertThat(String.format(STRING_PAIR, TZ_FORMAT
185 | .format(passTime.getStartTime()),
186 | polePassed)).isEqualTo("2009-01-05T07:42:45+0000, north");
187 | northFound = true;
188 |
189 | minute += (int) ((endTime - startTime) / 60000);
190 | } else if (!southFound && polePassed.equals("south")) {
191 | assertThat(String.format(STRING_PAIR, TZ_FORMAT
192 | .format(passTime.getStartTime()),
193 | polePassed)).isEqualTo("2009-01-06T07:03:20+0000, south");
194 | southFound = true;
195 |
196 | minute += (int) ((endTime - startTime) / 60000);
197 | }
198 | }
199 |
200 | cal = cal.plusMinutes(minute);
201 | }
202 | }
203 |
204 | @Test
205 | public void testGetPassList() throws SatNotFoundException {
206 | final TLE tle = new TLE(LEO_TLE);
207 | assertThat(tle.isDeepspace()).isFalse();
208 |
209 | final PassPredictor passPredictor = new PassPredictor(tle,
210 | GROUND_STATION);
211 | final DateTime start = new DateTime(DATE_2009_01_05T07_00_00Z);
212 |
213 | final List passed = passPredictor.getPasses(
214 | start.toDate(), 24, false);
215 | assertThat(passed).hasSize(10);
216 | }
217 |
218 | @Test
219 | public void testGetPassListWithWindBack() throws SatNotFoundException {
220 | final TLE tle = new TLE(LEO_TLE);
221 | assertThat(tle.isDeepspace()).isFalse();
222 |
223 | final PassPredictor passPredictor = new PassPredictor(tle,
224 | GROUND_STATION);
225 | final DateTime start = new DateTime(DATE_2009_01_05T07_00_00Z);
226 |
227 | final List passes = passPredictor.getPasses(
228 | start.toDate(), 24, true);
229 | assertThat(passes).hasSize(10);
230 | assertThat(passPredictor.getIterationCount()).isEqualTo(1039);
231 | }
232 |
233 | @Test
234 | public void testGetSatelliteTrack() throws SatNotFoundException {
235 | final TLE tle = new TLE(LEO_TLE);
236 |
237 | assertThat(tle.isDeepspace()).isFalse();
238 |
239 | final PassPredictor passPredictor = new PassPredictor(tle,
240 | GROUND_STATION);
241 | final DateTime referenceDate = new DateTime(DATE_2009_01_05T07_00_00Z);
242 | final int incrementSeconds = 30;
243 | final int minutesBefore = 50;
244 | final int minutesAfter = 50;
245 | final List positions = passPredictor.getPositions(
246 | referenceDate.toDate(), incrementSeconds, minutesBefore,
247 | minutesAfter);
248 | assertThat(positions).hasSize(200);
249 |
250 | }
251 |
252 | }
253 |
--------------------------------------------------------------------------------
/src/test/java/com/github/amsacode/predict4java/SatNotFoundExceptionTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | predict4java: An SDP4 / SGP4 library for satellite orbit predictions
3 |
4 | Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
5 |
6 | Author: David A. B. Johnson, G4DPZ
7 |
8 | Comments, questions and bug reports should be submitted via
9 | http://sourceforge.net/projects/websat/
10 | More details can be found at the project home page:
11 |
12 | http://websat.sourceforge.net
13 |
14 | This program is free software; you can redistribute it and/or modify
15 | it under the terms of the GNU General Public License as published by
16 | the Free Software Foundation; either version 2 of the License, or
17 | (at your option) any later version.
18 |
19 | This program is distributed in the hope that it will be useful,
20 | but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | GNU General Public License for more details.
23 |
24 | You should have received a copy of the GNU General Public License
25 | along with this program; if not, visit http://www.fsf.org/
26 | */
27 | package com.github.amsacode.predict4java;
28 |
29 | import org.junit.Test;
30 |
31 | public final class SatNotFoundExceptionTest {
32 |
33 | @Test
34 | public void testInstantiation() {
35 | new SatNotFoundException("boo");
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/test/java/com/github/amsacode/predict4java/SatPassTimeTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | predict4java: An SDP4 / SGP4 library for satellite orbit predictions
3 |
4 | Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
5 |
6 | Author: David A. B. Johnson, G4DPZ
7 |
8 | Comments, questions and bug reports should be submitted via
9 | http://sourceforge.net/projects/websat/
10 | More details can be found at the project home page:
11 |
12 | http://websat.sourceforge.net
13 |
14 | This program is free software; you can redistribute it and/or modify
15 | it under the terms of the GNU General Public License as published by
16 | the Free Software Foundation; either version 2 of the License, or
17 | (at your option) any later version.
18 |
19 | This program is distributed in the hope that it will be useful,
20 | but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | GNU General Public License for more details.
23 |
24 | You should have received a copy of the GNU General Public License
25 | along with this program; if not, visit http://www.fsf.org/
26 | */
27 | package com.github.amsacode.predict4java;
28 |
29 | import static org.assertj.core.api.Assertions.assertThat;
30 |
31 | import java.util.Date;
32 |
33 | import org.junit.Test;
34 |
35 | /**
36 | * @author David A. B. Johnson, g4dpz
37 | */
38 | public final class SatPassTimeTest {
39 |
40 | private static final int PERIOD_MS = 1000;
41 |
42 | // @Test
43 | // public void testSatPassTime() {
44 | // // Assert.assertTrue(TestUtil.verifyMutable(new SatPassTime(),
45 | // // "./src/uk/me/g4dpz/satellite/SatPassTime.java", 0));
46 | // }
47 |
48 | @Test
49 | public void testConstructor() {
50 | Date start = new Date();
51 | Date end = new Date(start.getTime() + PERIOD_MS);
52 | SatPassTime s = new SatPassTime(start, end, "passed", 1, 2, 3.0);
53 | assertThat(s.getTCA().getTime()).isEqualTo(start.getTime() + PERIOD_MS / 2);
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/test/java/com/github/amsacode/predict4java/SatPosTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | predict4java: An SDP4 / SGP4 library for satellite orbit predictions
3 |
4 | Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
5 |
6 | Author: David A. B. Johnson, G4DPZ
7 |
8 | Comments, questions and bug reports should be submitted via
9 | http://sourceforge.net/projects/websat/
10 | More details can be found at the project home page:
11 |
12 | http://websat.sourceforge.net
13 |
14 | This program is free software; you can redistribute it and/or modify
15 | it under the terms of the GNU General Public License as published by
16 | the Free Software Foundation; either version 2 of the License, or
17 | (at your option) any later version.
18 |
19 | This program is distributed in the hope that it will be useful,
20 | but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | GNU General Public License for more details.
23 |
24 | You should have received a copy of the GNU General Public License
25 | along with this program; if not, visit http://www.fsf.org/
26 | */
27 | package com.github.amsacode.predict4java;
28 |
29 | import static com.github.amsacode.predict4java.TestingUtil.eq;
30 | import static org.assertj.core.api.Assertions.assertThat;
31 |
32 | import java.util.Date;
33 | import java.util.List;
34 |
35 | import org.assertj.core.data.Offset;
36 | import org.junit.Test;
37 |
38 | /**
39 | * @author David A. B. Johnson, g4dpz
40 | */
41 | public final class SatPosTest {
42 |
43 | private static final Offset PRECISION = Offset.offset(0.00001);
44 | private static final double ROUNDING_PRECISION = 0.5;
45 |
46 | // @Test
47 | // public void testSatPos() {
48 | // // Assert.assertTrue(TestUtil.verifyMutable(new SatPos(),
49 | // // "./src/uk/me/g4dpz/satellite/SatPos.java", 0));
50 | // }
51 |
52 | @Test
53 | public void footprintCalculatedCorrectly() {
54 | final SatPos pos = new SatPos();
55 | pos.setLatitude(0);
56 | pos.setLongitude(0);
57 | pos.setAltitude(1000);
58 | List rangeCircle = pos.getRangeCircle();
59 | assertThat(eq(rangeCircle.get(0), 30, 0, ROUNDING_PRECISION)).isTrue();
60 | assertThat(eq(rangeCircle.get(89), 1, 330, ROUNDING_PRECISION)).isTrue();
61 | assertThat(eq(rangeCircle.get(179), -30, 359, ROUNDING_PRECISION)).isTrue();
62 | assertThat(eq(rangeCircle.get(269), -1, 30, ROUNDING_PRECISION)).isTrue();
63 |
64 | pos.setLatitude(10.0 / 360.0 * 2.0 * Math.PI);
65 | pos.setLongitude(10.0 / 360.0 * 2.0 * Math.PI);
66 | pos.setAltitude(1000);
67 | rangeCircle = pos.getRangeCircle();
68 | assertThat(eq(rangeCircle.get(0), 40, 10, ROUNDING_PRECISION)).isTrue();
69 | assertThat(eq(rangeCircle.get(89), 9, 339, ROUNDING_PRECISION)).isTrue();
70 | assertThat(eq(rangeCircle.get(179), -20, 9, ROUNDING_PRECISION)).isTrue();
71 | assertThat(eq(rangeCircle.get(269), 8, 41, ROUNDING_PRECISION)).isTrue();
72 |
73 | }
74 |
75 | @Test
76 | public void testSatPosConstructor() {
77 | Date now = new Date();
78 | SatPos pos = new SatPos(1, 2, now);
79 | assertThat(pos.getAzimuth()).isEqualTo(1.0, PRECISION);
80 | assertThat(pos.getElevation()).isEqualTo(2.0, PRECISION);
81 | assertThat(pos.getTime().getTime()).isEqualTo(now.getTime());
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/src/test/java/com/github/amsacode/predict4java/SatelliteFactoryTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | predict4java: An SDP4 / SGP4 library for satellite orbit predictions
3 |
4 | Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
5 |
6 | Author: David A. B. Johnson, G4DPZ
7 |
8 | Comments, questions and bug reports should be submitted via
9 | http://sourceforge.net/projects/websat/
10 | More details can be found at the project home page:
11 |
12 | http://websat.sourceforge.net
13 |
14 | This program is free software; you can redistribute it and/or modify
15 | it under the terms of the GNU General Public License as published by
16 | the Free Software Foundation; either version 2 of the License, or
17 | (at your option) any later version.
18 |
19 | This program is distributed in the hope that it will be useful,
20 | but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | GNU General Public License for more details.
23 |
24 | You should have received a copy of the GNU General Public License
25 | along with this program; if not, visit http://www.fsf.org/
26 | */
27 | package com.github.amsacode.predict4java;
28 |
29 | import static org.assertj.core.api.Assertions.assertThat;
30 |
31 | import java.lang.reflect.Constructor;
32 | import java.lang.reflect.InvocationTargetException;
33 |
34 | import org.junit.Test;
35 |
36 | /**
37 | * @author David A. B. Johnson, g4dpz
38 | */
39 | public final class SatelliteFactoryTest extends AbstractSatelliteTestBase {
40 |
41 | @Test
42 | public void testCreateLEOSatellite() {
43 | final TLE tle = new TLE(LEO_TLE);
44 | final Satellite satellite = SatelliteFactory.createSatellite(tle);
45 | assertThat(satellite).isInstanceOf(LEOSatellite.class);
46 | }
47 |
48 | @Test
49 | public void testCreateDeepSpaceSatellite() {
50 | final TLE tle = new TLE(DEEP_SPACE_TLE);
51 | final Satellite satellite = SatelliteFactory.createSatellite(tle);
52 | assertThat(satellite).isInstanceOf(DeepSpaceSatellite.class);
53 | }
54 |
55 | @Test(expected = IllegalArgumentException.class)
56 | public void testNullTLE() {
57 | SatelliteFactory.createSatellite(null);
58 | }
59 |
60 | @Test(expected = IllegalArgumentException.class)
61 | public void testTLEWithWrongNumberOfRows() {
62 | final String[] theTLE = new String[0];
63 | final TLE tle = new TLE(theTLE);
64 | SatelliteFactory.createSatellite(tle);
65 | }
66 |
67 | @Test
68 | public void testPrivateConstructorForCoverage() throws NoSuchMethodException, IllegalAccessException,
69 | InvocationTargetException, InstantiationException {
70 | Constructor constructor = SatelliteFactory.class
71 | .getDeclaredConstructor();
72 | assertThat(constructor.isAccessible()).isFalse();
73 | constructor.setAccessible(true);
74 | constructor.newInstance();
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/test/java/com/github/amsacode/predict4java/TLETest.java:
--------------------------------------------------------------------------------
1 | /**
2 | predict4java: An SDP4 / SGP4 library for satellite orbit predictions
3 |
4 | Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
5 |
6 | Author: David A. B. Johnson, G4DPZ
7 |
8 | Comments, questions and bug reports should be submitted via
9 | http://sourceforge.net/projects/websat/
10 | More details can be found at the project home page:
11 |
12 | http://websat.sourceforge.net
13 |
14 | This program is free software; you can redistribute it and/or modify
15 | it under the terms of the GNU General Public License as published by
16 | the Free Software Foundation; either version 2 of the License, or
17 | (at your option) any later version.
18 |
19 | This program is distributed in the hope that it will be useful,
20 | but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | GNU General Public License for more details.
23 |
24 | You should have received a copy of the GNU General Public License
25 | along with this program; if not, visit http://www.fsf.org/
26 | */
27 | package com.github.amsacode.predict4java;
28 |
29 | import static org.assertj.core.api.Assertions.assertThat;
30 |
31 | import java.io.IOException;
32 | import java.io.InputStream;
33 | import java.util.List;
34 |
35 | import org.junit.Test;
36 |
37 | /**
38 | * @author David A. B. Johnson, g4dpz
39 | */
40 | public final class TLETest extends AbstractSatelliteTestBase {
41 |
42 | private static final String VALUE_0_0000 = "0.0000";
43 | private static final String VALUE_0_0084159 = "0.0084159";
44 | private static final String FORMAT_6_4F = "%6.4f";
45 | private static final String TLELINE_3 = "2 28375 98.0821 101.6821 0084935 88.2048 272.8868 14.40599338194363";
46 | private static final String FORMAT_9_7F = "%9.7f";
47 | private static final String FORMAT_10_7F = "%10.7f";
48 | private static final String FORMAT_11_7F = "%11.7f";
49 | private static final String AO_51_NAME = "AO-51 [+]";
50 |
51 | @Test
52 | public void testTLEReadLEO() {
53 | final TLE tle = new TLE(LEO_TLE);
54 | checkData(tle);
55 | }
56 |
57 | @Test
58 | public void testCopyConstructor() {
59 | final TLE tle = new TLE(LEO_TLE);
60 | final TLE tleCopy = new TLE(tle);
61 | checkData(tleCopy);
62 | }
63 |
64 | @Test
65 | public void testTLEReadDeepSpace() {
66 | final String[] theTLE = {
67 | "AO-40",
68 | "1 26609U 00072B 00326.22269097 -.00000581 00000-0 00000+0 0 29",
69 | "2 26609 6.4279 245.5626 7344055 179.5891 182.1915 2.03421959 104"};
70 | final TLE tle = new TLE(theTLE);
71 | assertThat(tle.isDeepspace()).isTrue();
72 | }
73 |
74 | @Test(expected = IllegalArgumentException.class)
75 | public void testForNullDataInTLE() {
76 | final String[] theTLE = {AO_51_NAME, null, TLELINE_3};
77 | new TLE(theTLE);
78 | }
79 |
80 | @Test(expected = IllegalArgumentException.class)
81 | public void testForBlankDataInTLE() {
82 | final String[] theTLE = {AO_51_NAME, "", TLELINE_3};
83 | new TLE(theTLE);
84 | }
85 |
86 | @Test(expected = IllegalArgumentException.class)
87 | public void testForNoDataInTLE() {
88 | final String[] theTLE = new String[0];
89 | new TLE(theTLE);
90 | }
91 |
92 | @Test
93 | public void testLoadFromResource() throws IOException {
94 | InputStream is = TLETest.class.getResourceAsStream("/LEO.txt");
95 | final List tles = TLE.importSat(is);
96 | assertThat(tles).hasSize(1);
97 | checkData(tles.get(0));
98 | }
99 |
100 | @Test(expected = IllegalArgumentException.class)
101 | public void testNullArrayPassedToTLEConstructorThrowsIllegalArgumentException() {
102 | new TLE((String[]) null);
103 | }
104 |
105 | private void checkData(final TLE tle) {
106 | assertThat(tle.getName()).isEqualTo(AO_51_NAME);
107 | assertThat(tle.toString()).isEqualTo(AO_51_NAME);
108 | assertThat(tle.getCatnum()).isEqualTo(28375);
109 | assertThat(tle.getSetnum()).isEqualTo(364);
110 | assertThat(tle.getYear()).isEqualTo(9);
111 | assertThat(String.format(FORMAT_11_7F, tle.getRefepoch())).isEqualTo("105.6639197");
112 | assertThat(String.format(FORMAT_10_7F, tle.getIncl())).isEqualTo("98.0551000");
113 | assertThat(String.format(FORMAT_11_7F, tle.getRaan())).isEqualTo("118.9086000");
114 | assertThat(String.format(FORMAT_9_7F, tle.getEccn())).isEqualTo(VALUE_0_0084159);
115 | assertThat(String.format(FORMAT_10_7F, tle.getArgper())).isEqualTo("315.8041000");
116 | assertThat(String.format(FORMAT_11_7F, tle.getMeanan())).isEqualTo(" 43.6444000");
117 | assertThat(String.format(FORMAT_10_7F, tle.getMeanmo())).isEqualTo("14.4063845");
118 | assertThat(String.format(FORMAT_6_4F, tle.getDrag())).isEqualTo(VALUE_0_0000);
119 | assertThat(String.format(FORMAT_6_4F, tle.getNddot6())).isEqualTo(VALUE_0_0000);
120 | assertThat(String.format(FORMAT_9_7F, tle.getBstar())).isEqualTo("0.0000138");
121 | assertThat(tle.getOrbitnum()).isEqualTo(25195);
122 | assertThat(String.format("%12.7f", tle.getEpoch())).isEqualTo("9105.6639197");
123 | assertThat(String.format(FORMAT_9_7F, tle.getXndt2o())).isEqualTo("0.0000000");
124 | assertThat(String.format(FORMAT_9_7F, tle.getXincl())).isEqualTo("1.7113843");
125 | assertThat(String.format(FORMAT_9_7F, tle.getXnodeo())).isEqualTo("2.0753466");
126 | assertThat(String.format(FORMAT_9_7F, tle.getEo())).isEqualTo(VALUE_0_0084159);
127 | assertThat(String.format(FORMAT_9_7F, tle.getOmegao())).isEqualTo("5.5118213");
128 | assertThat(String.format(FORMAT_9_7F, tle.getXmo())).isEqualTo("0.7617385");
129 | assertThat(String.format("%8.6f", tle.getXno())).isEqualTo("0.062860");
130 | assertThat(tle.isDeepspace()).isFalse();
131 | }
132 |
133 | }
134 |
--------------------------------------------------------------------------------
/src/test/java/com/github/amsacode/predict4java/TestingUtil.java:
--------------------------------------------------------------------------------
1 | package com.github.amsacode.predict4java;
2 |
3 | public class TestingUtil {
4 |
5 | public static boolean eq(Position position, double lat, double lon, double precision) {
6 | return Math.abs(position.getLat() - lat) <= precision
7 | && Math.abs(position.getLon() - lon) <= precision;
8 | }
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/test/java/com/github/amsacode/predict4java/Vector4Test.java:
--------------------------------------------------------------------------------
1 | /**
2 | predict4java: An SDP4 / SGP4 library for satellite orbit predictions
3 |
4 | Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
5 |
6 | Author: David A. B. Johnson, G4DPZ
7 |
8 | Comments, questions and bug reports should be submitted via
9 | http://sourceforge.net/projects/websat/
10 | More details can be found at the project home page:
11 |
12 | http://websat.sourceforge.net
13 |
14 | This program is free software; you can redistribute it and/or modify
15 | it under the terms of the GNU General Public License as published by
16 | the Free Software Foundation; either version 2 of the License, or
17 | (at your option) any later version.
18 |
19 | This program is distributed in the hope that it will be useful,
20 | but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | GNU General Public License for more details.
23 |
24 | You should have received a copy of the GNU General Public License
25 | along with this program; if not, visit http://www.fsf.org/
26 | */
27 | package com.github.amsacode.predict4java;
28 |
29 | import static org.assertj.core.api.Assertions.assertThat;
30 |
31 | import org.assertj.core.data.Offset;
32 | import org.junit.Test;
33 |
34 | import com.github.amsacode.predict4java.AbstractSatellite.Vector4;
35 |
36 | public final class Vector4Test {
37 |
38 | private static final Offset PRECISION = Offset.offset(0.00001);
39 |
40 | @Test
41 | public void testSubtract() {
42 | Vector4 v1 = new Vector4(1, 2, 3, 4);
43 | Vector4 v2 = new Vector4(0.1, 0.2, 0.3, 0.4);
44 | Vector4 v3 = v1.subtract(v2);
45 | assertThat(v3.getW()).isEqualTo(0.9, PRECISION);
46 | assertThat(v3.getX()).isEqualTo(1.8, PRECISION);
47 | assertThat(v3.getY()).isEqualTo(2.7, PRECISION);
48 | assertThat(v3.getZ()).isEqualTo(3.6, PRECISION);
49 |
50 | }
51 |
52 | @Test
53 | public void testToString() {
54 | Vector4 v1 = new Vector4(1, 2, 3, 4);
55 | assertThat(v1.toString()).isNotNull();
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/test/resources/LEO.txt:
--------------------------------------------------------------------------------
1 | AO-51 [+]
2 | 1 28375U 04025K 09105.66391970 .00000003 00000-0 13761-4 0 3643
3 | 2 28375 098.0551 118.9086 0084159 315.8041 043.6444 14.40638450251959
--------------------------------------------------------------------------------
/src/test/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | #log4j.rootLogger=error, console
2 |
3 | log4j.category.uk.me.g4dpz.satellite=debug, console
4 |
5 | log4j.appender.console=org.apache.log4j.ConsoleAppender
6 | log4j.appender.console.Target=System.out
7 | log4j.appender.console.layout=org.apache.log4j.PatternLayout
8 | log4j.appender.console.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
9 |
10 |
--------------------------------------------------------------------------------