altos: re-order ao_task to match single-arch code
[fw/altos] / src / core / ao_kalman.c
1 /*
2  * Copyright © 2011 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #ifndef AO_FLIGHT_TEST
19 #include "ao.h"
20 #endif
21
22 #include "ao_kalman.h"
23
24 static __pdata int32_t          ao_k_height;
25 static __pdata int32_t          ao_k_speed;
26 static __pdata int32_t          ao_k_accel;
27
28 #define AO_K_STEP_100           to_fix16(0.01)
29 #define AO_K_STEP_2_2_100       to_fix16(0.00005)
30
31 #define AO_K_STEP_10            to_fix16(0.1)
32 #define AO_K_STEP_2_2_10        to_fix16(0.005)
33
34 #define AO_K_STEP_1             to_fix16(1)
35 #define AO_K_STEP_2_2_1         to_fix16(0.5)
36
37 __pdata int16_t                 ao_height;
38 __pdata int16_t                 ao_speed;
39 __pdata int16_t                 ao_accel;
40 __pdata int16_t                 ao_max_height;
41 static __pdata int32_t          ao_avg_height_scaled;
42 __pdata int16_t                 ao_avg_height;
43
44 __pdata int16_t                 ao_error_h;
45 __pdata int16_t                 ao_error_h_sq_avg;
46
47 #if HAS_ACCEL
48 __pdata int16_t                 ao_error_a;
49 #endif
50
51 static void
52 ao_kalman_predict(void)
53 {
54 #ifdef AO_FLIGHT_TEST
55         if (ao_sample_tick - ao_sample_prev_tick > 50) {
56                 ao_k_height += ((int32_t) ao_speed * AO_K_STEP_1 +
57                                 (int32_t) ao_accel * AO_K_STEP_2_2_1) >> 4;
58                 ao_k_speed += (int32_t) ao_accel * AO_K_STEP_1;
59
60                 return;
61         }
62         if (ao_sample_tick - ao_sample_prev_tick > 5) {
63                 ao_k_height += ((int32_t) ao_speed * AO_K_STEP_10 +
64                                 (int32_t) ao_accel * AO_K_STEP_2_2_10) >> 4;
65                 ao_k_speed += (int32_t) ao_accel * AO_K_STEP_10;
66
67                 return;
68         }
69         if (ao_flight_debug) {
70                 printf ("predict speed %g + (%g * %g) = %g\n",
71                         ao_k_speed / (65536.0 * 16.0), ao_accel / 16.0, AO_K_STEP_100 / 65536.0,
72                         (ao_k_speed + (int32_t) ao_accel * AO_K_STEP_100) / (65536.0 * 16.0));
73         }
74 #endif
75         ao_k_height += ((int32_t) ao_speed * AO_K_STEP_100 +
76                         (int32_t) ao_accel * AO_K_STEP_2_2_100) >> 4;
77         ao_k_speed += (int32_t) ao_accel * AO_K_STEP_100;
78 }
79
80 static void
81 ao_kalman_err_height(void)
82 {
83         int16_t e;
84         int16_t height_distrust;
85 #if HAS_ACCEL
86         int16_t speed_distrust;
87 #endif
88
89         ao_error_h = ao_sample_height - (int16_t) (ao_k_height >> 16);
90
91         e = ao_error_h;
92         if (e < 0)
93                 e = -e;
94         if (e > 127)
95                 e = 127;
96 #if HAS_ACCEL
97         ao_error_h_sq_avg -= ao_error_h_sq_avg >> 2;
98         ao_error_h_sq_avg += (e * e) >> 2;
99 #else
100         ao_error_h_sq_avg -= ao_error_h_sq_avg >> 4;
101         ao_error_h_sq_avg += (e * e) >> 4;
102 #endif
103
104         if (ao_flight_state >= ao_flight_drogue)
105                 return;
106         height_distrust = ao_sample_alt - AO_MAX_BARO_HEIGHT;
107 #if HAS_ACCEL
108         /* speed is stored * 16, but we need to ramp between 200 and 328, so
109          * we want to multiply by 2. The result is a shift by 3.
110          */
111         speed_distrust = (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) >> (4 - 1);
112         if (speed_distrust <= 0)
113                 speed_distrust = 0;
114         else if (speed_distrust > height_distrust)
115                 height_distrust = speed_distrust;
116 #endif
117         if (height_distrust > 0) {
118 #ifdef AO_FLIGHT_TEST
119                 int     old_ao_error_h = ao_error_h;
120 #endif
121                 if (height_distrust > 0x100)
122                         height_distrust = 0x100;
123                 ao_error_h = (int16_t) (((int32_t) ao_error_h * (0x100 - height_distrust)) >> 8);
124 #ifdef AO_FLIGHT_TEST
125                 if (ao_flight_debug) {
126                         printf("over height %g over speed %g distrust: %g height: error %d -> %d\n",
127                                (double) (ao_sample_alt - AO_MAX_BARO_HEIGHT),
128                                (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) / 16.0,
129                                height_distrust / 256.0,
130                                old_ao_error_h, ao_error_h);
131                 }
132 #endif
133         }
134 }
135
136 static void
137 ao_kalman_correct_baro(void)
138 {
139         ao_kalman_err_height();
140 #ifdef AO_FLIGHT_TEST
141         if (ao_sample_tick - ao_sample_prev_tick > 50) {
142                 ao_k_height += (int32_t) AO_BARO_K0_1 * ao_error_h;
143                 ao_k_speed  += (int32_t) AO_BARO_K1_1 * ao_error_h;
144                 ao_k_accel  += (int32_t) AO_BARO_K2_1 * ao_error_h;
145                 return;
146         }
147         if (ao_sample_tick - ao_sample_prev_tick > 5) {
148                 ao_k_height += (int32_t) AO_BARO_K0_10 * ao_error_h;
149                 ao_k_speed  += (int32_t) AO_BARO_K1_10 * ao_error_h;
150                 ao_k_accel  += (int32_t) AO_BARO_K2_10 * ao_error_h;
151                 return;
152         }
153 #endif
154         ao_k_height += (int32_t) AO_BARO_K0_100 * ao_error_h;
155         ao_k_speed  += (int32_t) AO_BARO_K1_100 * ao_error_h;
156         ao_k_accel  += (int32_t) AO_BARO_K2_100 * ao_error_h;
157 }
158
159 #if HAS_ACCEL
160
161 static void
162 ao_kalman_err_accel(void)
163 {
164         int32_t accel;
165
166         accel = (ao_ground_accel - ao_sample_accel) * ao_accel_scale;
167
168         /* Can't use ao_accel here as it is the pre-prediction value still */
169         ao_error_a = (accel - ao_k_accel) >> 16;
170 }
171
172 static void
173 ao_kalman_correct_both(void)
174 {
175         ao_kalman_err_height();
176         ao_kalman_err_accel();
177
178 #ifdef AO_FLIGHT_TEST
179         if (ao_sample_tick - ao_sample_prev_tick > 50) {
180                 if (ao_flight_debug) {
181                         printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n",
182                                 ao_k_speed / (65536.0 * 16.0),
183                                 (double) ao_error_h, AO_BOTH_K10_1 / 65536.0,
184                                 (double) ao_error_a, AO_BOTH_K11_1 / 65536.0,
185                                 (ao_k_speed +
186                                  (int32_t) AO_BOTH_K10_1 * ao_error_h +
187                                  (int32_t) AO_BOTH_K11_1 * ao_error_a) / (65536.0 * 16.0));
188                 }
189                 ao_k_height +=
190                         (int32_t) AO_BOTH_K00_1 * ao_error_h +
191                         (int32_t) AO_BOTH_K01_1 * ao_error_a;
192                 ao_k_speed +=
193                         (int32_t) AO_BOTH_K10_1 * ao_error_h +
194                         (int32_t) AO_BOTH_K11_1 * ao_error_a;
195                 ao_k_accel +=
196                         (int32_t) AO_BOTH_K20_1 * ao_error_h +
197                         (int32_t) AO_BOTH_K21_1 * ao_error_a;
198                 return;
199         }
200         if (ao_sample_tick - ao_sample_prev_tick > 5) {
201                 if (ao_flight_debug) {
202                         printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n",
203                                 ao_k_speed / (65536.0 * 16.0),
204                                 (double) ao_error_h, AO_BOTH_K10_10 / 65536.0,
205                                 (double) ao_error_a, AO_BOTH_K11_10 / 65536.0,
206                                 (ao_k_speed +
207                                  (int32_t) AO_BOTH_K10_10 * ao_error_h +
208                                  (int32_t) AO_BOTH_K11_10 * ao_error_a) / (65536.0 * 16.0));
209                 }
210                 ao_k_height +=
211                         (int32_t) AO_BOTH_K00_10 * ao_error_h +
212                         (int32_t) AO_BOTH_K01_10 * ao_error_a;
213                 ao_k_speed +=
214                         (int32_t) AO_BOTH_K10_10 * ao_error_h +
215                         (int32_t) AO_BOTH_K11_10 * ao_error_a;
216                 ao_k_accel +=
217                         (int32_t) AO_BOTH_K20_10 * ao_error_h +
218                         (int32_t) AO_BOTH_K21_10 * ao_error_a;
219                 return;
220         }
221         if (ao_flight_debug) {
222                 printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n",
223                         ao_k_speed / (65536.0 * 16.0),
224                         (double) ao_error_h, AO_BOTH_K10_100 / 65536.0,
225                         (double) ao_error_a, AO_BOTH_K11_100 / 65536.0,
226                         (ao_k_speed +
227                          (int32_t) AO_BOTH_K10_100 * ao_error_h +
228                          (int32_t) AO_BOTH_K11_100 * ao_error_a) / (65536.0 * 16.0));
229         }
230 #endif
231         ao_k_height +=
232                 (int32_t) AO_BOTH_K00_100 * ao_error_h +
233                 (int32_t) AO_BOTH_K01_100 * ao_error_a;
234         ao_k_speed +=
235                 (int32_t) AO_BOTH_K10_100 * ao_error_h +
236                 (int32_t) AO_BOTH_K11_100 * ao_error_a;
237         ao_k_accel +=
238                 (int32_t) AO_BOTH_K20_100 * ao_error_h +
239                 (int32_t) AO_BOTH_K21_100 * ao_error_a;
240 }
241
242 #ifdef FORCE_ACCEL
243 static void
244 ao_kalman_correct_accel(void)
245 {
246         ao_kalman_err_accel();
247
248         if (ao_sample_tick - ao_sample_prev_tick > 5) {
249                 ao_k_height +=(int32_t) AO_ACCEL_K0_10 * ao_error_a;
250                 ao_k_speed  += (int32_t) AO_ACCEL_K1_10 * ao_error_a;
251                 ao_k_accel  += (int32_t) AO_ACCEL_K2_10 * ao_error_a;
252                 return;
253         }
254         ao_k_height += (int32_t) AO_ACCEL_K0_100 * ao_error_a;
255         ao_k_speed  += (int32_t) AO_ACCEL_K1_100 * ao_error_a;
256         ao_k_accel  += (int32_t) AO_ACCEL_K2_100 * ao_error_a;
257 }
258 #endif
259 #endif /* HAS_ACCEL */
260
261 void
262 ao_kalman(void)
263 {
264         ao_kalman_predict();
265 #if HAS_ACCEL
266         if (ao_flight_state <= ao_flight_coast) {
267 #ifdef FORCE_ACCEL
268                 ao_kalman_correct_accel();
269 #else
270                 ao_kalman_correct_both();
271 #endif
272         } else
273 #endif
274                 ao_kalman_correct_baro();
275         ao_height = from_fix(ao_k_height);
276         ao_speed = from_fix(ao_k_speed);
277         ao_accel = from_fix(ao_k_accel);
278         if (ao_height > ao_max_height)
279                 ao_max_height = ao_height;
280         ao_avg_height_scaled = ao_avg_height_scaled - ao_avg_height + ao_sample_height;
281 #ifdef AO_FLIGHT_TEST
282         if (ao_sample_tick - ao_sample_prev_tick > 50)
283                 ao_avg_height = (ao_avg_height_scaled + 1) >> 1;
284         else if (ao_sample_tick - ao_sample_prev_tick > 5)
285                 ao_avg_height = (ao_avg_height_scaled + 7) >> 4;
286         else 
287 #endif
288                 ao_avg_height = (ao_avg_height_scaled + 63) >> 7;
289 #ifdef AO_FLIGHT_TEST
290         ao_sample_prev_tick = ao_sample_tick;
291 #endif
292 }