15 KiB
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…e27109tx_packet.bin(268 B):cc179e93…e4554btx_bpsk_cs8.iq(2 798 400 B):15260dbc…f42e7rx_cs8.iq(64 000 000 B):8d5f4cd1…1019f1(в Git не добавляется)rx_packet.bin(264 B):b6ebbce3…c694e1rx_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
python tools/quick_gate.py— уже в этой сессии проходит синтаксис и импорт; локально должен пройти целиком, включаяpytest tests -q.python -m pytest tests/ -q— полный реальный прогон (в этой сессии недоступен физически, см. выше). Ожидается: все прежние тесты Lab043 зелёные, все 22 тестаtest_lab044_hackrf_bpsk_packet.pyзелёные.git diff --check— конфликт-маркеры/whitespace.- Только после полного PASS —
python experiments/lab044_hackrf_bpsk_packet.py --hardware --i-understand-hardware. - 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). - 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. - Raw IQ (
rx_cs8.iq,tx_bpsk_cs8.iq) в Git не добавлять.