4 XCSoar Glide Computer - http://www.xcsoar.org/
5 Copyright (C) 2000-2013 The XCSoar Project
6 A detailed list of copyright holders can be found in the file "AUTHORS".
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "LiftDatabaseComputer.hpp"
25 #include "Engine/Navigation/TraceHistory.hpp"
26 #include "NMEA/LiftDatabase.hpp"
27 #include "NMEA/MoreData.hpp"
28 #include "NMEA/CirclingInfo.hpp"
29 #include "Util/Clamp.hpp"
32 LiftDatabaseComputer::Clear(LiftDatabase
&lift_database
,
33 TraceVariableHistory
&circling_average_trace
)
35 lift_database
.Clear();
37 circling_average_trace
.clear();
41 LiftDatabaseComputer::Reset(LiftDatabase
&lift_database
,
42 TraceVariableHistory
&circling_average_trace
)
44 last_circling
= false;
45 last_heading
= Angle::Zero();
47 Clear(lift_database
, circling_average_trace
);
51 * This function converts a heading into an unsigned index for the LiftDatabase.
53 * This is calculated with Angles to deal with the 360 degree limit.
61 * @param heading The heading to convert
62 * @return The index for the LiftDatabase array
65 heading_to_index(Angle
&heading
)
67 static constexpr Angle afive
= Angle::Degrees(5);
69 unsigned index
= (unsigned)
70 ((heading
+ afive
).AsBearing().Degrees() / 10);
72 return Clamp(index
, 0u, 35u);
76 LiftDatabaseComputer::Compute(LiftDatabase
&lift_database
,
77 TraceVariableHistory
&circling_average_trace
,
78 const MoreData
&basic
,
79 const CirclingInfo
&circling_info
)
81 // If we just started circling
82 // -> reset the database because this is a new thermal
83 if (!circling_info
.circling
&& last_circling
)
84 Clear(lift_database
, circling_average_trace
);
86 // Determine the direction in which we are circling
87 bool left
= circling_info
.TurningLeft();
89 // Depending on the direction set the step size sign for the
91 Angle heading_step
= left
? Angle::Degrees(-10) : Angle::Degrees(10);
93 const Angle heading
= basic
.attitude
.heading
;
95 // Start at the last heading and add heading_step until the current heading
96 // is reached. For each heading save the current lift value into the
97 // LiftDatabase. Last and current heading are included since they are
98 // a part of the ten degree interval most of the time.
100 // This is done with Angles to deal with the 360 degrees limit.
101 // e.g. last heading 348 degrees, current heading 21 degrees
103 // The loop condition stops until the current heading is reached.
104 // Depending on the circling direction the current heading will be
105 // smaller or bigger then the last one, because of that negative() is
106 // tested against the left variable.
107 for (Angle h
= last_heading
;
108 left
== negative((heading
- h
).AsDelta().Degrees());
110 unsigned index
= heading_to_index(h
);
111 lift_database
[index
] = basic
.brutto_vario
;
114 // detect zero crossing
115 if ((heading
< Angle::QuarterCircle() &&
116 last_heading
.Degrees() > fixed(270)) ||
117 (last_heading
< Angle::QuarterCircle() &&
118 heading
.Degrees() > fixed(270))) {
120 fixed h_av
= fixed(0);
121 for (auto i
: lift_database
)
124 h_av
/= lift_database
.size();
125 circling_average_trace
.push(h_av
);
128 last_circling
= circling_info
.circling
;
129 last_heading
= basic
.attitude
.heading
;