From a9e2d98d15e1a26eaafa1bd80c943febe4a15c7d Mon Sep 17 00:00:00 2001 From: gaozheng Date: Mon, 29 Jun 2026 12:30:28 +0800 Subject: [PATCH] =?UTF-8?q?feat(radar):=20=E8=A7=84=E8=8C=83=E5=8C=96=20.d?= =?UTF-8?q?ata=20=E7=AB=8B=E6=96=B9=E4=BD=93=E8=AF=BB=E5=8F=96(position-ma?= =?UTF-8?q?jor/16bit/=E5=AD=97=E8=8A=82=E5=BA=8F)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/io/gpr/NormalizedRadarReader.cpp | 27 +++++++++++++ src/io/gpr/NormalizedRadarReader.hpp | 7 ++++ tests/io/gpr/test_normalized_radar_reader.cpp | 38 +++++++++++++++++++ 3 files changed, 72 insertions(+) diff --git a/src/io/gpr/NormalizedRadarReader.cpp b/src/io/gpr/NormalizedRadarReader.cpp index e8c86e2..aa9e43a 100644 --- a/src/io/gpr/NormalizedRadarReader.cpp +++ b/src/io/gpr/NormalizedRadarReader.cpp @@ -1,8 +1,12 @@ #include "io/gpr/NormalizedRadarReader.hpp" #include +#include +#include +#include #include #include #include +#include namespace geopro::io::gpr { namespace { std::map parseKv(const std::string& text) { @@ -64,4 +68,27 @@ double depthSpacingZ(const RadarHeader& h) { if (h.samples <= 1 || h.timeWindowNs <= 0.0) return 0.0; return (h.timeWindowNs / (h.samples - 1)) * waveVelocityMperNs(h) / 2.0; } +std::vector readRadarDataCube(const std::string& dataPath, + const RadarHeader& h) { + if (h.bits != 16) + throw std::runtime_error("readRadarDataCube: 暂仅支持 16-bit(BITS=" + + std::to_string(h.bits) + " 待实现)"); + const std::size_t n = static_cast(h.lastTrace) * h.samples; + const std::uintmax_t expect = static_cast(n) * 2; + std::error_code ec; + const auto fsize = std::filesystem::file_size(dataPath, ec); + if (ec || fsize != expect) + throw std::runtime_error("规范化 .data 大小不符: " + dataPath); + std::vector cube(n); + std::ifstream f(dataPath, std::ios::binary); + if (!f) throw std::runtime_error("打开 .data 失败: " + dataPath); + f.read(reinterpret_cast(cube.data()), static_cast(expect)); + if (!f) throw std::runtime_error("读 .data 失败: " + dataPath); + if (h.endianType == 2) // 大端 → 主机小端(x86),逐元素交换字节 + for (auto& v : cube) { + const std::uint16_t u = static_cast(v); + v = static_cast((u >> 8) | (u << 8)); + } + return cube; +} } // namespace geopro::io::gpr diff --git a/src/io/gpr/NormalizedRadarReader.hpp b/src/io/gpr/NormalizedRadarReader.hpp index 2556c18..2623724 100644 --- a/src/io/gpr/NormalizedRadarReader.hpp +++ b/src/io/gpr/NormalizedRadarReader.hpp @@ -1,6 +1,7 @@ #ifndef GEOPRO_IO_GPR_NORMALIZED_RADAR_READER_HPP #define GEOPRO_IO_GPR_NORMALIZED_RADAR_READER_HPP +#include #include #include @@ -30,6 +31,12 @@ double waveVelocityMperNs(const RadarHeader& h); // 深度采样间距(米): timeWindowNs/(samples-1) × 波速/2。samples<=1 → 0。 double depthSpacingZ(const RadarHeader& h); +// 读规范化 .data → 扁平 int16 立方体,position-major 索引 ((t*M + c)*N + s)。 +// 按 header.bits/endianType 解码;P0 仅 16-bit(32-bit 抛 not implemented)。 +// 文件大小须 == lastTrace*samples*(bits/8),否则抛 std::runtime_error。 +std::vector readRadarDataCube(const std::string& dataPath, + const RadarHeader& h); + } // namespace geopro::io::gpr #endif // GEOPRO_IO_GPR_NORMALIZED_RADAR_READER_HPP diff --git a/tests/io/gpr/test_normalized_radar_reader.cpp b/tests/io/gpr/test_normalized_radar_reader.cpp index e445350..42146a9 100644 --- a/tests/io/gpr/test_normalized_radar_reader.cpp +++ b/tests/io/gpr/test_normalized_radar_reader.cpp @@ -1,6 +1,10 @@ #include +#include +#include +#include #include "io/gpr/NormalizedRadarReader.hpp" using namespace geopro::io::gpr; +namespace fs = std::filesystem; TEST(NormalizedRadarHead, ParsesCoreFieldsAndDerivesTraces) { const std::string head = @@ -33,3 +37,37 @@ TEST(NormalizedRadarHead, DepthSpacingUsesDefaultVelocityWhenNoDielectric) { const double dz = depthSpacingZ(h); EXPECT_NEAR(dz, (96.419553 / 515.0) * 0.1 / 2.0, 1e-9); } + +TEST(NormalizedRadarData, ReadsPositionMajorCubeLittleEndian) { + // K=2 道, M=3 通道, N=2 采样; 值 v(t,c,s)=int16(100*t+10*c+s)。position-major 写。 + fs::path dir = fs::temp_directory_path() / "radar_data_test"; + fs::create_directories(dir); + const fs::path dp = dir / "L.data"; + { + std::ofstream f(dp, std::ios::binary); + for (int t = 0; t < 2; ++t) + for (int c = 0; c < 3; ++c) + for (int s = 0; s < 2; ++s) { + std::int16_t v = static_cast(100 * t + 10 * c + s); + f.write(reinterpret_cast(&v), sizeof(v)); // 小端(x86) + } + } + geopro::io::gpr::RadarHeader h; + h.samples = 2; h.channels = 3; h.lastTrace = 6; h.traces = 2; h.bits = 16; h.endianType = 1; + const auto cube = geopro::io::gpr::readRadarDataCube(dp.string(), h); + ASSERT_EQ(cube.size(), 2u * 3u * 2u); + auto at = [&](int t, int c, int s) { return cube[(size_t(t) * 3 + c) * 2 + s]; }; + EXPECT_EQ(at(0, 0, 0), 0); + EXPECT_EQ(at(1, 2, 1), 121); // 100+20+1 + EXPECT_EQ(at(0, 1, 0), 10); +} + +TEST(NormalizedRadarData, WrongFileSizeThrows) { + fs::path dir = fs::temp_directory_path() / "radar_data_test"; + fs::create_directories(dir); + const fs::path dp = dir / "bad.data"; + { std::ofstream f(dp, std::ios::binary); std::int16_t v = 0; f.write((char*)&v, 2); } + geopro::io::gpr::RadarHeader h; + h.samples = 2; h.channels = 3; h.lastTrace = 6; h.traces = 2; h.bits = 16; + EXPECT_THROW(geopro::io::gpr::readRadarDataCube(dp.string(), h), std::runtime_error); +}