Prepare coordinated RF-001A OTA test

This commit is contained in:
LittleSam129
2026-09-18 15:30:45 +03:00
parent 7ec8c351bc
commit 320adeea4a
8 changed files with 414 additions and 50 deletions

View File

@@ -7,72 +7,45 @@ stop and report the conflict.
# Current RX task
TASK =
RX-ONLY HACKRF HARDWARE PREFLIGHT
1. GIT. In the laptop project named in RX_NODE_STATE.md, record the starting branch, HEAD, and `git status --short --untracked-files=no`. Stop if tracked files are modified or the branch is not `video-development`. Run `git pull origin video-development`. Require `git branch --show-current` = `video-development`, `git rev-parse HEAD` = `git rev-parse origin/video-development`, and a clean tracked checkout. Local ignored or untracked RF-001 results outside Git are not a conflict.
2. VIDEO FIXTURE AND SEPARATE VIDEO TESTS. Check whether `data/raw/video001/udacity_project_video.mp4` exists, then record its size and `Get-FileHash -Algorithm SHA256`. The required file has 25268015 bytes and SHA256 `651949922042c223375d40bf8929def97dbb62c6ade651d1f5b08eea47127d5f`. A same-size file with SHA256 `bff9b28d0e1f5442cfdf9f2bd51251d66506ca518ad7dfe6074670859731a8fb` is not valid. If absent or mismatched, report VIDEO FIXTURE = NOT_READY, VIDEO FIXTURE TESTS = NOT_RUN / BLOCKED_BY_FIXTURE, and VIDEO GATE = NOT_RUN. This is NON-BLOCKING FOR RX-ONLY HARDWARE PREFLIGHT. Do not download or substitute a file, change the expected SHA256, weaken VIDEO-001 checks, or mark the two previously failing VIDEO-004 tests PASS. If the fixture is valid, run the complete `python -B -X utf8 tools/video_gate.py` and report the VIDEO fixture test and gate results separately; failures remain failures and do not become RF targeted test results.
3. RF TARGETED PYTEST. Run the following explicit, fixture-independent RF/QPSK test scope. Do not expand the wildcard `test_video*.py` or add the entire VIDEO-004 suite to this mandatory command:
PREPARE RF-001A COMMON-CLOCK RX
1. In the project path from RX_NODE_STATE.md, record branch, HEAD and `git status --short --untracked-files=no`. Require clean tracked state and `video-development`. Run `git pull origin video-development`; then require local HEAD = `origin/video-development`. Do not commit or push.
2. Read `configs/rf/rf001a_common_clock.json` and `docs/rf/RF_001A_PREPARATION.md`. Run `python -B -X utf8 tools/rf001a_prepare.py --verify-dir <TX artifact directory>` only if the TX artifact has been transferred locally; otherwise run `python -B -X utf8 -c "from tools.rf001a_prepare import load_spec; print(load_spec())"` to check the shared spec against the existing PHY. Do not substitute a video fixture or alter the expected hashes.
3. Run fixture-independent RF TARGETED PYTEST, Ruff, Pyright and `git diff --check`:
```powershell
python -B -m pytest tests/test_packet.py tests/test_video003_modem.py tests/test_video005_iq.py tests/test_rf001_preparation.py tests/test_clock001.py tests/test_hackrf_process_check.py -q
```
This covers packet parsing and CRC, QPSK modulation/demodulation, FEC 2/3, VIDEO-005 raw IQ timing and carrier recovery, the RF-001 offline TX/IQ/RX tools, CLOCK-001, and hardware-independent HackRF process checks. The RF-001 receiver uses the VIDEO-004 Viterbi decoder, which the full RF-001 round-trip test exercises. Outer erasure FEC reconstructs video frames and is not in the RF-001 packet receiver path; it is not part of this RF-only gate. These six files require neither `data/raw/video001/udacity_project_video.mp4` nor `data/raw/lab064/tx_metadata.json`. Missing Numba or another required dependency is a failure, not a reason to skip the RF-001 round trip.
Also run targeted Ruff, Pyright, and `git diff --check`:
```powershell
python -B -c "import subprocess, sys; from tools.video_gate import STATIC_PATHS; sys.exit(subprocess.call([sys.executable, '-B', '-m', 'ruff', 'check', *STATIC_PATHS]))"
python -B -m pytest tests/test_packet.py tests/test_video003_modem.py tests/test_video005_iq.py tests/test_rf001_preparation.py tests/test_rf001a_prepare.py tests/test_clock001.py tests/test_hackrf_process_check.py -q
python -B -m ruff check tools/rf001a_prepare.py tests/test_rf001a_prepare.py tools/qpsk_rf_common.py tools/qpsk_rf_tx.py tools/qpsk_rf_rx.py
python -B -m pyright --project pyrightconfig.json
git diff --check
```
Repeat the software-only offline RF-001 round trip from `docs/rf/RF_001.md` in new local output paths: 100 generated packets → IQ file → independent receiver. Require 100/100 CRC-valid and 100/100 exact packets; preserve stdout and the JSON report. Run `hackrf_info` and record its full output. Stop before hardware streaming if RF TARGETED PYTEST, Ruff, Pyright, `git diff --check`, the offline packet counts, the Git checks, or `hackrf_info` fails.
4. HISTORICAL LAB064. The missing `data/raw/lab064/tx_metadata.json` is not in RF TARGETED PYTEST and is NON-BLOCKING FOR RF-001 RX NODE. Do not create or simulate it. A full `python -B -m pytest tests/ -q` is optional; if run, classify only the verified failure caused by that missing file as HISTORICAL LAB064 FIXTURE MISSING. Any other new failure blocks readiness and stops the hardware stream test.
5. RX-ONLY HARDWARE PREFLIGHT. When all mandatory checks in step 3 pass, RX NODE READY FOR RX-ONLY HARDWARE TEST = YES even if VIDEO FIXTURE = NOT_READY and VIDEO GATE = NOT_RUN. Open the HackRF only as a receiver. Make one bounded raw IQ capture at 8,000,000 samples/s, center frequency 1,400,000,000 Hz, for about 5 seconds. Record the exact receive-only command and settings. A 5-second `cs8` capture contains 40,000,000 complex samples and 80,000,000 bytes if complete. Save raw interleaved signed I/Q bytes in a new local file outside Git; do not overwrite prior captures. Preserve stdout/stderr, start and end times, file size and SHA256, actual sample count and duration, elapsed wall time, and measured file write rate. Record every available RX overrun observation during the run and the final value, USB errors, and file write errors. Never convert an absent or incomplete counter into zero: report NOT_REPORTED and mark the stream test FAIL if capture integrity cannot be verified. Any nonzero overrun, USB error, file write error, truncated file, or capture failure is FAIL. Use a receive-only tool; `hackrf_transfer` is permitted for this bounded RX capture only, never with a transmit option. Do not decode RF-001 packets: the transmitter is off.
6. CLASSIFICATION. Set RX-ONLY IQ STREAM TEST = PASS only for a complete capture with clean, sufficiently observed counters. Set RX NODE READY FOR RF-001 OTA = YES only if the Git checks, RF TARGETED PYTEST, targeted Ruff, Pyright, `git diff --check`, offline RF-001 100/100 CRC-valid and 100/100 exact packets, `hackrf_info`, and RX-only IQ stream test all pass. VIDEO fixture, VIDEO fixture tests, VIDEO GATE, and the sole verified historical Lab064 fixture failure are separate findings and do not block this RF-only stage. Readiness does not authorize RF TX; that requires a separate explicit task.
7. Do not perform RF TX, firmware or CPLD updates, `hackrf_spiflash`, Zadig, USB driver changes, commit, or push on the RX laptop. Do not add raw IQ or video files to Git.
8. Finish with the following report. Use PASS, FAIL, NOT_RUN, NOT_READY, BLOCKED_BY_FIXTURE, or NOT_REPORTED as appropriate; state the cause of each failure.
These checks do not use the VIDEO-001 file or historical Lab064 metadata. Repeat the existing offline RF-001 100/100 packet check in new local paths. Missing prerequisites remain failures; do not label blocked video tests PASS.
4. Run `hackrf_info`, save full output, and confirm this is the RX device. Check shared-spec center frequency 1400000000 Hz, sample rate 8000000/s, RX LNA 24 dB, RX VGA 24 dB, RF amp OFF, antenna bias OFF and digital carrier +125000 Hz. Confirm `hackrf_transfer -h` maps `-l` to RX LNA, `-g` to RX VGA, `-a 0` to amp OFF and `-p 0` to bias OFF. Record actual RX serial.
5. Prepare a new unique raw IQ output directory outside Git, preserving existing captures. Check at least 320000000 bytes plus comfortable free-space margin on the destination volume. The 20 s finite capture is 160000000 complex samples in signed interleaved I/Q cs8, exactly 320000000 bytes (about 320 MB / 305.2 MiB). Prepare this command with the actual RX serial and a new path; **do not run it in this preparation task**:
```powershell
& '<verified hackrf_transfer.exe path>' -d <RX_SERIAL> -r <NEW_RAW_IQ_PATH.cs8> -f 1400000000 -s 8000000 -n 160000000 -l 24 -g 24 -a 0 -p 0 -B
```
6. Manual checkpoint for a future coordinated session: both antennas and USB connections, 10 MHz reference → MASTER → MASTER CLKOUT → SLAVE CLKIN, roles, polarization and safe distance. Freshly verify MASTER/SLAVE reg29 and SLAVE CLKIN. Old 0x26/DETECTED readings are historical only. Record `COMMON CLOCK VERIFIED = YES / NO`; until YES, RF TX is prohibited. RX capture also waits for the later coordinated task.
7. Future session sequence: start finite RX capture, confirm it is active, then a separately authorized one-shot TX, finish capture, preserve full raw IQ plus stdout/stderr and every available intermediate/final overrun or underrun observation, then decode the same raw IQ offline with existing `qpsk_rf_rx.py --iq-format cs8`. Record size, sample count, duration and SHA256. Missing or incomplete counters are NOT_REPORTED, never zero.
8. Report readiness and STOP. No RX capture now, RF TX, continuous RX, firmware/CPLD updates, hackrf_spiflash, Zadig, USB driver changes, commit or push. Keep large IQ/video out of Git.
TASK =
RX-ONLY HACKRF HARDWARE PREFLIGHT
PREPARE RF-001A COMMON-CLOCK RX
BRANCH =
HEAD =
VIDEO FIXTURE =
VIDEO FIXTURE SHA256 =
VIDEO FIXTURE TESTS =
VIDEO GATE =
SHARED TEST SPEC =
RF TARGETED PYTEST =
RUFF =
PYRIGHT =
GIT DIFF CHECK =
OFFLINE RF-001 =
HACKRF INFO =
RX-ONLY IQ STREAM TEST =
SAMPLE RATE =
CAPTURE DURATION =
CAPTURE SIZE =
RX OVERRUNS =
USB ERRORS =
FILE WRITE ERRORS =
RAW IQ SHA256 =
RX NODE READY FOR RF-001 OTA =
RX SERIAL =
RX CAPTURE COMMAND PREPARED =
RX CAPTURE FREE SPACE =
COMMON CLOCK VERIFIED =
PHYSICAL CHECKPOINT =
RX READY TO CAPTURE =
YES / NO
RF TX =
0
STOP.

