import numpy as np
import pytest
import orion_sdr as sdr
def _payload(n: int) -> np.ndarray:
return np.frombuffer(bytes((i * 37 + 11) & 0xFF for i in range(n)), dtype=np.uint8)
def test_super_frame_params():
p = sdr.DvbTSuperFrameParams("1/8", "qam16", "3/4", cell_id=0x1234)
assert p.guard == "1/8"
assert p.constellation == "qam16"
assert p.code_rate == "3/4"
assert p.cell_id == 0x1234
def test_super_frame_params_default_cell_id():
p = sdr.DvbTSuperFrameParams("1/32", "qpsk", "1/2")
assert p.cell_id == 0
def test_super_frame_roundtrip():
p = sdr.DvbTSuperFrameParams("1/8", "qpsk", "1/2", cell_id=0xBEEF)
payload = _payload(700)
sf = sdr.DvbTSuperFrameMod(p).modulate(payload)
assert sf.n_symbols == 4 * sf.symbols_per_frame
assert sum(sf.frame_payload_lens) == len(payload)
assert sf.iq.shape == (sf.n_symbols * sf.samples_per_symbol,)
rx = sdr.DvbTSuperFrameDemod(p).decode(
sf.iq, sf.symbols_per_frame, sf.frame_payload_lens
)
assert rx.payload == payload.tobytes()
assert rx.cell_id == 0xBEEF
def test_super_frame_cell_id_split():
p = sdr.DvbTSuperFrameParams("1/8", "qam16", "3/4", cell_id=0xABCD)
payload = _payload(400)
sf = sdr.DvbTSuperFrameMod(p).modulate(payload)
rx = sdr.DvbTSuperFrameDemod(p).decode(
sf.iq, sf.symbols_per_frame, sf.frame_payload_lens
)
assert rx.cell_id == 0xABCD
assert rx.payload == payload.tobytes()
def test_super_frame_demodulate_garbage_raises():
p = sdr.DvbTSuperFrameParams("1/8", "qpsk", "1/2")
payload = _payload(400)
sf = sdr.DvbTSuperFrameMod(p).modulate(payload)
with pytest.raises(ValueError):
sdr.DvbTSuperFrameDemod(p).decode(
np.zeros(1000, dtype=np.complex64), sf.symbols_per_frame, sf.frame_payload_lens
)
def _stream_of(params, payloads):
modulator = sdr.DvbTFrameMod(params)
frames = [modulator.modulate(pl) for pl in payloads]
n = frames[0].n_symbols
assert all(f.n_symbols == n for f in frames)
parts = [np.zeros(200, dtype=np.complex64)]
parts += [f.iq for f in frames]
parts.append(np.zeros(frames[0].samples_per_symbol, dtype=np.complex64))
return np.concatenate(parts), n
def test_stream_single_frame():
p = sdr.DvbTFrameParams("1/8", "qpsk", "1/2")
payload = _payload(184)
iq, n = _stream_of(p, [payload])
rx = sdr.DvbTFrameStreamDemod(p, n, len(payload))
got = rx.feed(iq) + rx.flush()
assert len(got) == 1
assert got[0].payload == payload.tobytes()
def test_stream_multiple_frames_chunked():
p = sdr.DvbTFrameParams("1/8", "qpsk", "1/2")
payloads = [
np.frombuffer(bytes((i * 13 + k * 40 + 1) & 0xFF for i in range(184)), np.uint8)
for k in range(3)
]
iq, n = _stream_of(p, payloads)
rx = sdr.DvbTFrameStreamDemod(p, n, 184)
got = []
for chunk in np.array_split(iq, 7):
got += rx.feed(np.ascontiguousarray(chunk))
got += rx.flush()
assert [f.payload for f in got] == [pl.tobytes() for pl in payloads]
def test_stream_holds_partial_frame():
p = sdr.DvbTFrameParams("1/8", "qpsk", "1/2")
payload = _payload(184)
iq, n = _stream_of(p, [payload])
rx = sdr.DvbTFrameStreamDemod(p, n, len(payload))
half = len(iq) // 2
assert rx.feed(np.ascontiguousarray(iq[:half])) == []
assert rx.buffered > 0
got = rx.feed(np.ascontiguousarray(iq[half:])) + rx.flush()
assert len(got) == 1
assert got[0].payload == payload.tobytes()
def test_stream_clear():
p = sdr.DvbTFrameParams("1/8", "qpsk", "1/2")
payload = _payload(184)
iq, n = _stream_of(p, [payload])
rx = sdr.DvbTFrameStreamDemod(p, n, len(payload))
rx.feed(np.ascontiguousarray(iq[: len(iq) // 3]))
assert rx.buffered > 0
rx.clear()
assert rx.buffered == 0