blocky/playground/sensor.cc
2022-06-22 11:48:52 +09:00

193 lines
5.2 KiB
C++

extern "C" {
# include <liblocky.h>
}
#include <algorithm>
#include <cinttypes>
#include <cmath>
#include <numeric>
#include <string>
#include <vector>
#include <imgui.h>
#include <implot.h>
#include "app.hh"
#include "input.hh"
namespace pg {
namespace {
class Sensor final : public App {
public:
static inline TypeInfo kType = TypeInfo::Create<Sensor>("Sensor");
Sensor() noexcept {
}
void Update() noexcept override {
const auto em = ImGui::GetFontSize();
const auto id = "Sensor | "+
std::to_string(reinterpret_cast<uintptr_t>(this));
ImGui::SetNextWindowSize({64*em, 24*em}, ImGuiCond_Once);
if (ImGui::Begin(id.c_str())) {
bool mod = false;
ImGui::BeginGroup();
{
ImGui::PushItemWidth(6*em);
mod |= ImGui::DragInt("input slot", &src_, 1, 0, 1024);
mod |= ImGui::DragInt("start", &start_, 1, 0, 1024);
mod |= ImGui::DragInt("dur", &dur_, 1, 1, BLKY_SENSOR_MAX_DUR);
ImGui::Spacing();
ImGui::DragFloat2("pos", pos_, .001f);
ImGui::DragInt("offset", &offset_, 1, 0, 3);
if (ImGui::Button("add")) {
mod = true;
data_.emplace_back(pos_[0], pos_[1], offset_);
}
if (ImGui::BeginListBox("##points")) {
for (size_t i = 0; i < data_.size(); ++i) {
const auto& data = data_[i];
const auto name =
std::to_string(i)+". "+
std::to_string(data.pos[0])+","+
std::to_string(data.pos[1]);
ImGui::Selectable(name.c_str());
if (ImGui::BeginPopupContextItem()) {
if (ImGui::MenuItem("clear all")) {
mod = true;
data_.clear();
}
ImGui::EndPopup();
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip(
"pos : %f,%f + %" PRIiMAX "\n"
"avg : %f\n"
"var : %f\n"
"correl: %f",
data.pos[0], data.pos[1], data.offset,
data.avg, data.var, data.correl);
}
}
ImGui::EndListBox();
}
double correl_abs_avg = 0;
for (auto& data : data_) {
correl_abs_avg += fabs(data.correl);
}
correl_abs_avg /= static_cast<float>(data_.size());
ImGui::Text("avg(abs(r)) = %f", correl_abs_avg);
double correl_abs_var = 0;
for (auto& data : data_) {
const auto diff = fabs(data.correl)-correl_abs_avg;
correl_abs_var += diff*diff;
}
correl_abs_var /= static_cast<float>(data_.size());
ImGui::Text("var(abs(r)) = %f", correl_abs_var);
ImGui::PopItemWidth();
if (mod) {
try {
Calc();
msg_ = "";
} catch (const char* msg) {
msg_ = msg;
}
}
}
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
auto avail = ImGui::GetContentRegionAvail();
avail.x -= em;
avail.y -= em;
const ImVec2 size = {avail.x/2, avail.y};
if (ImPlot::BeginPlot("input value", size)) {
ImPlot::SetupAxis(ImAxis_X1, nullptr, ImPlotAxisFlags_AutoFit);
ImPlot::SetupAxisLimits(ImAxis_Y1, -0.1, 1.1);
for (size_t i = 0; i < data_.size(); ++i) {
const auto& d = data_[i];
ImPlot::PlotLine(
std::to_string(i).c_str(),
d.values.data(), static_cast<int>(d.values.size()), 1, start_);
}
ImPlot::EndPlot();
}
ImGui::SameLine();
if (ImPlot::BeginPlot("input histogram", size)) {
ImPlot::SetupAxisLimits(ImAxis_X1, 0, 1);
ImPlot::SetupAxis(ImAxis_Y1, nullptr, ImPlotAxisFlags_AutoFit);
for (size_t i = 0; i < data_.size(); ++i) {
const auto& d = data_[i];
ImPlot::PlotHistogram(
std::to_string(i).c_str(),
d.values.data(), static_cast<int>(d.values.size()));
}
ImPlot::EndPlot();
}
ImGui::EndGroup();
ImGui::TextUnformatted(msg_.c_str());
}
ImGui::End();
}
private:
int src_ = 0, start_ = 0, dur_ = 30;
float pos_[2];
int offset_;
struct Data final {
public:
float pos[2];
size_t offset;
std::vector<float> values;
double avg;
double var;
double cov;
double correl;
Data(float x, float y, int off) noexcept :
pos{x, y}, offset(static_cast<size_t>(off)) {
}
};
std::vector<Data> data_;
std::string msg_;
void Calc();
};
void Sensor::Calc() {
auto in = Input::instance().slots(static_cast<size_t>(src_));
if (!in) throw "missing slot";
if (dur_ == 0) throw "invalid time range";
for (auto& data : data_) {
const auto xf = std::clamp(data.pos[0], 0.f, 1.f);
const auto yf = std::clamp(data.pos[1], 0.f, 1.f);
const auto dur = static_cast<size_t>(dur_);
const auto st = static_cast<size_t>(start_);
data.values = in->FetchSamples(st, dur, xf, yf, data.offset);
blky_sensor_t sensor = {};
blky_sensor_feed(&sensor, data.values.data(), data.values.size());
data.avg = sensor.avg;
data.var = sensor.var;
data.cov = sensor.cov;
data.correl = sensor.correl;
}
}
}
} // namespace pg