#include "io/gpr/Gpr3dvVolumeBridge.hpp" #include #include #include #include #include #include #include "GPRDataModel.h" #include "IprhParser.h" #include "RadarProcessor.h" #include "core/model/ScalarVolumeI16.hpp" #include "io/gpr/RadarVolumeAssembler.hpp" // assembleRadarVolume(共享建体) namespace geopro::io::gpr { namespace { // 全体 traces 平均绝对幅值——朴素的「处理是否生效」标量证据(与 P1 冒烟同口径)。 double meanAbsAmplitude(const GPRDataModel& model) { long double sum = 0.0L; long long count = 0; for (const RadarTrace& tr : model.traces) { for (short v : tr.amplitudes) { sum += static_cast(v < 0 ? -v : v); ++count; } } return count > 0 ? static_cast(sum / count) : 0.0; } // 通道横向间距(米):优先 chYOffsets 跨度 /(通道数-1);取不到退路 ≈1.37/(通道数-1)。 double channelSpacingY(const GPRDataModel::Header& h, int channels) { if (channels <= 1) return 1.0; const auto& off = h.chYOffsets; if (off.size() >= 2) { float lo = off.front(), hi = off.front(); for (float v : off) { lo = std::min(lo, v); hi = std::max(hi, v); } const double span = static_cast(hi) - static_cast(lo); if (span > 1e-9) return span / (channels - 1); } // 退路:明星路 14 通道横向跨度 ≈1.37m(-0.686~+0.686)。 constexpr double kArrayWidthM = 1.37; return kArrayWidthM / (channels - 1); } // 深度采样间距(米):(timeWindow/samples) ns × 波速(m/ns) / 2(往返)。 // 与 GPRDataModel::calculateDepth 同式。取不到 → 1.0(单位间距)。 double depthSpacingZ(const GPRDataModel::Header& h) { if (h.samplesPerTrace <= 0 || h.timeWindowNs <= 0.0) return 1.0; const double timePerSample = h.timeWindowNs / h.samplesPerTrace; // ns const double vel = h.waveVelocity > 0.0 ? h.waveVelocity : 0.1; // m/ns const double dz = timePerSample * vel / 2.0; return dz > 1e-12 ? dz : 1.0; } double nowMs(std::chrono::steady_clock::time_point t0) { const auto t1 = std::chrono::steady_clock::now(); return std::chrono::duration(t1 - t0).count(); } } // namespace geopro::core::BuiltI16 buildLineVolumeFromGpr3dv(const std::string& lineDir, const std::string& linePrefix, BridgeMetrics* metricsOut, int coarse, double targetDy) { const QString dir = QString::fromLocal8Bit(lineDir.c_str()); const QString base = QString::fromLocal8Bit(linePrefix.c_str()); // 1) 走 P1 链:load → buildVolumeData(处理前) → runPipeline → 再 buildVolumeData。 const auto tLoad = std::chrono::steady_clock::now(); GPRDataModel model; if (!IprhParser::loadImpulseMultiChannel(dir, base, model)) { throw std::runtime_error("loadImpulseMultiChannel 失败: " + lineDir + " / " + linePrefix); } model.buildVolumeData(); // 处理前立方体(用于 before 统计) const double meanBefore = meanAbsAmplitude(model); const double loadMs = nowMs(tLoad); const auto tPipe = std::chrono::steady_clock::now(); RadarProcessor::ProcPipeline pipeline; pipeline.setDefaultFlow(); GPRDataModel processed = RadarProcessor::runPipeline(model, pipeline); // ★关键:runPipeline 原位变换 traces 且零时校正会改 samplesPerTrace, // 不重建 volumeData,故必须再建一次拿处理后立方体。 processed.buildVolumeData(); const double meanAfter = meanAbsAmplitude(processed); const double pipelineMs = nowMs(tPipe); // 2) 立方体维度:volumeData[通道][道][样本] → 轴 X=道/Y=通道/Z=样本。 const int channels = processed.volumeData.size(); const int traces = channels > 0 ? processed.volumeData[0].size() : 0; const int samples = (channels > 0 && traces > 0) ? processed.volumeData[0][0].size() : 0; if (channels <= 0 || traces <= 0 || samples <= 0) { throw std::runtime_error("处理后立方体为空(通道/道/样本 = " + std::to_string(channels) + "/" + std::to_string(traces) + "/" + std::to_string(samples) + ")"); } // §1 线内通道插值偏移:读各通道真实横向偏移(header.chXOffsets)。绝不跨线;间距/ // 通道数从数据来,不假设。空/不等长 → 不启用通道插值(helper 内退路=逐通道 identity)。 std::vector latOff; const auto& chx = processed.header.chXOffsets; if (chx.size() == channels) for (int c = 0; c < channels; ++c) latOff.push_back(static_cast(chx[c])); // 3) 组立方体描述 + 采样器(volumeData[通道][道][样本],越界取 0),调共享建体 helper。 // 扫值域→Quant(中点 offset)→通道插值(规则化 Y 到 targetDy)→逐体素填→spacing 均在 // helper 内完成(与后续规范化 .head/.data 路共用同一逻辑,零漂移)。 const GPRDataModel::Header& h = processed.header; RadarCubeDesc desc; desc.channels = channels; desc.traces = traces; desc.samples = samples; desc.chXOffsets = latOff; desc.dxBase = h.distanceInc > 1e-9 ? h.distanceInc : 1.0; // 道距(米) desc.dyWhenNotInterpolated = channelSpacingY(h, channels); // 原通道横距(米) desc.dz = depthSpacingZ(h); // 深度采样距(米) CubeSampler sample = [&processed](int c, int t, int s) -> double { const auto& ch = processed.volumeData[c]; if (t >= static_cast(ch.size())) return 0.0; const auto& tr = ch[t]; return s < static_cast(tr.size()) ? static_cast(tr[s]) : 0.0; }; const auto tFill = std::chrono::steady_clock::now(); geopro::core::BuiltI16 built = assembleRadarVolume(desc, sample, coarse, targetDy); const double fillMs = nowMs(tFill); if (metricsOut) { metricsOut->nx = built.vol.nx(); metricsOut->ny = built.vol.ny(); metricsOut->nz = built.vol.nz(); metricsOut->meanAbsBefore = meanBefore; metricsOut->meanAbsAfter = meanAfter; metricsOut->vminPhys = built.vminPhys; metricsOut->vmaxPhys = built.vmaxPhys; metricsOut->dx = built.spacing[0]; metricsOut->dy = built.spacing[1]; metricsOut->dz = built.spacing[2]; metricsOut->loadMs = loadMs; metricsOut->pipelineMs = pipelineMs; metricsOut->fillMs = fillMs; } return built; } } // namespace geopro::io::gpr