Implement Galileo E1B I/NAV navigation decoding
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import numpy as np
|
||||
|
||||
from galileo_rx.navigation.e1b_symbol_sync import NavigationSymbol
|
||||
from galileo_rx.navigation.inav_page_sync import INAV_SYNC_BITS, InavPageSynchronizer
|
||||
|
||||
|
||||
def _symbols(bits: np.ndarray, *, invert: bool = False, prefix: int = 17) -> list[NavigationSymbol]:
|
||||
raw = np.concatenate((np.zeros(prefix, dtype=np.int8), bits))
|
||||
if invert:
|
||||
raw = 1 - raw
|
||||
return [NavigationSymbol(1, i, i * 4, (i + 1) * 4, 1.0 if bit else -1.0, int(bit), 1.0, False, True) for i, bit in enumerate(raw)]
|
||||
|
||||
|
||||
def test_page_sync_rejects_wrong_boundary_and_requires_repetition() -> None:
|
||||
rng = np.random.default_rng(4)
|
||||
part = np.concatenate((INAV_SYNC_BITS, rng.integers(0, 2, 240, dtype=np.int8)))
|
||||
stream = _symbols(np.tile(part, 3))
|
||||
sync = InavPageSynchronizer(required_confirmations=2)
|
||||
first = sync.process_many(stream[:267])
|
||||
assert first == []
|
||||
output = sync.process_many(stream[267:])
|
||||
assert len(output) == 3
|
||||
assert all(item.sync_valid for item in output)
|
||||
|
||||
|
||||
def test_page_sync_records_global_inversion() -> None:
|
||||
body = np.zeros(240, dtype=np.int8)
|
||||
parts = InavPageSynchronizer().process_many(_symbols(np.tile(np.concatenate((INAV_SYNC_BITS, body)), 3), invert=True))
|
||||
assert len(parts) == 3
|
||||
assert all(item.polarity_inverted for item in parts)
|
||||
assert np.array_equal(parts[0].hard_symbols[:10], INAV_SYNC_BITS)
|
||||
|
||||
|
||||
def test_page_sync_loses_and_reacquires_after_corrupted_sync() -> None:
|
||||
body = np.zeros(240, dtype=np.int8)
|
||||
part = np.concatenate((INAV_SYNC_BITS, body))
|
||||
bits = np.tile(part, 6)
|
||||
bits[3 * 250] ^= 1
|
||||
output = InavPageSynchronizer().process_many(_symbols(bits, prefix=0))
|
||||
assert len(output) == 5
|
||||
assert [item.receive_sample_timestamp // (250 * 4) for item in output] == [0, 1, 2, 4, 5]
|
||||
|
||||
|
||||
def test_page_sync_does_not_lock_through_symbol_erasure() -> None:
|
||||
body = np.zeros(240, dtype=np.int8)
|
||||
symbols = _symbols(np.tile(np.concatenate((INAV_SYNC_BITS, body)), 3), prefix=0)
|
||||
erased = symbols[250]
|
||||
symbols[250] = NavigationSymbol(
|
||||
erased.prn, erased.symbol_index, erased.start_sample_timestamp,
|
||||
erased.end_sample_timestamp, 0.0, 0, 0.0, False, False,
|
||||
)
|
||||
assert InavPageSynchronizer().process_many(symbols) == []
|
||||
Reference in New Issue
Block a user