mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-08 13:37:25 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
623d859c97 | ||
|
|
08803e0f55 |
No files matched your search
Binary file not shown.
@@ -36,7 +36,7 @@ import java.util.Locale
|
||||
import java.util.zip.GZIPInputStream
|
||||
import javax.xml.parsers.DocumentBuilderFactory
|
||||
|
||||
/** Bundled ARRL configuration 11.34 from https://lotw.arrl.org/lotw/config.tq6. */
|
||||
/** Bundled ARRL configuration 11.35 from https://lotw.arrl.org/lotw/config.tq6. */
|
||||
internal class LoTWConfig(input: InputStream) {
|
||||
private val root = input.use { source -> GZIPInputStream(source).use { gzip ->
|
||||
val xml = gzip.bufferedReader(Charsets.UTF_8).readText()
|
||||
|
||||
@@ -87,6 +87,7 @@ class LoTWConfigTest {
|
||||
assertEquals("AO-91", config.resolveSatellite("FOX-1B"))
|
||||
assertEquals("IO-86", config.resolveSatellite("LAPAN-A2"))
|
||||
assertEquals("RS-44", config.resolveSatellite("DOSAAF-85"))
|
||||
assertEquals("RS95S", config.resolveSatellite("QMR-KWT 2"))
|
||||
assertEquals("BO-102", config.resolveSatellite("CAS-7B"))
|
||||
assertEquals("SO-50", config.resolveSatellite("SO-50"))
|
||||
}
|
||||
|
||||
+5
-3
@@ -34,6 +34,8 @@ import java.util.Locale
|
||||
* - live SatNOGS 3LE names and Celestrak amateur names joined to the same NORAD id,
|
||||
* - designator tokens of the config.tq6 satellite descriptions (e.g. CAS-7B -> BO-102),
|
||||
* - the ISS family, which SatNOGS does not list under its ARRL name "ARISS".
|
||||
* Added 2026-10-08: config.tq6 v11.35 lists QMR-KWT 2 as "RS95S"; SatNOGS DB carries it as
|
||||
* "QMR-KWT 2" (alias "RS95S") and other sources spell it "RS-95S", hence the identity entry.
|
||||
* Placeholder names ("OBJECT AY" and friends) are deliberately NOT mapped: they are recycled
|
||||
* between objects and would sign the wrong satellite. LoTWConfigTest asserts that every target
|
||||
* here is a real config.tq6 name.
|
||||
@@ -79,11 +81,11 @@ object LoTWSatelliteAliases {
|
||||
"OSCAR16PACSAT" to "AO-16", "OSCAR19LUSAT" to "LO-19", "OSCAR64" to "DO-64",
|
||||
"OSCAR7" to "AO-7", "PACSAT" to "AO-16", "PARKINSONSAT" to "NO-84",
|
||||
"PCSAT" to "NO-44", "PHILLIPINESOSCAR101" to "PO-101", "PO101" to "PO-101",
|
||||
"PSAT" to "NO-84", "PSAT2" to "NO-104", "QB50P1" to "EO-79",
|
||||
"PSAT" to "NO-84", "PSAT2" to "NO-104", "QB50P1" to "EO-79", "QMRKWT2" to "RS95S",
|
||||
"QO100" to "QO-100", "RADFXSAT" to "AO-91", "RADIOROSTO" to "RS-15",
|
||||
"RS0ISS" to "ARISS", "RS14" to "AO-21", "RS15" to "RS-15",
|
||||
"RS44" to "RS-44", "RS64S" to "AO-123", "SAUDISAT1C" to "SO-50",
|
||||
"SO121" to "SO-121", "SO124" to "SO-124", "SO125" to "SO-125",
|
||||
"RS44" to "RS-44", "RS64S" to "AO-123", "RS95S" to "RS95S",
|
||||
"SAUDISAT1C" to "SO-50", "SO121" to "SO-121", "SO124" to "SO-124", "SO125" to "SO-125",
|
||||
"SO50" to "SO-50", "SOLUTUSNANOSATTELITE" to "SONATE", "SONATE2" to "SONATE",
|
||||
"TAURUS1" to "TAURUS", "TEVEL21" to "TEV2-1", "TEVEL22" to "TEV2-2",
|
||||
"TEVEL23" to "TEV2-3", "TEVEL24" to "TEV2-4", "TEVEL25" to "TEV2-5",
|
||||
|
||||
+4
-1
@@ -27,7 +27,7 @@ import org.junit.Test
|
||||
/** Alias table that maps tracker catalogue names onto the names ARRL's config.tq6 uses. */
|
||||
class LoTWSatelliteAliasesTest {
|
||||
|
||||
private val catalogue = listOf("SO-50", "ARISS", "PO-101", "BO-102", "AO-91", "RS-44", "IO-117")
|
||||
private val catalogue = listOf("SO-50", "ARISS", "PO-101", "BO-102", "AO-91", "RS-44", "IO-117", "RS95S")
|
||||
|
||||
@Test
|
||||
fun `lookup maps SatNOGS catalogue names to ARRL names`() {
|
||||
@@ -37,6 +37,7 @@ class LoTWSatelliteAliasesTest {
|
||||
assertEquals("AO-91", LoTWSatelliteAliases.lookup("FOX-1B"))
|
||||
assertEquals("RS-44", LoTWSatelliteAliases.lookup("DOSAAF-85"))
|
||||
assertEquals("IO-117", LoTWSatelliteAliases.lookup("GREENCUBE"))
|
||||
assertEquals("RS95S", LoTWSatelliteAliases.lookup("QMR-KWT 2"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -59,6 +60,8 @@ class LoTWSatelliteAliasesTest {
|
||||
assertEquals("SO-50", LoTWSatelliteAliases.resolve("SAUDISAT 1C (SO-50)", catalogue))
|
||||
assertEquals("ARISS", LoTWSatelliteAliases.resolve("ISS (ZARYA)", catalogue))
|
||||
assertEquals("AO-91", LoTWSatelliteAliases.resolve("AO-91 (RadFxSat)", catalogue))
|
||||
assertEquals("RS95S", LoTWSatelliteAliases.resolve("RS-95S", catalogue))
|
||||
assertEquals("RS95S", LoTWSatelliteAliases.resolve("QMR-KWT 2", catalogue))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+5
-2
@@ -82,7 +82,10 @@ class MutualViewModel(
|
||||
private val settingsRepo: ISettingsRepo,
|
||||
// Injected so unit tests can run the pass computation on a test dispatcher;
|
||||
// production callers keep the CPU-bound pool default.
|
||||
private val computeDispatcher: CoroutineDispatcher = Dispatchers.Default
|
||||
private val computeDispatcher: CoroutineDispatcher = Dispatchers.Default,
|
||||
// Injected so unit tests can pin the wall clock to the fixture TLE epoch and
|
||||
// stay deterministic; production callers keep the real clock default.
|
||||
private val nowMillis: () -> Long = System::currentTimeMillis
|
||||
) : ViewModel() {
|
||||
|
||||
private val _uiState = MutableStateFlow(MutualUiState())
|
||||
@@ -303,7 +306,7 @@ class MutualViewModel(
|
||||
queryGeneration += 1
|
||||
|
||||
viewModelScope.launch {
|
||||
val now = System.currentTimeMillis()
|
||||
val now = nowMillis()
|
||||
// 转发器类型筛选: 使用硬编码 AMSAT Live 清单 (见 Sources):
|
||||
// FM = {SO-50, ISS ZARYA, AO-123}, Linear = {RS-44, FO-29,
|
||||
// AO-7, AO-73, JO-97}. 不再依赖 AMSAT 网页同步: 任何网络下都
|
||||
|
||||
+4
-2
@@ -53,7 +53,9 @@ class MutualViewModelTest {
|
||||
): MutualViewModel = MutualViewModel(
|
||||
satelliteRepo = FakeSatelliteRepo(satellites, passes),
|
||||
settingsRepo = FakeSettingsRepo(position),
|
||||
computeDispatcher = StandardTestDispatcher(mainDispatcherRule.dispatcher.scheduler)
|
||||
computeDispatcher = StandardTestDispatcher(mainDispatcherRule.dispatcher.scheduler),
|
||||
// Pin the clock to the fixture base so results never depend on wall time.
|
||||
nowMillis = { TestOrbits.FIXTURE_BASE }
|
||||
)
|
||||
|
||||
private fun TestScope.queryAndSettle(vm: MutualViewModel) {
|
||||
@@ -219,7 +221,7 @@ class MutualViewModelTest {
|
||||
assertTrue(state.mutualPasses.all { it.catNum == 25544 })
|
||||
assertTrue(state.mutualPasses.all { it.name == "ISS (ZARYA)" })
|
||||
// AOS/LOS within the searched horizon
|
||||
val now = System.currentTimeMillis()
|
||||
val now = TestOrbits.FIXTURE_BASE
|
||||
assertTrue(state.mutualPasses.all { it.startTime >= now - 120_000L })
|
||||
assertTrue(state.mutualPasses.all { it.endTime <= now + 12 * 3600_000L + 120_000L })
|
||||
}
|
||||
|
||||
@@ -48,6 +48,15 @@ object TestOrbits {
|
||||
)
|
||||
)
|
||||
|
||||
/**
|
||||
* Fixed wall-clock base for every fixture computation: 2024-03-10T00:00Z,
|
||||
* ~18 h after [ISS]'s TLE epoch, so SGP4 propagates an accurate, healthy
|
||||
* orbit. Tests pin the ViewModel clock to this value as well
|
||||
* (MutualViewModel.nowMillis), which makes pass windows deterministic
|
||||
* instead of rotting as the fixture ages against System.currentTimeMillis().
|
||||
*/
|
||||
val FIXTURE_BASE: Long = 1710028800000L
|
||||
|
||||
/** Guangzhou (default BA7OPF grid OL62/OL63 area). */
|
||||
val GUANGZHOU = GeoPos(23.13, 113.26)
|
||||
|
||||
@@ -85,7 +94,7 @@ object TestOrbits {
|
||||
fun findPassWindows(
|
||||
sat: OrbitalObject = ISS,
|
||||
pos: GeoPos = GUANGZHOU,
|
||||
time: Long = System.currentTimeMillis(),
|
||||
time: Long = FIXTURE_BASE,
|
||||
hoursAhead: Int = 12
|
||||
): List<OrbitalPass> {
|
||||
if (!sat.willBeSeen(pos)) return emptyList()
|
||||
|
||||
Reference in new issue
Block a user