telegps-v1.0: Provide one log and append to it
[fw/altos] / src / kernel / 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 #include "ao_flight.h"
21 #endif
22
23 #include "ao_sample.h"
24 #include "ao_kalman.h"
25
26 static __pdata ao_k_t           ao_k_height;
27 static __pdata ao_k_t           ao_k_speed;
28 static __pdata ao_k_t           ao_k_accel;
29
30 #define AO_K_STEP_100           to_fix_v(0.01)
31 #define AO_K_STEP_2_2_100       to_fix_v(0.00005)
32
33 #define AO_K_STEP_10            to_fix_v(0.1)
34 #define AO_K_STEP_2_2_10        to_fix_v(0.005)
35
36 #define AO_K_STEP_1             to_fix_v(1)
37 #define AO_K_STEP_2_2_1         to_fix_v(0.5)
38
39 __pdata ao_v_t                  ao_height;
40 __pdata ao_v_t                  ao_speed;
41 __pdata ao_v_t                  ao_accel;
42 __xdata ao_v_t                  ao_max_height;
43 static __pdata ao_k_t           ao_avg_height_scaled;
44 __xdata ao_v_t                  ao_avg_height;
45
46 __pdata ao_v_t                  ao_error_h;
47 __pdata ao_v_t                  ao_error_h_sq_avg;
48
49 #if HAS_ACCEL
50 __pdata ao_v_t                  ao_error_a;
51 #endif
52
53 static void
54 ao_kalman_predict(void)
55 {
56 #ifdef AO_FLIGHT_TEST
57         if (ao_sample_tick - ao_sample_prev_tick > 50) {
58                 ao_k_height += ((ao_k_t) ao_speed * AO_K_STEP_1 +
59                                 (ao_k_t) ao_accel * AO_K_STEP_2_2_1) >> 4;
60                 ao_k_speed += (ao_k_t) ao_accel * AO_K_STEP_1;
61
62                 return;
63         }
64         if (ao_sample_tick - ao_sample_prev_tick > 5) {
65                 ao_k_height += ((ao_k_t) ao_speed * AO_K_STEP_10 +
66                                 (ao_k_t) ao_accel * AO_K_STEP_2_2_10) >> 4;
67                 ao_k_speed += (ao_k_t) ao_accel * AO_K_STEP_10;
68
69                 return;
70         }
71         if (ao_flight_debug) {
72                 printf ("predict speed %g + (%g * %g) = %g\n",
73                         ao_k_speed / (65536.0 * 16.0), ao_accel / 16.0, AO_K_STEP_100 / 65536.0,
74                         (ao_k_speed + (ao_k_t) ao_accel * AO_K_STEP_100) / (65536.0 * 16.0));
75         }
76 #endif
77         ao_k_height += ((ao_k_t) ao_speed * AO_K_STEP_100 +
78                         (ao_k_t) ao_accel * AO_K_STEP_2_2_100) >> 4;
79         ao_k_speed += (ao_k_t) ao_accel * AO_K_STEP_100;
80 }
81
82 static void
83 ao_kalman_err_height(void)
84 {
85         ao_v_t  e;
86         ao_v_t height_distrust;
87 #if HAS_ACCEL
88         ao_v_t  speed_distrust;
89 #endif
90
91         ao_error_h = ao_sample_height - (ao_v_t) (ao_k_height >> 16);
92
93         e = ao_error_h;
94         if (e < 0)
95                 e = -e;
96         if (e > 127)
97                 e = 127;
98 #if HAS_ACCEL
99         ao_error_h_sq_avg -= ao_error_h_sq_avg >> 2;
100         ao_error_h_sq_avg += (e * e) >> 2;
101 #else
102         ao_error_h_sq_avg -= ao_error_h_sq_avg >> 4;
103         ao_error_h_sq_avg += (e * e) >> 4;
104 #endif
105
106         if (ao_flight_state >= ao_flight_drogue)
107                 return;
108         height_distrust = ao_sample_alt - AO_MAX_BARO_HEIGHT;
109 #if HAS_ACCEL
110         /* speed is stored * 16, but we need to ramp between 200 and 328, so
111          * we want to multiply by 2. The result is a shift by 3.
112          */
113         speed_distrust = (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) >> (4 - 1);
114         if (speed_distrust <= 0)
115                 speed_distrust = 0;
116         else if (speed_distrust > height_distrust)
117                 height_distrust = speed_distrust;
118 #endif
119         if (height_distrust > 0) {
120 #ifdef AO_FLIGHT_TEST
121                 int     old_ao_error_h = ao_error_h;
122 #endif
123                 if (height_distrust > 0x100)
124                         height_distrust = 0x100;
125                 ao_error_h = (ao_v_t) (((ao_k_t) ao_error_h * (0x100 - height_distrust)) >> 8);
126 #ifdef AO_FLIGHT_TEST
127                 if (ao_flight_debug) {
128                         printf("over height %g over speed %g distrust: %g height: error %d -> %d\n",
129                                (double) (ao_sample_alt - AO_MAX_BARO_HEIGHT),
130                                (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) / 16.0,
131                                height_distrust / 256.0,
132                                old_ao_error_h, ao_error_h);
133                 }
134 #endif
135         }
136 }
137
138 static void
139 ao_kalman_correct_baro(void)
140 {
141         ao_kalman_err_height();
142 #ifdef AO_FLIGHT_TEST
143         if (ao_sample_tick - ao_sample_prev_tick > 50) {
144                 ao_k_height += (ao_k_t) AO_BARO_K0_1 * ao_error_h;
145                 ao_k_speed  += (ao_k_t) AO_BARO_K1_1 * ao_error_h;
146                 ao_k_accel  += (ao_k_t) AO_BARO_K2_1 * ao_error_h;
147                 return;
148         }
149         if (ao_sample_tick - ao_sample_prev_tick > 5) {
150                 ao_k_height += (ao_k_t) AO_BARO_K0_10 * ao_error_h;
151                 ao_k_speed  += (ao_k_t) AO_BARO_K1_10 * ao_error_h;
152                 ao_k_accel  += (ao_k_t) AO_BARO_K2_10 * ao_error_h;
153                 return;
154         }
155 #endif
156         ao_k_height += (ao_k_t) AO_BARO_K0_100 * ao_error_h;
157         ao_k_speed  += (ao_k_t) AO_BARO_K1_100 * ao_error_h;
158         ao_k_accel  += (ao_k_t) AO_BARO_K2_100 * ao_error_h;
159 }
160
161 #if HAS_ACCEL
162
163 static void
164 ao_kalman_err_accel(void)
165 {
166         ao_k_t  accel;
167
168         accel = (ao_config.accel_plus_g - ao_sample_accel) * ao_accel_scale;
169
170         /* Can't use ao_accel here as it is the pre-prediction value still */
171         ao_error_a = (accel - ao_k_accel) >> 16;
172 }
173
174 #ifndef FORCE_ACCEL
175 static void
176 ao_kalman_correct_both(void)
177 {
178         ao_kalman_err_height();
179         ao_kalman_err_accel();
180
181 #ifdef AO_FLIGHT_TEST
182         if (ao_sample_tick - ao_sample_prev_tick > 50) {
183                 if (ao_flight_debug) {
184                         printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n",
185                                 ao_k_speed / (65536.0 * 16.0),
186                                 (double) ao_error_h, AO_BOTH_K10_1 / 65536.0,
187                                 (double) ao_error_a, AO_BOTH_K11_1 / 65536.0,
188                                 (ao_k_speed +
189                                  (ao_k_t) AO_BOTH_K10_1 * ao_error_h +
190                                  (ao_k_t) AO_BOTH_K11_1 * ao_error_a) / (65536.0 * 16.0));
191                 }
192                 ao_k_height +=
193                         (ao_k_t) AO_BOTH_K00_1 * ao_error_h +
194                         (ao_k_t) AO_BOTH_K01_1 * ao_error_a;
195                 ao_k_speed +=
196                         (ao_k_t) AO_BOTH_K10_1 * ao_error_h +
197                         (ao_k_t) AO_BOTH_K11_1 * ao_error_a;
198                 ao_k_accel +=
199                         (ao_k_t) AO_BOTH_K20_1 * ao_error_h +
200                         (ao_k_t) AO_BOTH_K21_1 * ao_error_a;
201                 return;
202         }
203         if (ao_sample_tick - ao_sample_prev_tick > 5) {
204                 if (ao_flight_debug) {
205                         printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n",
206                                 ao_k_speed / (65536.0 * 16.0),
207                                 (double) ao_error_h, AO_BOTH_K10_10 / 65536.0,
208                                 (double) ao_error_a, AO_BOTH_K11_10 / 65536.0,
209                                 (ao_k_speed +
210                                  (ao_k_t) AO_BOTH_K10_10 * ao_error_h +
211                                  (ao_k_t) AO_BOTH_K11_10 * ao_error_a) / (65536.0 * 16.0));
212                 }
213                 ao_k_height +=
214                         (ao_k_t) AO_BOTH_K00_10 * ao_error_h +
215                         (ao_k_t) AO_BOTH_K01_10 * ao_error_a;
216                 ao_k_speed +=
217                         (ao_k_t) AO_BOTH_K10_10 * ao_error_h +
218                         (ao_k_t) AO_BOTH_K11_10 * ao_error_a;
219                 ao_k_accel +=
220                         (ao_k_t) AO_BOTH_K20_10 * ao_error_h +
221                         (ao_k_t) AO_BOTH_K21_10 * ao_error_a;
222                 return;
223         }
224         if (ao_flight_debug) {
225                 printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n",
226                         ao_k_speed / (65536.0 * 16.0),
227                         (double) ao_error_h, AO_BOTH_K10_100 / 65536.0,
228                         (double) ao_error_a, AO_BOTH_K11_100 / 65536.0,
229                         (ao_k_speed +
230                          (ao_k_t) AO_BOTH_K10_100 * ao_error_h +
231                          (ao_k_t) AO_BOTH_K11_100 * ao_error_a) / (65536.0 * 16.0));
232         }
233 #endif
234         ao_k_height +=
235                 (ao_k_t) AO_BOTH_K00_100 * ao_error_h +
236                 (ao_k_t) AO_BOTH_K01_100 * ao_error_a;
237         ao_k_speed +=
238                 (ao_k_t) AO_BOTH_K10_100 * ao_error_h +
239                 (ao_k_t) AO_BOTH_K11_100 * ao_error_a;
240         ao_k_accel +=
241                 (ao_k_t) AO_BOTH_K20_100 * ao_error_h +
242                 (ao_k_t) AO_BOTH_K21_100 * ao_error_a;
243 }
244
245 #else
246
247 static void
248 ao_kalman_correct_accel(void)
249 {
250         ao_kalman_err_accel();
251
252         if (ao_sample_tick - ao_sample_prev_tick > 5) {
253                 ao_k_height +=(ao_k_t) AO_ACCEL_K0_10 * ao_error_a;
254                 ao_k_speed  += (ao_k_t) AO_ACCEL_K1_10 * ao_error_a;
255                 ao_k_accel  += (ao_k_t) AO_ACCEL_K2_10 * ao_error_a;
256                 return;
257         }
258         ao_k_height += (ao_k_t) AO_ACCEL_K0_100 * ao_error_a;
259         ao_k_speed  += (ao_k_t) AO_ACCEL_K1_100 * ao_error_a;
260         ao_k_accel  += (ao_k_t) AO_ACCEL_K2_100 * ao_error_a;
261 }
262
263 #endif /* else FORCE_ACCEL */
264 #endif /* HAS_ACCEL */
265
266 void
267 ao_kalman(void)
268 {
269         ao_kalman_predict();
270 #if HAS_ACCEL
271         if (ao_flight_state <= ao_flight_coast) {
272 #ifdef FORCE_ACCEL
273                 ao_kalman_correct_accel();
274 #else
275                 ao_kalman_correct_both();
276 #endif
277         } else
278 #endif
279                 ao_kalman_correct_baro();
280         ao_height = from_fix(ao_k_height);
281         ao_speed = from_fix(ao_k_speed);
282         ao_accel = from_fix(ao_k_accel);
283         if (ao_height > ao_max_height)
284                 ao_max_height = ao_height;
285         ao_avg_height_scaled = ao_avg_height_scaled - ao_avg_height + ao_sample_height;
286 #ifdef AO_FLIGHT_TEST
287         if (ao_sample_tick - ao_sample_prev_tick > 50)
288                 ao_avg_height = (ao_avg_height_scaled + 1) >> 1;
289         else if (ao_sample_tick - ao_sample_prev_tick > 5)
290                 ao_avg_height = (ao_avg_height_scaled + 7) >> 4;
291         else 
292 #endif
293                 ao_avg_height = (ao_avg_height_scaled + 63) >> 7;
294 }