geopro/tests/io/gpr/test_gpr_geometry.cpp

87 lines
3.8 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "io/gpr/GprGeometry.hpp"
#include "io/gpr/IprHeader.hpp"
#include <gtest/gtest.h>
#include <algorithm>
#include <vector>
using namespace geopro::io::gpr;
TEST(GprGeometry, ParsesActiveChannelOffsets) {
const std::string ord = "0 -0.686000 -1.5 1\n1 -0.581000 -1.5 1\n14 0 -1.5 0\n";
auto xs = parseChannelXOffsets(ord);
ASSERT_EQ(xs.size(), 2u); // 仅 2 个有效(末列=1)
EXPECT_NEAR(xs[0], -0.686, 1e-6);
EXPECT_NEAR(xs[1], -0.581, 1e-6);
}
TEST(GprGeometry, ChannelInterpDensifiesToTargetGrid) {
// 14 通道 ~均匀 0.105m,跨度 1.372mtargetDy=0.025 → ny=round(1.372/0.025)+1=56。
std::vector<double> off;
for (int i = 0; i < 14; ++i) off.push_back(-0.686 + i * 0.1055385); // -0.686..+0.686
auto rows = planChannelInterpolation(off, 0.025);
EXPECT_EQ(rows.size(), 56u);
// 首行=最左通道(无插值),末行=最右通道。
EXPECT_EQ(rows.front().a, 0);
EXPECT_NEAR(rows.front().wb, 0.0, 1e-9);
EXPECT_EQ(rows.back().a, 13);
// 中间存在真插值行wb 落在 (0,1))。
bool sawInterp = false;
for (const auto& r : rows)
if (r.a != r.b && r.wb > 0.05 && r.wb < 0.95) sawInterp = true;
EXPECT_TRUE(sawInterp);
}
TEST(GprGeometry, ChannelInterpDynamicCountBySpacing) {
// 不同道间距 → 不同插值条数(动态,不写死)。两通道 0.10m 间距:
// targetDy=0.025 → ny=round(0.10/0.025)+1=5端点 + 中间 3 条)。
auto r1 = planChannelInterpolation({0.0, 0.10}, 0.025);
EXPECT_EQ(r1.size(), 5u);
// targetDy=0.05 → ny=round(0.10/0.05)+1=3端点 + 中间 1 条)。
auto r2 = planChannelInterpolation({0.0, 0.10}, 0.05);
EXPECT_EQ(r2.size(), 3u);
}
TEST(GprGeometry, ChannelInterpHandlesUnsortedOffsets) {
// 通道在文件里可能非按偏移有序(任意排布)。偏移乱序但物理跨度相同 → 网格行数、
// 端点、单调性应不受顺序影响(内部按偏移排序定位)。
std::vector<double> sorted = {-0.4, -0.2, 0.0, 0.2, 0.4};
std::vector<double> shuffled = {0.0, 0.4, -0.4, 0.2, -0.2}; // 同偏移集合,乱序
auto rs = planChannelInterpolation(sorted, 0.1);
auto ru = planChannelInterpolation(shuffled, 0.1);
ASSERT_EQ(rs.size(), ru.size()); // ny 仅取决于跨度,与顺序无关
EXPECT_EQ(rs.size(), 9u); // round(0.8/0.1)+1
// 真正的不变量:每行的【有效插值位置】=(1-wb)*off[a]+wb*off[b] 应等于网格位置
// p=min+j*targetDy与通道在文件里的顺序无关。末行恰落在 max 时会以 [次末,末] 夹
// 且 wb=1值=末通道),故不能直接断言 a==末通道,要看有效位置。
auto effPos = [](const std::vector<double>& off, const ChannelInterpRow& r) {
return (1.0 - r.wb) * off[r.a] + r.wb * off[r.b];
};
for (std::size_t j = 0; j < ru.size(); ++j) {
const double p = -0.4 + static_cast<double>(j) * 0.1;
EXPECT_NEAR(effPos(sorted, rs[j]), p, 1e-9); // 有序
EXPECT_NEAR(effPos(shuffled, ru[j]), p, 1e-9); // 乱序:同一结果
// a/b 偏移夹住网格位置。
const double oa = shuffled[ru[j].a], ob = shuffled[ru[j].b];
EXPECT_LE(std::min(oa, ob) - 1e-9, p);
EXPECT_GE(std::max(oa, ob) + 1e-9, p);
}
}
TEST(GprGeometry, ChannelInterpDegenerateIdentity) {
// 单通道 / 已比 targetDy 密 / targetDy<=0 → 逐通道 identity。
EXPECT_EQ(planChannelInterpolation({0.5}, 0.025).size(), 1u);
auto dense = planChannelInterpolation({0.0, 0.01}, 0.025); // 跨度<targetDy/2
ASSERT_EQ(dense.size(), 2u);
EXPECT_EQ(dense[0].a, 0);
EXPECT_EQ(dense[1].a, 1);
EXPECT_EQ(planChannelInterpolation({0.0, 0.10}, -1.0).size(), 2u);
}
TEST(GprGeometry, DepthOfLastSampleMatchesPhysics) {
IprHeader h{};
h.samples = 821;
h.timeWindowNs = 160.352;
h.soilVelocity = 1e8; // m/s
EXPECT_NEAR(depthOfSample(820, h), 8.0, 0.05); // ~8m
EXPECT_NEAR(depthOfSample(0, h), 0.0, 1e-9);
}