fix graph and white background added
This commit is contained in:
@@ -38,8 +38,11 @@ class DataProcessor {
|
||||
const ProcessingLiveConfig& live_config
|
||||
) -> ipc::ResultCollection;
|
||||
|
||||
[[nodiscard]] auto requested_mode(const ProcessingLiveConfig& live_config) const -> const std::string&;
|
||||
[[nodiscard]] auto resolve_processor(const ProcessingLiveConfig& live_config) -> ProcessorInterface&;
|
||||
[[nodiscard]] auto should_replay_entire_history(const ProcessingLiveConfig& live_config) const -> bool;
|
||||
// Only gpr and sar3d use the speed, so only they recompute when a locator client changes it.
|
||||
[[nodiscard]] auto uses_socket_speed(const ProcessingLiveConfig& live_config) const -> bool;
|
||||
|
||||
// Speed streamed by a locator client (`vlc`), which then replaces
|
||||
// `gpr_speed_m_s`; nullopt when `ignore_socket_speed` is set or no fresh
|
||||
|
||||
@@ -76,9 +76,8 @@ void DataProcessor::run(const std::atomic<bool>& stop_requested) {
|
||||
std::uint64_t last_replayed_revision = live_config_loader_.revision();
|
||||
runtime::CollectionErrors errors;
|
||||
std::uint64_t oversized_results = 0;
|
||||
// track the socket-fed speed used for the last reprocess so a change
|
||||
// arriving without a live-config revision bump still triggers a reprocess of
|
||||
// the current result (gated below by reprocess_current_result).
|
||||
// The socket-fed speed used by the last reprocess: in the modes that use the speed, a
|
||||
// change without a live-config revision still recomputes the current result.
|
||||
std::optional<double> last_reprocessed_socket_speed = std::nullopt;
|
||||
|
||||
while (!stop_requested.load(std::memory_order_relaxed)) {
|
||||
@@ -97,7 +96,8 @@ void DataProcessor::run(const std::atomic<bool>& stop_requested) {
|
||||
}
|
||||
auto& processor = resolve_processor(live_config);
|
||||
const auto history_limit = processing_history_limit(config_, live_config);
|
||||
const bool socket_speed_dirty = current_socket_speed != last_reprocessed_socket_speed;
|
||||
const bool socket_speed_dirty =
|
||||
uses_socket_speed(live_config) && current_socket_speed != last_reprocessed_socket_speed;
|
||||
|
||||
const auto was_removed = [&](const ipc::PreprocessedCollection& collection) {
|
||||
if (live_config.history_clear_before_ns &&
|
||||
@@ -111,39 +111,36 @@ void DataProcessor::run(const std::atomic<bool>& stop_requested) {
|
||||
});
|
||||
};
|
||||
if (live_revision != last_replayed_revision || socket_speed_dirty) {
|
||||
// Settled before recomputing: a sweep that fails is reported once rather than
|
||||
// retried every tick, which would stop all new input.
|
||||
last_replayed_revision = live_revision;
|
||||
last_reprocessed_socket_speed = current_socket_speed;
|
||||
std::erase_if(preprocessed_history, was_removed);
|
||||
if (preprocessed_history.size() > history_limit) {
|
||||
preprocessed_history.erase(preprocessed_history.begin(), preprocessed_history.end() - history_limit);
|
||||
}
|
||||
|
||||
if (!live_config.reprocess_current_result) {
|
||||
// Socket-fed speed updates should affect only future preprocessed collections,
|
||||
// not replay the current history entry.
|
||||
} else if (should_replay_entire_history(live_config)) {
|
||||
for (std::size_t index = 0; index < preprocessed_history.size(); ++index) {
|
||||
const auto replay_result = process_collection(
|
||||
preprocessed_history[index],
|
||||
std::span<const ipc::PreprocessedCollection>(preprocessed_history.data(), index),
|
||||
processor,
|
||||
live_config
|
||||
);
|
||||
publish_result_collection(replay_result, results_ring_, oversized_results);
|
||||
publish_locator(replay_result);
|
||||
// The GUI turns this off while it re-feeds the sweeps of a stopped B-scan itself.
|
||||
if (live_config.reprocess_current_result && !preprocessed_history.empty()) {
|
||||
const auto newest = preprocessed_history.size() - 1U;
|
||||
const auto first = should_replay_entire_history(live_config) ? std::size_t{0} : newest;
|
||||
for (auto index = first; index <= newest; ++index) {
|
||||
try {
|
||||
const auto replay_result = process_collection(
|
||||
preprocessed_history[index],
|
||||
std::span<const ipc::PreprocessedCollection>(preprocessed_history.data(), index),
|
||||
processor,
|
||||
live_config
|
||||
);
|
||||
publish_result_collection(replay_result, results_ring_, oversized_results);
|
||||
if (index == newest) {
|
||||
publish_locator(replay_result); // The locator reports the current scene.
|
||||
}
|
||||
} catch (const std::exception& exc) {
|
||||
errors.report("data_processor", exc);
|
||||
}
|
||||
}
|
||||
} else if (!preprocessed_history.empty()) {
|
||||
const auto replay_result = process_collection(
|
||||
preprocessed_history.back(),
|
||||
std::span<const ipc::PreprocessedCollection>(preprocessed_history.data(), preprocessed_history.size() - 1U),
|
||||
processor,
|
||||
live_config
|
||||
);
|
||||
publish_result_collection(replay_result, results_ring_, oversized_results);
|
||||
publish_locator(replay_result);
|
||||
}
|
||||
last_replayed_revision = live_revision;
|
||||
//record the speed we just reprocessed with so an
|
||||
// unchanged socket value does not retrigger every iteration.
|
||||
last_reprocessed_socket_speed = current_socket_speed;
|
||||
}
|
||||
|
||||
if (preprocessed_ring_.pop(bytes)) {
|
||||
@@ -219,11 +216,12 @@ auto DataProcessor::process_collection(
|
||||
return result;
|
||||
}
|
||||
|
||||
auto DataProcessor::resolve_processor(const ProcessingLiveConfig& live_config) -> ProcessorInterface& {
|
||||
const std::string requested_mode =
|
||||
live_config.processor_mode.empty() ? default_processor_mode_ : live_config.processor_mode;
|
||||
auto DataProcessor::requested_mode(const ProcessingLiveConfig& live_config) const -> const std::string& {
|
||||
return live_config.processor_mode.empty() ? default_processor_mode_ : live_config.processor_mode;
|
||||
}
|
||||
|
||||
if (auto found = processors_.find(requested_mode); found != processors_.end()) {
|
||||
auto DataProcessor::resolve_processor(const ProcessingLiveConfig& live_config) -> ProcessorInterface& {
|
||||
if (auto found = processors_.find(requested_mode(live_config)); found != processors_.end()) {
|
||||
return *(found->second);
|
||||
}
|
||||
if (auto fallback = processors_.find(default_processor_mode_); fallback != processors_.end()) {
|
||||
@@ -233,9 +231,12 @@ auto DataProcessor::resolve_processor(const ProcessingLiveConfig& live_config) -
|
||||
}
|
||||
|
||||
auto DataProcessor::should_replay_entire_history(const ProcessingLiveConfig& live_config) const -> bool {
|
||||
const std::string requested_mode =
|
||||
live_config.processor_mode.empty() ? default_processor_mode_ : live_config.processor_mode;
|
||||
return requested_mode == "bscan";
|
||||
return requested_mode(live_config) == "bscan";
|
||||
}
|
||||
|
||||
auto DataProcessor::uses_socket_speed(const ProcessingLiveConfig& live_config) const -> bool {
|
||||
const auto& mode = requested_mode(live_config);
|
||||
return mode == "gpr" || mode == "sar3d";
|
||||
}
|
||||
|
||||
auto DataProcessor::socket_speed(const ProcessingLiveConfig& live_config) const -> std::optional<double> {
|
||||
|
||||
@@ -93,24 +93,9 @@ void fft_inplace(std::vector<std::complex<double>>& values, bool inverse) {
|
||||
return std::abs(sample);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto fallback_profile(
|
||||
const ipc::SweepTraceBlock& trace,
|
||||
std::span<const ipc::Complex32> selected_samples
|
||||
) -> BScanProfile {
|
||||
const std::size_t point_count = std::min(trace.frequency_hz.size(), selected_samples.size());
|
||||
BScanProfile fallback{};
|
||||
fallback.depth_m.reserve(point_count);
|
||||
fallback.response.reserve(point_count);
|
||||
|
||||
const float denominator = point_count > 1U ? static_cast<float>(point_count - 1U) : 1.0F;
|
||||
for (std::size_t index = 0U; index < point_count; ++index) {
|
||||
const auto& sample = selected_samples[index];
|
||||
fallback.depth_m.push_back(static_cast<float>(static_cast<float>(index) / denominator));
|
||||
fallback.response.push_back(std::sqrt(sample.re * sample.re + sample.im * sample.im));
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
// A range profile needs at least two in-band points on an increasing frequency grid.
|
||||
// Otherwise the profile is empty and the display leaves the column out: drawing |S21|
|
||||
// against a made-up depth axis would look like a valid B-scan.
|
||||
[[nodiscard]] auto compute_bscan_profile(
|
||||
const ipc::SweepTraceBlock& trace,
|
||||
const ProcessingLiveConfig& live_config
|
||||
@@ -118,7 +103,7 @@ void fft_inplace(std::vector<std::complex<double>>& values, bool inverse) {
|
||||
const auto selected_samples = std::span<const ipc::Complex32>(trace.s21);
|
||||
const std::size_t point_count = std::min(trace.frequency_hz.size(), selected_samples.size());
|
||||
if (point_count < 2U) {
|
||||
return fallback_profile(trace, selected_samples);
|
||||
return {};
|
||||
}
|
||||
|
||||
const double configured_start_hz = static_cast<double>(live_config.bscan_start_freq_mhz) * 1'000'000.0;
|
||||
@@ -142,35 +127,35 @@ void fft_inplace(std::vector<std::complex<double>>& values, bool inverse) {
|
||||
}
|
||||
|
||||
if (filtered_freq_hz.size() < 2U) {
|
||||
return fallback_profile(trace, selected_samples);
|
||||
return {};
|
||||
}
|
||||
|
||||
const std::size_t filtered_count = filtered_freq_hz.size();
|
||||
const double df = (filtered_freq_hz.back() - filtered_freq_hz.front()) / static_cast<double>(filtered_count - 1U);
|
||||
if (df <= 0.0) {
|
||||
return fallback_profile(trace, selected_samples);
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto start_bin = static_cast<std::int64_t>(std::llround(filtered_freq_hz.front() / df));
|
||||
if (start_bin < 0) {
|
||||
return fallback_profile(trace, selected_samples);
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto start_index = static_cast<std::size_t>(start_bin);
|
||||
if (start_index > (std::numeric_limits<std::size_t>::max() / 2U)) {
|
||||
return fallback_profile(trace, selected_samples);
|
||||
return {};
|
||||
}
|
||||
if (start_index > (std::numeric_limits<std::size_t>::max() - filtered_count + 1U)) {
|
||||
return fallback_profile(trace, selected_samples);
|
||||
return {};
|
||||
}
|
||||
|
||||
const std::size_t min_fft_len = 2U * (start_index + filtered_count - 1U);
|
||||
const std::size_t fft_len = next_power_of_two(min_fft_len);
|
||||
if (fft_len < min_fft_len || (fft_len & (fft_len - 1U)) != 0U) {
|
||||
return fallback_profile(trace, selected_samples);
|
||||
return {};
|
||||
}
|
||||
if (start_index > fft_len || filtered_count > (fft_len - start_index)) {
|
||||
return fallback_profile(trace, selected_samples);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::complex<double>> spectrum(fft_len, std::complex<double>(0.0, 0.0));
|
||||
|
||||
Reference in New Issue
Block a user