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
@@ -0,0 +1,58 @@
// Препроцессинг S21 → комплексные A-сканы (host, float64). Порт preprocess.py.
#pragma once
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "gpr/config.hpp"
#include "gpr/types.hpp"
namespace gpr {
using PairKey = std::pair<int, int>;
// Тайминги пары (нужны slot/n_slots/t_center для фазовой коррекции).
struct PairTiming {
int tx_interleave_slot = 0;
int tx_interleave_slots = 1;
double t_center_s = 0.0;
};
using PairTimestamps = std::map<PairKey, PairTiming>;
PairTimestamps compute_pair_timestamps(const MotionConfig&, const GeometryConfig&);
// A-сканы одного снапшота, общая ось времени у всех пар (assert).
struct AScanSet {
int n_pairs = 0;
int n_fft = 0;
double t0 = 0.0, dt = 0.0; // общая ось: t_k = t0 + k*dt
std::vector<PairKey> pairs; // порядок как в geom.pair_keys()
std::vector<c128> H; // [n_pairs * n_fft] float64
const c128* pair_ptr(int p) const { return H.data() + (size_t)p * n_fft; }
};
// Порт compute_pair_ascans: bg-subtract → phase correction → k0-IFFT → норма.
// s21/freq/background — по ключам (i_tx,i_rx); background может быть nullptr.
AScanSet preprocess_snapshot(
const std::map<PairKey, std::vector<c128>>& s21,
const std::map<PairKey, std::vector<double>>& freq,
const std::map<PairKey, std::vector<c128>>* background,
const MotionConfig&, const GeometryConfig&, const BPConfig&,
const PairTimestamps&, bool normalize = true);
// Отдельные шаги (для тестов/переиспользования):
std::vector<c128> apply_intra_sweep_phase_correction(
const std::vector<c128>& s21, const std::vector<double>& freq_full,
const PairTiming&, const MotionConfig&, double wave_speed,
double f_start, double f_stop, int n_slots_default);
// Возвращает t (ось), h (комплексный A-скан). n_fft через out-параметр.
void compute_ascan_bp(const std::vector<c128>& s21, const std::vector<double>& freq,
double f_start, double f_stop, bool window, int oversample,
std::vector<double>& t_out, std::vector<c128>& h_out);
double pair_norm_scale(const std::vector<c128>& h, const std::vector<double>& t,
double wave_speed, const BPConfig&);
} // namespace gpr
@@ -0,0 +1,102 @@
// Конфигурация счёт-ядра. Дефолты 1:1 повторяют gpr_core/config.py.
#pragma once
#include <algorithm>
#include <array>
#include <cmath>
#include <cstdint>
#include <utility>
#include <vector>
namespace gpr {
struct GeometryConfig {
std::vector<int> input_idx{0, 1, 2, 3};
std::vector<int> output_idx{0, 1};
// (x,y,z) метры; порядок по физическим индексам как в config.py
std::vector<std::array<double, 3>> tx_positions{{0.785, 0.0, 0.0}, {-0.785, 0.0, 0.0}};
std::vector<std::array<double, 3>> rx_positions{
{-0.42, 0.0, 0.0}, {0.48, 0.0, 0.0}, {0.18, 0.0, 0.0}, {-0.12, 0.0, 0.0}};
double eps_r = 1.0;
double bp_plane_y = 0.0;
// --- производные (заполняются finalize) ---
std::vector<double> x_tx, y_tx, z_tx; // отсортированы по phys-индексу
std::vector<double> x_rx, y_rx, z_rx;
int n_tx = 0, n_rx = 0;
double v = 0.0;
void finalize() {
auto sort_xyz = [](std::vector<int> idx, const std::vector<std::array<double, 3>>& pos,
std::vector<double>& X, std::vector<double>& Y, std::vector<double>& Z) {
std::vector<int> order(idx.size());
for (size_t i = 0; i < idx.size(); ++i) order[i] = (int)i;
std::sort(order.begin(), order.end(), [&](int a, int b) { return idx[a] < idx[b]; });
X.clear(); Y.clear(); Z.clear();
for (int o : order) { X.push_back(pos[o][0]); Y.push_back(pos[o][1]); Z.push_back(pos[o][2]); }
};
sort_xyz(output_idx, tx_positions, x_tx, y_tx, z_tx);
sort_xyz(input_idx, rx_positions, x_rx, y_rx, z_rx);
n_tx = (int)output_idx.size();
n_rx = (int)input_idx.size();
v = 3e8 / std::sqrt(eps_r);
}
std::vector<std::pair<int, int>> pair_keys() const {
std::vector<std::pair<int, int>> p;
for (int i = 0; i < n_tx; ++i)
for (int j = 0; j < n_rx; ++j) p.emplace_back(i, j);
return p;
}
};
struct BPConfig {
double f_start = 20 * 1e8; // 2 ГГц
double f_stop = 6.0e9;
double min_depth = 3.2;
double max_depth = 10.0;
double grid_x_pad = 2.0;
double z_min = 0.1;
int nx = 300;
int nz = 300;
int oversample = 8;
bool window = true;
bool pair_normalize = true;
double pair_norm_percentile = 50.0;
double pair_norm_depth_min = 3.2;
double pair_norm_depth_max = 10.0;
double pair_norm_eps = 1e-15;
double comp_range_power = 0.25;
double comp_weight_max = 5.0;
double comp_ref_depth = 5.0;
double smooth_sigma = 1.5;
bool bg_subtract = true;
double cf_eps = 1e-12;
};
struct MotionConfig {
double speed_m_s = 0.854;
double look_angle_deg = 6.0;
double pitch_deg = 6.0;
double tx_sweep_time_s = 0.079;
double tx_switch_time_s = 1e-5;
// frequency_timing_mode всегда interleaved_tx_by_frequency
double direction_sign = +1.0;
bool apply_freq_phase_correction = true;
double motion_phase_sign = -1.0;
double frame_time_s(int n_tx) const {
return n_tx * tx_sweep_time_s + std::max(0, n_tx - 1) * tx_switch_time_s;
}
};
struct SARConfig {
int frame_radius = 6;
double edge_frame_weight = 0.75;
std::array<double, 3> half_width_m{1.8, 1.0, 1.8};
std::array<int, 3> grid{150, 120, 160}; // NX, NY, NZ
bool coord_mode_ground = true; // 'ground' vs 'radar_local'
bool use_compensation = true;
bool normalize_each_frame = true;
};
} // namespace gpr
@@ -0,0 +1,52 @@
// CUDA Driver API RAII: контекст, поток, буфер устройства.
#pragma once
#include <cuda.h>
#include <cstddef>
#include <stdexcept>
#include <string>
namespace gpr {
void cu_check(CUresult r, const char* what);
// Инициализация драйвера + primary context на device 0. Возвращает (major,minor) CC.
struct CudaContext {
CUdevice dev = 0;
CUcontext ctx = nullptr;
int cc_major = 0, cc_minor = 0;
CudaContext();
~CudaContext();
std::string arch_flag() const; // "--gpu-architecture=sm_XY"
};
template <class T>
class DeviceBuffer {
CUdeviceptr ptr_ = 0;
size_t n_ = 0;
public:
DeviceBuffer() = default;
explicit DeviceBuffer(size_t n) { alloc(n); }
~DeviceBuffer() { free(); }
DeviceBuffer(const DeviceBuffer&) = delete;
DeviceBuffer& operator=(const DeviceBuffer&) = delete;
DeviceBuffer(DeviceBuffer&& o) noexcept : ptr_(o.ptr_), n_(o.n_) { o.ptr_ = 0; o.n_ = 0; }
void alloc(size_t n) {
free();
if (n) cu_check(cuMemAlloc(&ptr_, n * sizeof(T)), "cuMemAlloc");
n_ = n;
}
void free() {
if (ptr_) cuMemFree(ptr_);
ptr_ = 0; n_ = 0;
}
void upload(const T* host, size_t n) { cu_check(cuMemcpyHtoD(ptr_, host, n * sizeof(T)), "HtoD"); }
void download(T* host, size_t n) const { cu_check(cuMemcpyDtoH(host, ptr_, n * sizeof(T)), "DtoH"); }
CUdeviceptr ptr() const { return ptr_; }
CUdeviceptr* addr() { return &ptr_; }
size_t size() const { return n_; }
};
} // namespace gpr
@@ -0,0 +1,28 @@
// Геометрия: опорное расхождение пары, смещения/веса кадров, построение сетки.
#pragma once
#include <vector>
#include "gpr/config.hpp"
#include "gpr/types.hpp"
namespace gpr {
// 1/geo_ref пары (порт pair_geo_ref, скаляр float64).
double pair_geo_ref(const GeometryConfig&, const BPConfig&, int i_tx, int i_rx, double yy);
// Смещения кадров относительно опорного (порт sar_frame_offsets).
// frame_times[k] — время кадра (сек, от ns-таймстемпа); t_ref — время опорного.
std::vector<FrameOffset> frame_offsets(const std::vector<double>& frame_times, double t_ref,
const MotionConfig&);
// Косинусные веса апертуры (порт sar_frame_weights); dt берётся относительно центра.
std::vector<double> frame_weights(const std::vector<FrameOffset>& offsets, double edge_weight);
// Сетка вокруг точки сцены (порт sar_build_grid_scene).
Grid build_grid_scene(const std::array<double, 3>& center_scene, const SARConfig&);
// point_to_scene: оси радара → сцена (поворот на pitch, если ground).
std::array<double, 3> point_to_scene(double x, double y, double z, const MotionConfig&,
const SARConfig&);
} // namespace gpr
@@ -0,0 +1,25 @@
// Компиляция строки CUDA-ядра через NVRTC → cubin под арх устройства → CUfunction.
#pragma once
#include <cuda.h>
#include <string>
namespace gpr {
class NvrtcKernel {
CUmodule module_ = nullptr;
CUfunction func_ = nullptr;
public:
NvrtcKernel() = default;
~NvrtcKernel();
NvrtcKernel(const NvrtcKernel&) = delete;
NvrtcKernel& operator=(const NvrtcKernel&) = delete;
// Компилирует src в cubin под arch_flag ("--gpu-architecture=sm_XY"),
// загружает модуль и берёт функцию func_name.
void compile(const char* src, const std::string& arch_flag, const char* func_name);
CUfunction func() const { return func_; }
};
} // namespace gpr
@@ -0,0 +1,44 @@
// 3D SAR: сборка взвешенного объёма апертуры за один запуск ядра.
#pragma once
#include <memory>
#include <vector>
#include "gpr/ascan.hpp"
#include "gpr/config.hpp"
#include "gpr/device.hpp"
#include "gpr/geometry.hpp"
#include "gpr/nvrtc_kernel.hpp"
#include "gpr/types.hpp"
namespace gpr {
// Один кадр апертуры: A-сканы + смещение + вес.
struct ApertureFrame {
const AScanSet* ascans;
FrameOffset offset;
double weight;
};
// Сырой результат объёма (Python делает finish: abs+gate+gaussian+normalize).
struct VolumeRaw {
std::vector<c64> acc; // [NY*NZ*NX]
std::vector<float> cnt; // [NY*NZ*NX]
int NX = 0, NY = 0, NZ = 0;
};
class SarEngine {
public:
SarEngine(const GeometryConfig&, const BPConfig&, const MotionConfig&, const SARConfig&);
// Весь объём апертуры за один запуск ядра; возвращает сырые acc/cnt (host).
VolumeRaw aperture_volume(const std::vector<ApertureFrame>& frames, const Grid&);
private:
GeometryConfig geom_;
BPConfig bp_;
MotionConfig mot_;
SARConfig sar_;
std::unique_ptr<CudaContext> ctx_;
std::unique_ptr<NvrtcKernel> kernel_;
};
} // namespace gpr
@@ -0,0 +1,25 @@
// Базовые типы счёт-ядра.
#pragma once
#include <complex>
#include <cstdint>
#include <vector>
namespace gpr {
using c64 = std::complex<float>; // complex64, layout == cuComplex (2×float)
using c128 = std::complex<double>; // float64 для препроцессинга/IFFT
// Ground-scene сетка (порт dict из geometry.py: x,y,z оси в метрах).
struct Grid {
std::vector<double> x, y, z;
int NX() const { return (int)x.size(); }
int NY() const { return (int)y.size(); }
int NZ() const { return (int)z.size(); }
};
// Смещение антенн кадра апертуры (порт sar_frame_offsets).
struct FrameOffset {
double dx_m = 0.0, dy_m = 0.0, dz_m = 0.0, dt_s = 0.0, horizontal_m = 0.0;
};
} // namespace gpr