/** * Attempt to compute airspeed when it is not yet available from: * 1) dynamic pressure and air density derived from some altitude. * 2) pitot pressure and static pressure. * 3) ground speed and wind. */ static void ComputeAirspeed(NMEAInfo &basic, const DerivedInfo &calculated) { if (basic.airspeed_available && basic.airspeed_real) /* got it already */ return; const auto any_altitude = basic.GetAnyAltitude(); if (!basic.airspeed_available && any_altitude.first) { fixed dyn; bool available = false; if (basic.dyn_pressure_available) { dyn = basic.dyn_pressure.GetHectoPascal(); available = true; } else if (basic.pitot_pressure_available && basic.static_pressure_available) { dyn = basic.pitot_pressure.GetHectoPascal() - basic.static_pressure.GetHectoPascal(); available = true; } if (available) { basic.indicated_airspeed = sqrt(fixed(163.2653061) * dyn); basic.true_airspeed = basic.indicated_airspeed * AirDensityRatio(any_altitude.second); basic.airspeed_available.Update(basic.clock); basic.airspeed_real = true; // Anyway not less real then any other method. return; } } if (!basic.ground_speed_available || !calculated.wind_available || !calculated.flight.flying) { /* impossible to calculate */ basic.airspeed_available.Clear(); return; } fixed TrueAirspeedEstimated = fixed(0); const SpeedVector wind = calculated.wind; if (positive(basic.ground_speed) || wind.IsNonZero()) { fixed x0 = basic.track.fastsine() * basic.ground_speed; fixed y0 = basic.track.fastcosine() * basic.ground_speed; x0 += wind.bearing.fastsine() * wind.norm; y0 += wind.bearing.fastcosine() * wind.norm; TrueAirspeedEstimated = SmallHypot(x0, y0); } basic.true_airspeed = TrueAirspeedEstimated; basic.indicated_airspeed = TrueAirspeedEstimated; if (any_altitude.first) basic.indicated_airspeed /= AirDensityRatio(any_altitude.second); basic.airspeed_available.Update(basic.clock); basic.airspeed_real = false; }
void GlideState::CalcSpeedups(const SpeedVector _wind) { if (_wind.IsNonZero()) { wind = _wind; effective_wind_angle = wind.bearing.Reciprocal() - vector.bearing; wind_speed_squared = sqr(wind.norm); head_wind = -wind.norm * effective_wind_angle.cos(); } else { wind = SpeedVector::Zero(); effective_wind_angle = Angle::Zero(); head_wind = fixed(0); wind_speed_squared = fixed(0); } }
void GlideComputerAirData::Heading(const NMEAInfo &basic, DerivedInfo &calculated) { const SpeedVector wind = calculated.wind; if (calculated.wind_available && (positive(basic.ground_speed) || wind.IsNonZero()) && calculated.flight.flying) { fixed x0 = basic.track.fastsine() * basic.ground_speed; fixed y0 = basic.track.fastcosine() * basic.ground_speed; x0 += wind.bearing.fastsine() * wind.norm; y0 += wind.bearing.fastcosine() * wind.norm; calculated.heading = Angle::Radians(atan2(x0, y0)).AsBearing(); } else { calculated.heading = basic.track; } }
static void DrawThermalSources(Canvas &canvas, const MaskedIcon &icon, const WindowProjection &projection, const T &sources, const double aircraft_altitude, const SpeedVector &wind) { for (const auto &source : sources) { // find height difference if (aircraft_altitude < source.ground_height) continue; // draw thermal at location it would be at the glider's height GeoPoint location = wind.IsNonZero() ? source.CalculateAdjustedLocation(aircraft_altitude, wind) : source.location; // draw if it is in the field of view PixelPoint pt; if (projection.GeoToScreenIfVisible(location, pt)) icon.Draw(canvas, pt); } }