altoslib: Add user-selectable filter width for data smoothing
authorKeith Packard <keithp@keithp.com>
Tue, 3 Oct 2017 02:33:37 +0000 (19:33 -0700)
committerKeith Packard <keithp@keithp.com>
Tue, 3 Oct 2017 02:33:37 +0000 (19:33 -0700)
Also switch smoothing window to Kaiser and change default accel filter
width to 1 second instead of 4 seconds.

Now users can play with the filter and see what it does.

Signed-off-by: Keith Packard <keithp@keithp.com>
altoslib/AltosFlightSeries.java
altoslib/AltosTimeSeries.java
altoslib/Makefile.am
altosui/AltosGraphUI.java
altosuilib/AltosFlightStatsTable.java
altosuilib/AltosGraph.java
altosuilib/AltosUIEnable.java
altosuilib/AltosUIGraph.java
altosuilib/AltosUITimeSeries.java
micropeak/MicroPeak.java
telegps/TeleGPSGraphUI.java

index ab7943b..02bf64f 100644 (file)
@@ -21,7 +21,7 @@ public class AltosFlightSeries extends AltosDataListener {
        public ArrayList<AltosTimeSeries> series = new ArrayList<AltosTimeSeries>();
 
        public double   speed_filter_width = 4.0;
-       public double   accel_filter_width = 4.0;
+       public double   accel_filter_width = 1.0;
 
        public int[] indices() {
                int[] indices = new int[series.size()];
@@ -160,6 +160,7 @@ public class AltosFlightSeries extends AltosDataListener {
        }
 
        public AltosTimeSeries  accel_series;
+       public boolean          accel_computed;
 
        public static final String accel_name = "Accel";
 
@@ -174,17 +175,44 @@ public class AltosFlightSeries extends AltosDataListener {
                        accel_series = add_series(accel_name, AltosConvert.accel);
 
                accel_series.add(time(), acceleration);
+               accel_computed = false;
        }
 
-       private void compute_accel() {
-               if (accel_series != null)
-                       return;
+       private AltosTimeSeries compute_accel() {
+               AltosTimeSeries new_accel_series = null;
 
                if (speed_series != null) {
-                       AltosTimeSeries temp_series = make_series(speed_name, AltosConvert.speed);
-                       speed_series.filter(temp_series, accel_filter_width);
-                       accel_series = add_series(accel_name, AltosConvert.accel);
-                       temp_series.differentiate(accel_series);
+                       AltosTimeSeries temp_series;
+                       if (accel_filter_width > 0) {
+                               temp_series = make_series(speed_name, AltosConvert.speed);
+                               speed_series.filter(temp_series, accel_filter_width);
+                       } else
+                               temp_series = speed_series;
+
+                       new_accel_series = make_series(accel_name, AltosConvert.accel);
+                       temp_series.differentiate(new_accel_series);
+               }
+               return new_accel_series;
+       }
+
+       public void set_filter(double speed_filter, double accel_filter) {
+               this.speed_filter_width = speed_filter;
+               this.accel_filter_width = accel_filter;
+
+               AltosTimeSeries new_speed_series = compute_speed();
+
+               if (new_speed_series != null) {
+                       speed_series.erase_values();
+                       for (AltosTimeValue tv : new_speed_series)
+                               speed_series.add(tv);
+               }
+               if (accel_computed) {
+                       AltosTimeSeries new_accel_series = compute_accel();
+                       if (new_accel_series != null) {
+                               accel_series.erase_values();
+                               for (AltosTimeValue tv : new_accel_series)
+                                       accel_series.add(tv);
+                       }
                }
        }
 
@@ -268,21 +296,24 @@ public class AltosFlightSeries extends AltosDataListener {
 
        public static final String speed_name = "Speed";
 
-       private void compute_speed() {
-               if (speed_series != null)
-                       return;
-
+       private AltosTimeSeries compute_speed() {
+               AltosTimeSeries new_speed_series = null;
                AltosTimeSeries alt_speed_series = null;
                AltosTimeSeries accel_speed_series = null;
 
                if (altitude_series != null) {
-                       AltosTimeSeries temp_series = make_series(altitude_name, AltosConvert.height);
-                       altitude_series.filter(temp_series, speed_filter_width);
+                       AltosTimeSeries temp_series;
+
+                       if (speed_filter_width > 0) {
+                               temp_series = make_series(speed_name, AltosConvert.height);
+                               altitude_series.filter(temp_series, speed_filter_width);
+                       } else
+                               temp_series = altitude_series;
 
                        alt_speed_series = make_series(speed_name, AltosConvert.speed);
                        temp_series.differentiate(alt_speed_series);
                }
-               if (accel_series != null) {
+               if (accel_series != null && !accel_computed) {
 
                        if (orient_series != null) {
                                vert_accel_series = add_series(vert_accel_name, AltosConvert.accel);
@@ -318,26 +349,25 @@ public class AltosFlightSeries extends AltosDataListener {
                                }
                        }
                        if (apogee_time == AltosLib.MISSING) {
-                               speed_series = alt_speed_series;
+                               new_speed_series = alt_speed_series;
                        } else {
-                               speed_series = make_series(speed_name, AltosConvert.speed);
+                               new_speed_series = make_series(speed_name, AltosConvert.speed);
                                for (AltosTimeValue d : accel_speed_series) {
                                        if (d.time <= apogee_time)
-                                               speed_series.add(d);
+                                               new_speed_series.add(d);
                                }
                                for (AltosTimeValue d : alt_speed_series) {
                                        if (d.time > apogee_time)
-                                               speed_series.add(d);
+                                               new_speed_series.add(d);
                                }
 
                        }
                } else if (alt_speed_series != null) {
-                       speed_series = alt_speed_series;
+                       new_speed_series = alt_speed_series;
                } else if (accel_speed_series != null) {
-                       speed_series = accel_speed_series;
+                       new_speed_series = accel_speed_series;
                }
-               if (speed_series != null)
-                       add_series(speed_series);
+               return new_speed_series;
        }
 
        public AltosTimeSeries orient_series;
@@ -690,8 +720,18 @@ public class AltosFlightSeries extends AltosDataListener {
 
        public void finish() {
                compute_orient();
-               compute_speed();
-               compute_accel();
+               if (speed_series == null) {
+                       speed_series = compute_speed();
+                       if (speed_series != null)
+                               add_series(speed_series);
+               }
+               if (accel_series == null) {
+                       accel_series = compute_accel();
+                       if (accel_series != null) {
+                               add_series(accel_series);
+                               accel_computed = true;
+                       }
+               }
                compute_height();
        }
 
index 9f3b4d8..7208c17 100644 (file)
@@ -20,15 +20,30 @@ public class AltosTimeSeries implements Iterable<AltosTimeValue>, Comparable<Alt
        public String                   label;
        public AltosUnits               units;
        ArrayList<AltosTimeValue>       values;
+       boolean                         data_changed;
 
        public int compareTo(AltosTimeSeries other) {
                return label.compareTo(other.label);
        }
 
        public void add(AltosTimeValue tv) {
+               data_changed = true;
                values.add(tv);
        }
 
+       public void erase_values() {
+               data_changed = true;
+               this.values = new ArrayList<AltosTimeValue>();
+       }
+
+       public void clear_changed() {
+               data_changed = false;
+       }
+
+//     public boolean changed() {
+//             return data_changed;
+//     }
+
        public void add(double time, double value) {
                add(new AltosTimeValue(time, value));
        }
@@ -264,14 +279,35 @@ public class AltosTimeSeries implements Iterable<AltosTimeValue>, Comparable<Alt
 
        }
 
-       private double filter_coeff(double dist, double width) {
-               double ratio = dist / (width / 2);
+       private static double i0(double x) {
+               double  ds = 1, d = 0, s = 0;
 
-               return Math.cos(ratio * Math.PI / 2);
+               do {
+                       d += 2;
+                       ds = ds * (x * x) / (d * d);
+                       s += ds;
+               } while (ds - 0.2e-8 * s > 0);
+               return s;
+       }
+
+       private static double kaiser(double n, double m, double beta) {
+               double alpha = m / 2;
+               double t = (n - alpha) / alpha;
+
+               if (t > 1)
+                       t = 1;
+               double k = i0 (beta * Math.sqrt (1 - t*t)) / i0(beta);
+               return k;
+       }
+
+       private double filter_coeff(double dist, double width) {
+               return kaiser(dist + width/2.0, width, 2 * Math.PI);
        }
 
        public AltosTimeSeries filter(AltosTimeSeries f, double width) {
+
                double  half_width = width/2;
+               int half_point = values.size() / 2;
                for (int i = 0; i < values.size(); i++) {
                        double  center_time = values.get(i).time;
                        double  left_time = center_time - half_width;
index 08af949..2a1cb8e 100644 (file)
@@ -55,6 +55,7 @@ altoslib_JAVA = \
        AltosEepromList.java \
        AltosEepromLog.java \
        AltosFile.java \
+       AltosFilterListener.java \
        AltosFlash.java \
        AltosFlashListener.java \
        AltosDataListener.java \
index 042f927..f387ed9 100644 (file)
@@ -31,7 +31,7 @@ import org.jfree.chart.ChartPanel;
 import org.jfree.chart.JFreeChart;
 import org.jfree.ui.RefineryUtilities;
 
-public class AltosGraphUI extends AltosUIFrame implements AltosFontListener, AltosUnitsListener
+public class AltosGraphUI extends AltosUIFrame implements AltosFontListener, AltosUnitsListener, AltosFilterListener
 {
        JTabbedPane             pane;
        AltosGraph              graph;
@@ -82,6 +82,23 @@ public class AltosGraphUI extends AltosUIFrame implements AltosFontListener, Alt
                        enable.units_changed(imperial_units);
        }
 
+       AltosUIFlightSeries flight_series;
+
+       public void filter_changed(double speed_filter, double accel_filter) {
+               flight_series.set_filter(speed_filter, accel_filter);
+               graph.filter_changed();
+               stats = new AltosFlightStats(flight_series);
+               statsTable.filter_changed(stats);
+       }
+
+       public double speed_filter() {
+               return flight_series.speed_filter_width;
+       }
+
+       public double accel_filter() {
+               return flight_series.accel_filter_width;
+       }
+
        AltosGraphUI(AltosRecordSet set, File file) throws InterruptedException, IOException {
                super(file.getName());
                AltosCalData    cal_data = set.cal_data();
@@ -89,9 +106,9 @@ public class AltosGraphUI extends AltosUIFrame implements AltosFontListener, Alt
 
                pane = new JTabbedPane();
 
-               enable = new AltosUIEnable();
+               flight_series = new AltosUIFlightSeries(cal_data);
 
-               AltosUIFlightSeries flight_series = new AltosUIFlightSeries(cal_data);
+               enable = new AltosUIEnable(this);
 
                set.capture_series(flight_series);
 
index 415c024..8f7e9bf 100644 (file)
@@ -38,6 +38,11 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen
                                value[i].setFont(AltosUILib.value_font);
                }
 
+               public void set(String ... values) {
+                       for (int j = 0; j < values.length; j++)
+                               value[j].setText(values[j]);
+               }
+
                public FlightStat(GridBagLayout layout, int y, String label_text, String ... values) {
                        GridBagConstraints      c = new GridBagConstraints();
                        c.insets = new Insets(AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad);
@@ -87,6 +92,43 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen
                return String.format("%s %4d° %9.6f'", h, deg, min);
        }
 
+       private FlightStat      max_height_stat;
+       private FlightStat      max_speed_stat;
+       private FlightStat      max_accel_stat;
+       private FlightStat      boost_accel_stat;
+       private FlightStat      drogue_descent_stat;
+       private FlightStat      main_descent_stat;
+
+       public void set_values(AltosFlightStats stats) {
+               if (max_height_stat != null && stats.max_height != AltosLib.MISSING) {
+                       max_height_stat.set(String.format("%6.1f m", stats.max_height),
+                                           String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_height)));
+               }
+               if (max_speed_stat != null && stats.max_speed != AltosLib.MISSING) {
+                       max_speed_stat.set(String.format("%6.1f m/s", stats.max_speed),
+                                          String.format("%5.0f fps", AltosConvert.mps_to_fps(stats.max_speed)),
+                                          String.format("Mach %4.1f", AltosConvert.meters_to_mach(stats.max_speed)));
+               }
+               if (max_accel_stat != null && stats.max_acceleration != AltosLib.MISSING) {
+                       max_accel_stat.set(String.format("%6.1f m/s²", stats.max_acceleration),
+                                          String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.max_acceleration)),
+                                          String.format("%6.2f G", AltosConvert.meters_to_g(stats.max_acceleration)));
+               }
+               if (boost_accel_stat != null && stats.state_accel[AltosLib.ao_flight_boost] != AltosLib.MISSING) {
+                       boost_accel_stat.set(String.format("%6.1f m/s²", stats.state_accel[AltosLib.ao_flight_boost]),
+                                            String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.state_accel[AltosLib.ao_flight_boost])),
+                                            String.format("%6.2f G", AltosConvert.meters_to_g(stats.state_accel[AltosLib.ao_flight_boost])));
+               }
+               if (drogue_descent_stat != null && stats.state_speed[AltosLib.ao_flight_drogue] != AltosLib.MISSING) {
+                       drogue_descent_stat.set(String.format("%6.1f m/s", -stats.state_speed[AltosLib.ao_flight_drogue]),
+                                               String.format("%5.0f ft/s", -AltosConvert.meters_to_feet(stats.state_speed[AltosLib.ao_flight_drogue])));
+               }
+               if (main_descent_stat != null && stats.state_speed[AltosLib.ao_flight_main] != AltosLib.MISSING) {
+                               main_descent_stat.set(String.format("%6.1f m/s", -stats.state_speed[AltosLib.ao_flight_main]),
+                                                     String.format("%5.0f ft/s", -AltosConvert.meters_to_feet(stats.state_speed[AltosLib.ao_flight_main])));
+               }
+       }
+
        public void set_stats(AltosFlightStats stats) {
                int y = 0;
                if (stats.serial != AltosLib.MISSING) {
@@ -113,9 +155,9 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen
                                               String.format("%02d:%02d:%02d UTC", stats.hour, stats.minute, stats.second));
                }
                if (stats.max_height != AltosLib.MISSING) {
-                       new FlightStat(layout, y++, "Maximum height",
-                                      String.format("%6.1f m", stats.max_height),
-                                      String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_height)));
+                       max_height_stat = new FlightStat(layout, y++, "Maximum height",
+                                                        String.format("%6.1f m", stats.max_height),
+                                                        String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_height)));
                }
                if (stats.max_gps_height != AltosLib.MISSING) {
                        new FlightStat(layout, y++, "Maximum GPS height",
@@ -123,21 +165,21 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen
                                       String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_gps_height)));
                }
                if (stats.max_speed != AltosLib.MISSING) {
-                       new FlightStat(layout, y++, "Maximum speed",
-                                      String.format("%6.1f m/s", stats.max_speed),
-                                      String.format("%5.0f fps", AltosConvert.mps_to_fps(stats.max_speed)),
-                                      String.format("Mach %4.1f", AltosConvert.meters_to_mach(stats.max_speed)));
+                       max_speed_stat = new FlightStat(layout, y++, "Maximum speed",
+                                                       String.format("%6.1f m/s", stats.max_speed),
+                                                       String.format("%5.0f fps", AltosConvert.mps_to_fps(stats.max_speed)),
+                                                       String.format("Mach %4.1f", AltosConvert.meters_to_mach(stats.max_speed)));
                }
                if (stats.max_acceleration != AltosLib.MISSING)
