示例#1
0
void
GlideComputerTask::ProcessBasicTask(const MoreData &basic,
                                    const MoreData &last_basic,
                                    DerivedInfo &calculated,
                                    const DerivedInfo &last_calculated,
                                    const ComputerSettings &settings_computer)
{
    if (basic.HasTimeAdvancedSince(last_basic) && basic.location_available)
        trace.Update(settings_computer, ToAircraftState(basic, calculated));

    ProtectedTaskManager::ExclusiveLease _task(task);

    _task->SetTaskBehaviour(settings_computer.task);

    if (basic.HasTimeAdvancedSince(last_basic) && basic.location_available) {
        const AircraftState current_as = ToAircraftState(basic, calculated);
        const AircraftState last_as = ToAircraftState(last_basic, last_calculated);

        _task->Update(current_as, last_as);

        const fixed fallback_mc = calculated.last_thermal.IsDefined() &&
                                  positive(calculated.last_thermal_average_smooth)
                                  ? calculated.last_thermal_average_smooth
                                  : fixed_zero;
        if (_task->UpdateAutoMC(current_as, fallback_mc))
            calculated.ProvideAutoMacCready(basic.clock,
                                            _task->GetGlidePolar().GetMC());
    }

    calculated.task_stats = _task->GetStats();
    calculated.common_stats = _task->GetCommonStats();
    calculated.glide_polar_safety = _task->GetSafetyPolar();
}
示例#2
0
/**
 * Logs GPS fixes for stats
 * @return True if valid fix (fix distance <= 200m), False otherwise
 */
bool
StatsComputer::DoLogging(const MoreData &basic,
                         const DerivedInfo &calculated)
{
    /// @todo consider putting this sanity check inside Parser
    bool location_jump = basic.location_available && last_location.IsValid() &&
                         basic.location.DistanceS(last_location) > 200;

    last_location = basic.location_available
                    ? basic.location : GeoPoint::Invalid();

    if (location_jump || !basic.location_available)
        // prevent bad fixes from being logged or added to OLC store
        return false;

    if (calculated.flight.flying &&
            stats_clock.CheckAdvance(basic.time, PERIOD)) {
        flightstats.AddAltitudeTerrain(calculated.flight.flight_time,
                                       calculated.terrain_altitude);

        if (basic.NavAltitudeAvailable())
            flightstats.AddAltitude(calculated.flight.flight_time,
                                    basic.nav_altitude);

        if (calculated.task_stats.IsPirkerSpeedAvailable())
            flightstats.AddTaskSpeed(calculated.flight.flight_time,
                                     calculated.task_stats.get_pirker_speed());
    }

    return true;
}
void
GlideComputerAirData::Average30s(const MoreData &basic,
                                 const NMEAInfo &last_basic,
                                 DerivedInfo &calculated,
                                 const DerivedInfo &last_calculated)
{
  const bool time_advanced = basic.HasTimeAdvancedSince(last_basic);
  if (!time_advanced || calculated.circling != last_calculated.circling) {
    vario_30s_filter.reset();
    netto_30s_filter.reset();
    calculated.average = basic.brutto_vario;
    calculated.netto_average = basic.netto_vario;
  }

  if (!time_advanced)
    return;

  const unsigned Elapsed(basic.time - last_basic.time);
  if (Elapsed == 0)
    return;

  for (unsigned i = 0; i < Elapsed; ++i) {
    vario_30s_filter.update(basic.brutto_vario);
    netto_30s_filter.update(basic.netto_vario);
  }
  calculated.average = vario_30s_filter.average();
  calculated.netto_average = netto_30s_filter.average();
}
/**
 * Reads the current terrain height
 */
void
GlideComputerAirData::TerrainHeight(const MoreData &basic,
                                    TerrainInfo &calculated)
{
  if (!basic.location_available || terrain == NULL) {
    calculated.terrain_valid = false;
    calculated.terrain_altitude = fixed_zero;
    calculated.altitude_agl_valid = false;
    calculated.altitude_agl = fixed_zero;
    return;
  }

  short Alt = terrain->GetTerrainHeight(basic.location);
  if (RasterBuffer::IsSpecial(Alt)) {
    if (RasterBuffer::IsWater(Alt))
      /* assume water is 0m MSL; that's the best guess */
      Alt = 0;
    else {
      calculated.terrain_valid = false;
      calculated.terrain_altitude = fixed_zero;
      calculated.altitude_agl_valid = false;
      calculated.altitude_agl = fixed_zero;
      return;
    }
  }

  calculated.terrain_valid = true;
  calculated.terrain_altitude = fixed(Alt);

  if (basic.NavAltitudeAvailable()) {
    calculated.altitude_agl = basic.nav_altitude - calculated.terrain_altitude;
    calculated.altitude_agl_valid = true;
  } else
    calculated.altitude_agl_valid = false;
}
示例#5
0
gcc_pure
NearestAirspace
NearestAirspace::FindHorizontal(const MoreData &basic,
                                const ProtectedAirspaceWarningManager &airspace_warnings,
                                const Airspaces &airspace_database)
{
  if (!basic.location_available)
    /* can't check for airspaces without a GPS fix */
    return NearestAirspace();

  /* find the nearest airspace */
  //consider only active airspaces
  const auto outside_and_active =
    MakeAndPredicate(ActiveAirspacePredicate(&airspace_warnings),
                     OutsideAirspacePredicate(AGeoPoint(basic.location, 0)));

  //if altitude is available, filter airspaces in same height as airplane
  if (basic.NavAltitudeAvailable()) {
    /* check altitude; hard-coded margin of 50m (for now) */
    const auto outside_and_active_and_height =
      MakeAndPredicate(outside_and_active,
                       AirspacePredicateHeightRange(basic.nav_altitude - 50,
                                                    basic.nav_altitude + 50));
    const auto predicate = WrapAirspacePredicate(outside_and_active_and_height);
    return ::FindHorizontal(basic.location, airspace_database, predicate);
  } else {
    /* only filter outside and active */
    const auto predicate = WrapAirspacePredicate(outside_and_active);
    return ::FindHorizontal(basic.location, airspace_database, predicate);
  }
}
示例#6
0
void
BasicComputer::Compute(MoreData &data,
                       const MoreData &last, const MoreData &last_gps,
                       const DerivedInfo &calculated)
{
  ComputeTrack(data, last_gps);

  if (data.HasTimeAdvancedSince(last_gps)) {
    ComputeGroundSpeed(data, last_gps);
    ComputeAirspeed(data, calculated);
  }
#ifndef NDEBUG
  // For testing without gps.
  // When CPU load is low enough it can be done for every sample.
  else if (data.dyn_pressure_available)
    ComputeAirspeed(data, calculated);
#endif

  ComputeHeading(data.attitude, data, calculated);

  ComputeEnergyHeight(data);
  ComputeGPSVario(data, last, last_gps);
  ComputeBruttoVario(data);
  ComputeNettoVario(data, calculated);
  ComputeDynamics(data, calculated);
}
示例#7
0
void
TraceComputer::Update(const ComputerSettings &settings_computer,
                      const MoreData &basic, const DerivedInfo &calculated)
{
  /* time warps are handled by the Trace class */

  if (!basic.time_available || !basic.location_available ||
      !basic.NavAltitudeAvailable() ||
      !calculated.flight.flying)
    return;

  // either olc or basic trace requires trace_full
  if (settings_computer.contest.enable ||
      settings_computer.task.enable_trace) {
    const TracePoint point(basic);

    mutex.Lock();
    full.push_back(point);
    mutex.Unlock();

    // only olc requires trace_sprint
    if (settings_computer.contest.enable)
      sprint.push_back(point);
  }
}
示例#8
0
 HorizontalAirspaceCondition(const MoreData &basic,
                             const DerivedInfo &calculated)
   :location(basic.location),
    altitude_available(basic.NavAltitudeAvailable())
 {
   if (altitude_available) {
     altitude.altitude = basic.nav_altitude;
     altitude.altitude_agl = calculated.altitude_agl;
   }
 }
