From 0a06ad223fc1daab86c325c64d0123e4329cd90d Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Sun, 28 Jan 2018 05:17:47 +0100 Subject: [PATCH] Ref T231, Ref T236, Ref T238 improvements of interpolator * keep last interpolated sitation, removed m_isFirstInterpolation * allow to obtain the old/new situation * transfer of elevations to newer situations --- .../aviation/aircraftsituationlist.cpp | 4 +- .../aviation/aircraftsituationlist.h | 2 +- src/blackmisc/simulation/interpolator.cpp | 59 ++++++++++--------- src/blackmisc/simulation/interpolator.h | 6 +- .../simulation/interpolatorlinear.cpp | 18 +++--- src/blackmisc/simulation/interpolatorlinear.h | 8 ++- .../simulation/interpolatorspline.cpp | 16 +++-- src/blackmisc/simulation/interpolatorspline.h | 6 ++ 8 files changed, 67 insertions(+), 52 deletions(-) diff --git a/src/blackmisc/aviation/aircraftsituationlist.cpp b/src/blackmisc/aviation/aircraftsituationlist.cpp index 58477cc99..20bc90b0c 100644 --- a/src/blackmisc/aviation/aircraftsituationlist.cpp +++ b/src/blackmisc/aviation/aircraftsituationlist.cpp @@ -43,13 +43,13 @@ namespace BlackMisc return c; } - int CAircraftSituationList::setGroundElevationChecked(const CElevationPlane &elevationPlane, qint64 newerThan, bool ignoreNullValues, bool overrideExisting) + int CAircraftSituationList::setGroundElevationChecked(const CElevationPlane &elevationPlane, qint64 newerThanAdjustedMs, bool ignoreNullValues, bool overrideExisting) { if (ignoreNullValues && elevationPlane.isNull()) { return 0; } int c = 0; for (CAircraftSituation &s : *this) { - if (s.getMSecsSinceEpoch() <= newerThan) { continue; } + if (s.getAdjustedMSecsSinceEpoch() <= newerThanAdjustedMs) { continue; } const bool set = s.setGroundElevationChecked(elevationPlane, ignoreNullValues, overrideExisting); if (set) { c++; } } diff --git a/src/blackmisc/aviation/aircraftsituationlist.h b/src/blackmisc/aviation/aircraftsituationlist.h index 4aa136f8b..4ef7ec834 100644 --- a/src/blackmisc/aviation/aircraftsituationlist.h +++ b/src/blackmisc/aviation/aircraftsituationlist.h @@ -53,7 +53,7 @@ namespace BlackMisc int setGroundElevationChecked(const Geo::CElevationPlane &elevationPlane, bool ignoreNullValues = true, bool overrideExisting = true); //! Set ground elevation from elevation plane - int setGroundElevationChecked(const Geo::CElevationPlane &elevationPlane, qint64 newerThan, bool ignoreNullValues = true, bool overrideExisting = true); + int setGroundElevationChecked(const Geo::CElevationPlane &elevationPlane, qint64 newerThanAdjustedMs, bool ignoreNullValues = true, bool overrideExisting = true); }; } // namespace } // namespace diff --git a/src/blackmisc/simulation/interpolator.cpp b/src/blackmisc/simulation/interpolator.cpp index ef9bb069c..75f9ec386 100644 --- a/src/blackmisc/simulation/interpolator.cpp +++ b/src/blackmisc/simulation/interpolator.cpp @@ -57,23 +57,25 @@ namespace BlackMisc const CInterpolationAndRenderingSetup &setup, const CInterpolationHints &hints, CInterpolationStatus &status) { + // this code is used by linear and spline interpolator status.reset(); CInterpolationLogger::SituationLog log; // any data at all? if (m_aircraftSituations.isEmpty()) { return {}; } - CAircraftSituation currentSituation = m_aircraftSituations.front(); + CAircraftSituation currentSituation = m_lastInterpolation.isNull() ? m_aircraftSituations.front() : m_lastInterpolation; // Update current position by hints' elevation // * for XP provided by hints.getElevationProvider at current position // * for FSX/P3D provided as hints.getElevation which is set to current position of remote aircraft in simulator // * As XP uses lazy init we will call getGroundElevation only when needed // * default here via getElevationPlane - CAltitude currentGroundElevation(hints.getGroundElevation(currentSituation, false, false)); - currentSituation.setGroundElevationChecked(currentGroundElevation); // set as default + CAltitude currentGroundElevation(hints.getGroundElevation(currentSituation, currentSituation.getDistancePerTime(1000), false, false)); + currentSituation.setGroundElevation(currentGroundElevation); // set as default // data, split situations by time if (currentTimeMsSinceEpoc < 0) { currentTimeMsSinceEpoc = QDateTime::currentMSecsSinceEpoch(); } + currentSituation.setMSecsSinceEpoch(currentTimeMsSinceEpoc); // interpolant function from derived class // CInterpolatorLinear::Interpolant or CInterpolatorSpline::Interpolant @@ -90,7 +92,7 @@ namespace BlackMisc currentSituation.setPosition(interpolant.interpolatePosition(setup, hints)); currentSituation.setAltitude(interpolant.interpolateAltitude(setup, hints)); - // PBH before ground so we can use PBH + // PBH before ground so we can use PBH in guessing ground if (setup.isForcingFullInterpolation() || hints.isVtolAircraft() || status.isInterpolated()) { const auto pbh = interpolant.pbh(); @@ -100,16 +102,17 @@ namespace BlackMisc currentSituation.setGroundSpeed(pbh.getGroundSpeed()); status.setInterpolatedAndCheckSituation(true, currentSituation); } - m_isFirstInterpolation = false; // Interpolate between altitude and ground elevation, with proportions weighted according to interpolated onGround flag + constexpr double NoGroundFactor = -1; + double groundFactor = NoGroundFactor; + if (hints.hasAircraftParts()) { - const double groundFactor = hints.getAircraftParts().isOnGroundInterpolated(); - log.groundFactor = groundFactor; + groundFactor = hints.getAircraftParts().isOnGroundInterpolated(); if (groundFactor > 0.0) { - // if not having an ground elevation yet, we fetch from provider + // if not having an ground elevation yet, we fetch from provider (if there is a provider) if (!currentGroundElevation.isNull()) { currentGroundElevation = hints.getGroundElevation(currentSituation, true); // "expensive on XPlane" if provider is called @@ -129,23 +132,10 @@ namespace BlackMisc } } } - else - { - // guess ground flag - constexpr double NoGroundFactor = -1; - CInterpolator::setGroundFlagFromInterpolator(hints, NoGroundFactor, currentSituation); - } - if (m_logger && hints.isLoggingInterpolation()) - { - log.timestamp = currentTimeMsSinceEpoc; - log.callsign = m_callsign; - log.groundFactor = groundFactor; - log.situationCurrent = currentSituation; - log.usedHints = hints; - log.usedSetup = setup; - m_logger->logInterpolation(log); - } + // depending on ground factor set ground flag and reliability + // it will use the hints ground flag or elevation/CG or guessing + CInterpolator::setGroundFlagFromInterpolator(hints, groundFactor, currentSituation); // we transfer ground elevation for future usage if (currentSituation.hasGroundElevation()) @@ -154,11 +144,23 @@ namespace BlackMisc ep.setSinglePointRadius(); // transfer to newer situations - const int transfered = m_aircraftSituations.setGroundElevationChecked(ep, currentSituation.getMSecsSinceEpoch()); - Q_UNUSED(transfered); // for debugging + log.noTransferredElevations = m_aircraftSituations.setGroundElevationChecked(ep, currentTimeMsSinceEpoc); + } + + // logging + if (m_logger && hints.isLoggingInterpolation()) + { + log.tsCurrent = currentTimeMsSinceEpoc; + log.callsign = m_callsign; + log.groundFactor = groundFactor; + log.situationCurrent = currentSituation; + log.usedHints = hints; + log.usedSetup = setup; + m_logger->logInterpolation(log); } // bye + m_lastInterpolation = currentSituation; return currentSituation; } @@ -214,6 +216,7 @@ namespace BlackMisc CAircraftParts CInterpolator::getInterpolatedParts(qint64 currentTimeMsSinceEpoch, const CInterpolationAndRenderingSetup &setup, CPartsStatus &partsStatus, bool log) const { + // this code is used by linear and spline interpolator Q_UNUSED(setup); partsStatus.reset(); if (currentTimeMsSinceEpoch < 0) { currentTimeMsSinceEpoch = QDateTime::currentMSecsSinceEpoch(); } @@ -284,7 +287,7 @@ namespace BlackMisc if (!log || !m_logger) { return; } CInterpolationLogger::PartsLog logInfo; logInfo.callsign = m_callsign; - logInfo.timestamp = timestamp; + logInfo.tsCurrent = timestamp; logInfo.parts = parts; logInfo.empty = empty; m_logger->logParts(logInfo); @@ -331,7 +334,7 @@ namespace BlackMisc QStringLiteral(" parts: ") % QString::number(m_aircraftParts.size()) % QStringLiteral(" 1st interpolation: ") % - boolToYesNo(m_isFirstInterpolation); + boolToYesNo(m_lastInterpolation.isNull()); } template diff --git a/src/blackmisc/simulation/interpolator.h b/src/blackmisc/simulation/interpolator.h index 95892edf4..e49459910 100644 --- a/src/blackmisc/simulation/interpolator.h +++ b/src/blackmisc/simulation/interpolator.h @@ -86,7 +86,7 @@ namespace BlackMisc Aviation::CAircraftSituationList m_aircraftSituations; //!< recent situations for one aircraft Aviation::CAircraftPartsList m_aircraftParts; //!< recent parts for one aircraft Aviation::CCallsign m_callsign; //!< callsign - bool m_isFirstInterpolation = true; //!< set to false after the first successful interpolation + Aviation::CAircraftSituation m_lastInterpolation; //!< last interpolation //! Constructor CInterpolator(const QString &objectName, const Aviation::CCallsign &callsign, QObject *parent); @@ -129,8 +129,8 @@ namespace BlackMisc PhysicalQuantities::CAngle getPitch() const; PhysicalQuantities::CAngle getBank() const; PhysicalQuantities::CSpeed getGroundSpeed() const; - Aviation::CAircraftSituation getOldSituation() const { return m_oldSituation; } - Aviation::CAircraftSituation getNewSituation() const { return m_newSituation; } + const Aviation::CAircraftSituation &getOldSituation() const { return m_oldSituation; } + const Aviation::CAircraftSituation &getNewSituation() const { return m_newSituation; } //! @} //! Change time fraction diff --git a/src/blackmisc/simulation/interpolatorlinear.cpp b/src/blackmisc/simulation/interpolatorlinear.cpp index 42b7047dc..56673fe04 100644 --- a/src/blackmisc/simulation/interpolatorlinear.cpp +++ b/src/blackmisc/simulation/interpolatorlinear.cpp @@ -119,27 +119,29 @@ namespace BlackMisc CAircraftSituation currentSituation(oldSituation); // also sets ground elevation if available // Time between start and end packet - const double deltaTimeMs = newSituation.getAdjustedMSecsSinceEpoch() - oldSituation.getAdjustedMSecsSinceEpoch(); - Q_ASSERT_X(deltaTimeMs >= 0, Q_FUNC_INFO, "Negative delta time"); + const double sampleDeltaTimeMs = newSituation.getAdjustedMSecsSinceEpoch() - oldSituation.getAdjustedMSecsSinceEpoch(); + Q_ASSERT_X(sampleDeltaTimeMs >= 0, Q_FUNC_INFO, "Negative delta time"); log.interpolator = 'l'; - log.deltaTimeMs = deltaTimeMs; + log.tsCurrent = currentTimeMsSinceEpoc; + log.deltaSampleTimesMs = sampleDeltaTimeMs; // Fraction of the deltaTime, ideally [0.0 - 1.0] // < 0 should not happen due to the split, > 1 can happen if new values are delayed beyond split time // 1) values > 1 mean extrapolation // 2) values > 2 mean no new situations coming in const double distanceToSplitTimeMs = newSituation.getAdjustedMSecsSinceEpoch() - currentTimeMsSinceEpoc; - const double simulationTimeFraction = 1.0 - (distanceToSplitTimeMs / deltaTimeMs); - const double deltaTimeFractionMs = deltaTimeMs * simulationTimeFraction; + const double simulationTimeFraction = qMax(1.0 - (distanceToSplitTimeMs / sampleDeltaTimeMs), 0.0); + const double deltaTimeFractionMs = sampleDeltaTimeMs * simulationTimeFraction; log.simulationTimeFraction = simulationTimeFraction; - log.deltaTimeFractionMs = deltaTimeFractionMs; + log.deltaSampleTimesMs = sampleDeltaTimeMs; currentSituation.setTimeOffsetMs(oldSituation.getTimeOffsetMs() + (newSituation.getTimeOffsetMs() - oldSituation.getTimeOffsetMs()) * simulationTimeFraction); currentSituation.setMSecsSinceEpoch(oldSituation.getMSecsSinceEpoch() + deltaTimeFractionMs); status.setInterpolatedAndCheckSituation(true, currentSituation); + log.tsInterpolated = currentSituation.getAdjustedMSecsSinceEpoch(); - log.oldSituation = oldSituation; - log.newSituation = newSituation; + log.situationOld = oldSituation; + log.situationNew = newSituation; return { oldSituation, newSituation, simulationTimeFraction }; } diff --git a/src/blackmisc/simulation/interpolatorlinear.h b/src/blackmisc/simulation/interpolatorlinear.h index 32ae5b0d7..f33b3b12d 100644 --- a/src/blackmisc/simulation/interpolatorlinear.h +++ b/src/blackmisc/simulation/interpolatorlinear.h @@ -56,11 +56,17 @@ namespace BlackMisc //! Interpolator for pitch, bank, heading, groundspeed const CInterpolatorPbh &pbh() const { return m_pbh; } + //! Old situation + const Aviation::CAircraftSituation &getOldSituation() const { return m_oldSituation; } + + //! New situation + const Aviation::CAircraftSituation &getNewSituation() const { return m_newSituation; } + private: int m_situationsAvailable = 0; Aviation::CAircraftSituation m_oldSituation; Aviation::CAircraftSituation m_newSituation; - double m_simulationTimeFraction = 0.0; + double m_simulationTimeFraction = 0.0; //!< 0..1 const CInterpolatorPbh m_pbh; }; diff --git a/src/blackmisc/simulation/interpolatorspline.cpp b/src/blackmisc/simulation/interpolatorspline.cpp index 1aa957b47..130de59a8 100644 --- a/src/blackmisc/simulation/interpolatorspline.cpp +++ b/src/blackmisc/simulation/interpolatorspline.cpp @@ -129,12 +129,10 @@ namespace BlackMisc // - flying the ground elevation not really matters if (!hints.getElevationPlane().isNull()) { - const CAltitude groundElevation = hints.getElevationPlane().getAltitude(); - // do not override existing values - s[0].setGroundElevationChecked(groundElevation); - s[1].setGroundElevationChecked(groundElevation); - s[2].setGroundElevationChecked(groundElevation); + s[0].setGroundElevationChecked(hints.getElevationPlane()); + s[1].setGroundElevationChecked(hints.getElevationPlane()); + s[2].setGroundElevationChecked(hints.getElevationPlane()); } const double a0 = s[0].getCorrectedAltitude(hints.getCGAboveGround()).value(); @@ -163,11 +161,11 @@ namespace BlackMisc const double dt2 = static_cast(m_nextSampleTime - m_prevSampleTime); const double timeFraction = dt1 / dt2; log.interpolator = 's'; - log.oldSituation = m_interpolant.pbh().getOldSituation(); - log.newSituation = m_interpolant.pbh().getNewSituation(); - log.deltaTimeMs = dt1; - log.deltaTimeFractionMs = dt2; + log.situationOld = m_interpolant.pbh().getOldSituation(); + log.situationNew = m_interpolant.pbh().getNewSituation(); + log.deltaSampleTimesMs = dt2; log.simulationTimeFraction = timeFraction; + log.tsInterpolated = log.situationNew.getMSecsSinceEpoch(); // without offset status.setInterpolated(true); m_interpolant.setTimes(currentTimeMsSinceEpoc, timeFraction); diff --git a/src/blackmisc/simulation/interpolatorspline.h b/src/blackmisc/simulation/interpolatorspline.h index 6c4f422cd..c2c545b84 100644 --- a/src/blackmisc/simulation/interpolatorspline.h +++ b/src/blackmisc/simulation/interpolatorspline.h @@ -70,6 +70,12 @@ namespace BlackMisc //! Interpolator for pitch, bank, heading, groundspeed const CInterpolatorPbh &pbh() const { return m_pbh; } + //! Old situation + const Aviation::CAircraftSituation &getOldSituation() const { return pbh().getOldSituation(); } + + //! New situation + const Aviation::CAircraftSituation &getNewSituation() const { return pbh().getNewSituation(); } + //! Set the time values void setTimes(qint64 currentTimeMs, double timeFraction);