Add variable winds (direction and gusts) for the boundary layer if defined in METAR.
This commit is contained in:
parent
1873346d18
commit
ab4928f7a9
6 changed files with 338 additions and 189 deletions
|
@ -9,6 +9,7 @@ libEnvironment_a_SOURCES = \
|
||||||
environment_mgr.cxx environment_mgr.hxx \
|
environment_mgr.cxx environment_mgr.hxx \
|
||||||
environment_ctrl.cxx environment_ctrl.hxx \
|
environment_ctrl.cxx environment_ctrl.hxx \
|
||||||
fgmetar.cxx fgmetar.hxx fgclouds.cxx fgclouds.hxx \
|
fgmetar.cxx fgmetar.hxx fgclouds.cxx fgclouds.hxx \
|
||||||
|
fgwind.cxx fgwind.hxx \
|
||||||
atmosphere.cxx atmosphere.hxx \
|
atmosphere.cxx atmosphere.hxx \
|
||||||
precipitation_mgr.cxx precipitation_mgr.hxx \
|
precipitation_mgr.cxx precipitation_mgr.hxx \
|
||||||
ridge_lift.cxx ridge_lift.hxx
|
ridge_lift.cxx ridge_lift.hxx
|
||||||
|
|
|
@ -133,35 +133,49 @@ FGInterpolateEnvironmentCtrl::init ()
|
||||||
void
|
void
|
||||||
FGInterpolateEnvironmentCtrl::reinit ()
|
FGInterpolateEnvironmentCtrl::reinit ()
|
||||||
{
|
{
|
||||||
// TODO: do we really need to throw away the old tables on reinit? Better recycle
|
|
||||||
unsigned int i;
|
|
||||||
for (i = 0; i < _boundary_table.size(); i++)
|
|
||||||
delete _boundary_table[i];
|
|
||||||
for (i = 0; i < _aloft_table.size(); i++)
|
|
||||||
delete _aloft_table[i];
|
|
||||||
_boundary_table.clear();
|
|
||||||
_aloft_table.clear();
|
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FGInterpolateEnvironmentCtrl::read_table (const SGPropertyNode * node, vector<bucket *> &table)
|
FGInterpolateEnvironmentCtrl::read_table (const SGPropertyNode * node, vector<bucket *> &table)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < node->nChildren(); i++) {
|
double last_altitude_ft = 0.0;
|
||||||
|
double sort_required = false;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < node->nChildren(); i++) {
|
||||||
const SGPropertyNode * child = node->getChild(i);
|
const SGPropertyNode * child = node->getChild(i);
|
||||||
if ( strcmp(child->getName(), "entry") == 0
|
if ( strcmp(child->getName(), "entry") == 0
|
||||||
&& child->getStringValue("elevation-ft", "")[0] != '\0'
|
&& child->getStringValue("elevation-ft", "")[0] != '\0'
|
||||||
&& ( child->getDoubleValue("elevation-ft") > 0.1 || i == 0 ) )
|
&& ( child->getDoubleValue("elevation-ft") > 0.1 || i == 0 ) )
|
||||||
{
|
{
|
||||||
bucket * b = new bucket;
|
bucket * b;
|
||||||
|
if( i < table.size() ) {
|
||||||
|
// recycle existing bucket
|
||||||
|
b = table[i];
|
||||||
|
} else {
|
||||||
|
// more nodes than buckets in table, add a new one
|
||||||
|
b = new bucket;
|
||||||
|
table.push_back(b);
|
||||||
|
}
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
b->environment.copy(table[i-1]->environment);
|
b->environment.copy(table[i-1]->environment);
|
||||||
b->environment.read(child);
|
b->environment.read(child);
|
||||||
b->altitude_ft = b->environment.get_elevation_ft();
|
b->altitude_ft = b->environment.get_elevation_ft();
|
||||||
table.push_back(b);
|
|
||||||
|
// check, if altitudes are in ascending order
|
||||||
|
if( b->altitude_ft < last_altitude_ft )
|
||||||
|
sort_required = true;
|
||||||
|
last_altitude_ft = b->altitude_ft;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sort(table.begin(), table.end(), bucket::lessThan);
|
// remove leftover buckets
|
||||||
|
vector<bucket*>::iterator it = table.begin() + i;
|
||||||
|
while( it != table.end() )
|
||||||
|
table.erase( it );
|
||||||
|
|
||||||
|
if( sort_required )
|
||||||
|
sort(table.begin(), table.end(), bucket::lessThan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -181,6 +195,8 @@ FGInterpolateEnvironmentCtrl::update (double delta_time_sec)
|
||||||
do_interpolate(_boundary_table, altitude_agl_ft, _environment);
|
do_interpolate(_boundary_table, altitude_agl_ft, _environment);
|
||||||
return;
|
return;
|
||||||
} else if ((boundary_limit + boundary_transition) >= altitude_agl_ft) {
|
} else if ((boundary_limit + boundary_transition) >= altitude_agl_ft) {
|
||||||
|
//TODO: this is 500ft above the top altitude of boundary layer
|
||||||
|
//shouldn't this be +/-250 ft off of the top altitude?
|
||||||
// both tables
|
// both tables
|
||||||
do_interpolate(_boundary_table, altitude_agl_ft, &env1);
|
do_interpolate(_boundary_table, altitude_agl_ft, &env1);
|
||||||
do_interpolate(_aloft_table, altitude_ft, &env2);
|
do_interpolate(_aloft_table, altitude_ft, &env2);
|
||||||
|
@ -250,6 +266,7 @@ FGMetarCtrl::FGMetarCtrl( SGSubsystem * environmentCtrl )
|
||||||
station_elevation_ft(0.0),
|
station_elevation_ft(0.0),
|
||||||
metar_valid(false),
|
metar_valid(false),
|
||||||
setup_winds_aloft(true),
|
setup_winds_aloft(true),
|
||||||
|
wind_interpolation_required(true),
|
||||||
// Interpolation constant definitions.
|
// Interpolation constant definitions.
|
||||||
EnvironmentUpdatePeriodSec( 0.2 ),
|
EnvironmentUpdatePeriodSec( 0.2 ),
|
||||||
MaxWindChangeKtsSec( 0.2 ),
|
MaxWindChangeKtsSec( 0.2 ),
|
||||||
|
@ -260,6 +277,8 @@ FGMetarCtrl::FGMetarCtrl( SGSubsystem * environmentCtrl )
|
||||||
MaxCloudInterpolationHeightFt( 5000.0 ),
|
MaxCloudInterpolationHeightFt( 5000.0 ),
|
||||||
MaxCloudInterpolationDeltaFt( 4000.0 )
|
MaxCloudInterpolationDeltaFt( 4000.0 )
|
||||||
{
|
{
|
||||||
|
windModulator = new FGBasicWindModulator();
|
||||||
|
|
||||||
metar_base_n = fgGetNode( "/environment/metar", true );
|
metar_base_n = fgGetNode( "/environment/metar", true );
|
||||||
station_id_n = metar_base_n->getNode("station-id", true );
|
station_id_n = metar_base_n->getNode("station-id", true );
|
||||||
station_elevation_n = metar_base_n->getNode("station-elevation-ft", true );
|
station_elevation_n = metar_base_n->getNode("station-elevation-ft", true );
|
||||||
|
@ -268,7 +287,7 @@ FGMetarCtrl::FGMetarCtrl( SGSubsystem * environmentCtrl )
|
||||||
base_wind_range_from_n = metar_base_n->getNode("base-wind-range-from", true );
|
base_wind_range_from_n = metar_base_n->getNode("base-wind-range-from", true );
|
||||||
base_wind_range_to_n = metar_base_n->getNode("base-wind-range-to", true );
|
base_wind_range_to_n = metar_base_n->getNode("base-wind-range-to", true );
|
||||||
base_wind_speed_n = metar_base_n->getNode("base-wind-speed-kt", true );
|
base_wind_speed_n = metar_base_n->getNode("base-wind-speed-kt", true );
|
||||||
base_wind_dir_n = metar_base_n->getNode("base-wind-dir-deg", true );
|
base_wind_dir_n = metar_base_n->getNode("base-wind-dir-deg", true );
|
||||||
gust_wind_speed_n = metar_base_n->getNode("gust-wind-speed-kt", true );
|
gust_wind_speed_n = metar_base_n->getNode("gust-wind-speed-kt", true );
|
||||||
temperature_n = metar_base_n->getNode("temperature-degc", true );
|
temperature_n = metar_base_n->getNode("temperature-degc", true );
|
||||||
dewpoint_n = metar_base_n->getNode("dewpoint-degc", true );
|
dewpoint_n = metar_base_n->getNode("dewpoint-degc", true );
|
||||||
|
@ -296,16 +315,16 @@ FGMetarCtrl::~FGMetarCtrl ()
|
||||||
|
|
||||||
void FGMetarCtrl::bind ()
|
void FGMetarCtrl::bind ()
|
||||||
{
|
{
|
||||||
fgTie("/environment/metar/valid", this, &FGMetarCtrl::get_valid );
|
fgTie("/environment/metar/valid", this, &FGMetarCtrl::get_valid );
|
||||||
fgTie("/environment/params/metar-updates-environment", this, &FGMetarCtrl::get_enabled, &FGMetarCtrl::set_enabled );
|
fgTie("/environment/params/metar-updates-environment", this, &FGMetarCtrl::get_enabled, &FGMetarCtrl::set_enabled );
|
||||||
fgTie("/environment/params/metar-updates-winds-aloft", this, &FGMetarCtrl::get_setup_winds_aloft, &FGMetarCtrl::set_setup_winds_aloft );
|
fgTie("/environment/params/metar-updates-winds-aloft", this, &FGMetarCtrl::get_setup_winds_aloft, &FGMetarCtrl::set_setup_winds_aloft );
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGMetarCtrl::unbind ()
|
void FGMetarCtrl::unbind ()
|
||||||
{
|
{
|
||||||
fgUntie("/environment/metar/valid");
|
fgUntie("/environment/metar/valid");
|
||||||
fgUntie("/environment/params/metar-updates-environment");
|
fgUntie("/environment/params/metar-updates-environment");
|
||||||
fgUntie("/environment/params/metar-updates-winds-aloft");
|
fgUntie("/environment/params/metar-updates-winds-aloft");
|
||||||
}
|
}
|
||||||
|
|
||||||
// use a "command" to set station temp at station elevation
|
// use a "command" to set station temp at station elevation
|
||||||
|
@ -369,9 +388,11 @@ static void setupWindBranch( string branchName, double dir, double speed, double
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setupWind( bool setup_aloft, double dir, double speed, double gust )
|
static void setupWind( bool setup_boundary, bool setup_aloft, double dir, double speed, double gust )
|
||||||
{
|
{
|
||||||
setupWindBranch( "boundary", dir, speed, gust );
|
if( setup_boundary )
|
||||||
|
setupWindBranch( "boundary", dir, speed, gust );
|
||||||
|
|
||||||
if( setup_aloft )
|
if( setup_aloft )
|
||||||
setupWindBranch( "aloft", dir, speed, gust );
|
setupWindBranch( "aloft", dir, speed, gust );
|
||||||
}
|
}
|
||||||
|
@ -390,6 +411,7 @@ void
|
||||||
FGMetarCtrl::init ()
|
FGMetarCtrl::init ()
|
||||||
{
|
{
|
||||||
first_update = true;
|
first_update = true;
|
||||||
|
wind_interpolation_required = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -398,12 +420,25 @@ FGMetarCtrl::reinit ()
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline double convert_to_360( double d )
|
||||||
|
{
|
||||||
|
if( d < 0.0 ) return d + 360.0;
|
||||||
|
if( d >= 360.0 ) return d - 360.0;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline double convert_to_180( double d )
|
||||||
|
{
|
||||||
|
return d > 180.0 ? d - 360.0 : d;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FGMetarCtrl::update(double dt)
|
FGMetarCtrl::update(double dt)
|
||||||
{
|
{
|
||||||
if( dt <= 0 || !metar_valid ||!enabled)
|
if( dt <= 0 || !metar_valid ||!enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
windModulator->update(dt);
|
||||||
// Interpolate the current configuration closer to the actual METAR
|
// Interpolate the current configuration closer to the actual METAR
|
||||||
|
|
||||||
bool reinit_required = false;
|
bool reinit_required = false;
|
||||||
|
@ -413,7 +448,7 @@ FGMetarCtrl::update(double dt)
|
||||||
double dir = base_wind_dir_n->getDoubleValue();
|
double dir = base_wind_dir_n->getDoubleValue();
|
||||||
double speed = base_wind_speed_n->getDoubleValue();
|
double speed = base_wind_speed_n->getDoubleValue();
|
||||||
double gust = gust_wind_speed_n->getDoubleValue();
|
double gust = gust_wind_speed_n->getDoubleValue();
|
||||||
setupWind(setup_winds_aloft, dir, speed, gust);
|
setupWind(true, setup_winds_aloft, dir, speed, gust);
|
||||||
|
|
||||||
double metarvis = min_visibility_n->getDoubleValue();
|
double metarvis = min_visibility_n->getDoubleValue();
|
||||||
fgDefaultWeatherValue("visibility-m", metarvis);
|
fgDefaultWeatherValue("visibility-m", metarvis);
|
||||||
|
@ -444,61 +479,92 @@ FGMetarCtrl::update(double dt)
|
||||||
layer_rebuild_required = true;
|
layer_rebuild_required = true;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Generate interpolated values between the METAR and the current
|
if( wind_interpolation_required ) {
|
||||||
// configuration.
|
// Generate interpolated values between the METAR and the current
|
||||||
|
// configuration.
|
||||||
|
|
||||||
// Pick up the METAR wind values and convert them into a vector.
|
// Pick up the METAR wind values and convert them into a vector.
|
||||||
double metar[2];
|
double metar[2];
|
||||||
double metar_speed = base_wind_speed_n->getDoubleValue();
|
double metar_speed = base_wind_speed_n->getDoubleValue();
|
||||||
double metar_heading = base_wind_dir_n->getDoubleValue();
|
double metar_heading = base_wind_dir_n->getDoubleValue();
|
||||||
|
|
||||||
metar[0] = metar_speed * sin(metar_heading * SG_DEGREES_TO_RADIANS );
|
metar[0] = metar_speed * sin(metar_heading * SG_DEGREES_TO_RADIANS );
|
||||||
metar[1] = metar_speed * cos(metar_heading * SG_DEGREES_TO_RADIANS);
|
metar[1] = metar_speed * cos(metar_heading * SG_DEGREES_TO_RADIANS);
|
||||||
|
|
||||||
// Convert the current wind values and convert them into a vector
|
// Convert the current wind values and convert them into a vector
|
||||||
double current[2];
|
double current[2];
|
||||||
double speed = boundary_wind_speed_n->getDoubleValue();
|
double speed = boundary_wind_speed_n->getDoubleValue();
|
||||||
double dir_from = boundary_wind_from_heading_n->getDoubleValue();;
|
double dir_from = boundary_wind_from_heading_n->getDoubleValue();;
|
||||||
|
|
||||||
current[0] = speed * sin(dir_from * SG_DEGREES_TO_RADIANS );
|
current[0] = speed * sin(dir_from * SG_DEGREES_TO_RADIANS );
|
||||||
current[1] = speed * cos(dir_from * SG_DEGREES_TO_RADIANS );
|
current[1] = speed * cos(dir_from * SG_DEGREES_TO_RADIANS );
|
||||||
|
|
||||||
// Determine the maximum component-wise value that the wind can change.
|
// Determine the maximum component-wise value that the wind can change.
|
||||||
// First we determine the fraction in the X and Y component, then
|
// First we determine the fraction in the X and Y component, then
|
||||||
// factor by the maximum wind change.
|
// factor by the maximum wind change.
|
||||||
double x = fabs(current[0] - metar[0]);
|
double x = fabs(current[0] - metar[0]);
|
||||||
double y = fabs(current[1] - metar[1]);
|
double y = fabs(current[1] - metar[1]);
|
||||||
|
|
||||||
// only interpolate if we have a difference
|
// only interpolate if we have a difference
|
||||||
if (x + y > 0) {
|
if (x + y > 0.01 ) {
|
||||||
double dx = x / (x + y);
|
double dx = x / (x + y);
|
||||||
double dy = 1 - dx;
|
double dy = 1 - dx;
|
||||||
|
|
||||||
double maxdx = dx * MaxWindChangeKtsSec;
|
double maxdx = dx * MaxWindChangeKtsSec;
|
||||||
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);
|
||||||
current[1] = interpolate_val(current[1], metar[1], maxdy);
|
current[1] = interpolate_val(current[1], metar[1], maxdy);
|
||||||
|
|
||||||
// Now convert back to polar coordinates.
|
// Now convert back to polar coordinates.
|
||||||
if ((current[0] == 0.0) && (current[1] == 0.0)) {
|
if ((current[0] == 0.0) && (current[1] == 0.0)) {
|
||||||
// Special case where there is no wind (otherwise atan2 barfs)
|
// Special case where there is no wind (otherwise atan2 barfs)
|
||||||
speed = 0.0;
|
speed = 0.0;
|
||||||
} else {
|
} else {
|
||||||
// Some real wind to convert back from. Work out the speed
|
// Some real wind to convert back from. Work out the speed
|
||||||
// and direction value in degrees.
|
// and direction value in degrees.
|
||||||
speed = sqrt((current[0] * current[0]) + (current[1] * current[1]));
|
speed = sqrt((current[0] * current[0]) + (current[1] * current[1]));
|
||||||
dir_from = (atan2(current[0], current[1]) * SG_RADIANS_TO_DEGREES );
|
dir_from = (atan2(current[0], current[1]) * SG_RADIANS_TO_DEGREES );
|
||||||
|
|
||||||
// Normalize the direction.
|
// Normalize the direction.
|
||||||
if (dir_from < 0.0)
|
if (dir_from < 0.0)
|
||||||
dir_from += 360.0;
|
dir_from += 360.0;
|
||||||
|
|
||||||
SG_LOG( SG_GENERAL, SG_DEBUG, "Wind : " << dir_from << "@" << speed);
|
SG_LOG( SG_GENERAL, SG_DEBUG, "Wind : " << dir_from << "@" << speed);
|
||||||
|
}
|
||||||
|
double gust = gust_wind_speed_n->getDoubleValue();
|
||||||
|
setupWind(true, setup_winds_aloft, dir_from, speed, gust);
|
||||||
|
reinit_required = true;
|
||||||
|
} else {
|
||||||
|
wind_interpolation_required = false;
|
||||||
}
|
}
|
||||||
double gust = gust_wind_speed_n->getDoubleValue();
|
} else { // if(wind_interpolation_required)
|
||||||
setupWind(setup_winds_aloft, dir_from, speed, gust);
|
// interpolation of wind vector is finished, apply wind
|
||||||
|
// variations and gusts for the boundary layer only
|
||||||
|
|
||||||
|
// start with the main wind direction
|
||||||
|
double wind_dir = base_wind_dir_n->getDoubleValue();
|
||||||
|
double min = convert_to_180(base_wind_range_from_n->getDoubleValue());
|
||||||
|
double max = convert_to_180(base_wind_range_to_n->getDoubleValue());
|
||||||
|
if( max > min ) {
|
||||||
|
// if variable winds configured, modulate the wind direction
|
||||||
|
double f = windModulator->get_direction_offset_norm();
|
||||||
|
wind_dir = min+(max-min)*f;
|
||||||
|
double old = convert_to_180(boundary_wind_from_heading_n->getDoubleValue());
|
||||||
|
wind_dir = convert_to_360(fgGetLowPass(old, wind_dir, dt ));
|
||||||
|
}
|
||||||
|
|
||||||
|
// start with main wind speed
|
||||||
|
double wind_speed = base_wind_speed_n->getDoubleValue();
|
||||||
|
max = gust_wind_speed_n->getDoubleValue();
|
||||||
|
if( max > wind_speed ) {
|
||||||
|
// if gusts are configured, modulate wind magnitude
|
||||||
|
double f = windModulator->get_magnitude_factor_norm();
|
||||||
|
wind_speed = wind_speed+(max-wind_speed)*f;
|
||||||
|
wind_speed = fgGetLowPass(boundary_wind_speed_n->getDoubleValue(), wind_speed, dt );
|
||||||
|
}
|
||||||
|
setupWind(true, false, wind_dir, wind_speed, max);
|
||||||
reinit_required = true;
|
reinit_required = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -595,6 +661,7 @@ FGMetarCtrl::update(double dt)
|
||||||
|
|
||||||
set_temp_at_altitude(temperature_n->getDoubleValue(), station_elevation_ft);
|
set_temp_at_altitude(temperature_n->getDoubleValue(), station_elevation_ft);
|
||||||
set_dewpoint_at_altitude(dewpoint_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 )
|
||||||
|
@ -629,6 +696,8 @@ void FGMetarCtrl::set_metar( const char * metar_string )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wind_interpolation_required = true;
|
||||||
|
|
||||||
min_visibility_n->setDoubleValue( m->getMinVisibility().getVisibility_m() );
|
min_visibility_n->setDoubleValue( m->getMinVisibility().getVisibility_m() );
|
||||||
max_visibility_n->setDoubleValue( m->getMaxVisibility().getVisibility_m() );
|
max_visibility_n->setDoubleValue( m->getMaxVisibility().getVisibility_m() );
|
||||||
|
|
||||||
|
@ -751,8 +820,7 @@ void MetarThread::run()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FGMetarFetcher::FGMetarFetcher()
|
FGMetarFetcher::FGMetarFetcher() :
|
||||||
:
|
|
||||||
#if defined(ENABLE_THREADS)
|
#if defined(ENABLE_THREADS)
|
||||||
metar_thread(NULL),
|
metar_thread(NULL),
|
||||||
#endif
|
#endif
|
||||||
|
@ -764,12 +832,12 @@ FGMetarFetcher::FGMetarFetcher()
|
||||||
{
|
{
|
||||||
longitude_n = fgGetNode( "/position/longitude-deg", true );
|
longitude_n = fgGetNode( "/position/longitude-deg", true );
|
||||||
latitude_n = fgGetNode( "/position/latitude-deg", true );
|
latitude_n = fgGetNode( "/position/latitude-deg", true );
|
||||||
enable_n = fgGetNode( "/environment/params/real-world-weather-fetch", true );
|
enable_n = fgGetNode( "/environment/params/real-world-weather-fetch", true );
|
||||||
|
|
||||||
proxy_host_n = fgGetNode("/sim/presets/proxy/host", true);
|
proxy_host_n = fgGetNode("/sim/presets/proxy/host", true);
|
||||||
proxy_port_n = fgGetNode("/sim/presets/proxy/port", true);
|
proxy_port_n = fgGetNode("/sim/presets/proxy/port", true);
|
||||||
proxy_auth_n = fgGetNode("/sim/presets/proxy/authentication", true);
|
proxy_auth_n = fgGetNode("/sim/presets/proxy/authentication", true);
|
||||||
max_age_n = fgGetNode("/environment/params/metar-max-age-min", true);
|
max_age_n = fgGetNode("/environment/params/metar-max-age-min", true);
|
||||||
|
|
||||||
output_n = fgGetNode("/environment/metar/data", true );
|
output_n = fgGetNode("/environment/metar/data", true );
|
||||||
#if defined(ENABLE_THREADS)
|
#if defined(ENABLE_THREADS)
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
|
|
||||||
#include <Navaids/positioned.hxx>
|
#include <Navaids/positioned.hxx>
|
||||||
#include <Environment/environment.hxx>
|
#include <Environment/environment.hxx>
|
||||||
|
#include "fgwind.hxx"
|
||||||
|
|
||||||
// forward decls
|
// forward decls
|
||||||
class SGPropertyNode;
|
class SGPropertyNode;
|
||||||
|
@ -49,28 +50,28 @@ class FGEnvironmentCtrl : public SGSubsystem
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
FGEnvironmentCtrl ();
|
FGEnvironmentCtrl ();
|
||||||
virtual ~FGEnvironmentCtrl ();
|
virtual ~FGEnvironmentCtrl ();
|
||||||
|
|
||||||
virtual void setEnvironment (FGEnvironment * environment);
|
virtual void setEnvironment (FGEnvironment * environment);
|
||||||
|
|
||||||
virtual const FGEnvironment * getEnvironment () const { return _environment; }
|
virtual const FGEnvironment * getEnvironment () const { return _environment; }
|
||||||
|
|
||||||
virtual void setLongitudeDeg (double lon_deg);
|
virtual void setLongitudeDeg (double lon_deg);
|
||||||
virtual void setLatitudeDeg (double lat_deg);
|
virtual void setLatitudeDeg (double lat_deg);
|
||||||
virtual void setElevationFt (double elev_ft);
|
virtual void setElevationFt (double elev_ft);
|
||||||
virtual void setPosition (double lon_deg, double lat_deg, double elev_ft);
|
virtual void setPosition (double lon_deg, double lat_deg, double elev_ft);
|
||||||
|
|
||||||
virtual double getLongitudeDeg () const { return _lon_deg; }
|
virtual double getLongitudeDeg () const { return _lon_deg; }
|
||||||
virtual double getLatitudeDeg () const { return _lat_deg; }
|
virtual double getLatitudeDeg () const { return _lat_deg; }
|
||||||
virtual double getElevationFt () const { return _elev_ft; }
|
virtual double getElevationFt () const { return _elev_ft; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
FGEnvironment * _environment;
|
FGEnvironment * _environment;
|
||||||
double _lon_deg;
|
double _lon_deg;
|
||||||
double _lat_deg;
|
double _lat_deg;
|
||||||
double _elev_ft;
|
double _elev_ft;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -82,31 +83,31 @@ protected:
|
||||||
class FGInterpolateEnvironmentCtrl : public FGEnvironmentCtrl
|
class FGInterpolateEnvironmentCtrl : public FGEnvironmentCtrl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FGInterpolateEnvironmentCtrl ();
|
FGInterpolateEnvironmentCtrl ();
|
||||||
virtual ~FGInterpolateEnvironmentCtrl ();
|
virtual ~FGInterpolateEnvironmentCtrl ();
|
||||||
|
|
||||||
virtual void init ();
|
virtual void init ();
|
||||||
virtual void reinit ();
|
virtual void reinit ();
|
||||||
virtual void update (double delta_time_sec);
|
virtual void update (double delta_time_sec);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct bucket {
|
struct bucket {
|
||||||
double altitude_ft;
|
double altitude_ft;
|
||||||
FGEnvironment environment;
|
FGEnvironment environment;
|
||||||
bool operator< (const bucket &b) const;
|
bool operator< (const bucket &b) const;
|
||||||
// LessThan predicate for bucket pointers.
|
// LessThan predicate for bucket pointers.
|
||||||
static bool lessThan(bucket *a, bucket *b);
|
static bool lessThan(bucket *a, bucket *b);
|
||||||
};
|
};
|
||||||
|
|
||||||
void read_table (const SGPropertyNode * node, std::vector<bucket *> &table);
|
void read_table (const SGPropertyNode * node, std::vector<bucket *> &table);
|
||||||
void do_interpolate (std::vector<bucket *> &table, double altitude_ft,
|
void do_interpolate (std::vector<bucket *> &table, double altitude_ft,
|
||||||
FGEnvironment * environment);
|
FGEnvironment * environment);
|
||||||
|
|
||||||
FGEnvironment env1, env2; // temporaries
|
FGEnvironment env1, env2; // temporaries
|
||||||
|
|
||||||
std::vector<bucket *> _boundary_table;
|
std::vector<bucket *> _boundary_table;
|
||||||
std::vector<bucket *> _aloft_table;
|
std::vector<bucket *> _aloft_table;
|
||||||
|
|
||||||
SGPropertyNode_ptr altitude_n;
|
SGPropertyNode_ptr altitude_n;
|
||||||
SGPropertyNode_ptr altitude_agl_n;
|
SGPropertyNode_ptr altitude_agl_n;
|
||||||
|
@ -124,15 +125,15 @@ private:
|
||||||
class FGMetarCtrl : public SGSubsystem
|
class FGMetarCtrl : public SGSubsystem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FGMetarCtrl (SGSubsystem * environmentCtrl);
|
FGMetarCtrl (SGSubsystem * environmentCtrl);
|
||||||
virtual ~FGMetarCtrl ();
|
virtual ~FGMetarCtrl ();
|
||||||
|
|
||||||
virtual void init ();
|
virtual void init ();
|
||||||
virtual void reinit ();
|
virtual void reinit ();
|
||||||
virtual void update (double delta_time_sec);
|
virtual void update (double delta_time_sec);
|
||||||
|
|
||||||
void set_metar( const char * metar );
|
void set_metar( const char * metar );
|
||||||
const char * get_metar(void) const;
|
const char * get_metar(void) const;
|
||||||
bool get_valid(void) const { return metar_valid; }
|
bool get_valid(void) const { return metar_valid; }
|
||||||
void set_enabled(bool _enabled) { enabled = _enabled; }
|
void set_enabled(bool _enabled) { enabled = _enabled; }
|
||||||
bool get_enabled(void) const { return enabled; }
|
bool get_enabled(void) const { return enabled; }
|
||||||
|
@ -142,59 +143,62 @@ public:
|
||||||
private:
|
private:
|
||||||
void bind();
|
void bind();
|
||||||
void unbind();
|
void unbind();
|
||||||
bool metar_valid;
|
|
||||||
bool enabled;
|
SGSharedPtr<FGWindModulator> windModulator;
|
||||||
|
bool metar_valid;
|
||||||
|
bool enabled;
|
||||||
bool setup_winds_aloft;
|
bool setup_winds_aloft;
|
||||||
bool first_update;
|
bool first_update;
|
||||||
double station_elevation_ft;
|
bool wind_interpolation_required;
|
||||||
string metar;
|
double station_elevation_ft;
|
||||||
double interpolate_prop(const char * currentname, const char * requiredname, double dvalue);
|
string metar;
|
||||||
double interpolate_val(double currentval, double requiredval, double dvalue);
|
double interpolate_prop(const char * currentname, const char * requiredname, double dvalue);
|
||||||
const double EnvironmentUpdatePeriodSec; // Seconds between interpolations
|
double interpolate_val(double currentval, double requiredval, double dvalue);
|
||||||
const double MaxWindChangeKtsSec; // Max wind change in kts/sec
|
const double EnvironmentUpdatePeriodSec; // Seconds between interpolations
|
||||||
const double MaxVisChangePercentSec; // Max visibility change in %/sec
|
const double MaxWindChangeKtsSec; // Max wind change in kts/sec
|
||||||
const double MaxPressureChangeInHgSec; // Max pressure change in InHg/sec
|
const double MaxVisChangePercentSec; // Max visibility change in %/sec
|
||||||
const double MaxCloudAltitudeChangeFtSec; // Max cloud altitude change in ft/s
|
const double MaxPressureChangeInHgSec; // Max pressure change in InHg/sec
|
||||||
const double MaxCloudThicknessChangeFtSec; // Max cloud thickness change in ft/s
|
const double MaxCloudAltitudeChangeFtSec; // Max cloud altitude change in ft/s
|
||||||
const double MaxCloudInterpolationHeightFt; // Max distance from aircraft to
|
const double MaxCloudThicknessChangeFtSec; // Max cloud thickness change in ft/s
|
||||||
// interpolate at. Any cloud
|
const double MaxCloudInterpolationHeightFt; // Max distance from aircraft to
|
||||||
// changes above this height
|
// interpolate at. Any cloud
|
||||||
// difference are not interpolated
|
// changes above this height
|
||||||
const double MaxCloudInterpolationDeltaFt; // Max difference in altitude to
|
// difference are not interpolated
|
||||||
// interpolate. Any cloud changing height
|
const double MaxCloudInterpolationDeltaFt; // Max difference in altitude to
|
||||||
// by more than this value is not
|
// interpolate. Any cloud changing height
|
||||||
// interpolated
|
// by more than this value is not
|
||||||
|
// interpolated
|
||||||
|
|
||||||
SGSubsystem * _environmentCtrl;
|
SGSubsystem * _environmentCtrl;
|
||||||
|
|
||||||
SGPropertyNode_ptr metar_base_n;
|
SGPropertyNode_ptr metar_base_n;
|
||||||
SGPropertyNode_ptr station_id_n;
|
SGPropertyNode_ptr station_id_n;
|
||||||
SGPropertyNode_ptr station_elevation_n;
|
SGPropertyNode_ptr station_elevation_n;
|
||||||
SGPropertyNode_ptr min_visibility_n;
|
SGPropertyNode_ptr min_visibility_n;
|
||||||
SGPropertyNode_ptr max_visibility_n;
|
SGPropertyNode_ptr max_visibility_n;
|
||||||
SGPropertyNode_ptr base_wind_range_from_n;
|
SGPropertyNode_ptr base_wind_range_from_n;
|
||||||
SGPropertyNode_ptr base_wind_range_to_n;
|
SGPropertyNode_ptr base_wind_range_to_n;
|
||||||
SGPropertyNode_ptr base_wind_dir_n;
|
SGPropertyNode_ptr base_wind_dir_n;
|
||||||
SGPropertyNode_ptr base_wind_speed_n;
|
SGPropertyNode_ptr base_wind_speed_n;
|
||||||
SGPropertyNode_ptr gust_wind_speed_n;
|
SGPropertyNode_ptr gust_wind_speed_n;
|
||||||
SGPropertyNode_ptr temperature_n;
|
SGPropertyNode_ptr temperature_n;
|
||||||
SGPropertyNode_ptr dewpoint_n;
|
SGPropertyNode_ptr dewpoint_n;
|
||||||
SGPropertyNode_ptr humidity_n;
|
SGPropertyNode_ptr humidity_n;
|
||||||
SGPropertyNode_ptr pressure_n;
|
SGPropertyNode_ptr pressure_n;
|
||||||
SGPropertyNode_ptr clouds_n;
|
SGPropertyNode_ptr clouds_n;
|
||||||
SGPropertyNode_ptr environment_clouds_n;
|
SGPropertyNode_ptr environment_clouds_n;
|
||||||
SGPropertyNode_ptr rain_n;
|
SGPropertyNode_ptr rain_n;
|
||||||
SGPropertyNode_ptr hail_n;
|
SGPropertyNode_ptr hail_n;
|
||||||
SGPropertyNode_ptr snow_n;
|
SGPropertyNode_ptr snow_n;
|
||||||
SGPropertyNode_ptr snow_cover_n;
|
SGPropertyNode_ptr snow_cover_n;
|
||||||
SGPropertyNode_ptr ground_elevation_n;
|
SGPropertyNode_ptr ground_elevation_n;
|
||||||
SGPropertyNode_ptr longitude_n;
|
SGPropertyNode_ptr longitude_n;
|
||||||
SGPropertyNode_ptr latitude_n;
|
SGPropertyNode_ptr latitude_n;
|
||||||
|
|
||||||
SGPropertyNode_ptr boundary_wind_speed_n;
|
SGPropertyNode_ptr boundary_wind_speed_n;
|
||||||
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;
|
||||||
private:
|
private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -205,45 +209,45 @@ private:
|
||||||
class FGMetarFetcher : public SGSubsystem
|
class FGMetarFetcher : public SGSubsystem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FGMetarFetcher();
|
FGMetarFetcher();
|
||||||
virtual ~FGMetarFetcher();
|
virtual ~FGMetarFetcher();
|
||||||
|
|
||||||
virtual void init ();
|
virtual void init ();
|
||||||
virtual void reinit ();
|
virtual void reinit ();
|
||||||
virtual void update (double delta_time_sec);
|
virtual void update (double delta_time_sec);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class MetarThread;
|
friend class MetarThread;
|
||||||
#if defined(ENABLE_THREADS)
|
#if defined(ENABLE_THREADS)
|
||||||
/**
|
/**
|
||||||
* FIFO queue which holds a pointer to the metar requests.
|
* FIFO queue which holds a pointer to the metar requests.
|
||||||
*/
|
*/
|
||||||
SGBlockingQueue <string> request_queue;
|
SGBlockingQueue <string> request_queue;
|
||||||
|
|
||||||
OpenThreads::Thread * metar_thread;
|
OpenThreads::Thread * metar_thread;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void fetch( const string & id );
|
void fetch( const string & id );
|
||||||
|
|
||||||
SGPropertyNode_ptr enable_n;
|
SGPropertyNode_ptr enable_n;
|
||||||
|
|
||||||
SGPropertyNode_ptr longitude_n;
|
SGPropertyNode_ptr longitude_n;
|
||||||
SGPropertyNode_ptr latitude_n;
|
SGPropertyNode_ptr latitude_n;
|
||||||
|
|
||||||
SGPropertyNode_ptr proxy_host_n;
|
SGPropertyNode_ptr proxy_host_n;
|
||||||
SGPropertyNode_ptr proxy_port_n;
|
SGPropertyNode_ptr proxy_port_n;
|
||||||
SGPropertyNode_ptr proxy_auth_n;
|
SGPropertyNode_ptr proxy_auth_n;
|
||||||
SGPropertyNode_ptr max_age_n;
|
SGPropertyNode_ptr max_age_n;
|
||||||
|
|
||||||
SGPropertyNode_ptr output_n;
|
SGPropertyNode_ptr output_n;
|
||||||
|
|
||||||
string current_airport_id;
|
string current_airport_id;
|
||||||
double fetch_timer;
|
double fetch_timer;
|
||||||
double search_timer;
|
double search_timer;
|
||||||
double error_timer;
|
double error_timer;
|
||||||
|
|
||||||
long _stale_count;
|
long _stale_count;
|
||||||
long _error_count;
|
long _error_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -52,12 +52,12 @@ FGEnvironmentMgr::FGEnvironmentMgr ()
|
||||||
|
|
||||||
_controller = new FGInterpolateEnvironmentCtrl;
|
_controller = new FGInterpolateEnvironmentCtrl;
|
||||||
_controller->setEnvironment(_environment);
|
_controller->setEnvironment(_environment);
|
||||||
set_subsystem("controller", _controller, 0.5);
|
set_subsystem("controller", _controller, 0.1 );
|
||||||
|
|
||||||
fgClouds = new FGClouds();
|
fgClouds = new FGClouds();
|
||||||
|
|
||||||
_metarcontroller = new FGMetarCtrl(_controller);
|
_metarcontroller = new FGMetarCtrl(_controller );
|
||||||
set_subsystem("metarcontroller", _metarcontroller, 0.25 );
|
set_subsystem("metarcontroller", _metarcontroller, 0.1 );
|
||||||
|
|
||||||
_metarfetcher = new FGMetarFetcher();
|
_metarfetcher = new FGMetarFetcher();
|
||||||
set_subsystem("metarfetcher", _metarfetcher, 1.0 );
|
set_subsystem("metarfetcher", _metarfetcher, 1.0 );
|
||||||
|
|
36
src/Environment/fgwind.cxx
Normal file
36
src/Environment/fgwind.cxx
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#include "fgwind.hxx"
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
FGWindModulator::FGWindModulator() :
|
||||||
|
direction_offset_norm(0.0),
|
||||||
|
magnitude_factor_norm(1.0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FGWindModulator::~FGWindModulator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FGBasicWindModulator::FGBasicWindModulator() :
|
||||||
|
elapsed(0.0),
|
||||||
|
direction_period(17),
|
||||||
|
speed_period(1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FGBasicWindModulator::~FGBasicWindModulator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGBasicWindModulator::update( double dt)
|
||||||
|
{
|
||||||
|
elapsed += dt;
|
||||||
|
double t = elapsed/direction_period;
|
||||||
|
|
||||||
|
direction_offset_norm = (sin(t)*sin(2*t)+sin(t/3)) / 1.75;
|
||||||
|
|
||||||
|
t = elapsed/speed_period;
|
||||||
|
magnitude_factor_norm = sin(t)* sin(5*direction_offset_norm*direction_offset_norm);;
|
||||||
|
magnitude_factor_norm = magnitude_factor_norm < 0 ? 0 : magnitude_factor_norm;
|
||||||
|
}
|
40
src/Environment/fgwind.hxx
Normal file
40
src/Environment/fgwind.hxx
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#ifndef _FGWIND_HXX
|
||||||
|
|
||||||
|
#include <simgear/structure/SGReferenced.hxx>
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
// A Wind Modulator interface, generates gusts and wind direction changes
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
class FGWindModulator : public SGReferenced {
|
||||||
|
public:
|
||||||
|
FGWindModulator();
|
||||||
|
virtual ~FGWindModulator();
|
||||||
|
virtual void update( double dt ) = 0;
|
||||||
|
double get_direction_offset_norm() const { return direction_offset_norm; }
|
||||||
|
double get_magnitude_factor_norm() const { return magnitude_factor_norm; }
|
||||||
|
protected:
|
||||||
|
double direction_offset_norm;
|
||||||
|
double magnitude_factor_norm;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
// A Basic Wind Modulator, implementation of FGWindModulator
|
||||||
|
// direction and magnitude variations are based on simple sin functions
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
class FGBasicWindModulator : public FGWindModulator {
|
||||||
|
public:
|
||||||
|
FGBasicWindModulator();
|
||||||
|
virtual ~FGBasicWindModulator();
|
||||||
|
virtual void update( double dt );
|
||||||
|
void set_direction_period( double _direction_period ) { direction_period = _direction_period; }
|
||||||
|
double get_direction_period() const { return direction_period; }
|
||||||
|
void set_speed_period( double _speed_period ) { speed_period = _speed_period; }
|
||||||
|
double get_speed_period() const{ return speed_period; }
|
||||||
|
private:
|
||||||
|
double elapsed;
|
||||||
|
double direction_period;
|
||||||
|
double speed_period;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue