예제 #1
0
void
DeviceBlackboard::Merge()
{
  real_data.Reset();
  for (unsigned i = 0; i < NUMDEV; ++i) {
    if (!per_device_data[i].connected)
      continue;

    per_device_data[i].UpdateClock();
    per_device_data[i].Expire();
    real_data.Complement(per_device_data[i]);
  }

  if (replay_data.connected) {
    /* the replay may run at a higher speed; use NMEA_INFO::Time as a
       "fake wallclock" to prevent them from expiring too quickly */
    replay_data.clock = replay_data.time;

    replay_data.Expire();
    SetBasic() = replay_data;
  } else if (simulator_data.connected) {
    simulator_data.UpdateClock();
    simulator_data.Expire();
    SetBasic() = simulator_data;
  } else {
    SetBasic() = real_data;
  }
}
예제 #2
0
void
DeviceBlackboard::tick()
{
  SetBasic().expire();

  // calculate fast data to complete aircraft state

  computer.Compute(SetBasic(), LastBasic(),
                   Calculated(), SettingsComputer());

  if (Basic().Time!= LastBasic().Time) {
    state_last = Basic();
  }
}
예제 #3
0
void
DeviceBlackboard::Merge()
{
  NMEAInfo &basic = SetBasic();

  real_data.Reset();
  for (unsigned i = 0; i < unsigned(NUMDEV); ++i) {
    if (!per_device_data[i].alive)
      continue;

    per_device_data[i].UpdateClock();
    per_device_data[i].Expire();
    real_data.Complement(per_device_data[i]);
  }

  real_clock.Normalise(real_data);

  if (replay_data.alive) {
    replay_data.Expire();
    basic = replay_data;

    /* WrapClock operates on the replay_data copy to avoid feeding
       back BrokenDate modifications to the NMEA parser, as this would
       trigger its time warp checks */
    replay_clock.Normalise(basic);
  } else if (simulator_data.alive) {
    simulator_data.UpdateClock();
    simulator_data.Expire();
    basic = simulator_data;
  } else {
    basic = real_data;
  }
}
예제 #4
0
void
DeviceBlackboard::Merge()
{
  real_data.reset();
  for (unsigned i = 0; i < NUMDEV; ++i) {
    per_device_data[i].expire();
    real_data.complement(per_device_data[i]);
  }

  if (replay_data.Connected) {
    replay_data.expire();
    SetBasic() = replay_data;
  } else if (simulator_data.Connected) {
    simulator_data.expire();
    SetBasic() = simulator_data;
  } else {
    SetBasic() = real_data;
  }

  computer.Fill(SetBasic(), SettingsComputer());

  ProcessFLARM();

  if (last_location_available != Basic().LocationAvailable) {
    last_location_available = Basic().LocationAvailable;
    TriggerGPSUpdate();
  } else if (last_vario_counter != Basic().VarioCounter) {
    last_vario_counter = Basic().VarioCounter;
    TriggerGPSUpdate();
  }

  if (last_te_vario_available != Basic().TotalEnergyVarioAvailable ||
      last_netto_vario_available != Basic().NettoVarioAvailable) {
    last_te_vario_available = Basic().TotalEnergyVarioAvailable;
    last_netto_vario_available = Basic().NettoVarioAvailable;
    TriggerVarioUpdate();
  }
}
예제 #5
0
/**
 * Calculates location, altitude, average climb speed and
 * looks up the callsign of each target
 */
