altosui: Show filename in AltosGraph window
[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 java.awt.event.*;
12 import javax.swing.*;
13 import javax.swing.filechooser.FileNameExtensionFilter;
14 import javax.swing.table.*;
15
16 import org.jfree.chart.ChartPanel;
17 import org.jfree.chart.ChartUtilities;
18 import org.jfree.chart.JFreeChart;
19 import org.jfree.chart.axis.AxisLocation;
20 import org.jfree.ui.ApplicationFrame;
21 import org.jfree.ui.RefineryUtilities;
22
23 public class AltosGraphUI extends JFrame 
24 {
25     JTabbedPane pane;
26
27     static final private Color red = new Color(194,31,31);
28     static final private Color green = new Color(31,194,31);
29     static final private Color blue = new Color(31,31,194);
30     static final private Color black = new Color(31,31,31);
31     static final private Color yellow = new Color(194,194,31);
32     static final private Color cyan = new Color(31,194,194);
33     static final private Color magenta = new Color(194,31,194);
34
35     static private class OverallGraphs {
36         AltosGraphTime.Element height = 
37             new AltosGraphTime.TimeSeries("Height (m)", "Height (AGL)", red) {
38                 public void gotTimeData(double time, AltosDataPoint d) {
39                         double  height = d.height();
40                         if (height != AltosRecord.MISSING)
41                                 series.add(time, d.height()); 
42                 } 
43             };
44     
45         AltosGraphTime.Element speed =
46             new AltosGraphTime.TimeSeries("Speed (m/s)", "Vertical Speed", green) { 
47                 public void gotTimeData(double time, AltosDataPoint d) {
48                     double      speed;
49                     if (d.state() < Altos.ao_flight_drogue && d.has_accel()) {
50                         speed = d.accel_speed();
51                     } else {
52                         speed = d.baro_speed();
53                     }
54                     if (speed != AltosRecord.MISSING)
55                         series.add(time, speed);
56                 }
57             };
58     
59         AltosGraphTime.Element acceleration =
60             new AltosGraphTime.TimeSeries("Acceleration (m/s\u00B2)", 
61                     "Axial Acceleration", blue) 
62             {
63                 public void gotTimeData(double time, AltosDataPoint d) {
64                     double acceleration = d.acceleration();
65                     if (acceleration != AltosRecord.MISSING)
66                         series.add(time, acceleration);
67                 }
68             };
69     
70         AltosGraphTime.Element temperature =
71             new AltosGraphTime.TimeSeries("Temperature (\u00B0C)", 
72                     "Board temperature", red) 
73             {
74                 public void gotTimeData(double time, AltosDataPoint d) {
75                     double temp = d.temperature();
76                     if (temp != AltosRecord.MISSING)
77                         series.add(time, d.temperature());
78                 }
79             };
80     
81         AltosGraphTime.Element drogue_voltage =
82             new AltosGraphTime.TimeSeries("Voltage (V)", "Drogue Continuity", yellow) 
83             {
84                 public void gotTimeData(double time, AltosDataPoint d) {
85                     double v = d.drogue_voltage();
86                     if (v != AltosRecord.MISSING)
87                         series.add(time, v);
88                 }
89             };
90     
91         AltosGraphTime.Element main_voltage =
92             new AltosGraphTime.TimeSeries("Voltage (V)", "Main Continuity", magenta) 
93             {
94                 public void gotTimeData(double time, AltosDataPoint d) {
95                     double v = d.main_voltage();
96                     if (v != AltosRecord.MISSING)
97                         series.add(time, v);
98                 }
99             };
100     
101         AltosGraphTime.Element e_pad    = new AltosGraphTime.StateMarker(Altos.ao_flight_pad, "Pad");
102         AltosGraphTime.Element e_boost  = new AltosGraphTime.StateMarker(Altos.ao_flight_boost, "Boost");
103         AltosGraphTime.Element e_fast   = new AltosGraphTime.StateMarker(Altos.ao_flight_fast, "Fast");
104         AltosGraphTime.Element e_coast  = new AltosGraphTime.StateMarker(Altos.ao_flight_coast, "Coast");
105         AltosGraphTime.Element e_drogue = new AltosGraphTime.StateMarker(Altos.ao_flight_drogue, "Drogue");
106         AltosGraphTime.Element e_main   = new AltosGraphTime.StateMarker(Altos.ao_flight_main, "Main");
107         AltosGraphTime.Element e_landed = new AltosGraphTime.StateMarker(Altos.ao_flight_landed, "Landed");
108     
109         protected AltosGraphTime myAltosGraphTime(String suffix) {
110             return (new AltosGraphTime("Overall " + suffix))
111                 .addElement(e_boost)
112                 .addElement(e_drogue)
113                 .addElement(e_main)
114                 .addElement(e_landed);
115         }
116     
117         public ArrayList<AltosGraph> graphs() {
118             ArrayList<AltosGraph> graphs = new ArrayList<AltosGraph>();
119     
120             graphs.add( myAltosGraphTime("Summary")
121                         .addElement(height)
122                         .addElement(speed)
123                         .addElement(acceleration)
124                         .addElement(drogue_voltage)
125                         .addElement(main_voltage) );
126
127             graphs.add( myAltosGraphTime("Summary")
128                         .addElement(height)
129                         .addElement(speed));
130     
131             graphs.add( myAltosGraphTime("Altitude")
132                     .addElement(height) );
133     
134             graphs.add( myAltosGraphTime("Speed")
135                     .addElement(speed) );
136     
137             graphs.add( myAltosGraphTime("Acceleration")
138                         .addElement(acceleration) );
139     
140             graphs.add( myAltosGraphTime("Temperature")
141                     .addElement(temperature) );
142     
143             graphs.add( myAltosGraphTime("Continuity")
144                         .addElement(drogue_voltage)
145                         .addElement(main_voltage) );
146     
147             return graphs;
148         }
149     }
150     
151     static private class AscentGraphs extends OverallGraphs {
152         protected AltosGraphTime myAltosGraphTime(String suffix) {
153             return (new AltosGraphTime("Ascent " + suffix) {
154                 public void addData(AltosDataPoint d) {
155                     int state = d.state();
156                     if (Altos.ao_flight_boost <= state && state <= Altos.ao_flight_coast) {
157                         super.addData(d);
158                     }
159                 }
160             }).addElement(e_boost)
161               .addElement(e_fast)
162               .addElement(e_coast);
163         }
164     }
165     
166     static private class DescentGraphs extends OverallGraphs {
167         protected AltosGraphTime myAltosGraphTime(String suffix) {
168             return (new AltosGraphTime("Descent " + suffix) {
169                 public void addData(AltosDataPoint d) {
170                     int state = d.state();
171                     if (Altos.ao_flight_drogue <= state && state <= Altos.ao_flight_main) {
172                         super.addData(d);
173                     }
174                 }
175             }).addElement(e_drogue)
176               .addElement(e_main);
177             // ((XYGraph)graph[8]).ymin = new Double(-50);
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                 if (reader == null)
186                         return;
187         
188                 if (reader.has_accel)
189                     init(reader, records, 0);
190                 else
191                     init(reader, records, 1);
192         }
193
194 //    public AltosGraphUI(AltosDataPointReader data, int which)
195     //  {
196 //        super("Altos Graph");
197 //        init(data, which);
198 //    }
199
200     private void init(AltosDataPointReader data, AltosRecordIterable records, int which) throws InterruptedException, IOException {
201         pane = new JTabbedPane();
202
203         AltosGraph graph = createGraph(data, which);
204
205         JFreeChart chart = graph.createChart();
206         ChartPanel chartPanel = new ChartPanel(chart);
207         chartPanel.setMouseWheelEnabled(true);
208         chartPanel.setPreferredSize(new java.awt.Dimension(800, 500));
209         pane.add(graph.title, chartPanel);
210
211         AltosFlightStatsTable stats = new AltosFlightStatsTable(new AltosFlightStats(records));
212         pane.add("Flight Statistics", stats);
213
214         setContentPane (pane);
215
216         pack();
217
218         RefineryUtilities.centerFrameOnScreen(this);
219
220         setDefaultCloseOperation(DISPOSE_ON_CLOSE);
221         setVisible(true);
222     }
223
224     private static AltosGraph createGraph(Iterable<AltosDataPoint> data,
225             int which)
226     {
227         return createGraphsWhich(data, which).get(0);
228     }
229
230     private static ArrayList<AltosGraph> createGraphs(
231             Iterable<AltosDataPoint> data)
232     {
233         return createGraphsWhich(data, -1);
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