kopia lustrzana https://github.com/rt-bishop/Look4Sat
Various changes to predict4kotlin classes
rodzic
5460ed2a6c
commit
dc92bf1ab1
|
@ -154,7 +154,7 @@ class SatMapViewModel @Inject constructor(
|
|||
|
||||
private suspend fun setSelectedSatFootprint(sat: Satellite, gsp: StationPosition, date: Date) {
|
||||
withContext(defaultDispatcher) {
|
||||
val satFootprint = sat.getPosition(gsp, date).getRangeCircle().map { rangePos ->
|
||||
val satFootprint = sat.getPredictor(gsp).getRangeCircle(date).map { rangePos ->
|
||||
val osmLat = clipLat(rangePos.latitude)
|
||||
val osmLon = clipLon(rangePos.longitude)
|
||||
Position(osmLat, osmLon)
|
||||
|
|
|
@ -18,11 +18,50 @@
|
|||
package com.rtbishop.look4sat.domain.predict4kotlin
|
||||
|
||||
import java.util.*
|
||||
import kotlin.math.*
|
||||
|
||||
class PassPredictor(private val satellite: Satellite, private val stationPos: StationPosition) {
|
||||
|
||||
private val oneQuarterOrbitMin = (24.0 * 60.0 / satellite.tle.meanmo / 4.0).toInt()
|
||||
private val speedOfLight = 2.99792458E8
|
||||
private val earthRadiusKm = 6378.16
|
||||
|
||||
fun getRangeCircle(date: Date): List<Position> {
|
||||
val satPos = getSatPos(date)
|
||||
val positions = mutableListOf<Position>()
|
||||
val lat = satPos.latitude
|
||||
val lon = satPos.longitude
|
||||
// rangeCircleRadiusKm
|
||||
// earthRadiusKm * acos(earthRadiusKm / (earthRadiusKm + satPos.altitude))
|
||||
val beta = acos(earthRadiusKm / (earthRadiusKm + satPos.altitude))
|
||||
var tempAzimuth = 0
|
||||
while (tempAzimuth < 360) {
|
||||
val azimuth = tempAzimuth / 360.0 * 2.0 * Math.PI
|
||||
var rangelat = asin(sin(lat) * cos(beta) + cos(azimuth) * sin(beta) * cos(lat))
|
||||
val num = (cos(beta) - (sin(lat) * sin(rangelat)))
|
||||
val den = cos(lat) * cos(rangelat)
|
||||
var rangelon = if (tempAzimuth == 0 && (beta > ((Math.PI / 2.0) - lat))) {
|
||||
lon + Math.PI
|
||||
} else if (tempAzimuth == 180 && (beta > ((Math.PI / 2.0) - lat))) {
|
||||
lon + Math.PI
|
||||
} else if (abs(num / den) > 1.0) {
|
||||
lon
|
||||
} else {
|
||||
if ((180 - tempAzimuth) >= 0) {
|
||||
lon - acos(num / den)
|
||||
} else {
|
||||
lon + acos(num / den)
|
||||
}
|
||||
}
|
||||
while (rangelon < 0.0) rangelon += Math.PI * 2.0
|
||||
while (rangelon > Math.PI * 2.0) rangelon -= Math.PI * 2.0
|
||||
rangelat = Math.toDegrees(rangelat)
|
||||
rangelon = Math.toDegrees(rangelon)
|
||||
positions.add(Position(rangelat, rangelon))
|
||||
tempAzimuth += 1
|
||||
}
|
||||
return positions
|
||||
}
|
||||
|
||||
fun getDownlinkFreq(freq: Long, date: Date): Long {
|
||||
val rangeRate = getSatPos(date).rangeRate
|
||||
|
|
|
@ -18,58 +18,15 @@
|
|||
package com.rtbishop.look4sat.domain.predict4kotlin
|
||||
|
||||
import java.util.*
|
||||
import kotlin.math.*
|
||||
|
||||
class SatPos {
|
||||
|
||||
private val earthRadiusKm = 6378.16
|
||||
|
||||
// Radians
|
||||
var azimuth = 0.0
|
||||
var elevation = 0.0
|
||||
var latitude = 0.0
|
||||
var longitude = 0.0
|
||||
var altitude = 0.0
|
||||
var range = 0.0
|
||||
var rangeRate = 0.0
|
||||
var theta = 0.0
|
||||
var time = Date()
|
||||
|
||||
fun getRangeCircleRadiusKm(): Double {
|
||||
return earthRadiusKm * acos(earthRadiusKm / (earthRadiusKm + altitude))
|
||||
}
|
||||
|
||||
fun getRangeCircle(incrementDegrees: Double = 1.0): List<Position> {
|
||||
val positions = mutableListOf<Position>()
|
||||
val lat = this.latitude
|
||||
val lon = this.longitude
|
||||
val beta = getRangeCircleRadiusKm() / earthRadiusKm
|
||||
var tempAzimuth = 0
|
||||
while (tempAzimuth < 360) {
|
||||
val azimuth = tempAzimuth / 360.0 * 2.0 * Math.PI
|
||||
var rangelat = asin(sin(lat) * cos(beta) + cos(azimuth) * sin(beta) * cos(lat))
|
||||
val num = (cos(beta) - (sin(lat) * sin(rangelat)))
|
||||
val den = cos(lat) * cos(rangelat)
|
||||
var rangelon = if (tempAzimuth == 0 && (beta > ((Math.PI / 2.0) - lat))) {
|
||||
lon + Math.PI
|
||||
} else if (tempAzimuth == 180 && (beta > ((Math.PI / 2.0) - lat))) {
|
||||
lon + Math.PI
|
||||
} else if (abs(num / den) > 1.0) {
|
||||
lon
|
||||
} else {
|
||||
if ((180 - tempAzimuth) >= 0) {
|
||||
lon - acos(num / den)
|
||||
} else {
|
||||
lon + acos(num / den)
|
||||
}
|
||||
}
|
||||
while (rangelon < 0.0) rangelon += Math.PI * 2.0
|
||||
while (rangelon > Math.PI * 2.0) rangelon -= Math.PI * 2.0
|
||||
rangelat = Math.toDegrees(rangelat)
|
||||
rangelon = Math.toDegrees(rangelon)
|
||||
positions.add(Position(rangelat, rangelon))
|
||||
tempAzimuth += incrementDegrees.toInt()
|
||||
}
|
||||
return positions
|
||||
}
|
||||
}
|
||||
data class SatPos(
|
||||
var azimuth: Double = 0.0,
|
||||
var elevation: Double = 0.0,
|
||||
var latitude: Double = 0.0,
|
||||
var longitude: Double = 0.0,
|
||||
var altitude: Double = 0.0,
|
||||
var range: Double = 0.0,
|
||||
var rangeRate: Double = 0.0,
|
||||
var theta: Double = 0.0,
|
||||
var time: Date = Date()
|
||||
)
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
package com.rtbishop.look4sat.domain.predict4kotlin
|
||||
|
||||
import java.io.InputStream
|
||||
import kotlin.math.pow
|
||||
|
||||
object SatelliteFactory {
|
||||
|
||||
fun createSat(tle: TLE?): Satellite? {
|
||||
return when {
|
||||
tle == null -> null
|
||||
tle.isDeepspace -> DeepSpaceSat(tle)
|
||||
else -> NearEarthSat(tle)
|
||||
}
|
||||
}
|
||||
|
||||
fun createSat(array: Array<String>): Satellite? {
|
||||
val importedElement = importElement(array)
|
||||
return createSat(importedElement)
|
||||
}
|
||||
|
||||
fun createDummySat(): Satellite? {
|
||||
val elementArray = arrayOf(
|
||||
"ISS (ZARYA)",
|
||||
"1 25544U 98067A 21242.56000419 .00070558 00000-0 12956-2 0 9996",
|
||||
"2 25544 51.6433 334.9559 0003020 334.9496 106.9882 15.48593918300128"
|
||||
)
|
||||
return createSat(importElement(elementArray))
|
||||
}
|
||||
|
||||
fun importElement(array: Array<String>): TLE? {
|
||||
if (array.size != 3) return null
|
||||
try {
|
||||
val name: String = array[0].trim()
|
||||
val epoch: Double = array[1].substring(18, 32).toDouble()
|
||||
val meanmo: Double = array[2].substring(52, 63).toDouble()
|
||||
val eccn: Double = 1.0e-07 * array[2].substring(26, 33).toDouble()
|
||||
val incl: Double = array[2].substring(8, 16).toDouble()
|
||||
val raan: Double = array[2].substring(17, 25).toDouble()
|
||||
val argper: Double = array[2].substring(34, 42).toDouble()
|
||||
val meanan: Double = array[2].substring(43, 51).toDouble()
|
||||
val catnum: Int = array[1].substring(2, 7).trim().toInt()
|
||||
val bstar: Double = 1.0e-5 * array[1].substring(53, 59).toDouble() /
|
||||
10.0.pow(array[1].substring(60, 61).toDouble())
|
||||
return TLE(name, epoch, meanmo, eccn, incl, raan, argper, meanan, catnum, bstar)
|
||||
} catch (exception: Exception) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
fun importElements(stream: InputStream): List<TLE> {
|
||||
val elementArray = arrayOf(String(), String(), String())
|
||||
val importedElements = mutableListOf<TLE>()
|
||||
var line = 0
|
||||
stream.bufferedReader().forEachLine {
|
||||
if (line != 2) {
|
||||
elementArray[line] = it
|
||||
line++
|
||||
} else {
|
||||
elementArray[line] = it
|
||||
importElement(elementArray)?.let { tle -> importedElements.add(tle) }
|
||||
line = 0
|
||||
}
|
||||
}
|
||||
return importedElements
|
||||
}
|
||||
}
|
|
@ -53,7 +53,7 @@ class QthConverterTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `Given invalid location returns null`() {
|
||||
fun `Given invalid POS returns null`() {
|
||||
assert(qthConverter.positionToQTH(91.0542, -170.1142) == null)
|
||||
assert(qthConverter.positionToQTH(89.0542, -240.1142) == null)
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue