Files
SDR-Rover/docs/lab048_current_state.md
2026-09-03 14:42:02 +03:00

207 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Lab048: профилирование и ускорение автономного BPSK-приёмника
## Состояние
Lab048 завершена успешно только на сохранённой аппаратной RX-записи Lab047.
Новый радиосеанс не выполнялся: `RF TX = 0`, HackRF не запускался. Научные
критерии обнаружения и принятия кадра, BPSK, PRBS7, PHY, FEC, CRC, формат
пакета и порог `0.030964473262429237` не изменены.
Итоговая обработка 15,0 с эфира занимает 13,966058 с. Это в 2,679633 раза
быстрее исходных 37,423910 с и впервые быстрее длительности самой записи:
отношение времени обработки к времени эфира равно 0,931071.
## Исходная контрольная точка
Использована та же запись:
`C:\Users\user\Documents\SDR_Rover_Lab047_raw\20260903_115747\rx_stream.cs8`.
Размер — 240000000 байт, 120000000 комплексных отсчётов, длительность 15,0 с,
SHA-256 `8521bf1b574cd1fe4e0a4f980c00c8664f8bb51551a241e46449e1eb2c77e635`.
Принятые до оптимизации метрики Lab047:
- полное время: 37,423910 с;
- строгая ступень: 32,459969 с;
- среднее время строгой проверки: 0,470434 с;
- строгих кандидатов: 69;
- приблизительный пик памяти: 1545755352 байта, около 1,44 ГиБ;
- действительных кадров: 36;
- CRC PASS/FAIL: `36/0`;
- полный JPEG, SHA-256 совпадает, ошибок байтов и битов нет.
## Базовое профилирование
До изменения кода выполнен один полный проход под `cProfile`. Он сохранил
185828 локальных максимумов, 32414 кандидатов первого каскада, 69 строгих
проверок, 36 действительных кадров, CRC PASS/FAIL `36/0` и точный JPEG.
Накладные расходы профилировщика увеличили полное время до 45,947287 с,
поэтому коэффициент ускорения считается относительно принятого измерения без
профилировщика 37,423910 с.
Десять функций по суммарному времени:
| Функция | Вызовы | Суммарно, с |
|---|---:|---:|
| `_run_with_fixed_candidate_rule` | 1 | 45,945 |
| `stream_process_capture` | 1 | 45,930 |
| `decode_candidate_from_memmap` | 69 | 40,912 |
| `_extract_soft_window` | 105 | 25,697 |
| `_matched_waveform` | 105 | 21,199 |
| `fftconvolve` | 252 | 13,660 |
| `_freq_domain_conv` | 252 | 12,811 |
| `__ua_function__` FFT | 756 | 11,889 |
| `root_raised_cosine_taps` | 175 | 11,885 |
| `_execute_nD` FFT | 756 | 11,881 |
Десять функций по собственному времени:
| Функция | Вызовы | Собственное время, с |
|---|---:|---:|
| `scipy.fft c2c` | 756 | 11,222 |
| `_matched_waveform` | 105 | 5,704 |
| `numpy.isclose` | 1400175 | 5,407 |
| `upfirdn.apply_filter` | 9 | 3,171 |
| `_timing_offsets` | 105 | 2,859 |
| `root_raised_cosine_taps` | 175 | 2,306 |
| `_scale_and_carrier` | 70 | 1,801 |
| генератор `numpy.isclose` | 7000875 | 1,160 |
| `_cs8_window` | 113 | 1,105 |
| `_freq_domain_conv` | 252 | 0,917 |
Профиль показал повторное формирование одной опорной преамбулы 70 раз и
одинаковых RRC-коэффициентов 175 раз. Согласованный фильтр вызывался 105 раз:
69 коротких окон для PHY и 36 полных окон. Временная синхронизация выполняла
1601 Python-итерацию для каждого окна. Витерби занимал лишь 0,875 с на все 36
кадров, CFO/фаза — 0,054 с на 105 вызовов, PHY-заголовок — 0,006 с. Поэтому
FEC, CFO, фаза, PHY и CRC не оптимизировались.
## Выполненные оптимизации
Изменены только вычислительные детали приёмника:
1. Опорная PRBS7-преамбула формируется один раз, кэшируется и защищается от
записи.
2. RRC-коэффициенты формируются один раз, хранятся как неизменяемый `float32`.
3. Та же полная линейная RRC-свёртка вычисляется методом overlap-add
(`oaconvolve`) вместо единой FFT (`fftconvolve`).
4. Неизменяемые векторы переноса несущей кэшируются по началу и длине окна;
кэш ограничен четырьмя записями.
5. Рабочие массивы согласованного фильтра переведены с `complex128` на
`complex64`. Максимальное абсолютное расхождение с прежним фильтром на
проверочном шумовом массиве равно `1,263e-6`, менее `5e-7` от пика.
6. Преамбульная временная синхронизация считает те же 1601 нормированные
оценки группами по 400 фазам и не вычисляет второй идентичный набор оценок.
Прямой тест прежнего `fftconvolve/complex128` и нового
`oaconvolve/complex64` требует абсолютное расхождение не более `2e-6` и
отношение максимального расхождения к пику менее `5e-7`. Отдельные тесты
подтверждают точность и неизменяемость кэшей, ограничение их размера, тот же
timing offset и отсутствие TX/expected-frame параметров у независимого API.
Существующие сквозные тесты защищают те же PHY, FEC, CRC и полезные данные.
## Единственный итоговый полный проход
После программного шлюза выполнен один итоговый полный проход той же записи.
Первый вызов нового командного файла завершился до импорта проекта из-за
отсутствующего загрузочного пути: RX не открывался и файл-свидетель не был
создан. После исправления загрузочного блока выполнен ровно один фактический
полный проход; автоматического повтора нет.
Независимая стадия не получала ожидаемое число кадров, TX offsets, номера
TX-фрагментов, переданный JPEG, пакеты или кодированные биты. Только после
`completed = true` и `OBJECT COMPLETE = YES` выполнена диагностическая сверка
с TX.
Результат:
- полное время: 13,966058 с;
- грубый поиск: 4,776677 с;
- строгая ступень: 9,171629 с;
- среднее время строгой проверки: 0,132922 с;
- ускорение полного прохода: 2,679633 раза;
- отношение обработки к длительности эфира: 0,931071;
- `REAL-TIME CAPABLE = YES`;
- локальных максимумов: 185828;
- кандидатов первого каскада: 32414;
- строгих проверок: 69;
- пропущено внутри уже принятых областей: 32345;
- точных дубликатов: 0;
- PHY-заголовок PASS/FAIL: `36/33`;
- FEC attempts/PASS/FAIL: `36/36/0`;
- CRC PASS/FAIL: `36/0`;
- действительных кадров и фрагментов: `36/36`;
- отсутствующих фрагментов: 0;
- `OBJECT COMPLETE = YES`.
Только после независимого вердикта подтверждены 36/36 переданных кадров,
19 ошибок кодированных бит до FEC, 0 ошибок протокольных бит после FEC и 0
ложных CRC PASS. Восстановленный JPEG имеет 8724 байта, RGB 320 x 240,
декодируется Pillow и имеет SHA-256
`e913dab9ac32795250880a4be67fbbbf89a4f96536842476ab591d1acaafc02a`.
SHA-256 переданного файла совпадает; ошибочных байтов 0, ошибочных битов 0.
## Время стадий после оптимизации
Измерения вложенных функций пересекаются по времени:
| Стадия | Вызовы | Суммарно, с |
|---|---:|---:|
| преобразование CS8 в `complex64` | 113 | 1,487798 |
| уточнение начала | 69 | 3,121533 |
| согласованный фильтр | 105 | 3,282575 |
| временная синхронизация | 105 | 1,270783 |
| CFO, фаза и мягкие решения | 105 | 0,042236 |
| PHY-заголовок | 105 | 0,004111 |
| FEC, разбор пакета и CRC | 36 | 0,645559 |
| Витерби | 36 | 0,627109 |
Следующее узкое место верхнего уровня — грубый поиск, 4,776677 с. Внутри
строгой ступени сопоставимы согласованный фильтр, 3,282575 с, и уточнение
начала, 3,121533 с. Запас реального времени пока мал: около 1,03 с на 15 с
эфира.
## Память
Консервативная пиковая оценка осталась 1545755352 байта, около 1,44 ГиБ,
поскольку максимум создаёт неизменённая обработка 16-миллионного блока
грубого поиска. Крупнейшие явно управляемые массивы:
| Назначение | dtype | shape | MiB |
|---|---|---:|---:|
| окно грубого поиска | `complex64` | 16000000 | 122,070 |
| прореженный поток | `complex64` | 800000 | 6,104 |
| вектор переноса грубого поиска | `complex64` | 800000 | 6,104 |
| оценки корреляции | `float32` | 773561 | 2,951 |
| полное строгое окно | `complex64` | 2306400 | 17,596 |
| кэшированный вектор несущей | `complex64` | 2306400 | 17,596 |
| основная полоса строгого окна | `complex64` | 2306400 | 17,596 |
| выход согласованного фильтра | `complex64` | 2310400 | 17,627 |
| RRC-коэффициенты | `float32` | 4001 | 0,015 |
Переход строгой ступени с `complex128` на `complex64` уменьшил её рабочие
массивы, но не общий пик всего процесса. Уменьшение блока грубого поиска в
Lab048 не выполнялось, чтобы не менять блочные границы и результаты детектора.
## Артефакты
- `experiments/lab048_receiver_performance.py`;
- `tests/test_lab048_receiver_performance.py`;
- `data/processed/lab048/final_processing_attempt.json`;
- `data/processed/lab048/result.json`;
- `data/processed/lab048/recovered_image.jpg`.
Файл `cProfile` сохранён только как временный локальный профиль вне проекта:
`C:\Users\user\AppData\Local\Temp\lab048_baseline_20260903_6fb7e4e.pstats`.
## Проверки
- связанные тесты после поэтапных изменений: 169 passed;
- `python tools/quick_gate.py`: 547 тестов и 11 функциональных проверок, PASS;
- `python -m pytest tests/ -q`: 547 passed, 0 failed;
- `git diff --check`: PASS.
## Следующий этап
STOP. Не переходить к Lab049, видео, QPSK, повышению символьной скорости или
новому RF-сеансу без отдельной постановки. `RF TX = 0`; HackRF не запускать.