Ref T421, interpolation log messages in interpolator(s)

This commit is contained in:
Klaus Basan
2018-10-31 15:27:02 +01:00
parent 2581ec5582
commit 41685df4ee
6 changed files with 141 additions and 37 deletions

View File

@@ -179,13 +179,15 @@ namespace BlackMisc
// CInterpolatorLinear::Interpolant or CInterpolatorSpline::Interpolant // CInterpolatorLinear::Interpolant or CInterpolatorSpline::Interpolant
SituationLog log; SituationLog log;
const auto interpolant = derived()->getInterpolant(log); const auto interpolant = derived()->getInterpolant(log);
const bool isValid = interpolant.isValid(); const bool isValidInterpolant = interpolant.isValid();
CAircraftSituation currentSituation = m_lastSituation; CAircraftSituation currentSituation = m_lastSituation;
CAircraftSituation::AltitudeCorrection altCorrection = CAircraftSituation::NoCorrection; CAircraftSituation::AltitudeCorrection altCorrection = CAircraftSituation::NoCorrection;
if (isValid) bool isValidInterpolation = false;
do
{ {
if (!isValidInterpolant) { break; }
const CInterpolatorPbh pbh = interpolant.pbh(); const CInterpolatorPbh pbh = interpolant.pbh();
// init interpolated situation // init interpolated situation
@@ -200,6 +202,8 @@ namespace BlackMisc
// use derived interpolant function // use derived interpolant function
const bool interpolateGndFlag = pbh.getNewSituation().hasGroundDetailsForGndInterpolation() && pbh.getOldSituation().hasGroundDetailsForGndInterpolation(); const bool interpolateGndFlag = pbh.getNewSituation().hasGroundDetailsForGndInterpolation() && pbh.getOldSituation().hasGroundDetailsForGndInterpolation();
currentSituation = interpolant.interpolatePositionAndAltitude(currentSituation, interpolateGndFlag); currentSituation = interpolant.interpolatePositionAndAltitude(currentSituation, interpolateGndFlag);
if (currentSituation.isNull()) { break; }
if (CBuildConfig::isLocalDeveloperDebugBuild()) if (CBuildConfig::isLocalDeveloperDebugBuild())
{ {
Q_ASSERT_X(currentSituation.isValidVectorRange(), Q_FUNC_INFO, "Invalid interpolation situation"); Q_ASSERT_X(currentSituation.isValidVectorRange(), Q_FUNC_INFO, "Invalid interpolation situation");
@@ -235,35 +239,62 @@ namespace BlackMisc
currentSituation.setPitch(correctedPitchOnGround); currentSituation.setPitch(correctedPitchOnGround);
} }
} }
isValidInterpolation = true;
} }
else while (false);
const bool valid = isValidInterpolant && isValidInterpolation;
if (!valid)
{ {
// further handling could go here, mainly we continue with last situation
m_invalidSituations++; m_invalidSituations++;
// further handling could go here, mainly we continue with last situation // avoid flooding of log.
const bool noSituation = currentSituation.isNull(); if (m_currentTimeMsSinceEpoch - m_lastInvalidLogTs > m_lastSituation.getTimeOffsetMs())
const qint64 diff = noSituation ? -1 : m_currentTimeMsSinceEpoch - currentSituation.getAdjustedMSecsSinceEpoch();
const qint64 thresholdMs = noSituation ? qRound(CFsdSetup::c_interimPositionTimeOffsetMsec * 0.5) : qRound(currentSituation.getTimeOffsetMs() * 0.5);
const bool threshold = diff > thresholdMs;
if (noSituation || threshold)
{ {
m_lastInvalidLogTs = m_currentTimeMsSinceEpoch;
const bool noSituation = m_lastSituation.isNull();
// Problem 1, we have no "last situation" // Problem 1, we have no "last situation"
// Problem 2, "it takes too long to recover" // Problem 2, "it takes too long to recover"
CStatusMessage m;
if (noSituation) if (noSituation)
{ {
CLogMessage(this).warning("No situation no %1 for interpolation reported for '%2'") << m_invalidSituations << m_callsign.asString(); m = CStatusMessage(this).warning("No situation #%1 for interpolation reported for '%2' (Interpolant: %3 interpolation: %4)") <<
m_invalidSituations << m_callsign.asString() << boolToTrueFalse(isValidInterpolant) << boolToTrueFalse(isValidInterpolation);
} }
else else
{ {
CLogMessage(this).warning("Invalid situation, diff %1ms no %2 for interpolation reported for '%3'") << diff << m_invalidSituations << m_callsign.asString(); const qint64 diff = noSituation ? -1 : m_currentTimeMsSinceEpoch - currentSituation.getAdjustedMSecsSinceEpoch();
m = CStatusMessage(this).warning("Invalid situation, diff. %1ms #%2 for interpolation reported for '%3' (Interpolant: %4 interpolation: %5)") <<
diff << m_invalidSituations << m_callsign.asString() << boolToTrueFalse(isValidInterpolant) << boolToTrueFalse(isValidInterpolation);
}
if (!m.isEmpty())
{
if (m_interpolationMessages.isEmpty())
{
// display first message as a hint in the general log
CLogMessage::preformatted(m);
}
m_interpolationMessages.push_back(m);
} }
} }
}// valid? }// valid?
// status // situation and status
Q_ASSERT_X(currentSituation.hasMSLGeodeticHeight(), Q_FUNC_INFO, "No MSL altitude"); if (valid)
m_currentInterpolationStatus.setInterpolatedAndCheckSituation(isValid, currentSituation); {
m_lastSituation = currentSituation; Q_ASSERT_X(currentSituation.hasMSLGeodeticHeight(), Q_FUNC_INFO, "No MSL altitude");
m_lastSituation = currentSituation;
m_currentInterpolationStatus.setInterpolatedAndCheckSituation(valid, currentSituation);
}
else
{
currentSituation = m_lastSituation;
m_currentInterpolationStatus.setSameSituation(true);
m_currentInterpolationStatus.setInterpolatedAndCheckSituation(valid, currentSituation);
}
// logging // logging
if (this->doLogging()) if (this->doLogging())
@@ -332,33 +363,36 @@ namespace BlackMisc
if (!doGuess && !doInterpolation) if (!doGuess && !doInterpolation)
{ {
m_currentPartsStatus = m_lastPartsStatus; // reuse
m_currentPartsStatus.setReusedParts(true); return this->logAndReturnNullParts("neither guess nor interpolation", true);
return m_lastParts;
} }
CAircraftParts parts; CAircraftParts parts = CAircraftParts::null();
if (m_currentSetup.isAircraftPartsEnabled()) if (m_currentSetup.isAircraftPartsEnabled())
{ {
// this already logs // this already logs and sets status
parts = this->getInterpolatedParts(); parts = this->getInterpolatedParts();
} }
// if we have supported parts, we skip this step, but it can happen // if we have supported parts, we skip this step, but it can happen the parts are still empty
// the parts are still empty
if (!m_currentPartsStatus.isSupportingParts()) if (!m_currentPartsStatus.isSupportingParts())
{ {
if (!doGuess) if (!doGuess)
{ {
m_currentPartsStatus = m_lastPartsStatus; return this->logAndReturnNullParts("not supporting parts, and marked for guessing", true);
m_currentPartsStatus.setReusedParts(true);
return m_lastParts;
} }
// check if model has been thru model matching // check if model has been thru model matching
Q_ASSERT_X(!m_lastSituation.isNull(), Q_FUNC_INFO, "null situations"); if (!m_lastSituation.isNull())
parts.guessParts(m_lastSituation, m_pastSituationsChange, m_model); {
this->logParts(parts, 0, false); parts.guessParts(m_lastSituation, m_pastSituationsChange, m_model);
this->logParts(parts, 0, false);
}
else
{
// quite normal initial situation, just return NULL
return this->logAndReturnNullParts("guessing, but no situation yet", false);
}
} }
m_lastParts = parts; m_lastParts = parts;
@@ -366,6 +400,27 @@ namespace BlackMisc
return parts; return parts;
} }
template<typename Derived>
const CAircraftParts &CInterpolator<Derived>::logAndReturnNullParts(const QString &info, bool log)
{
if (!m_lastParts.isNull())
{
m_currentPartsStatus = m_lastPartsStatus;
m_currentPartsStatus.setReusedParts(true);
return m_lastParts;
}
if (log)
{
const CStatusMessage m = CStatusMessage(this).warning("NULL parts reported for '%1', '%2')") << m_callsign.asString() << info;
if (m_interpolationMessages.isEmpty()) { CLogMessage::preformatted(m); }
m_interpolationMessages.push_back(m);
}
m_currentPartsStatus.reset();
return CAircraftParts::null();
}
template<typename Derived> template<typename Derived>
bool CInterpolator<Derived>::doLogging() const bool CInterpolator<Derived>::doLogging() const
{ {
@@ -418,6 +473,9 @@ namespace BlackMisc
m_currentInterpolationStatus.reset(); m_currentInterpolationStatus.reset();
m_currentPartsStatus.reset(); m_currentPartsStatus.reset();
m_interpolatedSituationsCounter = 0; m_interpolatedSituationsCounter = 0;
m_invalidSituations = 0;
m_lastInvalidLogTs = -1;
m_interpolationMessages.clear();
} }
template<typename Derived> template<typename Derived>
@@ -564,6 +622,7 @@ namespace BlackMisc
void CInterpolationStatus::checkIfValidSituation(const CAircraftSituation &situation) void CInterpolationStatus::checkIfValidSituation(const CAircraftSituation &situation)
{ {
m_isValidSituation = !situation.isPositionOrAltitudeNull(); m_isValidSituation = !situation.isPositionOrAltitudeNull();
if (!m_isValidSituation) { m_isValidSituation = false; }
} }
bool CInterpolationStatus::hasValidInterpolatedSituation() const bool CInterpolationStatus::hasValidInterpolatedSituation() const

