Files
SDR-Rover/docs/lab044_current_state.md
LittleSam129 72f933a32b Lab044: validate arbitrary BPSK packet reception
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-31 14:39:12 +03:00

15 KiB
Raw Blame History

Lab044: текущее состояние

Статус

Lab044 hardware experiment ВЫПОЛНЕН один раз. RF TX count = 1. Результат: RESULT C (PHY sync восстановлен независимо, но protocol packet не восстановлен, CRC NOT_REACHED). CRC не PASS — это честный отрицательный, но научно полезный результат.

Реализация подготовлена поверх рабочей точки Lab043 (checkpoint 4cee6e9, "Lab043: establish reproducible HackRF BPSK working point") и не меняет её RF-параметры, gain, PHY sync, PRBS7-преамбулу, CRC или независимый детектор.

Фактический аппаратный результат (31 августа 2026 года)

Каталог артефактов: C:\Users\user\Documents\SDR_Rover_Lab044_raw\20260831_140142_bpsk_packet\

  • RF TX count = 1 (ровно одна передача, TransmitGuard, без retry).
  • Common clock = PASS: MASTER reg29 = 0x26, SLAVE reg29 = 0x26, SLAVE CLKIN = DETECTED за 69 мс (1 опрос), bounded polling 0.05/0.05/0.5 с.
  • PHY SYNC = PASS: независимый PRBS7-детектор преамбулы, peak/median +38.3 dB, peak/second +11.6 dB, payload не использовался.
  • FRAME HEADER: PHY SYNC 0xD391 декодирован верно, но поле PHY LENGTH искажено битовой ошибкой — декодировано 264 вместо 268 байт. Структурно frame_header_pass=true (sync совпал, длина в границах 1..1024), но длина фактически неверна.
  • PROTOCOL HEADER = FAIL (PAYLOAD_LENGTH_MISMATCH): protocol SYNC 0xAA55, version 1, message type 2 (TELEMETRY), sequence 44 декодированы верно, но payload_length = 2304 вместо 256 (битовая ошибка в старшем байте длины). expected_packet_bytes = 2316 ≠ 264.
  • CRC = NOT_REACHED (packet не собран корректно, до CRC decode не дошло).
  • Classification = C.

Радиометрика

  • independent preamble detected: да
  • preamble errors: 8 / 1280 (physical-layer BER ≈ 0.625 %, согласуется с ~0.4586 % Lab043)
  • CFO: 0.101 Hz (общий опорный генератор ⇒ почти нулевой сдвиг несущей)
  • SNR: 7.19 dB
  • separation: 4.574
  • timing offset: −3 samples
  • ADC peak: peak_complex 5.10 code, peak_component 5.0 code
  • ADC p99.9: 3.606 code (headroom 122 code до предела int8)
  • clipping: 0 (fraction 0.0), near-int8: 0
  • RX overruns: 0, TX underruns: 0 (оба лога чистые)

Ошибки данных (только ПОСЛЕ независимого CRC decision)

CRC-решение было NOT_REACHED, поэтому packet/payload BER не вычисляются как «после успешного decode». Диагностическое сравнение с TX-артефактами показало:

  • packet: comparable=false — RX 264 байт против TX 268 байт (длины не совпадают из-за искажения PHY LENGTH), побитовый BER не определён.
  • payload: comparable=false — rx_payload.bin не создан (protocol header не прошёл), payload не извлечён.

Первичный вывод: канал по-прежнему даёт ~0.6 % BER (как в Lab043), и в этом единственном кадре ошибки попали именно в поля длины (PHY LENGTH и protocol payload_length), что структурно сорвало разбор пакета раньше CRC. Это не новый дефект, а известная чувствительность незащищённого кадра к одиночным битовым ошибкам в критических полях — прямой довод в пользу FEC/защиты заголовка на следующем этапе.

BEFORE / DURING / AFTER

Границы построены по независимо найденному preamble start (sample 6 122 876) и декодированной PHY LENGTH.

Регион Длительность RMS (после DC) p95 p99 p99.9 peak clipping
BEFORE 0.765 с 0.776 3.162 3.606 3.606 5.00 0
DURING 0.171 с 0.833 3.162 3.606 3.606 4.47 0
AFTER 3.063 с 0.782 3.162 3.606 3.606 5.10 0

DURING отличается от фоновых BEFORE/AFTER повышенным RMS после удаления DC (0.833 против 0.776/0.782) — то есть на интервале кадра действительно присутствует переданный сигнал над фоном; хвосты амплитуды (p95/p99/p99.9) и clipping идентичны, перегрузки АЦП нет.

