Files
radar_system/data_acq_and_processing/gpr_cpp
aweandClaude Fable 5 7329750c0c sar3d: fixed default scene window X [-2,2], Y [-0.5,2], Z [0,8] m
The grid bounds are now explicit config (sar3d_x/y/z_min/max_m) instead of
being derived from the antenna span and the depth gate. The depth mask
still zeroes voxels outside [min_depth, max_depth], so the wider Z window
just shows the masked wedge. The bound fields are double: the parity tool
recomputes the notebook-derived bounds (notebook_grid_bounds) and passes
them through the live config, and a float roundtrip shifted the axes by
~1e-7 m, flipping depth-mask knife-edge voxels against the reference npz.
Parity on frames 0034-0036 unchanged (1.3e-6, axes bit-match).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-25 17:12:18 +03:00
..
2026-09-21 13:39:04 +03:00
2026-09-21 13:39:04 +03:00
2026-09-21 13:39:04 +03:00

gpr_cpp — C++/CUDA счёт-ядро MIMO GPR 3D SAR

Инфраструктура (сборка, NVRTC, PocketFFT, npy) вендорена из репозитория VNA_AlGo (gpr_cpp/, коммит 544dc59) без python-биндингов (GPR_BUILD_PYTHON=OFF). АЛГОРИТМ с сентября 2026 переписан: это порт эталонного ноутбука Multi_antenna_3D_clean_v1.ipynb (ячейки 0 и 4), а не старого gpr_core/Horns_3D. Паритет с ноутбуком проверяется инструментом sar3d_parity + python_app/scripts/sar3d_volume_compare.py по референсным *_volume.npz. Собирается из корневого Makefile radar_system (цель $(GPR_CPP_LIB) вызывает build_cmake.sh).

Что внутри

В C++ (libgpr_core_cpp): сегментированный тайминг кадра по per-trace меткам захвата (compute_pair_timestamps), препроцессинг A-сканов (bg-subtract, полная фазовая коррекция движения intra+pair до IFFT, k0-вставка + Ханн + IFFT через PocketFFT, нормировка пар), полнообластная ground-сетка (build_full_region_grid), 3D SAR апертурный объём (одно CUDA-ядро на всю апертуру; геометрия в double, A-сканы float32) и финализация (finish_volume: |acc/cnt| → маска глубины → нормировка без Y-краёв → гаусс по (Z,X) → нормировка; возвращает объём [0,1] + level).

Ключевое решение: CUDA без nvcc (NVRTC + Driver API)

На целевых машинах (x86+T600, Jetson) нет полного CUDA toolkit — только runtime + NVRTC (как у cupy). Поэтому ядро не компилируется nvcc'ом: его исходник встроен строкой (src/kernel_src.hpp), компилируется в рантайме через NVRTC в cubin под точную арх устройства (запрос compute capability → sm_XY, без JIT PTX), грузится и запускается через CUDA Driver API. Хост-часть собирается обычным g++. Плюс: без toolkit и без привязки к SM — один код для x86 (sm_75) и Jetson (sm_87).

Сборка

bash build_cmake.sh            # авто-детект pip CUDA-путей; собирает всё
# артефакты в build/: libgpr_core_cpp.a, _gpr_cpp*.so, standalone_bp

Требуется: g++ ≥13, cmake ≥3.24, pybind11 (pip install pybind11), pip-пакеты nvidia-* (nvrtc+cudart, идут с cupy), системный libcuda. rpath на каталог libnvrtc прописан — бинарники/модуль грузятся без LD_LIBRARY_PATH.

Публичный C++ API (include/gpr/)

#include "gpr/config.hpp"    // GeometryConfig/BPConfig/MotionConfig/SARConfig (дефолты = ноутбук)
#include "gpr/ascan.hpp"     // compute_pair_timestamps, preprocess_snapshot(...) -> AScanSet
#include "gpr/sar3d.hpp"     // SarEngine::aperture_volume -> VolumeRaw; finish_volume -> FinishedVolume
#include "gpr/geometry.hpp"  // frame_offsets, frame_weights, build_full_region_grid

gpr::SarEngine engine(geom, bp, mot, sar);          // компилит ядро под устройство
auto raw = engine.aperture_volume(frames, grid);    // один запуск ядра на апертуру
auto fin = gpr::finish_volume(raw, grid, mot.pitch_deg, bp, sar);  // объём [0,1] + level

Пример без Python: examples/standalone_bp.cpp — грузит S21 из .npy, строит объём, печатает максимум.

./build/standalone_bp <preprocessed_dir> 0038_id39_ns11361438137486

Python-модуль

import _gpr_cpp                     # из gpr_cpp/build
eng = _gpr_cpp.SarEngine(_gpr_cpp.GeometryConfig(), _gpr_cpp.BPConfig(),
                         _gpr_cpp.MotionConfig(), _gpr_cpp.SARConfig())
a = _gpr_cpp.preprocess_snapshot(s21, freq, background, mot, geom, bp, True)  # -> AScanSet
acc, cnt = eng.aperture_volume([(a, dx, dy, dz, w), ...], gx, gy, gz)         # numpy

Паритет с ноутбуком (проверено на x86 T600, датасет 20260922_mine_fast_true)

Кадры 0034/0035/0036 против референсных *_volume.npz ноутбука (make sar3d_parity + python_app/scripts/sar3d_volume_compare.py): max|Δ| ≤ 1.6e-6 вне ножевой границы маски глубины, argmax и level совпадают (level rel ≤ 7e-7). Python-эталон той же цепочки: python_app/scripts/sar3d_reference_check.py.

Статус

  • x86 (T600, sm_75, CUDA 13): собрано, паритет, standalone работает.
  • Jetson (Orin NX, sm_87, CUDA 12.6): порт тривиален (NVRTC сам берёт sm_87); собрать build_cmake.sh на Jetson с его venv.
  • Опц.: ветка impl='cpp' в gpr_core/sar3d.py (адаптер gpr_cpp_backend.py), кэш device-A-сканов (сейчас каждый вызов грузит стек на GPU).