View File

@@ -22,6 +22,7 @@
#include "blackmisc/aviation/aircraftpartslist.h" #include "blackmisc/aviation/aircraftpartslist.h"
#include "blackmisc/aviation/callsign.h" #include "blackmisc/aviation/callsign.h"
#include "blackmisc/logcategorylist.h" #include "blackmisc/logcategorylist.h"
#include "blackmisc/statusmessagelist.h"
#include <QObject> #include <QObject>
#include <QString> #include <QString>
@@ -233,6 +234,12 @@ namespace BlackMisc
//! Get count of invalid situations //! Get count of invalid situations
int getInvalidSituationsCount() const { return m_invalidSituations; } int getInvalidSituationsCount() const { return m_invalidSituations; }
//! Interpolation messages
const CStatusMessageList &getInterpolationMessages() const { return m_interpolationMessages; }
//! Do we have interpolation messages
bool hasInterpolationMessages() const { return !m_interpolationMessages.isEmpty(); }
protected: protected:
//! Constructor //! Constructor
CInterpolator(const Aviation::CCallsign &callsign, CInterpolator(const Aviation::CCallsign &callsign,
@@ -281,6 +288,9 @@ namespace BlackMisc
int m_partsToSituationInterpolationRatio = 2; //!< ratio between parts and situation interpolation, 1..always, 2..every 2nd situation int m_partsToSituationInterpolationRatio = 2; //!< ratio between parts and situation interpolation, 1..always, 2..every 2nd situation
int m_partsToSituationGuessingRatio = 5; //!< ratio between parts guessing and situation interpolation int m_partsToSituationGuessingRatio = 5; //!< ratio between parts guessing and situation interpolation
int m_invalidSituations = 0; //!< mainly when there are no new situations int m_invalidSituations = 0; //!< mainly when there are no new situations
qint64 m_lastInvalidLogTs = -1; //!< last invalid situation timestamp
CStatusMessageList m_interpolationMessages; //!< interpolation messages
Aviation::CAircraftSituation m_lastSituation { Aviation::CAircraftSituation::null() }; //!< latest interpolation Aviation::CAircraftSituation m_lastSituation { Aviation::CAircraftSituation::null() }; //!< latest interpolation
Aviation::CAircraftParts m_lastParts { Aviation::CAircraftParts::null() }; //!< latest parts Aviation::CAircraftParts m_lastParts { Aviation::CAircraftParts::null() }; //!< latest parts
PhysicalQuantities::CLength m_currentSceneryOffset { PhysicalQuantities::CLength::null() }; //!< calculated scenery offset if any PhysicalQuantities::CLength m_currentSceneryOffset { PhysicalQuantities::CLength::null() }; //!< calculated scenery offset if any
@@ -312,8 +322,13 @@ namespace BlackMisc
//! Deferred init //! Deferred init
void deferredInit(); void deferredInit();
//! Return NULL parts and log
const BlackMisc::Aviation::CAircraftParts &logAndReturnNullParts(const QString &info, bool log);
//! Derived class @{
Derived *derived() { return static_cast<Derived *>(this); } Derived *derived() { return static_cast<Derived *>(this); }
const Derived *derived() const { return static_cast<const Derived *>(this); } const Derived *derived() const { return static_cast<const Derived *>(this); }
//! @}
}; };
//! \cond PRIVATE //! \cond PRIVATE

