Add data from flight 1
[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
204 count_to_g(real count)
205 {
206         return (15792 + g_count - count) / g_count;
207 }
208
209 real base_alt = 0;
210 real base_sec = 0;
211 real last_alt;
212 real last_sec;
213 real last_alt_speed;
214 real accel_speed;
215 real accel_meters;
216
217 real[...]       barometer;
218 real[...]       accelerometer;
219
220 real sinc(real x) = x != 0 ? sin(x)/x : 1;
221
222 real gaussian(real x) = exp(-(x**2)/2) / sqrt(2 * pi);
223
224 load "/usr/share/nickle/examples/kaiser.5c"
225
226 real[...] convolve(real[...] d, real[...] e) {
227         real sample(n) = n < 0 ? d[0] : n >= dim(d) ? d[dim(d)-1] : d[n];
228         real w = (dim(e) - 1) / 2;
229         real c(int center) {
230                 real    v = 0;
231                 for (int o = -w; o <= w; o++)
232                         v += sample(center + o) * e[o + w];
233                 return v;
234         }
235         return (real[dim(d)]) { [n] = c(n) };
236 }
237
238 real sum(real[...] x) { real s = 0; for(int i = 0; i < dim(x); i++) s += x[i]; return s; }
239
240 real[...] filter(real[...] d, int half_width) {
241 #       real[half_width * 2 + 1] fir = { [n] = sinc(2 * pi * n / (2 * half_width)) };
242         real M = half_width * 2 + 1;
243         real[M] fir = { [n] = kaiser(n, M, 8) };
244         real fir_sum = sum(fir);
245         for (int i = 0; i < dim(fir); i++) fir[i] /= fir_sum;
246         return convolve(d, fir);
247 }
248
249 real gravity = 9.80665;
250
251 real[...] pressure_value, accelerometer_value;
252 real[...] clock;
253
254 void readsamples(file in) {
255         setdim(pressure_value, 0);
256         setdim(accelerometer_value, 0);
257         while (!File::end(in)) {
258                 flight_record r = read_record(in);
259                 if (r.type == 'A') {
260                         clock[dim(clock)] = r.time / 100;
261                         pressure_value[dim(pressure_value)] = r.b;
262                         accelerometer_value[dim(accelerometer_value)] = r.a;
263                 }
264         }
265 }
266
267 readsamples(stdin);
268
269 int size = dim(accelerometer_value);
270 real[size] accelerometer = { [n] = gravity * (count_to_g(accelerometer_value[n]) - 1.0) };
271 real[size] barometer = { [n] = pressure_to_altitude(count_to_kPa(pressure_value[n] / 16) * 1000) };
272 real[size] filtered_accelerometer = filter(accelerometer, 8);
273 real[size] filtered_barometer = filter(barometer, 128);
274
275 real[...] integrate(real[...] d) {
276         real[dim(d)] ret;
277         for (int i = 0; i < dim(ret); i++)
278                 ret[i] = i == 0 ? 0 : ret[i-1] + (d[i-1] + d[i]) / 2 * (clock[i] - clock[i-1]);
279         return ret;
280 }
281
282 real[...] differentiate(real[...] d) {
283         real[dim(d)] ret;
284         for (int i = 1; i < dim(ret); i++)
285                 ret[i] = (d[i] - d[i-1]) / (clock[i] - clock[i-1]);
286         ret[0] = ret[1];
287         return ret;
288 }
289
290 real[size] accel_speed = integrate(filtered_accelerometer);
291 real[size] accel_pos = integrate(accel_speed);
292 real[size] baro_speed = differentiate(filtered_barometer);
293 real[size] baro_accel = differentiate(baro_speed);
294
295 for (int i = 0; i < size; i++)
296         printf("%g %g %g %g %g %g %g %g %g\n",
297                clock[i] - clock[0],
298                filtered_barometer[i] - filtered_barometer[0], accel_pos[i],
299                baro_speed[i], accel_speed[i],
300                baro_accel[i], filtered_accelerometer[i],
301                barometer[i] - barometer[0], accelerometer[i]);