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