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,145 @@
// Автономный пример: C++ без Python. Грузит S21 снапшота из .npy,
// строит A-сканы и 3D SAR-объём апертуры, печатает максимум |acc/cnt|.
//
// Использование:
// standalone_bp <preprocessed_dir> <center_snapshot_name>
// где preprocessed_dir содержит папки снапшотов с i{rx}_o{tx}_s21.npy и _freq.npy.
#include <algorithm>
#include <cmath>
#include <complex>
#include <cstdint>
#include <cstdio>
#include <dirent.h>
#include <fstream>
#include <map>
#include <string>
#include <vector>
#include "gpr/ascan.hpp"
#include "gpr/config.hpp"
#include "gpr/geometry.hpp"
#include "gpr/sar3d.hpp"
using namespace gpr;
// --- минимальный загрузчик numpy .npy (v1.0, 1-D complex128 или float64) ---
struct NpyArray { std::vector<double> f64; std::vector<c128> c128v; bool is_complex = false; };
static NpyArray load_npy(const std::string& path) {
std::ifstream in(path, std::ios::binary);
if (!in) throw std::runtime_error("не открыть " + path);
char magic[6]; in.read(magic, 6);
uint8_t ver[2]; in.read((char*)ver, 2);
uint16_t hlen; in.read((char*)&hlen, 2);
std::string hdr(hlen, '\0'); in.read(&hdr[0], hlen);
auto sp = hdr.find("'shape':");
auto lp = hdr.find('(', sp), rp = hdr.find(')', sp);
long n = std::stol(hdr.substr(lp + 1, rp - lp - 1));
NpyArray a;
auto has = [&](const char* s) { return hdr.find(s) != std::string::npos; };
if (has("c8")) { // complex64 → c128
a.is_complex = true; a.c128v.resize(n);
std::vector<std::complex<float>> tmp(n);
in.read((char*)tmp.data(), n * sizeof(std::complex<float>));
for (long i = 0; i < n; ++i) a.c128v[i] = c128(tmp[i].real(), tmp[i].imag());
} else if (has("c16")) { // complex128
a.is_complex = true; a.c128v.resize(n);
in.read((char*)a.c128v.data(), n * sizeof(c128));
} else if (has("f4")) { // float32 → double
a.f64.resize(n);
std::vector<float> tmp(n); in.read((char*)tmp.data(), n * sizeof(float));
for (long i = 0; i < n; ++i) a.f64[i] = tmp[i];
} else { // float64
a.f64.resize(n); in.read((char*)a.f64.data(), n * sizeof(double));
}
return a;
}
int main(int argc, char** argv) {
if (argc < 3) { printf("usage: %s <preprocessed_dir> <center_snapshot>\n", argv[0]); return 1; }
std::string root = argv[1], center = argv[2];
GeometryConfig geom; geom.finalize();
BPConfig bp; MotionConfig mot; SARConfig sar;
auto pairs = geom.pair_keys();
auto tx = geom.output_idx, rx = geom.input_idx;
std::sort(tx.begin(), tx.end()); std::sort(rx.begin(), rx.end());
// список снапшотов, выбор апертуры вокруг center
std::vector<std::string> snaps;
if (DIR* d = opendir(root.c_str())) {
for (dirent* e; (e = readdir(d));) {
std::string n = e->d_name;
if (!n.empty() && isdigit(n[0])) snaps.push_back(n);
}
closedir(d);
}
std::sort(snaps.begin(), snaps.end());
int ci = -1; for (int i = 0; i < (int)snaps.size(); ++i) if (snaps[i] == center) ci = i;
if (ci < 0) { printf("центр %s не найден\n", center.c_str()); return 1; }
int lo = std::max(0, ci - sar.frame_radius), hi = std::min((int)snaps.size(), ci + sar.frame_radius + 1);
std::vector<std::string> aperture(snaps.begin() + lo, snaps.begin() + hi);
printf("апертура: %d кадров вокруг %s\n", (int)aperture.size(), center.c_str());
auto load_snapshot = [&](const std::string& snap,
std::map<PairKey, std::vector<c128>>& s21,
std::map<PairKey, std::vector<double>>& freq) {
for (int p = 0; p < (int)pairs.size(); ++p) {
int i_tx = pairs[p].first, i_rx = pairs[p].second;
int phys_tx = tx[i_tx], phys_rx = rx[i_rx];
char fn[512];
snprintf(fn, sizeof(fn), "%s/%s/i%d_o%d_s21.npy", root.c_str(), snap.c_str(), phys_rx, phys_tx);
s21[{i_tx, i_rx}] = load_npy(fn).c128v;
snprintf(fn, sizeof(fn), "%s/%s/i%d_o%d_freq.npy", root.c_str(), snap.c_str(), phys_rx, phys_tx);
freq[{i_tx, i_rx}] = load_npy(fn).f64;
}
};
auto ts = compute_pair_timestamps(mot, geom);
SarEngine engine(geom, bp, mot, sar);
// держим AScanSet живыми
std::vector<std::shared_ptr<AScanSet>> keep;
std::vector<ApertureFrame> frames;
std::vector<double> frame_times;
for (auto& snap : aperture) {
// время из суффикса _nsNNNN
auto pos = snap.rfind("_ns");
double t = (pos != std::string::npos) ? std::stod(snap.substr(pos + 3)) * 1e-9 : 0.0;
frame_times.push_back(t);
}
double t_ref = frame_times[ci - lo];
auto offs = frame_offsets(frame_times, t_ref, mot);
auto wts = frame_weights(offs, sar.edge_frame_weight);
for (int f = 0; f < (int)aperture.size(); ++f) {
std::map<PairKey, std::vector<c128>> s21;
std::map<PairKey, std::vector<double>> freq;
load_snapshot(aperture[f], s21, freq);
auto a = std::make_shared<AScanSet>(
preprocess_snapshot(s21, freq, nullptr, mot, geom, bp, ts, true));
keep.push_back(a);
frames.push_back(ApertureFrame{a.get(), offs[f], wts[f]});
}
// центр сетки: под центральным снапшотом на глубине 5.6 м (сцена)
auto center_scene = point_to_scene(0.0, 0.0, 5.6, mot, sar);
Grid grid = build_grid_scene(center_scene, sar);
printf("сетка %dx%dx%d, счёт объёма...\n", grid.NX(), grid.NY(), grid.NZ());
VolumeRaw vol = engine.aperture_volume(frames, grid);
// финализация: |acc/cnt|, максимум
double vmax = 0; size_t amax = 0;
for (size_t i = 0; i < vol.acc.size(); ++i) {
double v = std::abs(vol.acc[i]) / (vol.cnt[i] + 1e-12);
if (v > vmax) { vmax = v; amax = i; }
}
int NX = vol.NX, NZ = vol.NZ;
int ix = amax % NX, iz = (amax / NX) % NZ, iy = amax / ((size_t)NX * NZ);
printf("МАКСИМУМ объёма: |acc/cnt|=%.4e в вокселе (ix=%d,iy=%d,iz=%d)\n", vmax, ix, iy, iz);
printf(" X=%.1f см, Y=%.1f см, Z=%.1f см\n",
grid.x[ix] * 100, grid.y[iy] * 100, grid.z[iz] * 100);
printf("OK: автономный C++ путь отработал без Python.\n");
return 0;
}