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