109 lines
3.8 KiB
Python
109 lines
3.8 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Tests for the frame synchronization prototype (frame_sync.py).
|
|
|
|
Tests cover stream generation (length, offsets) and syndrome screening
|
|
(correct offset identification, wrong offset rejection).
|
|
|
|
Run:
|
|
python3 -m pytest model/test_frame_sync.py -v
|
|
"""
|
|
|
|
import numpy as np
|
|
import pytest
|
|
|
|
from ldpc_sim import N, build_full_h_matrix
|
|
from frame_sync import generate_stream, syndrome_screen
|
|
|
|
|
|
# =============================================================================
|
|
# Fixtures
|
|
# =============================================================================
|
|
|
|
@pytest.fixture(scope="module")
|
|
def H():
|
|
"""Full expanded H matrix, built once per module."""
|
|
return build_full_h_matrix()
|
|
|
|
|
|
# =============================================================================
|
|
# TestStreamGeneration
|
|
# =============================================================================
|
|
|
|
class TestStreamGeneration:
|
|
"""Validate continuous LLR stream generation."""
|
|
|
|
def test_stream_length(self, H):
|
|
"""Stream should be n_frames * N + offset long."""
|
|
np.random.seed(100)
|
|
n_frames = 5
|
|
offset = 37
|
|
stream_llr, true_offset, info_list = generate_stream(
|
|
H, n_frames=n_frames, lam_s=5.0, lam_b=0.1, offset=offset
|
|
)
|
|
assert len(stream_llr) == n_frames * N + offset
|
|
assert true_offset == offset
|
|
assert len(info_list) == n_frames
|
|
|
|
def test_stream_zero_offset(self, H):
|
|
"""offset=0 should work, producing stream of length n_frames * N."""
|
|
np.random.seed(101)
|
|
n_frames = 3
|
|
stream_llr, true_offset, info_list = generate_stream(
|
|
H, n_frames=n_frames, lam_s=5.0, lam_b=0.1, offset=0
|
|
)
|
|
assert len(stream_llr) == n_frames * N
|
|
assert true_offset == 0
|
|
assert len(info_list) == n_frames
|
|
|
|
def test_stream_random_offset(self, H):
|
|
"""offset=None should pick a random offset in [0, N-1]."""
|
|
np.random.seed(102)
|
|
stream_llr, true_offset, info_list = generate_stream(
|
|
H, n_frames=4, lam_s=5.0, lam_b=0.1, offset=None
|
|
)
|
|
assert 0 <= true_offset < N
|
|
assert len(stream_llr) == 4 * N + true_offset
|
|
|
|
|
|
# =============================================================================
|
|
# TestSyndromeScreen
|
|
# =============================================================================
|
|
|
|
class TestSyndromeScreen:
|
|
"""Validate syndrome-based offset screening."""
|
|
|
|
def test_correct_offset_low_syndrome(self, H):
|
|
"""At high SNR (lam_s=10), the best offset should match the true offset."""
|
|
np.random.seed(200)
|
|
n_frames = 3
|
|
offset = 42
|
|
stream_llr, true_offset, _ = generate_stream(
|
|
H, n_frames=n_frames, lam_s=10.0, lam_b=0.1, offset=offset
|
|
)
|
|
scores = syndrome_screen(stream_llr, n_offsets=N)
|
|
# The true offset should have the lowest (or near-lowest) syndrome weight
|
|
best_offset = min(scores, key=scores.get)
|
|
assert best_offset == true_offset, (
|
|
f"Best offset {best_offset} (sw={scores[best_offset]}) "
|
|
f"!= true offset {true_offset} (sw={scores[true_offset]})"
|
|
)
|
|
|
|
def test_wrong_offsets_high_syndrome(self, H):
|
|
"""Wrong offsets should have average syndrome weight > 80."""
|
|
np.random.seed(201)
|
|
n_frames = 3
|
|
offset = 10
|
|
stream_llr, true_offset, _ = generate_stream(
|
|
H, n_frames=n_frames, lam_s=10.0, lam_b=0.1, offset=offset
|
|
)
|
|
scores = syndrome_screen(stream_llr, n_offsets=N)
|
|
# Collect syndrome weights for wrong offsets
|
|
wrong_weights = [
|
|
scores[o] for o in scores if o != true_offset
|
|
]
|
|
avg_wrong = np.mean(wrong_weights)
|
|
assert avg_wrong > 80, (
|
|
f"Average wrong-offset syndrome weight {avg_wrong:.1f} is not > 80"
|
|
)
|