1
0
Fork 0
- METAR changes caused strong aircraft movements if the station temperature or field elevation changed. Temperature and dewpoint are now also slowly interpolated to reach the new value.
- Probably unnoticed bug: calculation of the interpolation speed was wrong.
- some minor code-cleanup
This commit is contained in:
torsten 2010-03-24 14:25:36 +00:00 committed by Tim Moore
parent 89023eda69
commit 26a72a9ee2
2 changed files with 72 additions and 41 deletions

View file

@ -273,11 +273,13 @@ FGMetarCtrl::FGMetarCtrl( SGSubsystem * environmentCtrl )
metar_valid(false), metar_valid(false),
setup_winds_aloft(true), setup_winds_aloft(true),
wind_interpolation_required(true), wind_interpolation_required(true),
metar_sealevel_temperature(15.0),
metar_sealevel_dewpoint(5.0),
// Interpolation constant definitions. // Interpolation constant definitions.
EnvironmentUpdatePeriodSec( 0.2 ),
MaxWindChangeKtsSec( 0.2 ), MaxWindChangeKtsSec( 0.2 ),
MaxVisChangePercentSec( 0.05 ), MaxVisChangePercentSec( 0.05 ),
MaxPressureChangeInHgSec( 0.0033 ), MaxPressureChangeInHgSec( 0.0005 ), // approx 1hpa/min
MaxTemperatureChangeDegcSec(10.0/60.0), // approx 10degc/min
MaxCloudAltitudeChangeFtSec( 20.0 ), MaxCloudAltitudeChangeFtSec( 20.0 ),
MaxCloudThicknessChangeFtSec( 50.0 ), MaxCloudThicknessChangeFtSec( 50.0 ),
MaxCloudInterpolationHeightFt( 5000.0 ), MaxCloudInterpolationHeightFt( 5000.0 ),
@ -311,10 +313,12 @@ FGMetarCtrl::FGMetarCtrl( SGSubsystem * environmentCtrl )
latitude_n = fgGetNode( "/position/latitude-deg", true ); latitude_n = fgGetNode( "/position/latitude-deg", true );
environment_clouds_n = fgGetNode("/environment/clouds"); environment_clouds_n = fgGetNode("/environment/clouds");
boundary_wind_speed_n = fgGetNode("/environment/config/boundary/entry/wind-speed-kt"); boundary_wind_speed_n = fgGetNode("/environment/config/boundary/entry/wind-speed-kt", true );
boundary_wind_from_heading_n = fgGetNode("/environment/config/boundary/entry/wind-from-heading-deg"); boundary_wind_from_heading_n = fgGetNode("/environment/config/boundary/entry/wind-from-heading-deg", true );
boundary_visibility_n = fgGetNode("/environment/config/boundary/entry/visibility-m"); boundary_visibility_n = fgGetNode("/environment/config/boundary/entry/visibility-m", true );
boundary_sea_level_pressure_n = fgGetNode("/environment/config/boundary/entry/pressure-sea-level-inhg"); boundary_sea_level_pressure_n = fgGetNode("/environment/config/boundary/entry/pressure-sea-level-inhg", true );
boundary_sea_level_temperature_n = fgGetNode("/environment/config/boundary/entry/temperature-sea-level-degc", true );
boundary_sea_level_dewpoint_n = fgGetNode("/environment/config/boundary/entry/dewpoint-sea-level-degc", true );
} }
FGMetarCtrl::~FGMetarCtrl () FGMetarCtrl::~FGMetarCtrl ()
@ -336,22 +340,26 @@ void FGMetarCtrl::unbind ()
} }
// use a "command" to set station temp at station elevation // use a "command" to set station temp at station elevation
static void set_temp_at_altitude( float temp_degc, float altitude_ft ) { static void set_temp_at_altitude( double temp_degc, double altitude_ft ) {
SGPropertyNode args; SGPropertyNode args;
SGPropertyNode *node = args.getNode("temp-degc", 0, true); SGPropertyNode *node = args.getNode("temp-degc", 0, true);
node->setFloatValue( temp_degc ); node->setDoubleValue( temp_degc );
node = args.getNode("altitude-ft", 0, true); node = args.getNode("altitude-ft", 0, true);
node->setFloatValue( altitude_ft ); node->setDoubleValue( altitude_ft );
globals->get_commands()->execute("set-outside-air-temp-degc", &args); globals->get_commands()->execute( altitude_ft == 0.0 ?
"set-sea-level-air-temp-degc" :
"set-outside-air-temp-degc", &args);
} }
static void set_dewpoint_at_altitude( float dewpoint_degc, float altitude_ft ) { static void set_dewpoint_at_altitude( double dewpoint_degc, double altitude_ft ) {
SGPropertyNode args; SGPropertyNode args;
SGPropertyNode *node = args.getNode("dewpoint-degc", 0, true); SGPropertyNode *node = args.getNode("dewpoint-degc", 0, true);
node->setFloatValue( dewpoint_degc ); node->setDoubleValue( dewpoint_degc );
node = args.getNode("altitude-ft", 0, true); node = args.getNode("altitude-ft", 0, true);
node->setFloatValue( altitude_ft ); node->setDoubleValue( altitude_ft );
globals->get_commands()->execute("set-dewpoint-temp-degc", &args); globals->get_commands()->execute( altitude_ft == 0.0 ?
"set-dewpoint-sea-level-air-temp-degc" :
"set-dewpoint-temp-degc", &args);
} }
/* /*
@ -403,10 +411,8 @@ static void setupWind( bool setup_aloft, double dir, double speed, double gust )
setupWindBranch( "aloft", dir, speed, gust ); setupWindBranch( "aloft", dir, speed, gust );
} }
double FGMetarCtrl::interpolate_val(double currentval, double requiredval, double dt) double FGMetarCtrl::interpolate_val(double currentval, double requiredval, double dval )
{ {
double dval = EnvironmentUpdatePeriodSec * dt;
if (fabs(currentval - requiredval) < dval) return requiredval; if (fabs(currentval - requiredval) < dval) return requiredval;
if (currentval < requiredval) return (currentval + dval); if (currentval < requiredval) return (currentval + dval);
if (currentval > requiredval) return (currentval - dval); if (currentval > requiredval) return (currentval - dval);
@ -448,13 +454,12 @@ static inline double convert_to_180( double d )
static double reducePressureSl(double metarPressure, double fieldHt, static double reducePressureSl(double metarPressure, double fieldHt,
double fieldTemp) double fieldTemp)
{ {
double elev = fieldHt * SG_FEET_TO_METER; double elev = fieldHt * SG_FEET_TO_METER;
double fieldPressure double fieldPressure
= FGAtmo::fieldPressure(elev, metarPressure * atmodel::inHg); = FGAtmo::fieldPressure(elev, metarPressure * atmodel::inHg);
double slPressure = P_layer(0, elev, fieldPressure, double slPressure = P_layer(0, elev, fieldPressure,
fieldTemp + atmodel::freezing, fieldTemp + atmodel::freezing, atmodel::ISA::lam0);
atmodel::ISA::lam0); return slPressure / atmodel::inHg;
return slPressure / atmodel::inHg;
} }
void void
@ -468,7 +473,7 @@ FGMetarCtrl::update(double dt)
bool reinit_required = false; bool reinit_required = false;
bool layer_rebuild_required = false; bool layer_rebuild_required = false;
double station_elevation_ft = station_elevation_n->getDoubleValue(); double station_elevation_ft = station_elevation_n->getDoubleValue();
if (first_update) { if (first_update) {
double dir = base_wind_dir_n->getDoubleValue()+magnetic_variation_n->getDoubleValue(); double dir = base_wind_dir_n->getDoubleValue()+magnetic_variation_n->getDoubleValue();
@ -479,11 +484,14 @@ FGMetarCtrl::update(double dt)
double metarvis = min_visibility_n->getDoubleValue(); double metarvis = min_visibility_n->getDoubleValue();
fgDefaultWeatherValue("visibility-m", metarvis); fgDefaultWeatherValue("visibility-m", metarvis);
set_temp_at_altitude(temperature_n->getDoubleValue(), station_elevation_ft);
set_dewpoint_at_altitude(dewpoint_n->getDoubleValue(), station_elevation_ft);
double metarpressure = pressure_n->getDoubleValue(); double metarpressure = pressure_n->getDoubleValue();
fgDefaultWeatherValue("pressure-sea-level-inhg", fgDefaultWeatherValue("pressure-sea-level-inhg",
reducePressureSl(metarpressure, reducePressureSl(metarpressure,
station_elevation_ft, station_elevation_ft,
temperature_n->getDoubleValue())); temperature_n->getDoubleValue()));
// We haven't already loaded a METAR, so apply it immediately. // We haven't already loaded a METAR, so apply it immediately.
vector<SGPropertyNode_ptr> layers = clouds_n->getChildren("layer"); vector<SGPropertyNode_ptr> layers = clouds_n->getChildren("layer");
@ -543,8 +551,8 @@ FGMetarCtrl::update(double dt)
double maxdy = dy * MaxWindChangeKtsSec; double maxdy = dy * MaxWindChangeKtsSec;
// Interpolate each component separately. // Interpolate each component separately.
current[0] = interpolate_val(current[0], metar[0], maxdx); current[0] = interpolate_val(current[0], metar[0], maxdx*dt);
current[1] = interpolate_val(current[1], metar[1], maxdy); current[1] = interpolate_val(current[1], metar[1], maxdy*dt);
// Now convert back to polar coordinates. // Now convert back to polar coordinates.
if ((fabs(current[0]) > 0.1) || (fabs(current[1]) > 0.1)) { if ((fabs(current[0]) > 0.1) || (fabs(current[1]) > 0.1)) {
@ -615,7 +623,7 @@ FGMetarCtrl::update(double dt)
double currentxval = log(1000.0 + vis); double currentxval = log(1000.0 + vis);
double metarxval = log(1000.0 + metarvis); double metarxval = log(1000.0 + metarvis);
currentxval = interpolate_val(currentxval, metarxval, MaxVisChangePercentSec); currentxval = interpolate_val(currentxval, metarxval, MaxVisChangePercentSec*dt);
// Now convert back from an X-value to a straightforward visibility. // Now convert back from an X-value to a straightforward visibility.
vis = exp(currentxval) - 1000.0; vis = exp(currentxval) - 1000.0;
@ -625,15 +633,28 @@ FGMetarCtrl::update(double dt)
double pressure = boundary_sea_level_pressure_n->getDoubleValue(); double pressure = boundary_sea_level_pressure_n->getDoubleValue();
double metarpressure = pressure_n->getDoubleValue(); double metarpressure = pressure_n->getDoubleValue();
double newpressure = reducePressureSl(metarpressure, double newpressure = reducePressureSl(metarpressure,
station_elevation_ft, station_elevation_ft,
temperature_n->getDoubleValue()); temperature_n->getDoubleValue());
if( pressure != newpressure ) { if( pressure != newpressure ) {
pressure = interpolate_val( pressure, newpressure, MaxPressureChangeInHgSec ); pressure = interpolate_val( pressure, newpressure, MaxPressureChangeInHgSec*dt );
fgDefaultWeatherValue("pressure-sea-level-inhg", pressure); fgDefaultWeatherValue("pressure-sea-level-inhg", pressure);
reinit_required = true; reinit_required = true;
} }
{
double temperature = boundary_sea_level_temperature_n->getDoubleValue();
double dewpoint = boundary_sea_level_dewpoint_n->getDoubleValue();
if( metar_sealevel_temperature != temperature ) {
temperature = interpolate_val( temperature, metar_sealevel_temperature, MaxTemperatureChangeDegcSec*dt );
set_temp_at_altitude( temperature, 0.0 );
}
if( metar_sealevel_dewpoint != dewpoint ) {
dewpoint = interpolate_val( dewpoint, metar_sealevel_dewpoint, MaxTemperatureChangeDegcSec*dt );
set_dewpoint_at_altitude( dewpoint, 0.0 );
}
}
// Set the cloud layers by interpolating over the METAR versions. // Set the cloud layers by interpolating over the METAR versions.
vector<SGPropertyNode_ptr> layers = clouds_n->getChildren("layer"); vector<SGPropertyNode_ptr> layers = clouds_n->getChildren("layer");
vector<SGPropertyNode_ptr>::const_iterator layer; vector<SGPropertyNode_ptr>::const_iterator layer;
@ -682,7 +703,7 @@ FGMetarCtrl::update(double dt)
} else { } else {
// Interpolate the other values in the usual way // Interpolate the other values in the usual way
if (current_alt != required_alt) { if (current_alt != required_alt) {
current_alt = interpolate_val(current_alt, required_alt, MaxCloudAltitudeChangeFtSec); current_alt = interpolate_val(current_alt, required_alt, MaxCloudAltitudeChangeFtSec*dt);
target->setDoubleValue("elevation-ft", current_alt); target->setDoubleValue("elevation-ft", current_alt);
} }
@ -691,15 +712,12 @@ FGMetarCtrl::update(double dt)
if (current_thickness != required_thickness) { if (current_thickness != required_thickness) {
current_thickness = interpolate_val(current_thickness, current_thickness = interpolate_val(current_thickness,
required_thickness, required_thickness,
MaxCloudThicknessChangeFtSec); MaxCloudThicknessChangeFtSec*dt);
thickness->setDoubleValue(current_thickness); thickness->setDoubleValue(current_thickness);
} }
} }
} }
} }
set_temp_at_altitude(temperature_n->getDoubleValue(), station_elevation_ft);
set_dewpoint_at_altitude(dewpoint_n->getDoubleValue(), station_elevation_ft);
//TODO: check if temperature/dewpoint have changed. This requires reinit.
// Force an update of the 3D clouds // Force an update of the 3D clouds
if( layer_rebuild_required ) if( layer_rebuild_required )
@ -783,6 +801,15 @@ void FGMetarCtrl::set_metar( const char * metar_string )
station_elevation_n->setDoubleValue( station_elevation_ft ); station_elevation_n->setDoubleValue( station_elevation_ft );
{ // calculate sea level temperature and dewpoint
FGEnvironment dummy; // instantiate a dummy so we can leech a method
dummy.set_elevation_ft( station_elevation_ft );
dummy.set_temperature_degc( temperature_n->getDoubleValue() );
dummy.set_dewpoint_degc( dewpoint_n->getDoubleValue() );
metar_sealevel_temperature = dummy.get_temperature_sea_level_degc();
metar_sealevel_dewpoint = dummy.get_dewpoint_sea_level_degc();
}
vector<SGMetarCloud> cv = m->getClouds(); vector<SGMetarCloud> cv = m->getClouds();
vector<SGMetarCloud>::const_iterator cloud, cloud_end = cv.end(); vector<SGMetarCloud>::const_iterator cloud, cloud_end = cv.end();

View file

@ -152,12 +152,14 @@ private:
bool first_update; bool first_update;
bool wind_interpolation_required; bool wind_interpolation_required;
string metar; string metar;
double metar_sealevel_temperature;
double metar_sealevel_dewpoint;
double interpolate_prop(const char * currentname, const char * requiredname, double dvalue); double interpolate_prop(const char * currentname, const char * requiredname, double dvalue);
double interpolate_val(double currentval, double requiredval, double dvalue); double interpolate_val(double currentval, double requiredval, double dvalue);
const double EnvironmentUpdatePeriodSec; // Seconds between interpolations
const double MaxWindChangeKtsSec; // Max wind change in kts/sec const double MaxWindChangeKtsSec; // Max wind change in kts/sec
const double MaxVisChangePercentSec; // Max visibility change in %/sec const double MaxVisChangePercentSec; // Max visibility change in %/sec
const double MaxPressureChangeInHgSec; // Max pressure change in InHg/sec const double MaxPressureChangeInHgSec; // Max pressure change in InHg/sec
const double MaxTemperatureChangeDegcSec; // Max temperature change in degc/s
const double MaxCloudAltitudeChangeFtSec; // Max cloud altitude change in ft/s const double MaxCloudAltitudeChangeFtSec; // Max cloud altitude change in ft/s
const double MaxCloudThicknessChangeFtSec; // Max cloud thickness change in ft/s const double MaxCloudThicknessChangeFtSec; // Max cloud thickness change in ft/s
const double MaxCloudInterpolationHeightFt; // Max distance from aircraft to const double MaxCloudInterpolationHeightFt; // Max distance from aircraft to
@ -200,6 +202,8 @@ private:
SGPropertyNode_ptr boundary_wind_from_heading_n; SGPropertyNode_ptr boundary_wind_from_heading_n;
SGPropertyNode_ptr boundary_visibility_n; SGPropertyNode_ptr boundary_visibility_n;
SGPropertyNode_ptr boundary_sea_level_pressure_n; SGPropertyNode_ptr boundary_sea_level_pressure_n;
SGPropertyNode_ptr boundary_sea_level_temperature_n;
SGPropertyNode_ptr boundary_sea_level_dewpoint_n;
private: private:
}; };