Расчет витков по TLE
This commit is contained in:
+6
@@ -0,0 +1,6 @@
|
||||
package space.nstart.pcp.pcp_types_lib.dto.ballistics
|
||||
|
||||
class TleRevolutionsRequestDTO(
|
||||
val tle: TLEDTO = TLEDTO(),
|
||||
val days: Double = 1.0
|
||||
)
|
||||
+5
-1
@@ -8,6 +8,7 @@ import org.springframework.web.bind.annotation.RestController
|
||||
import space.nstart.pcp.pcp_request_service.service.TLEService
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.TLEDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.TlePointRequestDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.TleRevolutionsRequestDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.TleRvaRequestDTO
|
||||
|
||||
@RestController
|
||||
@@ -28,4 +29,7 @@ class TLEController {
|
||||
@PostMapping("/rva")
|
||||
fun rva(@RequestBody req : TleRvaRequestDTO) = tleService.rva(req)
|
||||
|
||||
}
|
||||
@PostMapping("/revolutions")
|
||||
fun revolutions(@RequestBody req: TleRevolutionsRequestDTO) = tleService.revolutions(req)
|
||||
|
||||
}
|
||||
|
||||
+62
-1
@@ -4,7 +4,9 @@ import ballistics.Ballistics
|
||||
import ballistics.orbitalPoints.timeStepper.TLEStepper
|
||||
import ballistics.types.BallisticsError
|
||||
import ballistics.types.EarthType
|
||||
import ballistics.types.KeplerParams
|
||||
import ballistics.types.PPI
|
||||
import ballistics.types.RevolutionParameter
|
||||
import ballistics.types.TLE
|
||||
import ballistics.types.TLEParams
|
||||
import ballistics.types.VisibilityParametersZRV
|
||||
@@ -14,17 +16,25 @@ import ballistics.utils.toDateTime
|
||||
import org.springframework.stereotype.Service
|
||||
import space.nstart.pcp.pcp_request_service.configuration.CustomErrorException
|
||||
import space.nstart.pcp.pcp_request_service.configuration.CustomValidationException
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.AscNodeDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.KeplersDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.OrbPointDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.RadioVisibilityAreaDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.TLEDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.TlePointRequestDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.TleRevolutionsRequestDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.TargetPositionDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.TleRvaRequestDTO
|
||||
import java.time.LocalDateTime
|
||||
import kotlin.math.PI
|
||||
|
||||
|
||||
@Service
|
||||
class TLEService() {
|
||||
private companion object {
|
||||
const val SECONDS_IN_DAY = 86_400.0
|
||||
const val PZ90_EQUATORIAL_RADIUS = 6_378_136.0
|
||||
}
|
||||
|
||||
fun mkTP(p : VisibilityParametersZRV) = TargetPositionDTO(
|
||||
toDateTime(p.t),
|
||||
@@ -117,4 +127,55 @@ class TLEService() {
|
||||
|
||||
return bal.zrv.map { mkRVA(it, tleParams.noradId) }
|
||||
}
|
||||
}
|
||||
|
||||
fun revolutions(req: TleRevolutionsRequestDTO): List<AscNodeDTO> {
|
||||
if (!req.days.isFinite() || req.days <= 0.0) {
|
||||
throw CustomValidationException("Интервал расчета должен быть больше 0 суток")
|
||||
}
|
||||
|
||||
val bal = Ballistics()
|
||||
val tle = TLE(req.tle.first, req.tle.second)
|
||||
try {
|
||||
bal.getTLEParams(tle, req.tle.header ?: "empty")
|
||||
} catch (ex: Exception) {
|
||||
throw CustomValidationException("Ошибка формата TLE : ${ex.message}")
|
||||
}
|
||||
|
||||
val result = bal.calculateOrbPoints(tle, req.days * SECONDS_IN_DAY)
|
||||
if (result != BallisticsError.OK) {
|
||||
throw CustomErrorException("Ошибка расчета витков по TLE : $result")
|
||||
}
|
||||
|
||||
return bal.revolutions.map { mkAscNode(it, bal.calculateKeplerParams(it.vuz)) }
|
||||
}
|
||||
|
||||
private fun mkAscNode(revolution: RevolutionParameter, keps: KeplerParams) = AscNodeDTO(
|
||||
time = toDateTime(revolution.vuz.t),
|
||||
revolution = revolution.vuz.vit,
|
||||
long = revolution.lVuz * 180 / PI,
|
||||
height = revolution.hVuz,
|
||||
x = revolution.vuz.r.x,
|
||||
y = revolution.vuz.r.y,
|
||||
z = revolution.vuz.r.z,
|
||||
vx = revolution.vuz.v.x,
|
||||
vy = revolution.vuz.v.y,
|
||||
vz = revolution.vuz.v.z,
|
||||
keps = KeplersDTO(
|
||||
(keps.ael - PZ90_EQUATORIAL_RADIUS) / 1000.0,
|
||||
keps.e,
|
||||
keps.nakl * 180 / PI,
|
||||
keps.omegab * 180 / PI,
|
||||
keps.omegam * 180 / PI
|
||||
),
|
||||
localMeanTime = tmest(toDateTime(revolution.vuz.t), revolution.lVuz)
|
||||
)
|
||||
|
||||
private fun tmest(t: LocalDateTime, longitudeRad: Double): LocalDateTime {
|
||||
var longitude = longitudeRad
|
||||
if (longitude > PI) {
|
||||
longitude -= 2 * PI
|
||||
}
|
||||
return t.plusSeconds(-60 * 60 * 3)
|
||||
.plusNanos((longitude / 2.0 / PI * SECONDS_IN_DAY * 1e9).toLong())
|
||||
}
|
||||
}
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package space.nstart.pcp.pcp_request_service.service
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import space.nstart.pcp.pcp_request_service.configuration.CustomValidationException
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.TLEDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.TleRevolutionsRequestDTO
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class TLEServiceTest {
|
||||
|
||||
@Test
|
||||
fun `revolutions calculates ascending nodes from tle epoch`() {
|
||||
val service = TLEService()
|
||||
|
||||
val revolutions = service.revolutions(
|
||||
TleRevolutionsRequestDTO(
|
||||
tle = issTle,
|
||||
days = 1.0
|
||||
)
|
||||
)
|
||||
|
||||
val epoch = service.parseTLE(issTle).time
|
||||
assertTrue(revolutions.isNotEmpty())
|
||||
assertTrue(revolutions.zipWithNext().all { (previous, next) -> previous.time < next.time })
|
||||
assertTrue(revolutions.zipWithNext().all { (previous, next) -> previous.revolution < next.revolution })
|
||||
assertTrue(revolutions.all { it.time >= epoch })
|
||||
assertTrue(revolutions.all { it.localMeanTime != null })
|
||||
assertTrue(revolutions.all { it.keps != null })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `revolutions rejects non-positive duration`() {
|
||||
val service = TLEService()
|
||||
|
||||
assertFailsWith<CustomValidationException> {
|
||||
service.revolutions(
|
||||
TleRevolutionsRequestDTO(
|
||||
tle = issTle,
|
||||
days = 0.0
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val issTle = TLEDTO(
|
||||
header = "ISS",
|
||||
first = "1 25994U 99068A 26167.13049375 .00000315 00000-0 73126-4 0 9997",
|
||||
second = "2 25994 97.9457 216.7186 0001501 193.3628 244.8059 14.61102329409455"
|
||||
)
|
||||
}
|
||||
}
|
||||
+12
@@ -13,6 +13,7 @@ import space.nstart.pcp.pcp_types_lib.dto.ballistics.SatelliteICDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.SatelliteOrbitAvailabilityDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.TLEDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.TlePointRequestDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.TleRevolutionsRequestDTO
|
||||
import space.nstart.pcp.slots_service.dto.tlecomparison.TleParsedDTO
|
||||
import space.nstart.pcp.slots_service.configuration.CustomErrorException
|
||||
import java.net.URI
|
||||
@@ -115,6 +116,17 @@ class BallisticsService (webClientBuilderProvider: ObjectProvider<WebClient.Buil
|
||||
.block()
|
||||
?: throw CustomErrorException("Не удалось рассчитать положение по TLE на время $time")
|
||||
|
||||
fun tleRevolutions(tle: TLEDTO, days: Double): List<AscNodeDTO> =
|
||||
webClientBuilder.build()
|
||||
.post()
|
||||
.uri("$url/api/tle/revolutions")
|
||||
.bodyValue(TleRevolutionsRequestDTO(tle = tle, days = days))
|
||||
.retrieve()
|
||||
.bodyToFlux(AscNodeDTO::class.java)
|
||||
.collectList()
|
||||
.block()
|
||||
?: emptyList()
|
||||
|
||||
private fun withTimeInterval(
|
||||
path: String,
|
||||
timeStart: LocalDateTime?,
|
||||
|
||||
+20
-2
@@ -11,6 +11,7 @@ import space.nstart.pcp.pcp_types_lib.dto.ballistics.InitialConditionsDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.MovementModel
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.OrbPointDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.SatelliteICDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.ballistics.TLEDTO
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.URI
|
||||
import java.time.LocalDateTime
|
||||
@@ -60,6 +61,13 @@ class BallisticsServiceTest {
|
||||
)
|
||||
)
|
||||
val currentInitialConditions = service.currentInitialConditions(101L)
|
||||
val tleRevolutions = service.tleRevolutions(
|
||||
TLEDTO(
|
||||
first = "1 25994U 99068A 26167.13049375 .00000315 00000-0 73126-4 0 9997",
|
||||
second = "2 25994 97.9457 216.7186 0001501 193.3628 244.8059 14.61102329409455"
|
||||
),
|
||||
days = 1.5
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
listOf(
|
||||
@@ -69,7 +77,8 @@ class BallisticsServiceTest {
|
||||
"/api/satellites/orbit/availability",
|
||||
"/api/satellites/101/extract-time",
|
||||
"/api/satellites/receive-rv",
|
||||
"/api/satellites/101/initial-conditions/current"
|
||||
"/api/satellites/101/initial-conditions/current",
|
||||
"/api/tle/revolutions"
|
||||
),
|
||||
requests.map { it.path }
|
||||
)
|
||||
@@ -81,6 +90,7 @@ class BallisticsServiceTest {
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
),
|
||||
requests.map { it.query }
|
||||
@@ -89,9 +99,12 @@ class BallisticsServiceTest {
|
||||
assertEquals(101L, availability.single().satelliteId)
|
||||
assertNotNull(exactPoint)
|
||||
assertEquals(timeStart, exactPoint.time)
|
||||
assertEquals(true, requestBodies.single().contains(""""movementModel":"KONDOR""""))
|
||||
assertNotNull(currentInitialConditions)
|
||||
assertEquals(101L, currentInitialConditions.satelliteId)
|
||||
assertEquals(emptyList(), tleRevolutions)
|
||||
assertEquals(2, requestBodies.size)
|
||||
assertEquals(true, requestBodies.any { it.contains(""""movementModel":"KONDOR"""") })
|
||||
assertEquals(true, requestBodies.any { it.contains(""""days":1.5""") })
|
||||
}
|
||||
|
||||
private fun createService(serverUrl: String): BallisticsService {
|
||||
@@ -164,6 +177,11 @@ class BallisticsServiceTest {
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
startedServer.createContext("/api/tle/revolutions") { exchange ->
|
||||
requests.add(exchange.requestURI)
|
||||
requestBodies.add(exchange.requestBody.bufferedReader().use { it.readText() })
|
||||
respond(exchange, "[]")
|
||||
}
|
||||
startedServer.start()
|
||||
server = startedServer
|
||||
return "http://localhost:${startedServer.address.port}"
|
||||
|
||||
Reference in New Issue
Block a user