[sysid] Error on missing tests in loaded DataLog (#7747)

* add exception

* detect missing tests

* throw in analyzer

* define tests setter

* change to std::map

* alignas fail

* make missingTests parameter const&

* const& impl

* use set and naive comparison

* use default comparison

* add <utility>

* Revert "alignas fail"

This reverts commit 5e97940f34.

* indent validtests

* format
This commit is contained in:
DeltaDizzy
2025-02-04 18:12:00 -05:00
committed by GitHub
parent 296986397b
commit b3b515e1dd
6 changed files with 68 additions and 2 deletions

View File

@@ -106,8 +106,10 @@ void Application(std::string_view saveDir) {
auto analyzer = std::make_unique<sysid::Analyzer>(storage, gLogger);
logLoader->unload.connect([ds = dataSelector.get()] { ds->Reset(); });
dataSelector->testdata = [_analyzer = analyzer.get()](auto data) {
dataSelector->testdata = [_analyzer = analyzer.get(),
ds = dataSelector.get()](auto data) {
_analyzer->m_data = data;
_analyzer->SetMissingTests(ds->m_missingTests);
_analyzer->AnalyzeData();
};

View File

@@ -10,6 +10,7 @@
#include <numbers>
#include <string>
#include <thread>
#include <vector>
#include <fmt/format.h>
#include <glass/Context.h>
@@ -251,6 +252,13 @@ void Analyzer::Display() {
}
break;
}
case AnalyzerState::kMissingTestsError: {
CreateErrorPopup(m_errorPopup, m_exception);
if (!m_errorPopup) {
m_state = AnalyzerState::kWaitingForData;
}
break;
}
case AnalyzerState::kGeneralDataError:
case AnalyzerState::kTestDurationError:
case AnalyzerState::kVelocityThresholdError: {
@@ -269,6 +277,9 @@ void Analyzer::Display() {
void Analyzer::PrepareData() {
WPI_INFO(m_logger, "{}", "Preparing data");
try {
if (m_missingTests.size() > 0) {
throw sysid::MissingTestsError{m_missingTests};
}
m_manager->PrepareData();
UpdateFeedforwardGains();
UpdateFeedbackGains();
@@ -281,6 +292,9 @@ void Analyzer::PrepareData() {
} catch (const sysid::NoDynamicDataError& e) {
m_state = AnalyzerState::kTestDurationError;
HandleError(e.what());
} catch (const sysid::MissingTestsError& e) {
m_state = AnalyzerState::kMissingTestsError;
HandleError(e.what());
} catch (const AnalysisManager::FileReadingError& e) {
m_state = AnalyzerState::kFileError;
HandleError(e.what());
@@ -324,6 +338,10 @@ void Analyzer::HandleError(std::string_view msg) {
PrepareRawGraphs();
}
void Analyzer::SetMissingTests(const std::vector<std::string>& missingTests) {
m_missingTests = missingTests;
}
void Analyzer::DisplayGraphs() {
ImGui::SetNextWindowPos(ImVec2{kDiagnosticPlotWindowPos},
ImGuiCond_FirstUseEver);

View File

@@ -6,6 +6,7 @@
#include <algorithm>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
@@ -111,6 +112,7 @@ void DataSelector::Display() {
continue;
}
WPI_INFO(m_logger, "Loaded test state {}", it2->first);
m_executedTests.insert(it2->first);
++it2;
}
if (it->second.empty()) {
@@ -132,6 +134,15 @@ void DataSelector::Display() {
return;
}
if (m_executedTests.size() < 4 && !m_testCountValidated) {
for (auto test : kValidTests) {
if (!m_executedTests.contains(test)) {
m_missingTests.push_back(test);
m_testCountValidated = true;
}
}
}
#if 0
// Test filtering
if (ImGui::BeginCombo("Test", m_selectedTest.c_str())) {

View File

@@ -4,15 +4,16 @@
#pragma once
#include <cmath>
#include <exception>
#include <functional>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
#include <vector>
#include <fmt/format.h>
#include <fmt/ranges.h>
#include <frc/filter/LinearFilter.h>
#include <units/time.h>
#include <wpi/StringMap.h>
@@ -68,6 +69,25 @@ class NoQuasistaticDataError : public std::exception {
}
};
/**
* Exception for not all tests being present.
*/
class MissingTestsError : public std::exception {
public:
explicit MissingTestsError(std::vector<std::string> MissingTests)
: missingTests(std::move(MissingTests)) {
errorString = fmt::format(
"The following tests were not detected: {}. Make sure to perform all "
"four tests as described in the SysId documentation.",
fmt::join(missingTests, ", "));
}
const char* what() const noexcept override { return errorString.c_str(); }
private:
std::vector<std::string> missingTests;
std::string errorString;
};
/**
* Exception for Dynamic Data being completely removed.
*/

View File

@@ -8,6 +8,7 @@
#include <string>
#include <string_view>
#include <thread>
#include <vector>
#include <glass/View.h>
#include <implot.h>
@@ -46,6 +47,7 @@ class Analyzer : public glass::View {
kVelocityThresholdError,
kTestDurationError,
kGeneralDataError,
kMissingTestsError,
kFileError
};
/**
@@ -91,6 +93,11 @@ class Analyzer : public glass::View {
*/
void AnalyzeData();
/**
* Used by DataSelector to import any missing tests.
*/
void SetMissingTests(const std::vector<std::string>& missingTests);
private:
/**
* Kills the data preparation thread
@@ -199,6 +206,7 @@ class Analyzer : public glass::View {
// Stores the exception message.
std::string m_exception;
std::vector<std::string> m_missingTests;
bool m_calcDefaults = false;

View File

@@ -7,6 +7,7 @@
#include <functional>
#include <future>
#include <map>
#include <set>
#include <string>
#include <utility>
#include <vector>
@@ -55,6 +56,7 @@ class DataSelector : public glass::View {
* Called when new test data is loaded.
*/
std::function<void(TestData)> testdata;
std::vector<std::string> m_missingTests;
private:
wpi::Logger& m_logger;
@@ -74,6 +76,11 @@ class DataSelector : public glass::View {
int m_selectedAnalysis = 0;
std::future<TestData> m_testdataFuture;
std::vector<std::string> m_testdataStats;
std::set<std::string> kValidTests = {"quasistatic-forward",
"quasistatic-reverse", "dynamic-forward",
"dynamic-reverse"};
std::set<std::string> m_executedTests;
bool m_testCountValidated = false;
static Tests LoadTests(const glass::DataLogReaderEntry& testStateEntry);
TestData BuildTestData();