1
0
Fork 0

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:
Dave Luff 2011-01-05 00:27:18 +00:00
parent b5d2e734d1
commit dd690909af
4 changed files with 110 additions and 46 deletions

View file

@ -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
}

View file

@ -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& );
};

View file

@ -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)

View file

@ -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)