Артефакты и SHA-256 (пересчитаны независимо, совпали с metadata.json)

  • tx_payload.bin (256 B): aae1ee74…e27109
  • tx_packet.bin (268 B): cc179e93…e4554b
  • tx_bpsk_cs8.iq (2 798 400 B): 15260dbc…f42e7
  • rx_cs8.iq (64 000 000 B): 8d5f4cd1…1019f1 (в Git не добавляется)
  • rx_packet.bin (264 B): b6ebbce3…c694e1
  • rx_payload.bin: не создан (SHA-256 = null, фиктивный файл не создаётся)

Cleanup

MASTER CLKOUT OFF (SLAVE CLKIN = "no clock signal detected"), SLAVE CLKOUT OFF, зависших hackrf_transfer.exe нет.

Цель Lab044

Впервые передать по реальному RF BPSK-пакет с произвольным payload, который приёмник заранее не знает: arbitrary bytes → protocol packet → PHY frame → BPSK → RF → independent synchronization → demodulation → frame parsing → CRC verification. CRC PASS желателен, но не обязателен — CRC FAIL при BER около 0.4586% (унаследованном из Lab043) является нормальным научно полезным результатом (RESULT B).

Формат (подтверждён по фактическому коду, не принят на веру)

  • protocol/packet.py: HEADER_FORMAT = ">HBBHH" (8 байт: SYNC 0xAA55, version, message type, sequence number, payload length), CRC-32 (zlib.crc32, big-endian uint32, 4 байта), CRC покрывает header+payload.
  • Payload = 256 bytes, protocol packet = 268 bytes (8 + 256 + 4), сгенерирован через secrets.token_bytes — системный источник случайности, один раз.
  • PHY frame = [1280-bit PRBS7 preamble Lab043][PHY SYNC 0xD391 + PHY LENGTH uint16, ">HH", big-endian][protocol packet] = 3456 BPSK-символов (1280 + 32 + 268×8). Преамбула — та же аппаратно проверенная 1280-битная PRBS7 (pilot_prbs7, PILOT_INITIAL_STATE=0x7F) из experiments/lab043_hackrf_bpsk.py, не generic-маркер из protocol/bpsk_radio.build_radio_frame().
  • Waveform = 1,399,200 сэмплов при 8 MS/s ⇒ длительность ≈ 174.9 мс (после RRC-формирования Lab042: rolloff 0.35, span 10 символов, guard 16 символов).
  • Bit order: MSB-first, явно (np.unpackbits(..., bitorder="big")).
  • MAX_PACKET_BYTES = 1024 (fail-closed предел для PHY LENGTH).

RF-параметры (без изменений от Lab043)

RF center 1080 MHz, sample rate 8 MS/s, symbol rate 20 ksym/s, digital carrier offset +50 kHz, TX VGA = 10 dB, RX LNA = 24 dB, RX VGA = 24 dB, RF amp OFF, common clock: JYEC TCXO 10 MHz MASTER → MASTER CLKOUT → SLAVE CLKIN, bounded common-clock preflight (initial_settle=0.05s, poll_interval=0.05s, timeout=0.5s), reg29 = 0x26 на обеих платах.

Пробелы аудита A/B/C — закрыты

A. TRUNCATED PROTOCOL PACKET TEST — FIXED. Добавлен test_truncated_protocol_packet_is_flagged_without_exception (tests/test_lab044_hackrf_bpsk_packet.py): синтетический capture с полной преамбулой и полным PHY header, но физически обрезанным (не дополненным нулями) телом protocol packet. Ожидаемое и фактическое поведение: phy_sync_pass=True, frame_header_pass=False, packet_received=False, frame_header["reason"]=="TRUNCATED_PACKET", crc=="NOT_REACHED", без исключений, без изменения рабочей классификации. Исходный код analyze_capture_independently этот путь уже предусматривал — не хватало только теста, подтверждающего его достижимость и корректность.

