Skip to content

Commit

Permalink
feat: option to use calculated ILS (#6783)
Browse files Browse the repository at this point in the history
* feat: calculated radio receiver
* docs: added documentation of the radio receiver simvars
* feat: use calculated ILS in ND if requested
* feat: use calculated ILS in PFD if requested
* fix: improved text
* fix: use variable in all places found
  • Loading branch information
aguther authored Feb 28, 2022
1 parent e9ad537 commit 7061589
Show file tree
Hide file tree
Showing 15 changed files with 729 additions and 453 deletions.
29 changes: 29 additions & 0 deletions docs/a320-simvars.md
Original file line number Diff line number Diff line change
Expand Up @@ -1526,6 +1526,35 @@ In the variables below, {number} should be replaced with one item in the set: {
- Bool
- Whether or not the GPS is used as the primary means of navigation/position determination.

## Radio Receivers

- A32NX_RADIO_RECEIVER_USAGE_ENABLED
- Bool
- Whether or not the calculated ILS signals shall be used

- A32NX_RADIO_RECEIVER_LOC_IS_VALID
- Bool
- Indicates if the localizer signal is valid

- A32NX_RADIO_RECEIVER_LOC_DISTANCE
- Number in nautical miles
- Indicates the distance from the localizer

- A32NX_RADIO_RECEIVER_LOC_DEVIATION
- Number in degrees
- If A32NX_RADIO_RECEIVER_USAGE_ENABLED == 0 it contains the deviation from the sim
- If A32NX_RADIO_RECEIVER_USAGE_ENABLED == 1 it contains calculated LOC deviation

- A32NX_RADIO_RECEIVER_GS_IS_VALID
- Bool
- Indicates if the glide slope signal is valid

- A32NX_RADIO_RECEIVER_GS_DEVIATION
- Number in degrees
- Deviation from glide slope
- If A32NX_RADIO_RECEIVER_USAGE_ENABLED == 0 it contains the deviation from the sim
- If A32NX_RADIO_RECEIVER_USAGE_ENABLED == 1 it contains calculated LOC deviation

## Flight Management System

- A32NX_FM_ENABLE_APPROACH_PHASE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -411,11 +411,11 @@ class A32NX_GPWS {
return;
}
const localizer = this.radnav.getBestILSBeacon();
if (localizer.id <= 0 || !SimVar.GetSimVarValue("NAV HAS GLIDE SLOPE:" + localizer.id, "Bool")) {
if (localizer.id <= 0 || !SimVar.GetSimVarValue('L:A32NX_RADIO_RECEIVER_GS_IS_VALID', 'number')) {
mode.current = 0;
return;
}
const error = SimVar.GetSimVarValue("NAV GLIDE SLOPE ERROR:" + localizer.id, "Degrees");
const error = SimVar.GetSimVarValue('L:A32NX_RADIO_RECEIVER_GS_DEVIATION', 'number');
const dots = -error * 2.5; //According to the FCOM, one dot is approx. 0.4 degrees. 1/0.4 = 2.5

const minAltForWarning = dots < 2.9 ? -75 * dots + 247.5 : 30;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2091,7 +2091,7 @@ class FMCMainDisplay extends BaseAirliners {
course = this.ilsCourse;
} else if (this.ilsAutoTuned && (!this._ilsIdentPilotEntered || this._ilsIcao === this.ilsAutoIcao) && !this._ilsFrequencyPilotEntered) {
course = this.ilsAutoCourse;
} else if (this.ilsFrequency > 0 && SimVar.GetSimVarValue('NAV HAS LOCALIZER:3', 'boolean') === 1) {
} else if (this.ilsFrequency > 0 && SimVar.GetSimVarValue('L:A32NX_RADIO_RECEIVER_LOC_IS_VALID', 'number') === 1) {
course = SimVar.GetSimVarValue('NAV LOCALIZER:3', 'degrees');
}
return SimVar.SetSimVarValue('L:A32NX_FM_LS_COURSE', 'number', course);
Expand Down
1 change: 1 addition & 0 deletions src/fbw/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ clang++ \
"${DIR}/src/RudderTrimHandler.cpp" \
"${DIR}/src/SpoilersHandler.cpp" \
"${DIR}/src/ThrottleAxisMapping.cpp" \
"${DIR}/src/CalculatedRadioReceiver.cpp" \
"${DIR}/src/main.cpp" \

# restore directory
Expand Down
162 changes: 162 additions & 0 deletions src/fbw/src/CalculatedRadioReceiver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
#include "CalculatedRadioReceiver.h"
#include <cmath>
#include <iostream>

RadioReceiver::RadioReceiver() {
this->cached_gs_deg = 0;
}

RadioReceiverResult RadioReceiver::calculateLocalizerDeviation(bool loc_valid,
double loc_deg,
double loc_magvar_deg,
double loc_position_lat,
double loc_position_lon,
double loc_position_alt,
double aircraft_position_lat,
double aircraft_position_lon,
double aircraft_position_alt) {
// conversion
double Phi1 = deg2rad(aircraft_position_lat);
double Phi2 = deg2rad(loc_position_lat);
double Gamma1 = deg2rad(aircraft_position_lon);
double Gamma2 = deg2rad(loc_position_lon);

// deltas
double deltaPhi = deg2rad(loc_position_lat - aircraft_position_lat);
double deltaGamma = deg2rad(loc_position_lon - aircraft_position_lon);

// calculate distance
// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
double a = sin(deltaPhi / 2.0) * sin(deltaPhi / 2.0) + cos(Phi1) * cos(Phi2) * sin(deltaGamma / 2.0) * sin(deltaGamma / 2.0);
// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
double c = 2.0 * atan2(sqrt(a), sqrt(1.0 - a));

double distance_m = EARTH_RADIUS_METER * c; // meters
// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
distance_m = sqrt(pow(distance_m, 2.0) + pow(aircraft_position_alt - loc_position_alt, 2.0));
// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
double distance = distance_m / 1852.0; // in nm

// calculate bearing
double y = sin(Gamma2 - Gamma1) * cos(Phi2);
double x = cos(Phi1) * sin(Phi2) - sin(Phi1) * cos(Phi2) * cos(Gamma2 - Gamma1);
double Theta = atan2(y, x);
// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
double bearing = fmod((rad2deg(Theta) + 360.0), 360.0); // in degrees

// calculate deviation
// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
double mag_var = headingDifference(360.0, loc_magvar_deg);
double deviation = headingDifference(headingNormalize(loc_deg - mag_var), bearing);

bool isValid = false;
double error = 0;
double dme = 0;

// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
if ((abs(distance) < 30.0) && abs(headingDifference(loc_deg, bearing)) < 90.0 &&
(loc_position_lat != 0 || loc_position_lon != 0 || loc_position_alt != 0)) {
isValid = true;
error = deviation;
dme = distance;
}

// result variable
return RadioReceiverResult{isValid, dme, bearing, error};
}

RadioReceiverResult RadioReceiver::calculateGlideSlopeDeviation(bool gs_valid,
double log_deg,
double gs_deg,
double gs_position_lat,
double gs_position_lon,
double gs_position_alt,
double aircraft_position_lat,
double aircraft_position_lon,
double aircraft_position_alt) {
// cache gs_deg
if (gs_valid) {
cached_gs_deg = gs_deg;
} else {
gs_deg = cached_gs_deg;
}

// conversion
double Phi1 = deg2rad(aircraft_position_lat);
double Phi2 = deg2rad(gs_position_lat);
double Gamma1 = deg2rad(aircraft_position_lon);
double Gamma2 = deg2rad(gs_position_lon);

// deltas
double deltaPhi = deg2rad(gs_position_lat - aircraft_position_lat);
double deltaGamma = deg2rad(gs_position_lon - aircraft_position_lon);

// calculate distance
// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
double a = sin(deltaPhi / 2.0) * sin(deltaPhi / 2.0) + cos(Phi1) * cos(Phi2) * sin(deltaGamma / 2.0) * sin(deltaGamma / 2.0);
// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
double c = 2.0 * atan2(sqrt(a), sqrt(1.0 - a));

double distance_m = EARTH_RADIUS_METER * c; // meters
// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
distance_m = sqrt(pow(distance_m, 2.0) + pow(aircraft_position_alt - gs_position_alt, 2.0));
// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
double distance = distance_m / 1852.0; // in nm

// calculate bearing
double y = sin(Gamma2 - Gamma1) * cos(Phi2);
double x = cos(Phi1) * sin(Phi2) - sin(Phi1) * cos(Phi2) * cos(Gamma2 - Gamma1);
double Theta = atan2(y, x);
// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
double bearing = fmod((rad2deg(Theta) + 360.0), 360.0); // in degrees

// calculate deviation
double deviation = rad2deg(asin((aircraft_position_alt - gs_position_alt) / distance_m)) - gs_deg;

bool isValid = false;
double error = 0;
double dme = 0;

// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
if ((abs(distance) < 30.0) && abs(headingDifference(log_deg, bearing)) < 90.0 &&
(gs_position_lat != 0 || gs_position_lon != 0 || gs_position_alt != 0)) {
isValid = true;
error = deviation;
dme = distance;
}

// result variable
return RadioReceiverResult{isValid, dme, bearing, error};
}

double RadioReceiver::headingNormalize(double u) {
// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
return fmod(fmod(u, 360.0) + 360.0, 360.0);
}

double RadioReceiver::headingDifference(double u1, double u2) {
// normalize headings
u1 = headingNormalize(u1);
u2 = headingNormalize(u2);

// calculate shortest path
// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
double L = fmod(u1 - (u2 + 360.0) + 360.0, 360.0);
// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
double R = fmod(360.0 - L, 360.0);
if (abs(L) < abs(R)) {
return -1.0 * L;
} else {
return R;
}
}

double RadioReceiver::deg2rad(double degrees) {
// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
return (degrees * M_PI) / 180.0;
}

double RadioReceiver::rad2deg(double radians) {
// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
return (radians * 180.0) / M_PI;
}
43 changes: 43 additions & 0 deletions src/fbw/src/CalculatedRadioReceiver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#pragma once

struct RadioReceiverResult {
bool isValid;
double distance;
double bearing;
double deviation;
};

class RadioReceiver {
public:
RadioReceiver();

RadioReceiverResult calculateLocalizerDeviation(bool loc_valid,
double loc_deg,
double loc_magvar_deg,
double loc_position_lat,
double loc_position_lon,
double loc_position_alt,
double aircraft_position_lat,
double aircraft_position_lon,
double aircraft_position_alt);

RadioReceiverResult calculateGlideSlopeDeviation(bool gs_valid,
double log_deg,
double gs_deg,
double gs_position_lat,
double gs_position_lon,
double gs_position_alt,
double aircraft_position_lat,
double aircraft_position_lon,
double aircraft_position_alt);

private:
static constexpr double EARTH_RADIUS_METER = 6371e3;

double cached_gs_deg;

double headingNormalize(double u);
double headingDifference(double u1, double u2);
double deg2rad(double degrees);
double rad2deg(double radians);
};
Loading

0 comments on commit 7061589

Please sign in to comment.