Airfest 2013: Bdale's new airframe on Loki M with TMv1 and Tmega
[fw/tmflights] / parse
1 #!/usr/bin/env nickle
2
3 /*
4  * Pressure Sensor Model, version 1.1
5  *
6  * written by Holly Grimes
7  *
8  * Uses the International Standard Atmosphere as described in
9  *   "A Quick Derivation relating altitude to air pressure" (version 1.03)
10  *    from the Portland State Aerospace Society, except that the atmosphere
11  *    is divided into layers with each layer having a different lapse rate.
12  *
13  * Lapse rate data for each layer was obtained from Wikipedia on Sept. 1, 2007
14  *    at site <http://en.wikipedia.org/wiki/International_Standard_Atmosphere
15  *
16  * Height measurements use the local tangent plane.  The postive z-direction is up.
17  *
18  * All measurements are given in SI units (Kelvin, Pascal, meter, meters/second^2).
19  *   The lapse rate is given in Kelvin/meter, the gas constant for air is given
20  *   in Joules/(kilogram-Kelvin).
21  */
22
23 const real GRAVITATIONAL_ACCELERATION = -9.80665;
24 const real AIR_GAS_CONSTANT = 287.053;
25 const int NUMBER_OF_LAYERS = 7;
26 const real MAXIMUM_ALTITUDE = 84852;
27 const real MINIMUM_PRESSURE = 0.3734;
28 const real LAYER0_BASE_TEMPERATURE = 288.15;
29 const real LAYER0_BASE_PRESSURE = 101325;
30
31 /* lapse rate and base altitude for each layer in the atmosphere */
32 const real[NUMBER_OF_LAYERS] lapse_rate = {
33         -0.0065, 0.0, 0.001, 0.0028, 0.0, -0.0028, -0.002
34 };
35 const int[NUMBER_OF_LAYERS] base_altitude = {
36         0, 11000, 20000, 32000, 47000, 51000, 71000
37 };
38
39
40 /* outputs atmospheric pressure associated with the given altitude. altitudes
41    are measured with respect to the mean sea level */
42 real altitude_to_pressure(real altitude) {
43  
44    real base_temperature = LAYER0_BASE_TEMPERATURE;
45    real base_pressure = LAYER0_BASE_PRESSURE;
46
47    real pressure;
48    real base; /* base for function to determine pressure */
49    real exponent; /* exponent for function to determine pressure */
50    int layer_number; /* identifies layer in the atmosphere */
51    int delta_z; /* difference between two altitudes */
52    
53    if (altitude > MAXIMUM_ALTITUDE) /* FIX ME: use sensor data to improve model */
54       return 0;
55
56    /* calculate the base temperature and pressure for the atmospheric layer
57       associated with the inputted altitude */
58    for(layer_number = 0; layer_number < NUMBER_OF_LAYERS - 1 && altitude > base_altitude[layer_number + 1]; layer_number++) {
59       delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number];
60       if (lapse_rate[layer_number] == 0.0) {
61          exponent = GRAVITATIONAL_ACCELERATION * delta_z 
62               / AIR_GAS_CONSTANT / base_temperature;
63          base_pressure *= exp(exponent);
64       }
65       else {
66          base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
67          exponent = GRAVITATIONAL_ACCELERATION / 
68               (AIR_GAS_CONSTANT * lapse_rate[layer_number]);
69          base_pressure *= pow(base, exponent);
70       }
71       base_temperature += delta_z * lapse_rate[layer_number];
72    }
73
74    /* calculate the pressure at the inputted altitude */
75    delta_z = altitude - base_altitude[layer_number];
76    if (lapse_rate[layer_number] == 0.0) {
77       exponent = GRAVITATIONAL_ACCELERATION * delta_z 
78            / AIR_GAS_CONSTANT / base_temperature;
79       pressure = base_pressure * exp(exponent);
80    }
81    else {
82       base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
83       exponent = GRAVITATIONAL_ACCELERATION /
84            (AIR_GAS_CONSTANT * lapse_rate[layer_number]);
85       pressure = base_pressure * pow(base, exponent);
86    } 
87
88    return pressure;
89 }
90
91
92 /* outputs the altitude associated with the given pressure. the altitude
93    returned is measured with respect to the mean sea level */
94 real pressure_to_altitude(real pressure) {
95
96    real next_base_temperature = LAYER0_BASE_TEMPERATURE;
97    real next_base_pressure = LAYER0_BASE_PRESSURE;
98
99    real altitude;
100    real base_pressure;
101    real base_temperature;
102    real base; /* base for function to determine base pressure of next layer */
103    real exponent; /* exponent for function to determine base pressure
104                              of next layer */
105    real coefficient;
106    int layer_number; /* identifies layer in the atmosphere */
107    int delta_z; /* difference between two altitudes */
108
109    if (pressure < 0)  /* illegal pressure */
110       return -1;
111    if (pressure < MINIMUM_PRESSURE) /* FIX ME: use sensor data to improve model */
112       return MAXIMUM_ALTITUDE;
113
114    /* calculate the base temperature and pressure for the atmospheric layer
115       associated with the inputted pressure. */
116    layer_number = -1;
117    do {
118       layer_number++;
119       base_pressure = next_base_pressure;
120       base_temperature = next_base_temperature;
121       delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number];
122       if (lapse_rate[layer_number] == 0.0) {
123          exponent = GRAVITATIONAL_ACCELERATION * delta_z 
124               / AIR_GAS_CONSTANT / base_temperature;
125          next_base_pressure *= exp(exponent);
126       }
127       else {
128          base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
129          exponent = GRAVITATIONAL_ACCELERATION / 
130               (AIR_GAS_CONSTANT * lapse_rate[layer_number]);
131          next_base_pressure *= pow(base, exponent);
132       }
133       next_base_temperature += delta_z * lapse_rate[layer_number];
134    }
135    while(layer_number < NUMBER_OF_LAYERS - 1 && pressure < next_base_pressure);
136
137    /* calculate the altitude associated with the inputted pressure */
138    if (lapse_rate[layer_number] == 0.0) {
139       coefficient = (AIR_GAS_CONSTANT / GRAVITATIONAL_ACCELERATION) 
140                                                     * base_temperature;
141       altitude = base_altitude[layer_number]
142                     + coefficient * log(pressure / base_pressure);
143    }
144    else {
145       base = pressure / base_pressure;
146       exponent = AIR_GAS_CONSTANT * lapse_rate[layer_number] 
147                                        / GRAVITATIONAL_ACCELERATION;
148       coefficient = base_temperature / lapse_rate[layer_number];
149       altitude = base_altitude[layer_number]
150                       + coefficient * (pow(base, exponent) - 1);
151    }
152
153    return altitude;
154 }
155
156 real feet_to_meters(real feet)
157 {
158     return feet * (12 * 2.54 / 100);
159 }
160
161 real meters_to_feet(real meters)
162 {
163     return meters / (12 * 2.54 / 100);
164 }
165
166 /*
167  * Values for our MP3H6115A pressure sensor
168  *
169  * From the data sheet:
170  *
171  * Pressure range: 15-115 kPa
172  * Voltage at 115kPa: 2.82
173  * Output scale: 27mV/kPa
174  *
175  * 
176  * 27 mV/kPa * 2047 / 3300 counts/mV = 16.75 counts/kPa
177  * 2.82V * 2047 / 3.3 counts/V = 1749 counts/115 kPa
178  */
179
180 real counts_per_kPa = 27 * 2047 / 3300;
181 real counts_at_101_3kPa = 1674;
182
183 real count_to_kPa(real count)
184 {
185         return (count / 2047 + 0.095) / 0.009;
186 }
187 typedef struct {
188         int     type;
189         int     time;
190         int     a;
191         int     b;
192 } flight_record;
193
194 flight_record
195 read_record(file in) {
196         flight_record   r;
197         File::fscanf(in, "%c %x %x %x\n",
198                &r.type, &r.time, &r.a, &r.b);
199         return r;
200 }
201
202 real g_count = 264.8;
203 #real g_count = 262;
204 #real g_count = 400;
205 int g_base = 15735;
206
207 real
208 count_to_g(real count)
209 {
210         return (g_base + g_count - count) / g_count;
211 }
212
213 real base_alt = 0;
214 real base_sec = 0;
215 real last_alt;
216 real last_sec;
217 real last_alt_speed;
218 real accel_speed;
219 real accel_meters;
220
221 real[...]       barometer;
222 real[...]       accelerometer;
223
224 real sinc(real x) = x != 0 ? sin(x)/x : 1;
225
226 real gaussian(real x) = exp(-(x**2)/2) / sqrt(2 * pi);
227
228 load "filter.5c"
229
230 real[...] convolve(real[...] d, real[...] e) {
231         real sample(n) = n < 0 ? d[0] : n >= dim(d) ? d[dim(d)-1] : d[n];
232         real w = (dim(e) - 1) / 2;
233         real c(int center) {
234                 real    v = 0;
235                 for (int o = -w; o <= w; o++)
236                         v += sample(center + o) * e[o + w];
237                 return v;
238         }
239         return (real[dim(d)]) { [n] = c(n) };
240 }
241
242 real sum(real[...] x) { real s = 0; for(int i = 0; i < dim(x); i++) s += x[i]; return s; }
243
244 real[...] kaiser_filter(real[...] d, int half_width) {
245 #       real[half_width * 2 + 1] fir = { [n] = sinc(2 * pi * n / (2 * half_width)) };
246         real M = half_width * 2 + 1;
247         real[M] fir = { [n] = kaiser(n, M, 8) };
248         real fir_sum = sum(fir);
249         for (int i = 0; i < dim(fir); i++) fir[i] /= fir_sum;
250         return convolve(d, fir);
251 }
252
253 int[...] int_filter(int[...] d, int shift) {
254         /* Emulate the exponential IIR filter used in the TeleMetrum flight
255         software */
256
257         int     v = d[0];
258         int     n;
259         int[dim(d)] ret;
260
261         for (n = 0; n < dim(d); n++) {
262                 v -= (v + (1 << (shift - 1))) >> shift;
263                 v += (d[n] + (1 << (shift - 1))) >> shift;
264                 ret[n] = v;
265         }
266         return ret;
267 }
268
269 real gravity = 9.80665;
270
271 int[...] pressure_value, accelerometer_value;
272 real[...] clock;
273
274 void readsamples_log(file in) {
275         setdim(pressure_value, 0);
276         setdim(accelerometer_value, 0);
277         while (!File::end(in)) {
278                 flight_record r = read_record(in);
279                 if (r.type == 'F') {
280                         g_base = r.a;
281                 }
282                 if (r.type == 'A') {
283                         clock[dim(clock)] = r.time / 100;
284                         pressure_value[dim(pressure_value)] = r.b;
285                         accelerometer_value[dim(accelerometer_value)] = r.a;
286                 }
287         }
288 }
289
290 typedef struct {
291         int     time;
292         int     accel;
293         int     pressure;
294         string  state;
295 } telem_record;
296
297 autoimport String;
298
299 telem_record read_telem(file in) {
300         string[*]       r = wordsplit(chomp(fgets(in)), " ");
301         static int line = 0;
302
303         line++;
304         if (dim(r) < 15) {
305                 printf ("invalid record line %d\n", line);
306                 return read_telem(in);
307         }
308         return (telem_record) {
309                 .time = string_to_integer(r[10]),
310                 .accel = string_to_integer(r[12]),
311                 .pressure = string_to_integer(r[14]),
312                 .state = r[9]
313         };
314 }
315
316 void readsamples_telem(file in) {
317         telem_record[...] telem;
318
319         setdim(telem, 0);
320
321         setdim(clock, 0);
322         setdim(pressure_value, 0);
323         setdim(accelerometer_value, 0);
324         real clock_bias = 0;
325
326         telem_record[...] save = {};
327         
328         setdim(save, 0);
329         while (!File::end(in)) {
330                 save[dim(save)] = read_telem(in);
331                 if (save[dim(save)-1].state == "boost")
332                         break;
333         }
334         int     start = dim(save) - 4;
335
336         int     accel_total = 0;
337         for (int i = 0; i < start; i++)
338                 accel_total += save[i].accel;
339         g_base = accel_total // start;
340
341         for (int i = start; i < dim(save); i++)
342                 telem[dim(telem)] = save[i];
343
344         while (!File::end(in)) {
345                 int n = dim(telem);
346                 telem[n] = read_telem(in);
347                 telem[n].time += clock_bias;
348                 if (n > 0 && telem[n].time < telem[n-1].time) {
349                         clock_bias += 65536;
350                         telem[n].time += 65536;
351                 }
352         }
353         int clock_start = telem[0].time;
354         int clock_end = telem[dim(telem)-1].time;
355         int samples = clock_end - clock_start;
356
357         int j = 0;
358         for (int i = 0; i < samples; i++) {
359                 clock[i] = i / 100;
360                 pressure_value[i] = telem[j].pressure;
361                 accelerometer_value[i] = telem[j].accel;
362                 if (j < dim(telem)-1) {
363                         int cur_time = clock_start + i;
364                         if (cur_time - telem[j].time > telem[j+1].time - cur_time)
365                                 j++;
366                 }
367         }
368 }
369
370 readsamples_log(stdin);
371
372 int[...] int_integrate(int[...] d, int base) {
373         int v = 0;
374         int[dim(d)] ret;
375
376         ret[0] = 0;
377         for (int i = 1; i < dim(d); i++)
378                 ret[i] = (v += (d[i-1] + d[i] + 1) // 2);
379         return ret;
380 }
381
382 int[...] int_differentiate(int[...] d) {
383         return (int[dim(d)]) { [n] = n == 0 ? 0 : d[n] - d[n-1] };
384 }
385
386 int average(int[...] d, int n) {
387         int     sum = 0;
388         for (int i = 0; i < n; i++)
389                 sum += d[n];
390         return sum // n;
391 }
392
393 int[...] rebase(int[...] d, int m, int a) = (int[dim(d)]) { [n] = d[n] * m + a };
394
395 int size = dim(accelerometer_value);
396
397 real[...] do_low_pass(real[] data, real ωpass, real ωstop, real error) {
398         real[*] fir = low_pass_filter (ωpass, ωstop, error);
399         File::fprintf (stderr, "low pass filter is %d long\n", dim(fir));
400         return convolve(data, fir);
401 }
402
403 if (false) {
404         accelerometer_value = rebase(accelerometer_value, -1, g_base);
405         int accel_i0_base = average(accelerometer_value, 30);
406         int[size] pres_d0 = int_filter(pressure_value, 4);
407         int[size] accel_i0 = int_filter(accelerometer_value, 4);
408         int[size] pres_d1 = int_filter(int_differentiate(pres_d0), 4);
409         int[size] accel_i1 = int_integrate(accelerometer_value, accel_i0_base);
410         int[size] pres_d2 = int_filter(int_differentiate(pres_d1), 4);
411         int[size] accel_i2 = int_integrate(accel_i1, 0);
412
413         real count_to_altitude(int count) = pressure_to_altitude(count_to_kPa(count / 16) * 1000);
414
415         for (int i = 0; i < size; i++)
416                 printf("%g %g %g %g %g %g %g %g %g\n",
417                        clock[i] - clock[0],
418                        count_to_altitude(pres_d0[i]) - count_to_altitude(pres_d0[0]), accel_i2[i] / 10000 / g_count * gravity,
419                        pres_d1[i] * 100, accel_i1[i] / 100 / g_count * gravity,
420                        pres_d2[i] * 10000, accel_i0[i] / g_count * gravity,
421                        count_to_altitude(pressure_value[i]) -
422                        count_to_altitude(pressure_value[0]), accelerometer_value[i]
423                        / g_count * gravity);
424
425 } else {
426         real[size] accelerometer = { [n] = gravity * (count_to_g(accelerometer_value[n]) - 1.0) };
427         real[size] barometer = { [n] = pressure_to_altitude(count_to_kPa(pressure_value[n] / 16) * 1000) };
428         real[size] filtered_accelerometer = do_low_pass(accelerometer,
429                                                         2 * π * 5/100,
430                                                         2 * π * 8/100,
431                                                         1e-8);
432         real[size] filtered_barometer = do_low_pass(barometer,
433                                                     2 * π * .5 / 100,
434                                                     2 * π * 1 / 100,
435                                                     1e-8);
436
437         real[...] integrate(real[...] d) {
438                 real[dim(d)] ret;
439                 for (int i = 0; i < dim(ret); i++)
440                         ret[i] = i == 0 ? 0 : ret[i-1] + (d[i-1] + d[i]) / 2 * (clock[i] - clock[i-1]);
441                 return ret;
442         }
443
444         real[...] differentiate(real[...] d) {
445                 real[dim(d)] ret;
446                 for (int i = 1; i < dim(ret); i++)
447                         ret[i] = (d[i] - d[i-1]) / (clock[i] - clock[i-1]);
448                 ret[0] = ret[1];
449                 return ret;
450         }
451
452         real[size] accel_speed = integrate(accelerometer);
453         real[size] accel_pos = integrate(accel_speed);
454         real[size] baro_speed = differentiate(filtered_barometer);
455         real[size] baro_accel = differentiate(baro_speed);
456
457         printf("%7s %12s %12s %12s %12s %12s %12s %12s %12s\n",
458                "time",
459                "height(baro)",
460                "height(accel)",
461                "speed(baro)",
462                "speed(accel)",
463                "accel(baro)",
464                "accel(accel)",
465                "raw(baro)",
466                "raw(accel)");
467         for (int i = 0; i < size; i++)
468                 printf("%7.2f %12.6f %12.6f %12.6f %12.6f %12.6f %12.6f %12.6f %12.6f\n",
469                        clock[i] - clock[0],
470                        filtered_barometer[i] - filtered_barometer[0], accel_pos[i],
471                        baro_speed[i], accel_speed[i],
472                        baro_accel[i], filtered_accelerometer[i],
473                        barometer[i] - barometer[0], accelerometer[i]);
474 }