示例#9
0
void
WarningComputer::Update(const ComputerSettings &settings_computer,
                        const MoreData &basic, const MoreData &last_basic,
                        const DerivedInfo &calculated,
                        AirspaceWarningsInfo &result)
{
  if (!basic.HasTimeAdvancedSince(last_basic) ||
      !clock.check_advance(basic.time))
    return;

  airspaces.set_flight_levels(settings_computer.pressure);

  AirspaceActivity day(calculated.date_time_local.day_of_week);
  airspaces.set_activity(day);

  if (!settings_computer.airspace.enable_warnings ||
      !basic.location_available || !basic.NavAltitudeAvailable()) {
    if (initialised) {
      initialised = false;
      protected_manager.clear();
    }

    return;
  }

  const AircraftState as = ToAircraftState(basic, calculated);
  ProtectedAirspaceWarningManager::ExclusiveLease lease(protected_manager);

  if (!initialised) {
    initialised = true;
    lease->Reset(as);
  }

  if (lease->Update(as, settings_computer.glide_polar_task,
                    calculated.task_stats,
                    calculated.circling,
                    uround(basic.time - last_basic.time)))
    result.latest.Update(basic.clock);
}
示例#10
0
const AircraftState
ToAircraftState(const MoreData &info, const DerivedInfo &calculated)
{
  AircraftState aircraft;

  /* SPEED_STATE */
  aircraft.ground_speed = info.ground_speed;
  aircraft.true_airspeed = info.true_airspeed;

  /* ALTITUDE_STATE */
  aircraft.altitude = info.NavAltitudeAvailable()
    ? info.nav_altitude
    : 0.;

  aircraft.working_band_fraction = calculated.common_stats.height_fraction_working;

  aircraft.altitude_agl =
    info.NavAltitudeAvailable() && calculated.terrain_valid
    ? calculated.altitude_agl
    : 0.;

  /* VARIO_INFO */
  aircraft.vario = info.brutto_vario;
  aircraft.netto_vario = info.netto_vario;

  /* AIRCRAFT_STATE */
  aircraft.time = info.time_available ? info.time : -1.;
  aircraft.location = info.location_available
    ? info.location
    : GeoPoint::Invalid();
  aircraft.track = info.track;
  aircraft.g_load = info.acceleration.available
    ? info.acceleration.g_load
    : 1.;
  aircraft.wind = calculated.GetWindOrZero();
  aircraft.flying = calculated.flight.flying;

  return aircraft;
}
示例#11
0
void
GlideRatioComputer::Compute(const MoreData &basic,
                            const DerivedInfo &calculated,
                            VarioInfo &vario_info,
                            const ComputerSettings &settings)
{
  if (!basic.NavAltitudeAvailable()) {
    Reset();
    vario_info.gr = INVALID_GR;
    vario_info.average_gr = 0;
    return;
  }

  if (!last_location_available) {
    /* need two consecutive valid locations; if the previous one
       wasn't valid, skip this iteration and try the next one */
    Reset();
    vario_info.gr = INVALID_GR;
    vario_info.average_gr = 0;

    last_location = basic.location;
    last_location_available = basic.location_available;
    last_altitude = basic.nav_altitude;
    return;
  }

  if (!basic.location_available.Modified(last_location_available))
    return;

  auto DistanceFlown = basic.location.DistanceS(last_location);

  // Glide ratio over ground
  vario_info.gr =
    UpdateGR(vario_info.gr, DistanceFlown,
             last_altitude - basic.nav_altitude, 0.1);

  if (calculated.flight.flying && !calculated.circling) {
    if (!gr_calculator_initialised) {
      gr_calculator_initialised = true;
      gr_calculator.Initialize(settings);
    }

    gr_calculator.Add((int)DistanceFlown, (int)basic.nav_altitude);
    vario_info.average_gr = gr_calculator.Calculate();
  } else
    gr_calculator_initialised = false;

  last_location = basic.location;
  last_location_available = basic.location_available;
  last_altitude = basic.nav_altitude;
}
示例#12
0
void
TrackingGlue::OnTimer(const MoreData &basic, const DerivedInfo &calculated)
{
#ifdef HAVE_SKYLINES_TRACKING
  skylines.Tick(basic);
#endif

#ifdef HAVE_LIVETRACK24
  if (!settings.livetrack24.enabled)
    /* disabled by configuration */
    /* note that we are allowed to read "settings" without locking the
       mutex, because the background thread never writes to this
       attribute */
    return;

  if (!basic.time_available || !basic.gps.real || !basic.location_available)
    /* can't track without a valid GPS fix */
    return;

  if (!clock.CheckUpdate(settings.interval * 1000))
    /* later */
    return;

  ScopeLock protect(mutex);
  if (IsBusy())
    /* still running, skip this submission */
    return;

  date_time = basic.date_time_utc;
  if (!date_time.IsDatePlausible())
    /* use "today" if the GPS didn't provide a date */
    (BrokenDate &)date_time = BrokenDate::TodayUTC();

  location = basic.location;
  /* XXX use nav_altitude? */
  altitude = basic.NavAltitudeAvailable() && basic.nav_altitude > 0
    ? (unsigned)basic.nav_altitude
    : 0u;
  ground_speed = basic.ground_speed_available
    ? (unsigned)Units::ToUserUnit(basic.ground_speed, Unit::KILOMETER_PER_HOUR)
    : 0u;
  track = basic.track_available
    ? basic.track
    : Angle::Zero();

  last_flying = flying;
  flying = calculated.flight.flying;

  Trigger();
#endif
}
void
GlideComputerAirData::GR(const MoreData &basic, const MoreData &last_basic,
                         const DerivedInfo &calculated, VarioInfo &vario_info)
{
  if (!basic.NavAltitudeAvailable() || !last_basic.NavAltitudeAvailable()) {
    vario_info.ld_vario = INVALID_GR;
    vario_info.gr = INVALID_GR;
    return;
  }

  if (basic.HasTimeRetreatedSince(last_basic)) {
    vario_info.ld_vario = INVALID_GR;
    vario_info.gr = INVALID_GR;
  }

  const bool time_advanced = basic.HasTimeAdvancedSince(last_basic);
  if (time_advanced) {
    fixed DistanceFlown = basic.location.Distance(last_basic.location);

    // Glide ratio over ground
    vario_info.gr =
      UpdateGR(vario_info.gr, DistanceFlown,
               last_basic.nav_altitude - basic.nav_altitude, fixed(0.1));

    if (calculated.flight.flying && !calculated.circling)
      gr_calculator.Add((int)DistanceFlown, (int)basic.nav_altitude);
  }

  // Lift / drag instantaneous from vario, updated every reading..
  if (basic.total_energy_vario_available && basic.airspeed_available &&
      calculated.flight.flying) {
    vario_info.ld_vario =
      UpdateGR(vario_info.ld_vario, basic.indicated_airspeed,
               -basic.total_energy_vario, fixed(0.3));
  } else {
    vario_info.ld_vario = INVALID_GR;
  }
}
示例#14
0
void
Update(const MoreData &basic, const FlyingState &state,
       FlightTimeResult &result)
{
  if (!basic.time_available || !basic.date_time_utc.IsDatePlausible())
    return;

  if (state.flying && !result.takeoff_time.IsPlausible()) {
    result.takeoff_time = basic.GetDateTimeAt(state.takeoff_time);
    result.takeoff_location = state.takeoff_location;
  }

  if (!state.flying && result.takeoff_time.IsPlausible() &&
      !result.landing_time.IsPlausible()) {
    result.landing_time = basic.GetDateTimeAt(state.landing_time);
    result.landing_location = state.landing_location;
  }

  if (!negative(state.release_time) && !result.release_time.IsPlausible()) {
    result.release_time = basic.GetDateTimeAt(state.release_time);
    result.release_location = state.release_location;
  }
}
示例#15
0
void
WarningComputer::Update(const ComputerSettings &settings_computer,
                        const MoreData &basic,
                        const DerivedInfo &calculated,
                        AirspaceWarningsInfo &result)
{
  if (!basic.time_available)
    return;

  const fixed dt = delta_time.Update(basic.time, fixed(1), fixed(20));
  if (negative(dt))
    /* time warp */
    Reset();

  if (!positive(dt))
    return;

  airspaces.SetFlightLevels(settings_computer.pressure);

  AirspaceActivity day(calculated.date_time_local.day_of_week);
  airspaces.SetActivity(day);

  if (!settings_computer.airspace.enable_warnings ||
      !basic.location_available || !basic.NavAltitudeAvailable()) {
    if (initialised) {
      initialised = false;
      protected_manager.Clear();
    }

    return;
  }

  const AircraftState as = ToAircraftState(basic, calculated);
  ProtectedAirspaceWarningManager::ExclusiveLease lease(protected_manager);

  lease->SetConfig(settings_computer.airspace.warnings);

  if (!initialised) {
    initialised = true;
    lease->Reset(as);
  }

  if (lease->Update(as, settings_computer.polar.glide_polar_task,
                    calculated.task_stats,
                    calculated.circling,
                    uround(dt)))
    result.latest.Update(basic.clock);
}
示例#16
0
void
GlideComputerAirData::MaxHeightGain(const MoreData &basic,
                                    DerivedInfo &calculated)
{
  if (!basic.NavAltitudeAvailable() || !calculated.flight.flying)
    return;

  if (positive(calculated.min_altitude)) {
    fixed height_gain = basic.nav_altitude - calculated.min_altitude;
    calculated.max_height_gain = max(height_gain, calculated.max_height_gain);
  } else {
    calculated.min_altitude = basic.nav_altitude;
  }

  calculated.min_altitude = min(basic.nav_altitude, calculated.min_altitude);
}
示例#17
0
void
RouteComputer::ProcessRoute(const MoreData &basic, DerivedInfo &calculated,
                            const GlideSettings &settings,
                            const RoutePlannerConfig &config,
                            const GlidePolar &glide_polar,
                            const GlidePolar &safety_polar)
{
  if (!basic.location_available || !basic.NavAltitudeAvailable())
    return;

  protected_route_planner.SetPolars(settings, glide_polar, safety_polar,
                                    calculated.GetWindOrZero());

  Reach(basic, calculated, config);
  TerrainWarning(basic, calculated, config);
}
示例#18
0
void
ThermalBandComputer::Compute(const MoreData &basic,
                             const DerivedInfo &calculated,
                             ThermalBandInfo &tbi,
                             const ComputerSettings &settings)
{
  if (!basic.NavAltitudeAvailable())
    return;

  const fixed h_safety =
    settings.task.route_planner.safety_height_terrain +
    calculated.GetTerrainBaseFallback();

  tbi.working_band_height = basic.TE_altitude - h_safety;
  if (negative(tbi.working_band_height)) {
    tbi.working_band_fraction = fixed(0);
    return;
  }

  const fixed max_height = tbi.max_thermal_height;
  if (positive(max_height))
    tbi.working_band_fraction = tbi.working_band_height / max_height;
  else
    tbi.working_band_fraction = fixed(1);

  tbi.working_band_ceiling = std::max(max_height + h_safety,
                                      basic.TE_altitude);


  last_vario_available.FixTimeWarp(basic.brutto_vario_available);
  if (basic.brutto_vario_available.Modified(last_vario_available)) {
    last_vario_available = basic.brutto_vario_available;

    // JMW TODO accuracy: Should really work out dt here,
    //           but i'm assuming constant time steps

    if (tbi.max_thermal_height == fixed(0))
      tbi.max_thermal_height = tbi.working_band_height;

    // only do this if in thermal and have been climbing
    if (calculated.circling && calculated.turning &&
        positive(calculated.average))
      tbi.Add(tbi.working_band_height, basic.brutto_vario);
  }
}
示例#19
0
void
CirclingComputer::MaxHeightGain(const MoreData &basic,
                                const FlyingState &flight,
                                CirclingInfo &circling_info)
{
  if (!basic.NavAltitudeAvailable() || !flight.flying)
    return;

  if (min_altitude > 0) {
    auto height_gain = basic.nav_altitude - min_altitude;
    circling_info.max_height_gain =
      std::max(height_gain, circling_info.max_height_gain);
  } else {
    min_altitude = basic.nav_altitude;
  }

  min_altitude = std::min(basic.nav_altitude, min_altitude);
}
示例#20
0
void
GlideComputerAirData::CruiseLD(const MoreData &basic, DerivedInfo &calculated)
{
  if (!calculated.circling && basic.NavAltitudeAvailable()) {
    if (negative(calculated.cruise_start_time)) {
      calculated.cruise_start_location = basic.location;
      calculated.cruise_start_altitude = basic.nav_altitude;
      calculated.cruise_start_time = basic.time;
    } else {
      fixed DistanceFlown =
        basic.location.Distance(calculated.cruise_start_location);

      calculated.cruise_ld =
          UpdateLD(calculated.cruise_ld, DistanceFlown,
                   calculated.cruise_start_altitude - basic.nav_altitude,
                   fixed_half);
    }
  }
}
示例#21
0
/**
 * Retrieves GPS data from the DeviceBlackboard
 * @param nmea_info New GPS data
 */
