修复展示数据
This commit is contained in:
@@ -31,7 +31,12 @@ public:
|
|||||||
void update(Value value, std::size_t retain_latest_count);
|
void update(Value value, std::size_t retain_latest_count);
|
||||||
void clear();
|
void clear();
|
||||||
std::size_t retain_latest(std::size_t count);
|
std::size_t retain_latest(std::size_t count);
|
||||||
|
struct Snapshot {
|
||||||
|
Container values;
|
||||||
|
Real_Time_Data_Update_State update_state;
|
||||||
|
};
|
||||||
Container snapshot() const;
|
Container snapshot() const;
|
||||||
|
Snapshot snapshot_with_update_state() const;
|
||||||
std::size_t size() const;
|
std::size_t size() const;
|
||||||
std::uint64_t revision() const;
|
std::uint64_t revision() const;
|
||||||
Real_Time_Data_Retention retention() const noexcept override;
|
Real_Time_Data_Retention retention() const noexcept override;
|
||||||
@@ -49,6 +54,7 @@ private:
|
|||||||
void reserve_update_times(std::size_t capacity);
|
void reserve_update_times(std::size_t capacity);
|
||||||
void publish_render_state() override;
|
void publish_render_state() override;
|
||||||
const Container& render_state_value() const noexcept;
|
const Container& render_state_value() const noexcept;
|
||||||
|
const Real_Time_Data_Update_State& render_update_state_value() const noexcept;
|
||||||
mutable Mutex mutex_;
|
mutable Mutex mutex_;
|
||||||
std::recursive_mutex mutation_mutex_;
|
std::recursive_mutex mutation_mutex_;
|
||||||
Observer observer_;
|
Observer observer_;
|
||||||
@@ -61,7 +67,7 @@ private:
|
|||||||
std::size_t update_times_size_{};
|
std::size_t update_times_size_{};
|
||||||
std::size_t update_times_capacity_{};
|
std::size_t update_times_capacity_{};
|
||||||
std::uint64_t revision_{};
|
std::uint64_t revision_{};
|
||||||
std::uint64_t render_revision_{};
|
Real_Time_Data_Update_State render_update_state_{};
|
||||||
std::uint64_t total_update_count_{};
|
std::uint64_t total_update_count_{};
|
||||||
std::uint64_t last_update_time_ns_{};
|
std::uint64_t last_update_time_ns_{};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -101,6 +101,15 @@ auto History_Real_Time_Data<Value_Type, Container, Mutex, Observer>::snapshot()
|
|||||||
return *cache_state_;
|
return *cache_state_;
|
||||||
}
|
}
|
||||||
template <class Value_Type, class Container, Mutex_Type Mutex, class Observer>
|
template <class Value_Type, class Container, Mutex_Type Mutex, class Observer>
|
||||||
|
auto History_Real_Time_Data<Value_Type, Container, Mutex, Observer>::snapshot_with_update_state() const -> Snapshot {
|
||||||
|
std::lock_guard < Mutex > lock(mutex_);
|
||||||
|
const Real_Time_Data_Update_State update_state{
|
||||||
|
this, Real_Time_Data_Retention::history, revision_, last_update_time_ns_,
|
||||||
|
total_update_count_, cache_state_->size()
|
||||||
|
};
|
||||||
|
return {*cache_state_, update_state};
|
||||||
|
}
|
||||||
|
template <class Value_Type, class Container, Mutex_Type Mutex, class Observer>
|
||||||
std::size_t History_Real_Time_Data<Value_Type, Container, Mutex, Observer>::size() const {
|
std::size_t History_Real_Time_Data<Value_Type, Container, Mutex, Observer>::size() const {
|
||||||
std::lock_guard < Mutex > lock(mutex_);
|
std::lock_guard < Mutex > lock(mutex_);
|
||||||
return cache_state_->size();
|
return cache_state_->size();
|
||||||
@@ -144,12 +153,20 @@ std::size_t History_Real_Time_Data<Value_Type, Container, Mutex, Observer>::disc
|
|||||||
template <class Value_Type, class Container, Mutex_Type Mutex, class Observer>
|
template <class Value_Type, class Container, Mutex_Type Mutex, class Observer>
|
||||||
void History_Real_Time_Data<Value_Type, Container, Mutex, Observer>::publish_render_state() {
|
void History_Real_Time_Data<Value_Type, Container, Mutex, Observer>::publish_render_state() {
|
||||||
std::lock_guard < Mutex > lock(mutex_);
|
std::lock_guard < Mutex > lock(mutex_);
|
||||||
if (render_revision_ == revision_) return;
|
if (render_update_state_.revision == revision_) return;
|
||||||
*scratch_state_ = *cache_state_;
|
*scratch_state_ = *cache_state_;
|
||||||
std::swap(render_state_, scratch_state_);
|
std::swap(render_state_, scratch_state_);
|
||||||
render_revision_ = revision_;
|
render_update_state_ = {
|
||||||
|
this, Real_Time_Data_Retention::history, revision_, last_update_time_ns_,
|
||||||
|
total_update_count_, render_state_->size()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
template <class Value_Type, class Container, Mutex_Type Mutex, class Observer>
|
template <class Value_Type, class Container, Mutex_Type Mutex, class Observer>
|
||||||
auto History_Real_Time_Data<Value_Type, Container, Mutex, Observer>::render_state_value() const noexcept -> const Container& {
|
auto History_Real_Time_Data<Value_Type, Container, Mutex, Observer>::render_state_value() const noexcept -> const Container& {
|
||||||
return *render_state_;
|
return *render_state_;
|
||||||
}
|
}
|
||||||
|
template <class Value_Type, class Container, Mutex_Type Mutex, class Observer>
|
||||||
|
auto History_Real_Time_Data<Value_Type, Container, Mutex, Observer>::render_update_state_value() const noexcept
|
||||||
|
-> const Real_Time_Data_Update_State& {
|
||||||
|
return render_update_state_;
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ public:
|
|||||||
[[nodiscard]] const auto& get(const Source& source) const noexcept {
|
[[nodiscard]] const auto& get(const Source& source) const noexcept {
|
||||||
return source.render_state_value();
|
return source.render_state_value();
|
||||||
}
|
}
|
||||||
|
template <class Source>
|
||||||
|
[[nodiscard]] const auto& update_state(const Source& source) const noexcept {
|
||||||
|
return source.render_update_state_value();
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
friend class Renderable_Base;
|
friend class Renderable_Base;
|
||||||
friend class Frame_Render_Snapshot;
|
friend class Frame_Render_Snapshot;
|
||||||
|
|||||||
@@ -3,18 +3,37 @@
|
|||||||
#include "Plottable_Real_Time_Data.h"
|
#include "Plottable_Real_Time_Data.h"
|
||||||
#include "../render/Blend2D_Cache.h"
|
#include "../render/Blend2D_Cache.h"
|
||||||
#include "../renderable/Renderable_p.h"
|
#include "../renderable/Renderable_p.h"
|
||||||
#include <algorithm>
|
#include <cstdint>
|
||||||
#include <cmath>
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
namespace renderive::detail {
|
namespace renderive::detail {
|
||||||
namespace {
|
namespace {
|
||||||
using Sweep_Spectrum_History = Plottable_History_Real_Time_Data<std::vector<double>, std::deque<std::vector<double>>>;
|
using Sweep_Spectrum_History = Plottable_History_Real_Time_Data<std::vector<double>, std::deque<std::vector<double>>>;
|
||||||
std::vector<double> flatten(const std::deque<std::vector<double>>& blocks) {
|
std::size_t current_sweep_block_count(std::uint64_t total_update_count,
|
||||||
|
std::size_t block_count) {
|
||||||
|
if (total_update_count == 0) return 0;
|
||||||
|
return static_cast<std::size_t>((total_update_count - 1) % block_count) + 1;
|
||||||
|
}
|
||||||
|
std::vector<double> flatten_latest(const std::deque<std::vector<double>>& blocks,
|
||||||
|
std::size_t block_count) {
|
||||||
std::vector<double> values;
|
std::vector<double> values;
|
||||||
for (const auto& block : blocks) values.insert(values.end(), block.begin(), block.end());
|
const std::size_t first = blocks.size() - block_count;
|
||||||
|
std::size_t value_count{};
|
||||||
|
for (std::size_t index = first; index < blocks.size(); ++index) {
|
||||||
|
value_count += blocks[index].size();
|
||||||
|
}
|
||||||
|
values.reserve(value_count);
|
||||||
|
for (std::size_t index = first; index < blocks.size(); ++index) {
|
||||||
|
values.insert(values.end(), blocks[index].begin(), blocks[index].end());
|
||||||
|
}
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
Range completed_frequency_range(Range frequency_range,
|
||||||
|
std::size_t completed_block_count,
|
||||||
|
std::size_t block_count) {
|
||||||
|
const double completed = static_cast<double>(completed_block_count) / static_cast<double>(block_count);
|
||||||
|
return {frequency_range.origin, frequency_range.origin + frequency_range.length() * completed};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
struct Sweep_Spectrum::Impl
|
struct Sweep_Spectrum::Impl
|
||||||
: Base::next_Impl<Impl> {
|
: Base::next_Impl<Impl> {
|
||||||
@@ -71,8 +90,17 @@ std::size_t Sweep_Spectrum::stored_point_count() const {
|
|||||||
}
|
}
|
||||||
std::size_t Sweep_Spectrum::rendered_point_count() const {
|
std::size_t Sweep_Spectrum::rendered_point_count() const {
|
||||||
const auto state = Renderable::state<State>();
|
const auto state = Renderable::state<State>();
|
||||||
const auto values = flatten(d_func<Impl>().blocks->snapshot());
|
const auto snapshot = d_func<Impl>().blocks->snapshot_with_update_state();
|
||||||
return curve_points(values, state.frequency_range, d_func<Impl>().frequency_axis->transform(), d_func<Impl>().power_axis->transform(), state.visible_range_only, state.interpolation_mode).size();
|
const std::size_t block_count = static_cast<std::size_t>(state.block_count.get());
|
||||||
|
const std::size_t completed_block_count =
|
||||||
|
current_sweep_block_count(snapshot.update_state.total_update_count, block_count);
|
||||||
|
const auto values = flatten_latest(snapshot.values, completed_block_count);
|
||||||
|
const Range frequency_range = completed_frequency_range(
|
||||||
|
state.frequency_range, completed_block_count, block_count);
|
||||||
|
return curve_points(values, frequency_range,
|
||||||
|
d_func<Impl>().frequency_axis->transform(),
|
||||||
|
d_func<Impl>().power_axis->transform(),
|
||||||
|
state.visible_range_only, state.interpolation_mode).size();
|
||||||
}
|
}
|
||||||
Sweep_Spectrum::Observer Sweep_Spectrum::capture_observation() const {
|
Sweep_Spectrum::Observer Sweep_Spectrum::capture_observation() const {
|
||||||
const auto value = Renderable::published_state<State>();
|
const auto value = Renderable::published_state<State>();
|
||||||
@@ -88,16 +116,21 @@ void Sweep_Spectrum::Impl::prepare_frame(const Prepare_Render_Context& context)
|
|||||||
const auto& view = context.frame.render_state;
|
const auto& view = context.frame.render_state;
|
||||||
const auto& state = control.render_state<State>(view);
|
const auto& state = control.render_state<State>(view);
|
||||||
const auto& published_blocks = view.get(*blocks);
|
const auto& published_blocks = view.get(*blocks);
|
||||||
const auto values = flatten(published_blocks);
|
const auto& published_update_state = view.update_state(*blocks);
|
||||||
|
const std::size_t block_count = static_cast<std::size_t>(state.block_count.get());
|
||||||
|
const std::size_t completed_block_count = current_sweep_block_count(
|
||||||
|
published_update_state.total_update_count, block_count);
|
||||||
|
const auto values = flatten_latest(published_blocks, completed_block_count);
|
||||||
auto& output = prepare_buffer;
|
auto& output = prepare_buffer;
|
||||||
output = {};
|
output = {};
|
||||||
if (values.size() < 2) return;
|
if (values.size() < 2) return;
|
||||||
const Axis_Transform x = frequency_axis->transform(view);
|
const Axis_Transform x = frequency_axis->transform(view);
|
||||||
const Axis_Transform y = power_axis->transform(view);
|
const Axis_Transform y = power_axis->transform(view);
|
||||||
output.points = curve_points(values, state.frequency_range, x, y,
|
const Range frequency_range = completed_frequency_range(
|
||||||
|
state.frequency_range, completed_block_count, block_count);
|
||||||
|
output.points = curve_points(values, frequency_range, x, y,
|
||||||
state.visible_range_only, state.interpolation_mode);
|
state.visible_range_only, state.interpolation_mode);
|
||||||
const double completed = std::min(1.0, static_cast<double>(published_blocks.size()) / state.block_count.get());
|
const double frequency = frequency_range.target;
|
||||||
const double frequency = state.frequency_range.origin + state.frequency_range.length() * completed;
|
|
||||||
output.current_first = mapped_point(x, frequency, y, y.coordinate_range.origin);
|
output.current_first = mapped_point(x, frequency, y, y.coordinate_range.origin);
|
||||||
output.current_second = mapped_point(x, frequency, y, y.coordinate_range.target);
|
output.current_second = mapped_point(x, frequency, y, y.coordinate_range.target);
|
||||||
output.valid = true;
|
output.valid = true;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <numbers>
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -35,6 +36,8 @@ struct Observer_Pfr_Adapter<Render_Scene_2D::Observer> {
|
|||||||
Render_Scene_2D::Observer, Render_Scene_2D::Observer_Fields>;
|
Render_Scene_2D::Observer, Render_Scene_2D::Observer_Fields>;
|
||||||
};
|
};
|
||||||
namespace {
|
namespace {
|
||||||
|
constexpr std::size_t sweep_bins_per_block = 64;
|
||||||
|
constexpr std::size_t sweep_block_count = 8;
|
||||||
std::shared_ptr<Frame_Control_Strategy_Base> make_strategy(
|
std::shared_ptr<Frame_Control_Strategy_Base> make_strategy(
|
||||||
Gallery_Frame_Mode mode) {
|
Gallery_Frame_Mode mode) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
@@ -349,8 +352,8 @@ private:
|
|||||||
} else if (case_id_ == "sweep_spectrum") {
|
} else if (case_id_ == "sweep_spectrum") {
|
||||||
Sweep_Spectrum::State state;
|
Sweep_Spectrum::State state;
|
||||||
state.frequency_range = {0.0, 300.0};
|
state.frequency_range = {0.0, 300.0};
|
||||||
state.bins_per_block = 64;
|
state.bins_per_block = static_cast<int>(sweep_bins_per_block);
|
||||||
state.block_count = 8;
|
state.block_count = static_cast<int>(sweep_block_count);
|
||||||
Sweep_Spectrum::Builder builder{state, &attach};
|
Sweep_Spectrum::Builder builder{state, &attach};
|
||||||
sweep_ = build<Sweep_Spectrum>(
|
sweep_ = build<Sweep_Spectrum>(
|
||||||
builder, root, domain_axis_, value_axis_);
|
builder, root, domain_axis_, value_axis_);
|
||||||
@@ -382,9 +385,16 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void update_samples() {
|
void update_samples() {
|
||||||
const std::size_t count = waterfall_ ? 256U : afterglow_ ? 192U : 512U;
|
const std::size_t count =
|
||||||
|
waterfall_ ? 256U :
|
||||||
|
afterglow_ ? 192U :
|
||||||
|
sweep_ ? sweep_bins_per_block * sweep_block_count : 512U;
|
||||||
std::vector<double> values(count);
|
std::vector<double> values(count);
|
||||||
const double time = static_cast<double>(sample_sequence_++) * 0.075;
|
const std::uint64_t sample_sequence = sample_sequence_++;
|
||||||
|
const std::uint64_t time_sequence = sweep_
|
||||||
|
? sample_sequence / sweep_block_count * sweep_block_count
|
||||||
|
: sample_sequence;
|
||||||
|
const double time = static_cast<double>(time_sequence) * 0.075;
|
||||||
for (std::size_t index = 0; index < count; ++index) {
|
for (std::size_t index = 0; index < count; ++index) {
|
||||||
const double x = static_cast<double>(index) / (count - 1);
|
const double x = static_cast<double>(index) / (count - 1);
|
||||||
const auto gaussian = [](double value, double center, double width) {
|
const auto gaussian = [](double value, double center, double width) {
|
||||||
@@ -402,15 +412,26 @@ private:
|
|||||||
if (waterfall_) waterfall_->append_row(current_time_of_day(), values);
|
if (waterfall_) waterfall_->append_row(current_time_of_day(), values);
|
||||||
if (afterglow_) afterglow_->append_spectrum(values);
|
if (afterglow_) afterglow_->append_spectrum(values);
|
||||||
if (sweep_) {
|
if (sweep_) {
|
||||||
values.resize(64);
|
const std::size_t block_index = static_cast<std::size_t>(
|
||||||
sweep_->append_block(values);
|
sample_sequence % sweep_block_count);
|
||||||
|
const std::size_t first = block_index * sweep_bins_per_block;
|
||||||
|
sweep_->append_block(std::span<const double>(
|
||||||
|
values.data() + first, sweep_bins_per_block));
|
||||||
}
|
}
|
||||||
if (trace_) trace_->append_sample(current_time_of_day(), std::sin(time));
|
if (trace_) trace_->append_sample(current_time_of_day(), std::sin(time));
|
||||||
if (constellation_) {
|
if (constellation_) {
|
||||||
const double phase = time * 1.7;
|
constexpr std::size_t symbol_count =
|
||||||
|
static_cast<std::size_t>(Constellation_Diagram_Type::Psk8);
|
||||||
|
const std::size_t symbol_index = sample_sequence % symbol_count;
|
||||||
|
const double phase = 2.0 * std::numbers::pi *
|
||||||
|
static_cast<double>(symbol_index) /
|
||||||
|
static_cast<double>(symbol_count);
|
||||||
|
const double i_noise =
|
||||||
|
std::sin(time * 17.0 + static_cast<double>(symbol_index) * 0.73) * 0.04;
|
||||||
|
const double q_noise =
|
||||||
|
std::cos(time * 19.0 + static_cast<double>(symbol_index) * 1.11) * 0.04;
|
||||||
constellation_->append_point(
|
constellation_->append_point(
|
||||||
{std::cos(phase) + std::sin(time * 9.0) * 0.08,
|
{std::cos(phase) + i_noise, std::sin(phase) + q_noise});
|
||||||
std::sin(phase) + std::cos(time * 7.0) * 0.08});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user