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

12 KiB
Raw Blame History

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 не запускать.