micropeak: Add flight stats pane
authorKeith Packard <keithp@keithp.com>
Mon, 31 Dec 2012 22:17:26 +0000 (14:17 -0800)
committerKeith Packard <keithp@keithp.com>
Mon, 31 Dec 2012 22:17:26 +0000 (14:17 -0800)
Shows graph or stats in alternate panes

Signed-off-by: Keith Packard <keithp@keithp.com>
altosuilib/AltosUILib.java
micropeak/Makefile.am
micropeak/MicroData.java
micropeak/MicroPeak.java
micropeak/MicroStats.java [new file with mode: 0644]
micropeak/MicroStatsTable.java [new file with mode: 0644]

index 717678bafa6d959d19df096fa317f4a0e2ec33da..5d5f9aaaa6cef61df18b93022f3299910087776f 100644 (file)
@@ -24,17 +24,17 @@ import org.altusmetrum.AltosLib.*;
 
 public class AltosUILib extends AltosLib {
 
-       static final int tab_elt_pad = 5;
+       public static final int tab_elt_pad = 5;
 
-       static Font label_font;
-       static Font value_font;
-       static Font status_font;
-       static Font table_label_font;
-       static Font table_value_font;
+       public static Font label_font;
+       public static Font value_font;
+       public static Font status_font;
+       public static Font table_label_font;
+       public static Font table_value_font;
 
-       final static int font_size_small = 1;
-       final static int font_size_medium = 2;
-       final static int font_size_large = 3;
+       final public static int font_size_small = 1;
+       final public static int font_size_medium = 2;
+       final public static int font_size_large = 3;
 
        static void set_fonts(int size) {
                int     brief_size;
index fde981a6c6bbe975f111388684feb6725736e4a5..e0de690c05270beb0453c60f0fd0be62758bd49d 100644 (file)
@@ -13,6 +13,8 @@ micropeak_JAVA= \
        MicroFrame.java \
        MicroGraph.java \
        MicroSerial.java \
+       MicroStats.java \
+       MicroStatsTable.java \
        MicroFileChooser.java \
        MicroUSB.java
 
index 783ae40f7a459c5f1d6f22f024c3d4045bd35482..ec9b83d8179e0902bc82c74de968bfac996b9e54 100644 (file)
@@ -22,6 +22,87 @@ import java.io.*;
 import java.util.*;
 import org.altusmetrum.AltosLib.*;
 
+abstract class MicroIterator implements Iterator<Double> {
+       int             i;
+       MicroData       data;
+
+       public boolean hasNext() {
+               return i < data.pressures.length;
+       }
+
+       public MicroIterator (MicroData data) {
+               this.data = data;
+               i = 0;
+       }
+
+       public void remove() {
+       }
+}
+
+class MicroHeightIterator extends MicroIterator {
+       public Double next() {
+               return data.height(i++);
+       }
+
+       public MicroHeightIterator(MicroData data) {
+               super(data);
+       }
+}
+
+class MicroHeightIterable implements Iterable<Double> {
+       MicroData       data;
+
+       public Iterator<Double> iterator() {
+               return new MicroHeightIterator(data);
+       }
+
+       public MicroHeightIterable(MicroData data) {
+               this.data = data;
+       }
+}
+
+class MicroSpeedIterator extends MicroIterator {
+       public Double next() {
+               return data.speed(i++);
+       }
+       public MicroSpeedIterator(MicroData data) {
+               super(data);
+       }
+}
+
+class MicroSpeedIterable implements Iterable<Double> {
+       MicroData       data;
+
+       public Iterator<Double> iterator() {
+               return new MicroSpeedIterator(data);
+       }
+
+       public MicroSpeedIterable(MicroData data) {
+               this.data = data;
+       }
+}
+
+class MicroAccelIterator extends MicroIterator {
+       public Double next() {
+               return data.acceleration(i++);
+       }
+       public MicroAccelIterator(MicroData data) {
+               super(data);
+       }
+}
+
+class MicroAccelIterable implements Iterable<Double> {
+       MicroData       data;
+
+       public Iterator<Double> iterator() {
+               return new MicroAccelIterator(data);
+       }
+
+       public MicroAccelIterable(MicroData data) {
+               this.data = data;
+       }
+}
+
 public class MicroData {
        public int              ground_pressure;
        public int              min_pressure;
@@ -143,6 +224,18 @@ public class MicroData {
                return AltosConvert.pressure_to_altitude(pressures[i]);
        }
 
+       public Iterable<Double> heights() {
+               return new MicroHeightIterable(this);
+       }
+
+       public Iterable<Double> speeds() {
+               return new MicroSpeedIterable(this);
+       }
+
+       public Iterable<Double> accels() {
+               return new MicroAccelIterable(this);
+       }
+
        int fact(int n) {
                if (n == 0)
                        return 1;
@@ -266,5 +359,12 @@ public class MicroData {
                        throw new IOException();
                }
        }
+
+       public MicroData() {
+               ground_pressure = 101000;
+               min_pressure = 101000;
+               pressures = new int[1];
+               pressures[0] = 101000;
+       }
        
 }
index 463238c83b1af3fd9982c67af35c3ef5344e982c..c69f7167904df828f9a103927fa1efec28dd3cb5 100644 (file)
@@ -30,13 +30,16 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene
 
        File            filename;
        MicroGraph      graph;
+       MicroStatsTable stats;
        MicroData       data;
-       Container       pane;
+       Container       container;
+       JTabbedPane     pane;
 
        private void RunFile(InputStream input) {
                try {
                        data = new MicroData(input);
                        graph.setData(data);
+                       stats.setData(data);
                } catch (IOException ioe) {
                }
                try {
@@ -90,7 +93,8 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene
 
                AltosUIPreferences.set_component(this);
 
-               pane = getContentPane();
+               container = getContentPane();
+               pane = new JTabbedPane();
 
                setTitle("MicroPeak");
 
@@ -129,9 +133,14 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene
                });
 
                graph = new MicroGraph();
-               pane.add(graph.panel);
+               stats = new MicroStatsTable();
+               pane.add(graph.panel, "Graph");
+               pane.add(stats, "Statistics");
                pane.doLayout();
                pane.validate();
+               container.add(pane);
+               container.doLayout();
+               container.validate();
                doLayout();
                validate();
                Insets i = getInsets();
diff --git a/micropeak/MicroStats.java b/micropeak/MicroStats.java
new file mode 100644 (file)
index 0000000..6ae8a2b
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.micropeak;
+
+import java.io.*;
+import org.altusmetrum.AltosLib.*;
+import org.altusmetrum.altosuilib.*;
+
+public class MicroStats {
+       double          coast_height;
+       double          coast_time;
+
+       double          apogee_height;
+       double          apogee_time;
+
+       double          landed_height;
+       double          landed_time;
+
+       double          max_speed;
+       double          max_accel;
+
+       MicroData       data;
+
+       void find_landing() {
+               landed_height = 0;
+
+               int t = 0;
+               for (double height : data.heights()) {
+                       landed_height = height;
+                       t++;
+               }
+               landed_time = data.time(t);
+
+               t = 0;
+               boolean above = false;
+               for (double height : data.heights()) {
+                       if (height > landed_height + 10) {
+                               above = true;
+                       } else {
+                               if (above && height < landed_height + 2) {
+                                       above = false;
+                                       landed_time = data.time(t);
+                               }
+                       }
+                       t++;
+               }
+       }
+
+       void find_apogee() {
+               apogee_height = 0;
+               apogee_time = 0;
+               
+               int t = 0;
+               for (double height : data.heights()) {
+                       if (height > apogee_height) {
+                               apogee_height = height;
+                               apogee_time = data.time(t);
+                       }
+                       t++;
+               }
+       }
+
+       void find_coast() {
+               coast_height = 0;
+               coast_time = 0;
+
+               int t = 0;
+               for (double accel : data.accels()) {
+                       if (accel < -9.8)
+                               break;
+                       t++;
+               }
+               coast_time = data.time(t);
+
+               int coast_t = t;
+               t = 0;
+               for (double height : data.heights()) {
+                       if (t >= coast_t) {
+                               coast_height = height;
+                               break;
+                       }
+                       t++;
+               }
+       }
+
+       void find_max_speed() {
+               max_speed = 0;
+               int     t = 0;
+               for (double speed : data.speeds()) {
+                       if (data.time(t) > apogee_time)
+                               break;
+                       if (speed > max_speed)
+                               max_speed = speed;
+                       t++;
+               }
+       }
+
+       void find_max_accel() {
+               max_accel = 0;
+
+               int t = 0;
+               for (double accel : data.accels()) {
+                       if (data.time(t) > apogee_time)
+                               break;
+                       if (accel > max_accel)
+                               max_accel = accel;
+                       t++;
+               }
+       }
+
+       double boost_duration() {
+               return coast_time;
+       }
+
+       double boost_height() {
+               return coast_height;
+       }
+
+       double  boost_speed() {
+               return coast_height / coast_time;
+       }
+
+       double boost_accel() {
+               return boost_speed() / boost_duration();
+       }
+
+       double coast_duration() {
+               return apogee_time - coast_time;
+       }
+
+       double coast_height() {
+               return apogee_height - coast_height;
+       }
+
+       double coast_speed() {
+               return coast_height() / coast_duration();
+       }
+
+       double coast_accel() {
+               return coast_speed() / coast_duration();
+       }
+
+       double descent_duration() {
+               return landed_time - apogee_time;
+       }
+
+       double descent_height() {
+               return apogee_height - landed_height;
+       }
+
+       double descent_speed() {
+               return descent_height() / descent_duration();
+       }
+
+       public MicroStats(MicroData data) {
+
+               this.data = data;
+
+               find_coast();
+               find_apogee();
+               find_landing();
+               find_max_speed();
+               find_max_accel();
+       }
+
+       public MicroStats() {
+               this(new MicroData());
+       }
+}
diff --git a/micropeak/MicroStatsTable.java b/micropeak/MicroStatsTable.java
new file mode 100644 (file)
index 0000000..f373e25
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.micropeak;
+
+import java.awt.*;
+import javax.swing.*;
+import org.altusmetrum.AltosLib.*;
+import org.altusmetrum.altosuilib.*;
+
+public class MicroStatsTable extends JComponent {
+       GridBagLayout   layout;
+
+       class MicroStat {
+               JLabel          label;
+               JTextField[]    texts;
+
+               public void set_values(String ... values) {
+                       for (int j = 0; j < values.length; j++) {
+                               texts[j].setText(values[j]);
+                       }
+               }
+
+               public MicroStat(GridBagLayout layout, int y, String label_text, String ... values) {
+                       GridBagConstraints      c = new GridBagConstraints();
+                       c.insets = new Insets(AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad);
+                       c.weighty = 1;
+
+                       label = new JLabel(label_text);
+                       label.setFont(AltosUILib.label_font);
+                       label.setHorizontalAlignment(SwingConstants.LEFT);
+                       c.gridx = 0; c.gridy = y;
+                       c.anchor = GridBagConstraints.WEST;
+                       c.fill = GridBagConstraints.VERTICAL;
+                       c.weightx = 0;
+                       layout.setConstraints(label, c);
+                       add(label);
+
+                       texts = new JTextField[values.length];
+                       for (int j = 0; j < values.length; j++) {
+                               JTextField value = new JTextField(values[j]);
+                               value.setFont(AltosUILib.value_font);
+                               value.setHorizontalAlignment(SwingConstants.RIGHT);
+                               texts[j] = value;
+                               c.gridx = j+1; c.gridy = y;
+                               c.anchor = GridBagConstraints.EAST;
+                               c.fill = GridBagConstraints.BOTH;
+                               c.weightx = 1;
+                               layout.setConstraints(value, c);
+                               add(value);
+                       }
+               }
+       }
+
+       MicroStat       max_height, max_speed;
+       MicroStat       max_accel, avg_accel;
+       MicroStat       boost_duration;
+       MicroStat       coast_duration;
+       MicroStat       descent_speed;
+       MicroStat       descent_duration;
+       MicroStat       flight_time;
+       
+       public void setStats(MicroStats stats) {
+               max_height.set_values(String.format("%5.0f m", stats.apogee_height),
+                                     String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.apogee_height)));
+               max_speed.set_values(String.format("%5.0f m/s", stats.max_speed),
+                                    String.format("%5.0f mph", AltosConvert.meters_to_mph(stats.max_speed)),
+                                    String.format("Mach %4.1f", AltosConvert.meters_to_mach(stats.max_speed)));
+               max_accel.set_values(String.format("%5.0f m/s²", stats.max_accel),
+                                    String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.max_accel)),
+                                    String.format("%5.0f G", AltosConvert.meters_to_g(stats.max_accel)));
+               avg_accel.set_values(String.format("%5.0f m/s²", stats.boost_accel(),
+                                                  String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.boost_accel())),
+                                                  String.format("%5.0f G", AltosConvert.meters_to_g(stats.boost_accel()))));
+               boost_duration.set_values(String.format("%6.1f s", stats.boost_duration()));
+               coast_duration.set_values(String.format("%6.1f s", stats.coast_duration()));
+               descent_speed.set_values(String.format("%5.0f m/s", stats.descent_speed()),
+                                        String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.descent_speed())));
+               descent_duration.set_values(String.format("%6.1f s", stats.descent_duration()));
+               flight_time.set_values(String.format("%6.1f s", stats.landed_time));
+       }
+
+       public void setData(MicroData data) {
+               setStats(new MicroStats(data));
+       }
+
+       public MicroStatsTable(MicroStats stats) {
+               layout = new GridBagLayout();
+
+               setLayout(layout);
+               int y = 0;
+               max_height = new MicroStat(layout, y++, "Maximum height",
+                                          String.format("%5.0f m", stats.apogee_height),
+                                          String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.apogee_height)));
+               max_speed = new MicroStat(layout, y++, "Maximum speed",
+                                         String.format("%5.0f m/s", stats.max_speed),
+                                         String.format("%5.0f mph", AltosConvert.meters_to_mph(stats.max_speed)),
+                                         String.format("Mach %4.1f", AltosConvert.meters_to_mach(stats.max_speed)));
+               max_accel = new MicroStat(layout, y++, "Maximum boost acceleration",
+                                         String.format("%5.0f m/s²", stats.max_accel),
+                                         String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.max_accel)),
+                                         String.format("%5.0f G", AltosConvert.meters_to_g(stats.max_accel)));
+               avg_accel = new MicroStat(layout, y++, "Average boost acceleration",
+                                         String.format("%5.0f m/s²", stats.boost_accel(),
+                                                       String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.boost_accel())),
+                                                       String.format("%5.0f G", AltosConvert.meters_to_g(stats.boost_accel()))));
+               boost_duration = new MicroStat(layout, y++, "Boost duration",
+                                              String.format("%6.0f s", stats.boost_duration()));
+               coast_duration = new MicroStat(layout, y++, "Coast duration",
+                                              String.format("%6.1f s", stats.coast_duration()));
+               descent_speed = new MicroStat(layout, y++, "Descent rate",
+                                             String.format("%5.0f m/s", stats.descent_speed()),
+                                             String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.descent_speed())));
+               descent_duration = new MicroStat(layout, y++, "Descent duration",
+                                                String.format("%6.1f s", stats.descent_duration()));
+               flight_time = new MicroStat(layout, y++, "Flight Time",
+                                           String.format("%6.0f s", stats.landed_time));
+       }
+
+       public MicroStatsTable() {
+               this(new MicroStats());
+       }
+       
+}
\ No newline at end of file