ATIS improvements from John Denker
Primarily an improvment to the internationalisation. Previously the ATIS considered the world as either the UK or the rest of the world. Now it considers it as US+Canada or the rest of the world. This is much more consistent with global usage of pressure units as either inches or millibars, which is the most important difference. Also some other tweaks and cleanups.
This commit is contained in:
parent
b5d2e734d1
commit
dd690909af
4 changed files with 110 additions and 46 deletions
|
@ -151,6 +151,7 @@ void FGATIS::Update(double dt) {
|
|||
// If !_prev_display, the radio had been detuned for a while and our
|
||||
// "transmission" variable was lost when we were de-instantiated.
|
||||
int rslt = GenTransmission(!_prev_display, attention);
|
||||
TreeOut(msg_OK);
|
||||
if (rslt || volume != old_volume) {
|
||||
//cout << "ATIS calling ATC::render volume: " << volume << endl;
|
||||
Render(transmission, volume, refname, true);
|
||||
|
@ -207,6 +208,28 @@ const int minute(60); // measured in seconds
|
|||
const int ATIS_interval(60*minute);
|
||||
#endif
|
||||
|
||||
// FIXME: This is heuristic. It gets the right answer for
|
||||
// more than 90% of the world's airports, which is a lot
|
||||
// better than nothing ... but it's not 100%.
|
||||
// We know "most" of the world uses millibars,
|
||||
// but the US, Canada and *some* other places use inches of mercury,
|
||||
// but (a) we have not implemented a reliable method of
|
||||
// ascertaining which airports are in the US, let alone
|
||||
// (b) ascertaining which other places use inches.
|
||||
//
|
||||
int Apt_US_CA(const string id) {
|
||||
// Assume all IDs have length 3 or 4.
|
||||
// No counterexamples have been seen.
|
||||
if (id.length() == 4) {
|
||||
if (id.substr(0,1) == "K") return 1;
|
||||
if (id.substr(0,2) == "CY") return 1;
|
||||
}
|
||||
for (string::const_iterator ptr = id.begin(); ptr != id.end(); ptr++) {
|
||||
if (isdigit(*ptr)) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Generate the actual broadcast ATIS transmission.
|
||||
// Regen means regenerate the /current/ transmission.
|
||||
// Special means generate a new transmission, with a new sequence.
|
||||
|
@ -238,7 +261,9 @@ int FGATIS::GenTransmission(const int regen, const int special) {
|
|||
|
||||
transmission = "";
|
||||
|
||||
if (ident.substr(0,2) == "EG") {
|
||||
int US_CA = Apt_US_CA(ident);
|
||||
|
||||
if (!US_CA) {
|
||||
// UK CAA radiotelephony manual indicates ATIS transmissions start
|
||||
// with "This is ..."
|
||||
transmission += This_is + " ";
|
||||
|
@ -338,29 +363,39 @@ int FGATIS::GenTransmission(const int regen, const int special) {
|
|||
snprintf(buf, bs, "/environment/clouds/layer[%i]/elevation-ft", layer);
|
||||
double ceiling = int(fgGetDouble(buf) - _geod.getElevationFt());
|
||||
if (ceiling > 12000) continue;
|
||||
if (coverage == scattered) {
|
||||
if (!did_some) transmission += " " + Sky_condition + ": ";
|
||||
did_some++;
|
||||
|
||||
// BEWARE: At the present time, the environment system has no
|
||||
// way (so far as I know) to represent a "thin broken" or
|
||||
// "thin overcast" layer. If/when such things are implemented
|
||||
// in the environment system, code will have to be written here
|
||||
// to handle them.
|
||||
|
||||
// First, do the prefix if any:
|
||||
if (coverage == scattered || coverage == few) {
|
||||
if (!did_some) {
|
||||
transmission += " " + Sky_condition + ": ";
|
||||
did_some++;
|
||||
}
|
||||
} else /* must be a ceiling */ if (!did_ceiling) {
|
||||
transmission += " " + Ceiling + ": ";
|
||||
did_ceiling++;
|
||||
did_some++;
|
||||
} else {
|
||||
transmission += " ";
|
||||
transmission += " "; // no prefix required
|
||||
}
|
||||
int cig00 = int(SGMiscd::round(ceiling/100)); // hundreds of feet
|
||||
if (cig00) {
|
||||
int cig000 = cig00/10;
|
||||
cig00 -= cig000*10; // just the hundreds digit
|
||||
if (cig000) {
|
||||
snprintf(buf, bs, "%i", cig000);
|
||||
transmission += ConvertNumToSpokenDigits(buf);
|
||||
transmission += " " + thousand + " ";
|
||||
snprintf(buf, bs, "%i", cig000);
|
||||
transmission += ConvertNumToSpokenDigits(buf);
|
||||
transmission += " " + thousand + " ";
|
||||
}
|
||||
if (cig00) {
|
||||
snprintf(buf, bs, "%i", cig00);
|
||||
transmission += ConvertNumToSpokenDigits(buf);
|
||||
transmission += " " + hundred + " ";
|
||||
snprintf(buf, bs, "%i", cig00);
|
||||
transmission += ConvertNumToSpokenDigits(buf);
|
||||
transmission += " " + hundred + " ";
|
||||
}
|
||||
} else {
|
||||
// Should this be "sky obscured?"
|
||||
|
@ -368,6 +403,7 @@ int FGATIS::GenTransmission(const int regen, const int special) {
|
|||
}
|
||||
transmission += coverage + BRK;
|
||||
}
|
||||
if (!did_some) transmission += " " + Sky + " " + clear + BRK;
|
||||
|
||||
transmission += Temperature + ": ";
|
||||
double Tsl = fgGetDouble("/environment/temperature-sea-level-degc");
|
||||
|
@ -377,7 +413,7 @@ int FGATIS::GenTransmission(const int regen, const int special) {
|
|||
}
|
||||
snprintf(buf, bs, "%i", abs(temp));
|
||||
transmission += ConvertNumToSpokenDigits(buf);
|
||||
transmission += " " + Celsius;
|
||||
if (US_CA) transmission += " " + Celsius;
|
||||
transmission += " " + dewpoint + " ";
|
||||
double dpsl = fgGetDouble("/environment/dewpoint-sea-level-degc");
|
||||
temp = int(SGMiscd::round(FGAtmo().fake_dp_vs_a_us(dpsl, _geod.getElevationFt())));
|
||||
|
@ -386,7 +422,8 @@ int FGATIS::GenTransmission(const int regen, const int special) {
|
|||
}
|
||||
snprintf(buf, bs, "%i", abs(temp));
|
||||
transmission += ConvertNumToSpokenDigits(buf);
|
||||
transmission += " " + Celsius + BRK;
|
||||
if (US_CA) transmission += " " + Celsius;
|
||||
transmission += BRK;
|
||||
|
||||
transmission += Visibility + ": ";
|
||||
double visibility = fgGetDouble("/environment/config/boundary/entry[0]/visibility-m");
|
||||
|
@ -409,7 +446,6 @@ int FGATIS::GenTransmission(const int regen, const int special) {
|
|||
}
|
||||
transmission += BRK;
|
||||
|
||||
transmission += Altimeter + ": ";
|
||||
double myQNH;
|
||||
double Psl = fgGetDouble("/environment/pressure-sea-level-inhg");
|
||||
{
|
||||
|
@ -424,17 +460,21 @@ int FGATIS::GenTransmission(const int regen, const int special) {
|
|||
#endif
|
||||
myQNH = FGAtmo().QNH(_geod.getElevationM(), press);
|
||||
}
|
||||
if(ident.substr(0,2) == "EG" && fgGetBool("/sim/atc/use-millibars")) {
|
||||
// Convert to millibars for the UK!
|
||||
|
||||
// Convert to millibars for most of the world (not US, not CA)
|
||||
if((!US_CA) || fgGetBool("/sim/atc/use-millibars")) {
|
||||
transmission += QNH + ": ";
|
||||
myQNH /= mbar;
|
||||
if (myQNH > 1000) myQNH -= 1000; // drop high digit
|
||||
snprintf(buf, bs, "%03.0f", myQNH);
|
||||
transmission += ConvertNumToSpokenDigits(buf) + " " + millibars + BRK;
|
||||
} else {
|
||||
myQNH /= inHg;
|
||||
myQNH *= 100.; // shift two decimal places
|
||||
snprintf(buf, bs, "%04.0f", myQNH);
|
||||
transmission += Altimeter + ": ";
|
||||
double asetting = myQNH / inHg; // use inches of mercury
|
||||
asetting *= 100.; // shift two decimal places
|
||||
snprintf(buf, bs, "%04.0f", asetting);
|
||||
transmission += ConvertNumToSpokenDigits(buf) + BRK;
|
||||
}
|
||||
transmission += ConvertNumToSpokenDigits(buf) + BRK;
|
||||
|
||||
if (_type == ATIS /* as opposed to AWOS */) {
|
||||
const FGAirport* apt = fgFindAirportID(ident);
|
||||
|
@ -456,27 +496,8 @@ int FGATIS::GenTransmission(const int regen, const int special) {
|
|||
transmission += phonetic_seq_string;
|
||||
transmission += "... " + BRK + PAUSE + PAUSE;
|
||||
}
|
||||
#ifdef ATIS_TEST
|
||||
cout << "**** ATIS active on:";
|
||||
#endif
|
||||
for (map<string,int>::iterator act = active_on.begin(); act != active_on.end(); act++){
|
||||
string prop = "/instrumentation/" + act->first + "/atis";
|
||||
globals->get_props()->setStringValue(prop.c_str(),
|
||||
("<pre>\n" + transmission + "</pre>\n").c_str());
|
||||
#ifdef ATIS_TEST
|
||||
cout << " " << prop;
|
||||
#endif
|
||||
}
|
||||
#ifdef ATIS_TEST
|
||||
cout << " ****" << endl;
|
||||
cout << transmission << endl;
|
||||
// Note that even if we aren't outputting the transmission
|
||||
// on stdout, you can still see it by pointing a web browser
|
||||
// at the property tree. The second comm radio is:
|
||||
// http://localhost:5400/instrumentation/comm[1]
|
||||
#endif
|
||||
|
||||
// Take the previous English-looking string and munge it to
|
||||
transmission_readable = transmission;
|
||||
// Take the previous readable string and munge it to
|
||||
// be relatively-more acceptable to the primitive tts system.
|
||||
// Note that : ; and . are among the token-delimeters recognized
|
||||
// by the tts system.
|
||||
|
@ -487,3 +508,27 @@ int FGATIS::GenTransmission(const int regen, const int special) {
|
|||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Put the transmission into the property tree,
|
||||
// possibly in multiple places if multiple radios
|
||||
// are tuned to the same ATIS.
|
||||
// You can see it by pointing a web browser
|
||||
// at the property tree. The second comm radio is:
|
||||
// http://localhost:5400/instrumentation/comm[1]
|
||||
//
|
||||
// (Also, if in debug mode, dump it to the console.)
|
||||
void FGATIS::TreeOut(int msg_OK){
|
||||
for (map<string,int>::iterator act = active_on.begin();
|
||||
act != active_on.end();
|
||||
act++){
|
||||
string prop = "/instrumentation/" + act->first + "/atis";
|
||||
globals->get_props()->setStringValue(prop.c_str(),
|
||||
("<pre>\n" + transmission_readable + "</pre>\n").c_str());
|
||||
#ifdef ATIS_TEST
|
||||
if (msg_OK) cout << "**** ATIS active on: " << prop << endl;
|
||||
#endif
|
||||
}
|
||||
#ifdef ATIS_TEST
|
||||
if (msg_OK) cout << transmission_readable << endl;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -39,10 +39,15 @@ typedef std::map<std::string,std::string> MSS;
|
|||
class FGATIS : public FGATC {
|
||||
|
||||
//atc_type type;
|
||||
std::string transmission; // The actual ATIS transmission
|
||||
// This is not stored in default.atis but is generated
|
||||
// from the prevailing conditions when required.
|
||||
|
||||
// The actual ATIS transmission
|
||||
// This is generated from the prevailing conditions when required.
|
||||
// This is the version with markup, suitable for voice synthesis:
|
||||
std::string transmission;
|
||||
|
||||
// Same as above, but in a form more readable as text.
|
||||
std::string transmission_readable;
|
||||
|
||||
// for failure modeling
|
||||
std::string trans_ident; // transmitted ident
|
||||
double old_volume;
|
||||
|
@ -82,9 +87,13 @@ class FGATIS : public FGATC {
|
|||
|
||||
std::string refname; // Holds the refname of a transmission in progress
|
||||
|
||||
int GenTransmission(const int regen,
|
||||
const int special); // Generate the transmission string
|
||||
// Generate the ATIS transmission text:
|
||||
int GenTransmission(const int regen, const int special);
|
||||
|
||||
// Put the text into the property tree
|
||||
// (and in debug mode, print it on the console):
|
||||
void TreeOut(int msgOK);
|
||||
|
||||
friend std::istream& operator>> ( std::istream&, FGATIS& );
|
||||
};
|
||||
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
// NOTE: This file serves as a database.
|
||||
// It is read by some utility programs that synthesize
|
||||
// the library of spoken words.
|
||||
|
||||
#define Q(word) const std::string word(#word);
|
||||
|
||||
|
@ -41,6 +44,7 @@ Q(broken)
|
|||
Q(overcast)
|
||||
Q(thin)
|
||||
Q(Sky_condition)
|
||||
Q(Sky)
|
||||
Q(Ceiling)
|
||||
Q(minus)
|
||||
Q(dewpoint)
|
||||
|
@ -51,6 +55,8 @@ Q(one_half)
|
|||
Q(three_quarters)
|
||||
Q(one_and_one_half)
|
||||
Q(Altimeter)
|
||||
Q(QNH)
|
||||
Q(millibars)
|
||||
Q(Landing_and_departing_runway)
|
||||
Q(On_initial_contact_advise_you_have_information)
|
||||
Q(This_is)
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// NOTE: This file serves as a database.
|
||||
// It is read by some utility programs that synthesize
|
||||
// the library of spoken words.
|
||||
|
||||
REMAP(Intl, International)
|
||||
REMAP(Rgnl, Regional)
|
||||
REMAP(Co, County)
|
||||
|
|
Loading…
Reference in a new issue