feat(radar): 规范化 .data 立方体读取(position-major/16bit/字节序)

This commit is contained in:
gaozheng 2026-06-29 12:30:28 +08:00
parent 47e94592ce
commit a9e2d98d15
3 changed files with 72 additions and 0 deletions

View File

@ -1,8 +1,12 @@
#include "io/gpr/NormalizedRadarReader.hpp"
#include <cmath>
#include <cstdint>
#include <filesystem>
#include <fstream>
#include <map>
#include <sstream>
#include <stdexcept>
#include <system_error>
namespace geopro::io::gpr {
namespace {
std::map<std::string, std::string> 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<std::int16_t> 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<std::size_t>(h.lastTrace) * h.samples;
const std::uintmax_t expect = static_cast<std::uintmax_t>(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<std::int16_t> cube(n);
std::ifstream f(dataPath, std::ios::binary);
if (!f) throw std::runtime_error("打开 .data 失败: " + dataPath);
f.read(reinterpret_cast<char*>(cube.data()), static_cast<std::streamsize>(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<std::uint16_t>(v);
v = static_cast<std::int16_t>((u >> 8) | (u << 8));
}
return cube;
}
} // namespace geopro::io::gpr

View File

@ -1,6 +1,7 @@
#ifndef GEOPRO_IO_GPR_NORMALIZED_RADAR_READER_HPP
#define GEOPRO_IO_GPR_NORMALIZED_RADAR_READER_HPP
#include <cstdint>
#include <string>
#include <vector>
@ -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<std::int16_t> readRadarDataCube(const std::string& dataPath,
const RadarHeader& h);
} // namespace geopro::io::gpr
#endif // GEOPRO_IO_GPR_NORMALIZED_RADAR_READER_HPP

View File

@ -1,6 +1,10 @@
#include <gtest/gtest.h>
#include <cstdint>
#include <filesystem>
#include <fstream>
#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<std::int16_t>(100 * t + 10 * c + s);
f.write(reinterpret_cast<const char*>(&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);
}