Reflecting discussed changes for interpolation performance refs #386

(based on FSX testing)
* Only send changed situation to SIM
* Split sending of parts / situations
* Only send parts with a reduced frequency (means slower as positions)
* Mark geodetic height as null for default values (the value is usually unavailable)
* Fixed altitude to MSL for network data
* Trace which aircrafts support aircraft parts via network
* Renamed insert_fron push_front (as proposed by Roland)

Status quo / lessons learnt
* On slower PCs jitter is still noticed for interpolated aircraft.
* Running interpolation in an independent process (aka core, not in GUI) reduced load dependencies
  => it seems to make sense to run driver in own thread
* The onGround flag in parts seems clumsy as it required to retrieve parts for position updates
* In interpolation performance really matters
This commit is contained in:
Klaus Basan
2015-02-26 21:47:28 +01:00
parent ca6cd9c063
commit eca8c5b637
21 changed files with 376 additions and 320 deletions

View File

@@ -20,18 +20,31 @@ using namespace BlackMisc::Aviation;
namespace BlackCore
{
CAircraftSituation CInterpolatorLinear::getCurrentInterpolatedSituation(const QHash<CCallsign, CAircraftSituationList> &allSituations, const CCallsign &callsign, qint64 currentTimeMsSinceEpoc, bool *ok) const
CAircraftSituation CInterpolatorLinear::getInterpolatedSituation(const CCallsign &callsign, qint64 currentTimeMsSinceEpoc, InterpolationStatus &status, const CSituationsPerCallsign *situationsPerCallsign) const
{
const static CAircraftSituation empty;
if (ok) { *ok = false; }
if (!allSituations.contains(callsign)) { return empty; }
if (allSituations[callsign].isEmpty()) { return empty; }
status.reset();
QList<CAircraftSituationList> splitSituations;
if (currentTimeMsSinceEpoc < 0) { currentTimeMsSinceEpoc = QDateTime::currentMSecsSinceEpoch(); }
qint64 splitTimeMsSinceEpoch = currentTimeMsSinceEpoc - TimeOffsetMs;
QList<CAircraftSituationList> splitSituations = allSituations[callsign].splitByTime(splitTimeMsSinceEpoch);
CAircraftSituationList &situationsNewer = splitSituations[0]; // latest first
CAircraftSituationList &situationsOlder = splitSituations[1]; // latest first
if (situationsPerCallsign)
{
if (!situationsPerCallsign->contains(callsign)) { return empty; }
if ((*situationsPerCallsign)[callsign].isEmpty()) { return empty; }
splitSituations = (*situationsPerCallsign)[callsign].splitByTime(splitTimeMsSinceEpoch);
}
else
{
// only part where it is locked
QReadLocker lock(&m_lockSituations);
if (!m_situationsByCallsign.contains(callsign)) { return empty; }
if (m_situationsByCallsign[callsign].isEmpty()) { return empty; }
splitSituations = m_situationsByCallsign[callsign].splitByTime(splitTimeMsSinceEpoch);
}
CAircraftSituationList &situationsNewer = splitSituations[0]; // newer part
CAircraftSituationList &situationsOlder = splitSituations[1]; // older part
// interpolation situations
CAircraftSituation oldSituation;
@@ -52,7 +65,6 @@ namespace BlackCore
// We just place at he last position until we get before / after situations
if (situationsOlderNo < 1 || situationsNewerNo < 1)
{
if (ok) { *ok = true; }
// no after situations
if (situationsOlderNo < 1) { return situationsNewer.back(); } // oldest newest
@@ -73,6 +85,7 @@ namespace BlackCore
CAircraftSituation currentSituation(oldSituation);
CCoordinateGeodetic currentPosition;
status.interpolationSucceeded = true;
// Time between start and end packet
double deltaTime = oldSituation.absMsecsTo(newSituation);
@@ -82,7 +95,7 @@ namespace BlackCore
// 1) values > 1 mean extrapolation
// 2) values > 2 mean no new situations coming in
double simulationTimeFraction = 1 - ((newSituation.getMSecsSinceEpoch() - splitTimeMsSinceEpoch) / deltaTime);
if (simulationTimeFraction > 1.5)
if (simulationTimeFraction > 2.0)
{
if (this->m_withDebugMsg)
{
@@ -91,21 +104,34 @@ namespace BlackCore
}
// Interpolate latitude: Lat = (LatB - LatA) * t + LatA
currentPosition.setLatitude((newSituation.getPosition().latitude() - oldSituation.getPosition().latitude())
const CLatitude oldLat(oldSituation.latitude());
const CLatitude newLat(newSituation.latitude());
const CLongitude oldLng(oldSituation.longitude());
const CLongitude newLng(newSituation.longitude());
currentPosition.setLatitude((newLat - oldLat)
* simulationTimeFraction
+ oldSituation.getPosition().latitude());
+ oldLat);
// Interpolate latitude: Lon = (LonB - LonA) * t + LonA
currentPosition.setLongitude((newSituation.getPosition().longitude() - oldSituation.getPosition().longitude())
currentPosition.setLongitude((newLng - oldLng)
* simulationTimeFraction
+ oldSituation.getPosition().longitude());
+ oldLng);
currentSituation.setPosition(currentPosition);
// Interpolate altitude: Alt = (AltB - AltA) * t + AltA
currentSituation.setAltitude(CAltitude((newSituation.getAltitude() - oldSituation.getAltitude())
const CAltitude oldAlt(oldSituation.getAltitude());
const CAltitude newAlt(newSituation.getAltitude());
Q_ASSERT(oldAlt.getReferenceDatum() == newAlt.getReferenceDatum()); // otherwise no calculation is possible
currentSituation.setAltitude(CAltitude((newAlt - oldAlt)
* simulationTimeFraction
+ oldSituation.getAltitude(),
oldSituation.getAltitude().getReferenceDatum()));
+ oldAlt,
oldAlt.getReferenceDatum()));
if (newLat == oldLat && newLng == oldLng && oldAlt == newAlt)
{
return currentSituation;
}
// Interpolate heading: HDG = (HdgB - HdgA) * t + HdgA
CHeading headingBegin = oldSituation.getHeading();
@@ -143,13 +169,13 @@ namespace BlackCore
// TODO: According to the specification, banks to the right should be negative.
// But somehow we get positive banks from the network.
bank *= -1;
bank *= -1.0;
currentSituation.setBank(bank);
currentSituation.setGroundspeed((newSituation.getGroundSpeed() - oldSituation.getGroundSpeed())
* simulationTimeFraction
+ oldSituation.getGroundSpeed());
if (ok) { *ok = true; }
status.changedPosition = true;
Q_ASSERT(currentSituation.getCallsign() == callsign);
return currentSituation;
}