void
DeviceBlackboard::ProcessFLARM()
{
  const NMEA_INFO &basic = Basic();
  FLARM_STATE &flarm = SetBasic().flarm;
  const FLARM_STATE &last_flarm = LastBasic().flarm;

  // if (FLARM data is available)
  if (!flarm.available || flarm.traffic.empty())
    return;

  fixed FLARM_NorthingToLatitude(0);
  fixed FLARM_EastingToLongitude(0);

  if (basic.LocationAvailable) {
    // Precalculate relative east and north projection to lat/lon
    // for Location calculations of each target
    Angle delta_lat = Angle::degrees(fixed(0.01));
    Angle delta_lon = Angle::degrees(fixed(0.01));

    GeoPoint plat = basic.Location;
    plat.Latitude += delta_lat;
    GeoPoint plon = basic.Location;
    plon.Longitude += delta_lon;

    fixed dlat = Distance(basic.Location, plat);
    fixed dlon = Distance(basic.Location, plon);

    if (positive(fabs(dlat)) && positive(fabs(dlon))) {
      FLARM_NorthingToLatitude = delta_lat.value_degrees() / dlat;
      FLARM_EastingToLongitude = delta_lon.value_degrees() / dlon;
    }
  }

  // for each item in traffic
  for (unsigned i = 0; i < flarm.traffic.size(); i++) {
    FLARM_TRAFFIC &traffic = flarm.traffic[i];

    // if we don't know the target's name yet
    if (!traffic.HasName()) {
      // lookup the name of this target's id
      const TCHAR *fname = FlarmDetails::LookupCallsign(traffic.id);
      if (fname != NULL)
        traffic.name = fname;
    }

    // Calculate distance
    traffic.distance = hypot(traffic.relative_north, traffic.relative_east);

    // Calculate Location
    traffic.location_available = basic.LocationAvailable;
    if (traffic.location_available) {
      traffic.location.Latitude =
          Angle::degrees(traffic.relative_north * FLARM_NorthingToLatitude) +
          basic.Location.Latitude;

      traffic.location.Longitude =
          Angle::degrees(traffic.relative_east * FLARM_EastingToLongitude) +
          basic.Location.Longitude;
    }

    // Calculate absolute altitude
    traffic.altitude_available = basic.GPSAltitudeAvailable;
    if (traffic.altitude_available)
      traffic.altitude = traffic.relative_altitude + basic.GPSAltitude;

    // Calculate average climb rate
    traffic.climb_rate_avg30s_available = traffic.altitude_available;
    if (traffic.climb_rate_avg30s_available)
      traffic.climb_rate_avg30s =
        flarmCalculations.Average30s(traffic.id, basic.Time, traffic.altitude);

    // The following calculations are only relevant for targets
    // where information is missing
    if (traffic.track_received || traffic.turn_rate_received ||
        traffic.speed_received || traffic.climb_rate_received)
      continue;

    // Check if the target has been seen before in the last seconds
    const FLARM_TRAFFIC *last_traffic = last_flarm.FindTraffic(traffic.id);
    if (last_traffic == NULL || !last_traffic->valid)
      continue;

    // Calculate the time difference between now and the last contact
    fixed dt = traffic.valid.GetTimeDifference(last_traffic->valid);
    if (positive(dt)) {
      // Calculate the immediate climb rate
      if (!traffic.climb_rate_received)
        traffic.climb_rate =
          (traffic.relative_altitude - last_traffic->relative_altitude) / dt;
    } else {
      // Since the time difference is zero (or negative)
      // we can just copy the old values
      if (!traffic.climb_rate_received)
        traffic.climb_rate = last_traffic->climb_rate;
    }

    if (positive(dt) &&
        traffic.location_available &&
        last_traffic->location_available) {
      // Calculate the GeoVector between now and the last contact
      GeoVector vec = last_traffic->location.distance_bearing(traffic.location);

      if (!traffic.track_received)
        traffic.track = vec.Bearing;

      // Calculate the turn rate
      if (!traffic.turn_rate_received)
        traffic.turn_rate =
          (traffic.track - last_traffic->track).as_delta().value_degrees() / dt;

      // Calculate the speed [m/s]
      if (!traffic.speed_received)
        traffic.speed = vec.Distance / dt;
    } else {
      // Since the time difference is zero (or negative)
      // we can just copy the old values
      if (!traffic.track_received)
        traffic.track = last_traffic->track;

      if (!traffic.turn_rate_received)
        traffic.turn_rate = last_traffic->turn_rate;

      if (!traffic.speed_received)
        traffic.speed = last_traffic->speed;
    }
  }
}
예제 #6
0
 void SetBaroAlt(double x) {
   SetBasic().BaroAltitude = x;
 }
예제 #7
0
 void SetBaroAlt(fixed x) {
   SetBasic().BaroAltitude = x;
 }