030bbc25d4dd25f54c114caaa98124979f14b8fc
[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_fast)
113                 .addElement(e_coast)
114                 .addElement(e_drogue)
115                 .addElement(e_main)
116                 .addElement(e_landed);
117         }
118     
119         public ArrayList<AltosGraph> graphs() {
120             ArrayList<AltosGraph> graphs = new ArrayList<AltosGraph>();
121     
122             graphs.add( myAltosGraphTime("Summary")
123                         .addElement(height)
124                         .addElement(speed)
125                         .addElement(acceleration)
126                         .addElement(drogue_voltage)
127                         .addElement(main_voltage) );
128
129             graphs.add( myAltosGraphTime("Summary")
130                         .addElement(height)
131                         .addElement(speed));
132     
133             graphs.add( myAltosGraphTime("Altitude")
134                     .addElement(height) );
135     
136             graphs.add( myAltosGraphTime("Speed")
137                     .addElement(speed) );
138     
139             graphs.add( myAltosGraphTime("Acceleration")
140                         .addElement(acceleration) );
141     
142             graphs.add( myAltosGraphTime("Temperature")
143                     .addElement(temperature) );
144     
145             graphs.add( myAltosGraphTime("Continuity")
146                         .addElement(drogue_voltage)
147                         .addElement(main_voltage) );
148     
149             return graphs;
150         }
151     }
152     
153     static private class AscentGraphs extends OverallGraphs {
154         protected AltosGraphTime myAltosGraphTime(String suffix) {
155             return (new AltosGraphTime("Ascent " + suffix) {
156                 public void addData(AltosDataPoint d) {
157                     int state = d.state();
158                     if (Altos.ao_flight_boost <= state && state <= Altos.ao_flight_coast) {
159                         super.addData(d);
160                     }
161                 }
162             }).addElement(e_boost)
163               .addElement(e_fast)
164               .addElement(e_coast);
165         }
166     }
167     
168     static private class DescentGraphs extends OverallGraphs {
169         protected AltosGraphTime myAltosGraphTime(String suffix) {
170             return (new AltosGraphTime("Descent " + suffix) {
171                 public void addData(AltosDataPoint d) {
172                     int state = d.state();
173                     if (Altos.ao_flight_drogue <= state && state <= Altos.ao_flight_main) {
174                         super.addData(d);
175                     }
176                 }
177             }).addElement(e_drogue)
178               .addElement(e_main);
179             // ((XYGraph)graph[8]).ymin = new Double(-50);
180         }
181     }
182
183         public AltosGraphUI(AltosRecordIterable records, String name) throws InterruptedException, IOException {
184                 super(String.format("Altos Graph %s", name));
185
186                 AltosDataPointReader reader = new AltosDataPointReader (records);
187                 if (reader == null)
188                         return;
189         
190                 if (reader.has_accel)
191                     init(reader, records, 0);
192                 else
193                     init(reader, records, 1);
194         }
195
196 //    public AltosGraphUI(AltosDataPointReader data, int which)
197     //  {
198 //        super("Altos Graph");
199 //        init(data, which);
200 //    }
201
202     private void init(AltosDataPointReader data, AltosRecordIterable records, int which) throws InterruptedException, IOException {
203         pane = new JTabbedPane();
204
205         AltosGraph graph = createGraph(data, which);
206
207         JFreeChart chart = graph.createChart();
208         ChartPanel chartPanel = new ChartPanel(chart);
209         chartPanel.setMouseWheelEnabled(true);
210         chartPanel.setPreferredSize(new java.awt.Dimension(800, 500));
211         pane.add(graph.title, chartPanel);
212
213         AltosFlightStatsTable stats = new AltosFlightStatsTable(new AltosFlightStats(records));
214         pane.add("Flight Statistics", stats);
215
216         setContentPane (pane);
217
218         pack();
219
220         RefineryUtilities.centerFrameOnScreen(this);
221
222         setDefaultCloseOperation(DISPOSE_ON_CLOSE);
223         setVisible(true);
224     }
225
226     private static AltosGraph createGraph(Iterable<AltosDataPoint> data,
227             int which)
228     {
229         return createGraphsWhich(data, which).get(0);
230     }
231
232     private static ArrayList<AltosGraph> createGraphs(
233             Iterable<AltosDataPoint> data)
234     {
235         return createGraphsWhich(data, -1);
236     }
237
238     private static ArrayList<AltosGraph> createGraphsWhich(
239             Iterable<AltosDataPoint> data, int which)
240     {
241         ArrayList<AltosGraph> graph = new ArrayList<AltosGraph>();
242         graph.addAll((new OverallGraphs()).graphs());
243 //        graph.addAll((new AscentGraphs()).graphs());
244 //        graph.addAll((new DescentGraphs()).graphs());
245
246         if (which > 0) {
247             if (which >= graph.size()) {
248                 which = 0;
249             }
250             AltosGraph g = graph.get(which);
251             graph = new ArrayList<AltosGraph>();
252             graph.add(g);
253         }
254
255         for (AltosDataPoint dp : data) {
256             for (AltosGraph g : graph) {
257                 g.addData(dp);
258             }
259         }
260
261         return graph;
262     }
263 }
264
265 /* gnuplot bits...
266  *
267 300x400
268
269 --------------------------------------------------------
270 TOO HARD! :)
271
272 "ascent-gps-accuracy.png" "Vertical error margin to apogee - GPS v Baro (m)"
273     5:($7 < 6 ? $24-$11 : 1/0)
274 "descent-gps-accuracy.png" "Vertical error margin during descent - GPS v Baro (m)"
275     5:($7 < 6 ? 1/0 : $24-$11)
276
277 set output "overall-gps-accuracy.png"
278 set ylabel "distance above sea level (m)"
279 plot "telemetry.csv" using 5:11 with lines ti "baro altitude" axis x1y1, \
280     "telemetry.csv" using 5:24 with lines ti "gps altitude" axis x1y1
281
282 set term png tiny size 700,700 enhanced
283 set xlabel "m"
284 set ylabel "m"
285 set polar
286 set grid polar
287 set rrange[*:*]
288 set angles degrees
289
290 set output "overall-gps-path.png"
291 #:30 with yerrorlines
292 plot "telemetry.csv" using (90-$33):($7 == 2 ? $31 : 1/0) with lines ti "pad", \
293     "telemetry.csv" using (90-$33):($7 == 3 ? $31 : 1/0) with lines ti "boost", \
294     "telemetry.csv" using (90-$33):($7 == 4 ? $31 : 1/0) with lines ti "fast", \
295     "telemetry.csv" using (90-$33):($7 == 5 ? $31 : 1/0) with lines ti "coast", \
296     "telemetry.csv" using (90-$33):($7 == 6 ? $31 : 1/0) with lines ti "drogue", \
297     "telemetry.csv" using (90-$33):($7 == 7 ? $31 : 1/0) with lines ti "main", \
298     "telemetry.csv" using (90-$33):($7 == 8 ? $31 : 1/0) with lines ti "landed"
299
300 set output "ascent-gps-path.png"
301 plot "telemetry.csv" using (90-$33):($7 == 2 ? $31 : 1/0):30 with lines ti "pad", \
302     "telemetry.csv" using (90-$33):($7 == 3 ? $31 : 1/0):20 with lines ti "boost", \
303     "telemetry.csv" using (90-$33):($7 == 4 ? $31 : 1/0):10 with lines ti "fast", \
304     "telemetry.csv" using (90-$33):($7 == 5 ? $31 : 1/0):5 with lines ti "coast"
305
306 set output "descent-gps-path.png"
307 plot "telemetry.csv" using (90-$33):($7 == 6 ? $31 : 1/0) with lines ti "drogue", \
308     "telemetry.csv" using (90-$33):($7 == 7 ? $31 : 1/0) with lines ti "main", \
309     "telemetry.csv" using (90-$33):($7 == 8 ? $31 : 1/0) with lines ti "landed"
310
311  */
312
313