void FlyingComputer::Compute(fixed takeoff_speed, const NMEAInfo &basic, const NMEAInfo &last_basic, const DerivedInfo &calculated, FlyingState &flying) { if (basic.HasTimeRetreatedSince(last_basic)) { Reset(); flying.Reset(); } // GPS not lost if (!basic.location_available) return; // Speed too high for being on the ground const fixed speed = basic.airspeed_available ? std::max(basic.true_airspeed, basic.ground_speed) : basic.ground_speed; if (speed > takeoff_speed || (calculated.altitude_agl_valid && calculated.altitude_agl > fixed(300))) Moving(flying, basic.time, basic.location); else Stationary(flying, basic.time, basic.location); }
void FlyingComputer::Compute(fixed takeoff_speed, const NMEAInfo &basic, const DerivedInfo &calculated, FlyingState &flying) { if (!basic.time_available || !basic.location_available) return; const fixed dt = delta_time.Update(basic.time, fixed(0.5), fixed(20)); if (negative(dt)) { Reset(); flying.Reset(); } if (!positive(dt)) return; const auto any_altitude = basic.GetAnyAltitude(); if (!basic.airspeed_available && !calculated.altitude_agl_valid && any_altitude.first && !negative(last_ground_altitude) && any_altitude.second > last_ground_altitude + fixed(250)) { /* lower the threshold for "not moving" when the aircraft is high above the take-off airfield and there's no airspeed probe; this shall reduce the risk of false landing detection when flying in strong head wind (e.g. ridge or wave) */ fixed dh = any_altitude.second - last_ground_altitude; if (dh > fixed(1000)) takeoff_speed /= 4; else if (dh > fixed(500)) takeoff_speed /= 2; else takeoff_speed = takeoff_speed * 2 / 3; } if (CheckTakeOffSpeed(takeoff_speed, basic) || CheckAltitudeAGL(calculated)) Moving(flying, basic.time, dt, basic.location); else if (!flying.flying || (CheckLandingSpeed(takeoff_speed, basic) && (!any_altitude.first || !CheckClimbing(dt, any_altitude.second)))) Stationary(flying, basic.time, dt, basic.location); if (basic.engine_noise_level_available) CheckPowered(dt, basic, flying); if (any_altitude.first) { if (flying.on_ground) last_ground_altitude = any_altitude.second; CheckRelease(flying, basic.time, basic.location, any_altitude.second); } else sinking_since = fixed(-1); if (flying.flying && flying.release_location.IsValid()) { fixed distance = basic.location.Distance(flying.release_location); if (distance > flying.far_distance) { flying.far_location = basic.location; flying.far_distance = distance; } } }
void WaveComputer::Compute(const NMEAInfo &basic, const FlyingState &flight, WaveResult &result, const WaveSettings &settings) { const bool new_enabled = settings.enabled; if (new_enabled != last_enabled) { last_enabled = new_enabled; if (new_enabled) { /* the WaveComputer has just been enabled - initialise internal state */ Initialise(); } else /* the WaveComputer has just been disabled - clear the result */ result.Clear(); } if (!new_enabled) { /* we're disabled: bail out */ assert(result.waves.empty()); return; } if (!flight.IsGliding()) { /* no wave calculations while not in gliding free-flight */ ResetCurrent(); return; } const auto netto_vario_available = GetNettoVarioAvailable(basic); if (!basic.location_available.Modified(last_location_available) || !netto_vario_available.Modified(last_netto_vario_available)) /* no new data since the last call; need both a new GPS location and a vario value */ return; const auto dt = delta_time.Update(basic.time, 0.5, 20); if (dt < 0) /* time warp */ Reset(); if (dt <= 0) /* throttle */ return; const auto vario = basic.netto_vario; constexpr double threshold(0.5); if (vario > threshold) { /* positive vario value - feed it to the #LeastSquares instance */ if (ls.IsEmpty()) /* initialise the projection each time we inspect a new wave "candidate" */ projection.SetCenter(basic.location); auto flat = projection.ProjectFloat(basic.location); ls.Update(flat.x, flat.y, vario - threshold / 2); } if (vario < 0) sinking_clock.Add(dt); else sinking_clock.Subtract(dt); const bool sinking = sinking_clock >= dt + 1; if (sinking) { /* we've been sinking; stop calculating the current wave; prepare to flush the #LeastSquares instance */ if (ls.GetCount() > 30) { /* we've been lifting in the wave for some time; see if we really spotted a wave */ const WaveInfo wave = GetWaveInfo(ls, projection, basic.time_available ? basic.time : 0); if (wave.IsDefined()) /* yes, spotted a wave: copy it from the #LeastSquares instance to the list of waves */ FoundWave(wave); } ls.Reset(); } if (basic.time_available) /* forget all waves which are older than 8 hours */ Decay(basic.time - 8 * 3600); /* fill the #WaveResult */ result.Clear(); /* first copy the wave that is currently being calculated (partial data) */ WaveInfo wave = GetWaveInfo(ls, projection, basic.time_available ? basic.time : 0); if (wave.IsDefined()) result.waves.push_back(wave); /* now copy the rest */ for (auto i = waves.begin(), end = waves.end(); i != end && !result.waves.full(); ++i) result.waves.push_back(*i); /* remember some data for the next iteration */ last_location_available = basic.location_available; last_netto_vario_available = netto_vario_available; }