Lab047: transmit JPEG over real RF link

This commit is contained in:
LittleSam129
2026-09-03 13:13:23 +03:00
parent b0111d2232
commit 6fb7e4ec54
11 changed files with 2858 additions and 17 deletions

View File

@@ -428,6 +428,211 @@ def test_cursor_is_strictly_monotonic(tmp_path: Path) -> None:
assert all(after > before for before, after in zip(result.cursor_history, result.cursor_history[1:]))
def test_streaming_more_than_ten_thousand_candidates_reach_strict_stage(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
capture = _capture_file(tmp_path / "many_candidates.cs8", 250_000)
candidate_count = 10_001
def blocks(raw, interval, chunk_samples):
del raw, interval, chunk_samples
scores = np.ones(candidate_count, dtype=np.float32)
yield 0, scores, np.arange(candidate_count), 250_000, 1_000
processed = 0
def reject(raw, sample_count, candidate, number):
nonlocal processed
del raw, sample_count, number
processed += 1
return _candidate_outcome(
candidate,
accepted=False,
next_sample=candidate.sample_offset + 1,
)
monkeypatch.setattr(offline, "_score_blocks", blocks)
coarse, strict = offline.stream_process_capture(
capture,
offline.CandidateRule("fixed", 0.999, 0.5),
max_candidates=20_000,
decoder=reject,
)
assert coarse.candidate_count == candidate_count
assert coarse.max_candidates_reached is False
assert strict.counters.candidates_processed == candidate_count
assert processed == candidate_count
assert strict.outcomes_truncated is True
def test_streaming_candidates_are_checked_before_next_block(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
capture = _capture_file(tmp_path / "stream_order.cs8", 500)
events: list[str] = []
def blocks(raw, interval, chunk_samples):
del raw, interval, chunk_samples
yield 0, np.ones(2, np.float32), np.array([0, 1]), 100, 100
assert events == ["decode:0", "decode:20"]
events.append("second_block")
yield 100, np.ones(1, np.float32), np.array([0]), 100, 100
def reject(raw, sample_count, candidate, number):
del raw, sample_count, number
events.append(f"decode:{candidate.sample_offset}")
return _candidate_outcome(candidate, accepted=False, next_sample=0)
monkeypatch.setattr(offline, "_score_blocks", blocks)
offline.stream_process_capture(
capture,
offline.CandidateRule("fixed", 0.999, 0.5),
decoder=reject,
)
assert events == ["decode:0", "decode:20", "second_block", "decode:100"]
def test_streaming_accepted_frame_owns_following_local_maxima(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
capture = _capture_file(tmp_path / "owned_event.cs8", 1_000)
def blocks(raw, interval, chunk_samples):
del raw, interval, chunk_samples
scores = np.ones(31, np.float32)
yield 0, scores, np.array([5, 6, 10, 24, 30]), 1_000, 100
def decoder(raw, sample_count, candidate, number):
del raw, sample_count, number
return _candidate_outcome(
candidate,
accepted=candidate.sample_offset == 100,
next_sample=500 if candidate.sample_offset == 100 else 0,
)
monkeypatch.setattr(offline, "_score_blocks", blocks)
coarse, strict = offline.stream_process_capture(
capture,
offline.CandidateRule("fixed", 0.999, 0.5),
decoder=decoder,
)
assert strict.counters.valid_frames == 1
assert strict.counters.candidates_processed == 2
assert coarse.candidates_skipped_as_same_local_event == 3
def test_streaming_exact_overlap_duplicate_is_checked_once(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
capture = _capture_file(tmp_path / "exact_overlap.cs8", 500)
def blocks(raw, interval, chunk_samples):
del raw, interval, chunk_samples
yield 0, np.ones(6, np.float32), np.array([5]), 100, 100
yield 100, np.ones(1, np.float32), np.array([0]), 100, 100
monkeypatch.setattr(offline, "_score_blocks", blocks)
coarse, strict = offline.stream_process_capture(
capture,
offline.CandidateRule("fixed", 0.999, 0.5),
decoder=lambda raw, count, candidate, number: _candidate_outcome(
candidate,
accepted=False,
next_sample=0,
),
)
assert coarse.candidate_count == 1
assert coarse.exact_duplicate_candidates_skipped == 1
assert strict.counters.candidates_processed == 1
def test_streaming_bad_candidate_cannot_hide_later_valid_frame(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
capture = _capture_file(tmp_path / "bad_then_valid.cs8", 500)
def blocks(raw, interval, chunk_samples):
del raw, interval, chunk_samples
yield 0, np.ones(3, np.float32), np.array([0, 1, 2]), 100, 100
def decoder(raw, sample_count, candidate, number):
del raw, sample_count, number
return _candidate_outcome(
candidate,
accepted=candidate.sample_offset == 20,
next_sample=10_000,
)
monkeypatch.setattr(offline, "_score_blocks", blocks)
_, strict = offline.stream_process_capture(
capture,
offline.CandidateRule("fixed", 0.999, 0.5),
decoder=decoder,
)
assert strict.counters.candidates_processed == 2
assert strict.counters.valid_frames == 1
assert strict.accepted_frames[0].refined_start_sample == 20
def test_streaming_max_candidates_limits_strict_checks(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
capture = _capture_file(tmp_path / "stream_limit.cs8", 500)
def blocks(raw, interval, chunk_samples):
del raw, interval, chunk_samples
yield 0, np.ones(4, np.float32), np.arange(4), 100, 100
monkeypatch.setattr(offline, "_score_blocks", blocks)
coarse, strict = offline.stream_process_capture(
capture,
offline.CandidateRule("fixed", 0.999, 0.5),
max_candidates=2,
decoder=lambda raw, count, candidate, number: _candidate_outcome(
candidate,
accepted=False,
next_sample=0,
),
)
assert coarse.max_candidates_reached is True
assert coarse.termination_reason == "MAX_CANDIDATES_REACHED"
assert strict.counters.candidates_processed == 2
assert strict.max_search_iterations_reached is True
def test_streaming_exhausted_blocks_cover_full_capture_not_last_correlation_start(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
capture = _capture_file(tmp_path / "full_coverage.cs8", 500)
def blocks(raw, interval, chunk_samples):
del raw, interval, chunk_samples
yield 0, np.zeros(1, np.float32), np.array([], dtype=np.int64), 500, 100
monkeypatch.setattr(offline, "_score_blocks", blocks)
coarse, strict = offline.stream_process_capture(
capture,
offline.CandidateRule("fixed", 0.999, 0.5),
)
assert coarse.processed_until_sample == 500
assert coarse.termination_reason == "END_OF_CAPTURE"
assert strict.termination_reason == "END_OF_CAPTURE"
def test_max_candidates_fails_closed(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
@@ -572,9 +777,26 @@ def test_safety_limited_independent_run_does_not_unlock_tx_reference(
"MAX_CANDIDATES_REACHED",
True,
)
strict = offline.StrictSearchResult(
counters=offline.StrictCounters(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
accepted_frames=(),
outcomes=(),
cursor_history=(0,),
elapsed_seconds=0.0,
average_candidate_seconds=0.0,
maximum_local_window_samples=0,
maximum_local_window_bytes=0,
termination_reason="MAX_CANDIDATES_REACHED",
max_search_iterations_reached=True,
max_valid_frames_reached=False,
)
monkeypatch.setattr(offline, "calibrate_candidate_rule", lambda path: (rule, background))
monkeypatch.setattr(offline, "evaluate_control_background", lambda path, fixed: background)
monkeypatch.setattr(offline, "coarse_search_capture", lambda path, fixed: coarse)
monkeypatch.setattr(
offline,
"stream_process_capture",
lambda path, fixed: (coarse, strict),
)
result = offline.run_independent_recovery(capture)
assert result.completed is False
with pytest.raises(RuntimeError, match="verdict"):