View File

@@ -0,0 +1,37 @@
This file is the authoritative current task for the main PC TX node.
Read TX_NODE_STATE.md first. If chat history, this file, the shared spec, and current Git HEAD conflict, stop and report the conflict.
# Current TX task
TASK =
PREPARE RF-001A COMMON-CLOCK TX
1. Record branch, HEAD and tracked Git status. Require video-development and agreement with origin/video-development.
2. Read configs/rf/rf001a_common_clock.json and docs/rf/RF_001A_PREPARATION.md. Check all parameters against the shared spec; do not adjust them silently.
3. Run hackrf_info and record board, serial, libhackrf and firmware. Stop if HackRF is absent. Do not invoke transmit.
4. Verify the local canonical waveform and cs8 file using `python -B -X utf8 tools/rf001a_prepare.py --verify-dir data/raw/rf001/rf001a_common_clock_001`. Require both exact SHA256 values from the shared spec, count, duration, I/Q order, signed format, zero rail codes and checked quantization error. If local files are absent, create a new unique directory with `--output-dir`, then verify; never overwrite prior files. Keep raw IQ out of Git.
5. Repeat the offline RX of that exact cs8 file with `tools/qpsk_rf_rx.py --iq-format cs8`, `tx_metadata.json` truth and a new report path. Require 100/100 CRC-valid and 100/100 exact packets. Preserve stdout and JSON.
6. Check center frequency, sample rate, +125 kHz digital offset and gains against the shared spec. Prepare the one-shot command shown in RF_001A_PREPARATION.md, but do not execute it.
7. Manual physical checkpoint: TX and RX antennas, both USB links, 10 MHz reference, MASTER/SLAVE roles, same antenna polarization, safe lab distance (about 1.2 m LOS if applicable), and no direct unattenuated TX RF → RX RF connection. Freshly verify MASTER and SLAVE reg29 and SLAVE CLKIN detection. Historical values 0x26/DETECTED do not count. Record COMMON CLOCK VERIFIED = YES / NO. If NO or unknown, TX remains prohibited.
8. Read RX preparation report. Do not infer RX readiness from older preflight. End before first RF TX. No firmware/CPLD, hackrf_spiflash, Zadig or driver changes.
TASK =
PREPARE RF-001A COMMON-CLOCK TX
BRANCH =
HEAD =
HACKRF INFO =
CANONICAL SHA256 =
HARDWARE CS8 SHA256 =
HARDWARE-FORMAT OFFLINE ROUNDTRIP =
CENTER FREQUENCY =
SAMPLE RATE =
DIGITAL CARRIER OFFSET =
TX GAIN =
COMMON CLOCK VERIFIED =
PHYSICAL CHECKPOINT =
RX READY TO CAPTURE =
TX READY FOR RF-001A =
YES / NO
RF TX =
0
STOP.

