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>
This commit is contained in:
@@ -135,8 +135,11 @@ int main(int argc, char** argv) {
|
||||
frames.push_back(ApertureFrame{a.get(), offs[f], wts[f]});
|
||||
}
|
||||
|
||||
// полнообластная ground-сетка (как одиночный 3D в ноутбуке)
|
||||
Grid grid = build_full_region_grid(geom, bp, sar, mot.pitch_deg);
|
||||
// ноутбучные границы сцены (размах антенн ±2 м, полоса глубин) вместо
|
||||
// фиксированного окна по умолчанию
|
||||
notebook_grid_bounds(geom, bp, sar, mot.pitch_deg, 2.0,
|
||||
sar.x_min_m, sar.x_max_m, sar.z_min_m, sar.z_max_m);
|
||||
Grid grid = build_full_region_grid(sar);
|
||||
printf("сетка %dx%dx%d, счёт объёма...\n", grid.NX(), grid.NY(), grid.NZ());
|
||||
|
||||
VolumeRaw vol = engine.aperture_volume(frames, grid);
|
||||
|
||||
@@ -94,12 +94,15 @@ struct SARConfig {
|
||||
bool use_compensation = true;
|
||||
// Высота НИЖНЕГО ряда антенн над землёй; Y=0 сцены — поверхность земли.
|
||||
double ground_depth_m = 1.25;
|
||||
// Полнообластная сетка: X — размах антенн ±x_margin_m, Y — высота над
|
||||
// землёй, Z — полоса, покрывающая радарные глубины [min,max]_depth на всех
|
||||
// высотах Y (см. build_full_region_grid).
|
||||
double x_margin_m = 2.0;
|
||||
// Явные границы сцены [м]: X — поперёк, Y — высота над землёй, Z — вдаль.
|
||||
// Воксели с радарной глубиной вне [min_depth, max_depth] всё равно
|
||||
// обнуляются маской, так что Z-окно шире полосы глубин безопасно.
|
||||
double x_min_m = -2.0;
|
||||
double x_max_m = 2.0;
|
||||
double y_min_m = -0.5;
|
||||
double y_max_m = 2.0;
|
||||
double z_min_m = 0.0;
|
||||
double z_max_m = 8.0;
|
||||
std::array<double, 3> voxel_m{0.025, 0.02, 0.02}; // шаг (X, Y, Z)
|
||||
// Финализация объёма: нормировка без верхних/нижних norm_edge_margin_m по Y
|
||||
// (там ложный гребень постоянной дальности), сглаживание по (Z,X) в каждом
|
||||
|
||||
@@ -22,11 +22,16 @@ std::vector<double> frame_weights(const std::vector<FrameOffset>& offsets, doubl
|
||||
// y = (-ground_depth + depth*sin(pitch)) / cos(pitch) (порт bp_plane_y).
|
||||
double ground_plane_y(double depth, double ground_depth_m, double pitch_rad);
|
||||
|
||||
// Полнообластная сетка сцены (порт sar_build_full_region_grid):
|
||||
// X — размах антенн ±x_margin, Y — [y_min, y_max] над землёй, Z — полоса,
|
||||
// покрывающая радарные глубины [min_depth, max_depth] на всех высотах Y.
|
||||
Grid build_full_region_grid(const GeometryConfig&, const BPConfig&, const SARConfig&,
|
||||
double pitch_deg);
|
||||
// Сетка сцены по явным границам SARConfig (x/y/z_min..max, шаг voxel_m);
|
||||
// оси — linspace c числом точек round(span/step)+1, как в ноутбуке.
|
||||
Grid build_full_region_grid(const SARConfig&);
|
||||
|
||||
// Ноутбучные границы (sar_build_full_region_grid): X — размах антенн ±margin,
|
||||
// Z — полоса, покрывающая радарные глубины [min_depth, max_depth] на всех
|
||||
// высотах Y. Используются parity-инструментом для сверки с эталонными npz.
|
||||
void notebook_grid_bounds(const GeometryConfig&, const BPConfig&, const SARConfig&,
|
||||
double pitch_deg, double x_margin_m,
|
||||
double& x_min, double& x_max, double& z_min, double& z_max);
|
||||
|
||||
// point_to_scene: оси радара → сцена (поворот на pitch + подъём на ground_depth,
|
||||
// если ground; Y=0 сцены — земля).
|
||||
|
||||
@@ -58,8 +58,7 @@ double ground_plane_y(double depth, double ground_depth_m, double pitch_rad) {
|
||||
return (-ground_depth_m + depth * std::sin(pitch_rad)) / std::cos(pitch_rad);
|
||||
}
|
||||
|
||||
Grid build_full_region_grid(const GeometryConfig& geom, const BPConfig& bp, const SARConfig& sar,
|
||||
double pitch_deg) {
|
||||
Grid build_full_region_grid(const SARConfig& sar) {
|
||||
// numpy: linspace(lo, hi, max(round(span/step)+1, 2)); nearbyint = банковское
|
||||
// округление python round()
|
||||
auto axis = [](double lo, double hi, double step, std::vector<double>& out) {
|
||||
@@ -67,36 +66,39 @@ Grid build_full_region_grid(const GeometryConfig& geom, const BPConfig& bp, cons
|
||||
out.resize(n);
|
||||
for (int i = 0; i < n; ++i) out[i] = lo + (hi - lo) * i / (double)(n - 1);
|
||||
};
|
||||
double x_lo = geom.x_tx[0], x_hi = geom.x_tx[0];
|
||||
for (double x : geom.x_tx) { x_lo = std::min(x_lo, x); x_hi = std::max(x_hi, x); }
|
||||
for (double x : geom.x_rx) { x_lo = std::min(x_lo, x); x_hi = std::max(x_hi, x); }
|
||||
x_lo -= sar.x_margin_m;
|
||||
x_hi += sar.x_margin_m;
|
||||
|
||||
Grid g;
|
||||
axis(x_lo, x_hi, sar.voxel_m[0], g.x);
|
||||
axis(sar.x_min_m, sar.x_max_m, sar.voxel_m[0], g.x);
|
||||
axis(sar.y_min_m, sar.y_max_m, sar.voxel_m[1], g.y);
|
||||
if (sar.coord_mode_ground) {
|
||||
// Радарная z линейна по Z сцены при фиксированной высоте:
|
||||
// z_rad(Y, Z=0) = -(Y - ground_depth)*sin(p), z = (depth - z_rad)/cos(p).
|
||||
double p = pitch_deg * M_PI / 180.0;
|
||||
double cos_p = std::cos(p), sin_p = std::sin(p);
|
||||
double z_lo = 0.0, z_hi = 0.0;
|
||||
bool first = true;
|
||||
for (double y : {sar.y_min_m, sar.y_max_m}) {
|
||||
for (double depth : {bp.min_depth, bp.max_depth}) {
|
||||
double z_rad0 = -(y - sar.ground_depth_m) * sin_p;
|
||||
double z = (depth - z_rad0) / cos_p;
|
||||
if (first) { z_lo = z_hi = z; first = false; }
|
||||
z_lo = std::min(z_lo, z);
|
||||
z_hi = std::max(z_hi, z);
|
||||
}
|
||||
}
|
||||
axis(z_lo, z_hi, sar.voxel_m[2], g.z);
|
||||
} else {
|
||||
axis(bp.min_depth, bp.max_depth, sar.voxel_m[2], g.z);
|
||||
}
|
||||
axis(sar.z_min_m, sar.z_max_m, sar.voxel_m[2], g.z);
|
||||
return g;
|
||||
}
|
||||
|
||||
void notebook_grid_bounds(const GeometryConfig& geom, const BPConfig& bp, const SARConfig& sar,
|
||||
double pitch_deg, double x_margin_m,
|
||||
double& x_min, double& x_max, double& z_min, double& z_max) {
|
||||
double x_lo = geom.x_tx[0], x_hi = geom.x_tx[0];
|
||||
for (double x : geom.x_tx) { x_lo = std::min(x_lo, x); x_hi = std::max(x_hi, x); }
|
||||
for (double x : geom.x_rx) { x_lo = std::min(x_lo, x); x_hi = std::max(x_hi, x); }
|
||||
x_min = x_lo - x_margin_m;
|
||||
x_max = x_hi + x_margin_m;
|
||||
|
||||
// Радарная z линейна по Z сцены при фиксированной высоте:
|
||||
// z_rad(Y, Z=0) = -(Y - ground_depth)*sin(p), z = (depth - z_rad)/cos(p).
|
||||
double p = pitch_deg * M_PI / 180.0;
|
||||
double cos_p = std::cos(p), sin_p = std::sin(p);
|
||||
double z_lo = 0.0, z_hi = 0.0;
|
||||
bool first = true;
|
||||
for (double y : {sar.y_min_m, sar.y_max_m}) {
|
||||
for (double depth : {bp.min_depth, bp.max_depth}) {
|
||||
double z_rad0 = -(y - sar.ground_depth_m) * sin_p;
|
||||
double z = (depth - z_rad0) / cos_p;
|
||||
if (first) { z_lo = z_hi = z; first = false; }
|
||||
z_lo = std::min(z_lo, z);
|
||||
z_hi = std::max(z_hi, z);
|
||||
}
|
||||
}
|
||||
z_min = z_lo;
|
||||
z_max = z_hi;
|
||||
}
|
||||
|
||||
} // namespace gpr
|
||||
|
||||
Reference in New Issue
Block a user