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