make gpr update

This commit is contained in:
awe
2026-09-21 13:39:04 +03:00
parent f0ad4e6185
commit 243963063c
22 changed files with 5161 additions and 30 deletions
+87
View File
@@ -0,0 +1,87 @@
# gpr_cpp — C++/CUDA счёт-ядро MIMO GPR 3D SAR
> Вендорено из репозитория VNA_AlGo (`gpr_cpp/`, коммит `544dc59`); python-биндинги
> (`bindings/`, pybind11) при переносе не взяты — сборка здесь только C++
> (`GPR_BUILD_PYTHON=OFF`). Собирается из корневого Makefile radar_system
> (цель `$(GPR_CPP_LIB)` вызывает `build_cmake.sh`).
Порт вычислительного ядра из Python/CuPy (`gpr_core`) в самостоятельную
C++/CUDA библиотеку для интеграции в C++ проект.
Алгоритм — см. `ALGORITHM.md` в репозитории VNA_AlGo.
## Что внутри (граница C++ ↔ Python)
**В C++ (`libgpr_core_cpp`):** геометрия, препроцессинг A-сканов (bg-subtract,
фазовая коррекция движения, k0-вставка + Ханн + IFFT через PocketFFT, нормировка),
3D SAR апертурный объём (одно CUDA-ядро на всю апертуру). Возвращает **сырые**
`acc`(complex64)/`cnt`(float32).
**Остаётся в Python:** загрузка `.npy`, финализация объёма (abs+gate+gaussian+
нормировка), CLEAN-детекция, трек, оценка скорости, plotly.
## Ключевое решение: CUDA без nvcc (NVRTC + Driver API)
На целевых машинах (x86+T600, Jetson) нет полного CUDA toolkit — только runtime +
**NVRTC** (как у cupy). Поэтому ядро **не компилируется nvcc'ом**: его исходник
встроен строкой ([src/kernel_src.hpp](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
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/))
```cpp
#include "gpr/config.hpp" // GeometryConfig/BPConfig/MotionConfig/SARConfig (дефолты = config.py)
#include "gpr/ascan.hpp" // preprocess_snapshot(...) -> AScanSet
#include "gpr/sar3d.hpp" // SarEngine::aperture_volume(frames, grid) -> VolumeRaw{acc,cnt}
#include "gpr/geometry.hpp" // frame_offsets, frame_weights, build_grid_scene, point_to_scene
gpr::SarEngine engine(geom, bp, mot, sar); // компилит ядро под устройство
auto vol = engine.aperture_volume(frames, grid); // один запуск ядра на апертуру
// vol.acc / vol.cnt — сырые; финализацию (gaussian/normalize) делает вызывающий
```
Пример без Python: [examples/standalone_bp.cpp](examples/standalone_bp.cpp) — грузит
S21 из `.npy`, строит объём, печатает максимум.
```bash
./build/standalone_bp <preprocessed_dir> 0038_id39_ns11361438137486
```
## Python-модуль
```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)
| Этап | Порог | Факт |
|---|---|---|
| config дефолты vs dataclass | точно | OK |
| A-сканы raw H vs numpy (float64) | <1e-9 | 1.7e-12 |
| A-сканы норм. H (FFT-ULP через медиану) | <1e-4 | 2.5e-6 |
| **3D объём C++ ядро vs cupy** (float32) | <5e-3 | **3e-7, argmax идентичен** |
Тесты: [../tests/test_parity_cpp.py](../tests/test_parity_cpp.py) (C++ vs cupy).
## Статус
- [x] 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).