void
GlideComputerBlackboard::ReadBlackboard(const MoreData &nmea_info)
{
  _time_retreated = nmea_info.HasTimeRetreatedSince(gps_info);

  if (_time_retreated) {
    // backwards in time, so reset last
    last_gps_info = nmea_info;
    last_calculated_info = calculated_info;
    _time_retreated = true;
  } else if (nmea_info.time > gps_info.time) {
    // forwards in time, so save state
    last_gps_info = gps_info;
    last_calculated_info = calculated_info;
  }

  gps_info = nmea_info;

  // if time hasn't advanced, don't copy last calculated
}
示例#22
0
  void CalculateReachabilityDirect(const MoreData &basic,
                                   const SpeedVector &wind,
                                   const MacCready &mac_cready,
                                   const TaskBehaviour &task_behaviour) {
    assert(basic.location_available);
    assert(basic.NavAltitudeAvailable());

    const auto elevation = waypoint->elevation +
      task_behaviour.safety_height_arrival;
    const GlideState state(GeoVector(basic.location, waypoint->location),
                           elevation, basic.nav_altitude, wind);

    const GlideResult result = mac_cready.SolveStraight(state);
    if (!result.IsOk())
      return;

    reach.direct = result.pure_glide_altitude_difference;
    if (result.pure_glide_altitude_difference > 0)
      reachable = WaypointRenderer::ReachableTerrain;
  }