View File

@@ -0,0 +1,27 @@
# TX node state
ROLE =
MAIN PC TX NODE
PROJECT PATH =
C:\Users\user\Desktop\projects\SDR_Rover_Video
BRANCH =
video-development
HARDWARE =
Auron HackRF Plus; hackrf_info reports HackRF One r9
RF-001A TEST SPEC =
configs/rf/rf001a_common_clock.json
Main PC owns development and pushes video-development. Current RF TX authorization = 0.
DO NOT WITHOUT EXPLICIT TASK AUTHORIZATION:
- RF TX or continuous TX
- firmware or CPLD update
- hackrf_spiflash
- Zadig or USB driver changes
- RF parameter changes
Large IQ/video files and local device logs stay out of Git.

View File

@@ -0,0 +1,75 @@
# RF-001A: подготовка опыта с общей опорой 10 МГц
Текущее состояние: **PREPARED_NOT_RUN**. Передача в эфир, общий такт и двухузловой захват в этой задаче не проверялись. Единый источник параметров: [rf001a_common_clock.json](../../configs/rf/rf001a_common_clock.json). Перед каждым опытом оба узла сверяют с ним настройки. Проверка `tools/rf001a_prepare.py` отвергает расхождение spec с действующими константами TX и VIDEO-005 RX. Новый PHY не добавлен.
## Подготовленные файлы на основном ПК
`python -B -X utf8 tools/rf001a_prepare.py --output-dir data/raw/rf001/<новый_уникальный_каталог>` создаёт исходный `tx_waveform.c64le`, прежнюю TX-ведомость `tx_metadata.json` с seed, порядком 0…99 и SHA каждого пакета, `tx_waveform.cs8` и `rf001a_metadata.json`. Каталог должен быть новым. Файлы лежат в игнорируемом Git `data/raw/`; их нельзя добавлять в коммит. Текущий локальный экземпляр: `data/raw/rf001/rf001a_common_clock_001/`.
| Параметр | Проверенное значение |
|---|---:|
| TEST ID | `RF001A_COMMON_CLOCK_001` |
| Идентификатор прежнего TX/RX формата metadata | `RF001_QPSK_500K_R23_256B_100P_GAP5MS` |
| QPSK, FEC, payload, packets, gap | 500000 симв/с, 2/3, 256 байт, 100, 5 мс |
| Seed | 20260917 |
| Центр RF / частота отсчётов | 1400000000 Гц / 8000000 отсчётов/с |
| Цифровое смещение | +125000 Гц: `RF_001_PLAN.md` и `protocol/video005_iq_waveform.py` |
| Длина TX | 8833828 комплексных отсчётов; 1,1042285 с |
| Исходный c64le | 70670624 байта; SHA256 `7cd81395efaa88b623b7e4e5a02e3a80b52185007397ea56ceaacc13353974b2` |
| Компонентный peak / комплексный RMS | 0,3949069381 / 0,1854172647 в исходных единицах |
| HackRF cs8 | 17667656 байт; SHA256 `75f3fa39bfa4ee419f0676c54e4b9c486d7ff64bd0fe2fc06343b20c9d117ecd` |
| cs8 | signed int8, чередование I/Q, множитель 256 кодов на единицу источника |
| Проверка cs8 | 0 кодов -128/127; обратное чтение совпало с ожидаемыми квантованными отсчётами; максимальная ошибка компоненты 0,001953125 |
| Офлайн-приём именно cs8 | 100/100 CRC-valid, 100/100 exact, существующий `qpsk_rf_rx.py` → VIDEO-005 receiver |
Проверить файлы повторно: `python -B -X utf8 tools/rf001a_prepare.py --verify-dir data/raw/rf001/rf001a_common_clock_001`. Затем `python -B -X utf8 tools/qpsk_rf_rx.py --iq-file data/raw/rf001/rf001a_common_clock_001/tx_waveform.cs8 --iq-format cs8 --truth-metadata data/raw/rf001/rf001a_common_clock_001/tx_metadata.json --report data/raw/rf001/<новый_отчёт>.json`. Отчёт нельзя перезаписывать. Метаданные TX сохраняют прежний идентификатор, который проверяет существующий RX; `rf001a_metadata.json` связывает их с новым ID опыта. Истина применяется после работы приёмника.
## Настройки оборудования для следующего, отдельно разрешённого сеанса
Предусмотрены TX VGA 20 дБ (`-x 20`), RX LNA 24 дБ (`-l 24`), RX VGA 24 дБ (`-g 24`), RF amplifier OFF (`-a 0`), питание антенны OFF (`-p 0`). Это baseline Lab066; назначения флагов и шаги проверены по установленному `hackrf_transfer -h`. На основном ПК `hackrf_info` обнаружил HackRF One r9, serial `000000000000000097c063dc323b97d3`, libhackrf/firmware 2024.02.1, API 1.08. Название устройства в задаче: Auron HackRF Plus. RX serial надо заново снять на ноутбуке; не переносить serial TX на RX.
Общая опора: 10 МГц reference → MASTER → MASTER CLKOUT → SLAVE CLKIN. Старые `reg29=0x26` на обоих устройствах и `SLAVE CLKIN=DETECTED` из `RF_001_PLAN.md` не доказывают текущую синхронизацию. Перед будущим TX требуется ручная отметка `COMMON CLOCK VERIFIED = YES` после свежей проверки MASTER/SLAVE, проводов и признака CLKIN на SLAVE. Также вручную подтвердить подключённые антенны, оба USB, согласованную поляризацию и безопасную дистанцию. Если прежняя геометрия применима, около 1,2 м, LOS, одинаковая поляризация. Прямой кабель TX RF → RX RF допустим лишь с нужным ослаблением. Геометрию A/B не менять.
**Будущая команда TX, только для подготовки, не запускать сейчас:**
```powershell
& 'C:\Users\user\Tools\HackRF\Library\bin\hackrf_transfer.exe' -d 000000000000000097c063dc323b97d3 -t data/raw/rf001/rf001a_common_clock_001/tx_waveform.cs8 -f 1400000000 -s 8000000 -n 8833828 -x 20 -a 0 -p 0 -B
```
Она однократная, без `-R`. Прежде чем дать отдельное разрешение на TX, сверить SHA cs8, RX READY, физический checkpoint и общую опору. Пока `RF TX = 0`.
RX готовит новый каталог и конечный захват 20 с: 160000000 комплексных отсчётов cs8, ровно 320000000 байт (около 320 MB или 305,2 MiB). До захвата проверить свободное место с запасом. RX запускается первым, пользователь видит активный захват, затем отдельно разрешённый TX делает одну передачу; оба процесса завершаются, raw IQ и полные stdout/stderr сохраняются, тот же raw IQ анализируется офлайн. Не принимать неизвестные промежуточные или конечные underrun/overrun за ноль.
## Форма отчёта будущего опыта
```text
TEST ID =
CLOCK MODE = COMMON 10 MHz
CENTER FREQUENCY =
SAMPLE RATE =
MODULATION = QPSK
SYMBOL RATE = 500 ksymbol/s
INNER FEC = 2/3
PAYLOAD = 256 bytes
GAP = 5 ms
TX PACKETS = 100
DETECTED PREAMBLES =
CRC VALID PACKETS =
EXACT PACKETS =
PACKET SUCCESS RATE =
RAW BER =
POST-FEC ERROR RATE =
MISSING PACKETS =
DUPLICATES =
CFO MEDIAN =
CFO P95 =
TIMING OFFSET =
TIMING DRIFT =
TX UNDERRUNS =
RX OVERRUNS =
RX CLIPPING =
RAW IQ SHA256 =
RESULT = GOOD / PARTIAL / FAIL
```
Для первого smoke test 99–100 exact = GOOD, 95–98 = PARTIAL/DIAGNOSTIC, <95 = FAIL FOR VIDEO PROGRESSION. Один прогон не подтверждает статистическую надёжность. Неизмеренное поле помечать `NOT_MEASURED`, отсутствующий счётчик `NOT_REPORTED`. RF-001B сейчас только план: повторить опыт без общей опоры при тех же частотах, sample/symbol rate, FEC, payload, gap, gain, антеннах и геометрии. RF-001B не запускать.