feat(radar): 规范化 .data 立方体读取(position-major/16bit/字节序)
This commit is contained in:
parent
47e94592ce
commit
a9e2d98d15
|
|
@ -1,8 +1,12 @@
|
||||||
#include "io/gpr/NormalizedRadarReader.hpp"
|
#include "io/gpr/NormalizedRadarReader.hpp"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <system_error>
|
||||||
namespace geopro::io::gpr {
|
namespace geopro::io::gpr {
|
||||||
namespace {
|
namespace {
|
||||||
std::map<std::string, std::string> parseKv(const std::string& text) {
|
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;
|
if (h.samples <= 1 || h.timeWindowNs <= 0.0) return 0.0;
|
||||||
return (h.timeWindowNs / (h.samples - 1)) * waveVelocityMperNs(h) / 2.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
|
} // namespace geopro::io::gpr
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef GEOPRO_IO_GPR_NORMALIZED_RADAR_READER_HPP
|
#ifndef GEOPRO_IO_GPR_NORMALIZED_RADAR_READER_HPP
|
||||||
#define GEOPRO_IO_GPR_NORMALIZED_RADAR_READER_HPP
|
#define GEOPRO_IO_GPR_NORMALIZED_RADAR_READER_HPP
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
@ -30,6 +31,12 @@ double waveVelocityMperNs(const RadarHeader& h);
|
||||||
// 深度采样间距(米): timeWindowNs/(samples-1) × 波速/2。samples<=1 → 0。
|
// 深度采样间距(米): timeWindowNs/(samples-1) × 波速/2。samples<=1 → 0。
|
||||||
double depthSpacingZ(const RadarHeader& h);
|
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
|
} // namespace geopro::io::gpr
|
||||||
|
|
||||||
#endif // GEOPRO_IO_GPR_NORMALIZED_RADAR_READER_HPP
|
#endif // GEOPRO_IO_GPR_NORMALIZED_RADAR_READER_HPP
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
#include "io/gpr/NormalizedRadarReader.hpp"
|
#include "io/gpr/NormalizedRadarReader.hpp"
|
||||||
using namespace geopro::io::gpr;
|
using namespace geopro::io::gpr;
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
TEST(NormalizedRadarHead, ParsesCoreFieldsAndDerivesTraces) {
|
TEST(NormalizedRadarHead, ParsesCoreFieldsAndDerivesTraces) {
|
||||||
const std::string head =
|
const std::string head =
|
||||||
|
|
@ -33,3 +37,37 @@ TEST(NormalizedRadarHead, DepthSpacingUsesDefaultVelocityWhenNoDielectric) {
|
||||||
const double dz = depthSpacingZ(h);
|
const double dz = depthSpacingZ(h);
|
||||||
EXPECT_NEAR(dz, (96.419553 / 515.0) * 0.1 / 2.0, 1e-9);
|
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);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue