From: Keith Packard Date: Fri, 26 May 2017 07:20:17 +0000 (-0700) Subject: altoslib,altosuilib,altosui: Get stats and replay working again. X-Git-Tag: 1.8~92 X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=commitdiff_plain;h=2e82051a6aaaccf1e8a242f9c8141e4167e652d2;ds=sidebyside altoslib,altosuilib,altosui: Get stats and replay working again. Stats are really easy with all of the data in memory. Replay takes a special thread to run the data and dump it into a single state. Signed-off-by: Keith Packard --- diff --git a/altoslib/AltosEepromRecordMega.java b/altoslib/AltosEepromRecordMega.java index d4a5a0b2..cd6916b4 100644 --- a/altoslib/AltosEepromRecordMega.java +++ b/altoslib/AltosEepromRecordMega.java @@ -143,7 +143,6 @@ public class AltosEepromRecordMega extends AltosEepromRecord { ground_yaw() / 512.0); break; case AltosLib.AO_LOG_STATE: - System.out.printf("log state %s\n", AltosLib.state_name(state())); listener.set_state(state()); break; case AltosLib.AO_LOG_SENSOR: diff --git a/altoslib/AltosFlightReader.java b/altoslib/AltosFlightReader.java index 250e2236..790710e0 100644 --- a/altoslib/AltosFlightReader.java +++ b/altoslib/AltosFlightReader.java @@ -45,8 +45,6 @@ public abstract class AltosFlightReader { public void save_telemetry_rate() { } - public void update(AltosState state) throws InterruptedException { } - public boolean supports_telemetry(int telemetry) { return false; } public boolean supports_telemetry_rate(int telemetry_rate) { return false; } diff --git a/altoslib/AltosFlightSeries.java b/altoslib/AltosFlightSeries.java index 0eea34b7..7bedf389 100644 --- a/altoslib/AltosFlightSeries.java +++ b/altoslib/AltosFlightSeries.java @@ -136,7 +136,6 @@ public class AltosFlightSeries extends AltosDataListener { state_series = add_series(state_name, AltosConvert.state_name); else if (this.state == state) return; - System.out.printf("state %s\n", AltosLib.state_name(state)); this.state = state; state_series.add(time(), state); } @@ -147,7 +146,6 @@ public class AltosFlightSeries extends AltosDataListener { public void set_acceleration(double acceleration) { if (accel_series == null) { - System.out.printf("set acceleration %g\n", acceleration); accel_series = add_series(accel_name, AltosConvert.accel); } accel_series.add(time(), acceleration); @@ -221,10 +219,8 @@ public class AltosFlightSeries extends AltosDataListener { public static final String speed_name = "Speed"; private void compute_speed() { - if (speed_series != null) { - System.out.printf("speed series already made\n"); + if (speed_series != null) return; - } AltosTimeSeries alt_speed_series = null; AltosTimeSeries accel_speed_series = null; @@ -235,8 +231,6 @@ public class AltosFlightSeries extends AltosDataListener { alt_speed_series = make_series(speed_name, AltosConvert.speed); temp_series.filter(alt_speed_series, 10.0); - } else { - System.out.printf("no altitude series\n"); } if (accel_series != null) { AltosTimeSeries temp_series = make_series(speed_name, AltosConvert.speed); @@ -244,8 +238,6 @@ public class AltosFlightSeries extends AltosDataListener { accel_speed_series = make_series(speed_name, AltosConvert.speed); temp_series.filter(accel_speed_series, 0.1); - } else { - System.out.printf("no accel series\n"); } if (alt_speed_series != null && accel_speed_series != null) { @@ -277,11 +269,8 @@ public class AltosFlightSeries extends AltosDataListener { } else if (accel_speed_series != null) { speed_series = accel_speed_series; } - if (speed_series != null) { + if (speed_series != null) add_series(speed_series); - System.out.printf("speed series for %s set to %s\n", this.toString(), speed_series.toString()); - } else - System.out.printf("didn't manage to make speed series\n"); } AltosTimeSeries kalman_height_series, kalman_speed_series, kalman_accel_series; @@ -575,7 +564,6 @@ public class AltosFlightSeries extends AltosDataListener { } public void fill_in() { - System.out.printf("fill in %s\n", this.toString()); compute_speed(); compute_accel(); if (cal_data.ground_altitude != AltosLib.MISSING) @@ -594,7 +582,6 @@ public class AltosFlightSeries extends AltosDataListener { public AltosFlightSeries(AltosCalData cal_data) { super(cal_data); - System.out.printf("new flight series %s\n", this.toString()); init(); } } diff --git a/altoslib/AltosFlightStats.java b/altoslib/AltosFlightStats.java index 54d0dd63..2948ad38 100644 --- a/altoslib/AltosFlightStats.java +++ b/altoslib/AltosFlightStats.java @@ -115,8 +115,6 @@ public class AltosFlightStats { double end_time = 0; double landed_time = landed_time(series); - System.out.printf("flight stats %s\n", series.toString()); - year = month = day = AltosLib.MISSING; hour = minute = second = AltosLib.MISSING; serial = flight = AltosLib.MISSING; @@ -133,8 +131,21 @@ public class AltosFlightStats { for (int s = AltosLib.ao_flight_startup; s <= AltosLib.ao_flight_landed; s++) { state_count[s] = 0; - state_speed[s] = 0.0; - state_accel[s] = 0.0; + + if (s == AltosLib.ao_flight_boost) + state_start[s] = boost_time; + else + state_start[s] = series.state_series.time_of(s); + if (s == AltosLib.ao_flight_landed) + state_end[s] = landed_time; + else + state_end[s] = series.state_series.time_of(s+1); + + if (series.speed_series != null) + state_speed[s] = series.speed_series.average(state_start[s], state_end[s]); + + if (series.accel_series != null) + state_accel[s] = series.accel_series.average(state_start[s], state_end[s]); } serial = cal_data.serial; @@ -145,92 +156,46 @@ public class AltosFlightStats { has_rssi = series.rssi_series != null; has_flight_data = series.pressure_series != null; - if (series.gps_series != null) { - AltosGPS gps = series.gps_series.get(0).gps; + AltosGPS gps = series.cal_data.gps_pad; + if (gps != null) { year = gps.year; month = gps.month; day = gps.day; hour = gps.hour; minute = gps.minute; second = gps.second; + has_gps = true; + lat = pad_lat = gps.lat; + lon = pad_lon = gps.lon; + for (AltosGPSTimeValue gtv : series.gps_series) { + gps = gtv.gps; + if (gps.locked && gps.nsat >= 4) { + lat = gps.lat; + lon = gps.lon; + } + } + } max_height = AltosLib.MISSING; if (series.height_series != null) max_height = series.height_series.max(); max_speed = AltosLib.MISSING; - if (series.speed_series != null) - max_speed = series.speed_series.max(); - else - System.out.printf("missing speed series\n"); + if (series.speed_series != null) { + max_speed = series.speed_series.max(state_start[AltosLib.ao_flight_boost], state_start[AltosLib.ao_flight_drogue]); + if (max_speed == AltosLib.MISSING) + max_speed = series.speed_series.max(); + } max_acceleration = AltosLib.MISSING; - if (series.accel_series != null) - max_acceleration = series.accel_series.max(); + if (series.accel_series != null) { + max_acceleration = series.accel_series.max(state_start[AltosLib.ao_flight_boost], state_start[AltosLib.ao_flight_drogue]); + if (max_acceleration == AltosLib.MISSING) + max_acceleration = series.accel_series.max(); + } max_gps_height = AltosLib.MISSING; if (series.gps_height != null) max_gps_height = series.gps_height.max(); -/* - for (AltosState state : states) { - end_time = state.time; - - int state_id = state.state(); - if (boost_time != AltosLib.MISSING && state.time >= boost_time && state_id < AltosLib.ao_flight_boost) { - state_id = AltosLib.ao_flight_boost; - } - if (landed_time != AltosLib.MISSING && state.time >= landed_time && state_id < AltosLib.ao_flight_landed) { - state_id = AltosLib.ao_flight_landed; - } - - if (0 <= state_id && state_id < AltosLib.ao_flight_invalid) { - double acceleration = state.acceleration(); - double speed = state.speed(); - if (acceleration != AltosLib.MISSING && speed != AltosLib.MISSING) { - state_accel[state_id] += acceleration; - state_speed[state_id] += speed; - state_count[state_id]++; - } - if (state_start[state_id] == 0.0) - state_start[state_id] = state.time; - if (state_end[state_id] < state.time) - state_end[state_id] = state.time; - } - if (state.pad_lat != AltosLib.MISSING) { - pad_lat = state.pad_lat; - pad_lon = state.pad_lon; - } - if (state.gps != null && state.gps.locked && state.gps.nsat >= 4) { - lat = state.gps.lat; - lon = state.gps.lon; - has_gps = true; - if (state.gps.cc_gps_sat != null) - has_gps_sats = true; - if (state.gps.course != AltosLib.MISSING) - has_gps_detail = true; - } - if (state.imu != null) - has_imu = true; - if (state.mag != null) - has_mag = true; - if (state.orient() != AltosLib.MISSING) - has_orient = true; - if (state.igniter_voltage != null && state.igniter_voltage.length > num_igniter) - num_igniter = state.igniter_voltage.length; - } -*/ - for (int s = AltosLib.ao_flight_startup; s <= AltosLib.ao_flight_landed; s++) { - if (state_count[s] > 0) { - state_speed[s] /= state_count[s]; - state_accel[s] /= state_count[s]; - } else { - state_speed[s] = AltosLib.MISSING; - state_accel[s] = AltosLib.MISSING; - } - if (state_start[s] == 0) - state_start[s] = end_time; - if (state_end[s] == 0) - state_end[s] = end_time; - } } } diff --git a/altoslib/AltosReplayReader.java b/altoslib/AltosReplayReader.java index 59ade871..fb8432e7 100644 --- a/altoslib/AltosReplayReader.java +++ b/altoslib/AltosReplayReader.java @@ -20,36 +20,131 @@ package org.altusmetrum.altoslib_11; import java.io.*; import java.util.*; +import java.util.concurrent.*; /* * Open an existing telemetry file and replay it in realtime */ +class AltosReplay extends AltosDataListener implements Runnable { + + AltosState state; + AltosRecordSet record_set; + double last_time = AltosLib.MISSING; + Semaphore semaphore = new Semaphore(1);; + boolean done = false; + + public void set_time(double time) { + if (last_time != AltosLib.MISSING) { + semaphore.release(); + double delay = Math.min(time - last_time,10); + if (delay > 0) { + try { + Thread.sleep((int) (delay * 1000)); + } catch (InterruptedException ie) { + } + } + } + last_time = time; + super.set_time(time); + state.set_time(time); + } + + public void set_state(int state) { + super.set_state(state); + this.state.set_state(state); + } + + public void set_rssi(int rssi, int status) { state.set_rssi(rssi, status); } + public void set_received_time(long received_time) { } + + public void set_acceleration(double accel) { state.set_acceleration(accel); } + public void set_pressure(double pa) { state.set_pressure(pa); } + public void set_thrust(double N) { state.set_thrust(N); } + + public void set_kalman(double height, double speed, double accel) { state.set_kalman(height, speed, accel); } + + public void set_temperature(double deg_c) { state.set_temperature(deg_c); } + public void set_battery_voltage(double volts) { state.set_battery_voltage(volts); } + + public void set_apogee_voltage(double volts) { state.set_apogee_voltage(volts); } + public void set_main_voltage(double volts) { state.set_main_voltage(volts); } + + public void set_gps(AltosGPS gps) { state.set_gps(gps); } + + public void set_orient(double orient) { state.set_orient(orient); } + public void set_gyro(double roll, double pitch, double yaw) { state.set_gyro(roll, pitch, yaw); } + public void set_accel_ground(double along, double across, double through) { state.set_accel_ground(along, across, through); } + public void set_accel(double along, double across, double through) { state.set_accel(along, across, through); } + public void set_mag(double along, double across, double through) { state.set_mag(along, across, through); } + public void set_pyro_voltage(double volts) { state.set_pyro_voltage(volts); } + public void set_igniter_voltage(double[] voltage) { state.set_igniter_voltage(voltage); } + public void set_pyro_fired(int pyro_mask) { state.set_pyro_fired(pyro_mask); } + public void set_companion(AltosCompanion companion) { state.set_companion(companion); } + + public void run () { + System.out.printf("ReplayReader running\n"); + state = new AltosState(record_set.cal_data()); + + /* Tell the display that we're in pad mode */ + state.set_state(AltosLib.ao_flight_pad); + semaphore.release(); + try { + Thread.sleep(100); + } catch (InterruptedException ie) { + } + + /* Run the flight */ + record_set.capture_series(this); + + /* All done, signal that it's over */ + done = true; + semaphore.release(); + } + + public AltosReplay(AltosRecordSet record_set) { + super(record_set.cal_data()); + try { + semaphore.acquire(); + } catch (InterruptedException ie) { } + this.record_set = record_set; + Thread t = new Thread(this); + t.start(); + } +} + public class AltosReplayReader extends AltosFlightReader { - Iterator iterator; - File file; + File file; + AltosReplay replay; public AltosState read() { - if (iterator.hasNext()) - return iterator.next(); - return null; + + /* When done, let the display know */ + if (replay.done) + return null; + + /* Wait for something to change */ + try { + replay.semaphore.acquire(); + } catch (InterruptedException ie) { + } + + /* Fake out the received time */ + replay.state.set_received_time(System.currentTimeMillis()); + return replay.state; } public void close (boolean interrupted) { } public void update(AltosState state) throws InterruptedException { - /* Make it run in realtime after the rocket leaves the pad */ - if (state.state() > AltosLib.ao_flight_pad && state.time_change > 0) - Thread.sleep((int) (Math.min(state.time_change,10) * 1000)); - state.set_received_time(System.currentTimeMillis()); } public File backing_file() { return file; } - public AltosReplayReader(Iterator in_iterator, File in_file) { - iterator = in_iterator; + public AltosReplayReader(AltosRecordSet record_set, File in_file) { file = in_file; name = file.getName(); + replay = new AltosReplay(record_set); } } diff --git a/altoslib/AltosTelemetryFile.java b/altoslib/AltosTelemetryFile.java index c6462872..8adf7e69 100644 --- a/altoslib/AltosTelemetryFile.java +++ b/altoslib/AltosTelemetryFile.java @@ -111,7 +111,6 @@ public class AltosTelemetryFile implements AltosRecordSet { if (l.cal_data_complete()) break; } - System.out.printf("Telemetry boost tick %d\n", cal_data.boost_tick); } return cal_data; } diff --git a/altoslib/AltosTimeSeries.java b/altoslib/AltosTimeSeries.java index 30b24d82..142c30ef 100644 --- a/altoslib/AltosTimeSeries.java +++ b/altoslib/AltosTimeSeries.java @@ -85,6 +85,16 @@ public class AltosTimeSeries implements Iterable { return values.get(after).value; } + public double time_of(double value) { + double last = AltosLib.MISSING; + for (AltosTimeValue v : values) { + if (v.value >= value) + return v.time; + last = v.time; + } + return last; + } + public int size() { return values.size(); } @@ -102,6 +112,16 @@ public class AltosTimeSeries implements Iterable { return max; } + public double max(double start_time, double end_time) { + double max = AltosLib.MISSING; + for (AltosTimeValue tv : values) { + if (start_time <= tv.time && tv.time <= end_time) + if (max == AltosLib.MISSING || tv.value > max) + max = tv.value; + } + return max; + } + public double min() { double min = AltosLib.MISSING; for (AltosTimeValue tv : values) { @@ -111,6 +131,42 @@ public class AltosTimeSeries implements Iterable { return min; } + public double min(double start_time, double end_time) { + double min = AltosLib.MISSING; + for (AltosTimeValue tv : values) { + if (start_time <= tv.time && tv.time <= end_time) + if (min == AltosLib.MISSING || tv.value < min) + min = tv.value; + } + return min; + } + + public double average() { + double total = 0; + int count = 0; + for (AltosTimeValue tv : values) { + total += tv.value; + count++; + } + if (count == 0) + return AltosLib.MISSING; + return total / count; + } + + public double average(double start_time, double end_time) { + double total = 0; + int count = 0; + for (AltosTimeValue tv : values) { + if (start_time <= tv.time && tv.time <= end_time) { + total += tv.value; + count++; + } + } + if (count == 0) + return AltosLib.MISSING; + return total / count; + } + public AltosTimeSeries integrate(AltosTimeSeries integral) { double value = 0.0; double pvalue = 0.0; diff --git a/altosui/AltosFlightUI.java b/altosui/AltosFlightUI.java index eaf19256..23a62e95 100644 --- a/altosui/AltosFlightUI.java +++ b/altosui/AltosFlightUI.java @@ -115,7 +115,9 @@ public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay { JComponent tab = which_tab(state); if (tab != cur_tab) { + System.out.printf("checking tab for state %s\n", AltosLib.state_name(state.state())); if (cur_tab == pane.getSelectedComponent()) { + System.out.printf("switch tabs\n"); pane.setSelectedComponent(tab); } cur_tab = tab; diff --git a/altosui/AltosUI.java b/altosui/AltosUI.java index b0cff381..a6b967f8 100644 --- a/altosui/AltosUI.java +++ b/altosui/AltosUI.java @@ -481,8 +481,7 @@ public class AltosUI extends AltosUIFrame { AltosRecordSet set = record_set(file); if (set == null) return null; -// return new AltosReplayReader(states.iterator(), file); - return null; + return new AltosReplayReader(set, file); } static boolean process_replay(File file) { diff --git a/altosuilib/AltosDisplayThread.java b/altosuilib/AltosDisplayThread.java index 52414c62..1edac8a9 100644 --- a/altosuilib/AltosDisplayThread.java +++ b/altosuilib/AltosDisplayThread.java @@ -30,7 +30,9 @@ public class AltosDisplayThread extends Thread { IdleThread idle_thread; AltosVoice voice; AltosFlightReader reader; - AltosState old_state, state; + AltosState state; + int old_state = AltosLib.ao_flight_invalid; + boolean old_gps_ready = false; AltosListenerState listener_state; AltosFlightDisplay display; @@ -164,7 +166,7 @@ public class AltosDisplayThread extends Thread { } public synchronized void notice(boolean spoken) { - if (old_state != null && old_state.state() != state.state()) { + if (old_state != state.state()) { report_time = now(); this.notify(); } else if (spoken) @@ -179,16 +181,16 @@ public class AltosDisplayThread extends Thread { synchronized boolean tell() { boolean ret = false; - if (old_state == null || old_state.state() != state.state()) { + if (old_state != state.state()) { if (state.state() != AltosLib.ao_flight_stateless) voice.speak(state.state_name()); - if ((old_state == null || old_state.state() <= AltosLib.ao_flight_boost) && + if ((old_state == AltosLib.ao_flight_invalid || old_state <= AltosLib.ao_flight_boost) && state.state() > AltosLib.ao_flight_boost) { if (state.max_speed() != AltosLib.MISSING) voice.speak("max speed: %s.", AltosConvert.speed.say_units(state.max_speed() + 0.5)); ret = true; - } else if ((old_state == null || old_state.state() < AltosLib.ao_flight_drogue) && + } else if ((old_state == AltosLib.ao_flight_invalid || old_state < AltosLib.ao_flight_drogue) && state.state() >= AltosLib.ao_flight_drogue) { if (state.max_height() != AltosLib.MISSING) voice.speak("max height: %s.", @@ -196,17 +198,18 @@ public class AltosDisplayThread extends Thread { ret = true; } } - if (old_state == null || old_state.gps_ready != state.gps_ready) { + if (old_gps_ready != state.gps_ready) { if (state.gps_ready) { voice.speak("GPS ready"); ret = true; } - else if (old_state != null) { + else if (old_gps_ready) { voice.speak("GPS lost"); ret = true; } } - old_state = state; + old_state = state.state(); + old_gps_ready = state.gps_ready; return ret; } @@ -220,14 +223,11 @@ public class AltosDisplayThread extends Thread { try { for (;;) { try { - AltosState new_state = reader.read(); - if (new_state == null) { - state = null; + state = reader.read(); + if (state == null) { listener_state.running = false; break; } - reader.update(new_state); - state = new_state; show_safely(); told = tell(); idle_thread.notice(told);