fix some changes and add a low pass filter to avoid fast ETA changes

This commit is contained in:
Sven Czarnian
2021-11-29 19:21:29 +01:00
parent d89e8fef4c
commit 055cf900fb
2 changed files with 75 additions and 41 deletions

View File

@@ -41,7 +41,9 @@ namespace aman {
Velocity indicatedAirspeed(const Length& altitude) const noexcept; Velocity indicatedAirspeed(const Length& altitude) const noexcept;
Velocity groundSpeed(const Length& altitude, const Velocity& ias, const Angle& heading); Velocity groundSpeed(const Length& altitude, const Velocity& ias, const Angle& heading);
void createWindTables(const google::protobuf::RepeatedPtrField<aman::WindData>& wind); void createWindTables(const google::protobuf::RepeatedPtrField<aman::WindData>& wind);
static int findIndexInPredictedPath(const EuroScopePlugIn::CFlightPlanPositionPredictions& predictions, const GeoCoordinate& position); static int matchToPredictedPath(const EuroScopePlugIn::CFlightPlanPositionPredictions& predictions, const GeoCoordinate& position,
Length& trackmiles);
void predictETA(const EuroScopePlugIn::CRadarTarget& target, const EuroScopePlugIn::CFlightPlanPositionPredictions& predictions, bool resetTTL);
public: public:
Inbound(EuroScopePlugIn::CRadarTarget& target, const aman::AircraftSchedule& inbound, const google::protobuf::RepeatedPtrField<aman::WindData>& wind); Inbound(EuroScopePlugIn::CRadarTarget& target, const aman::AircraftSchedule& inbound, const google::protobuf::RepeatedPtrField<aman::WindData>& wind);

View File

@@ -66,7 +66,10 @@ void Inbound::updatePrediction(EuroScopePlugIn::CRadarTarget& target, const aman
this->m_performanceData.speedBelowFL100 = static_cast<float>(inbound.performance().iasbelowfl100()) * knot; this->m_performanceData.speedBelowFL100 = static_cast<float>(inbound.performance().iasbelowfl100()) * knot;
this->m_performanceData.speedApproach = static_cast<float>(inbound.performance().iasapproach()) * knot; this->m_performanceData.speedApproach = static_cast<float>(inbound.performance().iasapproach()) * knot;
if (true == forceUpdate || this->m_star != target.GetCorrelatedFlightPlan().GetFlightPlanData().GetStarName() || this->m_runway != target.GetCorrelatedFlightPlan().GetFlightPlanData().GetArrivalRwy()) { bool updateEuroscopePlan = true == forceUpdate && 0 != this->m_star.length() && 0 != this->m_runway.length();
updateEuroscopePlan &= this->m_star != target.GetCorrelatedFlightPlan().GetFlightPlanData().GetStarName() || this->m_runway.length() && this->m_runway != target.GetCorrelatedFlightPlan().GetFlightPlanData().GetArrivalRwy();
if (true == updateEuroscopePlan) {
std::string route(target.GetCorrelatedFlightPlan().GetFlightPlanData().GetRoute()); std::string route(target.GetCorrelatedFlightPlan().GetFlightPlanData().GetRoute());
std::string arrival = this->m_star + "/" + this->m_runway; std::string arrival = this->m_star + "/" + this->m_runway;
@@ -92,7 +95,7 @@ void Inbound::updatePrediction(EuroScopePlugIn::CRadarTarget& target, const aman
updatedFlightplan = true; updatedFlightplan = true;
} }
if (true == updatedFlightplan) { if (true == forceUpdate || true == updatedFlightplan) {
this->m_arrivalRoute.clear(); this->m_arrivalRoute.clear();
this->m_arrivalRoute.reserve(inbound.waypoints_size()); this->m_arrivalRoute.reserve(inbound.waypoints_size());
auto route = target.GetCorrelatedFlightPlan().GetExtractedRoute(); auto route = target.GetCorrelatedFlightPlan().GetExtractedRoute();
@@ -225,7 +228,10 @@ static __inline Angle __normalize(const Angle& angle) {
return retval; return retval;
} }
int Inbound::findIndexInPredictedPath(const EuroScopePlugIn::CFlightPlanPositionPredictions& predictions, const GeoCoordinate& position) { int Inbound::matchToPredictedPath(const EuroScopePlugIn::CFlightPlanPositionPredictions& predictions, const GeoCoordinate& position,
Length& trackmiles) {
trackmiles = 0_m;
if (0 == predictions.GetPointsNumber()) if (0 == predictions.GetPointsNumber())
return 0; return 0;
@@ -237,39 +243,27 @@ int Inbound::findIndexInPredictedPath(const EuroScopePlugIn::CFlightPlanPosition
const auto prev = lastPosition.bearingTo(position); const auto prev = lastPosition.bearingTo(position);
const auto next = coordinate.bearingTo(position); const auto next = coordinate.bearingTo(position);
const auto delta = __normalize(prev - next); const auto delta = __normalize(prev - next);
if (100_deg <= delta.abs()) if (100_deg <= delta.abs()) {
return i; trackmiles += lastPosition.distanceTo(position);
return i - 1;
}
trackmiles += lastPosition.distanceTo(coordinate);
lastPosition = coordinate; lastPosition = coordinate;
} }
return predictions.GetPointsNumber(); return predictions.GetPointsNumber();
} }
void Inbound::update(EuroScopePlugIn::CRadarTarget& target) { void Inbound::predictETA(const EuroScopePlugIn::CRadarTarget& target, const EuroScopePlugIn::CFlightPlanPositionPredictions& predictions, bool resetTTL) {
if (this->m_arrivalRoute.size() <= this->m_nextStarWaypoint) { if (this->m_arrivalRoute.size() <= this->m_nextStarWaypoint || 1 >= predictions.GetPointsNumber()) {
this->m_timeToLose = 0_s; this->m_timeToLose = 0_s;
return; return;
} }
const auto& destination = gsl::at(this->m_arrivalRoute, this->m_nextStarWaypoint); const auto& destination = gsl::at(this->m_arrivalRoute, this->m_nextStarWaypoint);
const auto& predictions = target.GetCorrelatedFlightPlan().GetPositionPredictions();
GeoCoordinate lastPosition(__convert(target.GetPosition().GetPosition()));
Length distanceToNextWaypoint = 0_m; Length distanceToNextWaypoint = 0_m;
Inbound::matchToPredictedPath(predictions, destination.position(), distanceToNextWaypoint);
/* calculate the distance to the correct waypoint */
for (int i = 0; i < predictions.GetPointsNumber(); ++i) {
GeoCoordinate coordinate(__convert(predictions.GetPosition(i)));
const auto prev = lastPosition.bearingTo(destination.position());
const auto next = coordinate.bearingTo(destination.position());
const auto delta = __normalize(prev - next);
if (100_deg <= delta.abs())
break;
distanceToNextWaypoint += coordinate.distanceTo(lastPosition);
lastPosition = coordinate;
}
/* predict the flight and the descend */ /* predict the flight and the descend */
Velocity groundSpeed = static_cast<float>(target.GetPosition().GetReportedGS()) * knot; Velocity groundSpeed = static_cast<float>(target.GetPosition().GetReportedGS()) * knot;
@@ -298,33 +292,71 @@ void Inbound::update(EuroScopePlugIn::CRadarTarget& target) {
flightTime += 1_s; flightTime += 1_s;
} }
auto currentUtc = UtcTime::currentUtc(); const auto delta = std::chrono::duration_cast<std::chrono::seconds>(destination.plannedArrivalTime() - UtcTime::currentUtc());
auto pta = UtcTime::timeToString(destination.plannedArrivalTime()); const auto plannedFlightTime = static_cast<float>(delta.count()) * second;
auto estimated = UtcTime::timeToString(currentUtc + std::chrono::seconds(static_cast<int>(flightTime.convert(second)))); const auto newTTL = plannedFlightTime - flightTime;
auto delta = std::chrono::duration_cast<std::chrono::seconds>(destination.plannedArrivalTime() - currentUtc);
auto plannedFlightTime = static_cast<float>(delta.count()) * second; if (true == resetTTL)
this->m_timeToLose = plannedFlightTime - flightTime; this->m_timeToLose = newTTL;
else
this->m_timeToLose = 0.9f * this->m_timeToLose + 0.1f * newTTL;
}
void Inbound::update(EuroScopePlugIn::CRadarTarget& target) {
this->predictETA(target, target.GetCorrelatedFlightPlan().GetPositionPredictions(), false);
} }
void Inbound::update(EuroScopePlugIn::CFlightPlan& plan) { void Inbound::update(EuroScopePlugIn::CFlightPlan& plan) {
const auto lastStarWaypoint = this->m_nextStarWaypoint;
this->m_nextStarWaypoint = 0; this->m_nextStarWaypoint = 0;
if (0 == this->m_arrivalRoute.size())
if (0 == this->m_arrivalRoute.size()) {
this->m_timeToLose = 0_s;
return; return;
}
/* find the point on the route */ /* find the point on the route */
std::string_view direct(plan.GetControllerAssignedData().GetDirectToPointName()); std::string direct(plan.GetControllerAssignedData().GetDirectToPointName());
auto route = plan.GetExtractedRoute(); auto route = plan.GetExtractedRoute();
int starEntry = route.GetPointsNumber(), directEntry = route.GetPointsNumber(); int starEntry = route.GetPointsNumber(), directEntry = route.GetPointsNumber();
/* TODO search point if direct is empty */ /* find the star entry on the route */
for (int c = 0; c < route.GetPointsNumber(); ++c) { for (int c = 0; c < route.GetPointsNumber(); ++c) {
std::string_view waypointName(route.GetPointName(c)); std::string_view waypointName(route.GetPointName(c));
if (waypointName == this->m_arrivalRoute.front().name()) {
if (waypointName == this->m_arrivalRoute.front().name())
starEntry = c; starEntry = c;
else if (waypointName == direct) break;
}
}
if (0 != direct.length()) {
/* find the DIRECT waypoint */
for (int c = 0; c < route.GetPointsNumber(); ++c) {
std::string_view waypointName(route.GetPointName(c));
if (waypointName == direct) {
directEntry = c; directEntry = c;
break;
}
}
}
else {
const auto& acPosition = __convert(plan.GetCorrelatedRadarTarget().GetPosition().GetPosition());
Length minDistance(10000_nm);
/* search the next waypoint on the route */
for (int c = route.GetPointsNumber() - 1; c >= 0; --c) {
const auto& position = __convert(route.GetPointPosition(c));
const auto distance = position.distanceTo(acPosition);
if (distance < minDistance) {
direct = route.GetPointName(c);
minDistance = distance;
directEntry = c;
}
if (c < starEntry)
break;
}
} }
/* search the direct to entry */ /* search the direct to entry */
@@ -345,13 +377,13 @@ void Inbound::update(EuroScopePlugIn::CFlightPlan& plan) {
break; break;
} }
direct = std::string_view(route.GetPointName(directEntry)); direct = std::string(route.GetPointName(directEntry));
} }
} }
} }
EuroScopePlugIn::CRadarTarget target = plan.GetCorrelatedRadarTarget(); const auto target = plan.GetCorrelatedRadarTarget();
this->update(target); this->predictETA(target, plan.GetPositionPredictions(), this->m_nextStarWaypoint != lastStarWaypoint);
} }
bool Inbound::fixedPlan() const noexcept { bool Inbound::fixedPlan() const noexcept {