2 * Copyright © 2012 Keith Packard <keithp@keithp.com>
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.
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.
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.
18 package org.altusmetrum.micropeak;
23 import org.altusmetrum.AltosLib.*;
25 abstract class MicroIterator implements Iterator<Double> {
29 public boolean hasNext() {
30 return i < data.pressures.length;
33 public MicroIterator (MicroData data) {
38 public void remove() {
42 class MicroHeightIterator extends MicroIterator {
43 public Double next() {
44 return data.height(i++);
47 public MicroHeightIterator(MicroData data) {
52 class MicroHeightIterable implements Iterable<Double> {
55 public Iterator<Double> iterator() {
56 return new MicroHeightIterator(data);
59 public MicroHeightIterable(MicroData data) {
64 class MicroSpeedIterator extends MicroIterator {
65 public Double next() {
66 return data.speed(i++);
68 public MicroSpeedIterator(MicroData data) {
73 class MicroSpeedIterable implements Iterable<Double> {
76 public Iterator<Double> iterator() {
77 return new MicroSpeedIterator(data);
80 public MicroSpeedIterable(MicroData data) {
85 class MicroAccelIterator extends MicroIterator {
86 public Double next() {
87 return data.acceleration(i++);
89 public MicroAccelIterator(MicroData data) {
94 class MicroAccelIterable implements Iterable<Double> {
97 public Iterator<Double> iterator() {
98 return new MicroAccelIterator(data);
101 public MicroAccelIterable(MicroData data) {
106 public class MicroData {
107 public int ground_pressure;
108 public int min_pressure;
109 public int[] pressures;
110 private double time_step;
111 private double ground_altitude;
112 private ArrayList<Integer> bytes;
116 class FileEndedException extends Exception {
119 class NonHexcharException extends Exception {
122 class InvalidCrcException extends Exception {
125 private int getc(InputStream f) throws IOException, FileEndedException {
129 throw new FileEndedException();
134 private int get_nonwhite(InputStream f) throws IOException, FileEndedException {
139 if (!Character.isWhitespace(c))
144 private int get_hexc(InputStream f) throws IOException, FileEndedException, NonHexcharException {
145 int c = get_nonwhite(f);
147 if ('0' <= c && c <= '9')
149 if ('a' <= c && c <= 'f')
151 if ('A' <= c && c <= 'F')
153 throw new NonHexcharException();
156 private static final int POLY = 0x8408;
158 private int log_crc(int crc, int b) {
161 for (i = 0; i < 8; i++) {
162 if (((crc & 0x0001) ^ (b & 0x0001)) != 0)
163 crc = (crc >> 1) ^ POLY;
173 private int get_hex(InputStream f) throws IOException, FileEndedException, NonHexcharException {
177 int h = (a << 4) + b;
179 file_crc = log_crc(file_crc, h);
183 private boolean find_header(InputStream f) throws IOException {
186 if (get_nonwhite(f) == 'M' && get_nonwhite(f) == 'P')
189 } catch (FileEndedException fe) {
194 private int get_32(InputStream f) throws IOException, FileEndedException, NonHexcharException {
196 for (int i = 0; i < 4; i++) {
197 v += get_hex(f) << (i * 8);
202 private int get_16(InputStream f) throws IOException, FileEndedException, NonHexcharException {
204 for (int i = 0; i < 2; i++) {
205 v += get_hex(f) << (i * 8);
210 private int swap16(int i) {
211 return ((i << 8) & 0xff00) | ((i >> 8) & 0xff);
214 public boolean crc_valid;
216 int mix_in (int high, int low) {
217 return high - (high & 0xffff) + low;
220 boolean closer (int target, int a, int b) {
221 return Math.abs (target - a) < Math.abs(target - b);
224 public double altitude(int i) {
225 return AltosConvert.pressure_to_altitude(pressures[i]);
228 public Iterable<Double> heights() {
229 return new MicroHeightIterable(this);
232 public Iterable<Double> speeds() {
233 return new MicroSpeedIterable(this);
236 public Iterable<Double> accels() {
237 return new MicroAccelIterable(this);
243 return n * fact(n-1);
246 int choose(int n, int k) {
247 return fact(n) / (fact(k) * fact(n-k));
251 public double avg_altitude(int center, int dist) {
252 int start = center - dist;
253 int stop = center + dist;
257 if (stop >= pressures.length)
258 stop = pressures.length - 1;
265 for (int i = start; i <= stop; i++) {
266 int k = i - (center - dist);
267 int c = choose (n, k);
269 sum += c * pressures[i];
273 double pres = sum / div;
275 double alt = AltosConvert.pressure_to_altitude(pres);
279 public double height(int i) {
280 return altitude(i) - ground_altitude;
283 static final int speed_avg = 3;
284 static final int accel_avg = 5;
286 private double avg_speed(int center, int dist) {
290 double ai = avg_altitude(center, dist);
291 double aj = avg_altitude(center - 1, dist);
292 double s = (ai - aj) / time_step;
297 public double speed(int i) {
298 return avg_speed(i, speed_avg);
301 public double acceleration(int i) {
304 return (avg_speed(i, accel_avg) - avg_speed(i-1, accel_avg)) / time_step;
307 public double time(int i) {
308 return i * time_step;
311 public void save (OutputStream f) throws IOException {
317 public void set_name(String name) {
321 public MicroData (InputStream f, String name) throws IOException, InterruptedException {
323 bytes = new ArrayList<Integer>();
325 throw new IOException("No MicroPeak data header found");
328 ground_pressure = get_32(f);
329 min_pressure = get_32(f);
330 int nsamples = get_16(f);
331 pressures = new int[nsamples + 1];
333 ground_altitude = AltosConvert.pressure_to_altitude(ground_pressure);
334 int cur = ground_pressure;
336 for (int i = 0; i < nsamples; i++) {
338 int same = mix_in(cur, k);
339 int up = mix_in(cur + 0x10000, k);
340 int down = mix_in(cur - 0x10000, k);
342 if (closer (cur, same, up)) {
343 if (closer (cur, same, down))
348 if (closer (cur, up, down))
354 pressures[i+1] = cur;
357 int current_crc = swap16(~file_crc & 0xffff);
360 crc_valid = crc == current_crc;
363 } catch (FileEndedException fe) {
364 throw new IOException("File Ended Unexpectedly");
365 } catch (NonHexcharException ne) {
366 throw new IOException("Non hexadecimal character found");
371 ground_pressure = 101000;
372 min_pressure = 101000;
373 pressures = new int[1];
374 pressures[0] = 101000;