14using namespace swift::config;
15using namespace swift::misc::aviation;
16using namespace swift::misc::geo;
17using namespace swift::misc::math;
18using namespace swift::misc::network;
19using namespace swift::misc::physical_quantities;
20using namespace swift::misc::simulation;
22namespace swift::misc::simulation
28 std::array<double, N> solveTridiagonal(std::array<std::array<double, N>, N> &matrix, std::array<double, N> &d)
30 const auto a = [&matrix](
size_t i) ->
double & {
return matrix[i][i - 1]; };
31 const auto b = [&matrix](
size_t i) ->
double & {
return matrix[i][i]; };
32 const auto c = [&matrix](
size_t i) ->
double & {
return matrix[i][i + 1]; };
37 for (
size_t i = 1; i < N; ++i)
39 const double denom = b(i) - a(i) * c(i - 1);
44 d[i] = (d[i] - a(i) * d[i - 1]) / denom;
48 for (
int i = N - 2; i >= 0; --i)
50 const auto it =
static_cast<size_t>(i);
51 d[it] -= c(it) * d[it + 1];
60 std::array<double, N> getDerivatives(
const std::array<double, N> &x,
const std::array<double, N> &y)
62 std::array<std::array<double, N>, N> a { {} };
63 std::array<double, N> b { {} };
65 a[0][0] = 2.0 / (x[1] - x[0]);
66 a[0][1] = 1.0 / (x[1] - x[0]);
67 b[0] = 3.0 * (y[1] - y[0]) / ((x[1] - x[0]) * (x[1] - x[0]));
69 a[N - 1][N - 2] = 1.0 / (x[N - 1] - x[N - 2]);
70 a[N - 1][N - 1] = 2.0 / (x[N - 1] - x[N - 2]);
71 b[N - 1] = 3.0 * (y[N - 1] - y[N - 2]) / ((x[N - 1] - x[N - 2]) * (x[N - 1] - x[N - 2]));
73 for (
size_t i = 1; i < N - 1; ++i)
75 a[i][i - 1] = 1.0 / (x[i] - x[i - 1]);
76 a[i][i] = 2.0 / (x[i] - x[i - 1]) + 2.0 / (x[i + 1] - x[i]);
77 a[i][i + 1] = 1.0 / (x[i + 1] - x[i]);
78 b[i] = 3.0 * (y[i] - y[i - 1]) / ((x[i] - x[i - 1]) * (x[i] - x[i - 1])) +
79 3.0 * (y[i + 1] - y[i]) / ((x[i + 1] - x[i]) * (x[i + 1] - x[i]));
82 solveTridiagonal(a, b);
87 double evalSplineInterval(
double x,
double x0,
double x1,
double y0,
double y1,
double k0,
double k1)
89 const double t = (x - x0) / (x1 - x0);
90 const double a = k0 * (x1 - x0) - (y1 - y0);
91 const double b = -k1 * (x1 - x0) + (y1 - y0);
92 const double y = (1 - t) * y0 + t * y1 + t * (1 - t) * (a * (1 - t) + b * t);
103 bool CInterpolatorSpline::fillSituationsArray()
122 m_s[0] = m_s[1] = m_s[2] = f;
133 m_s[0].addMsecs(-os);
147 const qint64 currentAdjusted = m_s[1].getAdjustedMSecsSinceEpoch();
150 const qint64 osNotTooClose = qRound64(0.8 * os);
151 const CAircraftSituation older =
159 const CAircraftSituation closeOlder =
166 const qint64 latestAdjusted = m_s[2].getAdjustedMSecsSinceEpoch();
167 const qint64 olderAdjusted = m_s[0].getAdjustedMSecsSinceEpoch();
175 const bool verified =
176 verifyInterpolationSituations(m_s[0], m_s[1], m_s[2]);
179 static const QString vm(
"Unverified situations, m0-2 (oldest latest) %1 %2 %3");
180 const QString vmValues = vm.arg(olderAdjusted).arg(currentAdjusted).arg(latestAdjusted);
181 CLogMessage(
this).warning(vmValues);
189 void CInterpolatorSpline::anchor() {}
203 const bool fillStatus = this->fillSituationsArray();
206 m_interpolant.setValid(
false);
207 return m_interpolant;
210 const std::array<std::array<double, 3>, 3> normals { { m_s[0].getPosition().normalVectorDouble(),
211 m_s[1].getPosition().normalVectorDouble(),
212 m_s[2].getPosition().normalVectorDouble() } };
214 pa.
x = { { normals[0][0], normals[1][0], normals[2][0] } };
215 pa.
y = { { normals[0][1], normals[1][1], normals[2][1] } };
216 pa.
z = { { normals[0][2], normals[1][2], normals[2][2] } };
217 pa.
t = { {
static_cast<double>(m_s[0].getAdjustedMSecsSinceEpoch()),
218 static_cast<double>(m_s[1].getAdjustedMSecsSinceEpoch()),
219 static_cast<double>(m_s[2].getAdjustedMSecsSinceEpoch()) } };
221 pa.
dx = getDerivatives(pa.
t, pa.
x);
222 pa.
dy = getDerivatives(pa.
t, pa.
y);
223 pa.
dz = getDerivatives(pa.
t, pa.
z);
231 this->updateElevations(
true);
234 const double a0 = m_s[0].getCorrectedAltitude(cg).value(altUnit);
235 const double a1 = m_s[1].getCorrectedAltitude(cg).value(altUnit);
236 const double a2 = m_s[2].getCorrectedAltitude(cg).value(altUnit);
237 pa.
a = { { a0, a1, a2 } };
238 pa.
gnd = { { m_s[0].getOnGroundInfo().getGroundFactor(), m_s[1].getOnGroundInfo().getGroundFactor(),
239 m_s[2].getOnGroundInfo().getGroundFactor() } };
240 pa.
da = getDerivatives(pa.
t, pa.
a);
241 pa.
dgnd = getDerivatives(pa.
t, pa.
gnd);
243 m_prevSampleAdjustedTime = m_s[1].getAdjustedMSecsSinceEpoch();
244 m_nextSampleAdjustedTime = m_s[2].getAdjustedMSecsSinceEpoch();
245 m_prevSampleTime = m_s[1].getMSecsSinceEpoch();
246 m_nextSampleTime = m_s[2].getMSecsSinceEpoch();
248 Q_ASSERT_X(m_prevSampleAdjustedTime < m_nextSampleAdjustedTime, Q_FUNC_INFO,
"Wrong time order");
264 const auto dt2 =
static_cast<double>(m_nextSampleAdjustedTime - m_prevSampleAdjustedTime);
265 double timeFraction = dt1 / dt2;
274 const qint64 interpolatedTime = m_prevSampleTime + qRound64(timeFraction * dt2);
279 m_interpolant.setRecalculated(recalculate);
294 return m_interpolant;
297 bool CInterpolatorSpline::updateElevations(
bool canSkip)
299 bool updated =
false;
302 if (s.hasGroundElevation())
306 if (canSkip && s.canLikelySkipNearGroundInterpolation())
319 bool CInterpolatorSpline::areAnyElevationsMissing()
const
321 return std::ranges::any_of(m_s, [](
const auto &situation) {
return !situation.hasGroundElevation(); });
324 bool CInterpolatorSpline::isAnySituationNearGroundRelevant()
const
326 return std::ranges::any_of(
327 m_s, [](
const auto &situation) {
return !situation.canLikelySkipNearGroundInterpolation(); });
332 : m_pa(pa), m_altitudeUnit(altitudeUnit)
337 std::tuple<geo::CCoordinateGeodetic, aviation::CAltitude>
340 const double t1 = m_pa.t[1];
341 const double t2 = m_pa.t[2];
343 bool valid = (t1 < t2) && (m_currentTimeMsSinceEpoc >= t1) && (m_currentTimeMsSinceEpoc < t2);
346 Q_ASSERT_X(t1 < t2, Q_FUNC_INFO,
347 "Expect sorted times, latest first");
348 SWIFT_VERIFY_X(m_currentTimeMsSinceEpoc >= t1, Q_FUNC_INFO,
"invalid timestamp t1");
350 "invalid timestamp t2");
358 evalSplineInterval(m_currentTimeMsSinceEpoc, t1, t2, m_pa.x[1], m_pa.x[2], m_pa.dx[1], m_pa.dx[2]);
360 evalSplineInterval(m_currentTimeMsSinceEpoc, t1, t2, m_pa.y[1], m_pa.y[2], m_pa.dy[1], m_pa.dy[2]);
362 evalSplineInterval(m_currentTimeMsSinceEpoc, t1, t2, m_pa.z[1], m_pa.z[2], m_pa.dz[1], m_pa.dz[2]);
377 const std::array<double, 3> normalVector = { { newX, newY, newZ } };
385 << normalVector[0] << normalVector[1] << normalVector[2];
393 evalSplineInterval(m_currentTimeMsSinceEpoc, t1, t2, m_pa.a[1], m_pa.a[2], m_pa.da[1], m_pa.da[2]);
394 const CAltitude alt(newA, m_altitudeUnit);
396 return { currentPosition, alt };
401 const double t1 = m_pa.t[1];
402 const double t2 = m_pa.t[2];
403 bool valid = (t1 < t2) && (m_currentTimeMsSinceEpoc >= t1) && (m_currentTimeMsSinceEpoc < t2);
409 const double gnd1 = m_pa.gnd[1];
410 const double gnd2 = m_pa.gnd[2];
422 const double newGnd =
423 evalSplineInterval(m_currentTimeMsSinceEpoc, t1, t2, gnd1, gnd2, m_pa.dgnd[1], m_pa.dgnd[2]);
429 qint64 interpolatedTimeMs)
431 m_currentTimeMsSinceEpoc = currentTimeMs;
433 m_pbh.setTimeFraction(timeFraction);
438 for (uint i = 0; i < 3; i++)
464 bool CInterpolatorSpline::verifyInterpolationSituations(
const CAircraftSituation &oldest,
495 bool details =
false;
500 SWIFT_VERIFY_X(details, Q_FUNC_INFO,
"Once gnd.from parts -> always gnd. from parts");
503 for (
const CAircraftSituation &s : situations)
505 if (!s.hasGroundElevation())
509 SWIFT_VERIFY_X(!s.getGroundElevation().isZeroEpsilonConsidered(), Q_FUNC_INFO,
"Suspicous 0 gnd. value");
519 return sorted && details;
static bool isLocalDeveloperDebugBuild()
Local build for developers.
Class for emitting a log message.
Derived & warning(const char16_t(&format)[N])
Set the severity to warning, providing a format string.
void push_back(const T &value)
Appends an element at the end of the sequence.
void clear()
Removes all elements in the sequence.
void setAdjustedMSecsSinceEpoch(qint64 adjustedTimeMs)
Set timestamp with offset added for interpolation.
bool isNewerThanAdjusted(const ITimestampWithOffsetBased &otherTimestampObj) const
Is this newer than other?
Value object encapsulating information of an aircraft's situation.
bool hasGroundElevation() const
Is ground elevation value available.
static bool isGfEqualAirborne(double oldGroundFactor, double newGroundFactor)
Both not on ground.
static const CAircraftSituation & null()
Null situation.
bool isNull() const
Null situation.
static bool isGfEqualOnGround(double oldGroundFactor, double newGroundFactor)
Both on ground.
List of aircraft situations.
bool areAllOnGroundDetailsSame(COnGroundInfo::OnGroundDetails details) const
Are all on ground details the same?
bool containsOnGroundDetails(COnGroundInfo::OnGroundDetails details) const
Contains on ground details?
bool isSortedAdjustedLatestFirstWithoutNullPositions() const
Latest first and no null positions?
Altitude as used in aviation, can be AGL or MSL altitude.
static physical_quantities::CLengthUnit defaultUnit()
Default unit for calculations.
Information about the ground status.
@ InFromParts
set from aircraft parts
@ OnGroundByInterpolation
strongest for remote aircraft
@ NotSetGroundDetails
not set or unknown if correct (e.g.
Plane of same elevation, can be a single point or larger area (e.g. airport).
static const physical_quantities::CLength & singlePointRadius()
Radius for single point.
static bool isValidVector(const std::array< double, 3 > &v)
Check values.
static constexpr qint64 c_interimPositionTimeOffsetMsec
offset time for received interim position updates Ref T297
Physical unit length (length).
Specialized class for distance units (meter, foot, nautical miles).
bool isAircraftPartsEnabled() const
Aircraft parts enabled (still requires the other aircraft to send parts).
Value object for interpolator and rendering per callsign.
qint64 m_situationsLastModified
when situations were last modified
bool doLogging() const
Do logging.
const physical_quantities::CLength & getModelCG() const
Center of gravity.
CInterpolationStatus m_currentInterpolationStatus
this step's situation status
aviation::CAircraftSituation m_lastSituation
latest interpolation
qint64 m_situationsLastModifiedUsed
interpolant based on situations last updated
qint64 m_currentTimeMsSinceEpoch
current time
aviation::CAircraftSituationList m_currentSituations
current situations obtained by remoteAircraftSituationsAndChange
Simple linear interpolator for pitch, bank, heading and groundspeed from start to end situation.
Cubic function that performs the actual interpolation.
aviation::COnGroundInfo interpolateGroundFactor() const
Interpolate the ground information/factor.
std::tuple< geo::CCoordinateGeodetic, aviation::CAltitude > interpolatePositionAndAltitude() const
Perform the interpolation.
const IInterpolatorPbh & pbh() const
Get the PBH interpolator.
void setTimes(qint64 currentTimeMs, double timeFraction, qint64 interpolatedTimeMs)
Set the time values.
const IInterpolant & getInterpolant(SituationLog &log)
Get the interpolant for the given time point.
geo::CElevationPlane findClosestElevationWithinRange(const geo::ICoordinateGeodetic &reference, const physical_quantities::CLength &range) const
Find closest elevation (or return NULL).
qint64 m_interpolatedTime
"Real time "of interpolated situation
bool isAcceptableTimeFraction(double timeFraction)
Valid time fraction [0,1], this allows minor overshooting.
double clampValidTimeFraction(double timeFraction)
Clamp time fraction [0,1].
Position arrays for interpolation.
std::array< double, 3 > dz
3 coordinates for spline interpolation
std::array< double, 3 > dx
3 coordinates for spline interpolation
static const PosArray & zeroPosArray()
Zero initialized position array.
std::array< double, 3 > a
3 coordinates for spline interpolation
std::array< double, 3 > y
3 coordinates for spline interpolation
std::array< double, 3 > t
3 coordinates for spline interpolation
std::array< double, 3 > x
3 coordinates for spline interpolation
std::array< double, 3 > gnd
3 coordinates for spline interpolation
std::array< double, 3 > dgnd
3 coordinates for spline interpolation
std::array< double, 3 > z
3 coordinates for spline interpolation
void initToZero()
Init all values to zero.
std::array< double, 3 > dy
3 coordinates for spline interpolation
std::array< double, 3 > da
3 coordinates for spline interpolation
Log entry for situation interpolation.
QChar interpolator
what interpolator is used
aviation::CAircraftSituationList interpolationSituations
the interpolator uses 2, 3 situations (latest at end)
qint64 tsInterpolated
timestamp interpolated
double deltaSampleTimesMs
delta time between samples (i.e.
double simTimeFraction
time fraction, expected 0..1
bool interpolantRecalc
interpolant recalculated
#define SWIFT_VERIFY_X(COND, WHERE, WHAT)
A weaker kind of assert.