B. BEFORE/DURING/AFTER DIAGNOSTICS — FIXED. Добавлена функция _capture_diagnostics() в experiments/lab044_hackrf_bpsk_packet.py, переиспользующая lab043._capture_intervals() и lab043.raw_statistics() без изменения самого Lab043 (совместимый набор полей: mean I/Q, RMS после DC removal, p95/p99/p99.9 magnitude, peak, clipping count/fraction — плюс добавленные sample_range и duration_seconds на каждый регион). Граница DURING строится только по detection["refined_start_sample"] (независимый preamble) и по PHY LENGTH, если она уже декодирована; если PHY header ещё не восстановлен — по максимально возможной длине кадра Lab044 (MAX_PACKET_BYTES), payload никогда не используется. Если независимый preamble не найден вовсе, DURING остаётся None с явной пометкой в поле note, сохраняется только whole_capture. Результат добавлен как analysis["capture_intervals"] во всех пяти точках возврата analyze_capture_independently (RESULT A/B/C/D). Тесты: test_capture_intervals_present_for_independently_decoded_frame, test_capture_intervals_undefined_when_no_independent_start.

C. SHA-256 ДЛЯ ВСЕХ BINARY ARTIFACTS — FIXED. Добавлена функция _artifact_sha256(), переиспользующая lab043._sha256_file(). После run_hardware_experiment() в metadata.json появляется поле artifact_sha256 с хэшем каждого РЕАЛЬНО существующего файла: tx_payload.bin, tx_packet.bin, tx_bpsk_cs8.iq, rx_cs8.iq, rx_packet.bin, rx_payload.bin. Для rx_packet.bin/rx_payload.bin, если decode не дошёл до их создания, значение — None; фиктивный файл не создаётся (это поведение уже было в коде и не менялось). Тесты: test_artifact_sha256_recorded_for_every_real_rx_and_tx_file, test_no_fake_rx_artifacts_or_hashes_when_packet_not_decoded.

Ничего из RF-параметров, gain, packet format, PHY sync, PRBS7-преамбулы, payload size, CRC, независимого детектора или порогов Lab043 не менялось. FEC/QPSK/JPEG/video не добавлялись.

Что реально проверено в этой сессии

Эта сессия работает без device_bash на машине пользователя и без доступа к сети из своей песочницы (нет pip/apt-репозитория), поэтому команда pytest в буквальном смысле NOT EXECUTED IN THIS SESSION.

Вместо этого фактически выполнено (все результаты — реальный вывод интерпретатора, не предположение):

  • ast.parse() по experiments/lab044_hackrf_bpsk_packet.py и tests/test_lab044_hackrf_bpsk_packet.py — синтаксис корректен.
  • Полный импорт experiments.lab044_hackrf_bpsk_packet со всей цепочкой зависимостей (protocol.*, experiments.lab043_*) — импортируется без ошибок.
  • Все 22 функции test_* из tests/test_lab044_hackrf_bpsk_packet.py (17 существовавших + 5 новых для A/B/C) вызваны напрямую, как обычные Python-функции, с самодельными подстановками фикстур tmp_path и monkeypatch (реальный pytest недоступен для установки в этой песочнице — нет сетевого доступа к PyPI/apt) — 22/22 PASS. Это честная проверка логики, но не замена запуску pytest как CLI-команды.
  • python tools/quick_gate.py запущен реально: синтаксис и импорт protocol/* прошли, единственная сообщённая ошибка — сам pytest не установлен (No module named pytest), что ожидаемо и не является дефектом кода.
  • Аппаратный RF-эксперимент не запускался и не имитировался.

Что должен сделать локальный агент перед RF

  1. python tools/quick_gate.py — уже в этой сессии проходит синтаксис и импорт; локально должен пройти целиком, включая pytest tests -q.
  2. python -m pytest tests/ -q — полный реальный прогон (в этой сессии недоступен физически, см. выше). Ожидается: все прежние тесты Lab043 зелёные, все 22 теста test_lab044_hackrf_bpsk_packet.py зелёные.
  3. git diff --check — конфликт-маркеры/whitespace.
  4. Только после полного PASS — python experiments/lab044_hackrf_bpsk_packet.py --hardware --i-understand-hardware.
  5. STOP conditions: common-clock preflight FAIL, RX завершился до TX, TX/RX вернули ненулевой код, log содержит overrun/underrun, любое исключение — во всех случаях RF TX должен остаться равным 0 (гарантия TransmitGuard, покрыта тестами test_common_clock_failure_means_zero_tx, test_frame_validation_failure_means_zero_tx, test_rx_startup_failure_means_zero_tx).
  6. Artifacts появятся в ~/Documents/SDR_Rover_Lab044_raw/<timestamp>_bpsk_packet/: tx_payload.bin, tx_packet.bin, tx_bpsk_cs8.iq, rx_cs8.iq, rx_packet.bin (если извлечён), rx_payload.bin (если извлечён), metadata.json, analysis.json.
  7. Raw IQ (rx_cs8.iq, tx_bpsk_cs8.iq) в Git не добавлять.