36 lines
1.5 KiB
Python
36 lines
1.5 KiB
Python
from __future__ import annotations
|
|
|
|
import numpy as np
|
|
|
|
from galileo_rx.navigation.e1b_prompt_stream import E1BPromptEpoch
|
|
from galileo_rx.navigation.e1b_symbol_sync import E1BSymbolSynchronizer
|
|
|
|
|
|
def _epoch(index: int, sign: int, *, slip: bool = False) -> E1BPromptEpoch:
|
|
start = index * 16
|
|
prompt = sign * np.exp(1j * 0.37)
|
|
return E1BPromptEpoch(
|
|
1, start, start + 16, float(prompt.real), float(prompt.imag), 0.0, 1000.0, 0.0,
|
|
50.0, True, True, slip, False, True,
|
|
)
|
|
|
|
|
|
def test_symbol_sync_preserves_global_polarity_ambiguity() -> None:
|
|
truth = np.asarray([1, -1] * 12, dtype=np.int8)
|
|
synchronizer = E1BSymbolSynchronizer(minimum_axis_epochs=4, minimum_confidence=0.9)
|
|
symbols = synchronizer.process_many([_epoch(i, int(-value)) for i, value in enumerate(truth)])
|
|
hard = np.asarray([item.hard_value for item in symbols[4:]], dtype=np.int8)
|
|
# Either polarity is valid here; page synchronization resolves it later.
|
|
expected_bits = (truth[4:] > 0).astype(np.int8)
|
|
assert np.array_equal(hard, expected_bits) or np.array_equal(hard, 1 - expected_bits)
|
|
assert all(not item.inverted for item in symbols)
|
|
|
|
|
|
def test_cycle_slip_invalidates_and_restarts_axis_lock() -> None:
|
|
sync = E1BSymbolSynchronizer(minimum_axis_epochs=3, minimum_confidence=0.1)
|
|
symbols = [sync.process(_epoch(i, 1, slip=i == 5)) for i in range(10)]
|
|
assert symbols[5].valid is False
|
|
assert symbols[6].valid is False
|
|
assert symbols[7].valid is True
|
|
assert sync.loss_count == 1
|