示例#23
0
/**
 * Logs GPS fixes for stats
 * @return True if valid fix (fix distance <= 200m), False otherwise
 */
bool
GlideComputerStats::DoLogging(const MoreData &basic,
                              const NMEAInfo &last_basic,
                              const DerivedInfo &calculated,
                              const LoggerSettings &settings_logger)
{
  /// @todo consider putting this sanity check inside Parser
  if (basic.location.Distance(last_basic.location) > fixed(200))
    // prevent bad fixes from being logged or added to OLC store
    return false;

  // log points more often in circling mode
  if (calculated.circling)
    log_clock.set_dt(fixed(settings_logger.logger_time_step_circling));
  else
    log_clock.set_dt(fixed(settings_logger.logger_time_step_cruise));

  if (fast_log_num) {
    log_clock.set_dt(fixed_one);
    fast_log_num--;
  }

  if (log_clock.check_advance(basic.time) && logger != NULL)
      logger->LogPoint(basic);

  if (calculated.flight.flying &&
      stats_clock.check_advance(basic.time)) {
    flightstats.AddAltitudeTerrain(calculated.flight.flight_time,
                                   calculated.terrain_altitude);

    if (basic.NavAltitudeAvailable())
      flightstats.AddAltitude(calculated.flight.flight_time,
                              basic.nav_altitude);

    if (calculated.task_stats.IsPirkerSpeedAvailable())
      flightstats.AddTaskSpeed(calculated.flight.flight_time,
                               calculated.task_stats.get_pirker_speed());
  }

  return true;
}
示例#24
0
void
GlideComputerAirData::ThermalSources(const MoreData &basic,
                                     const DerivedInfo &calculated,
                                     ThermalLocatorInfo &thermal_locator)
{
  if (!thermal_locator.estimate_valid ||
      !basic.NavAltitudeAvailable() ||
      !calculated.last_thermal.IsDefined() ||
      negative(calculated.last_thermal.lift_rate))
    return;

  if (calculated.wind_available &&
      calculated.wind.norm / calculated.last_thermal.lift_rate > fixed(10.0)) {
    // thermal strength is so weak compared to wind that source estimate
    // is unlikely to be reliable, so don't calculate or remember it
    return;
  }

  GeoPoint ground_location;
  fixed ground_altitude = fixed_minus_one;
  EstimateThermalBase(terrain, thermal_locator.estimate_location,
                      basic.nav_altitude,
                      calculated.last_thermal.lift_rate,
                      calculated.GetWindOrZero(),
                      ground_location,
                      ground_altitude);

  if (positive(ground_altitude)) {
    ThermalSource &source =
      thermal_locator.AllocateSource(basic.time);

    source.lift_rate = calculated.last_thermal.lift_rate;
    source.location = ground_location;
    source.ground_height = ground_altitude;
    source.time = basic.time;
  }
}
示例#25
0
gcc_pure
NearestAirspace
NearestAirspace::FindHorizontal(const MoreData &basic,
                                const ProtectedAirspaceWarningManager &airspace_warnings,
                                const Airspaces &airspace_database)
{
  if (!basic.location_available)
    /* can't check for airspaces without a GPS fix */
    return NearestAirspace();

  /* find the nearest airspace */
  //consider only active airspaces
  const WrapAirspacePredicate<ActiveAirspacePredicate> active_predicate(&airspace_warnings);
  const WrapAirspacePredicate<OutsideAirspacePredicate> outside_predicate(AGeoPoint(basic.location, RoughAltitude(0)));
  const AndAirspacePredicate outside_and_active_predicate(active_predicate, outside_predicate);
  const Airspace *airspace;

  //if altitude is available, filter airspaces in same height as airplane
  if (basic.NavAltitudeAvailable()) {
    /* check altitude; hard-coded margin of 50m (for now) */
    WrapAirspacePredicate<AirspacePredicateHeightRange> height_range_predicate(RoughAltitude(basic.nav_altitude-fixed(50)),
                                                                               RoughAltitude(basic.nav_altitude+fixed(50)));
     AndAirspacePredicate and_predicate(outside_and_active_predicate, height_range_predicate);
     airspace = airspace_database.FindNearest(basic.location, and_predicate);
  } else //only filter outside and active
    airspace = airspace_database.FindNearest(basic.location, outside_and_active_predicate);

  if (airspace == nullptr)
    return NearestAirspace();

  const AbstractAirspace &as = airspace->GetAirspace();

  /* calculate distance to the nearest point */
  const GeoPoint closest = as.ClosestPoint(basic.location,
                                           airspace_database.GetProjection());
  return NearestAirspace(as, basic.location.Distance(closest));
}
示例#26
0
static bool
test_replay(const Contest olc_type,
            const ContestResult &official_score)
{
  Directory::Create(_T("output/results"));
  std::ofstream f("output/results/res-sample.txt");

  GlidePolar glide_polar(fixed(2));

  Error error;
  FileLineReaderA *reader = new FileLineReaderA(replay_file.c_str(), error);
  if (reader->error()) {
    delete reader;
    fprintf(stderr, "%s\n", error.GetMessage());
    return false;
  }

  ReplayLoggerSim sim(reader);

  ComputerSettings settings_computer;
  settings_computer.SetDefaults();
  settings_computer.contest.enable = true;
  load_scores(settings_computer.contest.handicap);

  if (verbose) {
    switch (olc_type) {
    case Contest::OLC_LEAGUE:
      std::cout << "# OLC-League\n";
      break;
    case Contest::OLC_SPRINT:
      std::cout << "# OLC-Sprint\n";
      break;
    case Contest::OLC_FAI:
      std::cout << "# OLC-FAI\n";
      break;
    case Contest::OLC_CLASSIC:
      std::cout << "# OLC-Classic\n";
      break;
    case Contest::OLC_PLUS:
      std::cout << "# OLC-Plus\n";
      break;
    default:
      std::cout << "# Unknown!\n";
      break;
    }
  }

  bool do_print = verbose;
  unsigned print_counter=0;

  MoreData basic;
  basic.Reset();

  FlyingComputer flying_computer;
  flying_computer.Reset();

  FlyingState flying_state;
  flying_state.Reset();

  TraceComputer trace_computer;

  ContestManager contest_manager(olc_type,
                                 trace_computer.GetFull(),
                                 trace_computer.GetFull(),
                                 trace_computer.GetSprint());
  contest_manager.SetHandicap(settings_computer.contest.handicap);

  DerivedInfo calculated;

  while (sim.Update(basic)) {
    n_samples++;

    flying_computer.Compute(glide_polar.GetVTakeoff(),
			    basic, calculated,
			    flying_state);

    calculated.flight.flying = true;
    
    trace_computer.Update(settings_computer, basic, calculated);
    
    contest_manager.UpdateIdle();
  
    if (verbose>1) {
      sim.print(f, basic);
      f.flush();
    }
    if (do_print) {
      PrintHelper::trace_print(trace_computer.GetFull(), basic.location);
    }
    do_print = (++print_counter % output_skip ==0) && verbose;
  };

  contest_manager.SolveExhaustive();

  if (verbose) {
    PrintDistanceCounts();
  }
  return compare_scores(official_score, 
                        contest_manager.GetStats().GetResult(0));
}
示例#27
0
void
CirclingComputer::Turning(CirclingInfo &circling_info,
                          const MoreData &basic, const MoreData &last_basic,
                          const DerivedInfo &calculated,
                          const DerivedInfo &last_calculated,
                          const ComputerSettings &settings_computer)
{
    // You can't be circling unless you're flying
    if (!calculated.flight.flying || !basic.HasTimeAdvancedSince(last_basic))
        return;

    // JMW limit rate to 50 deg per second otherwise a big spike
    // will cause spurious lock on circling for a long time
    fixed turn_rate = max(fixed(-50), min(fixed(50), calculated.turn_rate));

    // Make the turn rate more smooth using the LowPassFilter
    turn_rate = LowPassFilter(last_calculated.turn_rate_smoothed,
                              turn_rate, fixed(0.3));
    circling_info.turn_rate_smoothed = turn_rate;
    circling_info.turning = fabs(turn_rate) >= min_turn_rate;

    // Force cruise or climb mode if external device says so
    bool force_cruise = false;
    bool force_circling = false;
    if (settings_computer.external_trigger_cruise_enabled && !basic.gps.replay) {
        switch (basic.switch_state.flight_mode) {
        case SwitchInfo::FlightMode::UNKNOWN:
            force_circling = false;
            force_cruise = false;
            break;

        case SwitchInfo::FlightMode::CIRCLING:
            force_circling = true;
            force_cruise = false;
            break;

        case SwitchInfo::FlightMode::CRUISE:
            force_circling = false;
            force_cruise = true;
            break;
        }
    }

    switch (calculated.turn_mode) {
    case CirclingMode::CRUISE:
        // If (in cruise mode and beginning of circling detected)
        if (circling_info.turning || force_circling) {
            // Remember the start values of the turn
            circling_info.turn_start_time = basic.time;
            circling_info.turn_start_location = basic.location;
            circling_info.turn_start_altitude = basic.nav_altitude;
            circling_info.turn_start_energy_height = basic.energy_height;
            circling_info.turn_mode = CirclingMode::POSSIBLE_CLIMB;
        }
        if (!force_circling)
            break;

    case CirclingMode::POSSIBLE_CLIMB:
        if (force_cruise) {
            circling_info.turn_mode = CirclingMode::CRUISE;
            break;
        }
        if (circling_info.turning || force_circling) {
            if (((basic.time - calculated.turn_start_time) > cruise_climb_switch)
                    || force_circling) {
                // yes, we are certain now that we are circling
                circling_info.circling = true;

                // JMW Transition to climb
                circling_info.turn_mode = CirclingMode::CLIMB;

                // Remember the start values of the climbing period
                circling_info.climb_start_location = circling_info.turn_start_location;
                circling_info.climb_start_altitude = circling_info.turn_start_altitude
                                                     + circling_info.turn_start_energy_height;
                circling_info.climb_start_time = circling_info.turn_start_time;
            }
        } else {
            // nope, not turning, so go back to cruise
            circling_info.turn_mode = CirclingMode::CRUISE;
        }
        break;

    case CirclingMode::CLIMB:
        if (!circling_info.turning || force_cruise) {
            // Remember the end values of the turn
            circling_info.turn_start_time = basic.time;
            circling_info.turn_start_location = basic.location;
            circling_info.turn_start_altitude = basic.nav_altitude;
            circling_info.turn_start_energy_height = basic.energy_height;

            // JMW Transition to cruise, due to not properly turning
            circling_info.turn_mode = CirclingMode::POSSIBLE_CRUISE;
        }
        if (!force_cruise)
            break;

    case CirclingMode::POSSIBLE_CRUISE:
        if (force_circling) {
            circling_info.turn_mode = CirclingMode::CLIMB;
            break;
        }

        if (!circling_info.turning || force_cruise) {
            if (((basic.time - circling_info.turn_start_time) > climb_cruise_switch)
                    || force_cruise) {
                // yes, we are certain now that we are cruising again
                circling_info.circling = false;

                // Transition to cruise
                circling_info.turn_mode = CirclingMode::CRUISE;
                circling_info.cruise_start_location = circling_info.turn_start_location;
                circling_info.cruise_start_altitude = circling_info.turn_start_altitude;
                circling_info.cruise_start_time = circling_info.turn_start_time;
            }
        } else {
            // nope, we are circling again
            // JMW Transition back to climb, because we are turning again
            circling_info.turn_mode = CirclingMode::CLIMB;
        }
        break;
    }
}
示例#28
0
static bool
test_replay(const Contests olc_type, 
            const ContestResult &official_score)
{
  std::ofstream f("results/res-sample.txt");

  GlidePolar glide_polar(fixed_two);
  AircraftState state_last;

  FileLineReaderA *reader = new FileLineReaderA(replay_file.c_str());
  if (reader->error()) {
    delete reader;
    return false;
  }

  ReplayLoggerSim sim(reader);

  ComputerSettings settings_computer;
  settings_computer.SetDefaults();
  settings_computer.task.enable_olc = true;
  load_scores(settings_computer.task.contest_handicap);

  if (verbose) {
    switch (olc_type) {
    case OLC_League:
      std::cout << "# OLC-League\n";
      break;
    case OLC_Sprint:
      std::cout << "# OLC-Sprint\n";
      break;
    case OLC_FAI:
      std::cout << "# OLC-FAI\n";
      break;
    case OLC_Classic:
      std::cout << "# OLC-Classic\n";
      break;
    case OLC_Plus:
      std::cout << "# OLC-Plus\n";
      break;
    default:
      std::cout << "# Unknown!\n";
      break;
    }
  }

  bool do_print = verbose;
  unsigned print_counter=0;

  MoreData basic;
  basic.Reset();

  while (sim.Update(basic, fixed_one) && !sim.started) {
  }
  state_last = sim.state;

  fixed time_last = sim.state.time;

  FlyingComputer flying_computer;
  flying_computer.Reset();

  FlyingState flying_state;
  flying_state.Reset();

  TraceComputer trace_computer;

  ContestManager contest_manager(olc_type,
                                 trace_computer.GetFull(),
                                 trace_computer.GetSprint());
  contest_manager.SetHandicap(settings_computer.task.contest_handicap);

  DerivedInfo calculated;

  while (sim.Update(basic, fixed_one)) {
    if (sim.state.time>time_last) {

      n_samples++;

      flying_computer.Compute(glide_polar.GetVTakeoff(),
                              sim.state, flying_state);

      calculated.flight.flying = flying_state.flying;

      trace_computer.Update(settings_computer, basic, calculated);

      contest_manager.UpdateIdle();
  
      state_last = sim.state;

      if (verbose>1) {
        sim.print(f);
        f.flush();
      }
      if (do_print) {
        PrintHelper::trace_print(trace_computer.GetFull(), sim.state.location);
      }
      do_print = (++print_counter % output_skip ==0) && verbose;
    }
    time_last = sim.state.time;
  };

  contest_manager.SolveExhaustive();

  if (verbose) {
    PrintDistanceCounts();
  }
  return compare_scores(official_score, 
                        contest_manager.GetStats().GetResult(0));
}
示例#29
0
void
ThermalBandRenderer::_DrawThermalBand(const MoreData &basic,
                                      const DerivedInfo& calculated,
                                      const ComputerSettings &settings_computer,
                                      ChartRenderer &chart,
                                      const TaskBehaviour& task_props,
                                      const bool is_infobox,
                                      const OrderedTaskBehaviour *ordered_props) const
{
  const ThermalBandInfo &thermal_band = calculated.thermal_band;

  // calculate height above safety height
  fixed hoffset = task_props.route_planner.safety_height_terrain +
    calculated.GetTerrainBaseFallback();

  fixed h = fixed(0);
  if (basic.NavAltitudeAvailable()) {
    h = basic.nav_altitude - hoffset;
    chart.ScaleYFromValue(h);
  }

  bool draw_start_height = false;
  fixed hstart = fixed(0);

  draw_start_height = ordered_props
    && calculated.ordered_task_stats.task_valid
    && ordered_props->start_constraints.max_height != 0
    && calculated.terrain_valid;
  if (draw_start_height) {
    hstart = fixed(ordered_props->start_constraints.max_height);
    if (ordered_props->start_constraints.max_height_ref == AltitudeReference::AGL &&
        calculated.terrain_valid)
      hstart += calculated.terrain_altitude;

    hstart -= hoffset;
    chart.ScaleYFromValue(hstart);
  }

  // no thermalling has been done above safety height
  if (!positive(calculated.thermal_band.max_thermal_height))
    return;

  // calculate averages
  int numtherm = 0;

  fixed Wmax = fixed(0);
  fixed Wav = fixed(0);
  fixed Wt[ThermalBandInfo::NUMTHERMALBUCKETS];
  fixed ht[ThermalBandInfo::NUMTHERMALBUCKETS];

  for (unsigned i = 0; i < ThermalBandInfo::NUMTHERMALBUCKETS; ++i) {
    if (thermal_band.thermal_profile_n[i] < 6) 
      continue;

    if (positive(thermal_band.thermal_profile_w[i])) {
      // height of this thermal point [0,mth]
      // requires 5 items in bucket before displaying, to eliminate kinks
      fixed wthis = thermal_band.thermal_profile_w[i] / thermal_band.thermal_profile_n[i];
      ht[numtherm] = i * calculated.thermal_band.max_thermal_height 
        / ThermalBandInfo::NUMTHERMALBUCKETS;
      Wt[numtherm] = wthis;
      Wmax = std::max(Wmax, wthis);
      Wav+= wthis;
      numtherm++;
    }
  }
  chart.ScaleXFromValue(Wmax);
  if (!numtherm)
    return;
  chart.ScaleXFromValue(fixed(1.5)*Wav/numtherm);

  if ((!draw_start_height) && (numtherm<=1))
    // don't display if insufficient statistics
    // but do draw if start height needs to be drawn
    return;

  const Pen *fpen = is_infobox ? NULL : &look.pen;

  // position of thermal band
  if (numtherm > 1) {
    std::vector< std::pair<fixed, fixed> > thermal_profile;
    thermal_profile.reserve(numtherm);
    for (int i = 0; i < numtherm; ++i)
      thermal_profile.emplace_back(Wt[i], ht[i]);

    if (!is_infobox) {
#ifdef ENABLE_OPENGL
      const GLEnable blend(GL_BLEND);
#endif
      chart.DrawFilledY(thermal_profile, look.brush, fpen);
    } else
      chart.DrawFilledY(thermal_profile, look.brush, fpen);
  }

  // position of thermal band
  if (basic.NavAltitudeAvailable()) {
    const Pen &pen = is_infobox && look.inverse
      ? look.white_pen : look.black_pen;
    chart.DrawLine(fixed(0), h,
                   settings_computer.polar.glide_polar_task.GetMC(), h, pen);

    if (is_infobox && look.inverse)
      chart.GetCanvas().SelectWhiteBrush();
    else
      chart.GetCanvas().SelectBlackBrush();
    chart.DrawDot(settings_computer.polar.glide_polar_task.GetMC(),
                  h, Layout::Scale(2));
  }
}