View File

@@ -57,6 +57,18 @@ namespace BlackMisc
m_spline.initCorrespondingModel(model); m_spline.initCorrespondingModel(model);
} }
const CStatusMessageList &CInterpolatorMulti::getInterpolationMessages(CInterpolationAndRenderingSetupBase::InterpolatorMode mode) const
{
switch (mode)
{
case CInterpolationAndRenderingSetupBase::Spline: return m_spline.getInterpolationMessages();
case CInterpolationAndRenderingSetupBase::Linear: return m_linear.getInterpolationMessages();
default: break;
}
static const CStatusMessageList empty;
return empty;
}
QString CInterpolatorMulti::getInterpolatorInfo(CInterpolationAndRenderingSetupBase::InterpolatorMode mode) const QString CInterpolatorMulti::getInterpolatorInfo(CInterpolationAndRenderingSetupBase::InterpolatorMode mode) const
{ {
switch (mode) switch (mode)

View File

@@ -14,6 +14,7 @@
#include "blackmisc/simulation/interpolatorlinear.h" #include "blackmisc/simulation/interpolatorlinear.h"
#include "blackmisc/simulation/interpolatorspline.h" #include "blackmisc/simulation/interpolatorspline.h"
#include "blackmisc/statusmessagelist.h"
namespace BlackMisc namespace BlackMisc
{ {
@@ -34,6 +35,9 @@ namespace BlackMisc
//! \copydoc CInterpolator::getLastInterpolatedSituation //! \copydoc CInterpolator::getLastInterpolatedSituation
const Aviation::CAircraftSituation &getLastInterpolatedSituation(CInterpolationAndRenderingSetupBase::InterpolatorMode mode) const; const Aviation::CAircraftSituation &getLastInterpolatedSituation(CInterpolationAndRenderingSetupBase::InterpolatorMode mode) const;
//! \copydoc CInterpolator::getInterpolationMessages
const CStatusMessageList &getInterpolationMessages(CInterpolationAndRenderingSetupBase::InterpolatorMode mode) const;
//! \copydoc CInterpolator::attachLogger //! \copydoc CInterpolator::attachLogger
void attachLogger(CInterpolationLogger *logger); void attachLogger(CInterpolationLogger *logger);

View File

@@ -312,31 +312,38 @@ namespace BlackMisc
const double t1 = m_pa.t[1]; const double t1 = m_pa.t[1];
const double t2 = m_pa.t[2]; // latest (adjusted) const double t2 = m_pa.t[2]; // latest (adjusted)
if (CBuildConfig::isLocalDeveloperDebugBuild()) bool valid = (t1 < t2) && (m_currentTimeMsSinceEpoc >= t1) && (m_currentTimeMsSinceEpoc < t2);
if (!valid && CBuildConfig::isLocalDeveloperDebugBuild())
{ {
Q_ASSERT_X(t1 < t2, Q_FUNC_INFO, "Expect sorted times, latest first"); Q_ASSERT_X(t1 < t2, Q_FUNC_INFO, "Expect sorted times, latest first"); // that means a bug in our code init the values
Q_ASSERT_X(m_currentTimeMsSinceEpoc >= t1, Q_FUNC_INFO, "invalid timestamp t1"); BLACK_VERIFY_X(m_currentTimeMsSinceEpoc >= t1, Q_FUNC_INFO, "invalid timestamp t1");
Q_ASSERT_X(m_currentTimeMsSinceEpoc < t2, Q_FUNC_INFO, "invalid timestamp t2"); // t1==t2 results in div/0 BLACK_VERIFY_X(m_currentTimeMsSinceEpoc < t2, Q_FUNC_INFO, "invalid timestamp t2"); // t1==t2 results in div/0
} }
if (!valid) { return CAircraftSituation::null(); }
const double newX = evalSplineInterval(m_currentTimeMsSinceEpoc, t1, t2, m_pa.x[1], m_pa.x[2], m_pa.dx[1], m_pa.dx[2]); const double newX = evalSplineInterval(m_currentTimeMsSinceEpoc, t1, t2, m_pa.x[1], m_pa.x[2], m_pa.dx[1], m_pa.dx[2]);
const double newY = evalSplineInterval(m_currentTimeMsSinceEpoc, t1, t2, m_pa.y[1], m_pa.y[2], m_pa.dy[1], m_pa.dy[2]); const double newY = evalSplineInterval(m_currentTimeMsSinceEpoc, t1, t2, m_pa.y[1], m_pa.y[2], m_pa.dy[1], m_pa.dy[2]);
const double newZ = evalSplineInterval(m_currentTimeMsSinceEpoc, t1, t2, m_pa.z[1], m_pa.z[2], m_pa.dz[1], m_pa.dz[2]); const double newZ = evalSplineInterval(m_currentTimeMsSinceEpoc, t1, t2, m_pa.z[1], m_pa.z[2], m_pa.dz[1], m_pa.dz[2]);
if (CBuildConfig::isLocalDeveloperDebugBuild()) valid = CAircraftSituation::isValidVector(m_pa.x) && CAircraftSituation::isValidVector(m_pa.y) && CAircraftSituation::isValidVector(m_pa.z);
if (!valid && CBuildConfig::isLocalDeveloperDebugBuild())
{ {
BLACK_VERIFY_X(CAircraftSituation::isValidVector(m_pa.x), Q_FUNC_INFO, "invalid X"); // all x values BLACK_VERIFY_X(CAircraftSituation::isValidVector(m_pa.x), Q_FUNC_INFO, "invalid X"); // all x values
BLACK_VERIFY_X(CAircraftSituation::isValidVector(m_pa.y), Q_FUNC_INFO, "invalid Y"); // all y values BLACK_VERIFY_X(CAircraftSituation::isValidVector(m_pa.y), Q_FUNC_INFO, "invalid Y"); // all y values
BLACK_VERIFY_X(CAircraftSituation::isValidVector(m_pa.z), Q_FUNC_INFO, "invalid Z"); // all z values BLACK_VERIFY_X(CAircraftSituation::isValidVector(m_pa.z), Q_FUNC_INFO, "invalid Z"); // all z values
} }
if (!valid) { return CAircraftSituation::null(); }
CAircraftSituation newSituation(currentSituation); CAircraftSituation newSituation(currentSituation);
const std::array<double, 3> normalVector = {{ newX, newY, newZ }}; const std::array<double, 3> normalVector = {{ newX, newY, newZ }};
const CCoordinateGeodetic currentPosition(normalVector); const CCoordinateGeodetic currentPosition(normalVector);
if (CBuildConfig::isLocalDeveloperDebugBuild())
valid = CAircraftSituation::isValidVector(normalVector);
if (!valid && CBuildConfig::isLocalDeveloperDebugBuild())
{ {
BLACK_VERIFY_X(CAircraftSituation::isValidVector(normalVector), Q_FUNC_INFO, "invalid vector"); BLACK_VERIFY_X(valid, Q_FUNC_INFO, "invalid vector");
} }
if (!valid) { return CAircraftSituation::null(); }
const double newA = evalSplineInterval(m_currentTimeMsSinceEpoc, t1, t2, m_pa.a[1], m_pa.a[2], m_pa.da[1], m_pa.da[2]); const double newA = evalSplineInterval(m_currentTimeMsSinceEpoc, t1, t2, m_pa.a[1], m_pa.a[2], m_pa.da[1], m_pa.da[2]);
const CAltitude alt(newA, m_altitudeUnit); const CAltitude alt(newA, m_altitudeUnit);

View File

@@ -1737,8 +1737,9 @@ namespace BlackSimPlugin
{ {
SIMCONNECT_DATA_INITPOSITION position = this->aircraftSituationToFsxPosition(result, sendGround); SIMCONNECT_DATA_INITPOSITION position = this->aircraftSituationToFsxPosition(result, sendGround);
const HRESULT hr = this->logAndTraceSendId( const HRESULT hr = this->logAndTraceSendId(
SimConnect_SetDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSetPosition, SimConnect_SetDataOnSimObject(
static_cast<SIMCONNECT_OBJECT_ID>(objectId), 0, 0, sizeof(SIMCONNECT_DATA_INITPOSITION), &position), m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSetPosition,
static_cast<SIMCONNECT_OBJECT_ID>(objectId), 0, 0, sizeof(SIMCONNECT_DATA_INITPOSITION), &position),
traceSendId, simObject, "Failed to set position", Q_FUNC_INFO, "SimConnect_SetDataOnSimObject"); traceSendId, simObject, "Failed to set position", Q_FUNC_INFO, "SimConnect_SetDataOnSimObject");
if (isOk(hr)) if (isOk(hr))
{ {
@@ -1749,10 +1750,15 @@ namespace BlackSimPlugin
} }
else else
{ {
// already logged in interpolator
continue;
/**
static const QString so("SimObject id: %1"); static const QString so("SimObject id: %1");
const QString msg = this->getInvalidSituationLogMessage(callsign, result.getInterpolationStatus(), so.arg(objectId)); const QString msg = this->getInvalidSituationLogMessage(callsign, result.getInterpolationStatus(), so.arg(objectId));
const CStatusMessage sm(this, CStatusMessage::SeverityWarning, msg); const CStatusMessage sm(this, CStatusMessage::SeverityWarning, msg);
this->clampedLog(callsign, sm); this->clampedLog(callsign, sm);
**/
} }
// Interpolated parts // Interpolated parts
@@ -1769,6 +1775,7 @@ namespace BlackSimPlugin
if (!simObject.hasValidRequestAndObjectId()) { return false; } if (!simObject.hasValidRequestAndObjectId()) { return false; }
const CAircraftParts parts = result; const CAircraftParts parts = result;
if (parts.isNull()) { return false; }
if (parts.getPartsDetails() != CAircraftParts::GuessedParts && !result.getPartsStatus().isSupportingParts()) { return false; } if (parts.getPartsDetails() != CAircraftParts::GuessedParts && !result.getPartsStatus().isSupportingParts()) { return false; }
if (result.getPartsStatus().isReusedParts() || this->isEqualLastSent(parts, simObject.getCallsign())) { return true; } if (result.getPartsStatus().isReusedParts() || this->isEqualLastSent(parts, simObject.getCallsign())) { return true; }