-                       new FlightStat(layout, y++, "Maximum boost acceleration",
-                                      String.format("%6.1f m/s²", stats.max_acceleration),
-                                      String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.max_acceleration)),
-                                      String.format("%6.2f G", AltosConvert.meters_to_g(stats.max_acceleration)));
+                       max_accel_stat = new FlightStat(layout, y++, "Maximum boost acceleration",
+                                                       String.format("%6.1f m/s²", stats.max_acceleration),
+                                                       String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.max_acceleration)),
+                                                       String.format("%6.2f G", AltosConvert.meters_to_g(stats.max_acceleration)));
                if (stats.state_accel[AltosLib.ao_flight_boost] != AltosLib.MISSING)
-                       new FlightStat(layout, y++, "Average boost acceleration",
-                                      String.format("%6.1f m/s²", stats.state_accel[AltosLib.ao_flight_boost]),
-                                      String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.state_accel[AltosLib.ao_flight_boost])),
-                                      String.format("%6.2f G", AltosConvert.meters_to_g(stats.state_accel[AltosLib.ao_flight_boost])));
+                       boost_accel_stat = new FlightStat(layout, y++, "Average boost acceleration",
+                                                         String.format("%6.1f m/s²", stats.state_accel[AltosLib.ao_flight_boost]),
+                                                         String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.state_accel[AltosLib.ao_flight_boost])),
+                                                         String.format("%6.2f G", AltosConvert.meters_to_g(stats.state_accel[AltosLib.ao_flight_boost])));
                if (stats.state_time[AltosLib.ao_flight_boost] != 0 || stats.state_time[AltosLib.ao_flight_fast] != 0 || stats.state_time[AltosLib.ao_flight_coast] != 0) {
 
                        double  boost_time = stats.state_time[AltosLib.ao_flight_boost];
@@ -167,14 +209,14 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen
                                label = "Descent rate";
                        else
                                label = "Drogue descent rate";
-                       new FlightStat(layout, y++, label,
+                       drogue_descent_stat = new FlightStat(layout, y++, label,
                                       String.format("%6.1f m/s", -stats.state_speed[AltosLib.ao_flight_drogue]),
                                       String.format("%5.0f ft/s", -AltosConvert.meters_to_feet(stats.state_speed[AltosLib.ao_flight_drogue])));
                }
                if (stats.state_speed[AltosLib.ao_flight_main] != AltosLib.MISSING)
-                       new FlightStat(layout, y++, "Main descent rate",
-                                      String.format("%6.1f m/s", -stats.state_speed[AltosLib.ao_flight_main]),
-                                      String.format("%5.0f ft/s", -AltosConvert.meters_to_feet(stats.state_speed[AltosLib.ao_flight_main])));
+                       main_descent_stat = new FlightStat(layout, y++, "Main descent rate",
+                                                          String.format("%6.1f m/s", -stats.state_speed[AltosLib.ao_flight_main]),
+                                                          String.format("%5.0f ft/s", -AltosConvert.meters_to_feet(stats.state_speed[AltosLib.ao_flight_main])));
                if (stats.state_time[AltosLib.ao_flight_drogue] != 0 || stats.state_time[AltosLib.ao_flight_main] != 0) {
                        double  drogue_duration = stats.state_time[AltosLib.ao_flight_drogue];
                        double  main_duration = stats.state_time[AltosLib.ao_flight_main];
@@ -210,6 +252,10 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen
                AltosUIPreferences.unregister_font_listener(this);
        }
 
+       public void filter_changed(AltosFlightStats stats) {
+               set_values(stats);
+       }
+
        public AltosFlightStatsTable() {
                layout = new GridBagLayout();
 
index 5df9523..3f61028 100644 (file)
@@ -92,7 +92,7 @@ public class AltosGraph extends AltosUIGraph {
                AltosUIAxis     gyro_axis, orient_axis, mag_axis;
                AltosUIAxis     course_axis, dop_axis, tick_axis;
 
-               if (stats.serial != AltosLib.MISSING && stats.product != null && stats.flight != AltosLib.MISSING)
+               if (stats != null && stats.serial != AltosLib.MISSING && stats.product != null && stats.flight != AltosLib.MISSING)
                        setName(String.format("%s %d flight %d\n", stats.product, stats.serial, stats.flight));
 
                height_axis = newAxis("Height", AltosConvert.height, height_color);
@@ -327,12 +327,6 @@ public class AltosGraph extends AltosUIGraph {
                return flight_series.series(cal_data);
        }
 
-       public void set_filter(double filter) {
-               System.out.printf("filter set to %f\n", filter);
-               flight_series.set_filter(filter, filter);
-               units_changed(false);
-       }
-
        public void set_data(AltosFlightStats stats, AltosUIFlightSeries flight_series) {
                set_series(setup(stats, flight_series));
        }
index 0c23fa8..4bd07c5 100644 (file)
@@ -21,6 +21,7 @@ package org.altusmetrum.altosuilib_12;
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
+import javax.swing.event.*;
 import java.io.*;
 import java.util.concurrent.*;
 import java.util.*;
@@ -36,12 +37,17 @@ import org.jfree.chart.labels.*;
 import org.jfree.data.xy.*;
 import org.jfree.data.*;
 
-public class AltosUIEnable extends Container {
+public class AltosUIEnable extends Container implements ChangeListener {
 
        Insets          il, ir;
        int             y;
        int             x;
        JCheckBox       imperial_units;
+       JLabel          speed_filter_label;
+       JSlider         speed_filter;
+       JLabel          accel_filter_label;
+       JSlider         accel_filter;
+       AltosFilterListener     filter_listener;
 
        static final int max_rows = 14;
 
@@ -69,11 +75,15 @@ public class AltosUIEnable extends Container {
                }
        }
 
+       LinkedList<GraphElement> elements = new LinkedList<GraphElement>();
+
        public void add(String name, AltosUIGrapher grapher, boolean enabled) {
 
                GraphElement    e = new GraphElement(name, grapher, enabled);
                GridBagConstraints c = new GridBagConstraints();
 
+               elements.add(e);
+
                /* Add element */
                c = new GridBagConstraints();
                c.gridx = x; c.gridy = y;
@@ -90,6 +100,17 @@ public class AltosUIEnable extends Container {
                }
        }
 
+       public void stateChanged(ChangeEvent e) {
+               JSlider filter = (JSlider) e.getSource();
+               if (!filter.getValueIsAdjusting()) {
+                       double  speed_value = (int) speed_filter.getValue() / 1000.0;
+                       double  accel_value = (int) accel_filter.getValue() / 1000.0;
+                       if (filter_listener != null) {
+                               filter_listener.filter_changed(speed_value, accel_value);
+                       }
+               }
+       }
+
        public void add_units() {
                /* Imperial units setting */
 
@@ -109,9 +130,66 @@ public class AltosUIEnable extends Container {
                c.anchor = GridBagConstraints.LINE_START;
                c.insets = il;
                add(imperial_units, c);
+
+               speed_filter_label = new JLabel("Speed Filter(ms)");
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = 1001;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               add(speed_filter_label, c);
+
+               speed_filter = new JSlider(JSlider.HORIZONTAL, 0, 10000, (int) (filter_listener.speed_filter() * 1000.0));
+               Hashtable<Integer,JLabel> label_table = new Hashtable<Integer,JLabel>();
+               for (int i = 0; i <= 10000; i += 5000) {
+                       label_table.put(new Integer(i), new JLabel(String.format("%d", i)));
+               }
+               speed_filter.setPaintTicks(true);
+               speed_filter.setMajorTickSpacing(1000);
+               speed_filter.setMinorTickSpacing(250);
+               speed_filter.setLabelTable(label_table);
+               speed_filter.setPaintTrack(false);
+               speed_filter.setSnapToTicks(true);
+               speed_filter.setPaintLabels(true);
+               speed_filter.addChangeListener(this);
+
+               c = new GridBagConstraints();
+               c.gridx = 1; c.gridy = 1001;
+               c.gridwidth = 1000; c.gridheight = 1;
+               c.fill = GridBagConstraints.BOTH;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               add(speed_filter, c);
+
+               accel_filter_label = new JLabel("Acceleration Filter(ms)");
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = 1002;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               add(accel_filter_label, c);
+
+               accel_filter = new JSlider(JSlider.HORIZONTAL, 0, 10000, (int) (filter_listener.accel_filter() * 1000.0));
+               accel_filter.setPaintTicks(true);
+               accel_filter.setMajorTickSpacing(1000);
+               accel_filter.setMinorTickSpacing(250);
+               accel_filter.setLabelTable(label_table);
+               accel_filter.setPaintTrack(false);
+               accel_filter.setSnapToTicks(true);
+               accel_filter.setPaintLabels(true);
+               accel_filter.addChangeListener(this);
+
+               c = new GridBagConstraints();
+               c.gridx = 1; c.gridy = 1002;
+               c.gridwidth = 1000; c.gridheight = 1;
+               c.fill = GridBagConstraints.BOTH;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               add(accel_filter, c);
        }
 
-       public AltosUIEnable() {
+       public AltosUIEnable(AltosFilterListener filter_listener) {
+               this.filter_listener = filter_listener;
                il = new Insets(4,4,4,4);
                ir = new Insets(4,4,4,4);
                x = 0;
index 0caabcf..efc3d49 100644 (file)
@@ -95,6 +95,10 @@ public class AltosUIGraph implements AltosUnitsListener {
                        s.set_units();
        }
 
+       public void filter_changed() {
+               units_changed(false);
+       }
+
        public void setName (String name) {
                chart.setTitle(name);
        }
index 08f95ca..7116606 100644 (file)
@@ -89,7 +89,7 @@ public class AltosUITimeSeries extends AltosTimeSeries implements AltosUIGrapher
        public void fireSeriesChanged() {
        }
 
-       void set_data() {
+       public void set_data() {
                if (marker) {
                        if (markers != null) {
                                for (ValueMarker marker : markers)
@@ -124,6 +124,7 @@ public class AltosUITimeSeries extends AltosTimeSeries implements AltosUIGrapher
                        }
                        xy_series.setNotify(true);
                }
+               clear_changed();
        }
 
        public void set_units() {
index 749d0f6..c6a2a3c 100644 (file)
@@ -27,7 +27,7 @@ import java.util.*;
 import org.altusmetrum.altoslib_12.*;
 import org.altusmetrum.altosuilib_12.*;
 
-public class MicroPeak extends MicroFrame implements ActionListener, ItemListener {
+public class MicroPeak extends MicroFrame implements ActionListener, ItemListener, AltosFilterListener {
 
        File            filename;
        AltosGraph      graph;
@@ -206,6 +206,25 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene
                Preferences();
        }
 
+       public void filter_changed(double speed_filter, double accel_filter) {
+               data.flight_series.set_filter(speed_filter, accel_filter);
+               graph.filter_changed();
+               data.flight_stats = new AltosFlightStats(data.flight_series);
+               statsTable.filter_changed(data.flight_stats);
+       }
+
+       public double speed_filter() {
+               if (data != null && data.flight_series != null)
+                       return data.flight_series.speed_filter_width;
+               return 4.0;
+       }
+
+       public double accel_filter() {
+               if (data != null && data.flight_series != null)
+                       return data.flight_series.accel_filter_width;
+               return 1.0;
+       }
+
        public MicroPeak() {
 
                ++number_of_windows;
@@ -267,7 +286,7 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene
                        }
                });
 
-               enable = new AltosUIEnable();
+               enable = new AltosUIEnable(this);
 
                graph = new AltosGraph(enable);
                statsTable = new AltosFlightStatsTable();
index 9d8c6bf..c68f2ba 100644 (file)
@@ -34,7 +34,7 @@ import org.jfree.chart.ChartPanel;
 import org.jfree.chart.JFreeChart;
 import org.jfree.ui.RefineryUtilities;
 
-public class TeleGPSGraphUI extends AltosUIFrame implements AltosFontListener, AltosUnitsListener
+public class TeleGPSGraphUI extends AltosUIFrame implements AltosFontListener, AltosUnitsListener, AltosFilterListener
 {
        JTabbedPane             pane;
        AltosGraph              graph;
@@ -92,20 +92,38 @@ public class TeleGPSGraphUI extends AltosUIFrame implements AltosFontListener, A
                        enable.units_changed(imperial_units);
        }
 
+       AltosUIFlightSeries flight_series;
+
+       public void filter_changed(double speed_filter, double accel_filter) {
+               flight_series.set_filter(speed_filter, accel_filter);
+               graph.filter_changed();
+               stats = new AltosFlightStats(flight_series);
+               statsTable.filter_changed(stats);
+       }
+
+       public double speed_filter() {
+               return flight_series.speed_filter_width;
+       }
+
+       public double accel_filter() {
+               return flight_series.accel_filter_width;
+       }
+
        TeleGPSGraphUI(AltosRecordSet set, File file) throws InterruptedException, IOException {
                super(file.getName());
                AltosCalData cal_data = set.cal_data();
 
-               AltosUIFlightSeries flight_series = new AltosUIFlightSeries(cal_data);
+               flight_series = new AltosUIFlightSeries(cal_data);
                set.capture_series(flight_series);
                flight_series.finish();
 
                pane = new JTabbedPane();
 
-               enable = new AltosUIEnable();
+               graph = new AltosGraph(enable, stats, flight_series);
+
                stats = new AltosFlightStats(flight_series);
 
-               graph = new AltosGraph(enable, stats, flight_series);
+               enable = new AltosUIEnable(this);
 
                statsTable = new AltosFlightStatsTable(stats);