swift
testinterpolatorlinear.cpp
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (C) 2015 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
7 
8 #include <QCoreApplication>
9 #include <QDebug>
10 #include <QEventLoop>
11 #include <QScopedPointer>
12 #include <QTest>
13 #include <QTime>
14 #include <QtDebug>
15 
16 #include "test.h"
17 
23 #include "misc/aviation/altitude.h"
24 #include "misc/aviation/callsign.h"
25 #include "misc/aviation/heading.h"
27 #include "misc/geo/latitude.h"
28 #include "misc/geo/longitude.h"
30 #include "misc/pq/angle.h"
31 #include "misc/pq/length.h"
33 #include "misc/pq/speed.h"
34 #include "misc/pq/units.h"
38 
39 using namespace swift::misc;
40 using namespace swift::misc::aviation;
41 using namespace swift::misc::geo;
42 using namespace swift::misc::physical_quantities;
43 using namespace swift::misc::simulation;
44 
45 namespace MiscTest
46 {
48  class CTestInterpolatorLinear : public QObject
49  {
50  Q_OBJECT
51 
52  private slots:
54  void basicInterpolatorTests();
55 
56  private:
59  getTestSituation(const swift::misc::aviation::CCallsign &callsign, int number, qint64 ts, qint64 deltaT,
60  qint64 offset);
61 
63  static swift::misc::aviation::CAircraftParts getTestParts(int number, qint64 ts, qint64 deltaT);
64  };
65 
66  void CTestInterpolatorLinear::basicInterpolatorTests()
67  {
68  const CCallsign cs("SWIFT");
70  CInterpolatorLinear interpolator(cs, nullptr, nullptr, &provider);
71  interpolator.markAsUnitTest();
72 
73  // fixed time so everything can be debugged
74  const qint64 ts = 1425000000000; // QDateTime::currentMSecsSinceEpoch();
75  const qint64 deltaT = 5000; // ms
76  const qint64 offset = 5000; // ms
77  for (int i = IRemoteAircraftProvider::MaxSituationsPerCallsign - 1; i >= 0; i--)
78  {
79  const CAircraftSituation s(getTestSituation(cs, i, ts, deltaT, offset));
80 
81  // check height above ground
82  CLength hag = (s.getAltitude() - s.getGroundElevation());
83  QVERIFY2(s.getHeightAboveGround() == hag, "Wrong elevation");
84  provider.insertNewSituation(s);
85  }
86 
87  constexpr int partsCount = 10;
88  for (int i = partsCount - 1; i >= 0; i--)
89  {
90  const CAircraftParts p(getTestParts(i, ts, deltaT));
91  provider.insertNewAircraftParts(cs, p, false);
92  }
93 
94  // make sure signals are processed, if the interpolator depends on those signals
95  QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
96 
97  // interpolation functional check
99  double latOld = 360.0;
100  double lngOld = 360.0;
101 
102  qint64 from = ts - 2 * deltaT + offset;
103  qint64 to = ts; // ts + offset is last value, but we have to consider offset
104  qint64 step = deltaT / 20;
105  for (qint64 currentTime = from; currentTime < to; currentTime += step)
106  {
107  // This will use time range
108  // from: ts - 2 * deltaT + offset
109  // to: ts + offset
110 
111  const CInterpolationResult result = interpolator.getInterpolation(currentTime, setup, 0);
112  const CAircraftSituation currentSituation(result);
113  QVERIFY2(result.getInterpolationStatus().isInterpolated(), "Value was not interpolated");
114  const double latDeg = currentSituation.getPosition().latitude().valueRounded(CAngleUnit::deg(), 5);
115  const double lngDeg = currentSituation.getPosition().longitude().valueRounded(CAngleUnit::deg(), 5);
116  QVERIFY2(latDeg < latOld && lngDeg < lngOld, QStringLiteral("Values shall decrease: %1/%2 %3/%4")
117  .arg(latDeg)
118  .arg(latOld)
119  .arg(lngDeg)
120  .arg(lngOld)
121  .toLatin1());
122  QVERIFY2(latDeg >= 0 && latDeg <= IRemoteAircraftProvider::MaxSituationsPerCallsign,
123  "Values shall be in range");
124  latOld = latDeg;
125  lngOld = lngDeg;
126  }
127 
128  QElapsedTimer timer;
129  timer.start();
130  int interpolationNo = 0;
131  const qint64 startTimeMsSinceEpoch = ts - 2 * deltaT;
132 
133  // Pseudo performance test:
134  // Those make not completely sense, as the performance depends on the implementation of
135  // the dummy provider, which is different from the real provider
136  // With one callsign in the lists (of dummy provider) it is somehow expected to be roughly the same performance
137 
138  interpolator.resetLastInterpolation();
139  interpolator.markAsUnitTest();
140  for (int loops = 0; loops < 20; loops++)
141  {
142  from = startTimeMsSinceEpoch + offset;
143  to = ts; // ts + offset is last value, but we have to consider offset
144  step = deltaT / 20;
145 
146  for (qint64 currentTime = from; currentTime < to; currentTime += step)
147  {
148  // This will use range
149  // from: ts - 2* deltaT + offset
150  // to: ts + offset
151  const CInterpolationResult result = interpolator.getInterpolation(currentTime, setup, 0);
152  const CAircraftSituation currentSituation(result);
153  QVERIFY2(result.getInterpolationStatus().isInterpolated(), "Not interpolated");
154  QVERIFY2(!currentSituation.getCallsign().isEmpty(), "Empty callsign");
155  QVERIFY2(currentSituation.getCallsign() == cs, "Wrong callsign");
156  const double latDeg = currentSituation.getPosition().latitude().valueRounded(CAngleUnit::deg(), 5);
157  const double lngDeg = currentSituation.getPosition().longitude().valueRounded(CAngleUnit::deg(), 5);
158  Q_UNUSED(latDeg);
159  Q_UNUSED(lngDeg);
160  interpolationNo++;
161  }
162  }
163 
164  // check on time just to learn if interpolation suddenly gets very slow
165  // this is a risky test as in some situations the values can be exceeded
166  int timeMs = timer.elapsed();
167  QVERIFY2(timeMs < interpolationNo * 1.5, "Interpolation > 1.5ms");
168  qDebug() << timeMs << "ms"
169  << "for" << interpolationNo << "interpolations";
170 
171  int fetchedParts = 0;
172  timer.start();
173  for (qint64 currentTime = ts - 2 * deltaT; currentTime < ts; currentTime += 250)
174  {
175  const CInterpolationResult result = interpolator.getInterpolation(currentTime, setup, 0);
176  fetchedParts++;
177  QVERIFY2(result.getPartsStatus().isSupportingParts(), "Parts not supported");
178  }
179  timeMs = timer.elapsed();
180  qDebug() << timeMs << "ms"
181  << "for" << fetchedParts << "fetched parts";
182  }
183 
184  CAircraftSituation CTestInterpolatorLinear::getTestSituation(const CCallsign &callsign, int number, qint64 ts,
185  qint64 deltaT, qint64 offset)
186  {
187  const CAltitude alt(number, CAltitude::MeanSeaLevel, CLengthUnit::m());
188  const CLatitude lat(number, CAngleUnit::deg());
189  const CLongitude lng(180.0 + number, CAngleUnit::deg());
190  const CHeading heading(number * 10, CHeading::True, CAngleUnit::deg());
191  const CAngle bank(number, CAngleUnit::deg());
192  const CAngle pitch(number, CAngleUnit::deg());
193  const CSpeed gs(number * 10, CSpeedUnit::km_h());
194  const CAltitude gndElev({ 0, CLengthUnit::m() }, CAltitude::MeanSeaLevel);
195  const CCoordinateGeodetic c(lat, lng, alt);
196  CAircraftSituation s(callsign, c, heading, pitch, bank, gs);
197  s.setGroundElevation(gndElev, CAircraftSituation::Test);
198  s.setMSecsSinceEpoch(ts - deltaT * number); // values in past
199  s.setTimeOffsetMs(offset);
200  return s;
201  }
202 
203  CAircraftParts CTestInterpolatorLinear::getTestParts(int number, qint64 ts, qint64 deltaT)
204  {
205  CAircraftLights l(true, false, true, false, true, false);
206  CAircraftEngineList e({ CAircraftEngine(1, true), CAircraftEngine(2, false), CAircraftEngine(3, true) });
207  CAircraftParts p(l, true, 20, true, e, false);
208  p.setMSecsSinceEpoch(ts - deltaT * number); // values in past
209  return p;
210  }
211 } // namespace MiscTest
212 
214 SWIFTTEST_MAIN(MiscTest::CTestInterpolatorLinear);
215 
216 #include "testinterpolatorlinear.moc"
217 
Interpolator classes basic tests.
Value object encapsulating information of aircraft's parts.
Definition: aircraftparts.h:26
Value object encapsulating information of an aircraft's situation.
Value object encapsulating information of a callsign.
Definition: callsign.h:30
Physical unit length (length)
Definition: length.h:18
Value object for interpolator and rendering per callsign.
const CInterpolationStatus & getInterpolationStatus() const
Get status.
bool isInterpolated() const
Did interpolation succeed?
Linear interpolator, calculation inbetween positions.
void insertNewSituation(const aviation::CAircraftSituation &situation)
For testing, add new situation and fire signals.
void insertNewAircraftParts(const aviation::CCallsign &callsign, const aviation::CAircraftParts &parts, bool removeOutdatedParts)
For testing, add new situation and fire signals.
Free functions in swift::misc.