mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
Converted the PassPredictor class to Kotlin. Removed the class reference to Apache Commons Logging library which was causing an error during the code minification.
This commit is contained in:
1 parent
f094d02ed0
commit
24cc767085
1 file changed
+239
@@ -0,0 +1,239 @@
|
||||
/**
|
||||
* predict4java: An SDP4 / SGP4 library for satellite orbit predictions
|
||||
*
|
||||
* Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
|
||||
*
|
||||
* This class is a Java port of one of the core elements of
|
||||
* the Predict program, Copyright John A. Magliacane,
|
||||
* KD2BD 1991-2003: http://www.qsl.net/kd2bd/predict.html
|
||||
*
|
||||
* Dr. T.S. Kelso is the author of the SGP4/SDP4 orbital models,
|
||||
* originally written in Fortran and Pascal, and released into the
|
||||
* public domain through his website (http://www.celestrak.com/).
|
||||
* Neoklis Kyriazis, 5B4AZ, later re-wrote Dr. Kelso's code in C,
|
||||
* and released it under the GNU GPL in 2002.
|
||||
* PREDICT's core is based on 5B4AZ's code translation efforts.
|
||||
*
|
||||
* Author: David A. B. Johnson, G4DPZ <dave></dave>@g4dpz.me.uk>
|
||||
*
|
||||
* Comments, questions and bugreports should be submitted via
|
||||
* http://sourceforge.net/projects/websat/
|
||||
* More details can be found at the project home page:
|
||||
*
|
||||
* http://websat.sourceforge.net
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, visit http://www.fsf.org/
|
||||
*/
|
||||
package com.rtbishop.look4sat.predict4kotlin
|
||||
|
||||
import com.github.amsacode.predict4java.*
|
||||
import java.util.*
|
||||
|
||||
class PassPredictor(private val tle: TLE, private val qth: GroundStationPosition) {
|
||||
private val sat: Satellite = SatelliteFactory.createSatellite(tle)
|
||||
private val south = "south"
|
||||
private val north = "north"
|
||||
private val deadSpotNone = "none"
|
||||
private val speedOfLight = 2.99792458E8
|
||||
private val twoPi = Math.PI * 2.0
|
||||
private val timeZone: TimeZone = TimeZone.getTimeZone("UTC")
|
||||
private var iterationCount = 0
|
||||
|
||||
fun getDownlinkFreq(freq: Long, date: Date): Long {
|
||||
val cal = Calendar.getInstance(timeZone).apply {
|
||||
clear()
|
||||
timeInMillis = date.time
|
||||
}
|
||||
val satPos = getSatPos(cal.time)
|
||||
val rangeRate = satPos.rangeRate
|
||||
return (freq.toDouble() * (speedOfLight - rangeRate * 1000.0) / speedOfLight).toLong()
|
||||
}
|
||||
|
||||
fun getUplinkFreq(freq: Long, date: Date): Long {
|
||||
val cal = Calendar.getInstance(timeZone).apply {
|
||||
clear()
|
||||
timeInMillis = date.time
|
||||
}
|
||||
val satPos = getSatPos(cal.time)
|
||||
val rangeRate = satPos.rangeRate
|
||||
return (freq.toDouble() * (speedOfLight + rangeRate * 1000.0) / speedOfLight).toLong()
|
||||
}
|
||||
|
||||
fun getSatPos(time: Date): SatPos {
|
||||
iterationCount++
|
||||
return sat.getPosition(qth, time)
|
||||
}
|
||||
|
||||
fun getPositions(
|
||||
referenceDate: Date,
|
||||
incrementSeconds: Int,
|
||||
minutesBefore: Int,
|
||||
minutesAfter: Int
|
||||
): List<SatPos> {
|
||||
val positions: MutableList<SatPos> = ArrayList()
|
||||
val endDateDate = Date(referenceDate.time + minutesAfter * 60L * 1000L)
|
||||
var trackDate = Date(referenceDate.time - minutesBefore * 60L * 1000L)
|
||||
|
||||
while (trackDate.before(endDateDate)) {
|
||||
positions.add(getSatPos(trackDate))
|
||||
trackDate = Date(trackDate.time + incrementSeconds * 1000)
|
||||
}
|
||||
|
||||
return positions
|
||||
}
|
||||
|
||||
fun getPasses(start: Date, hoursAhead: Int, windBack: Boolean): List<SatPassTime> {
|
||||
iterationCount = 0
|
||||
|
||||
val passes: MutableList<SatPassTime> = ArrayList()
|
||||
val trackEndDate = Date(start.time + hoursAhead * 60L * 60L * 1000L)
|
||||
var trackStartDate = start
|
||||
var windBackTime = windBack
|
||||
var lastAOS: Date
|
||||
var count = 0
|
||||
|
||||
do {
|
||||
if (count > 0) windBackTime = false
|
||||
val pass = nextSatPass(trackStartDate, windBackTime)
|
||||
lastAOS = pass.startTime
|
||||
passes.add(pass)
|
||||
trackStartDate = Date(pass.endTime.time + threeQuarterOrbitMinutes() * 60L * 1000L)
|
||||
count++
|
||||
} while (lastAOS < trackEndDate)
|
||||
|
||||
return passes
|
||||
}
|
||||
|
||||
private fun nextSatPass(date: Date, windBack: Boolean = false): SatPassTime {
|
||||
val aosAzimuth: Int
|
||||
val losAzimuth: Int
|
||||
var maxElevation = 0.0
|
||||
var elevation: Double
|
||||
var prevPos: SatPos
|
||||
var tca: Date? = null
|
||||
var polePassed = deadSpotNone
|
||||
|
||||
// get the current position
|
||||
val cal = Calendar.getInstance(timeZone).apply {
|
||||
clear()
|
||||
timeInMillis = date.time
|
||||
}
|
||||
|
||||
// wind back time 1/4 of an orbit
|
||||
if (windBack) {
|
||||
val meanMotion = tle.meanmo
|
||||
cal.add(Calendar.MINUTE, (-24.0 * 60.0 / meanMotion / 4.0).toInt())
|
||||
}
|
||||
var satPos = getSatPos(cal.time)
|
||||
|
||||
// test for the elevation being above the horizon
|
||||
if (satPos.elevation > 0.0) {
|
||||
// move time forward in 30 second intervals until the sat goes below the horizon
|
||||
do {
|
||||
satPos = getPosition(cal, 60)
|
||||
} while (satPos.elevation > 0.0)
|
||||
// move time forward 3/4 orbit
|
||||
cal.add(Calendar.MINUTE, threeQuarterOrbitMinutes())
|
||||
}
|
||||
|
||||
// now find the next time it comes above the horizon
|
||||
do {
|
||||
satPos = getPosition(cal, 60)
|
||||
val now = cal.time
|
||||
elevation = satPos.elevation
|
||||
if (elevation > maxElevation) {
|
||||
maxElevation = elevation
|
||||
tca = now
|
||||
}
|
||||
} while (satPos.elevation < 0.0)
|
||||
|
||||
// refine it to 5 seconds
|
||||
cal.add(Calendar.SECOND, -60)
|
||||
do {
|
||||
satPos = getPosition(cal, 5)
|
||||
val now = cal.time
|
||||
elevation = satPos.elevation
|
||||
if (elevation > maxElevation) {
|
||||
maxElevation = elevation
|
||||
tca = now
|
||||
}
|
||||
prevPos = satPos
|
||||
} while (satPos.elevation < 0.0)
|
||||
val startDate = satPos.time
|
||||
aosAzimuth = (satPos.azimuth / (2.0 * Math.PI) * 360.0).toInt()
|
||||
|
||||
// now find when it goes below
|
||||
do {
|
||||
satPos = getPosition(cal, 30)
|
||||
val now = cal.time
|
||||
val currPolePassed = getPolePassed(prevPos, satPos)
|
||||
if (currPolePassed != deadSpotNone) {
|
||||
polePassed = currPolePassed
|
||||
}
|
||||
elevation = satPos.elevation
|
||||
if (elevation > maxElevation) {
|
||||
maxElevation = elevation
|
||||
tca = now
|
||||
}
|
||||
prevPos = satPos
|
||||
} while (satPos.elevation > 0.0)
|
||||
|
||||
// refine it to 5 seconds
|
||||
cal.add(Calendar.SECOND, -30)
|
||||
do {
|
||||
satPos = getPosition(cal, 5)
|
||||
val now = cal.time
|
||||
elevation = satPos.elevation
|
||||
if (elevation > maxElevation) {
|
||||
maxElevation = elevation
|
||||
tca = now
|
||||
}
|
||||
} while (satPos.elevation > 0.0)
|
||||
|
||||
val endDate = satPos.time
|
||||
losAzimuth = (satPos.azimuth / (2.0 * Math.PI) * 360.0).toInt()
|
||||
|
||||
return SatPassTime(
|
||||
startDate, endDate, tca, polePassed, aosAzimuth,
|
||||
losAzimuth, maxElevation / (2.0 * Math.PI) * 360.0
|
||||
)
|
||||
}
|
||||
|
||||
private fun getPosition(cal: Calendar, offSet: Int): SatPos {
|
||||
cal.add(Calendar.SECOND, offSet)
|
||||
return getSatPos(cal.time)
|
||||
}
|
||||
|
||||
private fun getPolePassed(prevPos: SatPos, satPos: SatPos): String {
|
||||
var polePassed = deadSpotNone
|
||||
val az1 = prevPos.azimuth / twoPi * 360.0
|
||||
val az2 = satPos.azimuth / twoPi * 360.0
|
||||
if (az1 > az2) { // we may be moving from 350 or greater through north
|
||||
if (az1 > 350 && az2 < 10) polePassed = north
|
||||
else { // we may be moving from 190 or greater through south
|
||||
if (az1 > 180 && az2 < 180) polePassed = south
|
||||
}
|
||||
} else { // we may be moving from 10 or less through north
|
||||
if (az1 < 10 && az2 > 350) polePassed = north
|
||||
else { // we may be moving from 170 or more through south
|
||||
if (az1 < 180 && az2 > 180) polePassed = south
|
||||
}
|
||||
}
|
||||
return polePassed
|
||||
}
|
||||
|
||||
private fun threeQuarterOrbitMinutes(): Int {
|
||||
return (24.0 * 60.0 / tle.meanmo * 0.75).toInt()
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user