Skip to content

Commit

Permalink
Fix demo dashboard to show FFT magnitude plot.
Browse files Browse the repository at this point in the history
Signed-off-by: drslebedev <[email protected]>
  • Loading branch information
drslebedev committed Sep 12, 2024
1 parent db00420 commit a65a21e
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 49 deletions.
2 changes: 1 addition & 1 deletion src/ui/Flowgraph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ struct BlockDefinition {

bool isPlotSink() const {
// TODO make this smarter once metaInformation() is statically available
return name == "opendigitizer::ImPlotSink";
return name == "opendigitizer::ImPlotSink" || name == "opendigitizer::ImPlotSinkDataSet";
}

// TODO: Move to a separate class
Expand Down
7 changes: 4 additions & 3 deletions src/ui/assets/sampleDashboards/DemoDashboard.grc
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,20 @@ blocks:
- name: sine source 1
id: opendigitizer::SineSource
parameters:
frequency: 1.000000
frequency: 2.000000
- name: sine source 3
id: opendigitizer::SineSource
parameters:
frequency: 1.300000
frequency: 5.00000
- name: sink 1
id: opendigitizer::ImPlotSink
parameters:
color: 0xff0000
- name: sink 2
id: opendigitizer::ImPlotSink
id: opendigitizer::ImPlotSinkDataSet
parameters:
color: 0x00ff00
dataset_index: 3
- name: sink 3
id: opendigitizer::ImPlotSink
parameters:
Expand Down
12 changes: 6 additions & 6 deletions src/ui/assets/sampleDashboards/DemoDashboard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ plots:
- name: Plot 1
axes:
- axis: X
min: 80.608794095692545
max: 206.35240462778688
min: 0.1
max: 1500.
- axis: Y
min: -1
max: 1.0175589323043823
Expand All @@ -31,8 +31,8 @@ plots:
- name: Plot 2
axes:
- axis: X
min: 0.36935118162350633
max: 276.37280626129569
min: 0.1
max: 50.0
- axis: Y
min: 0.0003612833097577095
max: 0.78648322820663452
Expand All @@ -46,8 +46,8 @@ plots:
- name: Plot 3
axes:
- axis: X
min: 114.35908852541695
max: 967.13385827649222
min: 0.1
max: 3000.0
- axis: Y
min: -1.991981029510498
max: 1.9978399276733398
Expand Down
88 changes: 53 additions & 35 deletions src/ui/blocks/ImPlotSink.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
namespace opendigitizer {

template<typename T>
struct ImPlotSink : public gr::Block<ImPlotSink<T>,
gr::BlockingIO<false>, gr::SupportedTypes<float, double, gr::DataSet<float>, gr::DataSet<double>>, gr::Drawable<gr::UICategory::ChartPane, "Dear ImGui">> {
struct ImPlotSink : public gr::Block<ImPlotSink<T>, gr::BlockingIO<false>, gr::SupportedTypes<float, double>, gr::Drawable<gr::UICategory::ChartPane, "Dear ImGui">> {
gr::PortIn<T> in;
uint32_t color = 0xff0000; ///< RGB color for the plot // TODO use better type, support configurable colors for datasets?
std::string signal_name;
Expand All @@ -26,58 +25,77 @@ struct ImPlotSink : public gr::Block<ImPlotSink<T>,
float signal_max = std::numeric_limits<float>::max();

public:
std::conditional_t<meta::is_dataset_v<T>, T, gr::HistoryBuffer<T>> data = [] {
if constexpr (meta::is_dataset_v<T>) {
return T{};
} else {
return gr::HistoryBuffer<T>{ 65536 };
}
}();
gr::HistoryBuffer<T> data = gr::HistoryBuffer<T>{65536};

gr::work::Status processBulk(gr::ConsumableSpan auto& input) noexcept {
data.push_back_bulk(input);
std::ignore = input.consume(input.size());
return gr::work::Status::OK;
}

gr::work::Status processBulk(gr::ConsumableSpan auto &input) noexcept {
if constexpr (meta::is_dataset_v<T>) {
data = input.back();
gr::work::Status draw() noexcept {
[[maybe_unused]] const gr::work::Status status = this->invokeWork();
const auto& label = signal_name.empty() ? this->name.value : signal_name;
if (data.empty()) {
// Plot one single dummy value so that the sink shows up in the plot legend
T v = {};
ImPlot::PlotLine(label.c_str(), &v, 1);
} else {
data.push_back_bulk(input);
// ImPlot::SetNextLineStyle(ImGui::ColorConvertU32ToFloat4((color << 8) | 0xff));
// ImPlot::HideNextItem(false, ImPlotCond_Always);
const auto span = std::span(data.begin(), data.end());
// TODO should we limit this to the last N (N might be UI-dependent) samples?
ImPlot::PlotLine(label.c_str(), span.data(), static_cast<int>(span.size()));
}

return gr::work::Status::OK;
}
};

template<typename T>
struct ImPlotSinkDataSet : public gr::Block<ImPlotSinkDataSet<T>, gr::BlockingIO<false>, gr::SupportedTypes<float, double>, gr::Drawable<gr::UICategory::ChartPane, "Dear ImGui">> {
gr::PortIn<gr::DataSet<T>> in;
uint32_t color = 0xff0000; ///< RGB color for the plot // TODO use better type, support configurable colors for datasets?
std::string signal_name;
std::string signal_unit;
float signal_min = std::numeric_limits<float>::lowest();
float signal_max = std::numeric_limits<float>::max();
gr::Size_t dataset_index = std::numeric_limits<gr::Size_t>::max();

public:
gr::DataSet<T> data{};

gr::work::Status processBulk(gr::ConsumableSpan auto& input) noexcept {
data = input.back();
std::ignore = input.consume(input.size());
return gr::work::Status::OK;
}

gr::work::Status
draw() noexcept {
gr::work::Status draw() noexcept {
[[maybe_unused]] const gr::work::Status status = this->invokeWork();
if constexpr (meta::is_dataset_v<T>) {
if (data.extents.empty()) {
return gr::work::Status::OK;
}

if (data.extents.empty()) {
return gr::work::Status::OK;
}
const auto n = data.extents[1];
if (dataset_index == std::numeric_limits<gr::Size_t>::max()) {
for (std::int32_t i = 0; i < data.extents[0]; ++i) {
const auto n = data.extents[1];
ImPlot::PlotLine(data.signal_names[static_cast<std::size_t>(i)].c_str(), data.signal_values.data() + n * i, n);
}
} else {
const auto &label = signal_name.empty() ? this->name.value : signal_name;
if (data.empty()) {
// Plot one single dummy value so that the sink shows up in the plot legend
T v = {};
ImPlot::PlotLine(label.c_str(), &v, 1);
} else {
ImPlot::SetNextLineStyle(ImGui::ColorConvertU32ToFloat4((color << 8) | 0xff));
ImPlot::HideNextItem(false, ImPlotCond_Always);
const auto span = std::span(data.begin(), data.end());
// TODO should we limit this to the last N (N might be UI-dependent) samples?
ImPlot::PlotLine(label.c_str(), span.data(), static_cast<int>(span.size()));
if (dataset_index >= data.extents[0]) {
dataset_index = 0U;
}
ImPlot::PlotLine(data.signal_names[static_cast<std::size_t>(dataset_index)].c_str(), data.signal_values.data() + n * dataset_index, n);
}
return gr::work::Status::OK;
}
};

} // namespace opendigitizer

ENABLE_REFLECTION_FOR_TEMPLATE(opendigitizer::ImPlotSink, in, color, signal_name, signal_unit, signal_min, signal_max);

auto registerImPlotSink = gr::registerBlock<opendigitizer::ImPlotSink, float, double, gr::DataSet<float>, gr::DataSet<double>>(gr::globalBlockRegistry());
ENABLE_REFLECTION_FOR_TEMPLATE_FULL((typename T), (opendigitizer::ImPlotSink<T>), in, color, signal_name, signal_unit, signal_min, signal_max);
ENABLE_REFLECTION_FOR_TEMPLATE_FULL((typename T), (opendigitizer::ImPlotSinkDataSet<T>), in, color, signal_name, signal_unit, signal_min, signal_max, dataset_index);

auto registerImPlotSink = gr::registerBlock<opendigitizer::ImPlotSink, float, double>(gr::globalBlockRegistry());
auto registerImPlotSinkDataSet = gr::registerBlock<opendigitizer::ImPlotSinkDataSet, float, double>(gr::globalBlockRegistry());
#endif
8 changes: 4 additions & 4 deletions src/ui/blocks/SineSource.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
namespace opendigitizer {

template<typename T>
requires std::is_arithmetic_v<T>
requires std::is_arithmetic_v<T>
struct SineSource : public gr::Block<SineSource<T>, gr::BlockingIO<true>> {
using super_t = gr::Block<SineSource<T>, gr::BlockingIO<true>>;
gr::MsgPortIn freqIn;
Expand All @@ -23,7 +23,7 @@ struct SineSource : public gr::Block<SineSource<T>, gr::BlockingIO<true>> {
std::thread thread;
std::atomic_bool quit = false;

void start() {
void start() {
thread = std::thread([this]() {
using namespace std::chrono_literals;
while (!quit) {
Expand All @@ -36,7 +36,7 @@ struct SineSource : public gr::Block<SineSource<T>, gr::BlockingIO<true>> {
conditionvar.notify_all();
}

std::this_thread::sleep_for(20ms);
std::this_thread::sleep_for(2ms);
}
});
}
Expand All @@ -48,7 +48,7 @@ struct SineSource : public gr::Block<SineSource<T>, gr::BlockingIO<true>> {
conditionvar.notify_all();
}

auto processBulk(gr::PublishableSpan auto &output) {
auto processBulk(gr::PublishableSpan auto& output) {
// technically, this wouldn't have to block, but could just publish 0 samples,
// but keep it as test case for BlockingIO<true>.
std::unique_lock guard(mutex);
Expand Down

0 comments on commit a65a21e

Please sign in to comment.