altosdroid: initial implementation of telemetry logging.
[fw/altos] / altosui / AltosGraphUI.java
1
2 // Copyright (c) 2010 Anthony Towns
3 // GPL v2 or later
4
5 package altosui;
6
7 import java.io.*;
8 import java.util.ArrayList;
9
10 import java.awt.*;
11 import javax.swing.*;
12 import org.altusmetrum.AltosLib.*;
13
14 import org.jfree.chart.ChartPanel;
15 import org.jfree.chart.JFreeChart;
16 import org.jfree.ui.RefineryUtilities;
17
18 public class AltosGraphUI extends AltosFrame 
19 {
20     JTabbedPane pane;
21
22     static final private Color red = new Color(194,31,31);
23     static final private Color green = new Color(31,194,31);
24     static final private Color blue = new Color(31,31,194);
25     //static final private Color black = new Color(31,31,31);
26     static final private Color yellow = new Color(194,194,31);
27     //static final private Color cyan = new Color(31,194,194);
28     static final private Color magenta = new Color(194,31,194);
29
30     static private class OverallGraphs {
31         AltosGraphTime.Element height = 
32                 new AltosGraphTime.TimeSeries(String.format("Height (%s)", AltosConvert.height.show_units()), "Height (AGL)", red) {
33                 public void gotTimeData(double time, AltosDataPoint d) {
34                         double  height = d.height();
35                         if (height != AltosRecord.MISSING)
36                                 series.add(time, AltosConvert.height.value(height));
37                 } 
38             };
39     
40         AltosGraphTime.Element speed =
41                 new AltosGraphTime.TimeSeries(String.format("Speed (%s)", AltosConvert.speed.show_units()), "Vertical Speed", green) { 
42                 public void gotTimeData(double time, AltosDataPoint d) {
43                     double      speed;
44                     if (d.state() < Altos.ao_flight_drogue && d.has_accel()) {
45                         speed = d.accel_speed();
46                     } else {
47                         speed = d.baro_speed();
48                     }
49                     if (speed != AltosRecord.MISSING)
50                             series.add(time, AltosConvert.speed.value(speed));
51                 }
52             };
53     
54         AltosGraphTime.Element acceleration =
55                 new AltosGraphTime.TimeSeries(String.format("Acceleration (%s)",
56                                                             AltosConvert.accel.show_units()),
57                                               "Axial Acceleration", blue)
58             {
59                 public void gotTimeData(double time, AltosDataPoint d) {
60                     double acceleration = d.acceleration();
61                     if (acceleration != AltosRecord.MISSING)
62                             series.add(time, AltosConvert.accel.value(acceleration));
63                 }
64             };
65     
66         AltosGraphTime.Element temperature =
67             new AltosGraphTime.TimeSeries("Temperature (\u00B0C)", 
68                     "Board temperature", red) 
69             {
70                 public void gotTimeData(double time, AltosDataPoint d) {
71                     double temp = d.temperature();
72                     if (temp != AltosRecord.MISSING)
73                         series.add(time, d.temperature());
74                 }
75             };
76     
77         AltosGraphTime.Element drogue_voltage =
78             new AltosGraphTime.TimeSeries("Voltage (V)", "Drogue Continuity", yellow) 
79             {
80                 public void gotTimeData(double time, AltosDataPoint d) {
81                     double v = d.drogue_voltage();
82                     if (v != AltosRecord.MISSING)
83                         series.add(time, v);
84                 }
85             };
86     
87         AltosGraphTime.Element main_voltage =
88             new AltosGraphTime.TimeSeries("Voltage (V)", "Main Continuity", magenta) 
89             {
90                 public void gotTimeData(double time, AltosDataPoint d) {
91                     double v = d.main_voltage();
92                     if (v != AltosRecord.MISSING)
93                         series.add(time, v);
94                 }
95             };
96     
97         //AltosGraphTime.Element e_pad    = new AltosGraphTime.StateMarker(Altos.ao_flight_pad, "Pad");
98         AltosGraphTime.Element e_boost  = new AltosGraphTime.StateMarker(Altos.ao_flight_boost, "Boost");
99         AltosGraphTime.Element e_fast   = new AltosGraphTime.StateMarker(Altos.ao_flight_fast, "Fast");
100         AltosGraphTime.Element e_coast  = new AltosGraphTime.StateMarker(Altos.ao_flight_coast, "Coast");
101         AltosGraphTime.Element e_drogue = new AltosGraphTime.StateMarker(Altos.ao_flight_drogue, "Drogue");
102         AltosGraphTime.Element e_main   = new AltosGraphTime.StateMarker(Altos.ao_flight_main, "Main");
103         AltosGraphTime.Element e_landed = new AltosGraphTime.StateMarker(Altos.ao_flight_landed, "Landed");
104     
105         protected AltosGraphTime myAltosGraphTime(String suffix) {
106             return (new AltosGraphTime("Overall " + suffix))
107                 .addElement(e_boost)
108                 .addElement(e_fast)
109                 .addElement(e_coast)
110                 .addElement(e_drogue)
111                 .addElement(e_main)
112                 .addElement(e_landed);
113         }
114     
115         public ArrayList<AltosGraph> graphs() {
116             ArrayList<AltosGraph> graphs = new ArrayList<AltosGraph>();
117     
118             graphs.add( myAltosGraphTime("Summary")
119                         .addElement(height)
120                         .addElement(speed)
121                         .addElement(acceleration) );
122
123             graphs.add( myAltosGraphTime("Summary")
124                         .addElement(height)
125                         .addElement(speed));
126     
127             graphs.add( myAltosGraphTime("Altitude")
128                     .addElement(height) );
129     
130             graphs.add( myAltosGraphTime("Speed")
131                     .addElement(speed) );
132     
133             graphs.add( myAltosGraphTime("Acceleration")
134                         .addElement(acceleration) );
135     
136             graphs.add( myAltosGraphTime("Temperature")
137                     .addElement(temperature) );
138     
139             graphs.add( myAltosGraphTime("Continuity")
140                         .addElement(drogue_voltage)
141                         .addElement(main_voltage) );
142     
143             return graphs;
144         }
145     }
146
147     /*
148     static private class AscentGraphs extends OverallGraphs {
149         protected AltosGraphTime myAltosGraphTime(String suffix) {
150             return (new AltosGraphTime("Ascent " + suffix) {
151                 public void addData(AltosDataPoint d) {
152                     int state = d.state();
153                     if (Altos.ao_flight_boost <= state && state <= Altos.ao_flight_coast) {
154                         super.addData(d);
155                     }
156                 }
157             }).addElement(e_boost)
158               .addElement(e_fast)
159               .addElement(e_coast);
160         }
161     }
162     */
163
164     /*
165     static private class DescentGraphs extends OverallGraphs {
166         protected AltosGraphTime myAltosGraphTime(String suffix) {
167             return (new AltosGraphTime("Descent " + suffix) {
168                 public void addData(AltosDataPoint d) {
169                     int state = d.state();
170                     if (Altos.ao_flight_drogue <= state && state <= Altos.ao_flight_main) {
171                         super.addData(d);
172                     }
173                 }
174             }).addElement(e_drogue)
175               .addElement(e_main);
176             // ((XYGraph)graph[8]).ymin = new Double(-50);
177         }
178     }
179     */
180
181         public AltosGraphUI(AltosRecordIterable records, String name) throws InterruptedException, IOException {
182                 super(String.format("Altos Graph %s", name));
183
184                 AltosDataPointReader reader = new AltosDataPointReader (records);
185         
186                 if (reader.has_accel)
187                     init(reader, records, 0);
188                 else
189                     init(reader, records, 1);
190         }
191
192 //    public AltosGraphUI(AltosDataPointReader data, int which)
193     //  {
194 //        super("Altos Graph");
195 //        init(data, which);
196 //    }
197
198     private void init(AltosDataPointReader data, AltosRecordIterable records, int which) throws InterruptedException, IOException {
199         pane = new JTabbedPane();
200
201         AltosGraph graph = createGraph(data, which);
202
203         JFreeChart chart = graph.createChart();
204         ChartPanel chartPanel = new ChartPanel(chart);
205         chartPanel.setMouseWheelEnabled(true);
206         chartPanel.setPreferredSize(new java.awt.Dimension(800, 500));
207         pane.add(graph.title, chartPanel);
208
209         AltosFlightStatsTable stats = new AltosFlightStatsTable(new AltosFlightStats(records));
210         pane.add("Flight Statistics", stats);
211
212         setContentPane (pane);
213
214         pack();
215
216         RefineryUtilities.centerFrameOnScreen(this);
217
218         setDefaultCloseOperation(DISPOSE_ON_CLOSE);
219         setVisible(true);
220     }
221
222     private static AltosGraph createGraph(Iterable<AltosDataPoint> data,
223             int which)
224     {
225         return createGraphsWhich(data, which).get(0);
226     }
227
228     /*
229     private static ArrayList<AltosGraph> createGraphs(
230             Iterable<AltosDataPoint> data)
231     {
232         return createGraphsWhich(data, -1);
233     }
234     */
235
236     private static ArrayList<AltosGraph> createGraphsWhich(
237             Iterable<AltosDataPoint> data, int which)
238     {
239         ArrayList<AltosGraph> graph = new ArrayList<AltosGraph>();
240         graph.addAll((new OverallGraphs()).graphs());
241 //        graph.addAll((new AscentGraphs()).graphs());
242 //        graph.addAll((new DescentGraphs()).graphs());
243
244         if (which > 0) {
245             if (which >= graph.size()) {
246                 which = 0;
247             }
248             AltosGraph g = graph.get(which);
249             graph = new ArrayList<AltosGraph>();
250             graph.add(g);
251         }
252
253         for (AltosDataPoint dp : data) {
254             for (AltosGraph g : graph) {
255                 g.addData(dp);
256             }
257         }
258
259         return graph;
260     }
261 }
262
263 /* gnuplot bits...
264  *
265 300x400
266
267 --------------------------------------------------------
268 TOO HARD! :)
269
270 "ascent-gps-accuracy.png" "Vertical error margin to apogee - GPS v Baro (m)"
271     5:($7 < 6 ? $24-$11 : 1/0)
272 "descent-gps-accuracy.png" "Vertical error margin during descent - GPS v Baro (m)"
273     5:($7 < 6 ? 1/0 : $24-$11)
274
275 set output "overall-gps-accuracy.png"
276 set ylabel "distance above sea level (m)"
277 plot "telemetry.csv" using 5:11 with lines ti "baro altitude" axis x1y1, \
278     "telemetry.csv" using 5:24 with lines ti "gps altitude" axis x1y1
279
280 set term png tiny size 700,700 enhanced
281 set xlabel "m"
282 set ylabel "m"
283 set polar
284 set grid polar
285 set rrange[*:*]
286 set angles degrees
287
288 set output "overall-gps-path.png"
289 #:30 with yerrorlines
290 plot "telemetry.csv" using (90-$33):($7 == 2 ? $31 : 1/0) with lines ti "pad", \
291     "telemetry.csv" using (90-$33):($7 == 3 ? $31 : 1/0) with lines ti "boost", \
292     "telemetry.csv" using (90-$33):($7 == 4 ? $31 : 1/0) with lines ti "fast", \
293     "telemetry.csv" using (90-$33):($7 == 5 ? $31 : 1/0) with lines ti "coast", \
294     "telemetry.csv" using (90-$33):($7 == 6 ? $31 : 1/0) with lines ti "drogue", \
295     "telemetry.csv" using (90-$33):($7 == 7 ? $31 : 1/0) with lines ti "main", \
296     "telemetry.csv" using (90-$33):($7 == 8 ? $31 : 1/0) with lines ti "landed"
297
298 set output "ascent-gps-path.png"
299 plot "telemetry.csv" using (90-$33):($7 == 2 ? $31 : 1/0):30 with lines ti "pad", \
300     "telemetry.csv" using (90-$33):($7 == 3 ? $31 : 1/0):20 with lines ti "boost", \
301     "telemetry.csv" using (90-$33):($7 == 4 ? $31 : 1/0):10 with lines ti "fast", \
302     "telemetry.csv" using (90-$33):($7 == 5 ? $31 : 1/0):5 with lines ti "coast"
303
304 set output "descent-gps-path.png"
305 plot "telemetry.csv" using (90-$33):($7 == 6 ? $31 : 1/0) with lines ti "drogue", \
306     "telemetry.csv" using (90-$33):($7 == 7 ? $31 : 1/0) with lines ti "main", \
307     "telemetry.csv" using (90-$33):($7 == 8 ? $31 : 1/0) with lines ti "landed"
308
309  */
310
311